diff --git a/## Changes.md b/## Changes.md new file mode 100644 index 0000000000..b6e11f7653 --- /dev/null +++ b/## Changes.md @@ -0,0 +1,138 @@ +## Additions + +- Netherite Backtank +- Netherite Diving Helmet and Boots +- Contraption Controls +- Elevator Pulley +- Copycat Panels and Copycat Steps +- Block of Andesite Alloy +- Block of Industrial Iron +- Large Water Wheel +- Mechanical Roller +- Andesite, Brass and Copper Doors +- Andesite, Brass and Copper Bars +- Andesite, Brass and Copper Scaffolding +- Clipboard +- Mangrove Windows (1.19) + +## Changes + +- Overhauled models and textures of Andesite & Brass components (Kryppers) +- Reworked textures of colored blocks such as seats and sails (dani) +- New filter sprites (vectorwing) +- Valve handles can now be used to precisely turn mechanical bearings by a set angle +- Pulley ropes are now climbable +- Lowered hitbox of seats for improved traversability inside contraptions +- Improved safety for players standing on vertically moving contraptions +- Pulley contraptions will now make an effort to place remote players at y values sensible to the client +- Fixed seated entities on rotating contraptions not rendering at the correct location +- Deployers no longer fail to activate in chunks claimed or protected by the player that placed them +- Fixed couplings, schematics and in-world overlays not rendering correctly at coordinates far from the origin +- Fixed Bearings, Pistons, Pulleys and Gantries powered by a Sequenced Gearshift not moving precisely to its instructions at high speeds +- Minecart contraptions no longer visually jump to a location when stalled +- Mechanical bearings now snap to a rounded angle when stopped +- Contraption storage now accepts more chests and barrels from other mods +- Players can now open chests and barrels on assembled contraptions +- Mechanical Pumps no longer reverse direction based on kinetic input +- Fixed pipe connections pulling fluids with half the speed compared to a directly attached pump +- Substantially increased speed of visual flow propagation inside pipe networks +- Portable storage interfaces now stall for longer after an exchange has happened, and shorter otherwise +- Single train track blocks with slopes connected on either side will angle themselves to create a smoother ascend across both +- Multiple pulleys can now attach to contraptions in a synchronised group +- Display Boards now update text instantaneously at high input rpm +- Diving helmets now always grant aqua affinity +- Diving helmets can no longer be enchanted with aqua affinity +- Water wheel fins are no longer directional +- Water wheels now only have one speed level +- Water wheels can now take the appearance of any reasonably implemented wood type +- Added sided door control options to elevator contact and train station UI +- Liquid can no longer spread perpendicularly on top of water wheels +- Overhauled UX of scroll values and item filtering +- Filtered item extraction can now be configured to pull "up to x items" per operation +- Connected textures now use and apply the getAppearance() standard by Forge, allowing them to connect across other mods' facades, etc. (1.19) +- Boiler status now highlights information about water flow when insufficient +- The majority of in-world options no longer require a wrench +- Chutes can now be encased in Industrial Iron Blocks +- Chutes are now less prone to resetting shape when moved or rotated +- Moved metal block variants to Building Blocks tab +- Changed stonecutting ingredient of metal block variants from sheet to ingot +- Base stone blocks can now be stonecut back from their cut variants +- Fixed track placement allowing an s-bend between two sloped track pieces in specific arrangements +- Fixed funnels losing filters when changing between types +- New randomised textures for natural palette stone types (Kryppers) +- Readjusted palette stone generation to use taller layers +- World generation now places fewer stone type veins by default +- Fixed lava fans voiding items that have smoking & smelting recipes with different outputs +- Filter items now filter for their own item type if left empty +- Valve handles no longer create stress config entries for each dyed variant +- Place near initial angle mode on bearings now has a smaller interval considered 'near' +- Players can now take items from saws via right-click +- Item Drains now accept dropped items as input +- Train track placement overlay now explicitly mentions the ctrl key +- Fixed Mechanical Saws not rendering as animated when using rubidium +- Fixed a ui element of the Station Screen rendering behind the background +- Belts printed instantly or via cannon now retain the correct type of casing +- Scheduled trains no longer slow down for slight ascends/descents on a straight track +- Fixed saplings and other non-collidables sticking to chassis or super glue +- Encased Fluid Pipes no longer z-fight on open pipe faces +- Valve handles now turn twice as quickly +- Bearings no longer have the angle-indicating nook on their block +- Depot hitbox is now a simple cuboid +- Fixed belts encased with andesite briefly showing brass textures +- Fixed Filters and Attribute Filters not stacking with unmodified, equivalent stacks +- Fixed Attribute Filters saving the name tag preview item in their data +- Filters and Schedules can now be reset via crafting +- Renamed Sails to Windmill Sails +- Crushing gold ore now yields more experience nuggets +- Fixed valve pipes sometimes not rotating their indicator fully +- Horizontal, encased belts now render a support structure when solid blocks are above them +- Added placement assist for mechanical drills, saws and deployers +- Mechanical Belts can now be waterlogged +- Depots and Ejectors can now be Waterlogged +- Chutes and Funnels can now be Waterlogged +- Fixed upright mechanical saws only able to be oriented in two directions +- Deployers now have their filter slot on the side of the block +- Deployers can now be rotated by wrenching them near the edge of the front face +- Deployers now set filters on blocks only by targeting any location on a correct side +- Fixed Schematics loaded for deployer printing not rotating block entity contents +- Added tripwire to #movable_empty_collider +- Renamed Stockpile Switch to Threshold Switch +- Renamed Content Observer to Smart Observer +- Smart observer and threshold switch can now be oriented to face blocks above or below them +- Smart observer will now also emit redstone when the block in front of it matches its filter +- Fixed non-vanilla signs not accepted as valid display targets +- Brass tunnels with no distribution behaviour no longer show the mode switcher +- Used more contrasting colours for diode and tunnel value inputs +- Fixed crash when hose pulley cannot find reference fluid for infinite draining +- Clipboards can now be used to transfer settings between blocks +- Clipboards can now be used to manually write to Display Boards and Nixie Tubes +- Clipboards can now be used as Material Checklists in the Schematicannon +- Fixed and edited existing tooltips and ponder scenes to include behavioural changes in 0.5.1 +- New ponder scenes for Smart Observer, Threshold Switch, Elevator Pulley, Contraption Controls and Mechanical Rollers +- Fixed ponder overlay text rendering with wonky pixels +- Added a ponder category for recently added/changed blocks +- Renamed Filter to List Filter +- Deployers can now apply filters to a Redstone link with less required precision +- Bezier track segments now render with a slight angle to reduce z-fighting +- Fixed offset shaft rotation on encased large cogwheels +- Fixed Smart Fluid Pipe not dropping filter when broken +- Placards and Creative Crates will no longer hold on to special nbt content (except potion data, damage, enchants) of the contained item when imported via Schematicannon +- Schematicannons can no longer print mobs +- Fixed item frames not requiring an exact nbt match for printed contents +- Players can now sneak while using exp nuggets to only consume one item at a time +- Minecart contraption items can no longer be placed in container items like toolboxes or shulkers (configurable) +- Implemented ComputerCraft interaction for Speed Controllers, Display Links, Speedometers, Stressometers, Sequenced Gearshifts and Train Stations (caelwarner) +- Hand crank no longer drains hunger when using the extendo grip (Xstoudi) +- Fixed Encased Chain Drives not reacting to block rotation and mirroring correctly +- Open Ended Pipes now correctly handle Builder's Tea (NerdsOfAFeather) +- Added Config entry for brass tunnel distribution cooldown (Walle123) +- API for custom bogey & track types (Rabbitminers, techno-sam) +- Fixed server crash caused by Gantry Contraptions assembling (Lucasmellof) +- Fix "Lighter than air" fluids displayed incorrectly in spouts (cakeGit) +- Added rotate and mirror methods to Fluid Pipes (xieve) +- Chocolate & Honey fluid fog distance is now configurable (radimous) +- Added a TrackGraph merge event (DaComputerNerd717) +- Fixed players dismounting when trains get assembled (Equinoxxe) +- Added GameTests (TropheusJ) +- Added armor tags (NerdsOfAFeather) +- Major updates now release as patch A \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 6ddef3d3c1..8fcc41721e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,9 @@ # http://editorconfig.org -root = true +#root = true [*] indent_style = space indent_size = 4 -continuation_indent_size = 8 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 17865fe1c8..06ce144188 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: Create a bug report to help us improve Create -labels: [ "bug" ] +labels: [ "type: bug" ] body: - type: textarea attributes: @@ -49,6 +49,13 @@ body: label: Mod Version description: The version of the mod you were using when the bug occured options: + - "0.5.1d" + - "0.5.1c" + - "0.5.1b" + - "0.5.1a" + - "0.5.0i" + - "0.5.0h" + - "0.5.0g" - "0.5.0f" - "0.5.0e" - "0.5.0d" @@ -109,6 +116,7 @@ body: label: Minecraft Version description: The version of Minecraft you were using when the bug occured options: + - "1.20.1" - "1.19.2" - "1.18.2" - "1.18.1" diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index 3a460558b7..ff5acdb33b 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,6 +1,6 @@ name: Suggestion description: Suggest something that would improve Create -labels: [ "suggestion" ] +labels: [ "type: suggestion" ] body: - type: textarea attributes: diff --git a/.github/config/labels.yml b/.github/config/labels.yml index f3378f6c1c..29e1fdc475 100644 --- a/.github/config/labels.yml +++ b/.github/config/labels.yml @@ -1,12 +1,12 @@ -1.14: - - "1.14" -1.15: - - "1.15" -1.16: - - "1.16" -1.17: - - "1.17" -1.18: - - "1.18" -1.19: - - "1.19" +'version: 1.14': + - '1\.14(?:\.\d)?' +'version: 1.15': + - '1\.15(?:\.\d)?' +'version: 1.16': + - '1\.16(?:\.\d)?' +'version: 1.17': + - '1\.17(?:\.\d)?' +'version: 1.18': + - '1\.18(?:\.\d)?' +'version: 1.19': + - '1\.19(?:\.\d)?' diff --git a/.github/workflows/gametest.yml b/.github/workflows/gametest.yml new file mode 100644 index 0000000000..23bb055a98 --- /dev/null +++ b/.github/workflows/gametest.yml @@ -0,0 +1,23 @@ +name: gametest +on: [ workflow_dispatch ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: checkout repository + uses: actions/checkout@v3 + + - name: setup Java + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + cache: gradle + + - name: make gradle wrapper executable + run: chmod +x ./gradlew + + - name: run gametests + run: ./gradlew prepareRunGameTestServer runGameTestServer --no-daemon diff --git a/.github/workflows/label_issues.yml b/.github/workflows/label_issues.yml index 83d771a2cb..02ae709080 100644 --- a/.github/workflows/label_issues.yml +++ b/.github/workflows/label_issues.yml @@ -7,8 +7,9 @@ jobs: label: runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v2.0 + - uses: github/issue-labeler@v3.0 with: configuration-path: .github/config/labels.yml enable-versioned-regex: 0 repo-token: ${{ secrets.GITHUB_TOKEN }} + sync-labels: 1 diff --git a/.github/workflows/localization.yml b/.github/workflows/localization.yml new file mode 100644 index 0000000000..fd159edd4c --- /dev/null +++ b/.github/workflows/localization.yml @@ -0,0 +1,48 @@ +# This workflow will run Crowdin Action that will upload new texts to Crowdin, download the newest translations and create a PR +# For more information see: https://github.com/crowdin/github-action + +name: Crowdin Action + +# Controls when the action will run. +on: workflow_dispatch + # Only run when started manually + + #: + # inputs: + # uploadTranslations: + # description: "Set to true to upload (changed) translations to Crowdin" + # type: boolean + # required: true + # default: false + + #schedule: + #- cron: '0 */6 * * *' # Every 6 hours - https://crontab.guru/#0_*/6_*_*_* + +jobs: + synchronize-with-crowdin: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: crowdin action + uses: crowdin/github-action@1.4.9 + with: + # Upload sources to Crowdin + upload_sources: true + # Upload translations to Crowdin, only use true at initial run + upload_translations: false + # Make pull request of Crowdin translations + download_translations: true + # To download translations to the specified version branch + localization_branch_name: l10n_crowdin_translations + # Create pull request after pushing to branch + create_pull_request: true + pull_request_title: 'New Crowdin translations' + pull_request_body: 'New Crowdin pull request with translations' + pull_request_base_branch_name: 'mc1.18/dev' + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.gitignore b/.gitignore index 4afb358659..b9a3321f87 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ local.properties # PDT-specific .buildpath -.DS_Store \ No newline at end of file +.DS_Store +/libs/ diff --git a/README.md b/README.md index 987cb9d1a5..ce6b553201 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@

Logo

Create
- Patreon - Supported Versions + Patreon + Supported Versions License Discord CF - Modrinth + Modrinth

diff --git a/build.gradle b/build.gradle index 43edb4c667..99a4e483b4 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { maven { url = 'https://maven.parchmentmc.org' } } dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: "${forgegradle_version}", changing: false + classpath "net.minecraftforge.gradle:ForgeGradle:${forgegradle_version}" classpath "org.spongepowered:mixingradle:${mixingradle_version}" classpath "org.parchmentmc:librarian:${librarian_version}" } @@ -21,6 +21,7 @@ apply plugin: 'org.parchmentmc.librarian.forgegradle' apply plugin: 'eclipse' apply plugin: 'maven-publish' apply plugin: 'org.spongepowered.mixin' +apply plugin: 'idea' jarJar.enable() @@ -49,9 +50,15 @@ version = mod_version + (dev && buildNumber != null ? "-${buildNumber}" : '') java.toolchain.languageVersion = JavaLanguageVersion.of(17) -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) +println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + ' (' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) + minecraft { - mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}" + if (Boolean.parseBoolean(project.use_parchment)) { + mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}" + } else { + mappings channel: 'official', version: "${minecraft_version}" + } + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') runs { @@ -166,44 +173,62 @@ minecraft { } } } + + gameTestServer { + workingDirectory project.file('run/gametest') + arg '-mixin.config=create.mixins.json' + property 'forge.logging.console.level', 'info' + mods { + create { + source sourceSets.main + } + } + + //setForceExit false + } } } repositories { maven { - // Location of the maven that hosts JEI files (and TiC) - name 'Progwml6 maven' - url 'https://dvs1.progwml6.com/files/maven' + // location of the maven for Registrate and Flywheel + name = 'tterrag maven' + url = 'https://maven.tterrag.com' + } + maven { + // location of the maven that hosts JEI files since January 2023 + // location of the maven for Vazkii's mods + name = "Jared's maven" + url = "https://maven.blamejared.com/" } /*maven { - // Location of a maven mirror for JEI files, as a fallback - name 'ModMaven' - url 'https://modmaven.k-4u.nl' + // location of a maven mirror for JEI files, as a fallback + name = "ModMaven" + url = "https://modmaven.dev" }*/ maven { - // Location of the maven for vazkii's mods - name 'blamejared' - url 'https://maven.blamejared.com' + // location of the maven for Dynamic Trees + url = 'https://harleyoconnor.com/maven' } maven { - // Location of the maven for mixed mappings, Registrate, and Flywheel - name 'tterrag maven' - url 'https://maven.tterrag.com' + // location of the maven for Curios API + url = "https://maven.theillusivec4.top/" } maven { - url 'https://www.cursemaven.com' + // location of maven for CC: Tweaked + name = "squiddev" + url = "https://squiddev.cc/maven/" + content { + includeGroup "org.squiddev" + } + } + + maven { + url = 'https://www.cursemaven.com' content { includeGroup "curse.maven" } } - maven { - //location of the maven for dynamic trees - url 'https://harleyoconnor.com/maven' - } - maven { - //location of the maven for curios api - url = "https://maven.theillusivec4.top/" - } maven { // Location of the maven for Ponder, Catnip name 'createmod maven' @@ -216,18 +241,22 @@ repositories { includeGroup "maven.modrinth" } } + + mavenLocal() + flatDir { + dirs 'libs' + } } dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - jarJar(group: 'com.tterrag.registrate', name: 'Registrate', version: '[MC1.18.2-1.1.3,)') { - jarJar.pin(it, project.registrate_version) + jarJar("com.tterrag.registrate:Registrate:${registrate_version}") { + jarJar.ranged(it, '[MC1.18.2-1.1.3,)') + } + jarJar("com.jozufozu.flywheel:flywheel-forge-${flywheel_minecraft_version}:${flywheel_version}") { + jarJar.ranged(it, '[0.6.9,0.6.10)') } - // Uncomment once Forge fixes mixins for included jars - //jarJar(group: 'com.jozufozu.flywheel', name: "flywheel-forge-${flywheel_minecraft_version}", version: '[0.6.4,0.6.5)') { - // jarJar.pin(it, project.flywheel_version) - //} implementation fg.deobf("com.tterrag.registrate:Registrate:${registrate_version}") @@ -257,6 +286,11 @@ dependencies { compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}:api") runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_minecraft_version}-${curios_version}") + if (cc_tweaked_enable.toBoolean()) { + compileOnly fg.deobf("org.squiddev:cc-tweaked-${cc_tweaked_minecraft_version}:${cc_tweaked_version}:api") + runtimeOnly fg.deobf("org.squiddev:cc-tweaked-${cc_tweaked_minecraft_version}:${cc_tweaked_version}") + } + // implementation fg.deobf("curse.maven:druidcraft-340991:3101903") // implementation fg.deobf("com.ferreusveritas.dynamictrees:DynamicTrees-1.16.5:0.10.0-Beta25") // runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") @@ -264,15 +298,22 @@ dependencies { // runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115") // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3") + // implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false } // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings // This allows 'Settings > Build, Execution, and Deployment > Build Tools > Gradle > Build and run using' set to IntelliJ to work correctly - if (System.getProperty('idea.sync.active') != 'true') { + if (!Boolean.getBoolean('idea.sync.active')) { annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" } } +sourceSets.main.java { + if (!cc_tweaked_enable.toBoolean()) { + exclude 'com/simibubi/create/compat/computercraft/implementation/**' + } +} + sourceSets.main.resources { srcDir 'src/generated/resources' exclude '.cache/' @@ -313,6 +354,7 @@ jar { } task jarJarRelease { + group = 'jarjar' doLast { tasks.jarJar { archiveClassifier = '' diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000000..3f0119cbaa --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,49 @@ +"project_id_env": "CROWDIN_PROJECT_ID" +"api_token_env": "CROWDIN_PERSONAL_TOKEN" +"base_path": "." + +"preserve_hierarchy": true + +"files": [ + { + "source": "src/generated/resources/assets/create/lang/en_us.json", + "translation": "src/main/resources/assets/create/lang/%locale_with_underscore%.json", + "languages_mapping": { + "locale_with_underscore": { + "cs": "cs_cz", + "cy": "cy_gb", + "da": "da_dk", + "de": "de_de", + "eo": "eo_uy", + "es-CL": "es_cl", + "es-ES": "es_es", + "es-MX": "es_mx", + "fa": "fa_ir", + "fi": "fi_fi", + "fr": "fr_fr", + "hu": "hu_hu", + "id": "id_id", + "is": "is_is", + "it": "it_it", + "ja": "ja_jp", + "kk": "kk_kz", + "ko": "ko_kr", + "nl": "nl_nl", + "no": "no_no", + "pl": "pl_pl", + "pt-BR": "pt_br", + "pt-PT": "pt_pt", + "ro": "ro_ro", + "rpr": "rpr", + "ru": "ru_ru", + "sv-SE": "sv_se", + "th": "th_th", + "tok": "tok", + "tr": "tr_tr", + "uk": "uk_ua", + "zh-CN": "zh_cn", + "zh-TW": "zh_tw", + } + } + } +] diff --git a/gradle.properties b/gradle.properties index bd716da6e7..abaffcbd79 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,11 +4,11 @@ org.gradle.jvmargs = -Xmx3G org.gradle.daemon = false # mod version info -mod_version = 0.5.0.e +mod_version = 0.5.1.c artifact_minecraft_version = 1.18.2 minecraft_version = 1.18.2 -forge_version = 40.1.60 +forge_version = 40.2.4 # build dependency versions forgegradle_version = 6.+ @@ -16,12 +16,14 @@ mixingradle_version = 0.7-SNAPSHOT mixin_version = 0.8.5 librarian_version = 1.+ cursegradle_version = 1.4.0 -parchment_version = 2022.07.10 +parchment_version = 2022.11.06 + +use_parchment = true # dependency versions registrate_version = MC1.18.2-1.1.3 flywheel_minecraft_version = 1.18.2 -flywheel_version = 0.6.5-91 +flywheel_version = 0.6.9-101 jei_minecraft_version = 1.18.2 jei_version = 9.7.0.209 curios_minecraft_version = 1.18.2 @@ -29,6 +31,10 @@ curios_version = 5.0.7.0 catnip_version = 0.5.7 ponder_version = 0.5.8 +cc_tweaked_enable = true +cc_tweaked_minecraft_version = 1.18.2 +cc_tweaked_version = 1.100.10 + # curseforge information projectId = 328085 curse_type = beta diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d..943f0cbfa7 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew b/gradlew index 1b6c787337..65dcd68d65 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # 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"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -205,6 +209,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32c4..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/src/generated/resources/assets/create/blockstates/andesite_alloy_block.json b/src/generated/resources/assets/create/blockstates/andesite_alloy_block.json new file mode 100644 index 0000000000..1a141d07ce --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/andesite_alloy_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "create:block/andesite_alloy_block" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/andesite_bars.json b/src/generated/resources/assets/create/blockstates/andesite_bars.json new file mode 100644 index 0000000000..29e7825a5b --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/andesite_bars.json @@ -0,0 +1,100 @@ +{ + "multipart": [ + { + "apply": { + "model": "create:block/andesite_post_ends" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/andesite_post" + } + }, + { + "when": { + "north": "true", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/andesite_cap" + } + }, + { + "when": { + "north": "false", + "east": "true", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/andesite_cap", + "y": 90 + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "true", + "west": "false" + }, + "apply": { + "model": "create:block/andesite_cap_alt" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "true" + }, + "apply": { + "model": "create:block/andesite_cap_alt", + "y": 90 + } + }, + { + "when": { + "north": "true" + }, + "apply": { + "model": "create:block/andesite_side" + } + }, + { + "when": { + "east": "true" + }, + "apply": { + "model": "create:block/andesite_side", + "y": 90 + } + }, + { + "when": { + "south": "true" + }, + "apply": { + "model": "create:block/andesite_side_alt" + } + }, + { + "when": { + "west": "true" + }, + "apply": { + "model": "create:block/andesite_side_alt", + "y": 90 + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/andesite_belt_funnel.json b/src/generated/resources/assets/create/blockstates/andesite_belt_funnel.json index 0199a6d72e..f5e4d200b1 100644 --- a/src/generated/resources/assets/create/blockstates/andesite_belt_funnel.json +++ b/src/generated/resources/assets/create/blockstates/andesite_belt_funnel.json @@ -1,122 +1,242 @@ { "variants": { - "facing=north,powered=false,shape=retracted": { - "model": "create:block/andesite_belt_funnel_retracted" + "facing=north,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered" }, - "facing=south,powered=false,shape=retracted": { - "model": "create:block/andesite_belt_funnel_retracted", + "facing=south,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", "y": 180 }, - "facing=west,powered=false,shape=retracted": { - "model": "create:block/andesite_belt_funnel_retracted", + "facing=west,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", "y": 270 }, - "facing=east,powered=false,shape=retracted": { - "model": "create:block/andesite_belt_funnel_retracted", + "facing=east,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", "y": 90 }, - "facing=north,powered=true,shape=retracted": { + "facing=north,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/andesite_belt_funnel_retracted_powered" }, - "facing=south,powered=true,shape=retracted": { + "facing=south,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/andesite_belt_funnel_retracted_powered", "y": 180 }, - "facing=west,powered=true,shape=retracted": { + "facing=west,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/andesite_belt_funnel_retracted_powered", "y": 270 }, - "facing=east,powered=true,shape=retracted": { + "facing=east,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/andesite_belt_funnel_retracted_powered", "y": 90 }, - "facing=north,powered=false,shape=extended": { - "model": "create:block/andesite_belt_funnel_extended" + "facing=north,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_extended_unpowered" }, - "facing=south,powered=false,shape=extended": { - "model": "create:block/andesite_belt_funnel_extended", + "facing=south,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", "y": 180 }, - "facing=west,powered=false,shape=extended": { - "model": "create:block/andesite_belt_funnel_extended", + "facing=west,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", "y": 270 }, - "facing=east,powered=false,shape=extended": { - "model": "create:block/andesite_belt_funnel_extended", + "facing=east,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", "y": 90 }, - "facing=north,powered=true,shape=extended": { + "facing=north,powered=true,shape=extended,waterlogged=false": { "model": "create:block/andesite_belt_funnel_extended_powered" }, - "facing=south,powered=true,shape=extended": { + "facing=south,powered=true,shape=extended,waterlogged=false": { "model": "create:block/andesite_belt_funnel_extended_powered", "y": 180 }, - "facing=west,powered=true,shape=extended": { + "facing=west,powered=true,shape=extended,waterlogged=false": { "model": "create:block/andesite_belt_funnel_extended_powered", "y": 270 }, - "facing=east,powered=true,shape=extended": { + "facing=east,powered=true,shape=extended,waterlogged=false": { "model": "create:block/andesite_belt_funnel_extended_powered", "y": 90 }, - "facing=north,powered=false,shape=pushing": { - "model": "create:block/andesite_belt_funnel_pushing" + "facing=north,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered" }, - "facing=south,powered=false,shape=pushing": { - "model": "create:block/andesite_belt_funnel_pushing", + "facing=south,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", "y": 180 }, - "facing=west,powered=false,shape=pushing": { - "model": "create:block/andesite_belt_funnel_pushing", + "facing=west,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", "y": 270 }, - "facing=east,powered=false,shape=pushing": { - "model": "create:block/andesite_belt_funnel_pushing", + "facing=east,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", "y": 90 }, - "facing=north,powered=true,shape=pushing": { + "facing=north,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pushing_powered" }, - "facing=south,powered=true,shape=pushing": { + "facing=south,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pushing_powered", "y": 180 }, - "facing=west,powered=true,shape=pushing": { + "facing=west,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pushing_powered", "y": 270 }, - "facing=east,powered=true,shape=pushing": { + "facing=east,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pushing_powered", "y": 90 }, - "facing=north,powered=false,shape=pulling": { - "model": "create:block/andesite_belt_funnel_pulling" + "facing=north,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered" }, - "facing=south,powered=false,shape=pulling": { - "model": "create:block/andesite_belt_funnel_pulling", + "facing=south,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", "y": 180 }, - "facing=west,powered=false,shape=pulling": { - "model": "create:block/andesite_belt_funnel_pulling", + "facing=west,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", "y": 270 }, - "facing=east,powered=false,shape=pulling": { - "model": "create:block/andesite_belt_funnel_pulling", + "facing=east,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", "y": 90 }, - "facing=north,powered=true,shape=pulling": { + "facing=north,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pulling_powered" }, - "facing=south,powered=true,shape=pulling": { + "facing=south,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pulling_powered", "y": 180 }, - "facing=west,powered=true,shape=pulling": { + "facing=west,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/andesite_belt_funnel_pulling_powered", "y": 270 }, - "facing=east,powered=true,shape=pulling": { + "facing=east,powered=true,shape=pulling,waterlogged=false": { + "model": "create:block/andesite_belt_funnel_pulling_powered", + "y": 90 + }, + "facing=north,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered" + }, + "facing=south,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_powered" + }, + "facing=south,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_powered", + "y": 180 + }, + "facing=west,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_powered", + "y": 270 + }, + "facing=east,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_retracted_powered", + "y": 90 + }, + "facing=north,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_unpowered" + }, + "facing=south,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_powered" + }, + "facing=south,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_powered", + "y": 180 + }, + "facing=west,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_powered", + "y": 270 + }, + "facing=east,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_extended_powered", + "y": 90 + }, + "facing=north,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered" + }, + "facing=south,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_powered" + }, + "facing=south,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_powered", + "y": 180 + }, + "facing=west,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_powered", + "y": 270 + }, + "facing=east,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pushing_powered", + "y": 90 + }, + "facing=north,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered" + }, + "facing=south,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_powered" + }, + "facing=south,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_powered", + "y": 180 + }, + "facing=west,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/andesite_belt_funnel_pulling_powered", + "y": 270 + }, + "facing=east,powered=true,shape=pulling,waterlogged=true": { "model": "create:block/andesite_belt_funnel_pulling_powered", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/andesite_door.json b/src/generated/resources/assets/create/blockstates/andesite_door.json new file mode 100644 index 0000000000..c3b1243764 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/andesite_door.json @@ -0,0 +1,244 @@ +{ + "variants": { + "facing=north,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=north,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/andesite_door/block_bottom", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/andesite_funnel.json b/src/generated/resources/assets/create/blockstates/andesite_funnel.json index 9ea4b09ee2..01f25e0da4 100644 --- a/src/generated/resources/assets/create/blockstates/andesite_funnel.json +++ b/src/generated/resources/assets/create/blockstates/andesite_funnel.json @@ -1,98 +1,194 @@ { "variants": { - "extracting=false,facing=down,powered=false": { - "model": "create:block/andesite_funnel_vertical_filterless_pull", + "extracting=false,facing=down,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_unpowered", "x": 180, "y": 180 }, - "extracting=true,facing=down,powered=false": { - "model": "create:block/andesite_funnel_vertical_filterless_push", + "extracting=true,facing=down,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_vertical_filterless_push_unpowered", "x": 180, "y": 180 }, - "extracting=false,facing=up,powered=false": { - "model": "create:block/andesite_funnel_vertical_filterless_pull", + "extracting=false,facing=up,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_unpowered", "y": 180 }, - "extracting=true,facing=up,powered=false": { - "model": "create:block/andesite_funnel_vertical_filterless_push", + "extracting=true,facing=up,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_vertical_filterless_push_unpowered", "y": 180 }, - "extracting=false,facing=north,powered=false": { - "model": "create:block/andesite_funnel_horizontal_pull" + "extracting=false,facing=north,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered" }, - "extracting=true,facing=north,powered=false": { - "model": "create:block/andesite_funnel_horizontal_push" + "extracting=true,facing=north,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered" }, - "extracting=false,facing=south,powered=false": { - "model": "create:block/andesite_funnel_horizontal_pull", + "extracting=false,facing=south,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", "y": 180 }, - "extracting=true,facing=south,powered=false": { - "model": "create:block/andesite_funnel_horizontal_push", + "extracting=true,facing=south,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", "y": 180 }, - "extracting=false,facing=west,powered=false": { - "model": "create:block/andesite_funnel_horizontal_pull", + "extracting=false,facing=west,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", "y": 270 }, - "extracting=true,facing=west,powered=false": { - "model": "create:block/andesite_funnel_horizontal_push", + "extracting=true,facing=west,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", "y": 270 }, - "extracting=false,facing=east,powered=false": { - "model": "create:block/andesite_funnel_horizontal_pull", + "extracting=false,facing=east,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", "y": 90 }, - "extracting=true,facing=east,powered=false": { - "model": "create:block/andesite_funnel_horizontal_push", + "extracting=true,facing=east,powered=false,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", "y": 90 }, - "extracting=false,facing=down,powered=true": { + "extracting=false,facing=down,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", "x": 180, "y": 180 }, - "extracting=true,facing=down,powered=true": { + "extracting=true,facing=down,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_vertical_filterless_push_powered", "x": 180, "y": 180 }, - "extracting=false,facing=up,powered=true": { + "extracting=false,facing=up,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", "y": 180 }, - "extracting=true,facing=up,powered=true": { + "extracting=true,facing=up,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_vertical_filterless_push_powered", "y": 180 }, - "extracting=false,facing=north,powered=true": { + "extracting=false,facing=north,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_pull_powered" }, - "extracting=true,facing=north,powered=true": { + "extracting=true,facing=north,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_push_powered" }, - "extracting=false,facing=south,powered=true": { + "extracting=false,facing=south,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 180 }, - "extracting=true,facing=south,powered=true": { + "extracting=true,facing=south,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 180 }, - "extracting=false,facing=west,powered=true": { + "extracting=false,facing=west,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 270 }, - "extracting=true,facing=west,powered=true": { + "extracting=true,facing=west,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 270 }, - "extracting=false,facing=east,powered=true": { + "extracting=false,facing=east,powered=true,waterlogged=false": { "model": "create:block/andesite_funnel_horizontal_pull_powered", "y": 90 }, - "extracting=true,facing=east,powered=true": { + "extracting=true,facing=east,powered=true,waterlogged=false": { + "model": "create:block/andesite_funnel_horizontal_push_powered", + "y": 90 + }, + "extracting=false,facing=down,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_unpowered", + "x": 180, + "y": 180 + }, + "extracting=true,facing=down,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_unpowered", + "x": 180, + "y": 180 + }, + "extracting=false,facing=up,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_unpowered", + "y": 180 + }, + "extracting=true,facing=up,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_unpowered", + "y": 180 + }, + "extracting=false,facing=north,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered" + }, + "extracting=true,facing=north,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered" + }, + "extracting=false,facing=south,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", + "y": 180 + }, + "extracting=true,facing=south,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", + "y": 180 + }, + "extracting=false,facing=west,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", + "y": 270 + }, + "extracting=true,facing=west,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", + "y": 270 + }, + "extracting=false,facing=east,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_unpowered", + "y": 90 + }, + "extracting=true,facing=east,powered=false,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_unpowered", + "y": 90 + }, + "extracting=false,facing=down,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", + "x": 180, + "y": 180 + }, + "extracting=true,facing=down,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_powered", + "x": 180, + "y": 180 + }, + "extracting=false,facing=up,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_pull_powered", + "y": 180 + }, + "extracting=true,facing=up,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_vertical_filterless_push_powered", + "y": 180 + }, + "extracting=false,facing=north,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered" + }, + "extracting=true,facing=north,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered" + }, + "extracting=false,facing=south,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", + "y": 180 + }, + "extracting=true,facing=south,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered", + "y": 180 + }, + "extracting=false,facing=west,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", + "y": 270 + }, + "extracting=true,facing=west,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_push_powered", + "y": 270 + }, + "extracting=false,facing=east,powered=true,waterlogged=true": { + "model": "create:block/andesite_funnel_horizontal_pull_powered", + "y": 90 + }, + "extracting=true,facing=east,powered=true,waterlogged=true": { "model": "create:block/andesite_funnel_horizontal_push_powered", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/andesite_scaffolding.json b/src/generated/resources/assets/create/blockstates/andesite_scaffolding.json new file mode 100644 index 0000000000..153f5928b7 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/andesite_scaffolding.json @@ -0,0 +1,10 @@ +{ + "variants": { + "bottom=false": { + "model": "create:block/andesite_scaffolding" + }, + "bottom=true": { + "model": "create:block/andesite_scaffolding_horizontal" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/andesite_tunnel.json b/src/generated/resources/assets/create/blockstates/andesite_tunnel.json index c38dbb250b..108c92e754 100644 --- a/src/generated/resources/assets/create/blockstates/andesite_tunnel.json +++ b/src/generated/resources/assets/create/blockstates/andesite_tunnel.json @@ -1,45 +1,45 @@ { "variants": { "axis=x,shape=straight": { - "model": "create:block/andesite_tunnel/straight" + "model": "create:block/tunnel/andesite_tunnel/straight" }, "axis=z,shape=straight": { - "model": "create:block/andesite_tunnel/straight", + "model": "create:block/tunnel/andesite_tunnel/straight", "y": 90 }, "axis=x,shape=window": { - "model": "create:block/andesite_tunnel/window" + "model": "create:block/tunnel/andesite_tunnel/window" }, "axis=z,shape=window": { - "model": "create:block/andesite_tunnel/window", + "model": "create:block/tunnel/andesite_tunnel/window", "y": 90 }, "axis=x,shape=closed": { - "model": "create:block/andesite_tunnel/straight" + "model": "create:block/tunnel/andesite_tunnel/straight" }, "axis=z,shape=closed": { - "model": "create:block/andesite_tunnel/straight", + "model": "create:block/tunnel/andesite_tunnel/straight", "y": 90 }, "axis=x,shape=t_left": { - "model": "create:block/andesite_tunnel/t_left" + "model": "create:block/tunnel/andesite_tunnel/t_left" }, "axis=z,shape=t_left": { - "model": "create:block/andesite_tunnel/t_left", + "model": "create:block/tunnel/andesite_tunnel/t_left", "y": 90 }, "axis=x,shape=t_right": { - "model": "create:block/andesite_tunnel/t_right" + "model": "create:block/tunnel/andesite_tunnel/t_right" }, "axis=z,shape=t_right": { - "model": "create:block/andesite_tunnel/t_right", + "model": "create:block/tunnel/andesite_tunnel/t_right", "y": 90 }, "axis=x,shape=cross": { - "model": "create:block/andesite_tunnel/cross" + "model": "create:block/tunnel/andesite_tunnel/cross" }, "axis=z,shape=cross": { - "model": "create:block/andesite_tunnel/cross", + "model": "create:block/tunnel/andesite_tunnel/cross", "y": 90 } } diff --git a/src/generated/resources/assets/create/blockstates/asurine.json b/src/generated/resources/assets/create/blockstates/asurine.json index 36e4d318f9..9411ef97a7 100644 --- a/src/generated/resources/assets/create/blockstates/asurine.json +++ b/src/generated/resources/assets/create/blockstates/asurine.json @@ -1,7 +1,18 @@ { "variants": { - "": { - "model": "create:block/asurine" - } + "": [ + { + "model": "create:block/asurine_natural_0" + }, + { + "model": "create:block/asurine_natural_1" + }, + { + "model": "create:block/asurine_natural_2" + }, + { + "model": "create:block/asurine_natural_3" + } + ] } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/belt.json b/src/generated/resources/assets/create/blockstates/belt.json index c09a0cb211..c17b445a7d 100644 --- a/src/generated/resources/assets/create/blockstates/belt.json +++ b/src/generated/resources/assets/create/blockstates/belt.json @@ -1,650 +1,1298 @@ { "variants": { - "casing=false,facing=north,part=start,slope=horizontal": { + "casing=false,facing=north,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=start,slope=horizontal": { + "casing=true,facing=north,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_start", "y": 180 }, - "casing=false,facing=south,part=start,slope=horizontal": { + "casing=false,facing=south,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=start,slope=horizontal": { + "casing=true,facing=south,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_start" }, - "casing=false,facing=west,part=start,slope=horizontal": { + "casing=false,facing=west,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=start,slope=horizontal": { + "casing=true,facing=west,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_start", "y": 90 }, - "casing=false,facing=east,part=start,slope=horizontal": { + "casing=false,facing=east,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=start,slope=horizontal": { + "casing=true,facing=east,part=start,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_start", "y": 270 }, - "casing=false,facing=north,part=middle,slope=horizontal": { + "casing=false,facing=north,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=middle,slope=horizontal": { + "casing=true,facing=north,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_middle", "y": 180 }, - "casing=false,facing=south,part=middle,slope=horizontal": { + "casing=false,facing=south,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=middle,slope=horizontal": { + "casing=true,facing=south,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_middle" }, - "casing=false,facing=west,part=middle,slope=horizontal": { + "casing=false,facing=west,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=middle,slope=horizontal": { + "casing=true,facing=west,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_middle", "y": 90 }, - "casing=false,facing=east,part=middle,slope=horizontal": { + "casing=false,facing=east,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=middle,slope=horizontal": { + "casing=true,facing=east,part=middle,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_middle", "y": 270 }, - "casing=false,facing=north,part=end,slope=horizontal": { + "casing=false,facing=north,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=end,slope=horizontal": { + "casing=true,facing=north,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_end", "y": 180 }, - "casing=false,facing=south,part=end,slope=horizontal": { + "casing=false,facing=south,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=end,slope=horizontal": { + "casing=true,facing=south,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_end" }, - "casing=false,facing=west,part=end,slope=horizontal": { + "casing=false,facing=west,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=end,slope=horizontal": { + "casing=true,facing=west,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_end", "y": 90 }, - "casing=false,facing=east,part=end,slope=horizontal": { + "casing=false,facing=east,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=end,slope=horizontal": { + "casing=true,facing=east,part=end,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_end", "y": 270 }, - "casing=false,facing=north,part=pulley,slope=horizontal": { + "casing=false,facing=north,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=pulley,slope=horizontal": { + "casing=true,facing=north,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_pulley", "y": 180 }, - "casing=false,facing=south,part=pulley,slope=horizontal": { + "casing=false,facing=south,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=pulley,slope=horizontal": { + "casing=true,facing=south,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_pulley" }, - "casing=false,facing=west,part=pulley,slope=horizontal": { + "casing=false,facing=west,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=pulley,slope=horizontal": { + "casing=true,facing=west,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_pulley", "y": 90 }, - "casing=false,facing=east,part=pulley,slope=horizontal": { + "casing=false,facing=east,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=pulley,slope=horizontal": { + "casing=true,facing=east,part=pulley,slope=horizontal,waterlogged=false": { "model": "create:block/belt_casing/horizontal_pulley", "y": 270 }, - "casing=false,facing=north,part=start,slope=upward": { + "casing=false,facing=north,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=north,part=start,slope=upward": { + "casing=true,facing=north,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start" }, - "casing=false,facing=south,part=start,slope=upward": { + "casing=false,facing=south,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=south,part=start,slope=upward": { + "casing=true,facing=south,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 180 }, - "casing=false,facing=west,part=start,slope=upward": { + "casing=false,facing=west,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=west,part=start,slope=upward": { + "casing=true,facing=west,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 270 }, - "casing=false,facing=east,part=start,slope=upward": { + "casing=false,facing=east,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=east,part=start,slope=upward": { + "casing=true,facing=east,part=start,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 90 }, - "casing=false,facing=north,part=middle,slope=upward": { + "casing=false,facing=north,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=north,part=middle,slope=upward": { + "casing=true,facing=north,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle" }, - "casing=false,facing=south,part=middle,slope=upward": { + "casing=false,facing=south,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=south,part=middle,slope=upward": { + "casing=true,facing=south,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 180 }, - "casing=false,facing=west,part=middle,slope=upward": { + "casing=false,facing=west,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=west,part=middle,slope=upward": { + "casing=true,facing=west,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 270 }, - "casing=false,facing=east,part=middle,slope=upward": { + "casing=false,facing=east,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=east,part=middle,slope=upward": { + "casing=true,facing=east,part=middle,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 90 }, - "casing=false,facing=north,part=end,slope=upward": { + "casing=false,facing=north,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=north,part=end,slope=upward": { + "casing=true,facing=north,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end" }, - "casing=false,facing=south,part=end,slope=upward": { + "casing=false,facing=south,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=south,part=end,slope=upward": { + "casing=true,facing=south,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 180 }, - "casing=false,facing=west,part=end,slope=upward": { + "casing=false,facing=west,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=west,part=end,slope=upward": { + "casing=true,facing=west,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 270 }, - "casing=false,facing=east,part=end,slope=upward": { + "casing=false,facing=east,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=east,part=end,slope=upward": { + "casing=true,facing=east,part=end,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 90 }, - "casing=false,facing=north,part=pulley,slope=upward": { + "casing=false,facing=north,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=north,part=pulley,slope=upward": { + "casing=true,facing=north,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley" }, - "casing=false,facing=south,part=pulley,slope=upward": { + "casing=false,facing=south,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=south,part=pulley,slope=upward": { + "casing=true,facing=south,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 180 }, - "casing=false,facing=west,part=pulley,slope=upward": { + "casing=false,facing=west,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=west,part=pulley,slope=upward": { + "casing=true,facing=west,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 270 }, - "casing=false,facing=east,part=pulley,slope=upward": { + "casing=false,facing=east,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=east,part=pulley,slope=upward": { + "casing=true,facing=east,part=pulley,slope=upward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 90 }, - "casing=false,facing=north,part=start,slope=downward": { + "casing=false,facing=north,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=start,slope=downward": { + "casing=true,facing=north,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 180 }, - "casing=false,facing=south,part=start,slope=downward": { + "casing=false,facing=south,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=start,slope=downward": { + "casing=true,facing=south,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end" }, - "casing=false,facing=west,part=start,slope=downward": { + "casing=false,facing=west,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=start,slope=downward": { + "casing=true,facing=west,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 90 }, - "casing=false,facing=east,part=start,slope=downward": { + "casing=false,facing=east,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=start,slope=downward": { + "casing=true,facing=east,part=start,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_end", "y": 270 }, - "casing=false,facing=north,part=middle,slope=downward": { + "casing=false,facing=north,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=middle,slope=downward": { + "casing=true,facing=north,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 180 }, - "casing=false,facing=south,part=middle,slope=downward": { + "casing=false,facing=south,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=middle,slope=downward": { + "casing=true,facing=south,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle" }, - "casing=false,facing=west,part=middle,slope=downward": { + "casing=false,facing=west,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=middle,slope=downward": { + "casing=true,facing=west,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 90 }, - "casing=false,facing=east,part=middle,slope=downward": { + "casing=false,facing=east,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=middle,slope=downward": { + "casing=true,facing=east,part=middle,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_middle", "y": 270 }, - "casing=false,facing=north,part=end,slope=downward": { + "casing=false,facing=north,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=end,slope=downward": { + "casing=true,facing=north,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 180 }, - "casing=false,facing=south,part=end,slope=downward": { + "casing=false,facing=south,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=end,slope=downward": { + "casing=true,facing=south,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start" }, - "casing=false,facing=west,part=end,slope=downward": { + "casing=false,facing=west,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=end,slope=downward": { + "casing=true,facing=west,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 90 }, - "casing=false,facing=east,part=end,slope=downward": { + "casing=false,facing=east,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=end,slope=downward": { + "casing=true,facing=east,part=end,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_start", "y": 270 }, - "casing=false,facing=north,part=pulley,slope=downward": { + "casing=false,facing=north,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 180 }, - "casing=true,facing=north,part=pulley,slope=downward": { + "casing=true,facing=north,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 180 }, - "casing=false,facing=south,part=pulley,slope=downward": { + "casing=false,facing=south,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=pulley,slope=downward": { + "casing=true,facing=south,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley" }, - "casing=false,facing=west,part=pulley,slope=downward": { + "casing=false,facing=west,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 90 }, - "casing=true,facing=west,part=pulley,slope=downward": { + "casing=true,facing=west,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 90 }, - "casing=false,facing=east,part=pulley,slope=downward": { + "casing=false,facing=east,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=pulley,slope=downward": { + "casing=true,facing=east,part=pulley,slope=downward,waterlogged=false": { "model": "create:block/belt_casing/diagonal_pulley", "y": 270 }, - "casing=false,facing=north,part=start,slope=vertical": { + "casing=false,facing=north,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 180 }, - "casing=true,facing=north,part=start,slope=vertical": { + "casing=true,facing=north,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 90, "y": 270 }, - "casing=false,facing=south,part=start,slope=vertical": { + "casing=false,facing=south,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90 }, - "casing=true,facing=south,part=start,slope=vertical": { + "casing=true,facing=south,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 90, "y": 90 }, - "casing=false,facing=west,part=start,slope=vertical": { + "casing=false,facing=west,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 90 }, - "casing=true,facing=west,part=start,slope=vertical": { + "casing=true,facing=west,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 90, "y": 180 }, - "casing=false,facing=east,part=start,slope=vertical": { + "casing=false,facing=east,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 270 }, - "casing=true,facing=east,part=start,slope=vertical": { + "casing=true,facing=east,part=start,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 90 }, - "casing=false,facing=north,part=middle,slope=vertical": { + "casing=false,facing=north,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 180 }, - "casing=true,facing=north,part=middle,slope=vertical": { + "casing=true,facing=north,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 90, "y": 270 }, - "casing=false,facing=south,part=middle,slope=vertical": { + "casing=false,facing=south,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90 }, - "casing=true,facing=south,part=middle,slope=vertical": { + "casing=true,facing=south,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 90, "y": 90 }, - "casing=false,facing=west,part=middle,slope=vertical": { + "casing=false,facing=west,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 90 }, - "casing=true,facing=west,part=middle,slope=vertical": { + "casing=true,facing=west,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 90, "y": 180 }, - "casing=false,facing=east,part=middle,slope=vertical": { + "casing=false,facing=east,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 270 }, - "casing=true,facing=east,part=middle,slope=vertical": { + "casing=true,facing=east,part=middle,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 90 }, - "casing=false,facing=north,part=end,slope=vertical": { + "casing=false,facing=north,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 180 }, - "casing=true,facing=north,part=end,slope=vertical": { + "casing=true,facing=north,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 90, "y": 270 }, - "casing=false,facing=south,part=end,slope=vertical": { + "casing=false,facing=south,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90 }, - "casing=true,facing=south,part=end,slope=vertical": { + "casing=true,facing=south,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 90, "y": 90 }, - "casing=false,facing=west,part=end,slope=vertical": { + "casing=false,facing=west,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 90 }, - "casing=true,facing=west,part=end,slope=vertical": { + "casing=true,facing=west,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 90, "y": 180 }, - "casing=false,facing=east,part=end,slope=vertical": { + "casing=false,facing=east,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 270 }, - "casing=true,facing=east,part=end,slope=vertical": { + "casing=true,facing=east,part=end,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 90 }, - "casing=false,facing=north,part=pulley,slope=vertical": { + "casing=false,facing=north,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 180 }, - "casing=true,facing=north,part=pulley,slope=vertical": { + "casing=true,facing=north,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 90, "y": 270 }, - "casing=false,facing=south,part=pulley,slope=vertical": { + "casing=false,facing=south,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90 }, - "casing=true,facing=south,part=pulley,slope=vertical": { + "casing=true,facing=south,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 90, "y": 90 }, - "casing=false,facing=west,part=pulley,slope=vertical": { + "casing=false,facing=west,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 90 }, - "casing=true,facing=west,part=pulley,slope=vertical": { + "casing=true,facing=west,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 90, "y": 180 }, - "casing=false,facing=east,part=pulley,slope=vertical": { + "casing=false,facing=east,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt/particle", "x": 90, "y": 270 }, - "casing=true,facing=east,part=pulley,slope=vertical": { + "casing=true,facing=east,part=pulley,slope=vertical,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 90 }, - "casing=false,facing=north,part=start,slope=sideways": { + "casing=false,facing=north,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 180 }, - "casing=true,facing=north,part=start,slope=sideways": { + "casing=true,facing=north,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 180, "y": 180 }, - "casing=false,facing=south,part=start,slope=sideways": { + "casing=false,facing=south,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=start,slope=sideways": { + "casing=true,facing=south,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_start" }, - "casing=false,facing=west,part=start,slope=sideways": { + "casing=false,facing=west,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 90 }, - "casing=true,facing=west,part=start,slope=sideways": { + "casing=true,facing=west,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "x": 180, "y": 90 }, - "casing=false,facing=east,part=start,slope=sideways": { + "casing=false,facing=east,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=start,slope=sideways": { + "casing=true,facing=east,part=start,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "y": 270 }, - "casing=false,facing=north,part=middle,slope=sideways": { + "casing=false,facing=north,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 180 }, - "casing=true,facing=north,part=middle,slope=sideways": { + "casing=true,facing=north,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 180, "y": 180 }, - "casing=false,facing=south,part=middle,slope=sideways": { + "casing=false,facing=south,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=middle,slope=sideways": { + "casing=true,facing=south,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle" }, - "casing=false,facing=west,part=middle,slope=sideways": { + "casing=false,facing=west,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 90 }, - "casing=true,facing=west,part=middle,slope=sideways": { + "casing=true,facing=west,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "x": 180, "y": 90 }, - "casing=false,facing=east,part=middle,slope=sideways": { + "casing=false,facing=east,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=middle,slope=sideways": { + "casing=true,facing=east,part=middle,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_middle", "y": 270 }, - "casing=false,facing=north,part=end,slope=sideways": { + "casing=false,facing=north,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 180 }, - "casing=true,facing=north,part=end,slope=sideways": { + "casing=true,facing=north,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 180, "y": 180 }, - "casing=false,facing=south,part=end,slope=sideways": { + "casing=false,facing=south,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=end,slope=sideways": { + "casing=true,facing=south,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_end" }, - "casing=false,facing=west,part=end,slope=sideways": { + "casing=false,facing=west,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 90 }, - "casing=true,facing=west,part=end,slope=sideways": { + "casing=true,facing=west,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_start", "x": 180, "y": 90 }, - "casing=false,facing=east,part=end,slope=sideways": { + "casing=false,facing=east,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=end,slope=sideways": { + "casing=true,facing=east,part=end,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_end", "y": 270 }, - "casing=false,facing=north,part=pulley,slope=sideways": { + "casing=false,facing=north,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 180 }, - "casing=true,facing=north,part=pulley,slope=sideways": { + "casing=true,facing=north,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 180, "y": 180 }, - "casing=false,facing=south,part=pulley,slope=sideways": { + "casing=false,facing=south,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle" }, - "casing=true,facing=south,part=pulley,slope=sideways": { + "casing=true,facing=south,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley" }, - "casing=false,facing=west,part=pulley,slope=sideways": { + "casing=false,facing=west,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "x": 180, "y": 90 }, - "casing=true,facing=west,part=pulley,slope=sideways": { + "casing=true,facing=west,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt_casing/sideways_pulley", "x": 180, "y": 90 }, - "casing=false,facing=east,part=pulley,slope=sideways": { + "casing=false,facing=east,part=pulley,slope=sideways,waterlogged=false": { "model": "create:block/belt/particle", "y": 270 }, - "casing=true,facing=east,part=pulley,slope=sideways": { + "casing=true,facing=east,part=pulley,slope=sideways,waterlogged=false": { + "model": "create:block/belt_casing/sideways_pulley", + "y": 270 + }, + "casing=false,facing=north,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_start", + "y": 180 + }, + "casing=false,facing=south,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_start" + }, + "casing=false,facing=west,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_start", + "y": 90 + }, + "casing=false,facing=east,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=start,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_start", + "y": 270 + }, + "casing=false,facing=north,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_middle", + "y": 180 + }, + "casing=false,facing=south,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_middle" + }, + "casing=false,facing=west,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_middle", + "y": 90 + }, + "casing=false,facing=east,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=middle,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_middle", + "y": 270 + }, + "casing=false,facing=north,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_end", + "y": 180 + }, + "casing=false,facing=south,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_end" + }, + "casing=false,facing=west,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_end", + "y": 90 + }, + "casing=false,facing=east,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=end,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_end", + "y": 270 + }, + "casing=false,facing=north,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_pulley", + "y": 180 + }, + "casing=false,facing=south,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_pulley" + }, + "casing=false,facing=west,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_pulley", + "y": 90 + }, + "casing=false,facing=east,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=pulley,slope=horizontal,waterlogged=true": { + "model": "create:block/belt_casing/horizontal_pulley", + "y": 270 + }, + "casing=false,facing=north,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=north,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start" + }, + "casing=false,facing=south,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=south,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 180 + }, + "casing=false,facing=west,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=west,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 270 + }, + "casing=false,facing=east,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=east,part=start,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 90 + }, + "casing=false,facing=north,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=north,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle" + }, + "casing=false,facing=south,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=south,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 180 + }, + "casing=false,facing=west,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=west,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 270 + }, + "casing=false,facing=east,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=east,part=middle,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 90 + }, + "casing=false,facing=north,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=north,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end" + }, + "casing=false,facing=south,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=south,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 180 + }, + "casing=false,facing=west,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=west,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 270 + }, + "casing=false,facing=east,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=east,part=end,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 90 + }, + "casing=false,facing=north,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=north,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley" + }, + "casing=false,facing=south,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=south,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 180 + }, + "casing=false,facing=west,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=west,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 270 + }, + "casing=false,facing=east,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=east,part=pulley,slope=upward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 90 + }, + "casing=false,facing=north,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 180 + }, + "casing=false,facing=south,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end" + }, + "casing=false,facing=west,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 90 + }, + "casing=false,facing=east,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=start,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_end", + "y": 270 + }, + "casing=false,facing=north,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 180 + }, + "casing=false,facing=south,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle" + }, + "casing=false,facing=west,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 90 + }, + "casing=false,facing=east,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=middle,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_middle", + "y": 270 + }, + "casing=false,facing=north,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 180 + }, + "casing=false,facing=south,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start" + }, + "casing=false,facing=west,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 90 + }, + "casing=false,facing=east,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=end,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_start", + "y": 270 + }, + "casing=false,facing=north,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 180 + }, + "casing=true,facing=north,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 180 + }, + "casing=false,facing=south,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley" + }, + "casing=false,facing=west,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 90 + }, + "casing=true,facing=west,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 90 + }, + "casing=false,facing=east,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=pulley,slope=downward,waterlogged=true": { + "model": "create:block/belt_casing/diagonal_pulley", + "y": 270 + }, + "casing=false,facing=north,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 180 + }, + "casing=true,facing=north,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 90, + "y": 270 + }, + "casing=false,facing=south,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90 + }, + "casing=true,facing=south,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 90, + "y": 90 + }, + "casing=false,facing=west,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 90 + }, + "casing=true,facing=west,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 90, + "y": 180 + }, + "casing=false,facing=east,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 270 + }, + "casing=true,facing=east,part=start,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 90 + }, + "casing=false,facing=north,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 180 + }, + "casing=true,facing=north,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 90, + "y": 270 + }, + "casing=false,facing=south,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90 + }, + "casing=true,facing=south,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 90, + "y": 90 + }, + "casing=false,facing=west,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 90 + }, + "casing=true,facing=west,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 90, + "y": 180 + }, + "casing=false,facing=east,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 270 + }, + "casing=true,facing=east,part=middle,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 90 + }, + "casing=false,facing=north,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 180 + }, + "casing=true,facing=north,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 90, + "y": 270 + }, + "casing=false,facing=south,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90 + }, + "casing=true,facing=south,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 90, + "y": 90 + }, + "casing=false,facing=west,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 90 + }, + "casing=true,facing=west,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 90, + "y": 180 + }, + "casing=false,facing=east,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 270 + }, + "casing=true,facing=east,part=end,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 90 + }, + "casing=false,facing=north,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 180 + }, + "casing=true,facing=north,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 90, + "y": 270 + }, + "casing=false,facing=south,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90 + }, + "casing=true,facing=south,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 90, + "y": 90 + }, + "casing=false,facing=west,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 90 + }, + "casing=true,facing=west,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 90, + "y": 180 + }, + "casing=false,facing=east,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 90, + "y": 270 + }, + "casing=true,facing=east,part=pulley,slope=vertical,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 90 + }, + "casing=false,facing=north,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 180 + }, + "casing=true,facing=north,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 180, + "y": 180 + }, + "casing=false,facing=south,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start" + }, + "casing=false,facing=west,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 90 + }, + "casing=true,facing=west,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "x": 180, + "y": 90 + }, + "casing=false,facing=east,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=start,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "y": 270 + }, + "casing=false,facing=north,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 180 + }, + "casing=true,facing=north,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 180, + "y": 180 + }, + "casing=false,facing=south,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle" + }, + "casing=false,facing=west,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 90 + }, + "casing=true,facing=west,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "x": 180, + "y": 90 + }, + "casing=false,facing=east,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=middle,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_middle", + "y": 270 + }, + "casing=false,facing=north,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 180 + }, + "casing=true,facing=north,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 180, + "y": 180 + }, + "casing=false,facing=south,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end" + }, + "casing=false,facing=west,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 90 + }, + "casing=true,facing=west,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_start", + "x": 180, + "y": 90 + }, + "casing=false,facing=east,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=end,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_end", + "y": 270 + }, + "casing=false,facing=north,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 180 + }, + "casing=true,facing=north,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 180, + "y": 180 + }, + "casing=false,facing=south,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle" + }, + "casing=true,facing=south,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley" + }, + "casing=false,facing=west,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "x": 180, + "y": 90 + }, + "casing=true,facing=west,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt_casing/sideways_pulley", + "x": 180, + "y": 90 + }, + "casing=false,facing=east,part=pulley,slope=sideways,waterlogged=true": { + "model": "create:block/belt/particle", + "y": 270 + }, + "casing=true,facing=east,part=pulley,slope=sideways,waterlogged=true": { "model": "create:block/belt_casing/sideways_pulley", "y": 270 } diff --git a/src/generated/resources/assets/create/blockstates/brass_bars.json b/src/generated/resources/assets/create/blockstates/brass_bars.json new file mode 100644 index 0000000000..3fb2a08ea6 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/brass_bars.json @@ -0,0 +1,100 @@ +{ + "multipart": [ + { + "apply": { + "model": "create:block/brass_post_ends" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/brass_post" + } + }, + { + "when": { + "north": "true", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/brass_cap" + } + }, + { + "when": { + "north": "false", + "east": "true", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/brass_cap", + "y": 90 + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "true", + "west": "false" + }, + "apply": { + "model": "create:block/brass_cap_alt" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "true" + }, + "apply": { + "model": "create:block/brass_cap_alt", + "y": 90 + } + }, + { + "when": { + "north": "true" + }, + "apply": { + "model": "create:block/brass_side" + } + }, + { + "when": { + "east": "true" + }, + "apply": { + "model": "create:block/brass_side", + "y": 90 + } + }, + { + "when": { + "south": "true" + }, + "apply": { + "model": "create:block/brass_side_alt" + } + }, + { + "when": { + "west": "true" + }, + "apply": { + "model": "create:block/brass_side_alt", + "y": 90 + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/brass_belt_funnel.json b/src/generated/resources/assets/create/blockstates/brass_belt_funnel.json index f4466bfb26..4765075394 100644 --- a/src/generated/resources/assets/create/blockstates/brass_belt_funnel.json +++ b/src/generated/resources/assets/create/blockstates/brass_belt_funnel.json @@ -1,122 +1,242 @@ { "variants": { - "facing=north,powered=false,shape=retracted": { - "model": "create:block/brass_belt_funnel_retracted" + "facing=north,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/brass_belt_funnel_retracted_unpowered" }, - "facing=south,powered=false,shape=retracted": { - "model": "create:block/brass_belt_funnel_retracted", + "facing=south,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", "y": 180 }, - "facing=west,powered=false,shape=retracted": { - "model": "create:block/brass_belt_funnel_retracted", + "facing=west,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", "y": 270 }, - "facing=east,powered=false,shape=retracted": { - "model": "create:block/brass_belt_funnel_retracted", + "facing=east,powered=false,shape=retracted,waterlogged=false": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", "y": 90 }, - "facing=north,powered=true,shape=retracted": { + "facing=north,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/brass_belt_funnel_retracted_powered" }, - "facing=south,powered=true,shape=retracted": { + "facing=south,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/brass_belt_funnel_retracted_powered", "y": 180 }, - "facing=west,powered=true,shape=retracted": { + "facing=west,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/brass_belt_funnel_retracted_powered", "y": 270 }, - "facing=east,powered=true,shape=retracted": { + "facing=east,powered=true,shape=retracted,waterlogged=false": { "model": "create:block/brass_belt_funnel_retracted_powered", "y": 90 }, - "facing=north,powered=false,shape=extended": { - "model": "create:block/brass_belt_funnel_extended" + "facing=north,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/brass_belt_funnel_extended_unpowered" }, - "facing=south,powered=false,shape=extended": { - "model": "create:block/brass_belt_funnel_extended", + "facing=south,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/brass_belt_funnel_extended_unpowered", "y": 180 }, - "facing=west,powered=false,shape=extended": { - "model": "create:block/brass_belt_funnel_extended", + "facing=west,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/brass_belt_funnel_extended_unpowered", "y": 270 }, - "facing=east,powered=false,shape=extended": { - "model": "create:block/brass_belt_funnel_extended", + "facing=east,powered=false,shape=extended,waterlogged=false": { + "model": "create:block/brass_belt_funnel_extended_unpowered", "y": 90 }, - "facing=north,powered=true,shape=extended": { + "facing=north,powered=true,shape=extended,waterlogged=false": { "model": "create:block/brass_belt_funnel_extended_powered" }, - "facing=south,powered=true,shape=extended": { + "facing=south,powered=true,shape=extended,waterlogged=false": { "model": "create:block/brass_belt_funnel_extended_powered", "y": 180 }, - "facing=west,powered=true,shape=extended": { + "facing=west,powered=true,shape=extended,waterlogged=false": { "model": "create:block/brass_belt_funnel_extended_powered", "y": 270 }, - "facing=east,powered=true,shape=extended": { + "facing=east,powered=true,shape=extended,waterlogged=false": { "model": "create:block/brass_belt_funnel_extended_powered", "y": 90 }, - "facing=north,powered=false,shape=pushing": { - "model": "create:block/brass_belt_funnel_pushing" + "facing=north,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pushing_unpowered" }, - "facing=south,powered=false,shape=pushing": { - "model": "create:block/brass_belt_funnel_pushing", + "facing=south,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", "y": 180 }, - "facing=west,powered=false,shape=pushing": { - "model": "create:block/brass_belt_funnel_pushing", + "facing=west,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", "y": 270 }, - "facing=east,powered=false,shape=pushing": { - "model": "create:block/brass_belt_funnel_pushing", + "facing=east,powered=false,shape=pushing,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", "y": 90 }, - "facing=north,powered=true,shape=pushing": { + "facing=north,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/brass_belt_funnel_pushing_powered" }, - "facing=south,powered=true,shape=pushing": { + "facing=south,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/brass_belt_funnel_pushing_powered", "y": 180 }, - "facing=west,powered=true,shape=pushing": { + "facing=west,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/brass_belt_funnel_pushing_powered", "y": 270 }, - "facing=east,powered=true,shape=pushing": { + "facing=east,powered=true,shape=pushing,waterlogged=false": { "model": "create:block/brass_belt_funnel_pushing_powered", "y": 90 }, - "facing=north,powered=false,shape=pulling": { - "model": "create:block/brass_belt_funnel_pulling" + "facing=north,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pulling_unpowered" }, - "facing=south,powered=false,shape=pulling": { - "model": "create:block/brass_belt_funnel_pulling", + "facing=south,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", "y": 180 }, - "facing=west,powered=false,shape=pulling": { - "model": "create:block/brass_belt_funnel_pulling", + "facing=west,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", "y": 270 }, - "facing=east,powered=false,shape=pulling": { - "model": "create:block/brass_belt_funnel_pulling", + "facing=east,powered=false,shape=pulling,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", "y": 90 }, - "facing=north,powered=true,shape=pulling": { + "facing=north,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/brass_belt_funnel_pulling_powered" }, - "facing=south,powered=true,shape=pulling": { + "facing=south,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/brass_belt_funnel_pulling_powered", "y": 180 }, - "facing=west,powered=true,shape=pulling": { + "facing=west,powered=true,shape=pulling,waterlogged=false": { "model": "create:block/brass_belt_funnel_pulling_powered", "y": 270 }, - "facing=east,powered=true,shape=pulling": { + "facing=east,powered=true,shape=pulling,waterlogged=false": { + "model": "create:block/brass_belt_funnel_pulling_powered", + "y": 90 + }, + "facing=north,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_unpowered" + }, + "facing=south,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_powered" + }, + "facing=south,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_powered", + "y": 180 + }, + "facing=west,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_powered", + "y": 270 + }, + "facing=east,powered=true,shape=retracted,waterlogged=true": { + "model": "create:block/brass_belt_funnel_retracted_powered", + "y": 90 + }, + "facing=north,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_unpowered" + }, + "facing=south,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_powered" + }, + "facing=south,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_powered", + "y": 180 + }, + "facing=west,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_powered", + "y": 270 + }, + "facing=east,powered=true,shape=extended,waterlogged=true": { + "model": "create:block/brass_belt_funnel_extended_powered", + "y": 90 + }, + "facing=north,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_unpowered" + }, + "facing=south,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_powered" + }, + "facing=south,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_powered", + "y": 180 + }, + "facing=west,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_powered", + "y": 270 + }, + "facing=east,powered=true,shape=pushing,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pushing_powered", + "y": 90 + }, + "facing=north,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_unpowered" + }, + "facing=south,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", + "y": 180 + }, + "facing=west,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", + "y": 270 + }, + "facing=east,powered=false,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_unpowered", + "y": 90 + }, + "facing=north,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_powered" + }, + "facing=south,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_powered", + "y": 180 + }, + "facing=west,powered=true,shape=pulling,waterlogged=true": { + "model": "create:block/brass_belt_funnel_pulling_powered", + "y": 270 + }, + "facing=east,powered=true,shape=pulling,waterlogged=true": { "model": "create:block/brass_belt_funnel_pulling_powered", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/brass_door.json b/src/generated/resources/assets/create/blockstates/brass_door.json new file mode 100644 index 0000000000..3fee16d2ce --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/brass_door.json @@ -0,0 +1,244 @@ +{ + "variants": { + "facing=north,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=north,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/brass_door/block_bottom", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/brass_funnel.json b/src/generated/resources/assets/create/blockstates/brass_funnel.json index 19a543d73d..9d829b3db1 100644 --- a/src/generated/resources/assets/create/blockstates/brass_funnel.json +++ b/src/generated/resources/assets/create/blockstates/brass_funnel.json @@ -1,98 +1,194 @@ { "variants": { - "extracting=false,facing=down,powered=false": { - "model": "create:block/brass_funnel_vertical_pull", + "extracting=false,facing=down,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_vertical_pull_unpowered", "x": 180, "y": 180 }, - "extracting=true,facing=down,powered=false": { - "model": "create:block/brass_funnel_vertical_push", + "extracting=true,facing=down,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_vertical_push_unpowered", "x": 180, "y": 180 }, - "extracting=false,facing=up,powered=false": { - "model": "create:block/brass_funnel_vertical_pull", + "extracting=false,facing=up,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_vertical_pull_unpowered", "y": 180 }, - "extracting=true,facing=up,powered=false": { - "model": "create:block/brass_funnel_vertical_push", + "extracting=true,facing=up,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_vertical_push_unpowered", "y": 180 }, - "extracting=false,facing=north,powered=false": { - "model": "create:block/brass_funnel_horizontal_pull" + "extracting=false,facing=north,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered" }, - "extracting=true,facing=north,powered=false": { - "model": "create:block/brass_funnel_horizontal_push" + "extracting=true,facing=north,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_push_unpowered" }, - "extracting=false,facing=south,powered=false": { - "model": "create:block/brass_funnel_horizontal_pull", + "extracting=false,facing=south,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", "y": 180 }, - "extracting=true,facing=south,powered=false": { - "model": "create:block/brass_funnel_horizontal_push", + "extracting=true,facing=south,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", "y": 180 }, - "extracting=false,facing=west,powered=false": { - "model": "create:block/brass_funnel_horizontal_pull", + "extracting=false,facing=west,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", "y": 270 }, - "extracting=true,facing=west,powered=false": { - "model": "create:block/brass_funnel_horizontal_push", + "extracting=true,facing=west,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", "y": 270 }, - "extracting=false,facing=east,powered=false": { - "model": "create:block/brass_funnel_horizontal_pull", + "extracting=false,facing=east,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", "y": 90 }, - "extracting=true,facing=east,powered=false": { - "model": "create:block/brass_funnel_horizontal_push", + "extracting=true,facing=east,powered=false,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", "y": 90 }, - "extracting=false,facing=down,powered=true": { + "extracting=false,facing=down,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_vertical_pull_powered", "x": 180, "y": 180 }, - "extracting=true,facing=down,powered=true": { + "extracting=true,facing=down,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_vertical_push_powered", "x": 180, "y": 180 }, - "extracting=false,facing=up,powered=true": { + "extracting=false,facing=up,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_vertical_pull_powered", "y": 180 }, - "extracting=true,facing=up,powered=true": { + "extracting=true,facing=up,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_vertical_push_powered", "y": 180 }, - "extracting=false,facing=north,powered=true": { + "extracting=false,facing=north,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_pull_powered" }, - "extracting=true,facing=north,powered=true": { + "extracting=true,facing=north,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_push_powered" }, - "extracting=false,facing=south,powered=true": { + "extracting=false,facing=south,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 180 }, - "extracting=true,facing=south,powered=true": { + "extracting=true,facing=south,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_push_powered", "y": 180 }, - "extracting=false,facing=west,powered=true": { + "extracting=false,facing=west,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 270 }, - "extracting=true,facing=west,powered=true": { + "extracting=true,facing=west,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_push_powered", "y": 270 }, - "extracting=false,facing=east,powered=true": { + "extracting=false,facing=east,powered=true,waterlogged=false": { "model": "create:block/brass_funnel_horizontal_pull_powered", "y": 90 }, - "extracting=true,facing=east,powered=true": { + "extracting=true,facing=east,powered=true,waterlogged=false": { + "model": "create:block/brass_funnel_horizontal_push_powered", + "y": 90 + }, + "extracting=false,facing=down,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_pull_unpowered", + "x": 180, + "y": 180 + }, + "extracting=true,facing=down,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_push_unpowered", + "x": 180, + "y": 180 + }, + "extracting=false,facing=up,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_pull_unpowered", + "y": 180 + }, + "extracting=true,facing=up,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_push_unpowered", + "y": 180 + }, + "extracting=false,facing=north,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered" + }, + "extracting=true,facing=north,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_unpowered" + }, + "extracting=false,facing=south,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", + "y": 180 + }, + "extracting=true,facing=south,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", + "y": 180 + }, + "extracting=false,facing=west,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", + "y": 270 + }, + "extracting=true,facing=west,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", + "y": 270 + }, + "extracting=false,facing=east,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_unpowered", + "y": 90 + }, + "extracting=true,facing=east,powered=false,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_unpowered", + "y": 90 + }, + "extracting=false,facing=down,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_pull_powered", + "x": 180, + "y": 180 + }, + "extracting=true,facing=down,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_push_powered", + "x": 180, + "y": 180 + }, + "extracting=false,facing=up,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_pull_powered", + "y": 180 + }, + "extracting=true,facing=up,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_vertical_push_powered", + "y": 180 + }, + "extracting=false,facing=north,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered" + }, + "extracting=true,facing=north,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_powered" + }, + "extracting=false,facing=south,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", + "y": 180 + }, + "extracting=true,facing=south,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_powered", + "y": 180 + }, + "extracting=false,facing=west,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", + "y": 270 + }, + "extracting=true,facing=west,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_push_powered", + "y": 270 + }, + "extracting=false,facing=east,powered=true,waterlogged=true": { + "model": "create:block/brass_funnel_horizontal_pull_powered", + "y": 90 + }, + "extracting=true,facing=east,powered=true,waterlogged=true": { "model": "create:block/brass_funnel_horizontal_push_powered", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/brass_scaffolding.json b/src/generated/resources/assets/create/blockstates/brass_scaffolding.json new file mode 100644 index 0000000000..422df16da0 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/brass_scaffolding.json @@ -0,0 +1,10 @@ +{ + "variants": { + "bottom=false": { + "model": "create:block/brass_scaffolding" + }, + "bottom=true": { + "model": "create:block/brass_scaffolding_horizontal" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/brass_tunnel.json b/src/generated/resources/assets/create/blockstates/brass_tunnel.json index 1566c2619d..b457c51e89 100644 --- a/src/generated/resources/assets/create/blockstates/brass_tunnel.json +++ b/src/generated/resources/assets/create/blockstates/brass_tunnel.json @@ -1,45 +1,45 @@ { "variants": { "axis=x,shape=straight": { - "model": "create:block/brass_tunnel/straight" + "model": "create:block/tunnel/brass_tunnel/straight" }, "axis=z,shape=straight": { - "model": "create:block/brass_tunnel/straight", + "model": "create:block/tunnel/brass_tunnel/straight", "y": 90 }, "axis=x,shape=window": { - "model": "create:block/brass_tunnel/window" + "model": "create:block/tunnel/brass_tunnel/window" }, "axis=z,shape=window": { - "model": "create:block/brass_tunnel/window", + "model": "create:block/tunnel/brass_tunnel/window", "y": 90 }, "axis=x,shape=closed": { - "model": "create:block/brass_tunnel/straight" + "model": "create:block/tunnel/brass_tunnel/straight" }, "axis=z,shape=closed": { - "model": "create:block/brass_tunnel/straight", + "model": "create:block/tunnel/brass_tunnel/straight", "y": 90 }, "axis=x,shape=t_left": { - "model": "create:block/brass_tunnel/t_left" + "model": "create:block/tunnel/brass_tunnel/t_left" }, "axis=z,shape=t_left": { - "model": "create:block/brass_tunnel/t_left", + "model": "create:block/tunnel/brass_tunnel/t_left", "y": 90 }, "axis=x,shape=t_right": { - "model": "create:block/brass_tunnel/t_right" + "model": "create:block/tunnel/brass_tunnel/t_right" }, "axis=z,shape=t_right": { - "model": "create:block/brass_tunnel/t_right", + "model": "create:block/tunnel/brass_tunnel/t_right", "y": 90 }, "axis=x,shape=cross": { - "model": "create:block/brass_tunnel/cross" + "model": "create:block/tunnel/brass_tunnel/cross" }, "axis=z,shape=cross": { - "model": "create:block/brass_tunnel/cross", + "model": "create:block/tunnel/brass_tunnel/cross", "y": 90 } } diff --git a/src/generated/resources/assets/create/blockstates/chute.json b/src/generated/resources/assets/create/blockstates/chute.json index 3e82ef8a8a..52ab0d85bb 100644 --- a/src/generated/resources/assets/create/blockstates/chute.json +++ b/src/generated/resources/assets/create/blockstates/chute.json @@ -1,58 +1,148 @@ { "variants": { - "facing=down,shape=intersection": { + "facing=down,shape=intersection,waterlogged=false": { "model": "create:block/chute/block_intersection" }, - "facing=north,shape=intersection": { + "facing=north,shape=intersection,waterlogged=false": { "model": "create:block/chute/block_diagonal_intersection", "y": 180 }, - "facing=south,shape=intersection": { + "facing=south,shape=intersection,waterlogged=false": { "model": "create:block/chute/block_diagonal_intersection" }, - "facing=west,shape=intersection": { + "facing=west,shape=intersection,waterlogged=false": { "model": "create:block/chute/block_diagonal_intersection", "y": 90 }, - "facing=east,shape=intersection": { + "facing=east,shape=intersection,waterlogged=false": { "model": "create:block/chute/block_diagonal_intersection", "y": 270 }, - "facing=down,shape=window": { + "facing=down,shape=window,waterlogged=false": { "model": "create:block/chute/block_windowed" }, - "facing=north,shape=window": { + "facing=north,shape=window,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 180 }, - "facing=south,shape=window": { + "facing=south,shape=window,waterlogged=false": { "model": "create:block/chute/block_diagonal" }, - "facing=west,shape=window": { + "facing=west,shape=window,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 90 }, - "facing=east,shape=window": { + "facing=east,shape=window,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 270 }, - "facing=down,shape=normal": { + "facing=down,shape=normal,waterlogged=false": { "model": "create:block/chute/block" }, - "facing=north,shape=normal": { + "facing=north,shape=normal,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 180 }, - "facing=south,shape=normal": { + "facing=south,shape=normal,waterlogged=false": { "model": "create:block/chute/block_diagonal" }, - "facing=west,shape=normal": { + "facing=west,shape=normal,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 90 }, - "facing=east,shape=normal": { + "facing=east,shape=normal,waterlogged=false": { "model": "create:block/chute/block_diagonal", "y": 270 + }, + "facing=down,shape=encased,waterlogged=false": { + "model": "create:block/chute/block_intersection" + }, + "facing=north,shape=encased,waterlogged=false": { + "model": "create:block/chute/block_diagonal_encased", + "y": 180 + }, + "facing=south,shape=encased,waterlogged=false": { + "model": "create:block/chute/block_diagonal_encased" + }, + "facing=west,shape=encased,waterlogged=false": { + "model": "create:block/chute/block_diagonal_encased", + "y": 90 + }, + "facing=east,shape=encased,waterlogged=false": { + "model": "create:block/chute/block_diagonal_encased", + "y": 270 + }, + "facing=down,shape=intersection,waterlogged=true": { + "model": "create:block/chute/block_intersection" + }, + "facing=north,shape=intersection,waterlogged=true": { + "model": "create:block/chute/block_diagonal_intersection", + "y": 180 + }, + "facing=south,shape=intersection,waterlogged=true": { + "model": "create:block/chute/block_diagonal_intersection" + }, + "facing=west,shape=intersection,waterlogged=true": { + "model": "create:block/chute/block_diagonal_intersection", + "y": 90 + }, + "facing=east,shape=intersection,waterlogged=true": { + "model": "create:block/chute/block_diagonal_intersection", + "y": 270 + }, + "facing=down,shape=window,waterlogged=true": { + "model": "create:block/chute/block_windowed" + }, + "facing=north,shape=window,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 180 + }, + "facing=south,shape=window,waterlogged=true": { + "model": "create:block/chute/block_diagonal" + }, + "facing=west,shape=window,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 90 + }, + "facing=east,shape=window,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 270 + }, + "facing=down,shape=normal,waterlogged=true": { + "model": "create:block/chute/block" + }, + "facing=north,shape=normal,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 180 + }, + "facing=south,shape=normal,waterlogged=true": { + "model": "create:block/chute/block_diagonal" + }, + "facing=west,shape=normal,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 90 + }, + "facing=east,shape=normal,waterlogged=true": { + "model": "create:block/chute/block_diagonal", + "y": 270 + }, + "facing=down,shape=encased,waterlogged=true": { + "model": "create:block/chute/block_intersection" + }, + "facing=north,shape=encased,waterlogged=true": { + "model": "create:block/chute/block_diagonal_encased", + "y": 180 + }, + "facing=south,shape=encased,waterlogged=true": { + "model": "create:block/chute/block_diagonal_encased" + }, + "facing=west,shape=encased,waterlogged=true": { + "model": "create:block/chute/block_diagonal_encased", + "y": 90 + }, + "facing=east,shape=encased,waterlogged=true": { + "model": "create:block/chute/block_diagonal_encased", + "y": 270 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/clipboard.json b/src/generated/resources/assets/create/blockstates/clipboard.json new file mode 100644 index 0000000000..5326b5382e --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/clipboard.json @@ -0,0 +1,216 @@ +{ + "variants": { + "face=floor,facing=north,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty" + }, + "face=wall,facing=north,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90 + }, + "face=ceiling,facing=north,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 180 + }, + "face=floor,facing=south,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 180 + }, + "face=wall,facing=south,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 180 + }, + "face=ceiling,facing=south,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180 + }, + "face=floor,facing=west,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 270 + }, + "face=wall,facing=west,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 270 + }, + "face=ceiling,facing=west,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 90 + }, + "face=floor,facing=east,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 90 + }, + "face=wall,facing=east,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 90 + }, + "face=ceiling,facing=east,waterlogged=false,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 270 + }, + "face=floor,facing=north,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty" + }, + "face=wall,facing=north,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90 + }, + "face=ceiling,facing=north,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 180 + }, + "face=floor,facing=south,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 180 + }, + "face=wall,facing=south,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 180 + }, + "face=ceiling,facing=south,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180 + }, + "face=floor,facing=west,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 270 + }, + "face=wall,facing=west,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 270 + }, + "face=ceiling,facing=west,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 90 + }, + "face=floor,facing=east,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "y": 90 + }, + "face=wall,facing=east,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 90, + "y": 90 + }, + "face=ceiling,facing=east,waterlogged=true,written=false": { + "model": "create:block/clipboard/block_empty", + "x": 180, + "y": 270 + }, + "face=floor,facing=north,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written" + }, + "face=wall,facing=north,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90 + }, + "face=ceiling,facing=north,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 180 + }, + "face=floor,facing=south,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "y": 180 + }, + "face=wall,facing=south,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 180 + }, + "face=ceiling,facing=south,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180 + }, + "face=floor,facing=west,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "y": 270 + }, + "face=wall,facing=west,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 270 + }, + "face=ceiling,facing=west,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 90 + }, + "face=floor,facing=east,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "y": 90 + }, + "face=wall,facing=east,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 90 + }, + "face=ceiling,facing=east,waterlogged=false,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 270 + }, + "face=floor,facing=north,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written" + }, + "face=wall,facing=north,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90 + }, + "face=ceiling,facing=north,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 180 + }, + "face=floor,facing=south,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "y": 180 + }, + "face=wall,facing=south,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 180 + }, + "face=ceiling,facing=south,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180 + }, + "face=floor,facing=west,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "y": 270 + }, + "face=wall,facing=west,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 270 + }, + "face=ceiling,facing=west,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 90 + }, + "face=floor,facing=east,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "y": 90 + }, + "face=wall,facing=east,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 90, + "y": 90 + }, + "face=ceiling,facing=east,waterlogged=true,written=true": { + "model": "create:block/clipboard/block_written", + "x": 180, + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/content_observer.json b/src/generated/resources/assets/create/blockstates/content_observer.json index e66a1472ce..458e8b3d6d 100644 --- a/src/generated/resources/assets/create/blockstates/content_observer.json +++ b/src/generated/resources/assets/create/blockstates/content_observer.json @@ -1,34 +1,110 @@ { "variants": { - "facing=north,powered=false": { + "facing=north,powered=false,target=floor": { + "model": "create:block/content_observer/block", + "x": 90 + }, + "facing=south,powered=false,target=floor": { + "model": "create:block/content_observer/block", + "x": 90, + "y": 180 + }, + "facing=west,powered=false,target=floor": { + "model": "create:block/content_observer/block", + "x": 90, + "y": 270 + }, + "facing=east,powered=false,target=floor": { + "model": "create:block/content_observer/block", + "x": 90, + "y": 90 + }, + "facing=north,powered=true,target=floor": { + "model": "create:block/content_observer/block_powered", + "x": 90 + }, + "facing=south,powered=true,target=floor": { + "model": "create:block/content_observer/block_powered", + "x": 90, + "y": 180 + }, + "facing=west,powered=true,target=floor": { + "model": "create:block/content_observer/block_powered", + "x": 90, + "y": 270 + }, + "facing=east,powered=true,target=floor": { + "model": "create:block/content_observer/block_powered", + "x": 90, + "y": 90 + }, + "facing=north,powered=false,target=wall": { "model": "create:block/content_observer/block" }, - "facing=south,powered=false": { + "facing=south,powered=false,target=wall": { "model": "create:block/content_observer/block", "y": 180 }, - "facing=west,powered=false": { + "facing=west,powered=false,target=wall": { "model": "create:block/content_observer/block", "y": 270 }, - "facing=east,powered=false": { + "facing=east,powered=false,target=wall": { "model": "create:block/content_observer/block", "y": 90 }, - "facing=north,powered=true": { + "facing=north,powered=true,target=wall": { "model": "create:block/content_observer/block_powered" }, - "facing=south,powered=true": { + "facing=south,powered=true,target=wall": { "model": "create:block/content_observer/block_powered", "y": 180 }, - "facing=west,powered=true": { + "facing=west,powered=true,target=wall": { "model": "create:block/content_observer/block_powered", "y": 270 }, - "facing=east,powered=true": { + "facing=east,powered=true,target=wall": { "model": "create:block/content_observer/block_powered", "y": 90 + }, + "facing=north,powered=false,target=ceiling": { + "model": "create:block/content_observer/block", + "x": 270 + }, + "facing=south,powered=false,target=ceiling": { + "model": "create:block/content_observer/block", + "x": 270, + "y": 180 + }, + "facing=west,powered=false,target=ceiling": { + "model": "create:block/content_observer/block", + "x": 270, + "y": 270 + }, + "facing=east,powered=false,target=ceiling": { + "model": "create:block/content_observer/block", + "x": 270, + "y": 90 + }, + "facing=north,powered=true,target=ceiling": { + "model": "create:block/content_observer/block_powered", + "x": 270 + }, + "facing=south,powered=true,target=ceiling": { + "model": "create:block/content_observer/block_powered", + "x": 270, + "y": 180 + }, + "facing=west,powered=true,target=ceiling": { + "model": "create:block/content_observer/block_powered", + "x": 270, + "y": 270 + }, + "facing=east,powered=true,target=ceiling": { + "model": "create:block/content_observer/block_powered", + "x": 270, + "y": 90 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/contraption_controls.json b/src/generated/resources/assets/create/blockstates/contraption_controls.json new file mode 100644 index 0000000000..c2c6be7bf4 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/contraption_controls.json @@ -0,0 +1,124 @@ +{ + "variants": { + "facing=north,open=false,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=false,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=false,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=false,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=true,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=true,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=true,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=true,virtual=false,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=false,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=false,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=false,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=false,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=true,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=true,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=true,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=true,virtual=true,waterlogged=false": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=false,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=false,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=false,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=false,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=true,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=true,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=true,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=true,virtual=false,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=false,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=false,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=false,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=false,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 90 + }, + "facing=north,open=true,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block" + }, + "facing=south,open=true,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 180 + }, + "facing=west,open=true,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 270 + }, + "facing=east,open=true,virtual=true,waterlogged=true": { + "model": "create:block/contraption_controls/block", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copper_bars.json b/src/generated/resources/assets/create/blockstates/copper_bars.json new file mode 100644 index 0000000000..0f9c35e0d6 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copper_bars.json @@ -0,0 +1,100 @@ +{ + "multipart": [ + { + "apply": { + "model": "create:block/copper_post_ends" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/copper_post" + } + }, + { + "when": { + "north": "true", + "east": "false", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/copper_cap" + } + }, + { + "when": { + "north": "false", + "east": "true", + "south": "false", + "west": "false" + }, + "apply": { + "model": "create:block/copper_cap", + "y": 90 + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "true", + "west": "false" + }, + "apply": { + "model": "create:block/copper_cap_alt" + } + }, + { + "when": { + "north": "false", + "east": "false", + "south": "false", + "west": "true" + }, + "apply": { + "model": "create:block/copper_cap_alt", + "y": 90 + } + }, + { + "when": { + "north": "true" + }, + "apply": { + "model": "create:block/copper_side" + } + }, + { + "when": { + "east": "true" + }, + "apply": { + "model": "create:block/copper_side", + "y": 90 + } + }, + { + "when": { + "south": "true" + }, + "apply": { + "model": "create:block/copper_side_alt" + } + }, + { + "when": { + "west": "true" + }, + "apply": { + "model": "create:block/copper_side_alt", + "y": 90 + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copper_door.json b/src/generated/resources/assets/create/blockstates/copper_door.json new file mode 100644 index 0000000000..fd70ddc576 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copper_door.json @@ -0,0 +1,244 @@ +{ + "variants": { + "facing=north,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=false": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=false": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=north,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_top" + }, + "facing=north,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=left,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=north,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=south,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=west,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=east,half=upper,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_top" + }, + "facing=north,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=south,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=west,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=east,half=lower,hinge=right,open=false,visible=true": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=north,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_top" + }, + "facing=south,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=west,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=east,half=upper,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=north,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=south,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=west,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + }, + "facing=east,half=lower,hinge=left,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=north,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 180 + }, + "facing=south,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_top" + }, + "facing=west,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 90 + }, + "facing=east,half=upper,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_top", + "y": 270 + }, + "facing=north,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 180 + }, + "facing=south,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom" + }, + "facing=west,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 90 + }, + "facing=east,half=lower,hinge=right,open=true,visible=true": { + "model": "create:block/copper_door/block_bottom", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copper_scaffolding.json b/src/generated/resources/assets/create/blockstates/copper_scaffolding.json new file mode 100644 index 0000000000..32d6ffe911 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copper_scaffolding.json @@ -0,0 +1,10 @@ +{ + "variants": { + "bottom=false": { + "model": "create:block/copper_scaffolding" + }, + "bottom=true": { + "model": "create:block/copper_scaffolding_horizontal" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_bars.json b/src/generated/resources/assets/create/blockstates/copycat_bars.json new file mode 100644 index 0000000000..440833baf8 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_bars.json @@ -0,0 +1,26 @@ +{ + "variants": { + "facing=down": { + "model": "create:block/copycat_panel/bars_vertical", + "x": 180 + }, + "facing=up": { + "model": "create:block/copycat_panel/bars_vertical" + }, + "facing=north": { + "model": "create:block/copycat_panel/bars", + "y": 180 + }, + "facing=south": { + "model": "create:block/copycat_panel/bars" + }, + "facing=west": { + "model": "create:block/copycat_panel/bars", + "y": 90 + }, + "facing=east": { + "model": "create:block/copycat_panel/bars", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_base.json b/src/generated/resources/assets/create/blockstates/copycat_base.json new file mode 100644 index 0000000000..739d7181a4 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_base.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "create:block/copycat_base/block" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_panel.json b/src/generated/resources/assets/create/blockstates/copycat_panel.json new file mode 100644 index 0000000000..2c8f02f067 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_panel.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_step.json b/src/generated/resources/assets/create/blockstates/copycat_step.json new file mode 100644 index 0000000000..2c8f02f067 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_step.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/crimsite.json b/src/generated/resources/assets/create/blockstates/crimsite.json index 61ca89d58a..495e95c1f7 100644 --- a/src/generated/resources/assets/create/blockstates/crimsite.json +++ b/src/generated/resources/assets/create/blockstates/crimsite.json @@ -1,7 +1,18 @@ { "variants": { - "": { - "model": "create:block/crimsite" - } + "": [ + { + "model": "create:block/crimsite_natural_0" + }, + { + "model": "create:block/crimsite_natural_1" + }, + { + "model": "create:block/crimsite_natural_2" + }, + { + "model": "create:block/crimsite_natural_3" + } + ] } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/crushing_wheel.json b/src/generated/resources/assets/create/blockstates/crushing_wheel.json index b0a631e3a3..f358bb1cf1 100644 --- a/src/generated/resources/assets/create/blockstates/crushing_wheel.json +++ b/src/generated/resources/assets/create/blockstates/crushing_wheel.json @@ -1,15 +1,15 @@ { "variants": { "axis=x": { - "model": "create:block/crushing_wheel", + "model": "create:block/crushing_wheel/block", "x": 90, "y": 90 }, "axis=y": { - "model": "create:block/crushing_wheel" + "model": "create:block/crushing_wheel/block" }, "axis=z": { - "model": "create:block/crushing_wheel", + "model": "create:block/crushing_wheel/block", "x": 90, "y": 180 } diff --git a/src/generated/resources/assets/create/blockstates/elevator_contact.json b/src/generated/resources/assets/create/blockstates/elevator_contact.json new file mode 100644 index 0000000000..33bbc03f6e --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/elevator_contact.json @@ -0,0 +1,212 @@ +{ + "variants": { + "calling=false,facing=down,powered=false,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 180 + }, + "calling=true,facing=down,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 180 + }, + "calling=false,facing=up,powered=false,powering=false": { + "model": "create:block/elevator_contact/block" + }, + "calling=true,facing=up,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim" + }, + "calling=false,facing=north,powered=false,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90 + }, + "calling=true,facing=north,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90 + }, + "calling=false,facing=south,powered=false,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 180 + }, + "calling=true,facing=south,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 180 + }, + "calling=false,facing=west,powered=false,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 270 + }, + "calling=true,facing=west,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 270 + }, + "calling=false,facing=east,powered=false,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 90 + }, + "calling=true,facing=east,powered=false,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 90 + }, + "calling=false,facing=down,powered=true,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 180 + }, + "calling=true,facing=down,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 180 + }, + "calling=false,facing=up,powered=true,powering=false": { + "model": "create:block/elevator_contact/block" + }, + "calling=true,facing=up,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim" + }, + "calling=false,facing=north,powered=true,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90 + }, + "calling=true,facing=north,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90 + }, + "calling=false,facing=south,powered=true,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 180 + }, + "calling=true,facing=south,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 180 + }, + "calling=false,facing=west,powered=true,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 270 + }, + "calling=true,facing=west,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 270 + }, + "calling=false,facing=east,powered=true,powering=false": { + "model": "create:block/elevator_contact/block", + "x": 90, + "y": 90 + }, + "calling=true,facing=east,powered=true,powering=false": { + "model": "create:block/elevator_contact/block_dim", + "x": 90, + "y": 90 + }, + "calling=false,facing=down,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 180 + }, + "calling=true,facing=down,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 180 + }, + "calling=false,facing=up,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered" + }, + "calling=true,facing=up,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered" + }, + "calling=false,facing=north,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90 + }, + "calling=true,facing=north,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90 + }, + "calling=false,facing=south,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 180 + }, + "calling=true,facing=south,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 180 + }, + "calling=false,facing=west,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 270 + }, + "calling=true,facing=west,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 270 + }, + "calling=false,facing=east,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 90 + }, + "calling=true,facing=east,powered=false,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 90 + }, + "calling=false,facing=down,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 180 + }, + "calling=true,facing=down,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 180 + }, + "calling=false,facing=up,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered" + }, + "calling=true,facing=up,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered" + }, + "calling=false,facing=north,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90 + }, + "calling=true,facing=north,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90 + }, + "calling=false,facing=south,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 180 + }, + "calling=true,facing=south,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 180 + }, + "calling=false,facing=west,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 270 + }, + "calling=true,facing=west,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 270 + }, + "calling=false,facing=east,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 90 + }, + "calling=true,facing=east,powered=true,powering=true": { + "model": "create:block/elevator_contact/block_powered", + "x": 90, + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/elevator_pulley.json b/src/generated/resources/assets/create/blockstates/elevator_pulley.json new file mode 100644 index 0000000000..b01fd9b7de --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/elevator_pulley.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=north": { + "model": "create:block/elevator_pulley/block" + }, + "facing=south": { + "model": "create:block/elevator_pulley/block", + "y": 180 + }, + "facing=west": { + "model": "create:block/elevator_pulley/block", + "y": 270 + }, + "facing=east": { + "model": "create:block/elevator_pulley/block", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/experience_block.json b/src/generated/resources/assets/create/blockstates/experience_block.json new file mode 100644 index 0000000000..96bde6400a --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/experience_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "create:block/experience_block" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/industrial_iron_block.json b/src/generated/resources/assets/create/blockstates/industrial_iron_block.json new file mode 100644 index 0000000000..c38604b94d --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/industrial_iron_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "create:block/industrial_iron_block" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/large_water_wheel.json b/src/generated/resources/assets/create/blockstates/large_water_wheel.json new file mode 100644 index 0000000000..7adbe2185f --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/large_water_wheel.json @@ -0,0 +1,30 @@ +{ + "variants": { + "axis=x,extension=false": { + "model": "create:block/large_water_wheel/block", + "x": 90, + "y": 90 + }, + "axis=y,extension=false": { + "model": "create:block/large_water_wheel/block" + }, + "axis=z,extension=false": { + "model": "create:block/large_water_wheel/block", + "x": 90, + "y": 180 + }, + "axis=x,extension=true": { + "model": "create:block/large_water_wheel/block_extension", + "x": 90, + "y": 90 + }, + "axis=y,extension=true": { + "model": "create:block/large_water_wheel/block_extension" + }, + "axis=z,extension=true": { + "model": "create:block/large_water_wheel/block_extension", + "x": 90, + "y": 180 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/mechanical_harvester.json b/src/generated/resources/assets/create/blockstates/mechanical_harvester.json index 3c36b86270..bb5b3b0d5d 100644 --- a/src/generated/resources/assets/create/blockstates/mechanical_harvester.json +++ b/src/generated/resources/assets/create/blockstates/mechanical_harvester.json @@ -1,17 +1,32 @@ { "variants": { - "facing=north": { + "facing=north,waterlogged=false": { "model": "create:block/mechanical_harvester/block" }, - "facing=south": { + "facing=south,waterlogged=false": { "model": "create:block/mechanical_harvester/block", "y": 180 }, - "facing=west": { + "facing=west,waterlogged=false": { "model": "create:block/mechanical_harvester/block", "y": 270 }, - "facing=east": { + "facing=east,waterlogged=false": { + "model": "create:block/mechanical_harvester/block", + "y": 90 + }, + "facing=north,waterlogged=true": { + "model": "create:block/mechanical_harvester/block" + }, + "facing=south,waterlogged=true": { + "model": "create:block/mechanical_harvester/block", + "y": 180 + }, + "facing=west,waterlogged=true": { + "model": "create:block/mechanical_harvester/block", + "y": 270 + }, + "facing=east,waterlogged=true": { "model": "create:block/mechanical_harvester/block", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/mechanical_plough.json b/src/generated/resources/assets/create/blockstates/mechanical_plough.json index 83bfa6dbd2..6d273fdc85 100644 --- a/src/generated/resources/assets/create/blockstates/mechanical_plough.json +++ b/src/generated/resources/assets/create/blockstates/mechanical_plough.json @@ -1,17 +1,32 @@ { "variants": { - "facing=north": { + "facing=north,waterlogged=false": { "model": "create:block/mechanical_plough" }, - "facing=south": { + "facing=south,waterlogged=false": { "model": "create:block/mechanical_plough", "y": 180 }, - "facing=west": { + "facing=west,waterlogged=false": { "model": "create:block/mechanical_plough", "y": 270 }, - "facing=east": { + "facing=east,waterlogged=false": { + "model": "create:block/mechanical_plough", + "y": 90 + }, + "facing=north,waterlogged=true": { + "model": "create:block/mechanical_plough" + }, + "facing=south,waterlogged=true": { + "model": "create:block/mechanical_plough", + "y": 180 + }, + "facing=west,waterlogged=true": { + "model": "create:block/mechanical_plough", + "y": 270 + }, + "facing=east,waterlogged=true": { "model": "create:block/mechanical_plough", "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/mechanical_roller.json b/src/generated/resources/assets/create/blockstates/mechanical_roller.json new file mode 100644 index 0000000000..128a164eda --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/mechanical_roller.json @@ -0,0 +1,34 @@ +{ + "variants": { + "facing=north,waterlogged=false": { + "model": "create:block/mechanical_roller/block" + }, + "facing=south,waterlogged=false": { + "model": "create:block/mechanical_roller/block", + "y": 180 + }, + "facing=west,waterlogged=false": { + "model": "create:block/mechanical_roller/block", + "y": 270 + }, + "facing=east,waterlogged=false": { + "model": "create:block/mechanical_roller/block", + "y": 90 + }, + "facing=north,waterlogged=true": { + "model": "create:block/mechanical_roller/block" + }, + "facing=south,waterlogged=true": { + "model": "create:block/mechanical_roller/block", + "y": 180 + }, + "facing=west,waterlogged=true": { + "model": "create:block/mechanical_roller/block", + "y": 270 + }, + "facing=east,waterlogged=true": { + "model": "create:block/mechanical_roller/block", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/mechanical_saw.json b/src/generated/resources/assets/create/blockstates/mechanical_saw.json index bad1bc6d7f..7a2ed12f76 100644 --- a/src/generated/resources/assets/create/blockstates/mechanical_saw.json +++ b/src/generated/resources/assets/create/blockstates/mechanical_saw.json @@ -1,48 +1,96 @@ { "variants": { - "axis_along_first=false,facing=down": { + "axis_along_first=false,facing=down,flipped=false": { "model": "create:block/mechanical_saw/vertical", "x": 180 }, - "axis_along_first=true,facing=down": { + "axis_along_first=true,facing=down,flipped=false": { + "model": "create:block/mechanical_saw/vertical", + "x": 180, + "y": 270 + }, + "axis_along_first=false,facing=up,flipped=false": { + "model": "create:block/mechanical_saw/vertical" + }, + "axis_along_first=true,facing=up,flipped=false": { + "model": "create:block/mechanical_saw/vertical", + "y": 270 + }, + "axis_along_first=false,facing=north,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 180 + }, + "axis_along_first=true,facing=north,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 180 + }, + "axis_along_first=false,facing=south,flipped=false": { + "model": "create:block/mechanical_saw/horizontal" + }, + "axis_along_first=true,facing=south,flipped=false": { + "model": "create:block/mechanical_saw/horizontal" + }, + "axis_along_first=false,facing=west,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 90 + }, + "axis_along_first=true,facing=west,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 90 + }, + "axis_along_first=false,facing=east,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 270 + }, + "axis_along_first=true,facing=east,flipped=false": { + "model": "create:block/mechanical_saw/horizontal", + "y": 270 + }, + "axis_along_first=false,facing=down,flipped=true": { + "model": "create:block/mechanical_saw/vertical", + "x": 180, + "y": 180 + }, + "axis_along_first=true,facing=down,flipped=true": { "model": "create:block/mechanical_saw/vertical", "x": 180, "y": 90 }, - "axis_along_first=false,facing=up": { - "model": "create:block/mechanical_saw/vertical" + "axis_along_first=false,facing=up,flipped=true": { + "model": "create:block/mechanical_saw/vertical", + "y": 180 }, - "axis_along_first=true,facing=up": { + "axis_along_first=true,facing=up,flipped=true": { "model": "create:block/mechanical_saw/vertical", "y": 90 }, - "axis_along_first=false,facing=north": { + "axis_along_first=false,facing=north,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 180 }, - "axis_along_first=true,facing=north": { + "axis_along_first=true,facing=north,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 180 }, - "axis_along_first=false,facing=south": { + "axis_along_first=false,facing=south,flipped=true": { "model": "create:block/mechanical_saw/horizontal" }, - "axis_along_first=true,facing=south": { + "axis_along_first=true,facing=south,flipped=true": { "model": "create:block/mechanical_saw/horizontal" }, - "axis_along_first=false,facing=west": { + "axis_along_first=false,facing=west,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 90 }, - "axis_along_first=true,facing=west": { + "axis_along_first=true,facing=west,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 90 }, - "axis_along_first=false,facing=east": { + "axis_along_first=false,facing=east,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 270 }, - "axis_along_first=true,facing=east": { + "axis_along_first=true,facing=east,flipped=true": { "model": "create:block/mechanical_saw/horizontal", "y": 270 } diff --git a/src/generated/resources/assets/create/blockstates/netherite_backtank.json b/src/generated/resources/assets/create/blockstates/netherite_backtank.json new file mode 100644 index 0000000000..c8113d1068 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/netherite_backtank.json @@ -0,0 +1,34 @@ +{ + "variants": { + "facing=north,waterlogged=false": { + "model": "create:block/netherite_backtank/block" + }, + "facing=south,waterlogged=false": { + "model": "create:block/netherite_backtank/block", + "y": 180 + }, + "facing=west,waterlogged=false": { + "model": "create:block/netherite_backtank/block", + "y": 270 + }, + "facing=east,waterlogged=false": { + "model": "create:block/netherite_backtank/block", + "y": 90 + }, + "facing=north,waterlogged=true": { + "model": "create:block/netherite_backtank/block" + }, + "facing=south,waterlogged=true": { + "model": "create:block/netherite_backtank/block", + "y": 180 + }, + "facing=west,waterlogged=true": { + "model": "create:block/netherite_backtank/block", + "y": 270 + }, + "facing=east,waterlogged=true": { + "model": "create:block/netherite_backtank/block", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/ochrum.json b/src/generated/resources/assets/create/blockstates/ochrum.json index cc43d8475b..024cf71fbd 100644 --- a/src/generated/resources/assets/create/blockstates/ochrum.json +++ b/src/generated/resources/assets/create/blockstates/ochrum.json @@ -1,7 +1,18 @@ { "variants": { - "": { - "model": "create:block/ochrum" - } + "": [ + { + "model": "create:block/ochrum_natural_0" + }, + { + "model": "create:block/ochrum_natural_1" + }, + { + "model": "create:block/ochrum_natural_2" + }, + { + "model": "create:block/ochrum_natural_3" + } + ] } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/stockpile_switch.json b/src/generated/resources/assets/create/blockstates/stockpile_switch.json index c5f9e6ae3d..f270ea11c3 100644 --- a/src/generated/resources/assets/create/blockstates/stockpile_switch.json +++ b/src/generated/resources/assets/create/blockstates/stockpile_switch.json @@ -1,108 +1,273 @@ { "variants": { - "facing=north,indicator=0": { - "model": "create:block/stockpile_switch_0" + "facing=north,level=0,target=floor": { + "model": "create:threshold_switch/block_floor_0" }, - "facing=south,indicator=0": { - "model": "create:block/stockpile_switch_0", + "facing=south,level=0,target=floor": { + "model": "create:threshold_switch/block_floor_0", "y": 180 }, - "facing=west,indicator=0": { - "model": "create:block/stockpile_switch_0", + "facing=west,level=0,target=floor": { + "model": "create:threshold_switch/block_floor_0", "y": 270 }, - "facing=east,indicator=0": { - "model": "create:block/stockpile_switch_0", + "facing=east,level=0,target=floor": { + "model": "create:threshold_switch/block_floor_0", "y": 90 }, - "facing=north,indicator=1": { - "model": "create:block/stockpile_switch_1" + "facing=north,level=1,target=floor": { + "model": "create:threshold_switch/block_floor_1" }, - "facing=south,indicator=1": { - "model": "create:block/stockpile_switch_1", + "facing=south,level=1,target=floor": { + "model": "create:threshold_switch/block_floor_1", "y": 180 }, - "facing=west,indicator=1": { - "model": "create:block/stockpile_switch_1", + "facing=west,level=1,target=floor": { + "model": "create:threshold_switch/block_floor_1", "y": 270 }, - "facing=east,indicator=1": { - "model": "create:block/stockpile_switch_1", + "facing=east,level=1,target=floor": { + "model": "create:threshold_switch/block_floor_1", "y": 90 }, - "facing=north,indicator=2": { - "model": "create:block/stockpile_switch_2" + "facing=north,level=2,target=floor": { + "model": "create:threshold_switch/block_floor_2" }, - "facing=south,indicator=2": { - "model": "create:block/stockpile_switch_2", + "facing=south,level=2,target=floor": { + "model": "create:threshold_switch/block_floor_2", "y": 180 }, - "facing=west,indicator=2": { - "model": "create:block/stockpile_switch_2", + "facing=west,level=2,target=floor": { + "model": "create:threshold_switch/block_floor_2", "y": 270 }, - "facing=east,indicator=2": { - "model": "create:block/stockpile_switch_2", + "facing=east,level=2,target=floor": { + "model": "create:threshold_switch/block_floor_2", "y": 90 }, - "facing=north,indicator=3": { - "model": "create:block/stockpile_switch_3" + "facing=north,level=3,target=floor": { + "model": "create:threshold_switch/block_floor_3" }, - "facing=south,indicator=3": { - "model": "create:block/stockpile_switch_3", + "facing=south,level=3,target=floor": { + "model": "create:threshold_switch/block_floor_3", "y": 180 }, - "facing=west,indicator=3": { - "model": "create:block/stockpile_switch_3", + "facing=west,level=3,target=floor": { + "model": "create:threshold_switch/block_floor_3", "y": 270 }, - "facing=east,indicator=3": { - "model": "create:block/stockpile_switch_3", + "facing=east,level=3,target=floor": { + "model": "create:threshold_switch/block_floor_3", "y": 90 }, - "facing=north,indicator=4": { - "model": "create:block/stockpile_switch_4" + "facing=north,level=4,target=floor": { + "model": "create:threshold_switch/block_floor_4" }, - "facing=south,indicator=4": { - "model": "create:block/stockpile_switch_4", + "facing=south,level=4,target=floor": { + "model": "create:threshold_switch/block_floor_4", "y": 180 }, - "facing=west,indicator=4": { - "model": "create:block/stockpile_switch_4", + "facing=west,level=4,target=floor": { + "model": "create:threshold_switch/block_floor_4", "y": 270 }, - "facing=east,indicator=4": { - "model": "create:block/stockpile_switch_4", + "facing=east,level=4,target=floor": { + "model": "create:threshold_switch/block_floor_4", "y": 90 }, - "facing=north,indicator=5": { - "model": "create:block/stockpile_switch_5" + "facing=north,level=5,target=floor": { + "model": "create:threshold_switch/block_floor_5" }, - "facing=south,indicator=5": { - "model": "create:block/stockpile_switch_5", + "facing=south,level=5,target=floor": { + "model": "create:threshold_switch/block_floor_5", "y": 180 }, - "facing=west,indicator=5": { - "model": "create:block/stockpile_switch_5", + "facing=west,level=5,target=floor": { + "model": "create:threshold_switch/block_floor_5", "y": 270 }, - "facing=east,indicator=5": { - "model": "create:block/stockpile_switch_5", + "facing=east,level=5,target=floor": { + "model": "create:threshold_switch/block_floor_5", "y": 90 }, - "facing=north,indicator=6": { - "model": "create:block/stockpile_switch_6" + "facing=north,level=0,target=wall": { + "model": "create:threshold_switch/block_wall_0" }, - "facing=south,indicator=6": { - "model": "create:block/stockpile_switch_6", + "facing=south,level=0,target=wall": { + "model": "create:threshold_switch/block_wall_0", "y": 180 }, - "facing=west,indicator=6": { - "model": "create:block/stockpile_switch_6", + "facing=west,level=0,target=wall": { + "model": "create:threshold_switch/block_wall_0", "y": 270 }, - "facing=east,indicator=6": { - "model": "create:block/stockpile_switch_6", + "facing=east,level=0,target=wall": { + "model": "create:threshold_switch/block_wall_0", + "y": 90 + }, + "facing=north,level=1,target=wall": { + "model": "create:threshold_switch/block_wall_1" + }, + "facing=south,level=1,target=wall": { + "model": "create:threshold_switch/block_wall_1", + "y": 180 + }, + "facing=west,level=1,target=wall": { + "model": "create:threshold_switch/block_wall_1", + "y": 270 + }, + "facing=east,level=1,target=wall": { + "model": "create:threshold_switch/block_wall_1", + "y": 90 + }, + "facing=north,level=2,target=wall": { + "model": "create:threshold_switch/block_wall_2" + }, + "facing=south,level=2,target=wall": { + "model": "create:threshold_switch/block_wall_2", + "y": 180 + }, + "facing=west,level=2,target=wall": { + "model": "create:threshold_switch/block_wall_2", + "y": 270 + }, + "facing=east,level=2,target=wall": { + "model": "create:threshold_switch/block_wall_2", + "y": 90 + }, + "facing=north,level=3,target=wall": { + "model": "create:threshold_switch/block_wall_3" + }, + "facing=south,level=3,target=wall": { + "model": "create:threshold_switch/block_wall_3", + "y": 180 + }, + "facing=west,level=3,target=wall": { + "model": "create:threshold_switch/block_wall_3", + "y": 270 + }, + "facing=east,level=3,target=wall": { + "model": "create:threshold_switch/block_wall_3", + "y": 90 + }, + "facing=north,level=4,target=wall": { + "model": "create:threshold_switch/block_wall_4" + }, + "facing=south,level=4,target=wall": { + "model": "create:threshold_switch/block_wall_4", + "y": 180 + }, + "facing=west,level=4,target=wall": { + "model": "create:threshold_switch/block_wall_4", + "y": 270 + }, + "facing=east,level=4,target=wall": { + "model": "create:threshold_switch/block_wall_4", + "y": 90 + }, + "facing=north,level=5,target=wall": { + "model": "create:threshold_switch/block_wall_5" + }, + "facing=south,level=5,target=wall": { + "model": "create:threshold_switch/block_wall_5", + "y": 180 + }, + "facing=west,level=5,target=wall": { + "model": "create:threshold_switch/block_wall_5", + "y": 270 + }, + "facing=east,level=5,target=wall": { + "model": "create:threshold_switch/block_wall_5", + "y": 90 + }, + "facing=north,level=0,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_0" + }, + "facing=south,level=0,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_0", + "y": 180 + }, + "facing=west,level=0,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_0", + "y": 270 + }, + "facing=east,level=0,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_0", + "y": 90 + }, + "facing=north,level=1,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_1" + }, + "facing=south,level=1,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_1", + "y": 180 + }, + "facing=west,level=1,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_1", + "y": 270 + }, + "facing=east,level=1,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_1", + "y": 90 + }, + "facing=north,level=2,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_2" + }, + "facing=south,level=2,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_2", + "y": 180 + }, + "facing=west,level=2,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_2", + "y": 270 + }, + "facing=east,level=2,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_2", + "y": 90 + }, + "facing=north,level=3,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_3" + }, + "facing=south,level=3,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_3", + "y": 180 + }, + "facing=west,level=3,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_3", + "y": 270 + }, + "facing=east,level=3,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_3", + "y": 90 + }, + "facing=north,level=4,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_4" + }, + "facing=south,level=4,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_4", + "y": 180 + }, + "facing=west,level=4,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_4", + "y": 270 + }, + "facing=east,level=4,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_4", + "y": 90 + }, + "facing=north,level=5,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_5" + }, + "facing=south,level=5,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_5", + "y": 180 + }, + "facing=west,level=5,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_5", + "y": 270 + }, + "facing=east,level=5,target=ceiling": { + "model": "create:threshold_switch/block_ceiling_5", "y": 90 } } diff --git a/src/generated/resources/assets/create/blockstates/veridium.json b/src/generated/resources/assets/create/blockstates/veridium.json index 447fd84cd3..5e9b5c9811 100644 --- a/src/generated/resources/assets/create/blockstates/veridium.json +++ b/src/generated/resources/assets/create/blockstates/veridium.json @@ -1,7 +1,18 @@ { "variants": { - "": { - "model": "create:block/veridium" - } + "": [ + { + "model": "create:block/veridium_natural_0" + }, + { + "model": "create:block/veridium_natural_1" + }, + { + "model": "create:block/veridium_natural_2" + }, + { + "model": "create:block/veridium_natural_3" + } + ] } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/water_wheel.json b/src/generated/resources/assets/create/blockstates/water_wheel.json index fe99163dfb..f6e3c566a9 100644 --- a/src/generated/resources/assets/create/blockstates/water_wheel.json +++ b/src/generated/resources/assets/create/blockstates/water_wheel.json @@ -1,28 +1,28 @@ { "variants": { "facing=down": { - "model": "create:block/water_wheel", + "model": "create:block/water_wheel/block", "x": 180 }, "facing=up": { - "model": "create:block/water_wheel" + "model": "create:block/water_wheel/block" }, "facing=north": { - "model": "create:block/water_wheel", + "model": "create:block/water_wheel/block", "x": 90 }, "facing=south": { - "model": "create:block/water_wheel", + "model": "create:block/water_wheel/block", "x": 90, "y": 180 }, "facing=west": { - "model": "create:block/water_wheel", + "model": "create:block/water_wheel/block", "x": 90, "y": 270 }, "facing=east": { - "model": "create:block/water_wheel", + "model": "create:block/water_wheel/block", "x": 90, "y": 90 } diff --git a/src/generated/resources/assets/create/blockstates/water_wheel_structure.json b/src/generated/resources/assets/create/blockstates/water_wheel_structure.json new file mode 100644 index 0000000000..2c8f02f067 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/water_wheel_structure.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/weighted_ejector.json b/src/generated/resources/assets/create/blockstates/weighted_ejector.json index 12044c3dbe..656e61b6c5 100644 --- a/src/generated/resources/assets/create/blockstates/weighted_ejector.json +++ b/src/generated/resources/assets/create/blockstates/weighted_ejector.json @@ -1,17 +1,32 @@ { "variants": { - "facing=north": { + "facing=north,waterlogged=false": { "model": "create:block/weighted_ejector/block" }, - "facing=south": { + "facing=south,waterlogged=false": { "model": "create:block/weighted_ejector/block", "y": 180 }, - "facing=west": { + "facing=west,waterlogged=false": { "model": "create:block/weighted_ejector/block", "y": 270 }, - "facing=east": { + "facing=east,waterlogged=false": { + "model": "create:block/weighted_ejector/block", + "y": 90 + }, + "facing=north,waterlogged=true": { + "model": "create:block/weighted_ejector/block" + }, + "facing=south,waterlogged=true": { + "model": "create:block/weighted_ejector/block", + "y": 180 + }, + "facing=west,waterlogged=true": { + "model": "create:block/weighted_ejector/block", + "y": 270 + }, + "facing=east,waterlogged=true": { "model": "create:block/weighted_ejector/block", "y": 90 } diff --git a/src/generated/resources/assets/create/lang/en_ud.json b/src/generated/resources/assets/create/lang/en_ud.json index d57821dd53..3e038f2daf 100644 --- a/src/generated/resources/assets/create/lang/en_ud.json +++ b/src/generated/resources/assets/create/lang/en_ud.json @@ -3,14 +3,18 @@ "block.create.acacia_window_pane": "\u01DDu\u0250\u0500 \u028Dopu\u0131M \u0250\u0131\u0254\u0250\u0254\u2C6F", "block.create.adjustable_chain_gearshift": "\u0287\u025F\u0131\u0265s\u0279\u0250\u01DD\u2141 u\u0131\u0250\u0265\u0186 \u01DD\u05DFq\u0250\u0287sn\u0638p\u2C6F", "block.create.analog_lever": "\u0279\u01DD\u028C\u01DD\uA780 bo\u05DF\u0250u\u2C6F", + "block.create.andesite_alloy_block": "\u028Eo\u05DF\u05DF\u2C6F \u01DD\u0287\u0131s\u01DDpu\u2C6F \u025Fo \u029E\u0254o\u05DF\u15FA", + "block.create.andesite_bars": "s\u0279\u0250\u15FA \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_belt_funnel": "\u05DF\u01DDuun\u2132 \u0287\u05DF\u01DD\u15FA \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_casing": "bu\u0131s\u0250\u0186 \u01DD\u0287\u0131s\u01DDpu\u2C6F", + "block.create.andesite_door": "\u0279oo\u15E1 \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_encased_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 p\u01DDs\u0250\u0254u\u018E \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_encased_large_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 \u01DDb\u0279\u0250\uA780 p\u01DDs\u0250\u0254u\u018E \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_encased_shaft": "\u0287\u025F\u0250\u0265S p\u01DDs\u0250\u0254u\u018E \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_funnel": "\u05DF\u01DDuun\u2132 \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_ladder": "\u0279\u01DDpp\u0250\uA780 \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 \u01DD\u0287\u0131s\u01DDpu\u2C6F", + "block.create.andesite_scaffolding": "bu\u0131p\u05DFo\u025F\u025F\u0250\u0254S \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.andesite_tunnel": "\u05DF\u01DDuun\u27D8 \u01DD\u0287\u0131s\u01DDpu\u2C6F", "block.create.asurine": "\u01DDu\u0131\u0279ns\u2C6F", "block.create.asurine_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 \u01DDu\u0131\u0279ns\u2C6F", @@ -29,14 +33,17 @@ "block.create.blue_seat": "\u0287\u0250\u01DDS \u01DDn\u05DF\u15FA", "block.create.blue_toolbox": "xoq\u05DFoo\u27D8 \u01DDn\u05DF\u15FA", "block.create.blue_valve_handle": "\u01DD\u05DFpu\u0250H \u01DD\u028C\u05DF\u0250\u039B \u01DDn\u05DF\u15FA", + "block.create.brass_bars": "s\u0279\u0250\u15FA ss\u0250\u0279\u15FA", "block.create.brass_belt_funnel": "\u05DF\u01DDuun\u2132 \u0287\u05DF\u01DD\u15FA ss\u0250\u0279\u15FA", "block.create.brass_block": "ss\u0250\u0279\u15FA \u025Fo \u029E\u0254o\u05DF\u15FA", "block.create.brass_casing": "bu\u0131s\u0250\u0186 ss\u0250\u0279\u15FA", + "block.create.brass_door": "\u0279oo\u15E1 ss\u0250\u0279\u15FA", "block.create.brass_encased_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 p\u01DDs\u0250\u0254u\u018E ss\u0250\u0279\u15FA", "block.create.brass_encased_large_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 \u01DDb\u0279\u0250\uA780 p\u01DDs\u0250\u0254u\u018E ss\u0250\u0279\u15FA", "block.create.brass_encased_shaft": "\u0287\u025F\u0250\u0265S p\u01DDs\u0250\u0254u\u018E ss\u0250\u0279\u15FA", "block.create.brass_funnel": "\u05DF\u01DDuun\u2132 ss\u0250\u0279\u15FA", "block.create.brass_ladder": "\u0279\u01DDpp\u0250\uA780 ss\u0250\u0279\u15FA", + "block.create.brass_scaffolding": "bu\u0131p\u05DFo\u025F\u025F\u0250\u0254S ss\u0250\u0279\u15FA", "block.create.brass_tunnel": "\u05DF\u01DDuun\u27D8 ss\u0250\u0279\u15FA", "block.create.brown_nixie_tube": "\u01DDqn\u27D8 \u01DD\u0131x\u0131N u\u028Do\u0279\u15FA", "block.create.brown_sail": "\u05DF\u0131\u0250S u\u028Do\u0279\u15FA", @@ -47,15 +54,20 @@ "block.create.cart_assembler": "\u0279\u01DD\u05DFq\u026F\u01DDss\u2C6F \u0287\u0279\u0250\u0186", "block.create.chocolate": "\u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186", "block.create.chute": "\u01DD\u0287n\u0265\u0186", + "block.create.clipboard": "p\u0279\u0250oqd\u0131\u05DF\u0186", "block.create.clockwork_bearing": "bu\u0131\u0279\u0250\u01DD\u15FA \u029E\u0279o\u028D\u029E\u0254o\u05DF\u0186", "block.create.clutch": "\u0265\u0254\u0287n\u05DF\u0186", "block.create.cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186", - "block.create.content_observer": "\u0279\u01DD\u028C\u0279\u01DDsqO \u0287u\u01DD\u0287uo\u0186", + "block.create.content_observer": "\u0279\u01DD\u028C\u0279\u01DDsqO \u0287\u0279\u0250\u026FS", + "block.create.contraption_controls": "s\u05DFo\u0279\u0287uo\u0186 uo\u0131\u0287d\u0250\u0279\u0287uo\u0186", "block.create.controller_rail": "\u05DF\u0131\u0250\u1D1A \u0279\u01DD\u05DF\u05DFo\u0279\u0287uo\u0186", "block.create.controls": "s\u05DFo\u0279\u0287uo\u0186 u\u0131\u0250\u0279\u27D8", "block.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186", + "block.create.copper_bars": "s\u0279\u0250\u15FA \u0279\u01DDddo\u0186", "block.create.copper_casing": "bu\u0131s\u0250\u0186 \u0279\u01DDddo\u0186", + "block.create.copper_door": "\u0279oo\u15E1 \u0279\u01DDddo\u0186", "block.create.copper_ladder": "\u0279\u01DDpp\u0250\uA780 \u0279\u01DDddo\u0186", + "block.create.copper_scaffolding": "bu\u0131p\u05DFo\u025F\u025F\u0250\u0254S \u0279\u01DDddo\u0186", "block.create.copper_shingle_slab": "q\u0250\u05DFS \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186", "block.create.copper_shingle_stairs": "s\u0279\u0131\u0250\u0287S \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186", "block.create.copper_shingles": "s\u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186", @@ -63,6 +75,10 @@ "block.create.copper_tile_stairs": "s\u0279\u0131\u0250\u0287S \u01DD\u05DF\u0131\u27D8 \u0279\u01DDddo\u0186", "block.create.copper_tiles": "s\u01DD\u05DF\u0131\u27D8 \u0279\u01DDddo\u0186", "block.create.copper_valve_handle": "\u01DD\u05DFpu\u0250H \u01DD\u028C\u05DF\u0250\u039B \u0279\u01DDddo\u0186", + "block.create.copycat_bars": "s\u0279\u0250\u15FA \u0287\u0250\u0254\u028Edo\u0186", + "block.create.copycat_base": "\u01DDs\u0250\u15FA \u0287\u0250\u0254\u028Edo\u0186", + "block.create.copycat_panel": "\u05DF\u01DDu\u0250\u0500 \u0287\u0250\u0254\u028Edo\u0186", + "block.create.copycat_step": "d\u01DD\u0287S \u0287\u0250\u0254\u028Edo\u0186", "block.create.creative_crate": "\u01DD\u0287\u0250\u0279\u0186 \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186", "block.create.creative_fluid_tank": "\u029Eu\u0250\u27D8 p\u0131n\u05DF\u2132 \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186", "block.create.creative_motor": "\u0279o\u0287oW \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186", @@ -200,9 +216,12 @@ "block.create.display_board": "p\u0279\u0250o\u15FA \u028E\u0250\u05DFds\u0131\u15E1", "block.create.display_link": "\u029Eu\u0131\uA780 \u028E\u0250\u05DFds\u0131\u15E1", "block.create.dripstone_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 \u01DDuo\u0287sd\u0131\u0279\u15E1", + "block.create.elevator_contact": "\u0287\u0254\u0250\u0287uo\u0186 \u0279o\u0287\u0250\u028C\u01DD\u05DF\u018E", + "block.create.elevator_pulley": "\u028E\u01DD\u05DF\u05DFn\u0500 \u0279o\u0287\u0250\u028C\u01DD\u05DF\u018E", "block.create.encased_chain_drive": "\u01DD\u028C\u0131\u0279\u15E1 u\u0131\u0250\u0265\u0186 p\u01DDs\u0250\u0254u\u018E", "block.create.encased_fan": "u\u0250\u2132 p\u01DDs\u0250\u0254u\u018E", "block.create.encased_fluid_pipe": "\u01DDd\u0131\u0500 p\u0131n\u05DF\u2132 p\u01DDs\u0250\u0254u\u018E", + "block.create.experience_block": "\u01DD\u0254u\u01DD\u0131\u0279\u01DDdx\u018E \u025Fo \u029E\u0254o\u05DF\u15FA", "block.create.exposed_copper_shingle_slab": "q\u0250\u05DFS \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDsodx\u018E", "block.create.exposed_copper_shingle_stairs": "s\u0279\u0131\u0250\u0287S \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDsodx\u018E", "block.create.exposed_copper_shingles": "s\u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDsodx\u018E", @@ -240,12 +259,14 @@ "block.create.horizontal_framed_glass": "ss\u0250\u05DF\u2141 p\u01DD\u026F\u0250\u0279\u2132 \u05DF\u0250\u0287uoz\u0131\u0279oH", "block.create.horizontal_framed_glass_pane": "\u01DDu\u0250\u0500 ss\u0250\u05DF\u2141 p\u01DD\u026F\u0250\u0279\u2132 \u05DF\u0250\u0287uoz\u0131\u0279oH", "block.create.hose_pulley": "\u028E\u01DD\u05DF\u05DFn\u0500 \u01DDsoH", + "block.create.industrial_iron_block": "uo\u0279I \u05DF\u0250\u0131\u0279\u0287snpuI \u025Fo \u029E\u0254o\u05DF\u15FA", "block.create.item_drain": "u\u0131\u0250\u0279\u15E1 \u026F\u01DD\u0287I", "block.create.item_vault": "\u0287\u05DFn\u0250\u039B \u026F\u01DD\u0287I", "block.create.jungle_window": "\u028Dopu\u0131M \u01DD\u05DFbun\u017F", "block.create.jungle_window_pane": "\u01DDu\u0250\u0500 \u028Dopu\u0131M \u01DD\u05DFbun\u017F", "block.create.large_bogey": "\u028E\u01DDbo\u15FA \u01DDb\u0279\u0250\uA780", "block.create.large_cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186 \u01DDb\u0279\u0250\uA780", + "block.create.large_water_wheel": "\u05DF\u01DD\u01DD\u0265M \u0279\u01DD\u0287\u0250M \u01DDb\u0279\u0250\uA780", "block.create.layered_andesite": "\u01DD\u0287\u0131s\u01DDpu\u2C6F p\u01DD\u0279\u01DD\u028E\u0250\uA780", "block.create.layered_asurine": "\u01DDu\u0131\u0279ns\u2C6F p\u01DD\u0279\u01DD\u028E\u0250\uA780", "block.create.layered_calcite": "\u01DD\u0287\u0131\u0254\u05DF\u0250\u0186 p\u01DD\u0279\u01DD\u028E\u0250\uA780", @@ -296,6 +317,7 @@ "block.create.mechanical_plough": "\u0265bno\u05DF\u0500 \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW", "block.create.mechanical_press": "ss\u01DD\u0279\u0500 \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW", "block.create.mechanical_pump": "d\u026Fn\u0500 \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW", + "block.create.mechanical_roller": "\u0279\u01DD\u05DF\u05DFo\u1D1A \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW", "block.create.mechanical_saw": "\u028D\u0250S \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW", "block.create.metal_bracket": "\u0287\u01DD\u029E\u0254\u0250\u0279\u15FA \u05DF\u0250\u0287\u01DDW", "block.create.metal_girder": "\u0279\u01DDp\u0279\u0131\u2141 \u05DF\u0250\u0287\u01DDW", @@ -303,6 +325,7 @@ "block.create.millstone": "\u01DDuo\u0287s\u05DF\u05DF\u0131W", "block.create.minecart_anchor": "\u0279o\u0265\u0254u\u2C6F \u0287\u0279\u0250\u0254\u01DDu\u0131W", "block.create.mysterious_cuckoo_clock": "\u029E\u0254o\u05DF\u0186 oo\u029E\u0254n\u0186", + "block.create.netherite_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u01DD\u0287\u0131\u0279\u01DD\u0265\u0287\u01DDN", "block.create.nixie_tube": "\u01DDqn\u27D8 \u01DD\u0131x\u0131N", "block.create.nozzle": "\u01DD\u05DFzzoN", "block.create.oak_window": "\u028Dopu\u0131M \u029E\u0250O", @@ -415,7 +438,7 @@ "block.create.rose_quartz_lamp": "d\u026F\u0250\uA780 z\u0287\u0279\u0250n\u1F49 \u01DDso\u1D1A", "block.create.rose_quartz_tiles": "s\u01DD\u05DF\u0131\u27D8 z\u0287\u0279\u0250n\u1F49 \u01DDso\u1D1A", "block.create.rotation_speed_controller": "\u0279\u01DD\u05DF\u05DFo\u0279\u0287uo\u0186 p\u01DD\u01DDdS uo\u0131\u0287\u0250\u0287o\u1D1A", - "block.create.sail_frame": "\u01DD\u026F\u0250\u0279\u2132 \u05DF\u0131\u0250S", + "block.create.sail_frame": "\u01DD\u026F\u0250\u0279\u2132 \u05DF\u0131\u0250S \u05DF\u05DF\u0131\u026Fpu\u0131M", "block.create.schematic_table": "\u01DD\u05DFq\u0250\u27D8 \u0254\u0131\u0287\u0250\u026F\u01DD\u0265\u0254S", "block.create.schematicannon": "uouu\u0250\u0254\u0131\u0287\u0250\u026F\u01DD\u0265\u0254S", "block.create.scorchia": "\u0250\u0131\u0265\u0254\u0279o\u0254S", @@ -495,7 +518,7 @@ "block.create.steam_whistle_extension": "uo\u0131su\u01DD\u0287x\u018E \u01DD\u05DF\u0287s\u0131\u0265M \u026F\u0250\u01DD\u0287S", "block.create.sticker": "\u0279\u01DD\u029E\u0254\u0131\u0287S", "block.create.sticky_mechanical_piston": "uo\u0287s\u0131\u0500 \u05DF\u0250\u0254\u0131u\u0250\u0265\u0254\u01DDW \u028E\u029E\u0254\u0131\u0287S", - "block.create.stockpile_switch": "\u0265\u0254\u0287\u0131\u028DS \u01DD\u05DF\u0131d\u029E\u0254o\u0287S", + "block.create.stockpile_switch": "\u0265\u0254\u0287\u0131\u028DS p\u05DFo\u0265s\u01DD\u0279\u0265\u27D8", "block.create.stressometer": "\u0279\u01DD\u0287\u01DD\u026Foss\u01DD\u0279\u0287S", "block.create.tiled_glass": "ss\u0250\u05DF\u2141 p\u01DD\u05DF\u0131\u27D8", "block.create.tiled_glass_pane": "\u01DDu\u0250\u0500 ss\u0250\u05DF\u2141 p\u01DD\u05DF\u0131\u27D8", @@ -514,6 +537,7 @@ "block.create.warped_window": "\u028Dopu\u0131M p\u01DDd\u0279\u0250M", "block.create.warped_window_pane": "\u01DDu\u0250\u0500 \u028Dopu\u0131M p\u01DDd\u0279\u0250M", "block.create.water_wheel": "\u05DF\u01DD\u01DD\u0265M \u0279\u01DD\u0287\u0250M", + "block.create.water_wheel_structure": "\u05DF\u01DD\u01DD\u0265M \u0279\u01DD\u0287\u0250M \u01DDb\u0279\u0250\uA780", "block.create.waxed_copper_shingle_slab": "q\u0250\u05DFS \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDx\u0250M", "block.create.waxed_copper_shingle_stairs": "s\u0279\u0131\u0250\u0287S \u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDx\u0250M", "block.create.waxed_copper_shingles": "s\u01DD\u05DFbu\u0131\u0265S \u0279\u01DDddo\u0186 p\u01DDx\u0250M", @@ -546,7 +570,7 @@ "block.create.weathered_copper_tiles": "s\u01DD\u05DF\u0131\u27D8 \u0279\u01DDddo\u0186 p\u01DD\u0279\u01DD\u0265\u0287\u0250\u01DDM", "block.create.weighted_ejector": "\u0279o\u0287\u0254\u01DD\u0638\u018E p\u01DD\u0287\u0265b\u0131\u01DDM", "block.create.white_nixie_tube": "\u01DDqn\u27D8 \u01DD\u0131x\u0131N \u01DD\u0287\u0131\u0265M", - "block.create.white_sail": "\u05DF\u0131\u0250S \u01DD\u0287\u0131\u0265M", + "block.create.white_sail": "\u05DF\u0131\u0250S \u05DF\u05DF\u0131\u026Fpu\u0131M", "block.create.white_seat": "\u0287\u0250\u01DDS \u01DD\u0287\u0131\u0265M", "block.create.white_toolbox": "xoq\u05DFoo\u27D8 \u01DD\u0287\u0131\u0265M", "block.create.white_valve_handle": "\u01DD\u05DFpu\u0250H \u01DD\u028C\u05DF\u0250\u039B \u01DD\u0287\u0131\u0265M", @@ -589,33 +613,33 @@ "item.create.cinder_flour": "\u0279no\u05DF\u2132 \u0279\u01DDpu\u0131\u0186", "item.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186", "item.create.copper_backtank_placeable": "\u01DD\u05DFq\u0250\u01DD\u0254\u0250\u05DF\u0500 \u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186", + "item.create.copper_diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1 \u0279\u01DDddo\u0186", + "item.create.copper_diving_helmet": "\u0287\u01DD\u026F\u05DF\u01DDH bu\u0131\u028C\u0131\u15E1 \u0279\u01DDddo\u0186", "item.create.copper_nugget": "\u0287\u01DDbbnN \u0279\u01DDddo\u0186", "item.create.copper_sheet": "\u0287\u01DD\u01DD\u0265S \u0279\u01DDddo\u0186", "item.create.crafter_slot_cover": "\u0279\u01DD\u028Co\u0186 \u0287o\u05DFS \u0279\u01DD\u0287\u025F\u0250\u0279\u0186", "item.create.crafting_blueprint": "\u0287u\u0131\u0279d\u01DDn\u05DF\u15FA bu\u0131\u0287\u025F\u0250\u0279\u0186", "item.create.creative_blaze_cake": "\u01DD\u029E\u0250\u0186 \u01DDz\u0250\u05DF\u15FA \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186", - "item.create.crushed_aluminum_ore": "\u01DD\u0279O \u026Fnu\u0131\u026Fn\u05DF\u2C6F p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_copper_ore": "\u01DD\u0279O \u0279\u01DDddo\u0186 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_gold_ore": "\u01DD\u0279O p\u05DFo\u2141 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_iron_ore": "\u01DD\u0279O uo\u0279I p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_lead_ore": "\u01DD\u0279O p\u0250\u01DD\uA780 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_nickel_ore": "\u01DD\u0279O \u05DF\u01DD\u029E\u0254\u0131N p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_osmium_ore": "\u01DD\u0279O \u026Fn\u0131\u026FsO p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_platinum_ore": "\u01DD\u0279O \u026Fnu\u0131\u0287\u0250\u05DF\u0500 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_quicksilver_ore": "\u01DD\u0279O \u0279\u01DD\u028C\u05DF\u0131s\u029E\u0254\u0131n\u1F49 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_silver_ore": "\u01DD\u0279O \u0279\u01DD\u028C\u05DF\u0131S p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_tin_ore": "\u01DD\u0279O u\u0131\u27D8 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_uranium_ore": "\u01DD\u0279O \u026Fn\u0131u\u0250\u0279\u2229 p\u01DD\u0265sn\u0279\u0186", - "item.create.crushed_zinc_ore": "\u01DD\u0279O \u0254u\u0131Z p\u01DD\u0265sn\u0279\u0186", - "item.create.diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1", - "item.create.diving_helmet": "\u0287\u01DD\u026F\u05DF\u01DDH bu\u0131\u028C\u0131\u15E1", + "item.create.crushed_raw_aluminum": "\u026Fnu\u0131\u026Fn\u05DF\u2C6F \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_copper": "\u0279\u01DDddo\u0186 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_gold": "p\u05DFo\u2141 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_iron": "uo\u0279I \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_lead": "p\u0250\u01DD\uA780 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_nickel": "\u05DF\u01DD\u029E\u0254\u0131N \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_osmium": "\u026Fn\u0131\u026FsO \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_platinum": "\u026Fnu\u0131\u0287\u0250\u05DF\u0500 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_quicksilver": "\u0279\u01DD\u028C\u05DF\u0131s\u029E\u0254\u0131n\u1F49 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_silver": "\u0279\u01DD\u028C\u05DF\u0131S \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_tin": "u\u0131\u27D8 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_uranium": "\u026Fn\u0131u\u0250\u0279\u2229 \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", + "item.create.crushed_raw_zinc": "\u0254u\u0131Z \u028D\u0250\u1D1A p\u01DD\u0265sn\u0279\u0186", "item.create.dough": "\u0265bno\u15E1", "item.create.electron_tube": "\u01DDqn\u27D8 uo\u0279\u0287\u0254\u01DD\u05DF\u018E", "item.create.empty_blaze_burner": "\u0279\u01DDu\u0279n\u15FA \u01DDz\u0250\u05DF\u15FA \u028E\u0287d\u026F\u018E", "item.create.empty_schematic": "\u0254\u0131\u0287\u0250\u026F\u01DD\u0265\u0254S \u028E\u0287d\u026F\u018E", "item.create.experience_nugget": "\u01DD\u0254u\u01DD\u0131\u0279\u01DDdx\u018E \u025Fo \u0287\u01DDbbnN", "item.create.extendo_grip": "d\u0131\u0279\u2141 opu\u01DD\u0287x\u018E", - "item.create.filter": "\u0279\u01DD\u0287\u05DF\u0131\u2132", + "item.create.filter": "\u0279\u01DD\u0287\u05DF\u0131\u2132 \u0287s\u0131\uA780", "item.create.furnace_minecart_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W \u01DD\u0254\u0250u\u0279n\u2132", "item.create.goggles": "s\u01DD\u05DFbbo\u2141 s,\u0279\u01DD\u01DDu\u0131bu\u018E", "item.create.golden_sheet": "\u0287\u01DD\u01DD\u0265S u\u01DDp\u05DFo\u2141", @@ -628,6 +652,10 @@ "item.create.linked_controller": "\u0279\u01DD\u05DF\u05DFo\u0279\u0287uo\u0186 p\u01DD\u029Eu\u0131\uA780", "item.create.minecart_contraption": "uo\u0131\u0287d\u0250\u0279\u0287uo\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W", "item.create.minecart_coupling": "bu\u0131\u05DFdno\u0186 \u0287\u0279\u0250\u0254\u01DDu\u0131W", + "item.create.netherite_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u01DD\u0287\u0131\u0279\u01DD\u0265\u0287\u01DDN", + "item.create.netherite_backtank_placeable": "\u01DD\u05DFq\u0250\u01DD\u0254\u0250\u05DF\u0500 \u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u01DD\u0287\u0131\u0279\u01DD\u0265\u0287\u01DDN", + "item.create.netherite_diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1 \u01DD\u0287\u0131\u0279\u01DD\u0265\u0287\u01DDN", + "item.create.netherite_diving_helmet": "\u0287\u01DD\u026F\u05DF\u01DDH bu\u0131\u028C\u0131\u15E1 \u01DD\u0287\u0131\u0279\u01DD\u0265\u0287\u01DDN", "item.create.polished_rose_quartz": "z\u0287\u0279\u0250n\u1F49 \u01DDso\u1D1A p\u01DD\u0265s\u0131\u05DFo\u0500", "item.create.potato_cannon": "uouu\u0250\u0186 o\u0287\u0250\u0287o\u0500", "item.create.powdered_obsidian": "u\u0250\u0131p\u0131sqO p\u01DD\u0279\u01DDp\u028Do\u0500", diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 9c6ac9a801..8133c26a5d 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -6,14 +6,18 @@ "block.create.acacia_window_pane": "Acacia Window Pane", "block.create.adjustable_chain_gearshift": "Adjustable Chain Gearshift", "block.create.analog_lever": "Analog Lever", + "block.create.andesite_alloy_block": "Block of Andesite Alloy", + "block.create.andesite_bars": "Andesite Bars", "block.create.andesite_belt_funnel": "Andesite Belt Funnel", "block.create.andesite_casing": "Andesite Casing", + "block.create.andesite_door": "Andesite Door", "block.create.andesite_encased_cogwheel": "Andesite Encased Cogwheel", "block.create.andesite_encased_large_cogwheel": "Andesite Encased Large Cogwheel", "block.create.andesite_encased_shaft": "Andesite Encased Shaft", "block.create.andesite_funnel": "Andesite Funnel", "block.create.andesite_ladder": "Andesite Ladder", "block.create.andesite_pillar": "Andesite Pillar", + "block.create.andesite_scaffolding": "Andesite Scaffolding", "block.create.andesite_tunnel": "Andesite Tunnel", "block.create.asurine": "Asurine", "block.create.asurine_pillar": "Asurine Pillar", @@ -32,14 +36,17 @@ "block.create.blue_seat": "Blue Seat", "block.create.blue_toolbox": "Blue Toolbox", "block.create.blue_valve_handle": "Blue Valve Handle", + "block.create.brass_bars": "Brass Bars", "block.create.brass_belt_funnel": "Brass Belt Funnel", "block.create.brass_block": "Block of Brass", "block.create.brass_casing": "Brass Casing", + "block.create.brass_door": "Brass Door", "block.create.brass_encased_cogwheel": "Brass Encased Cogwheel", "block.create.brass_encased_large_cogwheel": "Brass Encased Large Cogwheel", "block.create.brass_encased_shaft": "Brass Encased Shaft", "block.create.brass_funnel": "Brass Funnel", "block.create.brass_ladder": "Brass Ladder", + "block.create.brass_scaffolding": "Brass Scaffolding", "block.create.brass_tunnel": "Brass Tunnel", "block.create.brown_nixie_tube": "Brown Nixie Tube", "block.create.brown_sail": "Brown Sail", @@ -50,15 +57,20 @@ "block.create.cart_assembler": "Cart Assembler", "block.create.chocolate": "Chocolate", "block.create.chute": "Chute", + "block.create.clipboard": "Clipboard", "block.create.clockwork_bearing": "Clockwork Bearing", "block.create.clutch": "Clutch", "block.create.cogwheel": "Cogwheel", - "block.create.content_observer": "Content Observer", + "block.create.content_observer": "Smart Observer", + "block.create.contraption_controls": "Contraption Controls", "block.create.controller_rail": "Controller Rail", "block.create.controls": "Train Controls", "block.create.copper_backtank": "Copper Backtank", + "block.create.copper_bars": "Copper Bars", "block.create.copper_casing": "Copper Casing", + "block.create.copper_door": "Copper Door", "block.create.copper_ladder": "Copper Ladder", + "block.create.copper_scaffolding": "Copper Scaffolding", "block.create.copper_shingle_slab": "Copper Shingle Slab", "block.create.copper_shingle_stairs": "Copper Shingle Stairs", "block.create.copper_shingles": "Copper Shingles", @@ -66,6 +78,10 @@ "block.create.copper_tile_stairs": "Copper Tile Stairs", "block.create.copper_tiles": "Copper Tiles", "block.create.copper_valve_handle": "Copper Valve Handle", + "block.create.copycat_bars": "Copycat Bars", + "block.create.copycat_base": "Copycat Base", + "block.create.copycat_panel": "Copycat Panel", + "block.create.copycat_step": "Copycat Step", "block.create.creative_crate": "Creative Crate", "block.create.creative_fluid_tank": "Creative Fluid Tank", "block.create.creative_motor": "Creative Motor", @@ -203,9 +219,12 @@ "block.create.display_board": "Display Board", "block.create.display_link": "Display Link", "block.create.dripstone_pillar": "Dripstone Pillar", + "block.create.elevator_contact": "Elevator Contact", + "block.create.elevator_pulley": "Elevator Pulley", "block.create.encased_chain_drive": "Encased Chain Drive", "block.create.encased_fan": "Encased Fan", "block.create.encased_fluid_pipe": "Encased Fluid Pipe", + "block.create.experience_block": "Block of Experience", "block.create.exposed_copper_shingle_slab": "Exposed Copper Shingle Slab", "block.create.exposed_copper_shingle_stairs": "Exposed Copper Shingle Stairs", "block.create.exposed_copper_shingles": "Exposed Copper Shingles", @@ -243,12 +262,14 @@ "block.create.horizontal_framed_glass": "Horizontal Framed Glass", "block.create.horizontal_framed_glass_pane": "Horizontal Framed Glass Pane", "block.create.hose_pulley": "Hose Pulley", + "block.create.industrial_iron_block": "Block of Industrial Iron", "block.create.item_drain": "Item Drain", "block.create.item_vault": "Item Vault", "block.create.jungle_window": "Jungle Window", "block.create.jungle_window_pane": "Jungle Window Pane", "block.create.large_bogey": "Large Bogey", "block.create.large_cogwheel": "Large Cogwheel", + "block.create.large_water_wheel": "Large Water Wheel", "block.create.layered_andesite": "Layered Andesite", "block.create.layered_asurine": "Layered Asurine", "block.create.layered_calcite": "Layered Calcite", @@ -299,6 +320,7 @@ "block.create.mechanical_plough": "Mechanical Plough", "block.create.mechanical_press": "Mechanical Press", "block.create.mechanical_pump": "Mechanical Pump", + "block.create.mechanical_roller": "Mechanical Roller", "block.create.mechanical_saw": "Mechanical Saw", "block.create.metal_bracket": "Metal Bracket", "block.create.metal_girder": "Metal Girder", @@ -306,6 +328,7 @@ "block.create.millstone": "Millstone", "block.create.minecart_anchor": "Minecart Anchor", "block.create.mysterious_cuckoo_clock": "Cuckoo Clock", + "block.create.netherite_backtank": "Netherite Backtank", "block.create.nixie_tube": "Nixie Tube", "block.create.nozzle": "Nozzle", "block.create.oak_window": "Oak Window", @@ -418,7 +441,7 @@ "block.create.rose_quartz_lamp": "Rose Quartz Lamp", "block.create.rose_quartz_tiles": "Rose Quartz Tiles", "block.create.rotation_speed_controller": "Rotation Speed Controller", - "block.create.sail_frame": "Sail Frame", + "block.create.sail_frame": "Windmill Sail Frame", "block.create.schematic_table": "Schematic Table", "block.create.schematicannon": "Schematicannon", "block.create.scorchia": "Scorchia", @@ -498,7 +521,7 @@ "block.create.steam_whistle_extension": "Steam Whistle Extension", "block.create.sticker": "Sticker", "block.create.sticky_mechanical_piston": "Sticky Mechanical Piston", - "block.create.stockpile_switch": "Stockpile Switch", + "block.create.stockpile_switch": "Threshold Switch", "block.create.stressometer": "Stressometer", "block.create.tiled_glass": "Tiled Glass", "block.create.tiled_glass_pane": "Tiled Glass Pane", @@ -517,6 +540,7 @@ "block.create.warped_window": "Warped Window", "block.create.warped_window_pane": "Warped Window Pane", "block.create.water_wheel": "Water Wheel", + "block.create.water_wheel_structure": "Large Water Wheel", "block.create.waxed_copper_shingle_slab": "Waxed Copper Shingle Slab", "block.create.waxed_copper_shingle_stairs": "Waxed Copper Shingle Stairs", "block.create.waxed_copper_shingles": "Waxed Copper Shingles", @@ -549,7 +573,7 @@ "block.create.weathered_copper_tiles": "Weathered Copper Tiles", "block.create.weighted_ejector": "Weighted Ejector", "block.create.white_nixie_tube": "White Nixie Tube", - "block.create.white_sail": "White Sail", + "block.create.white_sail": "Windmill Sail", "block.create.white_seat": "White Seat", "block.create.white_toolbox": "White Toolbox", "block.create.white_valve_handle": "White Valve Handle", @@ -596,33 +620,33 @@ "item.create.cinder_flour": "Cinder Flour", "item.create.copper_backtank": "Copper Backtank", "item.create.copper_backtank_placeable": "Copper Backtank Placeable", + "item.create.copper_diving_boots": "Copper Diving Boots", + "item.create.copper_diving_helmet": "Copper Diving Helmet", "item.create.copper_nugget": "Copper Nugget", "item.create.copper_sheet": "Copper Sheet", "item.create.crafter_slot_cover": "Crafter Slot Cover", "item.create.crafting_blueprint": "Crafting Blueprint", "item.create.creative_blaze_cake": "Creative Blaze Cake", - "item.create.crushed_aluminum_ore": "Crushed Aluminum Ore", - "item.create.crushed_copper_ore": "Crushed Copper Ore", - "item.create.crushed_gold_ore": "Crushed Gold Ore", - "item.create.crushed_iron_ore": "Crushed Iron Ore", - "item.create.crushed_lead_ore": "Crushed Lead Ore", - "item.create.crushed_nickel_ore": "Crushed Nickel Ore", - "item.create.crushed_osmium_ore": "Crushed Osmium Ore", - "item.create.crushed_platinum_ore": "Crushed Platinum Ore", - "item.create.crushed_quicksilver_ore": "Crushed Quicksilver Ore", - "item.create.crushed_silver_ore": "Crushed Silver Ore", - "item.create.crushed_tin_ore": "Crushed Tin Ore", - "item.create.crushed_uranium_ore": "Crushed Uranium Ore", - "item.create.crushed_zinc_ore": "Crushed Zinc Ore", - "item.create.diving_boots": "Diving Boots", - "item.create.diving_helmet": "Diving Helmet", + "item.create.crushed_raw_aluminum": "Crushed Raw Aluminum", + "item.create.crushed_raw_copper": "Crushed Raw Copper", + "item.create.crushed_raw_gold": "Crushed Raw Gold", + "item.create.crushed_raw_iron": "Crushed Raw Iron", + "item.create.crushed_raw_lead": "Crushed Raw Lead", + "item.create.crushed_raw_nickel": "Crushed Raw Nickel", + "item.create.crushed_raw_osmium": "Crushed Raw Osmium", + "item.create.crushed_raw_platinum": "Crushed Raw Platinum", + "item.create.crushed_raw_quicksilver": "Crushed Raw Quicksilver", + "item.create.crushed_raw_silver": "Crushed Raw Silver", + "item.create.crushed_raw_tin": "Crushed Raw Tin", + "item.create.crushed_raw_uranium": "Crushed Raw Uranium", + "item.create.crushed_raw_zinc": "Crushed Raw Zinc", "item.create.dough": "Dough", "item.create.electron_tube": "Electron Tube", "item.create.empty_blaze_burner": "Empty Blaze Burner", "item.create.empty_schematic": "Empty Schematic", "item.create.experience_nugget": "Nugget of Experience", "item.create.extendo_grip": "Extendo Grip", - "item.create.filter": "Filter", + "item.create.filter": "List Filter", "item.create.furnace_minecart_contraption": "Furnace Minecart Contraption", "item.create.goggles": "Engineer's Goggles", "item.create.golden_sheet": "Golden Sheet", @@ -635,6 +659,10 @@ "item.create.linked_controller": "Linked Controller", "item.create.minecart_contraption": "Minecart Contraption", "item.create.minecart_coupling": "Minecart Coupling", + "item.create.netherite_backtank": "Netherite Backtank", + "item.create.netherite_backtank_placeable": "Netherite Backtank Placeable", + "item.create.netherite_diving_boots": "Netherite Diving Boots", + "item.create.netherite_diving_helmet": "Netherite Diving Helmet", "item.create.polished_rose_quartz": "Polished Rose Quartz", "item.create.potato_cannon": "Potato Cannon", "item.create.powdered_obsidian": "Powdered Obsidian", @@ -839,8 +867,6 @@ "advancement.create.train_portal.desc": "Ride a Train through a Nether portal", "advancement.create.track_crafting_factory": "Track Factory", "advancement.create.track_crafting_factory.desc": "Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "The Longest Bend", - "advancement.create.long_bend.desc": "Create a curved track section that spans more than 30 blocks in length", "advancement.create.long_train": "Ambitious Endeavours", "advancement.create.long_train.desc": "Create a Train with at least 6 carriages", "advancement.create.long_travel": "Field Trip", @@ -860,6 +886,9 @@ "itemGroup.create.base": "Create", "itemGroup.create.palettes": "Create's Building Blocks", + "block.create.mangrove_window": "Mangrove Window", + "block.create.mangrove_window_pane": "Mangrove Window Pane", + "death.attack.create.crush": "%1$s was processed by Crushing Wheels", "death.attack.create.crush.player": "%1$s was thrown into Crushing Wheels by %2$s", "death.attack.create.fan_fire": "%1$s got smoked by an Encased Fan", @@ -868,6 +897,8 @@ "death.attack.create.fan_lava.player": "%1$s was thrown into a smelter by %2$s", "death.attack.create.mechanical_drill": "%1$s was impaled by a Mechanical Drill", "death.attack.create.mechanical_drill.player": "%1$s was thrown in front of a Drill by %2$s", + "death.attack.create.mechanical_roller": "%1$s was flattened by a Mechanical Roller", + "death.attack.create.mechanical_roller.player": "%1$s was thrown in front of a Mechanical Roller by %2$s", "death.attack.create.mechanical_saw": "%1$s got cut in half by a Mechanical Saw", "death.attack.create.mechanical_saw.player": "%1$s was thrown into a Saw by %2$s", "death.attack.create.potato_cannon": "%1$s was shot by %2$s's Potato Cannon", @@ -939,6 +970,7 @@ "create.generic.length": "Length", "create.generic.speed": "Speed", "create.generic.delay": "Delay", + "create.generic.angle": "Angle", "create.generic.duration": "Duration", "create.generic.timeUnit": "Time Unit", "create.generic.unit.ticks": "Ticks", @@ -1030,12 +1062,15 @@ "create.terrainzapper.usingBlock": "Using: %1$s", "create.terrainzapper.leftClickToSet": "Left-Click a Block to set Material", + "create.large_water_wheel.not_enough_space": "Clear Blocks for Placement", + "create.minecart_coupling.two_couplings_max": "Minecarts cannot have more than two couplings each", "create.minecart_coupling.unloaded": "Parts of your train seem to be in unloaded chunks", "create.minecart_coupling.no_loops": "Couplings cannot form a loop", "create.minecart_coupling.removed": "Removed all couplings from minecart", "create.minecart_coupling.too_far": "Minecarts are too far apart", + "create.contraptions.moving_container": "Moving %1$s", "create.contraptions.movement_mode": "Movement Mode", "create.contraptions.movement_mode.move_place": "Always Place when Stopped", "create.contraptions.movement_mode.move_place_returned": "Place only in Starting Position", @@ -1047,25 +1082,55 @@ "create.contraptions.cart_movement_mode.rotate": "Always face toward motion", "create.contraptions.cart_movement_mode.rotate_paused": "Pause actors while rotating", "create.contraptions.cart_movement_mode.rotation_locked": "Lock rotation", + "create.contraptions.roller_mode": "Roller Mode", + "create.contraptions.roller_mode.tunnel_pave": "Clear Blocks and Pave", + "create.contraptions.roller_mode.straight_fill": "Straight Fill Below", + "create.contraptions.roller_mode.wide_fill": "Sloped Fill Below", "create.contraptions.windmill.rotation_direction": "Rotation Direction", - "create.contraptions.clockwork.clock_hands": "Clock Hands", + "create.contraptions.clockwork.clock_hands": "Clock Hand Arrangement", "create.contraptions.clockwork.hour_first": "Hour hand first", "create.contraptions.clockwork.minute_first": "Minute hand first", "create.contraptions.clockwork.hour_first_24": "24-Hour hand first", + "create.logistics.crafter.connected": "Connected Crafters", + "create.logistics.crafter.click_to_merge": "Click to merge Inventories", + "create.logistics.crafter.click_to_separate": "Click to separate Inventories", "create.logistics.filter": "Filter", "create.logistics.recipe_filter": "Recipe Filter", "create.logistics.fluid_filter": "Fluid Filter", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Applied filter to %1$s.", - "create.logistics.filter.apply_click_again": "Applied filter to %1$s, click again to copy the amount.", - "create.logistics.filter.apply_count": "Applied extraction count to filter.", + "create.logistics.firstFrequency": "Frequency #1", + "create.logistics.secondFrequency": "Frequency #2", + "create.logistics.filter.click_to_set": "Click with item to set", + "create.logistics.filter.click_to_replace": "Click with item to replace", + "create.logistics.filter.hold_to_set_amount": "Click and hold for amount", + "create.logistics.filter.invalid_item": "Cannot use this item here.", + "create.logistics.filter.extracted_amount": "Extracted Amount", + "create.logistics.filter.any_amount_short": "Any", + "create.logistics.filter.up_to": "Up to", + "create.logistics.filter.exactly": "Exactly", + "create.logistics.filter.requires_item_in_inventory": "Requires %1$s item in Inventory", + "create.logistics.creative_crate.supply": "Infinite Supply", + "create.logistics.train_observer.cargo_filter": "Cargo Filter", + "create.kinetics.creative_motor.rotation_speed": "Generated Speed in RPM", + "create.kinetics.speed_controller.rotation_speed": "Targeted Speed in RPM", + "create.kinetics.valve_handle.rotated_angle": "Rotation when used", + + "create.logistics.redstone_interval": "Redstone Interval", + + "create.contraptions.contoller.target": "Targeted Component", + "create.contraptions.mechanical_roller.pave_material": "Paving Material", + "create.contraptions.chassis.radius": "Radius when Sticky", + "create.contraptions.chassis.range": "Range of Sticky Sides", + "create.contraptions.chassis.distance": "Distance", + + "create.gui.value_settings.hold_to_edit": "Click and hold to edit", + "create.gui.value_settings.release_to_confirm": "Release %1$s to Confirm", "create.gui.goggles.generator_stats": "Generator Stats:", "create.gui.goggles.kinetic_stats": "Kinetic Stats:", "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.pole_length": "Pole Length:", + "create.gui.goggles.basin_contents": "Basin Contents:", "create.gui.goggles.fluid_container": "Fluid Container Info:", "create.gui.goggles.fluid_container.capacity": "Capacity: ", "create.gui.assembly.exception": "This Contraption was unable to assemble:", @@ -1075,6 +1140,9 @@ "create.gui.assembly.exception.tooManyPistonPoles": "There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", "create.gui.assembly.exception.noPistonPoles": "The Piston is missing some extension Poles", "create.gui.assembly.exception.not_enough_sails": "Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", + "create.gui.assembly.exception.no_contacts": "Elevators require a horizontal _Redstone_ _Contact_ attached to the structure", + "create.gui.assembly.exception.too_many_contacts": "Cannot attach more than one _Redstone_ _Contact_ to Elevators", + "create.gui.assembly.exception.column_conflict": "Another Elevator is already targeting this column of contacts", "create.gui.gauge.info_header": "Gauge Information:", "create.gui.speedometer.title": "Rotation Speed", "create.gui.stressometer.title": "Network Stress", @@ -1085,10 +1153,10 @@ "create.gui.contraptions.network_overstressed": "It appears that this contraption is _overstressed_. Add more sources or _slow_ _down_ the components with a high _stress_ _impact_.", "create.gui.adjustable_crate.title": "Adjustable Crate", "create.gui.adjustable_crate.storageSpace": "Storage Space", - "create.gui.stockpile_switch.title": "Stockpile Switch", - "create.gui.stockpile_switch.invert_signal": "Invert Signal", - "create.gui.stockpile_switch.move_to_lower_at": "Move to lower lane at %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Move to upper lane at %1$s%%", + "create.gui.threshold_switch.title": "Threshold Switch", + "create.gui.threshold_switch.invert_signal": "Invert Signal", + "create.gui.threshold_switch.move_to_lower_at": "Move to lower lane at %1$s%%", + "create.gui.threshold_switch.move_to_upper_at": "Move to upper lane at %1$s%%", "create.gui.sequenced_gearshift.title": "Sequenced Gearshift", "create.gui.sequenced_gearshift.instruction": "Instruction", "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Turn by angle", @@ -1109,6 +1177,13 @@ "create.gui.sequenced_gearshift.speed.forward_fast": "Double speed, Forwards", "create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed", "create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed", + "create.gui.clipboard.erase_checked": "Erase checked items", + + "create.clipboard.actions": "Clipboard Actions", + "create.clipboard.to_copy": "%1$s to Copy settings", + "create.clipboard.to_paste": "%1$s to Paste settings", + "create.clipboard.copied_from": "Copying settings from %1$s", + "create.clipboard.pasted_to": "Applied settings to %1$s", "create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s", "create.schematicAndQuill.firstPos": "First position set.", @@ -1119,8 +1194,11 @@ "create.schematicAndQuill.convert": "Save and Upload Immediately", "create.schematicAndQuill.fallbackName": "My Schematic", "create.schematicAndQuill.saved": "Saved as %1$s", + "create.schematicAndQuill.failed": "Failed to save schematic, check logs for details", + "create.schematicAndQuill.instant_failed": "Schematic instant-upload failed, check logs for details", "create.schematic.invalid": "[!] Invalid Item - Use the Schematic Table instead", + "create.schematic.error": "Schematic failed to Load - Check Game Logs", "create.schematic.position": "Position", "create.schematic.rotation": "Rotation", "create.schematic.rotation.none": "None", @@ -1133,7 +1211,7 @@ "create.schematic.mirror.leftRight": "Left-Right", "create.schematic.tool.deploy": "Position", "create.schematic.tool.move": "Move XZ", - "create.schematic.tool.movey": "Move Y", + "create.schematic.tool.move_y": "Move Y", "create.schematic.tool.rotate": "Rotate", "create.schematic.tool.print": "Print", "create.schematic.tool.flip": "Mirror", @@ -1145,10 +1223,10 @@ "create.schematic.tool.move.description.1": "Point at the Schematic and [CTRL]-Scroll to push it.", "create.schematic.tool.move.description.2": "", "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Shifts the Schematic Vertically.", - "create.schematic.tool.movey.description.1": "[CTRL]-Scroll to move it up/down.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", + "create.schematic.tool.move_y.description.0": "Shifts the Schematic Vertically.", + "create.schematic.tool.move_y.description.1": "[CTRL]-Scroll to move it up/down.", + "create.schematic.tool.move_y.description.2": "", + "create.schematic.tool.move_y.description.3": "", "create.schematic.tool.rotate.description.0": "Rotates the Schematic around its center.", "create.schematic.tool.rotate.description.1": "[CTRL]-Scroll to rotate by 90 Degrees.", "create.schematic.tool.rotate.description.2": "", @@ -1186,12 +1264,12 @@ "create.gui.schematicannon.option.replaceWithAny": "Replace Solid with Any", "create.gui.schematicannon.option.replaceWithEmpty": "Replace Solid with Empty", "create.gui.schematicannon.option.skipMissing": "Skip missing Blocks", - "create.gui.schematicannon.option.skipTileEntities": "Protect Tile Entities", + "create.gui.schematicannon.option.skipBlockEntities": "Protect Block Entities", "create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon", - "create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.listPrinter": "Place a Clipboard or Book here to print a Checklist for your Schematic", "create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.", - "create.gui.schematicannon.option.skipTileEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.", + "create.gui.schematicannon.option.skipBlockEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.", "create.gui.schematicannon.option.dontReplaceSolid.description": "The cannon will never replace any Solid blocks in its working area, only non-Solid and Air.", "create.gui.schematicannon.option.replaceWithSolid.description": "The cannon will only replace Solid blocks in its working area if the Schematic contains a solid Block at the Location.", "create.gui.schematicannon.option.replaceWithAny.description": "The cannon will replace Solid blocks in its working area if the Schematic contains any Block at the Location.", @@ -1214,6 +1292,8 @@ "create.schematicannon.status.schematicInvalid": "Schematic Invalid", "create.schematicannon.status.schematicNotPlaced": "Schematic not Positioned", "create.schematicannon.status.schematicExpired": "Schematic File Expired", + "create.schematicannon.status.schematicErrored": "Incompatible Blocks", + "create.schematicannon.status.schematicErroredCheckLogs": "Check Server Logs", "create.materialChecklist": "Material Checklist", "create.materialChecklist.blocksNotLoaded": "* Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", @@ -1346,7 +1426,7 @@ "create.weighted_ejector.targeting": "Ejecting to [%1$s,%2$s,%3$s]", "create.weighted_ejector.stack_size": "Ejected Stack Size", - "create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available", + "create.logistics.when_multiple_outputs_available": "Distribution Method", "create.mechanical_arm.selection_mode.round_robin": "Round Robin", "create.mechanical_arm.selection_mode.forced_round_robin": "Forced Round Robin", @@ -1401,7 +1481,7 @@ "create.hint.mechanical_arm_no_targets": "It appears this _Mechanical_ _Arm_ has not been assigned any _targets._ Select belts, depots, funnels and other blocks by _right-clicking_ them while _holding_ the _Mechanical_ _Arm_ in your _hand_.", "create.hint.empty_bearing.title": "Update Bearing", "create.hint.empty_bearing": "_Right-click_ the bearing with an _empty_ _hand_ to _attach_ the structure you just built in front of it.", - "create.hint.full_deployer.title": "Deployer Item Overflow", + "create.hint.full_deployer.title": "Deployer cannot activate", "create.hint.full_deployer": "It appears this _Deployer_ contains _excess_ _items_ that need to be _extracted._ Use a _hopper,_ _funnel_ or other means to free it from its overflow.", "create.backtank.low": "Backtank pressure low", @@ -1424,6 +1504,12 @@ "create.boiler.heat_dots": "...... ", "create.boiler.via_one_engine": "via 1 engine", "create.boiler.via_engines": "via %1$s engines", + "create.boiler.water_input_rate": "Water input rate", + "create.boiler.per_tick": "%1$s per Tick", + + "create.elevator_contact.title": "Elevator Contact", + "create.elevator_contact.floor_identifier": "Floor Identifier", + "create.elevator_contact.floor_description": "Floor Description", "create.gui.schedule.lmb_edit": "Left-Click to Edit", "create.gui.schedule.rmb_remove": "Right-Click to Remove", @@ -1546,6 +1632,7 @@ "create.track.turn_start": "Cannot start connection from a Turn", "create.track.not_enough_tracks": "Not holding enough tracks", "create.track.not_enough_pavement": "Not holding enough pavement blocks", + "create.track.hold_for_smooth_curve": "Hold %1$s for maximized turn", "create.portal_track.failed": "Cannot place portal track:", "create.portal_track.missing": "Target portal not generated yet", @@ -1584,8 +1671,8 @@ "create.train_assembly.bogeys_too_close": "Bogeys %1$s and %2$s are too close to each other", "create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own", "create.train_assembly.nothing_attached": "No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "A mounted controls block is facing sideways", + "create.train_assembly.no_controls": "Attach at least one forward-facing Train Controls block (Are you missing Super Glue?)", + "create.train_assembly.sideways_controls": "Train Controls cannot face sideways", "create.train_assembly.bogey_created": "Bogey created. Click again to cycle type", "create.train_assembly.requires_casing": "Use Railway Casing to create bogeys on tracks", @@ -1630,6 +1717,25 @@ "create.contraption.controls.start_controlling": "Now controlling: %1$s", "create.contraption.controls.stop_controlling": "Stopped controlling contraption", "create.contraption.controls.approach_station": "Hold %1$s to approach %2$s", + "create.contraption.controls.specific_actor_toggle": "%1$s Actors: %2$s", + "create.contraption.controls.all_actor_toggle": "All Actors: %1$s", + "create.contraption.controls.actor_toggle.on": "On", + "create.contraption.controls.actor_toggle.off": "Off", + "create.contraption.controls.floor_unreachable": "Unreachable", + "create.contraption.door_control": "Onboard Door Control", + "create.contraption.door_control.all": "Open All Doors", + "create.contraption.door_control.all.short": "Open All", + "create.contraption.door_control.north": "North Side Only", + "create.contraption.door_control.north.short": "North", + "create.contraption.door_control.east": "East Side Only", + "create.contraption.door_control.east.short": "East", + "create.contraption.door_control.south": "South Side Only", + "create.contraption.door_control.south.short": "South", + "create.contraption.door_control.west": "West Side Only", + "create.contraption.door_control.west.short": "West", + "create.contraption.door_control.none": "Keep Doors Closed", + "create.contraption.door_control.none.short": "None", + "create.contraption.door_control.player_facing": "You are facing: %1$s", "create.display_link.set": "Targeted position selected", "create.display_link.success": "Successfully bound to targeted position", @@ -1692,6 +1798,7 @@ "create.display_source.max_enchant_level": "Max Enchanting Cost", "create.display_source.boiler_status": "Boiler Status", "create.display_source.entity_name": "Entity Name", + "create.display_source.current_floor": "Elevator Location", "create.display_source.kinetic_speed": "Rotation Speed (RPM)", "create.display_source.kinetic_speed.absolute": "Ignore Direction", "create.display_source.kinetic_speed.directional": "Include Direction", @@ -1708,6 +1815,7 @@ "create.display_source.redstone_power.progress_bar": "Progress Bar", "create.display_source.boiler.not_enough_space": "Not enough space ", "create.display_source.boiler.for_boiler_status": "for Boiler Status", + "create.display_source.computer_display_source": "From Computer", "create.display_target.line": "Line %1$s", "create.display_target.page": "Page %1$s", @@ -1730,6 +1838,8 @@ "create.super_glue.not_enough": "Not enough glue in inventory", "create.super_glue.success": "Applying Glue...", + "create.gui.attached_computer.controlled": "This device is being controlled by a computer", + "create.gui.attached_computer.hint": "To use device manually, disconnect all computers and modems", "create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay3": "Click or drag with your mouse", @@ -1750,6 +1860,15 @@ "create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world", + "enchantment.create.capacity.desc": "Increases Backtank air capacity.", + "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.", + + "create.bogey.style.updated_style": "Updated style", + "create.bogey.style.updated_style_and_size": "Updated style and size", + "create.bogey.style.no_other_sizes": "No other sizes", + "create.bogey.style.invalid": "Unnamed style", + "create.bogey.style.standard": "Standard", + "_": "->------------------------] Subtitles [------------------------<-", @@ -1827,57 +1946,49 @@ "item.create.blaze_cake.tooltip.summary": "A Delicious treat for your hard-working _Blaze Burners_. Gets them all fired up!", "item.create.wand_of_symmetry.tooltip": "SYMMETRY WAND", - "item.create.wand_of_symmetry.tooltip.summary": "Perfectly mirrors Block placement across configured planes.", - "item.create.wand_of_symmetry.tooltip.condition1": "When in Hotbar", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Stays Active", - "item.create.wand_of_symmetry.tooltip.control1": "R-Click on Ground", - "item.create.wand_of_symmetry.tooltip.action1": "_Creates_ or _Moves_ the Mirror", - "item.create.wand_of_symmetry.tooltip.control2": "R-Click in the Air", - "item.create.wand_of_symmetry.tooltip.action2": "_Removes_ the active Mirror", - "item.create.wand_of_symmetry.tooltip.control3": "R-Click while Sneaking", - "item.create.wand_of_symmetry.tooltip.action3": "Opens the _Configuration Interface_", + "item.create.wand_of_symmetry.tooltip.summary": "_Mirrors Block placement_ while present in any _Hotbar Slot_.", + "item.create.wand_of_symmetry.tooltip.condition1": "When used on a Surface", + "item.create.wand_of_symmetry.tooltip.behaviour1": "_Creates_ or _Moves_ its Mirror. _Sneak_ while using to open the _Configuration Interface_", + "item.create.wand_of_symmetry.tooltip.condition2": "When used with no target", + "item.create.wand_of_symmetry.tooltip.behaviour2": "_Removes_ the active Mirror", "item.create.handheld_worldshaper.tooltip": "HANDHELD WORLDSHAPER", - "item.create.handheld_worldshaper.tooltip.summary": "Handy tool for creating _landscapes_ and _terrain features_.", - "item.create.handheld_worldshaper.tooltip.control1": "L-Click at Block", - "item.create.handheld_worldshaper.tooltip.action1": "Sets blocks placed by the tool to the targeted block.", - "item.create.handheld_worldshaper.tooltip.control2": "R-Click at Block", - "item.create.handheld_worldshaper.tooltip.action2": "Applies the currently selected _Brush_ and _Tool_ at the targeted location.", - "item.create.handheld_worldshaper.tooltip.control3": "R-Click while Sneaking", - "item.create.handheld_worldshaper.tooltip.action3": "Opens the _Configuration Interface_", + "item.create.handheld_worldshaper.tooltip.summary": "_Creative mode_ tool for large-scale _landscaping_ from a distance.", + "item.create.handheld_worldshaper.tooltip.condition1": "L-Click at Block", + "item.create.handheld_worldshaper.tooltip.behaviour1": "_Targeted block_ will become the _material_ placed by the shaper.", + "item.create.handheld_worldshaper.tooltip.condition2": "R-Click at Block", + "item.create.handheld_worldshaper.tooltip.behaviour2": "Applies currently selected _Brush_ and _Tool_ at the targeted location.", + "item.create.handheld_worldshaper.tooltip.condition3": "R-Click while Sneaking", + "item.create.handheld_worldshaper.tooltip.behaviour3": "Opens the _Configuration Interface_", "item.create.tree_fertilizer.tooltip": "TREE FERTILIZER", - "item.create.tree_fertilizer.tooltip.summary": "A powerful combination of minerals suitable for speeding up the growth of common tree types.", + "item.create.tree_fertilizer.tooltip.summary": "A powerful combination of minerals useful for _growing saplings_ in tight spaces.", "item.create.tree_fertilizer.tooltip.condition1": "When used on a Sapling", - "item.create.tree_fertilizer.tooltip.behaviour1": "Grows Trees _regardless_ of their _spacing conditions_", + "item.create.tree_fertilizer.tooltip.behaviour1": "Creates a tree _regardless_ of its _spacing conditions_", "item.create.extendo_grip.tooltip": "EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "Boioioing! Greatly _increases reach distance_ of the wielder. Can be powered with Air Pressure from a _Copper_ _Backtank_", + "item.create.extendo_grip.tooltip.summary": "Greatly _increases reach distance_ of the wielder. Can be powered with _Air_ _Pressure_ from a _Backtank_", "item.create.extendo_grip.tooltip.condition1": "When in Off-Hand", "item.create.extendo_grip.tooltip.behaviour1": "Increases _reach distance_ of items used in the _Main-Hand_.", - "item.create.extendo_grip.tooltip.condition2": "While wearing Copper Backtank", + "item.create.extendo_grip.tooltip.condition2": "While wearing Backtank", "item.create.extendo_grip.tooltip.behaviour2": "_No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", "item.create.potato_cannon.tooltip": "POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "Fwoomp! Launch your home-grown vegetables at your Enemies. Can be powered with Air Pressure from a _Copper_ _Backtank_", + "item.create.potato_cannon.tooltip.summary": "Launches your home-grown vegetables at Enemies. Can be powered with _Air_ _Pressure_ from a _Backtank_", "item.create.potato_cannon.tooltip.condition1": "When R-Clicked", "item.create.potato_cannon.tooltip.behaviour1": "_Shoots_ a suitable item from your _Inventory_.", - "item.create.potato_cannon.tooltip.condition2": "While wearing Copper Backtank", + "item.create.potato_cannon.tooltip.condition2": "While wearing Backtank", "item.create.potato_cannon.tooltip.behaviour2": "_No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - "item.create.filter.tooltip": "FILTER", - "item.create.filter.tooltip.summary": "_Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of items_ or several _nested filters_.", - "item.create.filter.tooltip.condition1": "When in filter slot", - "item.create.filter.tooltip.behaviour1": "_Controls_ item flow according to its _configuration_.", - "item.create.filter.tooltip.condition2": "When R-Clicked", - "item.create.filter.tooltip.behaviour2": "Opens the _configuration interface_.", + "item.create.filter.tooltip": "LIST FILTER", + "item.create.filter.tooltip.summary": "_Matches items_ against a collection of _items_ or _other filters_. Can be used in _Filter Slots_ of Create's Components", + "item.create.filter.tooltip.condition1": "When R-Clicked", + "item.create.filter.tooltip.behaviour1": "Opens the _configuration interface_.", "item.create.attribute_filter.tooltip": "ATTRIBUTE FILTER", - "item.create.attribute_filter.tooltip.summary": "_Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of_ item _attributes_ and _categories_.", - "item.create.attribute_filter.tooltip.condition1": "When in filter slot", - "item.create.attribute_filter.tooltip.behaviour1": "_Controls_ item flow according to its _configuration_.", - "item.create.attribute_filter.tooltip.condition2": "When R-Clicked", - "item.create.attribute_filter.tooltip.behaviour2": "Opens the _configuration interface_.", + "item.create.attribute_filter.tooltip.summary": "_Matches items_ against a set of _attributes_ or _categories_. Can be used in _Filter Slots_ of Create's Components", + "item.create.attribute_filter.tooltip.condition1": "When R-Clicked", + "item.create.attribute_filter.tooltip.behaviour1": "Opens the _configuration interface_.", "item.create.empty_schematic.tooltip": "EMPTY SCHEMATIC", "item.create.empty_schematic.tooltip.summary": "Used as a recipe ingredient and for writing at the _Schematic Table_.", @@ -1886,21 +1997,15 @@ "item.create.schematic.tooltip.summary": "Holds a structure to be positioned and placed into the world. Position the Hologram as desired and use a _Schematicannon_ to build it.", "item.create.schematic.tooltip.condition1": "When Held", "item.create.schematic.tooltip.behaviour1": "Can be positioned using the Tools on Screen.", - "item.create.schematic.tooltip.control1": "R-Click while Sneaking", - "item.create.schematic.tooltip.action1": "Opens an _Interface_ for entering exact _Coordinates_.", + "item.create.schematic.tooltip.condition2": "R-Click while Sneaking", + "item.create.schematic.tooltip.behaviour2": "Opens an _Interface_ for entering exact _Coordinates_.", "item.create.schematic_and_quill.tooltip": "SCHEMATIC AND QUILL", - "item.create.schematic_and_quill.tooltip.summary": "Used for saving a Structure in your world to a .nbt file.", - "item.create.schematic_and_quill.tooltip.condition1": "Step 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Select two corner points using R-Click.", - "item.create.schematic_and_quill.tooltip.condition2": "Step 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Scroll_ on the faces to adjust the size. R-Click again to Save.", - "item.create.schematic_and_quill.tooltip.control1": "R-Click", - "item.create.schematic_and_quill.tooltip.action1": "Select a corner point / confirm save.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Held", - "item.create.schematic_and_quill.tooltip.action2": "Select points in _mid-air_. _Scroll_ to adjust the distance.", - "item.create.schematic_and_quill.tooltip.control3": "R-Click while Sneaking", - "item.create.schematic_and_quill.tooltip.action3": "_Resets_ and removes the selection.", + "item.create.schematic_and_quill.tooltip.summary": "Used for _saving a Structure_ in your world to a _.nbt file_.", + "item.create.schematic_and_quill.tooltip.condition1": "Creating a selection", + "item.create.schematic_and_quill.tooltip.behaviour1": "Select two _corner points_ using _R-Click_. Hold _Ctrl_ and Scroll to select locations mid-air.", + "item.create.schematic_and_quill.tooltip.condition2": "Adjusting and Saving", + "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Scroll_ on the faces to adjust the size, then R-Click again to Save.", "block.create.schematicannon.tooltip": "SCHEMATICANNON", "block.create.schematicannon.tooltip.summary": "Shoots blocks to recreate a deployed _Schematic_ in the World. Uses items from adjacent Inventories and _Gunpowder_ as fuel.", @@ -1913,20 +2018,16 @@ "block.create.schematic_table.tooltip.behaviour1": "Uploads a chosen File from your Schematics Folder.", "item.create.goggles.tooltip": "GOGGLES", - "item.create.goggles.tooltip.summary": "A pair of glasses to augment your vision with useful _kinetic information_.", - "item.create.goggles.tooltip.condition1": "When worn", - "item.create.goggles.tooltip.behaviour1": "Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", - "item.create.goggles.tooltip.condition2": "When looking at gauge", - "item.create.goggles.tooltip.behaviour2": "Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", - "item.create.goggles.tooltip.condition3": "When looking at fluid containers", - "item.create.goggles.tooltip.behaviour3": "Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", + "item.create.goggles.tooltip.summary": "Augments your HUD with _miscellaneous information_ about placed components.", + "item.create.goggles.tooltip.condition1": "When looking at blocks", + "item.create.goggles.tooltip.behaviour1": "_Kinetic components_ show added _Stress Impact_ or _Capacity_. _Stressometers_ show statistics of their _attached kinetic network_. Some other blocks reveal information such as item and fluid content.", "item.create.wrench.tooltip": "WRENCH", - "item.create.wrench.tooltip.summary": "A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", - "item.create.wrench.tooltip.control1": "Right-Click a kinetic block", - "item.create.wrench.tooltip.action1": "_Rotates components_ toward or away from the face with which you interacted.", - "item.create.wrench.tooltip.control2": "R-Click while Sneaking", - "item.create.wrench.tooltip.action2": "_Disassembles Kinetic components_ and places them back in _your inventory_.", + "item.create.wrench.tooltip.summary": "Multi-purpose tool for working with your kinetic contraptions.", + "item.create.wrench.tooltip.condition1": "When used on Blocks", + "item.create.wrench.tooltip.behaviour1": "_Rotates components_ around the clicked face. _Sneak_ while interacting to _dismantle_ components.", + "item.create.wrench.tooltip.condition2": "When used on Contraptions", + "item.create.wrench.tooltip.behaviour2": "_Relocates_ assembled minecart- and train-based contraptions.", "block.create.nozzle.tooltip": "NOZZLE", "block.create.nozzle.tooltip.summary": "Attach to the front of an _Encased Fan_ to distribute its effect on Entities in _all directions_.", @@ -1937,7 +2038,7 @@ "block.create.cuckoo_clock.tooltip.behaviour1": "Shows the _current time_ and plays a tune twice a day. _Activates_ once at _noon_ and at dusk, as soon as _players can sleep_.", "block.create.turntable.tooltip": "TURNTABLE", - "block.create.turntable.tooltip.summary": "Turns _Rotational Force_ into refined Motion Sickness.", + "block.create.turntable.tooltip.summary": "Uses _Rotational Force_ to create Motion Sickness.", "block.create.toolbox.tooltip": "TOOLBOX", "block.create.toolbox.tooltip.summary": "Every Inventors' dearest Companion. Conveniently _holds_ a large amount of _8 Different_ item types.", @@ -1948,51 +2049,29 @@ "block.create.toolbox.tooltip.condition3": "When R-Clicked", "block.create.toolbox.tooltip.behaviour3": "Opens the _Container Interface_.", - "block.create.stockpile_switch.tooltip": "STOCKPILE SWITCH", - "block.create.stockpile_switch.tooltip.summary": "Toggles a Redstone signal based on the amount of _Stored Items_ or _Fluids_ in the attached Container. Comes with a handy filter. As opposed to a _Comparator,_ the _Stockpile Switch_ allows configuration of _thresholds,_ at which signals are inverted.", - "block.create.stockpile_switch.tooltip.condition1": "When R-Clicked", - "block.create.stockpile_switch.tooltip.behaviour1": "Opens the _Configuration Interface_.", - - "block.create.content_observer.tooltip": "CONTENT OBSERVER", - "block.create.content_observer.tooltip.summary": "_Detects Items_ or _Fluids_ inside _containers_, _pipes_ or _conveyors_ matching a configured _filter_.", - "block.create.content_observer.tooltip.condition1": "When observing a Container", - "block.create.content_observer.tooltip.behaviour1": "Emits a _Redstone Signal_ while the observed container has _matching_ _content_.", - "block.create.content_observer.tooltip.condition2": "When observing a Funnel", - "block.create.content_observer.tooltip.behaviour2": "Emits a _Redstone Pulse_ when a _matching_ Item is _transferred_.", - "block.create.creative_crate.tooltip": "CREATIVE CRATE", - "block.create.creative_crate.tooltip.summary": "This _Storage Container_ allows infinite replication of any item. Place next to a _Schematicannon_ to remove any material requirements.", + "block.create.creative_crate.tooltip.summary": "This _Storage Container_ allows infinite replication of items.", "block.create.creative_crate.tooltip.condition1": "When Item in Filter Slot", "block.create.creative_crate.tooltip.behaviour1": "Anything _extracting_ from this container will provide an _endless supply_ of the item specified. Items _inserted_ into this crate will be _voided._", + "block.create.creative_crate.tooltip.condition2": "When next to Schematicannon", + "block.create.creative_crate.tooltip.behaviour2": "Provides any material required by the Schematic.", - "item.create.creative_blaze_cake.tooltip": "CREATIVE CAKE", + "item.create.creative_blaze_cake.tooltip": "CREATIVE BLAZE CAKE", "item.create.creative_blaze_cake.tooltip.summary": "A very special treat for your _Blaze Burners_. After eating this cake, Blaze Burners will _never run out of fuel_.", "item.create.creative_blaze_cake.tooltip.condition1": "When Used", "item.create.creative_blaze_cake.tooltip.behaviour1": "_Cycles_ a Blaze Burner's heat level.", "block.create.controller_rail.tooltip": "CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "A _uni-directional powered rail_ capable of _fine control_ over a minecarts' _movement speed_.", - "block.create.controller_rail.tooltip.condition1": "When Powered by Redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Accelerates_ or _Decelerates_ passing _minecarts_ corresponding to the _signal strength_. Propagates redstone power to adjacent controller rails. Powering two controller rails with different strengths will cause tracks between them to interpolate their signal.", + "block.create.controller_rail.tooltip.summary": "A _uni-directional_ powered rail with _variable speed_, controlled by the _signal strength_ supplied to it.", "item.create.sand_paper.tooltip": "SAND PAPER", - "item.create.sand_paper.tooltip.summary": "A rough paper that can be used to _polish materials_. Can be automatically applied using the Deployer.", + "item.create.sand_paper.tooltip.summary": "Can be used to _refine materials_. The process can be automated with a Deployer.", "item.create.sand_paper.tooltip.condition1": "When Used", "item.create.sand_paper.tooltip.behaviour1": "Applies polish to items held in the _offhand_ or lying on the _floor_ when _looking at them_", "item.create.builders_tea.tooltip": "BUILDERS TEA", "item.create.builders_tea.tooltip.summary": "The perfect drink to get the day started- _Motivating_ and _Saturating._", - "item.create.refined_radiance.tooltip": "REFINED RADIANCE", - "item.create.refined_radiance.tooltip.summary": "A Chromatic material forged from _absorbed light_.", - "item.create.refined_radiance.tooltip.condition1": "Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "Usages for this material will be available in a future release.", - - "item.create.shadow_steel.tooltip": "SHADOW STEEL", - "item.create.shadow_steel.tooltip.summary": "A Chromatic material forged _in the void_.", - "item.create.shadow_steel.tooltip.condition1": "Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "Usages for this material will be available in a future release.", - "item.create.linked_controller.tooltip": "LINKED CONTROLLER", "item.create.linked_controller.tooltip.summary": "Grants _handheld_ _control_ over _Redstone Link_ frequencies assigned to its _six_ _buttons_.", "item.create.linked_controller.tooltip.condition1": "R-Click", @@ -2004,10 +2083,15 @@ "item.create.linked_controller.tooltip.condition4": "R-Click on Lectern", "item.create.linked_controller.tooltip.behaviour4": "Places the Controller into the Lectern for easy activation. (R-Click while Sneaking to retrieve it)", - "item.create.diving_helmet.tooltip": "DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "Together with a _Copper_ _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", - "item.create.diving_helmet.tooltip.condition1": "When Worn", - "item.create.diving_helmet.tooltip.behaviour1": "Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", + "item.create.copper_diving_helmet.tooltip": "COPPER DIVING HELMET", + "item.create.copper_diving_helmet.tooltip.summary": "Together with a _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", + "item.create.copper_diving_helmet.tooltip.condition1": "When Worn", + "item.create.copper_diving_helmet.tooltip.behaviour1": "Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", + + "item.create.netherite_diving_helmet.tooltip": "NETHERITE DIVING HELMET", + "item.create.netherite_diving_helmet.tooltip.summary": "Together with a _Netherite Backtank_, this can protect you from _extreme heat_. To be effective, _Legs and Feet_ have to be covered in _Netherite_, too.", + "item.create.netherite_diving_helmet.tooltip.condition1": "When Worn (Full set)", + "item.create.netherite_diving_helmet.tooltip.behaviour1": "Provides immunity to _Fire_ and _Lava_, slowly draining _Air Pressure_ from the Backtank. Also grants _improved vision_ in Lava", "item.create.copper_backtank.tooltip": "COPPER BACKTANK", "item.create.copper_backtank.tooltip.summary": "A _Wearable_ _Tank_ for carrying Pressurized Air.", @@ -2016,6 +2100,13 @@ "item.create.copper_backtank.tooltip.condition2": "When placed, Powered by Kinetics", "item.create.copper_backtank.tooltip.behaviour2": "_Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", + "item.create.netherite_backtank.tooltip": "NETHERITE BACKTANK", + "item.create.netherite_backtank.tooltip.summary": "A _Wearable_ _Tank_ for carrying Pressurized Air.", + "item.create.netherite_backtank.tooltip.condition1": "When Worn", + "item.create.netherite_backtank.tooltip.behaviour1": "Provides _Pressurized_ _Air_ to Equipment that requires it.", + "item.create.netherite_backtank.tooltip.condition2": "When placed, Powered by Kinetics", + "item.create.netherite_backtank.tooltip.behaviour2": "_Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", + "block.create.placard.tooltip": "PLACARD", "block.create.placard.tooltip.summary": "_Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", "block.create.placard.tooltip.condition1": "When R-Clicked with Item", @@ -2028,10 +2119,15 @@ "block.create.flywheel.tooltip.condition1": "When Powered by Kinetics", "block.create.flywheel.tooltip.behaviour1": "Starts spinning.", - "item.create.diving_boots.tooltip": "DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", - "item.create.diving_boots.tooltip.condition1": "When Worn", - "item.create.diving_boots.tooltip.behaviour1": "Wielder _sinks_ _faster_ and _cannot_ _swim_. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", + "item.create.copper_diving_boots.tooltip": "COPPER DIVING BOOTS", + "item.create.copper_diving_boots.tooltip.summary": "A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", + "item.create.copper_diving_boots.tooltip.condition1": "When Worn", + "item.create.copper_diving_boots.tooltip.behaviour1": "Wielder _descends_ more _quickly_ in liquids. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", + + "item.create.netherite_diving_boots.tooltip": "NETHERITE DIVING BOOTS", + "item.create.netherite_diving_boots.tooltip.summary": "A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor, including Oceans made of Lava.", + "item.create.netherite_diving_boots.tooltip.condition1": "When Worn", + "item.create.netherite_diving_boots.tooltip.behaviour1": "Wielder _descends_ more _quickly_ in liquids. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", "item.create.crafting_blueprint.tooltip": "CRAFTING BLUEPRINT", "item.create.crafting_blueprint.tooltip.summary": "_Placed_ on a wall, it can be used to _specify_ _ingredient_ _arrangements_ for easier manual crafting. Each slot represents a Recipe.", @@ -2041,37 +2137,54 @@ "item.create.crafting_blueprint.behaviour2": "_Applies_ the _configured_ _recipe_ with matching Ingredients found in your _Inventory_. _Sneak_ to craft up to a _Stack_ of items.", "item.create.minecart_coupling.tooltip": "MINECART COUPLING", - "item.create.minecart_coupling.tooltip.summary": "_Chains_ all your _Minecarts_ or _Carriage Contraptions_ together to form a majestic Train.", - "item.create.minecart_coupling.tooltip.condition1": "When Used on Minecart", - "item.create.minecart_coupling.tooltip.behaviour1": "_Couples_ two Minecarts together, attempting to keep them at a _constant distance_ while moving.", + "item.create.minecart_coupling.tooltip.summary": "_Chains_ together individual _Minecarts_, causing them to move as a group.", "item.create.experience_nugget.tooltip": "NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "_Ding!_ A speck of _inspiration_ from your fantastic inventions.", + "item.create.experience_nugget.tooltip.summary": "A speck of _inspiration_ from your fantastic inventions.", "item.create.experience_nugget.tooltip.condition1": "When Used", "item.create.experience_nugget.tooltip.behaviour1": "_Redeems_ _Experience_ points contained within.", "block.create.peculiar_bell.tooltip": "PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may cause side-effects...", + "block.create.peculiar_bell.tooltip.summary": "A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may have side-effects...", "block.create.haunted_bell.tooltip": "HAUNTED BELL", "block.create.haunted_bell.tooltip.summary": "A _Cursed Bell_ haunted by lost souls of the Nether.", "block.create.haunted_bell.tooltip.condition1": "When Held or Rang", "block.create.haunted_bell.tooltip.behaviour1": "Highlights nearby _Lightless Spots_ on which _Hostile Mobs_ can spawn.", + "block.create.copycat_panel.tooltip": "COPYCAT PANEL", + "block.create.copycat_panel.tooltip.summary": "_Converts_ any _full block_ into a decorative panel. Also accepts _Bars_ and _Trapdoors_.", + "block.create.copycat_panel.tooltip.condition1": "When R-Clicked", + "block.create.copycat_panel.tooltip.behaviour1": "Applies _held item_ as its _material_ if possible. _Click again_ to cycle _orientation_ or _powered_ state. Use a _Wrench_ to _reset_ the material.", + + "block.create.copycat_step.tooltip": "COPYCAT STEP", + "block.create.copycat_step.tooltip.summary": "_Converts_ any _full block_ into a decorative step.", + "block.create.copycat_step.tooltip.condition1": "When R-Clicked", + "block.create.copycat_step.tooltip.behaviour1": "Applies _held item_ as its _material_ if possible. _Click again_ to cycle _orientation_ or _powered_ state. Use a _Wrench_ to _reset_ the material.", + + "block.create.clipboard.tooltip": "CLIPBOARD", + "block.create.clipboard.tooltip.summary": "_Keeps your notes_ and makes you look more professional.", + "block.create.clipboard.tooltip.condition1": "When R-Clicked", + "block.create.clipboard.tooltip.behaviour1": "Opens the _Interface_. _Sneak-Click_ to _place_ it on a surface.", + "block.create.clipboard.tooltip.condition2": "When Used on Blocks", + "block.create.clipboard.tooltip.behaviour2": "Some blocks' _settings_, such as filters, can be _copied (R-Click)_ and _applied (L-Click)_ elsewhere.", + "_": "->------------------------] Ponder Content [------------------------<-", "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "This behaviour can be modified using a Wrench", "create.ponder.shared.storage_on_contraption": "Inventories attached to the Contraption will pick up their drops automatically", "create.ponder.shared.rpm8": "8 RPM", "create.ponder.shared.rpm32": "32 RPM", + "create.ponder.shared.behaviour_modify_value_panel": "This behaviour can be modified using the value panel", "create.ponder.shared.rpm16_source": "Source: 16 RPM", - "create.ponder.shared.movement_anchors": "With the help of Super Glue, larger structures can be moved.", + "create.ponder.shared.movement_anchors": "With the help of Super Glue, larger structures can be moved", "create.ponder.tag.redstone": "Logic Components", "create.ponder.tag.redstone.description": "Components which help with redstone engineering", "create.ponder.tag.contraption_assembly": "Block Attachment Utility", "create.ponder.tag.contraption_assembly.description": "Tools and Components used to assemble structures moved as an animated Contraption", + "create.ponder.tag.recently_updated": "Recent Changes", + "create.ponder.tag.recently_updated.description": "Components that have been added or changed significantly in the latest versions of Create", "create.ponder.tag.fluids": "Fluid Manipulators", "create.ponder.tag.fluids.description": "Components which help relaying and making use of Fluids", "create.ponder.tag.decoration": "Aesthetics", @@ -2168,7 +2281,7 @@ "create.ponder.brass_funnel.header": "The Brass Funnel", "create.ponder.brass_funnel.text_1": "Andesite Funnels can only ever extract single items.", "create.ponder.brass_funnel.text_2": "Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "Scrolling on the filter slot allows for precise control over the extracted stack size.", + "create.ponder.brass_funnel.text_3": "The value panel allows for precise control over the extracted stack size.", "create.ponder.brass_funnel.text_4": "Using items on the filter slot will restrict the funnel to only transfer matching stacks.", "create.ponder.brass_tunnel.header": "Using Brass Tunnels", @@ -2182,7 +2295,7 @@ "create.ponder.brass_tunnel.text_8": "For this, items can also be inserted into the Tunnel block directly", "create.ponder.brass_tunnel_modes.header": "Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", + "create.ponder.brass_tunnel_modes.text_1": "The distribution behaviour of Brass Tunnels can be configured", "create.ponder.brass_tunnel_modes.text_10": "'Synchronize Inputs' is a unique setting for Brass Tunnels", "create.ponder.brass_tunnel_modes.text_11": "Items are only allowed past if every tunnel in the group has one waiting", "create.ponder.brass_tunnel_modes.text_12": "This ensures that all affected belts supply items at the same rate", @@ -2232,7 +2345,8 @@ "create.ponder.chute.header": "Transporting Items downward via Chutes", "create.ponder.chute.text_1": "Chutes can transport items vertically from and to inventories", "create.ponder.chute.text_2": "Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "Placing chutes targeting the side faces of another will make it diagonal", + "create.ponder.chute.text_3": "Using Industrial Iron Blocks, chutes can be encased", + "create.ponder.chute.text_4": "Placing chutes targeting the side faces of another will make it diagonal", "create.ponder.chute_upward.header": "Transporting Items upward via Chutes", "create.ponder.chute_upward.text_1": "Using Encased Fans at the top or bottom, a Chute can move items upward", @@ -2267,6 +2381,14 @@ "create.ponder.cogwheel_casing.text_2": "Components added after encasing will not connect to the shaft outputs", "create.ponder.cogwheel_casing.text_3": "The Wrench can be used to toggle connections", + "create.ponder.contraption_controls.header": "Using Contraption Controls", + "create.ponder.contraption_controls.text_1": "Actors on moving contraptions are always active by default", + "create.ponder.contraption_controls.text_2": "Contraption Controls can be used to toggle them on the fly", + "create.ponder.contraption_controls.text_3": "They can be attached anywhere on the contraption", + "create.ponder.contraption_controls.text_4": "While disassembled, the filter can be changed to target specific types of actors", + "create.ponder.contraption_controls.text_5": "If it is redstone-activated during assembly...", + "create.ponder.contraption_controls.text_6": "...targeted actors will be turned off from the start", + "create.ponder.creative_fluid_tank.header": "Creative Fluid Tanks", "create.ponder.creative_fluid_tank.text_1": "Creative Fluid Tanks can be used to provide a bottomless supply of fluid", "create.ponder.creative_fluid_tank.text_2": "Right-Click with a fluid containing item to configure it", @@ -2275,7 +2397,7 @@ "create.ponder.creative_motor.header": "Generating Rotational Force using Creative Motors", "create.ponder.creative_motor.text_1": "Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "Scrolling on the back panel changes the RPM of the motors' rotational output", + "create.ponder.creative_motor.text_2": "The generated speed can be configured on its input panels", "create.ponder.creative_motor_mojang.header": "Mojang's Enigma", @@ -2331,8 +2453,8 @@ "create.ponder.display_board.header": "Using Display Boards", "create.ponder.display_board.text_1": "Display Boards are a scalable alternative to the sign", "create.ponder.display_board.text_2": "They require Rotational Force to operate", - "create.ponder.display_board.text_3": "Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "...or through the use of Display Links", + "create.ponder.display_board.text_3": "Static text can be applied using written Clipboards", + "create.ponder.display_board.text_4": "And dynamic text through the use of Display Links", "create.ponder.display_board.text_5": "Dyes can be applied to individual lines of the board", "create.ponder.display_board.text_6": "Lines can be reset by clicking them with an empty hand", @@ -2351,6 +2473,31 @@ "create.ponder.display_link_redstone.text_2": "Once unpowered, the Timer is reset and new info is sent immediately", "create.ponder.display_link_redstone.text_3": "Signals emitted from the source do not affect the Link", + "create.ponder.elevator_pulley.header": "Using the Elevator Pulley", + "create.ponder.elevator_pulley.text_1": "Elevator Pulleys can move structures vertically between marked locations", + "create.ponder.elevator_pulley.text_10": "Any redstone contact sharing this column will be converted", + "create.ponder.elevator_pulley.text_11": "Supply a redstone pulse to call the elevator to the contact", + "create.ponder.elevator_pulley.text_12": "The movement speed depends on the rotation input on the pulley", + "create.ponder.elevator_pulley.text_13": "Scroll and click on the controls block to choose a floor while on-board", + "create.ponder.elevator_pulley.text_14": "Right-Clicking the assembled pulley will turn the cabin back into blocks", + "create.ponder.elevator_pulley.text_15": "Sliding doors attached to the cabin will open and close automatically", + "create.ponder.elevator_pulley.text_16": "Elevator Contacts emit a signal while the cabin is on their floor", + "create.ponder.elevator_pulley.text_17": "This can be useful to trigger doors or special effects upon arrival", + "create.ponder.elevator_pulley.text_18": "Display Links on any of the contacts can show the current floor of the elevator", + "create.ponder.elevator_pulley.text_2": "Start by constructing a cabin", + "create.ponder.elevator_pulley.text_3": "Place a pair of Redstone Contacts facing each other...", + "create.ponder.elevator_pulley.text_4": "...and glue one of them to your moving structure", + "create.ponder.elevator_pulley.text_5": "Contraption Controls can be attached to make floor selection easier", + "create.ponder.elevator_pulley.text_6": "Ensure that the pulley is supplied with Rotational Power", + "create.ponder.elevator_pulley.text_7": "Right-Clicking the pulley assembles the elevator", + "create.ponder.elevator_pulley.text_8": "The stationary contact now turns into an Elevator Contact", + "create.ponder.elevator_pulley.text_9": "Elevator Contacts represent a 'floor' and can be configured", + + "create.ponder.elevator_pulley_multi_rope.header": "Synchronised Pulley Movement", + "create.ponder.elevator_pulley_multi_rope.text_1": "Whenever a pulley assembles a contraption...", + "create.ponder.elevator_pulley_multi_rope.text_2": "...other pulleys on the same layer will connect to the structure", + "create.ponder.elevator_pulley_multi_rope.text_3": "They do not require to be powered, the effect is purely cosmetic", + "create.ponder.empty_blaze_burner.header": "Using Empty Blaze Burners", "create.ponder.empty_blaze_burner.text_1": "Right-click a Blaze with the empty burner to capture it", "create.ponder.empty_blaze_burner.text_2": "Alternatively, Blazes can be collected from their Spawners directly", @@ -2361,7 +2508,7 @@ "create.ponder.encased_fluid_pipe.header": "Encasing Fluid Pipes", "create.ponder.encased_fluid_pipe.text_1": "Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "Aside from being conceiled, Encased Pipes are locked into their connectivity state", + "create.ponder.encased_fluid_pipe.text_2": "Aside from being concealed, Encased Pipes are locked into their connectivity state", "create.ponder.encased_fluid_pipe.text_3": "It will no longer react to any neighbouring blocks being added or removed", "create.ponder.fan_direction.header": "Air flow of Encased Fans", @@ -2467,8 +2614,7 @@ "create.ponder.hand_crank.header": "Generating Rotational Force using Hand Cranks", "create.ponder.hand_crank.text_1": "Hand Cranks can be used by players to apply rotational force manually", "create.ponder.hand_crank.text_2": "Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "Sneak and Hold Right-Click to rotate it Clockwise", + "create.ponder.hand_crank.text_3": "Sneak and Hold Right-Click to rotate it Clockwise", "create.ponder.hose_pulley.header": "Source Filling and Draining using Hose Pulleys", "create.ponder.hose_pulley.text_1": "Hose Pulleys can be used to fill or drain large bodies of Fluid", @@ -2513,13 +2659,20 @@ "create.ponder.large_cogwheel.text_1": "Large cogwheels can connect to each other at right angles", "create.ponder.large_cogwheel.text_2": "It will help relaying conveyed speed to other axes of rotation", + "create.ponder.large_water_wheel.header": "Generating Rotational Force using Large Water Wheels", + "create.ponder.large_water_wheel.text_1": "Large Water Wheels draw force from adjacent Water Currents", + "create.ponder.large_water_wheel.text_2": "Covering additional sides will not improve its kinetic output further", + "create.ponder.large_water_wheel.text_3": "These rotate only at half the speed of regular water wheels...", + "create.ponder.large_water_wheel.text_4": "...but provide a substantially higher stress capacity", + "create.ponder.large_water_wheel.text_5": "Use wood planks on the wheel to change its appearance", + "create.ponder.linear_chassis_attachment.header": "Attaching blocks using Linear Chassis", "create.ponder.linear_chassis_attachment.text_1": "The open faces of a Linear Chassis can be made Sticky", "create.ponder.linear_chassis_attachment.text_2": "Click again to make the opposite side sticky", "create.ponder.linear_chassis_attachment.text_3": "Sneak and Right-Click with an empty hand to remove the slime", "create.ponder.linear_chassis_attachment.text_4": "Stickied faces of the Linear Chassis will attach a line of blocks in front of it", "create.ponder.linear_chassis_attachment.text_5": "Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", + "create.ponder.linear_chassis_attachment.text_6": "Holding CTRL adjusts the range of all connected Chassis Blocks", "create.ponder.linear_chassis_attachment.text_7": "Attaching blocks to any other side requires the use of Super Glue", "create.ponder.linear_chassis_attachment.text_8": "Using these mechanics, structures of any shape can move as a Contraption", @@ -2531,7 +2684,7 @@ "create.ponder.mechanical_arm.header": "Setting up Mechanical Arms", "create.ponder.mechanical_arm.text_1": "Mechanical Arms have to be assigned their in- and outputs before they are placed", "create.ponder.mechanical_arm.text_2": "Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "Right-Click again to toggle between Input (Blue) and Output (Orange)", + "create.ponder.mechanical_arm.text_3": "Right-Click again to toggle between Input (Blue) and Output (Yellow)", "create.ponder.mechanical_arm.text_4": "Left-Click components to remove their Selection", "create.ponder.mechanical_arm.text_5": "Once placed, the Mechanical Arm will target the blocks selected previously", "create.ponder.mechanical_arm.text_6": "They can have any amount of in- and outputs within their range", @@ -2551,7 +2704,7 @@ "create.ponder.mechanical_arm_modes.text_2": "Outputs", "create.ponder.mechanical_arm_modes.text_3": "Whenever an Arm has to choose between multiple valid outputs...", "create.ponder.mechanical_arm_modes.text_4": "...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "Scrolling with a Wrench will allow you to configure it", + "create.ponder.mechanical_arm_modes.text_5": "The value panel will allow you to configure it", "create.ponder.mechanical_arm_modes.text_6": "Round Robin mode simply cycles through all outputs that are available", "create.ponder.mechanical_arm_modes.text_7": "If an output is unable to take more items, it will be skipped", "create.ponder.mechanical_arm_modes.text_8": "Forced Round Robin mode will never skip outputs, and instead wait until they are free", @@ -2633,18 +2786,34 @@ "create.ponder.mechanical_pump_flow.header": "Fluid Transportation using Mechanical Pumps", "create.ponder.mechanical_pump_flow.text_1": "Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "When powered, their arrow indicates the direction of flow", + "create.ponder.mechanical_pump_flow.text_2": "Their arrow indicates the direction of flow", "create.ponder.mechanical_pump_flow.text_3": "The network behind is now pulling fluids...", "create.ponder.mechanical_pump_flow.text_4": "...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "Use a Wrench to reverse the orientation of pumps manually", + "create.ponder.mechanical_pump_flow.text_5": "The pumps direction is unaffected by the input rotation", + "create.ponder.mechanical_pump_flow.text_6": "Instead, a Wrench can be used to reverse the direction", "create.ponder.mechanical_pump_speed.header": "Throughput of Mechanical Pumps", "create.ponder.mechanical_pump_speed.text_1": "Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", "create.ponder.mechanical_pump_speed.text_2": "Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "...aswell as how quickly fluids are transferred", + "create.ponder.mechanical_pump_speed.text_3": "...and the speed at which fluids are transferred", "create.ponder.mechanical_pump_speed.text_4": "Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "Alternating their orientation can help align their flow directions", + "create.ponder.mechanical_pump_speed.text_5": "Ensure that all of them are facing in the same direction", + + "create.ponder.mechanical_roller_fill.header": "Filling terrain with the Roller", + "create.ponder.mechanical_roller_fill.text_1": "While disassembled, rollers can be set to other modes", + "create.ponder.mechanical_roller_fill.text_2": "The 'fill' modes can help to bridge gaps between pavement and terrain", + "create.ponder.mechanical_roller_fill.text_3": "On 'straight fill', they will place simple columns down to the surface", + "create.ponder.mechanical_roller_fill.text_4": "On 'sloped fill', layers placed further down will increase in size", + "create.ponder.mechanical_roller_fill.text_5": "As opposed to 'clear & pave', neither of these modes will cause the rollers to break existing blocks", + + "create.ponder.mechanical_roller_pave.header": "Clearing and Paving with the Roller", + "create.ponder.mechanical_roller_pave.text_1": "Mechanical rollers help to clean up terrain around tracks or paths", + "create.ponder.mechanical_roller_pave.text_2": "In its default mode, without a material set, it will simply clear blocks like a Drill", + "create.ponder.mechanical_roller_pave.text_3": "While disassembled, a suitable paving material can be specified", + "create.ponder.mechanical_roller_pave.text_4": "Materials can be supplied via chests or barrels attached to the structure", + "create.ponder.mechanical_roller_pave.text_5": "In addition to breaking blocks, it will now replace the layer beneath them", + "create.ponder.mechanical_roller_pave.text_6": "Note that any block destroyed by a roller has a chance not to yield drops", + "create.ponder.mechanical_roller_pave.text_7": "Rollers are especially useful on Trains, but can also be used on most other types of moving contraptions", "create.ponder.mechanical_saw_breaker.header": "Cutting Trees with the Mechanical Saw", "create.ponder.mechanical_saw_breaker.text_1": "When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", @@ -2669,8 +2838,8 @@ "create.ponder.millstone.text_5": "The outputs can also be extracted by automation", "create.ponder.nixie_tube.header": "Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "Using name tags edited with an anvil, custom text can be displayed", + "create.ponder.nixie_tube.text_1": "When powered by Redstone, Nixie Tubes will display the signal strength", + "create.ponder.nixie_tube.text_2": "Using written Clipboards, custom text can be displayed", "create.ponder.nixie_tube.text_3": "Right-Click with Dye to change their display colour", "create.ponder.piston_pole.header": "Piston Extension Poles", @@ -2688,7 +2857,7 @@ "create.ponder.portable_fluid_interface.text_8": "After no contents have been exchanged for a while, the contraption will continue on its way", "create.ponder.portable_storage_interface.header": "Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "Inventories on moving contraptions cannot be accessed by players.", + "create.ponder.portable_storage_interface.text_1": "Moving inventories can be tricky to access with automation.", "create.ponder.portable_storage_interface.text_2": "This component can interact with storage without the need to stop the contraption.", "create.ponder.portable_storage_interface.text_3": "Place a second one with a gap of 1 or 2 blocks inbetween", "create.ponder.portable_storage_interface.text_4": "Whenever they pass by each other, they will engage in a connection", @@ -2716,13 +2885,13 @@ "create.ponder.pulse_extender.text_1": "Pulse Extenders can lengthen a signal passing through", "create.ponder.pulse_extender.text_2": "They activate after a short delay...", "create.ponder.pulse_extender.text_3": "...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "The configured duration can range up to 30 minutes", + "create.ponder.pulse_extender.text_4": "Using the value panel, the discharge time can be configured", + "create.ponder.pulse_extender.text_5": "The configured duration can range up to an hour", "create.ponder.pulse_repeater.header": "Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "Configured delays can range up to 30 minutes", + "create.ponder.pulse_repeater.text_1": "Pulse Repeaters emit a short pulse after a delay", + "create.ponder.pulse_repeater.text_2": "Using the value panel, the charge time can be configured", + "create.ponder.pulse_repeater.text_3": "Configured delays can range up to an hour", "create.ponder.radial_chassis.header": "Attaching blocks using Radial Chassis", "create.ponder.radial_chassis.text_1": "Radial Chassis connect to identical Chassis blocks in a row", @@ -2760,6 +2929,11 @@ "create.ponder.rope_pulley_modes.text_1": "Whenever Pulleys stop moving, the moved structure reverts to blocks", "create.ponder.rope_pulley_modes.text_2": "It can be configured never to revert to solid blocks, or only at the location it started at", + "create.ponder.rope_pulley_multi_rope.header": "Synchronised Pulley Movement", + "create.ponder.rope_pulley_multi_rope.text_1": "Whenever a pulley assembles a contraption...", + "create.ponder.rope_pulley_multi_rope.text_2": "...other pulleys on the same layer will connect to the structure", + "create.ponder.rope_pulley_multi_rope.text_3": "They do not require to be powered, the effect is purely cosmetic", + "create.ponder.rose_quartz_lamp.header": "Rose Quartz Lamps", "create.ponder.rose_quartz_lamp.text_1": "Rose Quartz Lamps activate on a Redstone signal", "create.ponder.rose_quartz_lamp.text_2": "They will continue to emit redstone power afterwards", @@ -2770,7 +2944,7 @@ "create.ponder.rotation_speed_controller.header": "Using the Rotational Speed Controller", "create.ponder.rotation_speed_controller.text_1": "Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "Using the scroll input on its side, the conveyed speed can be configured", + "create.ponder.rotation_speed_controller.text_2": "Using the value panel on its side, the conveyed speed can be configured", "create.ponder.sail.header": "Assembling Windmills using Sails", "create.ponder.sail.text_1": "Sails are handy blocks to create Windmills with", @@ -2797,10 +2971,18 @@ "create.ponder.smart_chute.header": "Filtering Items using Smart Chutes", "create.ponder.smart_chute.text_1": "Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "Use the Mouse Wheel to specify the extracted stack size", + "create.ponder.smart_chute.text_2": "Items in the filter slot specify what to extract or transfer", + "create.ponder.smart_chute.text_3": "Use the value panel to specify the extracted stack size", "create.ponder.smart_chute.text_4": "Redstone power will prevent Smart Chutes from acting.", + "create.ponder.smart_observer.header": "Advanced detection with Smart Observers", + "create.ponder.smart_observer.text_1": "Smart Observers can be used to detect a variety of events", + "create.ponder.smart_observer.text_2": "It can detect items or fluids inside of generic containers", + "create.ponder.smart_observer.text_3": "The filter slot can be used to look for specific contents only", + "create.ponder.smart_observer.text_4": "It also activates when the block itself matches the filter", + "create.ponder.smart_observer.text_5": "Additionally, smart observers can monitor belts, chutes and pipes", + "create.ponder.smart_observer.text_6": "...and will emit a pulse, if an item enters or exits a funnel", + "create.ponder.smart_pipe.header": "Controlling Fluid flow using Smart Pipes", "create.ponder.smart_pipe.text_1": "Smart pipes can help control flows by fluid type", "create.ponder.smart_pipe.text_2": "When placed directly at the source, they can specify the type of fluid to extract", @@ -2808,7 +2990,7 @@ "create.ponder.smart_pipe.text_4": "When placed further down a pipe network, smart pipes will only let matching fluids continue", "create.ponder.speedometer.header": "Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "The Speedometer displays the current Speed of the attached components", + "create.ponder.speedometer.text_1": "The Speedometer displays the current Speed of attached components", "create.ponder.speedometer.text_2": "When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", "create.ponder.speedometer.text_3": "Comparators can emit analog Restone Signals relative to the Speedometer's measurements", @@ -2868,6 +3050,17 @@ "create.ponder.super_glue.text_5": "Overlapping glue volumes will move together", "create.ponder.super_glue.text_6": "Blocks hanging on others usually do not require glue", + "create.ponder.threshold_switch.header": "Monitoring with the Threshold Switch", + "create.ponder.threshold_switch.text_1": "Threshold Switches monitor the fill level of containers", + "create.ponder.threshold_switch.text_2": "When the inventory content exceeds the upper threshold...", + "create.ponder.threshold_switch.text_3": "...the switch will change its redstone output", + "create.ponder.threshold_switch.text_4": "The signal stays until the lower threshold is reached", + "create.ponder.threshold_switch.text_5": "The redstone output can now be used to control item supply, keeping the buffer filled", + "create.ponder.threshold_switch.text_6": "The specific thresholds can be changed in the UI", + "create.ponder.threshold_switch.text_7": "A filter can help to only count specific contents toward the total", + "create.ponder.threshold_switch.text_8": "Fluid buffers can be monitored in a similar fashion", + "create.ponder.threshold_switch.text_9": "...as well as, curiously, the length of an extended rope pulley", + "create.ponder.track_chunks.header": "Traversing unloaded Chunks", "create.ponder.track_chunks.text_1": "Tracks stay functional outside of loaded chunks", "create.ponder.track_chunks.text_2": "Trains will travel through inactive sections of the world without issue", @@ -2939,7 +3132,7 @@ "create.ponder.train_signal_redstone.header": "Signals & Redstone", "create.ponder.train_signal_redstone.text_1": "Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "Reversely, red signals emit a comparator output", + "create.ponder.train_signal_redstone.text_2": "Conversely, red signals emit a comparator output", "create.ponder.train_signal_signaling.header": "Collision Prevention with Signals", "create.ponder.train_signal_signaling.text_1": "Train Signals divide a track into segments", @@ -2952,12 +3145,13 @@ "create.ponder.train_signal_signaling.text_8": "...would not be able to leave the Segment immediately", "create.ponder.train_signal_signaling.text_9": "This helps keeping queued Trains out of a busy Segment", - "create.ponder.valve_handle.header": "Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "Valve handles can be dyed for aesthetic purposes", + "create.ponder.valve_handle.header": "Precise rotation using Valve Handles", + "create.ponder.valve_handle.text_1": "Valve handles can be used to rotate components by a precise angle", + "create.ponder.valve_handle.text_2": "The angle can be configured on the input panel", + "create.ponder.valve_handle.text_3": "Right-Click to activate one rotation", + "create.ponder.valve_handle.text_4": "Sneak-Right-Click to activate it in the opposite direction", + "create.ponder.valve_handle.text_5": "Mind that Bearings have to be specifically told not to disassemble", + "create.ponder.valve_handle.text_6": "Valve handles can be dyed for aesthetic purposes", "create.ponder.valve_pipe.header": "Controlling Fluid flow using Valves", "create.ponder.valve_pipe.text_1": "Valve pipes help control fluids propagating through pipe networks", @@ -2967,14 +3161,13 @@ "create.ponder.water_wheel.header": "Generating Rotational Force using Water Wheels", "create.ponder.water_wheel.text_1": "Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "Facing the opposite way, they will not be as effective", + "create.ponder.water_wheel.text_2": "Covering additional sides will not improve its kinetic output further", + "create.ponder.water_wheel.text_3": "Use wood planks on the wheel to change its appearance", "create.ponder.weighted_ejector.header": "Using Weighted Ejectors", "create.ponder.weighted_ejector.text_1": "Sneak and Right-Click holding an Ejector to select its target location", "create.ponder.weighted_ejector.text_10": "It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "Other Entities will always trigger an Ejector when stepping on it", + "create.ponder.weighted_ejector.text_11": "Mobs and Players will always trigger an Ejector when stepping on it", "create.ponder.weighted_ejector.text_2": "The placed ejector will now launch objects to the marked location", "create.ponder.weighted_ejector.text_3": "A valid target can be at any height or distance within range", "create.ponder.weighted_ejector.text_4": "They cannot however be off to a side", @@ -2982,11 +3175,11 @@ "create.ponder.weighted_ejector.text_6": "Supply Rotational Force in order to charge it up", "create.ponder.weighted_ejector.text_7": "Items placed on the ejector cause it to trigger", "create.ponder.weighted_ejector.text_8": "If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "Using the Wrench, a required Stack Size can be configured", + "create.ponder.weighted_ejector.text_9": "Using the value panel, a required Stack Size can be configured", "create.ponder.weighted_ejector_redstone.header": "Controlling Weighted Ejectors with Redstone", "create.ponder.weighted_ejector_redstone.text_1": "When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "Furthermore, Observers can detect when Ejectors activate", + "create.ponder.weighted_ejector_redstone.text_2": "Observers can detect when Ejectors activate", "create.ponder.weighted_ejector_tunnel.header": "Splitting item stacks using Weighted Ejectors", "create.ponder.weighted_ejector_tunnel.text_1": "Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", @@ -3001,7 +3194,7 @@ "create.ponder.windmill_source.text_3": "If enough Sail-like blocks are included, this can act as a Windmill", "create.ponder.windmill_source.text_4": "Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", "create.ponder.windmill_source.text_5": "The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "Use a Wrench to configure its rotation direction", + "create.ponder.windmill_source.text_6": "Use the value panel to configure its rotation direction", "create.ponder.windmill_source.text_7": "Right-click the Bearing anytime to stop and edit the Structure again", "create.ponder.windmill_structure.header": "Windmill Contraptions", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json deleted file mode 100644 index 2d71931e06..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 823", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Akazienholzfenster", - "block.create.acacia_window_pane": "Akazienholzfensterscheibe", - "block.create.adjustable_chain_gearshift": "Verstellbares Kettengetriebe", - "block.create.analog_lever": "Analoger Schalter", - "block.create.andesite_belt_funnel": "Riementrichter aus Andesit", - "block.create.andesite_casing": "Andesitrahmen", - "block.create.andesite_encased_cogwheel": "Andesit-Zahnrad", - "block.create.andesite_encased_large_cogwheel": "Großes Andesit-Zahnrad", - "block.create.andesite_encased_shaft": "Andesitummantelte Welle", - "block.create.andesite_funnel": "Andesittrichter", - "block.create.andesite_ladder": "Andesitleiter", - "block.create.andesite_pillar": "Andesitsäule", - "block.create.andesite_tunnel": "Andesittunnel", - "block.create.asurine": "Asurin", - "block.create.asurine_pillar": "Asurinsäule", - "block.create.basin": "Behälter", - "block.create.belt": "Mechanischer Riemen", - "block.create.birch_window": "Birkenholzfenster", - "block.create.birch_window_pane": "Birkenholzfensterscheibe", - "block.create.black_nixie_tube": "Schwarze Nixie-Röhre", - "block.create.black_sail": "Schwarzes Segel", - "block.create.black_seat": "Schwarzer Sitz", - "block.create.black_toolbox": "Schwarzer Werkzeugkasten", - "block.create.black_valve_handle": "Schwarzer Ventilgriff", - "block.create.blaze_burner": "Lohenbrenner", - "block.create.blue_nixie_tube": "Blaue Nixie-Röhre", - "block.create.blue_sail": "Blaues Segel", - "block.create.blue_seat": "Blauer Sitz", - "block.create.blue_toolbox": "Blauer Werkzeugkasten", - "block.create.blue_valve_handle": "Blauer Ventilgriff", - "block.create.brass_belt_funnel": "Riementrichter aus Messing", - "block.create.brass_block": "Messing Block", - "block.create.brass_casing": "Messingrahmen", - "block.create.brass_encased_cogwheel": "Messing-Zahnrad", - "block.create.brass_encased_large_cogwheel": "Großes Messing-Zahnrad", - "block.create.brass_encased_shaft": "Messingummantelte Welle", - "block.create.brass_funnel": "Messingtrichter", - "block.create.brass_ladder": "Messingleiter", - "block.create.brass_tunnel": "Messingtunnel", - "block.create.brown_nixie_tube": "Braune Nixie-Röhre", - "block.create.brown_sail": "Braunes Segel", - "block.create.brown_seat": "Brauner Sitz", - "block.create.brown_toolbox": "Brauner Werkzeugkasten", - "block.create.brown_valve_handle": "Brauner Ventilgriff", - "block.create.calcite_pillar": "Kalzitsäule", - "block.create.cart_assembler": "Lorenmonteur", - "block.create.chocolate": "Schokolade", - "block.create.chute": "Rinne", - "block.create.clockwork_bearing": "Uhrwerk-Lager", - "block.create.clutch": "Kupplung", - "block.create.cogwheel": "Zahnrad", - "block.create.content_observer": "Inhaltsbeobachter", - "block.create.controller_rail": "Steuerungsschiene", - "block.create.controls": "Zugsteuerung", - "block.create.copper_backtank": "Kupferne Druckluftflasche", - "block.create.copper_casing": "Kupferrahmen", - "block.create.copper_ladder": "Kupferleiter", - "block.create.copper_shingle_slab": "Kupferschindelstufe", - "block.create.copper_shingle_stairs": "Kupferschindeltreppe", - "block.create.copper_shingles": "Kupferschindeln", - "block.create.copper_tile_slab": "Kupferfliesenstufe", - "block.create.copper_tile_stairs": "Kupferfliesentreppe", - "block.create.copper_tiles": "Kupferfliesen", - "block.create.copper_valve_handle": "Kupfer Ventilgriff", - "block.create.creative_crate": "Kreative anpassbare Kiste", - "block.create.creative_fluid_tank": "Kreativer Flüssigkeitstank", - "block.create.creative_motor": "Kreativer Motor", - "block.create.crimsite": "Karmesit", - "block.create.crimsite_pillar": "Karmesitsäule", - "block.create.crimson_window": "Karmesinfenster", - "block.create.crimson_window_pane": "Karmesinfensterscheibe", - "block.create.crushing_wheel": "Mahlwerkrad", - "block.create.crushing_wheel_controller": "Mahlwerkrad Steurung", - "block.create.cuckoo_clock": "Kuckucksuhr", - "block.create.cut_andesite": "Geschnittener Andesit", - "block.create.cut_andesite_brick_slab": "Geschnittene Andesitziegelstufe", - "block.create.cut_andesite_brick_stairs": "Geschnittene Andesitziegeltreppe", - "block.create.cut_andesite_brick_wall": "Geschnittene Andesitziegelmauer", - "block.create.cut_andesite_bricks": "Geschnittene Andesitziegelsteine", - "block.create.cut_andesite_slab": "Geschnittene Andesitstufe", - "block.create.cut_andesite_stairs": "Geschnittene Andesittreppe", - "block.create.cut_andesite_wall": "Geschnittene Andesitmauer", - "block.create.cut_asurine": "Geschnittenes Asurin", - "block.create.cut_asurine_brick_slab": "Geschnittene Asurinziegelstufe", - "block.create.cut_asurine_brick_stairs": "Geschnittene Asurinziegeltreppe", - "block.create.cut_asurine_brick_wall": "Geschnittene Asurinziegelmauer", - "block.create.cut_asurine_bricks": "Geschnittene Asurinziegelsteine", - "block.create.cut_asurine_slab": "Geschnittene Asurinstufe", - "block.create.cut_asurine_stairs": "Geschnittene Asurintreppe", - "block.create.cut_asurine_wall": "Geschnittene Asurinmauer", - "block.create.cut_calcite": "Geschnittener Kalzit", - "block.create.cut_calcite_brick_slab": "Geschnittene Kalzitziegelstufe", - "block.create.cut_calcite_brick_stairs": "Geschnittene Kalzitziegeltreppe", - "block.create.cut_calcite_brick_wall": "Geschnittene Kalzitziegelmauer", - "block.create.cut_calcite_bricks": "Geschnittene Kalzitziegelsteine", - "block.create.cut_calcite_slab": "Geschnittene Kalzitstufe", - "block.create.cut_calcite_stairs": "Geschnittene Kalzittreppe", - "block.create.cut_calcite_wall": "Geschnittene Kalzitmauer", - "block.create.cut_crimsite": "Geschnittenes Karmesit", - "block.create.cut_crimsite_brick_slab": "Geschnittene Karmesitziegelstufe", - "block.create.cut_crimsite_brick_stairs": "Geschnittene Karmesitziegeltreppe", - "block.create.cut_crimsite_brick_wall": "Geschnittene Karmesitziegelmauer", - "block.create.cut_crimsite_bricks": "Geschnittene Karmesitziegelsteine", - "block.create.cut_crimsite_slab": "Geschnittene Karmesitstufe", - "block.create.cut_crimsite_stairs": "Geschnittene Karmesittreppe", - "block.create.cut_crimsite_wall": "Geschnittene Karmesitmauer", - "block.create.cut_deepslate": "Geschnittener Tiefenschiefer", - "block.create.cut_deepslate_brick_slab": "Geschnittene Tiefenschieferziegelstufe", - "block.create.cut_deepslate_brick_stairs": "Geschnittene Tiefenschieferziegeltreppe", - "block.create.cut_deepslate_brick_wall": "Geschnittene Tiefenschieferziegelmauer", - "block.create.cut_deepslate_bricks": "Geschnittene Tiefenschiefersteine", - "block.create.cut_deepslate_slab": "Geschnittene Tiefenschieferstufe", - "block.create.cut_deepslate_stairs": "Geschnittene Tiefenschiefertreppe", - "block.create.cut_deepslate_wall": "Geschnittene Tiefenschiefermauer", - "block.create.cut_diorite": "Gescnittener Diorit", - "block.create.cut_diorite_brick_slab": "Geschnittene Dioritziegelstufe", - "block.create.cut_diorite_brick_stairs": "Geschnittene Dioritziegeltreppe", - "block.create.cut_diorite_brick_wall": "Geschnittene Dioritziegelmauer", - "block.create.cut_diorite_bricks": "Geschnittene Dioritziegelsteine", - "block.create.cut_diorite_slab": "Geschnittene Dioritstufe", - "block.create.cut_diorite_stairs": "Geschnittene Diorittreppe", - "block.create.cut_diorite_wall": "Geschnittene Dioritmauer", - "block.create.cut_dripstone": "Geschnittener Tropfstein", - "block.create.cut_dripstone_brick_slab": "Geschnittene Tropfsteinziegelstufe", - "block.create.cut_dripstone_brick_stairs": "Geschnittene Tropfsteinziegeltreppe", - "block.create.cut_dripstone_brick_wall": "Geschnittene Tropfsteinziegelmauer", - "block.create.cut_dripstone_bricks": "Geschnittener Tropfsteinziegelsteine", - "block.create.cut_dripstone_slab": "Geschnittene Tropfsteinstufe", - "block.create.cut_dripstone_stairs": "Geschnittene Tropfsteintreppe", - "block.create.cut_dripstone_wall": "Geschnittene Tropfsteinmauer", - "block.create.cut_granite": "Geschnittener Granit", - "block.create.cut_granite_brick_slab": "Geschnittene Granitziegelstufe", - "block.create.cut_granite_brick_stairs": "Geschnittene Granitziegeltreppe", - "block.create.cut_granite_brick_wall": "Geschnittene Granitziegelmauer", - "block.create.cut_granite_bricks": "Geschnittene Granitziegelsteine", - "block.create.cut_granite_slab": "Geschnittene Granitstufe", - "block.create.cut_granite_stairs": "Geschnittene Granittreppe", - "block.create.cut_granite_wall": "Geschnittene Granitmauer", - "block.create.cut_limestone": "Geschnittener Kalkstein", - "block.create.cut_limestone_brick_slab": "Geschnittene Kalksteinziegelstufe", - "block.create.cut_limestone_brick_stairs": "Geschnittene Kalksteinziegeltreppe", - "block.create.cut_limestone_brick_wall": "Geschnittene Kalksteinziegelmauer", - "block.create.cut_limestone_bricks": "Geschnittene Kalksteinziegelsteine", - "block.create.cut_limestone_slab": "Geschnittene Kalksteinstufe", - "block.create.cut_limestone_stairs": "Geschnittene Kalksteintreppe", - "block.create.cut_limestone_wall": "Geschnittene Kalksteinmauer", - "block.create.cut_ochrum": "Geschnittenes Ockrum", - "block.create.cut_ochrum_brick_slab": "Geschnittene Ockrumziegelstufe", - "block.create.cut_ochrum_brick_stairs": "Geschnittene Ockrumziegeltreppe", - "block.create.cut_ochrum_brick_wall": "Geschnittene Ockrumziegelmauer", - "block.create.cut_ochrum_bricks": "Geschnittene Ockrumziegelsteine", - "block.create.cut_ochrum_slab": "Geschnittene Ockrumstufe", - "block.create.cut_ochrum_stairs": "Geschnittene Ockrumtreppe", - "block.create.cut_ochrum_wall": "Geschnittene Ockrummauer", - "block.create.cut_scorchia": "Geschnittenes Scorchia", - "block.create.cut_scorchia_brick_slab": "Geschnittene Scorchiaziegelstufe", - "block.create.cut_scorchia_brick_stairs": "Geschnittene Scorchiaziegeltreppe", - "block.create.cut_scorchia_brick_wall": "Geschnittene Scorchiaziegelmauer", - "block.create.cut_scorchia_bricks": "Geschnittene Scorchiaziegelsteine", - "block.create.cut_scorchia_slab": "Geschnittene Scorchiaziegelstufe", - "block.create.cut_scorchia_stairs": "Geschnittene Scorchiaziegeltreppe", - "block.create.cut_scorchia_wall": "Geschnittene Scorchiaziegelmauer", - "block.create.cut_scoria": "Geschnittenes Scoria", - "block.create.cut_scoria_brick_slab": "Geschnittene Scoriaziegelstufe", - "block.create.cut_scoria_brick_stairs": "Geschnittene Scoriaziegeltreppe", - "block.create.cut_scoria_brick_wall": "Geschnittene Scoriaziegelmauer", - "block.create.cut_scoria_bricks": "Geschnittene Scoriaziegelsteine", - "block.create.cut_scoria_slab": "Geschnittene Scoriaziegelstufe", - "block.create.cut_scoria_stairs": "Geschnittene Scoriaziegeltreppe", - "block.create.cut_scoria_wall": "Geschnittene Scoriaziegelmauer", - "block.create.cut_tuff": "Geschnittener Tuffstein", - "block.create.cut_tuff_brick_slab": "Geschnittene Tuffsteinziegelstufe", - "block.create.cut_tuff_brick_stairs": "Geschnittene Tuffsteinziegeltreppe", - "block.create.cut_tuff_brick_wall": "Geschnittene Tuffsteinziegelmauer", - "block.create.cut_tuff_bricks": "Geschnittene Tuffsteinziegelsteine", - "block.create.cut_tuff_slab": "Geschnittene Tuffsteinstufe", - "block.create.cut_tuff_stairs": "Geschnittene Tuffsteintreppe", - "block.create.cut_tuff_wall": "Geschnittene Tuffsteinmauer", - "block.create.cut_veridium": "Geschnittenes Veridium", - "block.create.cut_veridium_brick_slab": "Geschnittene Veridiumziegelstufe", - "block.create.cut_veridium_brick_stairs": "Geschnittene Veridiumziegeltreppe", - "block.create.cut_veridium_brick_wall": "Geschnittene Veridiumziegelmauer", - "block.create.cut_veridium_bricks": "Geschnittene Veridiumziegelsteine", - "block.create.cut_veridium_slab": "Geschnittene Veridiumziegelstufe", - "block.create.cut_veridium_stairs": "Geschnittene Veridiumziegeltreppe", - "block.create.cut_veridium_wall": "Geschnittene Veridiumziegelmauer", - "block.create.cyan_nixie_tube": "Türkise Nixie-Röhre", - "block.create.cyan_sail": "Türkises Segel", - "block.create.cyan_seat": "Türkiser Sitz", - "block.create.cyan_toolbox": "Türkiser Werkzeugkasten", - "block.create.cyan_valve_handle": "Türkiser Ventilgriff", - "block.create.dark_oak_window": "Schwarzeichenholzfenster", - "block.create.dark_oak_window_pane": "Schwarzeichenholzfensterscheibe", - "block.create.deepslate_pillar": "Tiefenschiefer-Säule", - "block.create.deepslate_zinc_ore": "Tiefenschiefer-Zinkerz", - "block.create.deployer": "Einsatzgerät", - "block.create.depot": "Depot", - "block.create.diorite_pillar": "Dioritsäule", - "block.create.display_board": "Anzeigetafel", - "block.create.display_link": "Anzeige-Link", - "block.create.dripstone_pillar": "Tropfstein-Säule", - "block.create.encased_chain_drive": "Ummantelter Kettenriemen", - "block.create.encased_fan": "Ummantelter Lüfter", - "block.create.encased_fluid_pipe": "Ummanteltes Rohr", - "block.create.exposed_copper_shingle_slab": "Angelaufene Kupferschindelstufe", - "block.create.exposed_copper_shingle_stairs": "Angelaufene Kupferschindeltreppe", - "block.create.exposed_copper_shingles": "Angelaufene Kupferschindel", - "block.create.exposed_copper_tile_slab": "Angelaufene Kupferfliesenstufe", - "block.create.exposed_copper_tile_stairs": "Angelaufene Kupferfliesentreppe", - "block.create.exposed_copper_tiles": "Angelaufene Kupferfliesen", - "block.create.fake_track": "Gleismarkierung für Karten", - "block.create.fluid_pipe": "Flüssigkeitsrohr", - "block.create.fluid_tank": "Flüssigkeitstank", - "block.create.fluid_valve": "Flüssigkeitsventil", - "block.create.flywheel": "Schwungrad", - "block.create.framed_glass": "Gerahmtes Glas", - "block.create.framed_glass_door": "Gerahmte Glastür", - "block.create.framed_glass_pane": "Gerahmte Glasscheibe", - "block.create.framed_glass_trapdoor": "Gerahmte Glasfalltür", - "block.create.gantry_carriage": "Portalkranwagen", - "block.create.gantry_shaft": "Portalkranachse", - "block.create.gearbox": "Getriebe", - "block.create.gearshift": "Gangschaltung", - "block.create.glass_fluid_pipe": "Glasrohr", - "block.create.granite_pillar": "Granitsäule", - "block.create.gray_nixie_tube": "Graue Nixie-Röhre", - "block.create.gray_sail": "Graues Segel", - "block.create.gray_seat": "Grauer Sitz", - "block.create.gray_toolbox": "Grauer Werkzeugkasten", - "block.create.gray_valve_handle": "Grauer Ventilgriff", - "block.create.green_nixie_tube": "Grüne Nixie-Röhre", - "block.create.green_sail": "Grünes Segel", - "block.create.green_seat": "Grüner Sitz", - "block.create.green_toolbox": "Grüner Werkzeugkasten", - "block.create.green_valve_handle": "Grüner Ventilgriff", - "block.create.hand_crank": "Handkurbel", - "block.create.haunted_bell": "Spukglocke", - "block.create.honey": "Honig", - "block.create.horizontal_framed_glass": "Horizontal Gerahmtes Glas", - "block.create.horizontal_framed_glass_pane": "Horizontal Gerahmte Glasscheibe", - "block.create.hose_pulley": "Umlenkrolle", - "block.create.item_drain": "Abfluss", - "block.create.item_vault": "Gegenstandstresor", - "block.create.jungle_window": "Tropenholzfenster", - "block.create.jungle_window_pane": "Tropenholzfensterscheibe", - "block.create.large_bogey": "Großes Drehgestell", - "block.create.large_cogwheel": "Großes Zahnrad", - "block.create.layered_andesite": "Geschichteter Andesit", - "block.create.layered_asurine": "Geschichtetes Asurin", - "block.create.layered_calcite": "Geschichtetes Kalzit", - "block.create.layered_crimsite": "Geschichtetes Karmesit", - "block.create.layered_deepslate": "Geschichteter Tiefenschiefer", - "block.create.layered_diorite": "Geschichteter Diorit", - "block.create.layered_dripstone": "Geschichteter Tropfstein", - "block.create.layered_granite": "Geschichteter Granit", - "block.create.layered_limestone": "Geschichteter Kalkstein", - "block.create.layered_ochrum": "Geschichtetes Ockrum", - "block.create.layered_scorchia": "Geschichtetes Scorchia", - "block.create.layered_scoria": "Geschichtete Schlacke", - "block.create.layered_tuff": "Geschichteter Tuffstein", - "block.create.layered_veridium": "Geschichtetes Veridium", - "block.create.lectern_controller": "Fernsteuerungspult", - "block.create.light_blue_nixie_tube": "Hellblaue Nixie-Röhre", - "block.create.light_blue_sail": "Hellblaues Segel", - "block.create.light_blue_seat": "Hellblauer Sitz", - "block.create.light_blue_toolbox": "Hellblauer Werkzeugkasten", - "block.create.light_blue_valve_handle": "Hellblauer Ventilgriff", - "block.create.light_gray_nixie_tube": "Hellgraue Nixie-Röhre", - "block.create.light_gray_sail": "Hellgraues Segel", - "block.create.light_gray_seat": "Hellgrauer Sitz", - "block.create.light_gray_toolbox": "Hellgrauer Werkzeugkasten", - "block.create.light_gray_valve_handle": "Hellgrauer Ventilgriff", - "block.create.lime_nixie_tube": "Hellgrüne Nixie-Röhre", - "block.create.lime_sail": "Hellgrünes Segel", - "block.create.lime_seat": "Hellgrüner Sitz", - "block.create.lime_toolbox": "Hellgrüner Werkzeugkasten", - "block.create.lime_valve_handle": "Hellgrüner Ventilgriff", - "block.create.limestone": "Kalkstein", - "block.create.limestone_pillar": "Kalksteinsäule", - "block.create.linear_chassis": "Schubgerüst", - "block.create.lit_blaze_burner": "Aktiver Lohenbrenner", - "block.create.magenta_nixie_tube": "Magenta Nixie-Röhre", - "block.create.magenta_sail": "Magenta Segel", - "block.create.magenta_seat": "Magenta Sitz", - "block.create.magenta_toolbox": "Magenta Werkzeugkasten", - "block.create.magenta_valve_handle": "Magenta Ventilgriff", - "block.create.mechanical_arm": "Mechanischer Arm", - "block.create.mechanical_bearing": "Mechanisches Lager", - "block.create.mechanical_crafter": "Mechanische Handwerkseinheit", - "block.create.mechanical_drill": "Mechanischer Bohrer", - "block.create.mechanical_harvester": "Mechanische Erntemaschine", - "block.create.mechanical_mixer": "Mechanischer Mixer", - "block.create.mechanical_piston": "Mechanischer Kolben", - "block.create.mechanical_piston_head": "Mechanisches Kolbenende", - "block.create.mechanical_plough": "Mechanischer Pflug", - "block.create.mechanical_press": "Mechanische Presse", - "block.create.mechanical_pump": "Mechanische Pumpe", - "block.create.mechanical_saw": "Mechanische Säge", - "block.create.metal_bracket": "Metallhalterung", - "block.create.metal_girder": "Metallträger", - "block.create.metal_girder_encased_shaft": "Metallträgerummantelte Welle", - "block.create.millstone": "Mahlstein", - "block.create.minecart_anchor": "Lorenanker", - "block.create.mysterious_cuckoo_clock": "Kuckucksuhr", - "block.create.nixie_tube": "Nixie-Röhre", - "block.create.nozzle": "Düse", - "block.create.oak_window": "Eichenfenster", - "block.create.oak_window_pane": "Eichenfensterscheibe", - "block.create.ochrum": "Ockrum", - "block.create.ochrum_pillar": "Ockrum-Säule", - "block.create.orange_sail": "Oranges Segel", - "block.create.orange_seat": "Oranger Sitz", - "block.create.orange_toolbox": "Oranger Werkzeugkasten", - "block.create.orange_valve_handle": "Oranger Ventilgriff", - "block.create.ornate_iron_window": "Kunstvolles Eisenfenster", - "block.create.ornate_iron_window_pane": "Kunstvolle Eisenfensterscheibe", - "block.create.oxidized_copper_shingle_slab": "Oxidierte Kupferschindelstufe", - "block.create.oxidized_copper_shingle_stairs": "Oxidierte Kupfertreppe", - "block.create.oxidized_copper_shingles": "Oxidierte Kupferschindel", - "block.create.oxidized_copper_tile_slab": "Oxidierte Kupferfliesenstufe", - "block.create.oxidized_copper_tile_stairs": "Oxidierte Kupferfliesentreppe", - "block.create.oxidized_copper_tiles": "Oxidierte Kupferfliesen", - "block.create.peculiar_bell": "Seltsame Glocke", - "block.create.pink_nixie_tube": "Rosa Nixie-Röhre", - "block.create.pink_sail": "Rosa Segel", - "block.create.pink_seat": "Rosa Sitz", - "block.create.pink_toolbox": "Rosa Werkzeugkasten", - "block.create.pink_valve_handle": "Rosa Ventilgriff", - "block.create.piston_extension_pole": "Kolben-Pleuelverlängerung", - "block.create.placard": "Aushang", - "block.create.polished_cut_andesite": "Polierter geschnittener Andesit", - "block.create.polished_cut_andesite_slab": "Polierte geschnittene Andesitstufe", - "block.create.polished_cut_andesite_stairs": "Polierte geschnittene Andesittreppe", - "block.create.polished_cut_andesite_wall": "Polierte geschnittene Andesitmauer", - "block.create.polished_cut_asurine": "Poliertes geschnittenes Asurin", - "block.create.polished_cut_asurine_slab": "Polierte geschnittene Asurinstufe", - "block.create.polished_cut_asurine_stairs": "Polierte geschnittene Asurintreppe", - "block.create.polished_cut_asurine_wall": "Polierte geschnittene Asurinmauer", - "block.create.polished_cut_calcite": "Polierter geschnittener Kalzit", - "block.create.polished_cut_calcite_slab": "Polierte geschnittene Kalzitstufe", - "block.create.polished_cut_calcite_stairs": "Polierte geschnittene Kalzittreppe", - "block.create.polished_cut_calcite_wall": "Polierte geschnittene Kalzitmauer", - "block.create.polished_cut_crimsite": "Poliertes geschnittenes Karmesit", - "block.create.polished_cut_crimsite_slab": "Polierte geschnittene Karmesitstufe", - "block.create.polished_cut_crimsite_stairs": "Polierte geschnittene Karmesittreppe", - "block.create.polished_cut_crimsite_wall": "Polierte geschnittene Karmesitmauer", - "block.create.polished_cut_deepslate": "Polierter geschnittener Tiefschiefer", - "block.create.polished_cut_deepslate_slab": "Polierte geschnittene Tiefschieferstufe", - "block.create.polished_cut_deepslate_stairs": "Polierte geschnittene Tiefschiefertreppe", - "block.create.polished_cut_deepslate_wall": "Polierte geschnittene Tiefschiefermauer", - "block.create.polished_cut_diorite": "Polierter geschnittener Diorit", - "block.create.polished_cut_diorite_slab": "Polierte geschnittene Dioritstufe", - "block.create.polished_cut_diorite_stairs": "Polierte geschnittene Diorittreppe", - "block.create.polished_cut_diorite_wall": "Polierte geschnittene Dioritmauer", - "block.create.polished_cut_dripstone": "Polierter geschnittener Tropfstein", - "block.create.polished_cut_dripstone_slab": "Polierte geschnittene Tropfsteinstufe", - "block.create.polished_cut_dripstone_stairs": "Polierte geschnittene Tropfsteintreppe", - "block.create.polished_cut_dripstone_wall": "Polierte geschnittene Tropfsteinmauer", - "block.create.polished_cut_granite": "Polierter geschnittener Granit", - "block.create.polished_cut_granite_slab": "Polierte geschnittene Granitstufe", - "block.create.polished_cut_granite_stairs": "Polierte geschnittene Granittreppe", - "block.create.polished_cut_granite_wall": "Polierte geschnittene Granitmauer", - "block.create.polished_cut_limestone": "Polierter geschnittener Kalkstein", - "block.create.polished_cut_limestone_slab": "Polierte geschnittene Kalksteinstufe", - "block.create.polished_cut_limestone_stairs": "Polierte geschnittene Kalksteintreppe", - "block.create.polished_cut_limestone_wall": "Polierte geschnittene Kalksteinmauer", - "block.create.polished_cut_ochrum": "Poliertes geschnittenes Ockrum", - "block.create.polished_cut_ochrum_slab": "Polierte geschnittene Ockrumstufe", - "block.create.polished_cut_ochrum_stairs": "Polierte geschnittene Ockrumtreppe", - "block.create.polished_cut_ochrum_wall": "Polierte geschnittene Ockrummauer", - "block.create.polished_cut_scorchia": "Poliertes geschnittenes Scorchia", - "block.create.polished_cut_scorchia_slab": "Polierte geschnittene Scorchiastufe", - "block.create.polished_cut_scorchia_stairs": "Polierte geschnittene Scorchiatreppe", - "block.create.polished_cut_scorchia_wall": "Polierte geschnittene Scorchiamauer", - "block.create.polished_cut_scoria": "Polierte geschnittene Schlacke", - "block.create.polished_cut_scoria_slab": "Polierte geschnittene Schlackenstufe", - "block.create.polished_cut_scoria_stairs": "Polierte geschnittene Schlackentreppe", - "block.create.polished_cut_scoria_wall": "Polierte geschnittene Schlackenmauer", - "block.create.polished_cut_tuff": "Polierter geschnittener Tuffstein", - "block.create.polished_cut_tuff_slab": "Polierte geschnittene Tuffsteinstufe", - "block.create.polished_cut_tuff_stairs": "Polierte geschnittene Tuffsteintreppe", - "block.create.polished_cut_tuff_wall": "Polierte geschnittene Tuffsteinmauer", - "block.create.polished_cut_veridium": "Poliertes geschnittenes Veridium", - "block.create.polished_cut_veridium_slab": "Polierte geschnittene Veridiumstufe", - "block.create.polished_cut_veridium_stairs": "Polierte geschnittene Veridiumtreppe", - "block.create.polished_cut_veridium_wall": "Polierte geschnittene Veridiummauer", - "block.create.portable_fluid_interface": "Portable Flüssigkeitsschnittstelle", - "block.create.portable_storage_interface": "Portable Lagerschnittstelle", - "block.create.powered_latch": "RS-Flipflop", - "block.create.powered_shaft": "Angetriebene Welle", - "block.create.powered_toggle_latch": "T-Flipflop", - "block.create.pulley_magnet": "Rollenmagnet", - "block.create.pulse_extender": "Pulsverlängerer", - "block.create.pulse_repeater": "Pulsierender Verstärker", - "block.create.purple_nixie_tube": "Violette Nixie-Röhre", - "block.create.purple_sail": "Violettes Segel", - "block.create.purple_seat": "Violetter Sitz", - "block.create.purple_toolbox": "Violetter Werkzeugkasten", - "block.create.purple_valve_handle": "Violetter Ventilgriff", - "block.create.radial_chassis": "Drehgerüst", - "block.create.railway_casing": "Zugrahmen", - "block.create.raw_zinc_block": "Rohzinkblock", - "block.create.red_nixie_tube": "Rote Nixie-Röhre", - "block.create.red_sail": "Rote Segel", - "block.create.red_seat": "Roter Sitz", - "block.create.red_toolbox": "Roter Werkzeugkasten", - "block.create.red_valve_handle": "Roter Ventilgriff", - "block.create.redstone_contact": "Redstone-Kontakt", - "block.create.redstone_link": "Redstone-Verbindung", - "block.create.refined_radiance_casing": "Glanzgehäuse", - "block.create.rope": "Seil", - "block.create.rope_pulley": "Seilrolle", - "block.create.rose_quartz_block": "Rosenquarzblock", - "block.create.rose_quartz_lamp": "Rosenquarzlampe", - "block.create.rose_quartz_tiles": "Rosenquarzfliesen", - "block.create.rotation_speed_controller": "Rotationsgeschwindigkeitsregler", - "block.create.sail_frame": "Segelrahmen", - "block.create.schematic_table": "Bauplantisch", - "block.create.schematicannon": "Bauplankanone", - "block.create.scorchia": "Scorchia", - "block.create.scorchia_pillar": "Scorchia-Säule", - "block.create.scoria": "Schlacke", - "block.create.scoria_pillar": "Schlackensäule", - "block.create.secondary_linear_chassis": "Sekundäres Schubgerüst", - "block.create.sequenced_gearshift": "Sequenzielle Gangschaltung", - "block.create.shadow_steel_casing": "Schattengehäuse", - "block.create.shaft": "Welle", - "block.create.small_andesite_brick_slab": "Kleine Andesitziegelstufe", - "block.create.small_andesite_brick_stairs": "Kleine Andesitziegeltreppe", - "block.create.small_andesite_brick_wall": "Kleine Andesitziegelmauer", - "block.create.small_andesite_bricks": "Kleine Andesitziegelsteine", - "block.create.small_asurine_brick_slab": "Kleine Asurinziegelstufe", - "block.create.small_asurine_brick_stairs": "Kleine Asurinziegeltreppe", - "block.create.small_asurine_brick_wall": "Kleine Asurinziegelmauer", - "block.create.small_asurine_bricks": "Kleine Asurinziegelsteine", - "block.create.small_bogey": "Kleines Drehgestell", - "block.create.small_calcite_brick_slab": "Kleine Kalzitziegelstufe", - "block.create.small_calcite_brick_stairs": "Kleine Kalzitziegeltreppe", - "block.create.small_calcite_brick_wall": "Kleine Kalzitziegelmauer", - "block.create.small_calcite_bricks": "Kleine Kalzitziegelsteine", - "block.create.small_crimsite_brick_slab": "Kleine Karmesitziegelstufe", - "block.create.small_crimsite_brick_stairs": "Kleine Karmesitziegeltreppe", - "block.create.small_crimsite_brick_wall": "Kleine Karmesitziegelmauer", - "block.create.small_crimsite_bricks": "Kleine Karmesitziegelsteine", - "block.create.small_deepslate_brick_slab": "Kleine Tiefenschieferziegelstufe", - "block.create.small_deepslate_brick_stairs": "Kleine Tiefenschieferziegeltreppe", - "block.create.small_deepslate_brick_wall": "Kleine Tiefenschieferziegelmauer", - "block.create.small_deepslate_bricks": "Kleine Tiefenschieferziegelsteine", - "block.create.small_diorite_brick_slab": "Kleine Dioritziegelstufe", - "block.create.small_diorite_brick_stairs": "Kleine Dioritziegeltreppe", - "block.create.small_diorite_brick_wall": "Kleine Dioritziegelmauer", - "block.create.small_diorite_bricks": "Kleine Dioritziegelsteine", - "block.create.small_dripstone_brick_slab": "Kleine Tropfsteinziegelstufe", - "block.create.small_dripstone_brick_stairs": "Kleine Tropfsteinziegeltreppe", - "block.create.small_dripstone_brick_wall": "Kleine Tropfsteinziegelmauer", - "block.create.small_dripstone_bricks": "Kleine Tropfsteinziegelsteine", - "block.create.small_granite_brick_slab": "Kleine Granitziegelstufe", - "block.create.small_granite_brick_stairs": "Kleine Granitziegeltreppe", - "block.create.small_granite_brick_wall": "Kleine Granitziegelmauer", - "block.create.small_granite_bricks": "Kleine Granitziegelsteine", - "block.create.small_limestone_brick_slab": "Kleine Kalksteinziegelstufe", - "block.create.small_limestone_brick_stairs": "Kleine Kalksteinziegeltreppe", - "block.create.small_limestone_brick_wall": "Kleine Kalksteinziegelmauer", - "block.create.small_limestone_bricks": "Kleine Kalksteinziegelsteine", - "block.create.small_ochrum_brick_slab": "Kleine Ockrumziegelstufe", - "block.create.small_ochrum_brick_stairs": "Kleine Ockrumziegeltreppe", - "block.create.small_ochrum_brick_wall": "Kleine Ockrumziegelmauer", - "block.create.small_ochrum_bricks": "Kleine Ockrumziegelsteine", - "block.create.small_rose_quartz_tiles": "Kleine Rosenquarzfliesen", - "block.create.small_scorchia_brick_slab": "Kleine Scorchiaziegelstufe", - "block.create.small_scorchia_brick_stairs": "Kleine Scorchiaziegeltreppe", - "block.create.small_scorchia_brick_wall": "Kleine Scorchiaziegelmauer", - "block.create.small_scorchia_bricks": "Kleine Scorchiaziegelsteine", - "block.create.small_scoria_brick_slab": "Kleine Scoriaziegelstufe", - "block.create.small_scoria_brick_stairs": "Kleine Scoriaziegeltreppe", - "block.create.small_scoria_brick_wall": "Kleine Scoriaziegelmauer", - "block.create.small_scoria_bricks": "Kleine Scoriaziegelsteine", - "block.create.small_tuff_brick_slab": "Kleine Tuffsteinziegelstufe", - "block.create.small_tuff_brick_stairs": "Kleine Tuffsteinziegeltreppe", - "block.create.small_tuff_brick_wall": "Kleine Tuffsteinziegelmauer", - "block.create.small_tuff_bricks": "Kleine Tuffsteinziegelsteine", - "block.create.small_veridium_brick_slab": "Kleine Veridiumziegelstufe", - "block.create.small_veridium_brick_stairs": "Kleine Veridiumziegeltreppe", - "block.create.small_veridium_brick_wall": "Kleine Veridiumziegelmauer", - "block.create.small_veridium_bricks": "Kleine Veridiumziegelsteine", - "block.create.smart_chute": "Schlaue Rinne", - "block.create.smart_fluid_pipe": "Schlaues Flüssigkeitsrohr", - "block.create.speedometer": "Tachometer", - "block.create.spout": "Ausguss", - "block.create.spruce_window": "Fichtenfenster", - "block.create.spruce_window_pane": "Fichtenfensterscheibe", - "block.create.steam_engine": "Dampfmaschine", - "block.create.steam_whistle": "Dampfpfeife", - "block.create.steam_whistle_extension": "Dampfpfeifenerweiterung", - "block.create.sticker": "Ankleber", - "block.create.sticky_mechanical_piston": "Klebriger Mechanischer Kolben", - "block.create.stockpile_switch": "Vorratssensor", - "block.create.stressometer": "Stressometer", - "block.create.tiled_glass": "Glasfliesen", - "block.create.tiled_glass_pane": "Glasfliesenscheibe", - "block.create.track": "Gleis", - "block.create.track_observer": "Zugbeobachter", - "block.create.track_signal": "Zugsignal", - "block.create.track_station": "Bahnhof", - "block.create.train_door": "Zugtür", - "block.create.train_trapdoor": "Zugfalltür", - "block.create.tuff_pillar": "Tuffstein-Säule", - "block.create.turntable": "Drehtisch", - "block.create.veridium": "Veridium", - "block.create.veridium_pillar": "Veridium-Säule", - "block.create.vertical_framed_glass": "Vertikal Gerahmtes Glas", - "block.create.vertical_framed_glass_pane": "Vertikal Gerahmte Glasscheibe", - "block.create.warped_window": "Wirrfenster", - "block.create.warped_window_pane": "Wirrfensterscheibe", - "block.create.water_wheel": "Wasserrad", - "block.create.waxed_copper_shingle_slab": "Gewachste Kupferschindelstufe", - "block.create.waxed_copper_shingle_stairs": "Gewachste Kupferschindeltreppe", - "block.create.waxed_copper_shingles": "Gewachste Kupferschindel", - "block.create.waxed_copper_tile_slab": "Gewachste Kupferfliesenstufe", - "block.create.waxed_copper_tile_stairs": "Gewachste Kupferfliesentreppe", - "block.create.waxed_copper_tiles": "Gewachste Kupferfliesen", - "block.create.waxed_exposed_copper_shingle_slab": "Gewachste angelaufene Kupferschindelstufe", - "block.create.waxed_exposed_copper_shingle_stairs": "Gewachste angelaufene Kupferschindeltreppe", - "block.create.waxed_exposed_copper_shingles": "Gewachste angelaufene Kupferschindel", - "block.create.waxed_exposed_copper_tile_slab": "Gewachste angelaufene Kupferfliesenstufe", - "block.create.waxed_exposed_copper_tile_stairs": "Gewachste angelaufene Kupferfliesentreppe", - "block.create.waxed_exposed_copper_tiles": "Gewachste angelaufene Kupferfliesen", - "block.create.waxed_oxidized_copper_shingle_slab": "Gewachste oxidierte Kupferschindelstufe", - "block.create.waxed_oxidized_copper_shingle_stairs": "Gewachste oxidierte Kupferschindeltreppe", - "block.create.waxed_oxidized_copper_shingles": "Gewachste oxidierte Kupferschindel", - "block.create.waxed_oxidized_copper_tile_slab": "Gewachste oxidierte Kupferfliesenstufe", - "block.create.waxed_oxidized_copper_tile_stairs": "Gewachste oxidierte Kupferfliesentreppe", - "block.create.waxed_oxidized_copper_tiles": "Gewachste oxidierte Kupferfliesen", - "block.create.waxed_weathered_copper_shingle_slab": "Gewachste verwittere Kupferschindelstufe", - "block.create.waxed_weathered_copper_shingle_stairs": "Gewachste verwitterte Kupferschindeltreppe", - "block.create.waxed_weathered_copper_shingles": "Gewachste verwitterte Kupferschindel", - "block.create.waxed_weathered_copper_tile_slab": "Gewachste verwitterte Kupferfliesenstufe", - "block.create.waxed_weathered_copper_tile_stairs": "Gewachste verwitterte Kupferfliesentreppe", - "block.create.waxed_weathered_copper_tiles": "Gewachste verwitterte Kupferfliesen", - "block.create.weathered_copper_shingle_slab": "Verwitterte Kupferschindelstufe", - "block.create.weathered_copper_shingle_stairs": "Verwitterte Kupferschindeltreppe", - "block.create.weathered_copper_shingles": "Verwitterte Kupferschindel", - "block.create.weathered_copper_tile_slab": "Verwitterte Kupferfliesenstufe", - "block.create.weathered_copper_tile_stairs": "Verwitterte Kupferfliesentreppe", - "block.create.weathered_copper_tiles": "Verwitterte Kupferfliesen", - "block.create.weighted_ejector": "Gewichteter Werfer", - "block.create.white_nixie_tube": "Weiße Nixie-Röhre", - "block.create.white_sail": "Weiße Segel", - "block.create.white_seat": "Weißer Sitz", - "block.create.white_toolbox": "Weißer Werkzeugkasten", - "block.create.white_valve_handle": "Weißer Ventilgriff", - "block.create.windmill_bearing": "Windmühlenlager", - "block.create.wooden_bracket": "Holzhalterung", - "block.create.yellow_nixie_tube": "Gelbe Nixie-Röhre", - "block.create.yellow_sail": "Gelbes Segel", - "block.create.yellow_seat": "Gelber Sitz", - "block.create.yellow_toolbox": "Gelber Werkzeugkasten", - "block.create.yellow_valve_handle": "Gelber Ventilgriff", - "block.create.zinc_block": "Zinkblock", - "block.create.zinc_ore": "Zinkerz", - - "enchantment.create.capacity": "Kapazität", - "enchantment.create.potato_recovery": "Kartoffel-Wiederherstellung", - - "entity.create.carriage_contraption": "Wagenvorrichtung", - "entity.create.contraption": "Vorrichtung", - "entity.create.crafting_blueprint": "Herstellungsblaupause", - "entity.create.gantry_contraption": "Portalkran Vorrichtung", - "entity.create.potato_projectile": "Kartoffel-Projektil", - "entity.create.seat": "Sitz", - "entity.create.stationary_contraption": "Stationäre Vorrichtung", - "entity.create.super_glue": "Sekundenkleber", - - "fluid.create.potion": "Trank", - "fluid.create.tea": "Bauherrentee", - - "item.create.andesite_alloy": "Andesitlegierung", - "item.create.attribute_filter": "Attribut Filter", - "item.create.bar_of_chocolate": "Schokoladentafel", - "item.create.belt_connector": "Mechanischer Riemen", - "item.create.blaze_cake": "Lohenkuchen", - "item.create.blaze_cake_base": "Lohenkuchenbasis", - "item.create.brass_hand": "Messing Hand", - "item.create.brass_ingot": "Messingbarren", - "item.create.brass_nugget": "Messingklumpen", - "item.create.brass_sheet": "Messingblech", - "item.create.builders_tea": "Baumeister-Tee", - "item.create.chest_minecart_contraption": "Güterloren Vorrichtung", - "item.create.chocolate_bucket": "Schokoladeneimer", - "item.create.chocolate_glazed_berries": "Schokoladenglasierte Beeren", - "item.create.chromatic_compound": "Chromatische Verbindung", - "item.create.cinder_flour": "Aschenmehl", - "item.create.copper_backtank": "Kupferner Rückentank", - "item.create.copper_backtank_placeable": "Platzierbarer Kupferner Rückentank", - "item.create.copper_nugget": "Kupferklumpen", - "item.create.copper_sheet": "Kupferblech", - "item.create.crafter_slot_cover": "Handwerkseinheit Slot Abdeckung", - "item.create.crafting_blueprint": "Herstellungsblaupause", - "item.create.creative_blaze_cake": "Kreativer Lohenkuchen", - "item.create.crushed_aluminum_ore": "Zerkleinertes Aluminiumerz", - "item.create.crushed_copper_ore": "Zerkleinertes Kupfererz", - "item.create.crushed_gold_ore": "Zerkleinertes Golderz", - "item.create.crushed_iron_ore": "Zerkleinertes Eisenerz", - "item.create.crushed_lead_ore": "Zerkleinertes Bleierz", - "item.create.crushed_nickel_ore": "Zerkleinertes Nickelerz", - "item.create.crushed_osmium_ore": "Zerkleinertes Osmiumerz", - "item.create.crushed_platinum_ore": "Zerkleinertes Platinerz", - "item.create.crushed_quicksilver_ore": "Zerkleinertes Quecksilbererz", - "item.create.crushed_silver_ore": "Zerkleinertes Silbererz", - "item.create.crushed_tin_ore": "Zerkleinertes Zinnerz", - "item.create.crushed_uranium_ore": "Zerkleinertes Uranerz", - "item.create.crushed_zinc_ore": "Zerkleinertes Zinkerz", - "item.create.diving_boots": "Tauchstiefel", - "item.create.diving_helmet": "Tauchhelm", - "item.create.dough": "Teig", - "item.create.electron_tube": "Elektronenröhre", - "item.create.empty_blaze_burner": "Leerer Lohenbrenner", - "item.create.empty_schematic": "Leerer Bauplan", - "item.create.experience_nugget": "Erfahrungsklumpen", - "item.create.extendo_grip": "Extendo Griff", - "item.create.filter": "Filter", - "item.create.furnace_minecart_contraption": "Antriebsloren Vorrichtung", - "item.create.goggles": "Ingenieursbrille", - "item.create.golden_sheet": "Goldblech", - "item.create.handheld_worldshaper": "Geländeformer", - "item.create.honey_bucket": "Honigeimer", - "item.create.honeyed_apple": "Honigapfel", - "item.create.incomplete_precision_mechanism": "Unfertiges Präzisionsgetriebe", - "item.create.incomplete_track": "Unfertiges Gleis", - "item.create.iron_sheet": "Eisenblech", - "item.create.linked_controller": "Fernsteuerung", - "item.create.minecart_contraption": "Loren Vorrichtung", - "item.create.minecart_coupling": "Lorenkupplung", - "item.create.polished_rose_quartz": "Polierter Rosenquarz", - "item.create.potato_cannon": "Kartoffelkanone", - "item.create.powdered_obsidian": "Pulverisierter Obsidian", - "item.create.precision_mechanism": "Präzisionsgetriebe", - "item.create.propeller": "Propeller", - "item.create.raw_zinc": "Rohzink", - "item.create.red_sand_paper": "Rotes Schmirgelpapier", - "item.create.refined_radiance": "Raffinierter Glanz", - "item.create.rose_quartz": "Rosenquarz", - "item.create.sand_paper": "Schmirgelpapier", - "item.create.schedule": "Zugfahrplan", - "item.create.schematic": "Bauplan", - "item.create.schematic_and_quill": "Bauplan und Feder", - "item.create.shadow_steel": "Schattenstahl", - "item.create.sturdy_sheet": "Robustes Blech", - "item.create.super_glue": "Superkleber", - "item.create.sweet_roll": "Rosinenschnecke", - "item.create.tree_fertilizer": "Baumdünger", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Vertikales Getriebe", - "item.create.wand_of_symmetry": "Symmetriestab", - "item.create.wheat_flour": "Weizenmehl", - "item.create.whisk": "Rührstab", - "item.create.wrench": "Schraubenschlüssel", - "item.create.zinc_ingot": "Zinkbarren", - "item.create.zinc_nugget": "Zinkklumpen", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Willkommen zu Create", - "advancement.create.root.desc": "Es ist Zeit mit dem Bauen von tollen Apparaten zu starten!", - "advancement.create.andesite_alloy": "Alliterationen in Massen", - "advancement.create.andesite_alloy.desc": "Create's Materialien haben verrückte Namen, Eisenlegierung ist im Deutschen leider keine.", - "advancement.create.andesite_casing": "Das Andesit Alter", - "advancement.create.andesite_casing.desc": "Verwende Andesite Legierungen und Holz, um einen einfachen Rahmen zu erstellen.", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "Stelle einige Stücke Blech in einer Mechanischen Presse her.", - "advancement.create.encased_fan": "Windverursacher", - "advancement.create.encased_fan.desc": "Platziere und aktiviere einen Ummantelten Lüfter.", - "advancement.create.fan_processing": "Verarbeitung in Windeseile", - "advancement.create.fan_processing.desc": "Benutze einen Ummantelten Lüfter zur Verarbeitung von Materialien.", - "advancement.create.saw_processing": "Finger weg!", - "advancement.create.saw_processing.desc": "Benutze eine aufrecht stehende Mechanische Säge zur Verarbeitung von Materialien.", - "advancement.create.compacting": "Kompakt und handlich", - "advancement.create.compacting.desc": "Mache mit einer Presse und einem Behälter aus mehr Items weniger Items.", - "advancement.create.belt": "Befördere es alles", - "advancement.create.belt.desc": "Verbinde zwei Wellen mit einem Mechanischem Riemen.", - "advancement.create.funnel": "Wie am Flughafen", - "advancement.create.funnel.desc": "Benutze einen Messing- oder Andesittrichter, um Items aus einem Behälter zu ziehen oder Items in ihn zu legen.", - "advancement.create.chute": "Abstürzen", - "advancement.create.chute.desc": "Platziere eine Rinne, das vertikale Gegenstück des Riemens.", - "advancement.create.mechanical_mixer": "Kräftig durchrühren", - "advancement.create.mechanical_mixer.desc": "Kombiniere Items mithilfe eines Mechanischen Mixers.", - "advancement.create.burner": "Mein neues Haustier lässt mich ganz warm ums Herz werden", - "advancement.create.burner.desc": "Beschaffe einen Lohenbrenner.", - "advancement.create.water_wheel": "Angespannte Hydraulik", - "advancement.create.water_wheel.desc": "Plaziere ein Wasserrad und versuche es zum drehen zu bringen!", - "advancement.create.windmill": "Eine leichte Brise", - "advancement.create.windmill.desc": "Baue eine Windmühle.", - "advancement.create.shifting_gears": "Wechsel deine Gänge", - "advancement.create.shifting_gears.desc": "Verbinde ein großes Zahnrad mit einem kleinem, um die Geschwindigkeit deiner Apparate zu verändern.", - "advancement.create.millstone": "Taschenmahlstein", - "advancement.create.millstone.desc": "Plaziere und aktiviere einen Mahlstein.", - "advancement.create.super_glue": "Bastelstunde", - "advancement.create.super_glue.desc": "Benutze Sekundenkleber, um Blöcke zu einer Gruppe zusammenzukleben.", - "advancement.create.contraption_actors": "Bewegte Maschinen", - "advancement.create.contraption_actors.desc": "Erschaffe eine Vorrichtung, die Bohrer, Sägen oder Pflüge beherbergt.", - "advancement.create.portable_storage_interface": "Ausladen, befüllen, weiterfahren", - "advancement.create.portable_storage_interface.desc": "Benutze eine Portable Lagerschnittstelle. um Items aus einer Vorrichtung zu ziehen oder in eine zu legen.", - "advancement.create.wrench_goggles": "Standardausrüstung eines jeden Mechanikers", - "advancement.create.wrench_goggles.desc": "Rüste dich mit einer Ingenieursbrille und einem Schraubenschlüssel aus.", - "advancement.create.stressometer": "Aber wie belastet genau?", - "advancement.create.stressometer.desc": "Platziere und schalte ein Stressometer ein. Schau es dir durch deine Ingenieursbrille an und lese den genauen Wert ab.", - "advancement.create.cuckoo_clock": "Is' schon Feierabend?", - "advancement.create.cuckoo_clock.desc": "Beobachte deine Kuckucksuhr bei der Ankündigung der Schlafenszeit.", - "advancement.create.windmill_maxed": "Eine starke Briese", - "advancement.create.windmill_maxed.desc": "Baue ein Windrad mit der höchtmöglichen Stärke.", - "advancement.create.ejector_maxed": "Huiii!", - "advancement.create.ejector_maxed.desc": "Lasse dich von einem Gewichteten Werfer mehr als 30 Blöcke weit katapultieren.", - "advancement.create.pulley_maxed": "Abseilen in die Tiefe", - "advancement.create.pulley_maxed.desc": "Lasse eine Seilrolle sich mehr als 200 Blöcke tief ausfahren.", - "advancement.create.cart_pickup": "Das Training zahlt sich aus", - "advancement.create.cart_pickup.desc": "Hebe eine Lorenvorrichtung auf, die mindestens 200 Blöcke beherbergt.", - "advancement.create.anvil_plough": "Hier gilt Helmpflicht!", - "advancement.create.anvil_plough.desc": "Befördere einen Amboss mithilfe eines Mechanischen Pflugs in die Luft.", - "advancement.create.lava_wheel_00000": "Magmarad", - "advancement.create.lava_wheel_00000.desc": "Moment mal, eigentlich sollte das nicht möglich sein...§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.hand_crank_000": "Bitte lege gelegentlich eine Pause ein", - "advancement.create.hand_crank_000.desc": "Drehe an einer Handkurbel bis zu völligen Erschöpfung.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.belt_funnel_kiss": "Die Hühnchen und die Klappen", - "advancement.create.belt_funnel_kiss.desc": "Lasse zwei an Mechanischen Riemen befestigte Riementrichter sich küssen.", - "advancement.create.stressometer_maxed": "Perfekt ausgelastet", - "advancement.create.stressometer_maxed.desc": "Lasse ein Stressometer exakt 100% anzeigen.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.copper": "Härtere Steine", - "advancement.create.copper.desc": "Häufe ein wenig Kupfer an, um es für die Verarbeitung von Flüssigkeiten zu verwenden.", - "advancement.create.copper_casing": "Das Kupferzeitalter", - "advancement.create.copper_casing.desc": "Verwende Kupferbarren und Holz, um einen Kupferrahmen herzustellen.", - "advancement.create.spout": "Platsch!", - "advancement.create.spout.desc": "Schaue einem Flüssigkeitsgegenstand zu, wie er von einem Ausguss gefüllt wird.", - "advancement.create.drain": "Kipp' alles rein", - "advancement.create.drain.desc": "Schaue einem Flüssigkeitsgegenstand zu, wie er von einem Abfluss geleert wird.", - "advancement.create.steam_engine": "Zisch!", - "advancement.create.steam_engine.desc": "Generiere Drehmoment mit einer Dampfmaschine.", - "advancement.create.steam_whistle": "Die Stimme eines Engels", - "advancement.create.steam_whistle.desc": "Aktiviere eine Dampfpfeife", - "advancement.create.backtank": "Druckluft To Go", - "advancement.create.backtank.desc": "Stelle eine Kupferne Druckluftflasche her und fülle sie mit Druckluft.", - "advancement.create.diving_suit": "Bereit für die Tiefe", - "advancement.create.diving_suit.desc": "Rüste dich mit einem Tauchhelm und einer Druckluftflasche aus und springe ins Wasser.", - "advancement.create.mechanical_pump_0": "Unter Druck", - "advancement.create.mechanical_pump_0.desc": "Platziere eine Mechanische Pumpe und treibe sie an.", - "advancement.create.glass_pipe": "Flussspion", - "advancement.create.glass_pipe.desc": "Beobachte durch ein Rohr mit Fenster, wie Flüssigkeiten durch ein Rohr fließen. Gerade Rohre bekommen ein Fenster, wenn du mit einem Schraubenschlüssel auf diese klickst.", - "advancement.create.water_supply": "Schlürf!", - "advancement.create.water_supply.desc": "Lasse ein Rohr eine Wasserquelle aufnehmen.", - "advancement.create.hose_pulley": "Industrielles Verschütten", - "advancement.create.hose_pulley.desc": "Lasse eine Umlenkrolle herab und schau ihr zu, wie sie Wasser aufsaugt oder rauslässt.", - "advancement.create.chocolate_bucket": "Ein Eimer voller Glück", - "advancement.create.chocolate_bucket.desc": "Beschaffe einen Schokoladeneimer.", - "advancement.create.honey_drain": "Industrielle Imkerei", - "advancement.create.honey_drain.desc": "Benutze Rohre, um Honig aus einem Bienennest oder einem Bienenstock zu ziehen.", - "advancement.create.hose_pulley_lava": "Praktisch unendlich", - "advancement.create.hose_pulley_lava.desc": "Pumpe Lava aus einem Vorkommen, welches groß genug ist, um als unerschöpflich zu gelten.", - "advancement.create.steam_engine_maxed": "Meilenstein der Industrialisierung", - "advancement.create.steam_engine_maxed.desc": "Betreiber einen Dampfkessel mit der höchtmöglichen Kapazität.", - "advancement.create.foods": "Eine ausgewogene Ernährung", - "advancement.create.foods.desc": "Produziere Schokoladenglasierte Beeren, einen Honigapfel und eine Rosinenschnecke mit demselben Ausguss.", - "advancement.create.diving_suit_lava": "Baden mit den Schreitern", - "advancement.create.diving_suit_lava.desc": "Versuche, mit deiner kupfernen Tauchausrüstung in Lava zu schwimmen.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.chained_drain": "Eine Abflussstraße", - "advancement.create.chained_drain.desc": "Beobachte ein Item, wie es sich über eine Reihe von Abflüssen bewegt.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.cross_streams": "Auf keinen Fall vermischen!!", - "advancement.create.cross_streams.desc": "Beobachte, wie zwei Flüssigkeiten sich in einem Rohr treffen.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.pipe_organ": "Ein majestätischer Klang", - "advancement.create.pipe_organ.desc": "Schließe 12 Dampfpfeifen mit unterschiedlichen Tonhöhen an einen Tank an.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.brass": "Echte Legierungen", - "advancement.create.brass.desc": "Verwende zerkleinertes Kupfererz und zerkleinertes Zinkerz um Messing herzustellen.", - "advancement.create.brass_casing": "Das Messingzeitalter", - "advancement.create.brass_casing.desc": "Verwende das neu erhaltene Messing und etwas Holz, um einen mehr fortgeschrittenen Rahmen herzustellen.", - "advancement.create.rose_quartz": "Pinke Diamanten", - "advancement.create.rose_quartz.desc": "Poliere etwas Rosenquarz.", - "advancement.create.deployer": "Stupse, platziere und attackiere!", - "advancement.create.deployer.desc": "Platziere und betreibe ein Einsatzgerät, die perfekte Reflektion deiner selbst.", - "advancement.create.precision_mechanism": "Komplexe Kuriositäten", - "advancement.create.precision_mechanism.desc": "Montiere ein Präzisionsgetriebe.", - "advancement.create.speed_controller": "Ingenieure hassen ihn!", - "advancement.create.speed_controller.desc": "Platziere einen Rotationsgeschwindigkeitsregler, das ultimative Gerät, um die Drehgeschwindigkeit zu ändern.", - "advancement.create.mechanical_arm": "Beschäftigte Hände!", - "advancement.create.mechanical_arm.desc": "Stelle einen Mechanischen Arm her, wähle Ein- und Ausgang, platziere ihn und gib ihm Energie; beobachte dann, wie er für dich all die Arbeit erledigt.", - "advancement.create.mechanical_crafter": "Automatisiertes Handwerk", - "advancement.create.mechanical_crafter.desc": "Platziere einige Mechanische Handwerkseinheiten und treibe sie an.", - "advancement.create.crushing_wheel": "Ein gigantisches Paar", - "advancement.create.crushing_wheel.desc": "Stelle Mahlwerkräder her, um mehr Materialien effizienter zu zermahlen.", - "advancement.create.haunted_bell": "Schattensinn", - "advancement.create.haunted_bell.desc": "Läute eine Spukglocke.", - "advancement.create.clockwork_bearing": "Uhrapparat", - "advancement.create.clockwork_bearing.desc": "Montiere eine Struktur auf einem Uhrwerklager.", - "advancement.create.display_link": "Alles auf einen Blick", - "advancement.create.display_link.desc": "Benutze einen Anzeige-Link, um Informationen zu visualisieren.", - "advancement.create.potato_cannon": "Fwump!", - "advancement.create.potato_cannon.desc": "Besiege einen Gegner mit deiner Kartoffelkanone.", - "advancement.create.extendo_grip": "Boioioing!", - "advancement.create.extendo_grip.desc": "Beschaffe einen Extendo-Griff.", - "advancement.create.linked_controller": "Ferngesteuert", - "advancement.create.linked_controller.desc": "Aktiviere eine Redstone-Verbindung mit ein", - "advancement.create.arm_blaze_burner": "Verbrennertron", - "advancement.create.arm_blaze_burner.desc": "Weise einen mechanischen Arm an, einen Lohenbrenner zu befeuern.", - "advancement.create.crusher_maxed_0000": "Lasst uns es zermahlen", - "advancement.create.crusher_maxed_0000.desc": "Betreiber ein Mahlwerkradpaar mit voller Geschwindigkeit.", - "advancement.create.arm_many_targets": "Organisiertron", - "advancement.create.arm_many_targets.desc": "Programmiere einen mechanischen Arm so, dass er zehn oder mehr Ausgänge hat.", - "advancement.create.potato_cannon_collide": "Vegetarisches Feuerwerk", - "advancement.create.potato_cannon_collide.desc": "Lasse zwei Kartoffelkanonenprojektile unterschiedlicher Art miteinander kolidieren.", - "advancement.create.self_deploying": "Wenn da doch nur nicht die Lava wäre...", - "advancement.create.self_deploying.desc": "Erschaffe eine Lorenvorrichtung, die ihre eigenen Schienen vor sich platziert.", - "advancement.create.fist_bump": "Verstampf es, Bro!", - "advancement.create.fist_bump.desc": "Lass zwei Einsatzgeräte aufeinander treffen.", - "advancement.create.crafter_lazy_000": "Ich habe Zeit", - "advancement.create.crafter_lazy_000.desc": "Fahre die Geschwindigkeit deiner Mechanischen Handwerkseinheit drastisch herunter, um beim Ausbau deiner Netzwerkinfrastruktur zu prokrastinieren.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.extendo_grip_dual": "Hand in Hand", - "advancement.create.extendo_grip_dual.desc": "Lasse einen Extendo-Griff einen weiteren Extendo-Griff tragen, um übermenschliche Reichweiten zu erlangen.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.musical_arm": "Spiel mir meine Erkennungsmelodie!", - "advancement.create.musical_arm.desc": "Beobachte einen mechanischen Arm dabei, wie er einen Plattenspieler bedient.", - "advancement.create.sturdy_sheet": "Noch härtere Steine", - "advancement.create.sturdy_sheet.desc": "Stelle ein Robustes Blech her, indem du zerkleinertes Obsidian veredelst.", - "advancement.create.train_casing_00": "Das logistische Zeitalter", - "advancement.create.train_casing_00.desc": "Verwende ein Robustes Blech, um einen Zugrahmen zu erstellen.", - "advancement.create.train": "Alles einsteigen!", - "advancement.create.train.desc": "Baue deinen ersten Zug.", - "advancement.create.conductor": "Konduktorinstruktor", - "advancement.create.conductor.desc": "Überreiche einem Zugführer einen Fahrplan.", - "advancement.create.track_signal": "Sicherheit im Schienenverkehr", - "advancement.create.track_signal.desc": "Platziere ein Zugsignal.", - "advancement.create.display_board_0": "Dynamischer Fahrplan", - "advancement.create.display_board_0.desc": "Kündige die Ankunft eines Zuges auf einer Anzeigetafel mithilfe eines Anzeige-Links an.", - "advancement.create.track_0": "Neue Maßstäbe", - "advancement.create.track_0.desc": "Beschaffe einige Gleise.", - "advancement.create.train_whistle": "Tschu-tschu!", - "advancement.create.train_whistle.desc": "Bringe eine Dampfpfeife an deinem Zug an und lasse sie während der Fahrt ertönen.", - "advancement.create.train_portal": "Interdimensional-Express", - "advancement.create.train_portal.desc": "Fahre mit einem Zug durch ein Netherportal.", - "advancement.create.track_crafting_factory": "Gleisfabrik", - "advancement.create.track_crafting_factory.desc": "Produziere mehr als 1000 Gleise mit derselben Mechanischen Presse.", - "advancement.create.long_bend": "Die längste Kurve", - "advancement.create.long_bend.desc": "Errichte einen kurvigen Gleisabschnitt, welcher sich über mehr als 30 Blöcke erstreckt.", - "advancement.create.long_train": "Dieser Zug ist laaaang", - "advancement.create.long_train.desc": "Baue einen Zug mit mindestens 6 Waggons.", - "advancement.create.long_travel": "Heute machen wir einen Ausflug", - "advancement.create.long_travel.desc": "Stehe von einem Sitz mindestens 5000 Blöcke von deinem Startort entfernt auf.", - "advancement.create.train_roadkill": "Haben wir gerade etwas überfahren?", - "advancement.create.train_roadkill.desc": "Überfahre einen Gegner mit deinem Zug.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.red_signal": "Ich kenne mich aus!", - "advancement.create.red_signal.desc": "Überfahre mit deinem Zug ein rotes Signal.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.train_crash": "Eine holprige Fahrt", - "advancement.create.train_crash.desc": "Erlebe als Fahrgast ein Zugunglück.§7\n(Ausgeblendeter Fortschritt)", - "advancement.create.train_crash_backwards": "Im toten Winkel", - "advancement.create.train_crash_backwards.desc": "Kollidiere mit einem anderen Zug, während du rückwärts fährst.§7\n(Ausgeblendeter Fortschritt)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create Paletten", - - "death.attack.create.crush": "%1$s stolperte in ein Mahlwerk", - "death.attack.create.crush.player": "%1$s wurde von %2$s in ein Mahlwerk gestoßen", - "death.attack.create.fan_fire": "%1$s hat heiße Luft eingeatmet", - "death.attack.create.fan_fire.player": "%1$s wurde von %2$s in einen Räucherofen gestoßen", - "death.attack.create.fan_lava": "%1$s wurde von Lava verweht", - "death.attack.create.fan_lava.player": "%1$s wurde von %2$s in einen Schmelzer geworfen", - "death.attack.create.mechanical_drill": "%1$s wurde von einem Bohrer durchlöchert", - "death.attack.create.mechanical_drill.player": "%1$s wurde von %2$s vor einen Bohrer gestoßen", - "death.attack.create.mechanical_saw": "%1$s wurde zersägt", - "death.attack.create.mechanical_saw.player": "%1$s wurde von %2$s in eine Säge gestoßen", - "death.attack.create.potato_cannon": "%1$s wurde von %2$s's Kartoffelkanone erschossen", - "death.attack.create.potato_cannon.item": "%1$s wurde von %2$s's %3$s erschossen", - "death.attack.create.cuckoo_clock_explosion": "%1$s wurde durch eine falsche Kuckucksuhr gesprengt", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s wurde von einer manipulierten Kuckucksuhr in die Luft gejagt", - "death.attack.create.run_over": "%1$s wurde von %2$s überfahren", - - "create.block.deployer.damage_source_name": "einem Finger", - "create.block.cart_assembler.invalid": "Platziere deinen Lorenmonteur auf einer Schiene.", - - "create.menu.return": "Zurück zum vorherigen Menü", - "create.menu.configure": "Konfigurieren...", - "create.menu.ponder_index": "Ponder-Verzeichnis", - "create.menu.only_ingame": "Im Pause-Menü verfügbar", - "create.menu.report_bugs": "Fehler melden", - "create.menu.support": "Unterstütze uns", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Mahlen (Mahlwerk)", - "create.recipe.milling": "Mahlen (Mahlstein)", - "create.recipe.fan_washing": "Sammelwaschen", - "create.recipe.fan_washing.fan": "Propeller hinter fließendem Wasser", - "create.recipe.fan_smoking": "Sammelräuchern", - "create.recipe.fan_smoking.fan": "Propeller hinter Feuer", - "create.recipe.fan_haunting": "Sammelspuken", - "create.recipe.fan_haunting.fan": "Propeller hinter Seelenfeuer", - "create.recipe.fan_blasting": "Sammelschmelzen", - "create.recipe.fan_blasting.fan": "Propeller hinter Lava", - "create.recipe.pressing": "Mechanische Presse", - "create.recipe.mixing": "Mixen", - "create.recipe.deploying": "Einsetzen", - "create.recipe.automatic_shapeless": "Automatisiertes Formloses Bauen", - "create.recipe.automatic_brewing": "Automatisiertes Brauen", - "create.recipe.packing": "Komprimieren", - "create.recipe.automatic_packing": "Automatisiertes Packen", - "create.recipe.sawing": "Sägen", - "create.recipe.mechanical_crafting": "Mechanisches Bauen", - "create.recipe.automatic_shaped": "Automatisiertes Geformtes Bauen", - "create.recipe.block_cutting": "Schneiden von Blöcken", - "create.recipe.wood_cutting": "Schneiden von Holz", - "create.recipe.sandpaper_polishing": "Schleifen", - "create.recipe.mystery_conversion": "Mysteriöse Konvertierung", - "create.recipe.spout_filling": "Befüllung per Ausguss", - "create.recipe.draining": "Gegenstandsablassung", - "create.recipe.item_application": "Manuelle Item-Anwendung", - "create.recipe.item_application.any_axe": "Beliebige Axt", - "create.recipe.sequenced_assembly": "Sequentielles Bauen", - "create.recipe.assembly.next": "Danach: %1$s", - "create.recipe.assembly.step": "Schritt %1$s:", - "create.recipe.assembly.progress": "Fortschritt: %1$s/%2$s", - "create.recipe.assembly.pressing": "Verarbeite in einer Presse", - "create.recipe.assembly.spout_filling_fluid": "Gieße %1$s aus", - "create.recipe.assembly.deploying_item": "Setze %1$s ein", - "create.recipe.assembly.cutting": "Zerteile mit einer Säge", - "create.recipe.assembly.repeat": "Wiederhole die Sequenz %1$s mal", - "create.recipe.assembly.junk": "Zufälliges Nebenprodukt", - "create.recipe.processing.chance": "Chance: %1$s%%", - "create.recipe.deploying.not_consumed": "Nicht verbraucht", - "create.recipe.heat_requirement.none": "Keine Hitze benötigt", - "create.recipe.heat_requirement.heated": "Wenig Hitze benötigt", - "create.recipe.heat_requirement.superheated": "Viel Hitze benötigt", - - "create.generic.range": "Reichweite", - "create.generic.radius": "Radius", - "create.generic.width": "Breite", - "create.generic.height": "Höhe", - "create.generic.length": "Länge", - "create.generic.speed": "Geschwindigkeit", - "create.generic.delay": "Verzögerung", - "create.generic.duration": "Dauer", - "create.generic.timeUnit": "Zeiteinheit", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Sekunden", - "create.generic.unit.minutes": "Minuten", - "create.generic.daytime.hour": "Stunde", - "create.generic.daytime.minute": "Minute", - "create.generic.daytime.second": "Sekunde", - "create.generic.daytime.pm": "nachmittags", - "create.generic.daytime.am": "vormittags", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "Uhrzeigersinn", - "create.generic.counter_clockwise": "Gegen-Uhrzeigersinn", - "create.generic.in_quotes": "„%1$s“", - "create.generic.pitch": "Tonhöhe: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;H;A#;A;G#;G", - - "create.action.scroll": "Wechseln", - "create.action.confirm": "Bestätigen", - "create.action.abort": "Abbrechen", - "create.action.saveToFile": "Speichern", - "create.action.discard": "Löschen", - - "create.keyinfo.toolmenu": "Werkzeugmenü", - "create.keyinfo.toolbelt": "Erreiche naheliegende Werkzeugkästen", - "create.keyinfo.scrollup": "Simuliere Mausrad hoch (In der Welt)", - "create.keyinfo.scrolldown": "Simuliere Mausrad runter (In der Welt)", - - "create.gui.scrollInput.defaultTitle": "Wähle eine Option:", - "create.gui.scrollInput.scrollToModify": "Mausrad zum Ändern", - "create.gui.scrollInput.scrollToAdjustAmount": "Mausrad um Betrag anzupassen", - "create.gui.scrollInput.scrollToSelect": "Mausrad zum Auswählen", - "create.gui.scrollInput.shiftScrollsFaster": "Shift zum schnelleren Auswählen", - "create.gui.toolmenu.focusKey": "Halte [%1$s] zum Fokussieren", - "create.gui.toolmenu.cycle": "[Mausrad] zum Wechseln", - - "create.toolbox.unequip": "Entfernen: %1$s", - "create.toolbox.outOfRange": "Werkzeugkasten des gehaltenen Gegenstands nicht in Reichweite", - "create.toolbox.detach": "Verfolgung stoppen und Gegenstand behalten", - "create.toolbox.depositAll": "Lege Gegenstände in nahegelegenen Werkzeugkasten zurück", - "create.toolbox.depositBox": "Lege Gegenstand in Werkzeugkasten zurück", - - "create.gui.symmetryWand.mirrorType": "Spiegeln", - "create.gui.symmetryWand.orientation": "Orientierung", - - "create.symmetry.mirror.plane": "Einfach Spiegeln", - "create.symmetry.mirror.doublePlane": "Rechteckig", - "create.symmetry.mirror.triplePlane": "Achteckig", - - "create.orientation.orthogonal": "Orthogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "Entlang Z", - "create.orientation.alongX": "Entlang X", - - "create.gui.terrainzapper.title": "Tragbarer Geländeformer", - "create.gui.terrainzapper.searchDiagonal": "Folge Diagonalen", - "create.gui.terrainzapper.searchFuzzy": "Ignoriere Kantenmaterial", - "create.gui.terrainzapper.patternSection": "Muster", - "create.gui.terrainzapper.pattern.solid": "Ausgefüllt", - "create.gui.terrainzapper.pattern.checkered": "Schachbrett", - "create.gui.terrainzapper.pattern.inversecheckered": "Invertiertes Schachbrett", - "create.gui.terrainzapper.pattern.chance25": "25% ausgefüllt", - "create.gui.terrainzapper.pattern.chance50": "50% ausgefüllt", - "create.gui.terrainzapper.pattern.chance75": "75% ausgefüllt", - "create.gui.terrainzapper.placement": "Platzierung", - "create.gui.terrainzapper.placement.merged": "Zusammengeführt", - "create.gui.terrainzapper.placement.attached": "Angefügt", - "create.gui.terrainzapper.placement.inserted": "Eingefügt", - "create.gui.terrainzapper.brush": "Pinsel", - "create.gui.terrainzapper.brush.cuboid": "Quader", - "create.gui.terrainzapper.brush.sphere": "Kugel", - "create.gui.terrainzapper.brush.cylinder": "Zylinder", - "create.gui.terrainzapper.brush.surface": "Fläche", - "create.gui.terrainzapper.brush.cluster": "Haufen", - "create.gui.terrainzapper.tool": "Werkzeug", - "create.gui.terrainzapper.tool.fill": "Füllen", - "create.gui.terrainzapper.tool.place": "Platzieren", - "create.gui.terrainzapper.tool.replace": "Ersetzen", - "create.gui.terrainzapper.tool.clear": "Löschen", - "create.gui.terrainzapper.tool.overlay": "Überlagern", - "create.gui.terrainzapper.tool.flatten": "Abflachen", - - "create.terrainzapper.shiftRightClickToSet": "Shift-Rechts-Klick um eine Form auszuwählen", - "create.terrainzapper.usingBlock": "Nutze: %1$s", - "create.terrainzapper.leftClickToSet": "Linksklicke einen Block, um ein Material auszuwählen", - - "create.minecart_coupling.two_couplings_max": "Jede Lore kann nicht mehr als zwei Kupplungen haben", - "create.minecart_coupling.unloaded": "Teile des Zuges scheinen in nicht geladenen Chunks zu sein", - "create.minecart_coupling.no_loops": "Kupplungen können keine Schleife bilden", - "create.minecart_coupling.removed": "Alle Kupplungen wurden von der Lore entfernt", - "create.minecart_coupling.too_far": "Loren sind zu weit entfernt", - - "create.contraptions.movement_mode": "Bewegungsmodus", - "create.contraptions.movement_mode.move_place": "Platziere immer wenn gestoppt", - "create.contraptions.movement_mode.move_place_returned": "Platziere nur in Ausgangsposition", - "create.contraptions.movement_mode.move_never_place": "Platziere nur wenn Anker zerstört", - "create.contraptions.movement_mode.rotate_place": "Platziere immer wenn gestoppt", - "create.contraptions.movement_mode.rotate_place_returned": "Platziere nur nahe des Ausgangswinkels", - "create.contraptions.movement_mode.rotate_never_place": "Platziere nur wenn Anker zerstört", - "create.contraptions.cart_movement_mode": "Loren-Bewegungsmodus", - "create.contraptions.cart_movement_mode.rotate": "Zeige immer in Bewegungsrichtung", - "create.contraptions.cart_movement_mode.rotate_paused": "Pausiere Akteure beim drehen", - "create.contraptions.cart_movement_mode.rotation_locked": "Sperre Rotation", - "create.contraptions.windmill.rotation_direction": "Rotationsrichtung", - "create.contraptions.clockwork.clock_hands": "Uhrzeiger", - "create.contraptions.clockwork.hour_first": "Stundenzeiger zuerst", - "create.contraptions.clockwork.minute_first": "Minutenzeiger zuerst", - "create.contraptions.clockwork.hour_first_24": "24-Stunden-Zeiger zuerst", - - "create.logistics.filter": "Filter", - "create.logistics.recipe_filter": "Rezeptfilter", - "create.logistics.fluid_filter": "Flüssigkeitsfilter", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Filter angewendet auf %1$s.", - "create.logistics.filter.apply_click_again": "Filter angewendet auf %1$s, klicke nochmal um Menge zu kopieren.", - "create.logistics.filter.apply_count": "Extraktionsmenge auf Filter angewendet.", - - "create.gui.goggles.generator_stats": "Generator Statistik:", - "create.gui.goggles.kinetic_stats": "Kinetische Statistik:", - "create.gui.goggles.at_current_speed": "bei derzeitiger Geschwindigkeit", - "create.gui.goggles.pole_length": "Stab Länge:", - "create.gui.goggles.fluid_container": "Flüssigkeitstank Info:", - "create.gui.goggles.fluid_container.capacity": "Kapazität:", - "create.gui.assembly.exception": "Diese Vorrichtung konnte nicht gebaut werden:", - "create.gui.assembly.exception.unmovableBlock": "Unbeweglicher Block (%4$s) bei [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Der Block bei [%1$s,%2$s,%3$s] war nicht in einem geladenen Chunk", - "create.gui.assembly.exception.structureTooLarge": "In dieser Vorrichtung sind zu viele Blöcke enthalten.\nDas konfigurierte Maximum ist: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Es sind zu viele Pleuelverlängerungen an diesen Kolben angebracht.\nDas konfigurierte Maximum ist: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Dem Kolben fehlen ein paar Pleuelverlängerungen", - "create.gui.assembly.exception.not_enough_sails": "Angebrachte Struktur enthält nicht genug segelähnliche Blöcke: %1$s\nEin Minimum von %2$s ist erforderlich", - "create.gui.gauge.info_header": "Messgerät Information:", - "create.gui.speedometer.title": "Rotationsgeschwindigkeit", - "create.gui.stressometer.title": "Netzwerkbelastung", - "create.gui.stressometer.capacity": "Verbleibende Kapazität", - "create.gui.stressometer.overstressed": "Überbelastet", - "create.gui.stressometer.no_rotation": "Keine Rotation", - "create.gui.contraptions.not_fast_enough": "Wie es scheint dreht sich dieses %1$s _nicht_ _schnell_ _genug_.", - "create.gui.contraptions.network_overstressed": "Wie es scheint ist diese Vorrichtung _überbelastet_. Füge mehr Quellen hinzu oder _verlangsame_ die Komponenten mit hoher _Belastungsauswirkung_.", - "create.gui.adjustable_crate.title": "Lagerraum", - "create.gui.adjustable_crate.storageSpace": "Lagerraum", - "create.gui.stockpile_switch.title": "Vorratssensor", - "create.gui.stockpile_switch.invert_signal": "Invertiere Signal", - "create.gui.stockpile_switch.move_to_lower_at": "Gehe zu unterer Spur bei %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Gehe zu oberer Spur bei %1$s%%", - "create.gui.sequenced_gearshift.title": "Sequenzielle Gangschaltung", - "create.gui.sequenced_gearshift.instruction": "Befehl", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Drehe um Winkel", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Drehe", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Winkel", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Drehe um Kolben/Seilrolle/Portalkran zu bewegen", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Kolben", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distanz", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Timed Delay", - "create.gui.sequenced_gearshift.instruction.delay": "Verzögerung", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Dauer", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Beende", - "create.gui.sequenced_gearshift.instruction.end": "Beende", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Warte auf neues Redstone Signal", - "create.gui.sequenced_gearshift.instruction.await": "Warte", - "create.gui.sequenced_gearshift.speed": "Geschwindigkeit, Richtung", - "create.gui.sequenced_gearshift.speed.forward": "Eingangsgeschwindigkeit, Vorwärts", - "create.gui.sequenced_gearshift.speed.forward_fast": "Doppelte Geschwindigkeit, Vorwärts", - "create.gui.sequenced_gearshift.speed.back": "Eingangsgeschwindigkeit, Umgekehrt", - "create.gui.sequenced_gearshift.speed.back_fast": "Doppelte Geschwindigkeit, Umgekehrt", - - "create.schematicAndQuill.dimensions": "Bauplangröße: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Erste Position festgelegt.", - "create.schematicAndQuill.secondPos": "Zweite Position festgelegt.", - "create.schematicAndQuill.noTarget": "Halte [Strg] zur Auswahl von Luft.", - "create.schematicAndQuill.abort": "Auswahl zurückgesetzt.", - "create.schematicAndQuill.title": "Bauplanname:", - "create.schematicAndQuill.convert": "Speichere und lade sofort hoch", - "create.schematicAndQuill.fallbackName": "Mein Bauplan", - "create.schematicAndQuill.saved": "Gespeichert als %1$s", - - "create.schematic.invalid": "[!] Ungültiger Gegenstand - Benutze einen Bauplantisch.", - "create.schematic.position": "Position", - "create.schematic.rotation": "Rotation", - "create.schematic.rotation.none": "Nein", - "create.schematic.rotation.cw90": "90° im Uhrzeigersinn", - "create.schematic.rotation.cw180": "180° im Uhrzeigersinn", - "create.schematic.rotation.cw270": "270° im Uhrzeigersinn", - "create.schematic.mirror": "Spiegeln", - "create.schematic.mirror.none": "Nein", - "create.schematic.mirror.frontBack": "Vor-Zurück", - "create.schematic.mirror.leftRight": "Links-Rechts", - "create.schematic.tool.deploy": "Positionieren", - "create.schematic.tool.move": "XZ Bewegen", - "create.schematic.tool.movey": "Y Bewegen", - "create.schematic.tool.rotate": "Rotieren", - "create.schematic.tool.print": "Drucken", - "create.schematic.tool.flip": "Umdrehen", - "create.schematic.tool.deploy.description.0": "Bewegt die Struktur an einen anderen ort.", - "create.schematic.tool.deploy.description.1": "Mit Rechtsklick auf den Boden platzieren.", - "create.schematic.tool.deploy.description.2": "[Strg] halten, um in einer bestimmten Entfernung zu arbeiten.", - "create.schematic.tool.deploy.description.3": "[Strg]-Mausrad um die Entfernung zu ändern.", - "create.schematic.tool.move.description.0": "Bewegt das Schema horizontal", - "create.schematic.tool.move.description.1": "Zeig auf das Schema und benutze [Strg]-Mausrad.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Bewegt das Schema vertikal", - "create.schematic.tool.movey.description.1": "[Strg]-Mausrad zum hoch- und runterbewegen", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Rotiert das Schema um seine Mitte.", - "create.schematic.tool.rotate.description.1": "[Strg]-Mausrad für eine Drehung um 90°", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Platziert sofort die Struktur in der Welt", - "create.schematic.tool.print.description.1": "[Rechtsklick] zum Bestätigen der Platzierung an der aktuellen Position.", - "create.schematic.tool.print.description.2": "Dieses Werkzeug ist nur für den Kreativ-Modus.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Kehrt das Schema entlang der ausgewählten Oberfläche um.", - "create.schematic.tool.flip.description.1": "Zeige auf das Schema und benutze [Strg]-Mausrad.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Synchronisation...", - "create.schematics.uploadTooLarge": "Dein Bauplan ist zu groß.", - "create.schematics.maxAllowedSize": "Die maximale Bauplan-Dateigröße ist:", - - "create.gui.schematicTable.refresh": "Aktualisiere Dateien", - "create.gui.schematicTable.open_folder": "Öffne Ordner", - "create.gui.schematicTable.title": "Bauplantisch", - "create.gui.schematicTable.availableSchematics": "Verfügbare Baupläne", - "create.gui.schematicTable.noSchematics": "Keine gespeicherten Baupläne", - "create.gui.schematicTable.uploading": "Hochladen...", - "create.gui.schematicTable.finished": "Hochgeladen!", - "create.gui.schematicannon.title": "Bauplankanone", - "create.gui.schematicannon.listPrinter": "Materiallistendruck", - "create.gui.schematicannon.gunpowderLevel": "Schwarzpulver bei %1$s%%", - "create.gui.schematicannon.shotsRemaining": "%1$s Schuss übrig", - "create.gui.schematicannon.shotsRemainingWithBackup": "Mit Reserve: %1$s", - "create.gui.schematicannon.optionEnabled": "Aktiviert", - "create.gui.schematicannon.optionDisabled": "Deaktiviert", - "create.gui.schematicannon.showOptions": "Zeige Drucker Einstellungen", - "create.gui.schematicannon.option.dontReplaceSolid": "Feste Blöcke nicht ersetzen", - "create.gui.schematicannon.option.replaceWithSolid": "Feste Blöcke mit festen ersetzen", - "create.gui.schematicannon.option.replaceWithAny": "Feste Blöcke immer ersetzen", - "create.gui.schematicannon.option.replaceWithEmpty": "Feste Blöcke mit Leere ersetzen", - "create.gui.schematicannon.option.skipMissing": "Fehlende Blöcke ignorieren", - "create.gui.schematicannon.option.skipTileEntities": "Tile Entities ignorieren", - "create.gui.schematicannon.slot.gunpowder": "Füge Schwarzpulver hinzu um die Kanone zu betreiben", - "create.gui.schematicannon.slot.listPrinter": "Platziere hier Bücher um eine Checkliste für deinen Bauplan zu drucken", - "create.gui.schematicannon.slot.schematic": "Füge Bauplan hier hinzu. Stelle sicher dass er an einer spezifischen Position bereitgestellt wird.", - "create.gui.schematicannon.option.skipMissing.description": "Wenn die Bauplankanone einen benötigten Block nicht finden kann, wird sie einfach beim nächsten weiter machen.", - "create.gui.schematicannon.option.skipTileEntities.description": "Die Bauplankanone wird versuchen, Blöcke mit extra Daten, beispielsweise Truhen, nicht zu ersetzen.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Die Kanone wird ausschließlich nicht feste Blöcke und Luft in ihrem Arbeitsbereich ersetzen.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Die Kanone wird feste Blöcke nur dann ersetzen, wenn an der Position vorher bereits ein fester Block war.", - "create.gui.schematicannon.option.replaceWithAny.description": "Die Kanone wird feste Blöcke ersetzen, wenn der Bauplan an der Position einen Block enthält.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Die Kanone wird alle Blöcke im Arbeitsbereich entfernen.", - - "create.schematicannon.status.idle": "Aus", - "create.schematicannon.status.ready": "Bereit", - "create.schematicannon.status.running": "An", - "create.schematicannon.status.finished": "Fertig", - "create.schematicannon.status.paused": "Pausiert", - "create.schematicannon.status.stopped": "Gestoppt", - "create.schematicannon.status.noGunpowder": "Schwarzpulver leer", - "create.schematicannon.status.targetNotLoaded": "Kein Block geladen", - "create.schematicannon.status.targetOutsideRange": "Ziel zu weit weg", - "create.schematicannon.status.searching": "Suchen", - "create.schematicannon.status.skipping": "Überspringen", - "create.schematicannon.status.missingBlock": "Fehlender Block:", - "create.schematicannon.status.placing": "Platzieren", - "create.schematicannon.status.clearing": "Blöcke löschen", - "create.schematicannon.status.schematicInvalid": "Bauplan ungültig", - "create.schematicannon.status.schematicNotPlaced": "Bauplan nicht positioniert", - "create.schematicannon.status.schematicExpired": "Bauplandatei abgelaufen", - - "create.materialChecklist": "Material Checkliste", - "create.materialChecklist.blocksNotLoaded": "* Haftungsausschluss *\n\nMaterialliste könnte inakkurat seit da es möglich ist dass releveante Chunks nicht geladen sind.", - - "create.gui.filter.deny_list": "Verweigert-Liste", - "create.gui.filter.deny_list.description": "Gegenstände werden nur weitergegeben wenn sie NICHT mit einem der oben genannten übereinstimmen. Eine leere Verweigert-Liste akzeptiert alles.", - "create.gui.filter.allow_list": "Erlaubt-Liste", - "create.gui.filter.allow_list.description": "Gegenstände werden nur weitergegeben wenn sie mit einem der oben genannten übereinstimmen. Eine leere Erlaubt-Liste lehnt alles ab.", - "create.gui.filter.respect_data": "Respektiere Daten", - "create.gui.filter.respect_data.description": "Gegenstände stimmen nur überein wenn ihre Haltbarkeit, Verzauberungen, und andere Attribute ebenfalls passen.", - "create.gui.filter.ignore_data": "Ignoriere Daten", - "create.gui.filter.ignore_data.description": "Gegenstände stimmen unabhängig ihrer Attribute überein.", - - "create.item_attributes.placeable": "ist plazierbar", - "create.item_attributes.placeable.inverted": "ist nicht plazierbar", - "create.item_attributes.consumable": "kann man essen", - "create.item_attributes.consumable.inverted": "kann man nicht essen", - "create.item_attributes.fluid_container": "kann Flüssigkeiten speichern", - "create.item_attributes.fluid_container.inverted": "kann Flüssigkeiten nicht speichern", - "create.item_attributes.enchanted": "ist verzaubert", - "create.item_attributes.enchanted.inverted": "ist nicht verzaubert", - "create.item_attributes.max_enchanted": "ist mit dem maximalen Level verzaubert", - "create.item_attributes.max_enchanted.inverted": "ist nicht mit dem maximalen Level verzaubert", - "create.item_attributes.renamed": "hat einen benutzerdefinierten Namen", - "create.item_attributes.renamed.inverted": "hat keinen benutzerdefinierten Namen", - "create.item_attributes.damaged": "ist beschädigt", - "create.item_attributes.damaged.inverted": "ist nicht beschädigt", - "create.item_attributes.badly_damaged": "ist stark beschädigt", - "create.item_attributes.badly_damaged.inverted": "ist nicht stark beschädigt", - "create.item_attributes.not_stackable": "kann nicht gestapelt werden", - "create.item_attributes.not_stackable.inverted": "kann gestapelt werden", - "create.item_attributes.equipable": "kann ausgerüstet werden", - "create.item_attributes.equipable.inverted": "kann nicht ausgerüstet werden", - "create.item_attributes.furnace_fuel": "ist Brennstoff", - "create.item_attributes.furnace_fuel.inverted": "ist nicht Brennstoff", - "create.item_attributes.washable": "kann gewaschen werden", - "create.item_attributes.washable.inverted": "kann nicht gewaschen werden", - "create.item_attributes.hauntable": "kann gespenstisch sein", - "create.item_attributes.hauntable.inverted": "kann nicht gespenstisch sein", - "create.item_attributes.crushable": "kann zerkleinert werden", - "create.item_attributes.crushable.inverted": "kann nicht zerkleinert werden", - "create.item_attributes.smeltable": "kann geschmolzen werden", - "create.item_attributes.smeltable.inverted": "kann nicht geschmolzen werden", - "create.item_attributes.smokable": "kann geräuchert werden", - "create.item_attributes.smokable.inverted": "kann nicht geräuchert werden", - "create.item_attributes.blastable": "ist im Schmelzofen schmelzbar", - "create.item_attributes.blastable.inverted": "ist nicht im Schmelzofen schmelzbar", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "ist Shulker %1$s", - "create.item_attributes.shulker_level.inverted": "ist Shulker nicht %1$s", - "create.item_attributes.shulker_level.full": "voll", - "create.item_attributes.shulker_level.empty": "leer", - "create.item_attributes.shulker_level.partial": "teilweise gefüllt", - "create.item_attributes.in_tag": "ist mit %1$s makiert", - "create.item_attributes.in_tag.inverted": "ist nicht mit %1$s markoiert", - "create.item_attributes.in_item_group": "ist in der Gruppe '%1$s'", - "create.item_attributes.in_item_group.inverted": "ist nicht in der Gruppe '%1$s'", - "create.item_attributes.added_by": "wurde von %1$s hinzugefügt", - "create.item_attributes.added_by.inverted": "wurde nicht von %1$s hinzugefügt", - "create.item_attributes.has_enchant": "ist mit %1$s verzaubert", - "create.item_attributes.has_enchant.inverted": "ist nicht mit %1$s verzaubert", - "create.item_attributes.color": "ist %1$s gefärbt", - "create.item_attributes.color.inverted": "ist nicht %1$s gefärbt", - "create.item_attributes.has_fluid": "enthält %1$s", - "create.item_attributes.has_fluid.inverted": "enthält nicht %1$s", - "create.item_attributes.has_name": "hat den Benutzerdefinierten Namen %1$s", - "create.item_attributes.has_name.inverted": "hat nicht den benutzerdefinierten Namen %1$s", - "create.item_attributes.book_author": "wurde verfasst von %1$s", - "create.item_attributes.book_author.inverted": "wurde nicht von %1$s verfasst", - "create.item_attributes.book_copy_original": "ist ein Original", - "create.item_attributes.book_copy_original.inverted": "ist kein Original", - "create.item_attributes.book_copy_first": "ist die erste Kopie", - "create.item_attributes.book_copy_first.inverted": "ist nicht die erste Kopie", - "create.item_attributes.book_copy_second": "ist die zweite Kopie", - "create.item_attributes.book_copy_second.inverted": "ist nicht die Zweite Kopie", - "create.item_attributes.book_copy_tattered": "ist ein zerfetztes Durcheinander", - "create.item_attributes.book_copy_tattered.inverted": "sit kein zerfetztes Durcheinander", - "create.item_attributes.astralsorcery_amulet": "verbessert %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "verbessert nicht %1$s", - "create.item_attributes.astralsorcery_constellation": "ist abgestimmt auf %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "ist nicht abgestimmt auf %1$s", - "create.item_attributes.astralsorcery_crystal": "hat das Kristallattribut %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "hat nicht das Kristallattribut %1$s", - "create.item_attributes.astralsorcery_perk_gem": "hat das Vorteilsattribut %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "hat nicht das Vorteilsattribut %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Keine Attribute ausgewählt", - "create.gui.attribute_filter.selected_attributes": "Ausgewählte Attribute:", - "create.gui.attribute_filter.add_attribute": "Füge Attribut zur Liste hinzu", - "create.gui.attribute_filter.add_inverted_attribute": "Füge gegenteiliges Attribut zur Liste hinzu", - "create.gui.attribute_filter.allow_list_disjunctive": "Erlaubt-Liste (Irgendeins)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Gegenstände werden weitergereicht wenn sie irgendeins der ausgewählten Attribute haben.", - "create.gui.attribute_filter.allow_list_conjunctive": "Erlaubt-Liste (Alle)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Gegenstände werden nur weitergereicht wenn sie ALLE der ausgewählten Attribute haben.", - "create.gui.attribute_filter.deny_list": "Verweigert-Liste", - "create.gui.attribute_filter.deny_list.description": "Gegenstände werden nur weitergereicht wenn sie KEINES der ausgewählten Attribute haben.", - "create.gui.attribute_filter.add_reference_item": "Füge Referenz-Gegenstand hinzu", - - "create.tooltip.holdForDescription": "Halte [%1$s] für eine Zusammenfassung", - "create.tooltip.holdForControls": "Halte [%1$s] für die Steuerung", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Strg", - "create.tooltip.speedRequirement": "Geschwindigkeitsanforderung: %1$s", - "create.tooltip.speedRequirement.none": "Keine", - "create.tooltip.speedRequirement.slow": "Langsam", - "create.tooltip.speedRequirement.medium": "Moderat", - "create.tooltip.speedRequirement.fast": "Schnell", - "create.tooltip.stressImpact": "Kinetische Belastungsauswirkung: %1$s", - "create.tooltip.stressImpact.low": "Niedrig", - "create.tooltip.stressImpact.medium": "Moderat", - "create.tooltip.stressImpact.high": "Hoch", - "create.tooltip.stressImpact.overstressed": "Überbelastet", - "create.tooltip.up_to": "Bis zu %1$s", - "create.tooltip.capacityProvided": "Kinetische Belastungskapazität: %1$s", - "create.tooltip.capacityProvided.low": "Niedrig", - "create.tooltip.capacityProvided.medium": "Mittel", - "create.tooltip.capacityProvided.high": "Groß", - "create.tooltip.generationSpeed": "Generiert mit %1$s %2$s", - "create.tooltip.analogStrength": "Analoge Stärke: %1$s/15", - - "create.mechanical_arm.extract_from": "Nehme Gegenstände von %1$s", - "create.mechanical_arm.deposit_to": "Lege Gegenstände in %1$s", - "create.mechanical_arm.summary": "Mechanischer Arm hat %1$s Eingabe(n) und %2$s Ausgabe(n).", - "create.mechanical_arm.points_outside_range": "%1$s ausgewählte(r) Interaktionspunkt(e) entfernt aufgrund Reichweitenlimitierungen.", - - "create.weighted_ejector.target_set": "Ziel ausgewählt", - "create.weighted_ejector.target_not_valid": "Werfe auf angrenzenden Block (Ziel war nicht gültig)", - "create.weighted_ejector.no_target": "Werfe auf angrenzenden Block (Kein Ziel war ausgewählt)", - "create.weighted_ejector.targeting": "Werfe nach [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Geworfene Stapelgröße", - - "create.logistics.when_multiple_outputs_available": "Wenn mehrere Ausgaben verfügbar sind", - - "create.mechanical_arm.selection_mode.round_robin": "Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "Gezwungener Round Robin", - "create.mechanical_arm.selection_mode.prefer_first": "Bevorzuge erstes Ziel", - - "create.tunnel.selection_mode.split": "Aufteilung", - "create.tunnel.selection_mode.forced_split": "Gezwungene Aufteilung", - "create.tunnel.selection_mode.round_robin": "Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "Gezwungener Round Robin", - "create.tunnel.selection_mode.prefer_nearest": "Bevorzuge Naheliegensten", - "create.tunnel.selection_mode.randomize": "Zufällig", - "create.tunnel.selection_mode.synchronize": "Synchronisiere Eingaben", - - "create.tooltip.chute.header": "Rinnen Information", - "create.tooltip.chute.items_move_down": "Gegenstände bewegen sich nach unten", - "create.tooltip.chute.items_move_up": "Gegenstände bewegen sich nach oben", - "create.tooltip.chute.no_fans_attached": "Keine angeschlossenen Propeller", - "create.tooltip.chute.fans_push_up": "Propeller schieben von unterhalb", - "create.tooltip.chute.fans_push_down": "Propeller schieben von oberhalb", - "create.tooltip.chute.fans_pull_up": "Propeller ziehen von oberhalb", - "create.tooltip.chute.fans_pull_down": "Propeller ziehen von unterhalb", - "create.tooltip.chute.contains": "Enthält: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Verteilt derzeit:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Rechtsklicken, um zu entnehmen", - - "create.linked_controller.bind_mode": "Bindungsmodus aktiv", - "create.linked_controller.press_keybind": "Drücke %1$s, %2$s, %3$s, %4$s, %5$s oder %6$s, um diese Frequenz zum zugehörigen Schlüssel zu binden", - "create.linked_controller.key_bound": "Frequenz wurde an %1$s gebunden", - "create.linked_controller.frequency_slot_1": "Taste: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "Taste: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "Zutatenplatz", - "create.crafting_blueprint.filter_items_viable": "Gegenstände des erweiterten Filters sind tragfähig", - "create.crafting_blueprint.display_slot": "Anzeigeplatz", - "create.crafting_blueprint.inferred": "Abgeleitet vom Rezept", - "create.crafting_blueprint.manually_assigned": "Manuell zugewiesen", - "create.crafting_blueprint.secondary_display_slot": "Sekundärer Anzeigeplatz", - "create.crafting_blueprint.optional": "Optional", - - "create.potato_cannon.ammo.attack_damage": "%1$s Angriffsschaden", - "create.potato_cannon.ammo.reload_ticks": "%1$s Neulade-Ticks", - "create.potato_cannon.ammo.knockback": "%1$s Rückstoß", - - "create.hint.hose_pulley.title": "Endlose Versorgung", - "create.hint.hose_pulley": "Das angewählte Gewässer wird als unendlich betrachtet.", - "create.hint.mechanical_arm_no_targets.title": "Keine Ziele", - "create.hint.mechanical_arm_no_targets": "Es schein dieser _Mechanische_ _Arm_ hat keine _Ziele_. Wähle Riemen, Depots oder Trichter und andere Blöcke indem du sie _Rechts-Klickst_ während du den _Mechanischen_ _Arm_ in deiner _Hand_ _hälst_.", - "create.hint.empty_bearing.title": "Aktualisiere Lager", - "create.hint.empty_bearing": "_Rechts-Klicke_ das Lager mit einer _leeren_ _Hand_ um die Struktur die du davor gebaut hast _anzubringen_.", - "create.hint.full_deployer.title": "Einsatzgerät Gegenstand Überlauf", - "create.hint.full_deployer": "Es scheint, dieses _Einsatzgerät_ enthält _überflüssige_ _Gegenstände_ die _extrahiert_ werden müssen. Nutze _Trichter_ oder anderes um ihn von seinem Überfluss zu befreien.", - - "create.backtank.low": "Flaschenluftdruck gering", - "create.backtank.depleted": "Flaschenluftdruck erschöpft", - - "create.hint.derailed_train.title": "Entgleister Zug", - "create.hint.derailed_train": "Es scheint, als befände sich dieser _Zug_ nicht mehr auf dem Gleis. _Rechts-klicke_ mit einem _Schraubenschlüssel_, um ihn auf ein Gleis in der Nähe zu hieven.", - - "create.boiler.status": "Kesselzustand: %1$s", - "create.boiler.status_short": "Kessel: %1$s", - "create.boiler.passive": "Passiv", - "create.boiler.idle": "Inaktiv", - "create.boiler.lvl": "Lvl %1$s", - "create.boiler.max_lvl": "Max.", - "create.boiler.size": "Größe", - "create.boiler.size_dots": "....... ", - "create.boiler.water": "Wasser", - "create.boiler.water_dots": "... ", - "create.boiler.heat": "Wärme", - "create.boiler.heat_dots": "...... ", - "create.boiler.via_one_engine": "mit einer Dampfmaschine", - "create.boiler.via_engines": "mit %1$s Dampfmaschinen", - - "create.gui.schedule.lmb_edit": "Links-Klick zum Bearbeiten", - "create.gui.schedule.rmb_remove": "Rechts-Klick zum Entfernen", - "create.gui.schedule.duplicate": "Duplizieren", - "create.gui.schedule.remove_entry": "Aktion entfernen", - "create.gui.schedule.add_entry": "Aktion hinzufügen", - "create.gui.schedule.move_up": "Nach oben", - "create.gui.schedule.move_down": "Nach unten", - "create.gui.schedule.add_condition": "Bedingung hinzufügen", - "create.gui.schedule.alternative_condition": "Alternative Bedingung", - - "create.schedule.instruction_type": "Nächste Aktion:", - "create.schedule.instruction.editor": "Aktion bearbeiten", - "create.schedule.instruction.destination": "Fahre zu Bahnhof", - "create.schedule.instruction.destination.summary": "Nächster Halt:", - "create.schedule.instruction.filter_edit_box": "Bahnhofsbezeichnung", - "create.schedule.instruction.filter_edit_box_1": "Benutze * als Textplatzhalter", - "create.schedule.instruction.filter_edit_box_2": "Beispiel: 'Mein Bahnhof, Gleis *'", - "create.schedule.instruction.filter_edit_box_3": "Züge wählen automatisch den nächstgelegenen unbesetzten Treffer", - "create.schedule.instruction.rename": "Aktualisiere Fahrplantitel", - "create.schedule.instruction.rename.summary": "Neuer Titel:", - "create.schedule.instruction.name_edit_box": "Fahrplantitel", - "create.schedule.instruction.name_edit_box_1": "Verändert den auf Anzeigetafeln angezeigten Text", - "create.schedule.instruction.name_edit_box_2": "Standardmäßig die Bezeichnung des nächsten Bahnhofs", - "create.schedule.instruction.throttle": "Ändere Höchstgeschwindigkeit", - "create.schedule.instruction.throttle.summary": "Setze Höchstgeschwindigkeit auf %1$s", - "create.schedule.instruction.throttle_edit_box": "Begrenzung", - "create.schedule.instruction.throttle_edit_box_1": "Legt die Höchstgeschwindigkeit des Zuges fest", - "create.schedule.condition_type": "Weiterfahrt wenn/nach:", - "create.schedule.condition.editor": "Bedingung bearbeiten", - "create.schedule.condition.delay": "Festgelegte Verzögerung", - "create.schedule.condition.delay_short": "Warte: %1$s", - "create.schedule.condition.delay.status": "Abfahrt in %1$s", - "create.schedule.condition.idle": "Kein weiterer Güteraustausch", - "create.schedule.condition.idle_short": "Kein Güteraustausch: %1$s", - "create.schedule.condition.idle.status": "Kein Güteraustausch in %1$s", - "create.schedule.condition.for_x_time": "für %1$s", - "create.schedule.condition.unloaded": "Chunk entladen", - "create.schedule.condition.unloaded.status": "Warten auf entladen des Chunks", - "create.schedule.condition.powered": "Bahnhof empfängt RS-Signal", - "create.schedule.condition.powered.status": "Warten auf Redstone-Signal", - "create.schedule.condition.time_of_day": "Tageszeit", - "create.schedule.condition.time_of_day.scheduled": "Geplante Zeit: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%2$s:%3$s", - "create.schedule.condition.time_of_day.rotation": "Taktung", - "create.schedule.condition.time_of_day.rotation.every_24": "Täglich", - "create.schedule.condition.time_of_day.rotation.every_12": "Alle 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "Alle 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "Alle 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "Alle 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "Alle 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "Stündlich", - "create.schedule.condition.time_of_day.rotation.every_0_45": "Alle 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "Halbstündlich", - "create.schedule.condition.time_of_day.rotation.every_0_15": "Viertelstündlich", - "create.schedule.condition.time_of_day.status": "Abfahrt um ", - "create.schedule.condition.threshold.train_holds": "Zug beinhaltet %1$s", - "create.schedule.condition.threshold.greater": "mehr als", - "create.schedule.condition.threshold.less": "weniger als", - "create.schedule.condition.threshold.equal": "genau", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$s %3$s", - "create.schedule.condition.threshold.matching_content": "passender Inhalt", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "Maßeinheit", - "create.schedule.condition.threshold.items": "Items", - "create.schedule.condition.threshold.stacks": "Stacks", - "create.schedule.condition.threshold.buckets": "Eimer", - "create.schedule.condition.threshold.status": "Zugladestand: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "Referenz-Item", - "create.schedule.condition.threshold.place_item_2": "Filter können verwendet werden", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "Flüssigkeitsladestand", - "create.schedule.condition.item_threshold": "Item-Ladestand", - "create.schedule.condition.redstone_link": "Redstone-Link", - "create.schedule.condition.redstone_link.status": "Warten auf Restone-Link", - "create.schedule.condition.redstone_link_on": "Link an", - "create.schedule.condition.redstone_link_off": "Link aus", - "create.schedule.condition.redstone_link.powered": "Aktiviert", - "create.schedule.condition.redstone_link.unpowered": "Deaktiviert", - "create.schedule.condition.redstone_link.frequency_state": "Frequenzzustand:", - "create.schedule.condition.redstone_link.frequency_powered": "Signal über Frequenz:", - "create.schedule.condition.redstone_link.frequency_unpowered": "Kein Signal über Frequenz:", - "create.schedule.condition.player_count": "Sitzauslastung", - "create.schedule.condition.player_count.summary": "%1$s Spieler", - "create.schedule.condition.player_count.summary_plural": "%1$s Spieler", - "create.schedule.condition.player_count.seated": "%1$s sitzend", - "create.schedule.condition.player_count.players": "Spieler", - "create.schedule.condition.player_count.condition": "Bedingung", - "create.schedule.condition.player_count.exactly": "Genau", - "create.schedule.condition.player_count.or_above": "Oder mehr", - "create.schedule.condition.player_count.status": "Fahrgäste: %1$s/%2$s", - "create.schedule.loop": "Fortlaufend wiederholen", - "create.schedule.loop1": "Fahrplan wird nach", - "create.schedule.loop2": "Abschluss wiederholt", - "create.schedule.reset": "Fortschritt zurücksetzen", - "create.schedule.skip": "Aktuellen Halt überspringen", - "create.schedule.applied_to_train": "Der Zug folgt jetzt diesem Fahrplan", - "create.schedule.non_controlling_seat": "Der Zugführer muss vor einer Zugsteuerung sitzen", - "create.schedule.remove_with_empty_hand": "Entferne den aktuellen Fahrplan mit der Hand", - "create.schedule.auto_removed_from_train": "Auto-Fahrplan entfernt", - "create.schedule.removed_from_train": "Fahrplan vom Zug entfernt", - "create.schedule.no_stops": "Dieser Fahrplan enthält noch keine Halte", - "create.schedule.continued": "Fahrt wird fortgesetzt", - - "create.track.selection_cleared": "Auswahl aufheben", - "create.track.valid_connection": "Kann verbinden ✔", - "create.track.second_point": "Platziere das Gleis oder wähle einen zweiten Punkt aus", - "create.track.too_far": "Zu weit entfernt", - "create.track.original_missing": "Ursprünglicher Block, Shift-Klicke, um zurückzusetzen", - "create.track.perpendicular": "Kann nicht senkrecht verbinden", - "create.track.ascending_s_curve": "Kann keine steigenden S-Kurven erzeugen", - "create.track.too_sharp": "Kurve zu scharf", - "create.track.too_steep": "Rampe zu steil", - "create.track.slope_turn": "Kann Rampe nicht in einer Kurve betreten oder verlassen", - "create.track.opposing_slopes": "Kann keine Rampen mit entgegengesetzen Steigungen verbinden", - "create.track.leave_slope_ascending": "Kann diese Rampe nicht während des Steigens verlassen", - "create.track.leave_slope_descending": "Kann diese Rampe nicht während des Sinkens verlassen", - "create.track.turn_90": "Kann sich höchstens um 90 Grad drehen", - "create.track.junction_start": "Kann keine Verbindung von einer Kreuzung starten", - "create.track.turn_start": "Kann keine Verbindung von einer Kurve starten", - "create.track.not_enough_tracks": "Nicht genug Gleise", - "create.track.not_enough_pavement": "Nicht genug Gleisbettblöcke", - - "create.portal_track.failed": "Kann Portalgleis nicht platzieren:", - "create.portal_track.missing": "Zielportal noch nicht generiert", - "create.portal_track.blocked": "Zielort blockiert (%1$s,%2$s,%3$s)", - - "create.station.idle": "Bahnhof ist inaktiv", - "create.station.assembly_title": "Zugbau", - "create.station.close": "Fenster schließen", - "create.station.cancel": "Bau abbrechen", - "create.station.failed": "Bau fehlgeschlagen", - "create.station.icon_type": "Symboltyp", - "create.station.create_train": "Neuen Zug bauen", - "create.station.assemble_train": "Zug bauen", - "create.station.disassemble_train": "Zug um-/abbauen", - "create.station.remove_schedule": "Fahrplan entfernen", - "create.station.remove_auto_schedule": "Auto-Fahrplan entfernen", - "create.station.no_assembly_diagonal": "Kann Züge nicht auf diagonal", - "create.station.no_assembly_diagonal_1": "verlaufenden Gleisen bauen", - "create.station.no_assembly_curve": "Kann Züge nicht auf kurvenförmig", - "create.station.no_assembly_curve_1": "verlaufenden Gleisen bauen", - "create.station.train_not_aligned": "Zug kann nicht umgebaut werden,", - "create.station.train_not_aligned_1": "nicht alle Waggons befinden sich auf einer geraden Strecke", - "create.station.carriage_number": "Waggon %1$s:", - "create.station.retry": "Behebe dies und versuche es erneut", - "create.station.no_bogeys": "Kein Drehgestell", - "create.station.one_bogey": "1 Drehgestell", - "create.station.more_bogeys": "%1$s Drehgestelle", - "create.station.how_to": "Wende den Zugrahmen auf markierte Gleise an, um ein neues Drehgestell zu bauen.", - "create.station.how_to_1": "Entferne Drehgestelle, indem du den oberen Block abbaust.", - "create.station.how_to_2": "Baue Waggons, die mit jeweils einem oder zwei Drehgestellen verbunden sind.", - - "create.train_assembly.too_many_bogeys": "Zu viele Drehgestelle verbunden: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "Vorderstes Drehgestell muss sich auf der Bahnhofsmarkierung befinden", - "create.train_assembly.no_bogeys": "Keine Drehgestelle gefunden", - "create.train_assembly.not_connected_in_order": "Drehgestelle sind nicht in der richtigen Reihenfolge verbunden", - "create.train_assembly.bogeys_too_close": "Waggons %1$s und %2$s befinden sich zu nah aneinander", - "create.train_assembly.single_bogey_carriage": "Dieser Drehgestelltyp kann alleine keinen Waggon tragen", - "create.train_assembly.nothing_attached": "Keine Struktur mit Drehgestell %1$s verbunden", - "create.train_assembly.no_controls": "Mindestens eine vorwärtsgerichtete Zugsteuerung muss sich auf diesem Zug befinden", - "create.train_assembly.sideways_controls": "Eine verbundene Zugsteuerung ist seitwärts angebracht", - "create.train_assembly.bogey_created": "Drehgestell erschaffen. Klicke erneut, um zwischen verschiedenen Typen zu wechseln", - "create.train_assembly.requires_casing": "Benutze Zugrahmen, um Drehgestelle auf Gleise zu bauen", - - "create.track_target.set": "Anvisiertes Gleis ausgewählt", - "create.track_target.success": "Erfolgreich mit anvisiertem Gleis gebunden", - "create.track_target.clear": "Gleisauswahl aufgehoben", - "create.track_target.missing": "Rechts-klicke zuerst das Zielgleis", - "create.track_target.too_far": "Ausgewähltes Gleis ist zu weit entfernt", - "create.track_target.no_junctions": "Gleis kann keine Kreuzung sein", - "create.track_target.occupied": "Anvisiertes Gleis ist belegt", - "create.track_target.invalid": "Kann dieses Gleis nicht auswählen", - - "create.train.unnamed": "Unbenannter Zug", - "create.train.cannot_relocate_moving": "Kann keinen fahrenden Zug versetzen", - "create.train.relocate": "Klicke auf Gleis, auf welches %1$s versetzt werden soll. Shift-Klicke zum Abbrechen", - "create.train.relocate.abort": "Versetzen abgebrochen", - "create.train.relocate.success": "Versetzen erfolgreich", - "create.train.relocate.valid": "Kann hierhin versetzen, Klicke zum Bestätigen", - "create.train.relocate.invalid": "Kann Zug nicht hierhin versetzen", - "create.train.relocate.too_far": "Kann Zug nicht so weit versetzen", - "create.train.departing_from": "Abfahrt von %1$s", - "create.train.arrived_at": "Ankunft bei %1$s", - "create.train.status": " Information über Zug: %1$s", - "create.train.status.back_on_track": "Zug befindet sich wieder auf Gleis", - "create.train.status.collision": "Kollision mit anderem Zug", - "create.train.status.end_of_track": "Ein Waggon hat das Ende seines Gleises erreicht", - "create.train.status.double_portal": "Ein Waggon kann kein Portal während des Verlassens eines anderen betreten", - "create.train.status.coupling_stress": "Zwangsbremsung aufgrund von Spannung an einer Kopplung", - "create.train.status.track_missing": "Gleise fehlen unter dem Zug", - "create.train.status.paused_for_manual": "Fahrplan für manuelle Fahrt pausiert", - "create.train.status.opposite_driver": "Pfad erfordert einen in die andere Richtung zeigenden Fahrer", - "create.train.status.missing_driver": "Fahrer ist verschwunden", - "create.train.status.found_driver": "Ein neuer Fahrer ist aufgetaucht", - "create.train.status.navigation_success": "Navigation erfolgreich", - "create.train.status.no_match": "Kein Bahnhof im Streckennetz passt zu '%1$s'", - "create.train.status.no_path": "Kein passender Pfad zum nächsten Bahnhof gefunden", - - "create.track_signal.cannot_change_mode": "Kann Modus dieses Signals nicht wechseln", - "create.track_signal.mode_change.entry_signal": "-> Erlaube Weiterfahrt wenn Abschnitt frei", - "create.track_signal.mode_change.cross_signal": "-> Erlaube Weiterfahrt wenn Abschnitt vollständig durchfahrbar", - - "create.contraption.controls.start_controlling": "Du steuerst jetzt: %1$s", - "create.contraption.controls.stop_controlling": "Du steuerst den Zug nicht mehr", - "create.contraption.controls.approach_station": "Halte %1$s gedrückt, um bei %2$s zu halten", - - "create.display_link.set": "Anvisierte Position ausgewählt", - "create.display_link.success": "Erfolgreich mit ausgewählter Position gebunden", - "create.display_link.clear": "Positionsauswahl aufgehoben", - "create.display_link.too_far": "Ausgewählte Position ist zu weit entfernt", - "create.display_link.invalid": "Link hat kein gültiges Ziel, versuche es erneut", - "create.display_link.title": "Anzeige-Link", - "create.display_link.no_source": "Keine Anzeigequelle", - "create.display_link.no_target": "Kein Anzeigeziel", - "create.display_link.reading_from": "Lesen von:", - "create.display_link.writing_to": "Übertragen an:", - "create.display_link.attached_side": "Block auf angebrachter Seite", - "create.display_link.targeted_location": "Block am Zielort", - "create.display_link.view_compatible": "Klicke, um alle kompatiblen Blöcke anzuzeigen", - "create.display_link.information_type": "Informationstyp", - "create.display_link.display_on": "Übertragen an:", - "create.display_link.display_on_multiline": "Beginne Schreiben bei:", - - "create.display_source.label": "Hinzugefügte Bezeichnung", - "create.display_source.combine_item_names": "Kombiniere Item-Namen", - "create.display_source.count_items": "Anzahl passender Items", - "create.display_source.list_items": "Liste passender Items", - "create.display_source.fluid_amount": "Menge passender Flüssigkeiten", - "create.display_source.list_fluids": "Liste passender Flüssigkeiten", - "create.display_source.nixie_tube": "Kopiere Nixie-Röhren", - "create.display_source.fill_level": "Behälterfüllstand", - "create.display_source.fill_level.display": "Anezigeformat", - "create.display_source.fill_level.percent": "Prozent", - "create.display_source.fill_level.progress_bar": "Fortschrittsleiste", - "create.display_source.value_list.display": "Werteanzeige", - "create.display_source.value_list.shortened": "Verkürzt", - "create.display_source.value_list.full_number": "Vollständige Zahl", - "create.display_source.value_list.thousand": "Tsd.", - "create.display_source.value_list.million": "Mio.", - "create.display_source.player_deaths": "Spielertode", - "create.display_source.scoreboard": "Punktetafel", - "create.display_source.scoreboard.objective": "Ziel-ID", - "create.display_source.scoreboard.objective_not_found": "'%1$s' nicht gefunden", - "create.display_source.scoreboard.objective.deaths": "Spielertode", - "create.display_source.time_of_day": "Tageszeit", - "create.display_source.stop_watch": "Stoppuhr", - "create.display_source.time.format": "Zeitformat", - "create.display_source.time.12_hour": "12 Stunden", - "create.display_source.time.24_hour": "24 Stunden", - "create.display_source.accumulate_items": "Gesamtdurchsatz", - "create.display_source.item_throughput": "Durchsatz", - "create.display_source.item_throughput.interval": "Intervall", - "create.display_source.item_throughput.interval.second": "pro Sekunde", - "create.display_source.item_throughput.interval.minute": "pro Minute", - "create.display_source.item_throughput.interval.hour": "pro Stunde", - "create.display_source.train_status": "Zugfahrplanstatus", - "create.display_source.station_summary": "Bahnhofsinformation", - "create.display_source.station_summary.filter": "Bahnhofsbezeichnungsfilter", - "create.display_source.station_summary.train_name_column": "Spalte 'Zug' Größe", - "create.display_source.station_summary.platform_column": "Spalte 'Gleis' Größe", - "create.display_source.station_summary.now": "jetzt", - "create.display_source.station_summary.minutes": "min", - "create.display_source.station_summary.seconds": "%1$ss", - "create.display_source.observed_train_name": "Zugnamen ermitteln", - "create.display_source.max_enchant_level": "Max. Verzauberungskosten", - "create.display_source.boiler_status": "Kesselstatus", - "create.display_source.entity_name": "Entitätenname", - "create.display_source.kinetic_speed": "Drehgeschwindigkeit (RPM)", - "create.display_source.kinetic_speed.absolute": "Ignoriere Richtung", - "create.display_source.kinetic_speed.directional": "Beachte Richtung", - "create.display_source.kinetic_stress": "Netzwerkbelastung", - "create.display_source.kinetic_stress.display": "Angezeigte Information", - "create.display_source.kinetic_stress.progress_bar": "Fortschrittsleiste", - "create.display_source.kinetic_stress.percent": "Prozentzahl", - "create.display_source.kinetic_stress.current": "Belastung in SU", - "create.display_source.kinetic_stress.max": "Gesamtkapazität", - "create.display_source.kinetic_stress.remaining": "Verbleibende SU", - "create.display_source.redstone_power": "Redstone-Signalstärke", - "create.display_source.redstone_power.display": "Anzeigeformat", - "create.display_source.redstone_power.number": "Zahl", - "create.display_source.redstone_power.progress_bar": "Fortschrittsleiste", - "create.display_source.boiler.not_enough_space": "Nicht genug Platz ", - "create.display_source.boiler.for_boiler_status": "für Kesselstatus", - - "create.display_target.line": "Zeile %1$s", - "create.display_target.page": "Seite %1$s", - "create.display_target.single_line": "Einzelne Zeile", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z;Ä;Ö;Ü;ß", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;jetzt;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;Tsd.;Mio.", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "Ausgewählter Bereich ist zu groß", - "create.super_glue.cannot_reach": "Ausgewählte Blöcke müssen miteinander verbunden sein", - "create.super_glue.click_to_confirm": "Klicke erneut zum Bestätigen", - "create.super_glue.click_to_discard": "Shift-klicke zum Aufheben der Auswahl", - "create.super_glue.first_pos": "Erste Position ausgewählt", - "create.super_glue.abort": "Auswahl aufgehoben", - "create.super_glue.not_enough": "Nicht genug Kleber im Inventar", - "create.super_glue.success": "Kleben...", - - "create.gui.config.overlay1": "Hi :)", - "create.gui.config.overlay2": "Dies ist ein Beispiel Overlay", - "create.gui.config.overlay3": "Klicke oder ziehe mit deiner Maus", - "create.gui.config.overlay4": "um diese Vorschau zu bewegen", - "create.gui.config.overlay5": "Drücke ESC um diesen Bildschirm zu verlassen", - "create.gui.config.overlay6": "und die neue Position zu speichern", - "create.gui.config.overlay7": "Benutze /create overlay reset", - "create.gui.config.overlay8": "um die Standardposition zurückzusetzen", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server Tick ist derzeitig um %s ms verlangsamt :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Server Tick ist jetzt um %s ms verlangsamt >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Server Tick ist jetzt wieder auf normaler Geschwindigkeit :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: Benutze /killtps stop um den Server Tick wieder auf normale Geschwindigkeit zu bringen", - "create.command.killTPSCommand.status.usage.1": "[Create]: Benutze /killtps start um den Server Tick künstlich zu verlangsamen", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Dieses Lorengespann ist zu groß, um es aufzusammeln", - "create.contraption.minecart_contraption_illegal_pickup": "Eine mysteriöse Kraft hält dieses Lorengespann in dieser Welt", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Apparat stoppt", - "create.subtitle.peculiar_bell_use": "Eigenartige Glockenschläge", - "create.subtitle.worldshaper_place": "Geländeformer zippt", - "create.subtitle.whistle_train_manual": "Zug hupt", - "create.subtitle.steam": "Dampf rauscht", - "create.subtitle.saw_activate_stone": "Mechanische Säge wird aktiviert", - "create.subtitle.schematicannon_finish": "Bauplankanone endet", - "create.subtitle.crafter_craft": "Hersteller stellt her", - "create.subtitle.wrench_remove": "Teil entfernt", - "create.subtitle.train3": "Zugräder grollen dumpf", - "create.subtitle.whistle": "Pfeifen", - "create.subtitle.cogs": "Zahnräder rattern", - "create.subtitle.slime_added": "Schleim matscht", - "create.subtitle.whistle_train_low": "Tiefes Pfeifen", - "create.subtitle.schematicannon_launch_block": "Bauplankanone schießt", - "create.subtitle.controller_take": "Lesepult geleert", - "create.subtitle.crafter_click": "Hersteller klickt", - "create.subtitle.depot_plop": "Gegenstand landet", - "create.subtitle.confirm": "Bestätigendes Klick", - "create.subtitle.mixing": "Mix-Geräusche", - "create.subtitle.mechanical_press_activation_belt": "Mechanische Presse klingt", - "create.subtitle.fwoomp": "Kartoffel-Kanone macht fwumps", - "create.subtitle.sanding_long": "Schleifgeräusche", - "create.subtitle.crushing_1": "Zermahlgeräusche", - "create.subtitle.depot_slide": "Gegenstand gleitet", - "create.subtitle.blaze_munch": "Lohe kaut glücklich", - "create.subtitle.funnel_flap": "Klappe klappert", - "create.subtitle.haunted_bell_use": "Spukglocke läutet", - "create.subtitle.scroll_value": "Klick bei der Bildlauf-Eingabe", - "create.subtitle.controller_put": "Kontroller stößt auf", - "create.subtitle.cranking": "Handkurbel dreht", - "create.subtitle.sanding_short": "Schleifgeräusche", - "create.subtitle.wrench_rotate": "Schraubenschlüssel benutzt", - "create.subtitle.potato_hit": "Gemüse schlägt ein", - "create.subtitle.saw_activate_wood": "Mechanische Säge wird aktiviert", - "create.subtitle.whistle_high": "Hohes Pfeifen", - "create.subtitle.whistle_train_manual_low": "Zug hupt", - "create.subtitle.whistle_train": "Pfeifen", - "create.subtitle.haunted_bell_convert": "Spukglocke erwacht", - "create.subtitle.train": "Zugräder grollen", - "create.subtitle.deny": "Ablehnendes boop", - "create.subtitle.controller_click": "Kontroller klickt", - "create.subtitle.whistle_low": "Tiefes Pfeifen", - "create.subtitle.copper_armor_equip": "Taucherausrüstung klirrt", - "create.subtitle.mechanical_press_activation": "Mechanische Presse wird aktiviert", - "create.subtitle.contraption_assemble": "Apparat bewegt sich", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "BEISPIELGEGENSTAND (nur ein Marker, um zu zeigen, dass dieser Tooltip existiert)", - "item.create.example_item.tooltip.summary": "Eine Kurzbeschreibung eines Gegenstands. _Unterstriche_ heben einen Begriff hervor.", - "item.create.example_item.tooltip.condition1": "Wenn dies", - "item.create.example_item.tooltip.behaviour1": "dann tut dieser Gegenstand das. (Verhalten wird mit der Shift-Taste angezeigt)", - "item.create.example_item.tooltip.condition2": "Und wenn dies", - "item.create.example_item.tooltip.behaviour2": "kannst du so viele Verhaltensweisen hinzufügen wie du magst", - "item.create.example_item.tooltip.control1": "Wenn Strg gedrückt ist", - "item.create.example_item.tooltip.action1": "wird diese Steuerung gezeigt.", - - "block.create.wooden_bracket.tooltip": "Holzhalterung", - "block.create.wooden_bracket.tooltip.summary": "_Verziere_ deine _Wellen_, _Zahnräder_ und _Rohre_ mit einem gemütlichem und hölzernem Stück Verstärkung.", - - "block.create.metal_bracket.tooltip": "Metallhalterung", - "block.create.metal_bracket.tooltip.summary": "_Verziere_ deine _Wellen_, _Zahnräder_ und _Rohre_ mit einem industriellem und robustem Stück Verstärkung.", - - "block.create.seat.tooltip": "Sitz", - "block.create.seat.tooltip.summary": "Setz dich hin und genieße die Fahrt! Der Sitz verankert den Spieler an einem sich bewegendem Apparat. Hervorragend auch für statische Möbel! Kommt in verschiedensten Farben.", - "block.create.seat.tooltip.condition1": "Rechtsklick auf den Sitz", - "block.create.seat.tooltip.behaviour1": "Setzt den Spieler auf den _Sitz_. Drücke L-Shift, um den _Sitz_ wieder zu verlassen.", - - "item.create.blaze_cake.tooltip": "Lohenkuchen", - "item.create.blaze_cake.tooltip.summary": "Ein leckeres Vergnügen für deine hart arbeitenden _Lohenbrenner_. Feuert die alle an!", - - "item.create.wand_of_symmetry.tooltip": "SYMMETRIESTAB", - "item.create.wand_of_symmetry.tooltip.summary": "Spiegelt deine Blockplatzierung perfekt über die konfigurierten Ebenen.", - "item.create.wand_of_symmetry.tooltip.condition1": "Wenn in der Schnellleiste", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Bleibt aktiv", - "item.create.wand_of_symmetry.tooltip.control1": "R-Klick auf Boden", - "item.create.wand_of_symmetry.tooltip.action1": "_Erstellt_ oder _Bewegt_ den Spiegel", - "item.create.wand_of_symmetry.tooltip.control2": "R-Klick in die Luft", - "item.create.wand_of_symmetry.tooltip.action2": "_Löscht_ den aktiven Spiegel", - "item.create.wand_of_symmetry.tooltip.control3": "R-Klick beim Schleichen", - "item.create.wand_of_symmetry.tooltip.action3": "Öffnet das _Konfigurationsmenü_", - - "item.create.handheld_worldshaper.tooltip": "GELÄNDEFORMER", - "item.create.handheld_worldshaper.tooltip.summary": "Cleveres Werkzeug, um _Landschaften_ und _Geländeformen_ zu erschaffen.", - "item.create.handheld_worldshaper.tooltip.control1": "L-Klick einen Block", - "item.create.handheld_worldshaper.tooltip.action1": "Setzt den ausgewählten Block als Block, welcher vom Werkzeug platziert wird.", - "item.create.handheld_worldshaper.tooltip.control2": "R-Klick einen Block", - "item.create.handheld_worldshaper.tooltip.action2": "Nutzt die ausgewählte _Einstellung_ auf den ausgewählten Block.", - "item.create.handheld_worldshaper.tooltip.control3": "R-Klick beim Schleichen", - "item.create.handheld_worldshaper.tooltip.action3": "Öffnet die _Konfigurationsoberfläche_", - - "item.create.tree_fertilizer.tooltip": "BAUMDÜNGER", - "item.create.tree_fertilizer.tooltip.summary": "Eine Mischung aus Mineralien, die sich für weit verbreitete Baumarten eignet", - "item.create.tree_fertilizer.tooltip.condition1": "Wenn auf einen Setzling angewendet", - "item.create.tree_fertilizer.tooltip.behaviour1": "Lässt Bäume unabhängig vom Platz um sie herum wachsen", - - "item.create.extendo_grip.tooltip": "Extendo Griff", - "item.create.extendo_grip.tooltip.summary": "Boioioing! _Erweitert die Reichweite_ des Anwenders enorm. Kann mit Luftdruck eines _kupfernen Rückentanks_ betrieben werden.", - "item.create.extendo_grip.tooltip.condition1": "Wenn in der zweiten Hand", - "item.create.extendo_grip.tooltip.behaviour1": "Erweitert die _maximale Reichweite_ von benutzbaren Gegenständen in der Haupthand.", - "item.create.extendo_grip.tooltip.condition2": "Während ein Kupferner Rückentank ausgerüstet ist", - "item.create.extendo_grip.tooltip.behaviour2": "Es wird _keine_ _Haltbarkeit_ verbraucht. Stattdessen wird _Luftdruck_ vom Tank genutzt", - - "item.create.potato_cannon.tooltip": "KARTOFFELKANONE", - "item.create.potato_cannon.tooltip.summary": "Fwump! Katapultiere dein selbstgewachsenes Gemüse auf deine Feinde. Kann mit Luftdruck eines _kupfernen Rückentanks_ betrieben werden.", - "item.create.potato_cannon.tooltip.condition1": "Wenn R-Klick", - "item.create.potato_cannon.tooltip.behaviour1": "_Schießt_ einen passenden Gegenstand aus deinem _Inventar_.", - "item.create.potato_cannon.tooltip.condition2": "Während ein Kupferner Rückentank ausgerüstet ist", - "item.create.potato_cannon.tooltip.behaviour2": "Es wird _keine_ _Haltbarkeit_ verbraucht. Stattdessen wird _Luftdruck_ vom Tank genutzt", - - "item.create.filter.tooltip": "Filter", - "item.create.filter.tooltip.summary": "_Kontrolliert den Ausgang_ und _Eingang_ eines logistischen Gerätes mit höherer Genauigkeit und vergleicht ein _Set von Gegenständen_ oder _vernetzten Filtern_.", - "item.create.filter.tooltip.condition1": "Wenn in gefiltertem Anzeigeplatz", - "item.create.filter.tooltip.behaviour1": "_Kontrolliert_ den Gegenstandsfluss basierend auf seiner _Konfiguration_.", - "item.create.filter.tooltip.condition2": "Wenn R-Klick", - "item.create.filter.tooltip.behaviour2": "Öffnet die _Konfigurationsoberfläche_.", - - "item.create.attribute_filter.tooltip": "Attribut Filter", - "item.create.attribute_filter.tooltip.summary": "_Kontrolliert den Ausgang_ und _Eingang_ eines logistischen Gerätes mit höherer Genauigkeit und vergleicht ein _Set von Gegenstands-Attributen_ und _-Kategorien_.", - "item.create.attribute_filter.tooltip.condition1": "Wenn in gefiltertem Anzeigeplatz", - "item.create.attribute_filter.tooltip.behaviour1": "_Kontrolliert_ den Gegenstandsfluss basierend auf seiner _Konfiguration_.", - "item.create.attribute_filter.tooltip.condition2": "Wenn R-Klick", - "item.create.attribute_filter.tooltip.behaviour2": "Öffnet die _Konfigurationsoberfläche_.", - - "item.create.empty_schematic.tooltip": "LEERER BAUPLAN", - "item.create.empty_schematic.tooltip.summary": "Wird für die Herstellung und das Schreiben auf dem _Bauplantisch_ verwendet", - - "item.create.schematic.tooltip": "BAUPLAN", - "item.create.schematic.tooltip.summary": "Beschreibt eine Struktur, die in der Welt platziert werden kann. Positioniere das Hologramm wie gewünscht und verwende eine _Bauplankanone_, um die Struktur zu bauen.", - "item.create.schematic.tooltip.condition1": "Wenn gehalten", - "item.create.schematic.tooltip.behaviour1": "Kann mit den Werkzeugen auf dem Bildschirm positioniert werden", - "item.create.schematic.tooltip.control1": "R-Klick beim Schleichen", - "item.create.schematic.tooltip.action1": "Öffnet ein Menü zur Eingabe exakter _Koordinaten_.", - - "item.create.schematic_and_quill.tooltip": "BAUPLAN UND FEDER", - "item.create.schematic_and_quill.tooltip.summary": "Wird benutzt, um eine existierende Struktur in der Welt als eine .nbt-Datei zu speichern.", - "item.create.schematic_and_quill.tooltip.condition1": "Schritt 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Wähle zwei Eckpunkte mit R-Klick aus", - "item.create.schematic_and_quill.tooltip.condition2": "Schritt 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "Auf den Oberflächen _Strg-Scrollen_ um die Größe zu verändern. Nochmals R-Klick um zu speichern.", - "item.create.schematic_and_quill.tooltip.control1": "R-Klick", - "item.create.schematic_and_quill.tooltip.action1": "Einen Eckpunkt auswählen / Speichern bestätigen", - "item.create.schematic_and_quill.tooltip.control2": "Strg gedrückt halten", - "item.create.schematic_and_quill.tooltip.action2": "Wählt Punkte _mitten_ _in_ _der_ _Luft._ _Scrolle,_ um die Distanz anzupassen.", - "item.create.schematic_and_quill.tooltip.control3": "R-Klick beim Schleichen", - "item.create.schematic_and_quill.tooltip.action3": "_Setzt_ die Auswahl _zurück_ und löscht sie.", - - "block.create.schematicannon.tooltip": "BAUPLANKANONE", - "block.create.schematicannon.tooltip.summary": "Schießt Blöcke, um eine Struktur nach einem positionierten _Bauplan_ zu errichten. Benutzt Gegenstände aus benachbarten Inventaren und _Schießpulver_ als Treibstoff.", - "block.create.schematicannon.tooltip.condition1": "Wenn gerechtsklickt", - "block.create.schematicannon.tooltip.behaviour1": "Öffnet das _Interface_", - - "block.create.schematic_table.tooltip": "BAUPLANTISCH", - "block.create.schematic_table.tooltip.summary": "Schreibt gespeicherte Baupläne auf einen _Leeren_ _Bauplan_", - "block.create.schematic_table.tooltip.condition1": "Wenn ein Leerer Bauplan bereitgestellt wird", - "block.create.schematic_table.tooltip.behaviour1": "Lädt eine ausgewählte Datei von deinem Bauplan-Ordner hoch", - - "item.create.goggles.tooltip": "Ingenieursbrille", - "item.create.goggles.tooltip.summary": "Eine Brille, welche _Informationen_ zur _Kinetik_ eines Blocks zeigt.", - "item.create.goggles.tooltip.condition1": "Wenn getragen", - "item.create.goggles.tooltip.behaviour1": "Zeigt _farbige Indikatoren_ basieren auf dem _Geschwindigkeitslevel_ einer platzierten kinetischen Komponente. Auch der _Stresslevel_ und die _Kapazität_ bestimmter Komponenten werden angezeigt.", - "item.create.goggles.tooltip.condition2": "Wenn auf ein Messgerät geschaut wird", - "item.create.goggles.tooltip.behaviour2": "Zeigt detaillierte Informationen über _Geschwindigkeit_ oder _Stress_ des Netzes an, mit dem das Messgerät verbunden ist.", - "item.create.goggles.tooltip.condition3": "Wenn auf einen Flüssigkeitsbehälter geschaut wird", - "item.create.goggles.tooltip.behaviour3": "Zeigt detaillierte Informationen zur _Kapazität_ des Blocks und welche _Flüssigkeit_ darin aufbewahrt wird.", - - "item.create.wrench.tooltip": "SCHRAUBENSCHLÜSSEL", - "item.create.wrench.tooltip.summary": "Ein nützliches Werkzeug, um mit kinetischen Vorrichtungen zu arbeiten. Kann benutzt werden, um Komponenten zu _rotieren_, _zerlegen_ und sie zu _konfigurieren_.", - "item.create.wrench.tooltip.control1": "R-Klick einen kinetischen Block", - "item.create.wrench.tooltip.action1": "_Rotiert Komponenten_ in Richtung oder weg von der Fläche, mit der du mit ihr interagiert hast.", - "item.create.wrench.tooltip.control2": "R-Klick beim Schleichen", - "item.create.wrench.tooltip.action2": "_Nimmt kinetische Komponenten auseinander_ und platziert sie zurück in _dein Inventar_.", - - "block.create.nozzle.tooltip": "DÜSE", - "block.create.nozzle.tooltip.summary": "Wird an der Vorderseite eines _ummantelnden Lüfters_ angebracht, um seine Wirkung auf Entitäten in _alle Richtungen_ zu verteilen.", - - "block.create.cuckoo_clock.tooltip": "KUCKUCKSUHR", - "block.create.cuckoo_clock.tooltip.summary": "Feine Handwerkskunst, um einen Raum zu _dekorieren_ und _die Zeit im Auge zu behalten_.", - "block.create.cuckoo_clock.tooltip.condition1": "Wenn kinetisch angetrieben", - "block.create.cuckoo_clock.tooltip.behaviour1": "Zeigt die _aktuelle Zeit_ und spielt zweimal täglich eine Melodie. Wird einmal _mittags_ und einmal zur _Dämmerung_, sobald _Spieler schlafen können_, aktiviert", - - "block.create.turntable.tooltip": "DREHTISCH", - "block.create.turntable.tooltip.summary": "Wandelt _Rotationsenergie_ in starkes Schwindelgefühl um.", - - "block.create.toolbox.tooltip": "WERKZEUGKASTEN", - "block.create.toolbox.tooltip.summary": "Der liebste Begleiter jedes Erfinders. Praktischerweise _behält_ der Werkzeugkasten eine große Menge von _8 verschiedenen_ Gegenstandstypen.", - "block.create.toolbox.tooltip.condition1": "Wenn augehoben", - "block.create.toolbox.tooltip.behaviour1": "Behält _Inhalt_ des _Inventars_.", - "block.create.toolbox.tooltip.condition2": "Wenn in Reichweite platziert", - "block.create.toolbox.tooltip.behaviour2": "_Spieler_ in der _Nähe_ können die _Taste_ für den _Werkzeugkasten_ drücken, um einen Fernzugriff auf den Inhalt zu bekommen.", - "block.create.toolbox.tooltip.condition3": "Wenn R-Klick", - "block.create.toolbox.tooltip.behaviour3": "Öffnet die _Behälteroberfläche_", - - "block.create.stockpile_switch.tooltip": "VORRATSSENSOR", - "block.create.stockpile_switch.tooltip.summary": "Schaltet ein Redstone-Signal ein oder aus, basierend auf der _Speichermenge_ im verbundenen Behälter.", - "block.create.stockpile_switch.tooltip.condition1": "Wenn unter dem unteren Limit", - "block.create.stockpile_switch.tooltip.behaviour1": "Wird das Redstone-Signal ausgeschaltet.", - - "block.create.content_observer.tooltip": "INHALTSBEOBACHTER", - "block.create.content_observer.tooltip.summary": "_Erkennt Gegenstände_ oder _Flüssigkeiten_ in einem _Behälter_, einer _Röhre_ oder einem _Fließband_, die zum eingestellten _Filter_ passen.", - "block.create.content_observer.tooltip.condition1": "Bei der Beobachtung eines Containers", - "block.create.content_observer.tooltip.behaviour1": "Gibt einen _Redstone-Puls_ aus, während der beobachtete Behälter _passenden_ _Inhalt_ hat.", - "block.create.content_observer.tooltip.condition2": "Bei der Beobachtung eines Trichters", - "block.create.content_observer.tooltip.behaviour2": "Gibt einen _Redstone-Puls_ aus, wenn ein _passender_ Gegenstand _übertragen_ wird.", - - "block.create.creative_crate.tooltip": "BAUPLANKANONENMACHER", - "block.create.creative_crate.tooltip.summary": "Stellt einen unendlichen Vorrat an Blöcken für benachbarte _Bauplaenkanonen_ bereit.", - "block.create.creative_crate.tooltip.condition1": "Wenn Gegenstand in Filter Slot", - "block.create.creative_crate.tooltip.behaviour1": "Alles _extrahierende_ von diesem Container wird einen _endlosen Vorrat_ des angegebenen Gegenstands zur Verfügung stellen. In diese Kiste _eingefügte_ Gegenstände werden _entsorgt_.", - - "item.create.creative_blaze_cake.tooltip": "KREATIVER KUCHEN", - "item.create.creative_blaze_cake.tooltip.summary": "Eine sehr spezielle Behandlung, welche es erlaubt, des _Lohenbrenners_ _Hitzelevel einzustellen_. After eating this cake, Blaze Burners will _never run out of fuel_.", - "item.create.creative_blaze_cake.tooltip.condition1": "R-Klick auf einen _Lohenbrenner_", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Rastet_ das Hitzelevel des Lohenbrenners _ein_. Wenn nochmal angewandt wird, _zirkuliert_ der Lohenbrenner sein Hitzelevel.", - - "block.create.controller_rail.tooltip": "STEUERUNGSSCHIENE", - "block.create.controller_rail.tooltip.summary": "Eine _einseitige Antriebsschiene_, welche fähig ist, die _Geschwindigkeit_ von Loren _sehr genau_ einzustellen.", - "block.create.controller_rail.tooltip.condition1": "Wenn mit Redstone aktiviert", - "block.create.controller_rail.tooltip.behaviour1": "_Verschnellert_ oder _verlangsamt_ vorbeifahrende Loren basierend auf der _Signalstärke_. Überträgt Redstone-Energie auf benachbarte Steuerungsschienen. Wenn zwei Steuerungsschienen mit unterschiedlicher Signalstärke versorgt werden, interpolieren die Schienen zwischen ihnen ihr Signal.", - - "item.create.sand_paper.tooltip": "SCHMIRGELPAPIER", - "item.create.sand_paper.tooltip.summary": "Ein raues papier, welches benutzt wird, um _Materialien_ zu _polieren_. Kann automatisch von einem Einsatzgerät benutzt werden.", - "item.create.sand_paper.tooltip.condition1": "Wenn benutzt", - "item.create.sand_paper.tooltip.behaviour1": "Gibt den Gegenständen in der _Zweithand_ oder auf dem _Boden_, welches du _anguckst_, eine Politur.", - - "item.create.builders_tea.tooltip": "Baumeister-Tee", - "item.create.builders_tea.tooltip.summary": "Das perfekte Getränk, um den Tag zu starten - _Motivierend_ und _sättigend_.", - - "item.create.refined_radiance.tooltip": "RAFFINIERTER GLANZ", - "item.create.refined_radiance.tooltip.summary": "Ein chromatisches Material, das aus _absorbiertem Licht_ geschmiedet wird.", - "item.create.refined_radiance.tooltip.condition1": "In Arbeit", - "item.create.refined_radiance.tooltip.behaviour1": "Verwendungen für dieses Material werden in zukünftigen Versionen verfügbar sein.", - - "item.create.shadow_steel.tooltip": "SCHATTENSTAHL", - "item.create.shadow_steel.tooltip.summary": "Ein chromatisches Material, das _in der Leere_ geschmiedet wird.", - "item.create.shadow_steel.tooltip.condition1": "In Arbeit", - "item.create.shadow_steel.tooltip.behaviour1": "Verwendungen für dieses Material werden in zukünftigen Versionen verfügbar sein.", - - "item.create.linked_controller.tooltip": "VERBUNDENER KONTROLLER", - "item.create.linked_controller.tooltip.summary": "Erlaubt _händische_ _Kontrolle_ über _Redstone-Verbindungs-Frequenzen_, welche auf ihre _sechs_ _Knöpfe_ gebunden sind.", - "item.create.linked_controller.tooltip.condition1": "R-Klick", - "item.create.linked_controller.tooltip.behaviour1": "_Schaltet_ den Kontroller _um_. _Bewegungssteuerung_ wird übernommen, solange der Kontroller aktiv ist.", - "item.create.linked_controller.tooltip.condition2": "R-Klick beim Schleichen", - "item.create.linked_controller.tooltip.behaviour2": "Öffnet das Handbuch _Konfigurationsoberfläche_.", - "item.create.linked_controller.tooltip.condition3": "R-Klick auf einen Redstone-Verbindungs-Empfänger", - "item.create.linked_controller.tooltip.behaviour3": "Aktiviert den _Bindungsmodus_. Drücke einen der _sechs Einstellungen_, um sie auf die _Verbindungsfrequenz_ zu binden.", - "item.create.linked_controller.tooltip.condition4": "R-Klick auf ein Lesepult", - "item.create.linked_controller.tooltip.behaviour4": "Platziert einen Kontroller in das Lesepult, um es einfacher zu aktivieren. (R-Klick beim Schleichen, um es zurück zu nehmen)", - - "item.create.diving_helmet.tooltip": "TAUCHHELM", - "item.create.diving_helmet.tooltip.summary": "Mit einem _kupfernen_ _Rückentank_ kombiniert erlaubt es dem Anwender, _unter Wasser_ länger _atmen_ zu können.", - "item.create.diving_helmet.tooltip.condition1": "Wenn getragen", - "item.create.diving_helmet.tooltip.behaviour1": "Gibt den _Wasseratmungs-Effekt_, für welchen langsam _Luftdruck_ aus dem Rückentank gezogen wird.", - - "item.create.copper_backtank.tooltip": "KUPFERNER RÜCKENTANK", - "item.create.copper_backtank.tooltip.summary": "Ein _tragbarer_ _Tank_, um komprimierte Luft aufzubewahren.", - "item.create.copper_backtank.tooltip.condition1": "Wenn getragen", - "item.create.copper_backtank.tooltip.behaviour1": "Stellt _komprimierte_ _Luft_ für Ausrüstung zur Verfügung, welche es braucht.", - "item.create.copper_backtank.tooltip.condition2": "Wenn platziert und mit kinetischer Energie betrieben", - "item.create.copper_backtank.tooltip.behaviour2": "_Sammelt_ _komprimierte_ _Luft_ mit einer Geschwindigkeit basierend auf der Rotationsgeschwindigkeit.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "TAUCHSCHUHE", - "item.create.diving_boots.tooltip.summary": "Ein Paar _schwere_ _Schuhe_, welches es erlaubt, besser auf dem Grund des Ozenas zu reisen.", - "item.create.diving_boots.tooltip.condition1": "Wenn getragen", - "item.create.diving_boots.tooltip.behaviour1": "Anwender _sinkt_ _schneller_ und _kann nicht_ _schwimmen_. Gibt die Möglichkeit, unter Wasser zu _laufen_ und zu _springen_. Anwender wird auch nicht mehr von _mechanischen_ _Riemen_ beeinflusst.", - - "item.create.crafting_blueprint.tooltip": "HERSTELLUNGSBLAUPAUSE", - "item.create.crafting_blueprint.tooltip.summary": "Wird es auf eine Wand _platziert_, kann es genutzt werden, um _Zutatenanordnung_ für leichtere manuelle Herstellung zu _spezifizieren_. Jeder Anzeigeplatz steht für ein Rezept.", - "item.create.crafting_blueprint.condition1": "R-Klick leeren Anzeigeplatz", - "item.create.crafting_blueprint.behaviour1": "Öffnet ein _Herstellungsmenü_, damit du ein _Rezept_ _konfigurieren_ und Gegenstände darstellen kannst.", - "item.create.crafting_blueprint.condition2": "R-Klick konfigurierten Anzeigeplatz", - "item.create.crafting_blueprint.behaviour2": "Wendet das _konfigurierte_ _Rezept_ mit den passenden Zutaten aus deinem _Inventar_ an. _Schleiche_, um bis zu einem _Stapel_ von Gegenständen herzustellen.", - - "item.create.minecart_coupling.tooltip": "LORENKUPPLUNG", - "item.create.minecart_coupling.tooltip.summary": "_Verkettet_ all deine _Loren_ oder _Karosseriebauwerke_, um einen majestätischen Zug zu formen.", - "item.create.minecart_coupling.tooltip.condition1": "Wenn auf eine Lore benutzt wird", - "item.create.minecart_coupling.tooltip.behaviour1": "Koppelt zwei Loren zusammen und versucht, sie während der Bewegung auf einem _konstanten Abstand_ zu halten.", - - "item.create.experience_nugget.tooltip": "ERFAHRUNGSKLUMPEN", - "item.create.experience_nugget.tooltip.summary": "_Ding!_ Ein Stückchen _Inspiration_ von Ihren fantastischen Erfindungen.", - "item.create.experience_nugget.tooltip.condition1": "Wenn benutzt", - "item.create.experience_nugget.tooltip.behaviour1": "_Löst_ alle _Erfahrungspunkte_ ein, welche darin gespeichert sind.", - - "block.create.peculiar_bell.tooltip": "SELTSAME GLOCKE", - "block.create.peculiar_bell.tooltip.summary": "Eine dekorative _Messingglocke_. Über einem Seelenfeuer platziert, könnte es Nebenwirkungen haben...", - - "block.create.haunted_bell.tooltip": "SPUKGLOCKE", - "block.create.haunted_bell.tooltip.summary": "Eine _verfluchte Glocke_ der verlorenen Seelen aus dem Nether.", - "block.create.haunted_bell.tooltip.condition1": "Wenn getragen oder geläutet wird", - "block.create.haunted_bell.tooltip.behaviour1": "Hebt nahe _lichtlose Stellen_ hervor, auf welchen _feindliche Kreaturen_ laichen können.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", - "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", - "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", - "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", - "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", - "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Super Glue, larger structures can be moved.", - "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", - "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", - "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", - "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", - "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", - "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", - "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", - "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", - "create.ponder.tag.windmill_sails": "UNLOCALIZED: Sails for Windmill Bearings", - "create.ponder.tag.windmill_sails.description": "UNLOCALIZED: Blocks that count towards the strength of a Windmill Contraption when assembled. Each of these have equal efficiency in doing so.", - "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", - "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", - "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", - "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", - "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", - "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", - "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", - "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", - "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", - "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", - "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", - "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", - "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", - "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", - "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", - "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", - "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", - "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", - - "create.ponder.andesite_tunnel.header": "UNLOCALIZED: Using Andesite Tunnels", - "create.ponder.andesite_tunnel.text_1": "UNLOCALIZED: Andesite Tunnels can be used to cover up your belts", - "create.ponder.andesite_tunnel.text_2": "UNLOCALIZED: Whenever an Andesite Tunnel has connections to the sides...", - "create.ponder.andesite_tunnel.text_3": "UNLOCALIZED: ...they will split exactly one item off of any passing stacks", - "create.ponder.andesite_tunnel.text_4": "UNLOCALIZED: The remainder will continue on its path", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "UNLOCALIZED: Processing Items in the Basin", - "create.ponder.basin.text_1": "UNLOCALIZED: A Basin can hold Items and Fluids for Processing", - "create.ponder.basin.text_2": "UNLOCALIZED: After a processing step, basins try to output below to the side of them", - "create.ponder.basin.text_3": "UNLOCALIZED: When a valid component is present, the Basin will show an output faucet", - "create.ponder.basin.text_4": "UNLOCALIZED: A number of options are applicable here", - "create.ponder.basin.text_5": "UNLOCALIZED: Outputs will be caught by the inventory below", - "create.ponder.basin.text_6": "UNLOCALIZED: Without output faucet, the Basin will retain items created in its processing", - "create.ponder.basin.text_7": "UNLOCALIZED: This can be useful if outputs should be re-used as ingredients", - "create.ponder.basin.text_8": "UNLOCALIZED: Desired outputs will then have to be extracted from the basin", - "create.ponder.basin.text_9": "UNLOCALIZED: A Filter might be necessary to avoid pulling out un-processed items", - - "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", - "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", - "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", - - "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", - "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", - "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", - - "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", - "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", - "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", - "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", - "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", - "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", - "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", - - "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", - "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", - "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", - "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", - "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", - "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", - "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions. Belts can span any Length between 2 and 20 blocks", - - "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", - "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", - "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", - - "create.ponder.blaze_burner.header": "UNLOCALIZED: Feeding Blaze Burners", - "create.ponder.blaze_burner.text_1": "UNLOCALIZED: Blaze Burners can provide Heat to Items processed in a Basin", - "create.ponder.blaze_burner.text_2": "UNLOCALIZED: For this, the Blaze has to be fed with flammable items", - "create.ponder.blaze_burner.text_3": "UNLOCALIZED: With a Blaze Cake, the Burner can reach an even stronger level of heat", - "create.ponder.blaze_burner.text_4": "UNLOCALIZED: The feeding process can be automated using Deployers or Mechanical Arms", - - "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", - "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", - "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", - "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", - - "create.ponder.brass_tunnel.header": "UNLOCALIZED: Using Brass Tunnels", - "create.ponder.brass_tunnel.text_1": "UNLOCALIZED: Brass Tunnels can be used to cover up your belts", - "create.ponder.brass_tunnel.text_2": "UNLOCALIZED: Brass Tunnels have filter slots on each open side", - "create.ponder.brass_tunnel.text_3": "UNLOCALIZED: Filters on inbound connections simply block non-matching items", - "create.ponder.brass_tunnel.text_4": "UNLOCALIZED: Filters on outbound connections can be used to sort items by type", - "create.ponder.brass_tunnel.text_5": "UNLOCALIZED: Whenever a passing item has multiple valid exits, the distribution mode will decide how to handle it", - "create.ponder.brass_tunnel.text_6": "UNLOCALIZED: Brass Tunnels on parallel belts will form a group", - "create.ponder.brass_tunnel.text_7": "UNLOCALIZED: Incoming Items will now be distributed across all connected exits", - "create.ponder.brass_tunnel.text_8": "UNLOCALIZED: For this, items can also be inserted into the Tunnel block directly", - - "create.ponder.brass_tunnel_modes.header": "UNLOCALIZED: Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "UNLOCALIZED: Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", - "create.ponder.brass_tunnel_modes.text_10": "UNLOCALIZED: 'Synchronize Inputs' is a unique setting for Brass Tunnels", - "create.ponder.brass_tunnel_modes.text_11": "UNLOCALIZED: Items are only allowed past if every tunnel in the group has one waiting", - "create.ponder.brass_tunnel_modes.text_12": "UNLOCALIZED: This ensures that all affected belts supply items at the same rate", - "create.ponder.brass_tunnel_modes.text_2": "UNLOCALIZED: 'Split' will attempt to distribute the stack evenly between available outputs", - "create.ponder.brass_tunnel_modes.text_3": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_4": "UNLOCALIZED: 'Forced Split' will never skip outputs, and instead wait until they are free", - "create.ponder.brass_tunnel_modes.text_5": "UNLOCALIZED: 'Round Robin' keeps stacks whole, and cycles through outputs iteratively", - "create.ponder.brass_tunnel_modes.text_6": "UNLOCALIZED: Once Again, if an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_7": "UNLOCALIZED: 'Forced Round Robin' never skips outputs", - "create.ponder.brass_tunnel_modes.text_8": "UNLOCALIZED: 'Prefer Nearest' prioritizes the outputs closest to the items' input location", - "create.ponder.brass_tunnel_modes.text_9": "UNLOCALIZED: 'Randomize' will distribute whole stacks to randomly picked outputs", - - "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", - "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", - "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", - "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", - - "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", - "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", - "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", - "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", - - "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", - "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", - "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: This Arrow indicates which side of the Structure will be considered the front", - "create.ponder.cart_assembler_modes.text_3": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", - - "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", - "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", - "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", - "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", - "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", - - "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", - "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", - "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", - "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", - - "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", - "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exactly like Chain Drives", - "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", - "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", - "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", - "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", - "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", - - "create.ponder.chute.header": "UNLOCALIZED: Transporting Items downward via Chutes", - "create.ponder.chute.text_1": "UNLOCALIZED: Chutes can transport items vertically from and to inventories", - "create.ponder.chute.text_2": "UNLOCALIZED: Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "UNLOCALIZED: Placing chutes targeting the side faces of another will make it diagonal", - - "create.ponder.chute_upward.header": "UNLOCALIZED: Transporting Items upward via Chutes", - "create.ponder.chute_upward.text_1": "UNLOCALIZED: Using Encased Fans at the top or bottom, a Chute can move items upward", - "create.ponder.chute_upward.text_2": "UNLOCALIZED: Inspecting chutes with Engineers' Goggles reveals information about the movement direction", - "create.ponder.chute_upward.text_3": "UNLOCALIZED: On the 'blocked' end, items will have to be inserted/taken from the sides", - - "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", - "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", - "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", - "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", - "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", - "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", - "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", - "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure that the two Structures are not glued to each other", - "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", - - "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", - "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", - "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", - - "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", - "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", - "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", - "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", - - "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", - "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", - "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "UNLOCALIZED: Creative Fluid Tanks", - "create.ponder.creative_fluid_tank.text_1": "UNLOCALIZED: Creative Fluid Tanks can be used to provide a bottomless supply of fluid", - "create.ponder.creative_fluid_tank.text_2": "UNLOCALIZED: Right-Click with a fluid containing item to configure it", - "create.ponder.creative_fluid_tank.text_3": "UNLOCALIZED: Pipe Networks can now endlessly draw the assigned fluid from the tank", - "create.ponder.creative_fluid_tank.text_4": "UNLOCALIZED: Any Fluids pushed back into a Creative Fluid Tank will be voided", - - "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", - "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "UNLOCALIZED: Processing Items with Crushing Wheels", - "create.ponder.crushing_wheels.text_1": "UNLOCALIZED: A pair of Crushing Wheels can grind items very effectively", - "create.ponder.crushing_wheels.text_2": "UNLOCALIZED: Their Rotational Input has to make them spin into each other", - "create.ponder.crushing_wheels.text_3": "UNLOCALIZED: Items thrown or inserted into the top will get processed", - "create.ponder.crushing_wheels.text_4": "UNLOCALIZED: Items can be inserted and picked up through automated means as well", - - "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", - "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", - "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", - "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", - "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", - "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", - "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", - "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", - "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", - "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", - "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", - "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", - "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", - "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", - "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", - "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", - - "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", - "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", - "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", - "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", - - "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", - "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", - "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", - - "create.ponder.deployer_processing.header": "UNLOCALIZED: Processing Items using Deployers", - "create.ponder.deployer_processing.text_1": "UNLOCALIZED: With a fitting held item, Deployers can process items provided beneath them", - "create.ponder.deployer_processing.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Deployer", - "create.ponder.deployer_processing.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.deployer_processing.text_4": "UNLOCALIZED: The Deployer will hold and process them automatically", - - "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", - "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", - "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", - "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.depot.header": "UNLOCALIZED: Using Depots", - "create.ponder.depot.text_1": "UNLOCALIZED: Depots can serve as 'stationary' belt elements", - "create.ponder.depot.text_2": "UNLOCALIZED: Right-Click to manually place or remove Items from it", - "create.ponder.depot.text_3": "UNLOCALIZED: Just like Mechanical Belts, it can provide items to processing", - "create.ponder.depot.text_4": "UNLOCALIZED: ...as well as provide Items to Mechanical Arms", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "UNLOCALIZED: Using Empty Blaze Burners", - "create.ponder.empty_blaze_burner.text_1": "UNLOCALIZED: Right-click a Blaze with the empty burner to capture it", - "create.ponder.empty_blaze_burner.text_2": "UNLOCALIZED: Alternatively, Blazes can be collected from their Spawners directly", - "create.ponder.empty_blaze_burner.text_3": "UNLOCALIZED: You now have an ideal heat source for various machines", - "create.ponder.empty_blaze_burner.text_4": "UNLOCALIZED: For Aesthetic purposes, Empty Blaze Burners can also be lit using Flint and Steel", - "create.ponder.empty_blaze_burner.text_5": "UNLOCALIZED: The flame can be transformed using a soul-infused item", - "create.ponder.empty_blaze_burner.text_6": "UNLOCALIZED: However, without a blaze they are not suitable for industrial heating", - - "create.ponder.encased_fluid_pipe.header": "UNLOCALIZED: Encasing Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_1": "UNLOCALIZED: Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "UNLOCALIZED: Aside from being conceiled, Encased Pipes are locked into their connectivity state", - "create.ponder.encased_fluid_pipe.text_3": "UNLOCALIZED: It will no longer react to any neighbouring blocks being added or removed", - - "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", - "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", - - "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", - "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", - "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", - "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", - "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", - "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", - "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", - "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", - - "create.ponder.fluid_pipe_flow.header": "UNLOCALIZED: Moving Fluids using Copper Pipes", - "create.ponder.fluid_pipe_flow.text_1": "UNLOCALIZED: Fluid Pipes can connect two or more fluid sources and targets", - "create.ponder.fluid_pipe_flow.text_2": "UNLOCALIZED: Using a wrench, a straight pipe segment can be given a window", - "create.ponder.fluid_pipe_flow.text_3": "UNLOCALIZED: Windowed pipes will not connect to any other adjacent pipe segments", - "create.ponder.fluid_pipe_flow.text_4": "UNLOCALIZED: Powered by Mechanical Pumps, the Pipes can transport Fluids", - "create.ponder.fluid_pipe_flow.text_5": "UNLOCALIZED: No fluid is being extracted at first", - "create.ponder.fluid_pipe_flow.text_6": "UNLOCALIZED: Once the flow connects them, the endpoints gradually transfer their contents", - "create.ponder.fluid_pipe_flow.text_7": "UNLOCALIZED: Thus, the Pipe blocks themselves never 'physically' contain any fluid", - - "create.ponder.fluid_pipe_interaction.header": "UNLOCALIZED: Draining and Filling fluid containers", - "create.ponder.fluid_pipe_interaction.text_1": "UNLOCALIZED: Endpoints of a pipe network can interact with a variety of blocks", - "create.ponder.fluid_pipe_interaction.text_2": "UNLOCALIZED: Any block with fluid storage capabilities can be filled or drained", - "create.ponder.fluid_pipe_interaction.text_3": "UNLOCALIZED: Source blocks right in front of an open end can be picked up...", - "create.ponder.fluid_pipe_interaction.text_4": "UNLOCALIZED: ...while spilling into empty spaces can create fluid sources", - "create.ponder.fluid_pipe_interaction.text_5": "UNLOCALIZED: Pipes can also extract fluids from a handful of other blocks directly", - - "create.ponder.fluid_tank_sizes.header": "UNLOCALIZED: Dimensions of a Fluid tank", - "create.ponder.fluid_tank_sizes.text_1": "UNLOCALIZED: Fluid Tanks can be combined to increase the total capacity", - "create.ponder.fluid_tank_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.fluid_tank_sizes.text_3": "UNLOCALIZED: ...and grow in height by more than 30 additional layers", - "create.ponder.fluid_tank_sizes.text_4": "UNLOCALIZED: Using a Wrench, a tanks' window can be toggled", - - "create.ponder.fluid_tank_storage.header": "UNLOCALIZED: Storing Fluids in Fluid Tanks", - "create.ponder.fluid_tank_storage.text_1": "UNLOCALIZED: Fluid Tanks can be used to store large amounts of fluid", - "create.ponder.fluid_tank_storage.text_2": "UNLOCALIZED: Pipe networks can push and pull fluids from any side", - "create.ponder.fluid_tank_storage.text_3": "UNLOCALIZED: The contained fluid can be measured by a Comparator", - "create.ponder.fluid_tank_storage.text_4": "UNLOCALIZED: However, in Survival Mode Fluids cannot be added or taken manually", - "create.ponder.fluid_tank_storage.text_5": "UNLOCALIZED: You can use Basins, Item Drains and Spouts to drain or fill fluid containing items", - - "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", - "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", - "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", - "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", - "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", - - "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", - "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", - "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", - "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", - "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", - "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", - - "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", - "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", - - "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", - "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting", - - "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", - "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", - "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", - "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement. A mechanical belt should help here.", - - "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", - "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", - "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", - "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", - "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", - "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", - - "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", - "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", - "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", - "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", - "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", - - "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", - "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", - "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", - - "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", - "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", - "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", - "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", - "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", - "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", - "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", - - "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", - "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", - "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", - - "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", - "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", - "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - - "create.ponder.hose_pulley.header": "UNLOCALIZED: Source Filling and Draining using Hose Pulleys", - "create.ponder.hose_pulley.text_1": "UNLOCALIZED: Hose Pulleys can be used to fill or drain large bodies of Fluid", - "create.ponder.hose_pulley.text_2": "UNLOCALIZED: With the Kinetic Input, the height of the pulleys' hose can be controlled", - "create.ponder.hose_pulley.text_3": "UNLOCALIZED: The Pulley retracts while the input rotation is inverted", - "create.ponder.hose_pulley.text_4": "UNLOCALIZED: On the opposite side, pipes can be connected", - "create.ponder.hose_pulley.text_5": "UNLOCALIZED: Attached pipe networks can either provide fluid to the hose...", - "create.ponder.hose_pulley.text_6": "UNLOCALIZED: ...or pull from it, draining the pool instead", - "create.ponder.hose_pulley.text_7": "UNLOCALIZED: Fill and Drain speed of the pulley depends entirely on the fluid networks' throughput", - - "create.ponder.hose_pulley_infinite.header": "UNLOCALIZED: Passively Filling and Draining large bodies of Fluid", - "create.ponder.hose_pulley_infinite.text_1": "UNLOCALIZED: When deploying the Hose Pulley into a large enough ocean...", - "create.ponder.hose_pulley_infinite.text_2": "UNLOCALIZED: It will provide/dispose fluids without affecting the source", - "create.ponder.hose_pulley_infinite.text_3": "UNLOCALIZED: Pipe networks can limitlessly take fluids from/to such pulleys", - - "create.ponder.hose_pulley_level.header": "UNLOCALIZED: Fill and Drain level of Hose Pulleys", - "create.ponder.hose_pulley_level.text_1": "UNLOCALIZED: While fully retracted, the Hose Pulley cannot operate", - "create.ponder.hose_pulley_level.text_2": "UNLOCALIZED: Draining runs from top to bottom", - "create.ponder.hose_pulley_level.text_3": "UNLOCALIZED: The surface level will end up just below where the hose ends", - "create.ponder.hose_pulley_level.text_4": "UNLOCALIZED: Filling runs from bottom to top", - "create.ponder.hose_pulley_level.text_5": "UNLOCALIZED: The filled pool will not grow beyond the layer above the hose end", - - "create.ponder.item_drain.header": "UNLOCALIZED: Emptying Fluid Containers using Item Drains", - "create.ponder.item_drain.text_1": "UNLOCALIZED: Item Drains can extract fluids from items", - "create.ponder.item_drain.text_2": "UNLOCALIZED: Right-click it to pour fluids from your held item into it", - "create.ponder.item_drain.text_3": "UNLOCALIZED: When items are inserted from the side...", - "create.ponder.item_drain.text_4": "UNLOCALIZED: ...they roll across, emptying out their contained fluid", - "create.ponder.item_drain.text_5": "UNLOCALIZED: Pipe Networks can now pull the fluid from the drains' internal buffer", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", - "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", - "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", - - "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", - "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", - "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", - "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", - "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", - "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", - - "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "UNLOCALIZED: Setting up Mechanical Arms", - "create.ponder.mechanical_arm.text_1": "UNLOCALIZED: Mechanical Arms have to be assigned their in- and outputs before they are placed", - "create.ponder.mechanical_arm.text_2": "UNLOCALIZED: Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "UNLOCALIZED: Right-Click again to toggle between Input (Blue) and Output (Orange)", - "create.ponder.mechanical_arm.text_4": "UNLOCALIZED: Left-Click components to remove their Selection", - "create.ponder.mechanical_arm.text_5": "UNLOCALIZED: Once placed, the Mechanical Arm will target the blocks selected previously", - "create.ponder.mechanical_arm.text_6": "UNLOCALIZED: They can have any amount of in- and outputs within their range", - "create.ponder.mechanical_arm.text_7": "UNLOCALIZED: However, not every type of Inventory can be interacted with directly", - "create.ponder.mechanical_arm.text_8": "UNLOCALIZED: Funnels and Depots can help to Bridge that gap", - - "create.ponder.mechanical_arm_filtering.header": "UNLOCALIZED: Filtering Outputs of the Mechanical Arm", - "create.ponder.mechanical_arm_filtering.text_1": "UNLOCALIZED: Inputs", - "create.ponder.mechanical_arm_filtering.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_filtering.text_3": "UNLOCALIZED: Sometimes it is desirable to restrict targets of the Arm by matching a filter", - "create.ponder.mechanical_arm_filtering.text_4": "UNLOCALIZED: Mechanical Arms by themselves do not provide any options for filtering", - "create.ponder.mechanical_arm_filtering.text_5": "UNLOCALIZED: Brass Funnels as Targets do however communicate their own filter to the Arm", - "create.ponder.mechanical_arm_filtering.text_6": "UNLOCALIZED: The Arm is smart enough not to pick up items it couldn't distribute", - - "create.ponder.mechanical_arm_modes.header": "UNLOCALIZED: Distribution modes of the Mechanical Arm", - "create.ponder.mechanical_arm_modes.text_1": "UNLOCALIZED: Input", - "create.ponder.mechanical_arm_modes.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_modes.text_3": "UNLOCALIZED: Whenever an Arm has to choose between multiple valid outputs...", - "create.ponder.mechanical_arm_modes.text_4": "UNLOCALIZED: ...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "UNLOCALIZED: Scrolling with a Wrench will allow you to configure it", - "create.ponder.mechanical_arm_modes.text_6": "UNLOCALIZED: Round Robin mode simply cycles through all outputs that are available", - "create.ponder.mechanical_arm_modes.text_7": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.mechanical_arm_modes.text_8": "UNLOCALIZED: Forced Round Robin mode will never skip outputs, and instead wait until they are free", - "create.ponder.mechanical_arm_modes.text_9": "UNLOCALIZED: Prefer First prioritizes the outputs selected earliest when configuring this Arm", - - "create.ponder.mechanical_arm_redstone.header": "UNLOCALIZED: Controlling Mechanical Arms with Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Mechanical Arms will not activate", - "create.ponder.mechanical_arm_redstone.text_2": "UNLOCALIZED: Before stopping, it will finish any started cycles", - "create.ponder.mechanical_arm_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", - "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", - "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", - - "create.ponder.mechanical_crafter.header": "UNLOCALIZED: Setting up Mechanical Crafters", - "create.ponder.mechanical_crafter.text_1": "UNLOCALIZED: An array of Mechanical Crafters can be used to automate any Crafting Recipe", - "create.ponder.mechanical_crafter.text_2": "UNLOCALIZED: Using a Wrench, the Crafters' paths can be arranged", - "create.ponder.mechanical_crafter.text_3": "UNLOCALIZED: For a valid setup, all paths have to converge into one exit at any side", - "create.ponder.mechanical_crafter.text_4": "UNLOCALIZED: The outputs will be placed into the inventory at the exit", - "create.ponder.mechanical_crafter.text_5": "UNLOCALIZED: Mechanical Crafters require Rotational Force to operate", - "create.ponder.mechanical_crafter.text_6": "UNLOCALIZED: Right-Click the front to insert Items manually", - "create.ponder.mechanical_crafter.text_7": "UNLOCALIZED: Once every slot of a path contains an Item, the crafting process will begin", - "create.ponder.mechanical_crafter.text_8": "UNLOCALIZED: For recipes not fully occupying the crafter setup, the start can be forced using a Redstone Pulse", - - "create.ponder.mechanical_crafter_connect.header": "UNLOCALIZED: Connecting Inventories of Crafters", - "create.ponder.mechanical_crafter_connect.text_1": "UNLOCALIZED: Items can be inserted to Crafters automatically", - "create.ponder.mechanical_crafter_connect.text_2": "UNLOCALIZED: Using the Wrench at their backs, Mechanical Crafter inputs can be combined", - "create.ponder.mechanical_crafter_connect.text_3": "UNLOCALIZED: All connected Crafters can now be accessed by the same input location", - - "create.ponder.mechanical_crafter_covers.header": "UNLOCALIZED: Covering slots of Mechanical Crafters", - "create.ponder.mechanical_crafter_covers.text_1": "UNLOCALIZED: Some recipes will require additional Crafters to bridge gaps in the path", - "create.ponder.mechanical_crafter_covers.text_2": "UNLOCALIZED: Using Slot Covers, Crafters can be set to act as an Empty Slot in the arrangement", - "create.ponder.mechanical_crafter_covers.text_3": "UNLOCALIZED: Shared Inputs created with the Wrench at the back can also reach across covered Crafters", - - "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", - "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", - "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", - - "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", - "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", - "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", - - "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", - "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", - "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", - - "create.ponder.mechanical_mixer.header": "UNLOCALIZED: Processing Items with the Mechanical Mixer", - "create.ponder.mechanical_mixer.text_1": "UNLOCALIZED: With a Mixer and Basin, some Crafting Recipes can be automated", - "create.ponder.mechanical_mixer.text_2": "UNLOCALIZED: Available recipes include any Shapeless Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_mixer.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_mixer.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", - "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", - "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", - "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", - - "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", - "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", - "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", - "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", - "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", - "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", - "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", - - "create.ponder.mechanical_press.header": "UNLOCALIZED: Processing Items with the Mechanical Press", - "create.ponder.mechanical_press.text_1": "UNLOCALIZED: The Mechanical Press can process items provided beneath it", - "create.ponder.mechanical_press.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Press", - "create.ponder.mechanical_press.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.mechanical_press.text_4": "UNLOCALIZED: The Press will hold and process them automatically", - - "create.ponder.mechanical_press_compacting.header": "UNLOCALIZED: Compacting items with the Mechanical Press", - "create.ponder.mechanical_press_compacting.text_1": "UNLOCALIZED: Pressing items held in a Basin will cause them to be Compacted", - "create.ponder.mechanical_press_compacting.text_2": "UNLOCALIZED: Compacting includes any filled 2x2 or 3x3 Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_press_compacting.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_press_compacting.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_pump_flow.header": "UNLOCALIZED: Fluid Transportation using Mechanical Pumps", - "create.ponder.mechanical_pump_flow.text_1": "UNLOCALIZED: Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "UNLOCALIZED: When powered, their arrow indicates the direction of flow", - "create.ponder.mechanical_pump_flow.text_3": "UNLOCALIZED: The network behind is now pulling fluids...", - "create.ponder.mechanical_pump_flow.text_4": "UNLOCALIZED: ...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "UNLOCALIZED: Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "UNLOCALIZED: Use a Wrench to reverse the orientation of pumps manually", - - "create.ponder.mechanical_pump_speed.header": "UNLOCALIZED: Throughput of Mechanical Pumps", - "create.ponder.mechanical_pump_speed.text_1": "UNLOCALIZED: Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", - "create.ponder.mechanical_pump_speed.text_2": "UNLOCALIZED: Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "UNLOCALIZED: ...aswell as how quickly fluids are transferred", - "create.ponder.mechanical_pump_speed.text_4": "UNLOCALIZED: Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "UNLOCALIZED: Alternating their orientation can help align their flow directions", - - "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", - "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", - "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", - - "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", - "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", - "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", - - "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", - "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", - "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", - "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", - "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", - "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", - - "create.ponder.millstone.header": "UNLOCALIZED: Processing Items in the Millstone", - "create.ponder.millstone.text_1": "UNLOCALIZED: Millstones process items by grinding them", - "create.ponder.millstone.text_2": "UNLOCALIZED: They can be powered from the side using cogwheels", - "create.ponder.millstone.text_3": "UNLOCALIZED: Throw or Insert items at the top", - "create.ponder.millstone.text_4": "UNLOCALIZED: After some time, the result can be obtained via Right-click", - "create.ponder.millstone.text_5": "UNLOCALIZED: The outputs can also be extracted by automation", - - "create.ponder.nixie_tube.header": "UNLOCALIZED: Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "UNLOCALIZED: When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "UNLOCALIZED: Using name tags edited with an anvil, custom text can be displayed", - "create.ponder.nixie_tube.text_3": "UNLOCALIZED: Right-Click with Dye to change their display colour", - - "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", - "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", - "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", - - "create.ponder.portable_fluid_interface.header": "UNLOCALIZED: Contraption Fluid Exchange", - "create.ponder.portable_fluid_interface.text_1": "UNLOCALIZED: Fluid Tanks on moving contraptions cannot be accessed by any pipes", - "create.ponder.portable_fluid_interface.text_2": "UNLOCALIZED: This component can interact with fluid tanks without the need to stop the contraption", - "create.ponder.portable_fluid_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_fluid_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_fluid_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL Tanks on the contraption", - "create.ponder.portable_fluid_interface.text_6": "UNLOCALIZED: Fluid can now be inserted...", - "create.ponder.portable_fluid_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_fluid_interface.text_8": "UNLOCALIZED: After no contents have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", - "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", - "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", - "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", - - "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", - "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", - "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", - "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", - "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", - - "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", - "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", - "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", - "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", - "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", - "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", - "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", - "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", - "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", - "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", - "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", - "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", - - "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", - "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", - "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", - - "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", - "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", - "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", - "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", - "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", - "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", - "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", - - "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", - "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", - "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", - - "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", - "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", - "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", - "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", - - "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", - "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", - "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", - "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", - - "create.ponder.sail.header": "UNLOCALIZED: Assembling Windmills using Sails", - "create.ponder.sail.text_1": "UNLOCALIZED: Sails are handy blocks to create Windmills with", - "create.ponder.sail.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - "create.ponder.sail.text_3": "UNLOCALIZED: Right-Click with Dye to paint them", - "create.ponder.sail.text_4": "UNLOCALIZED: Right-Click with Shears to turn them back into frames", - - "create.ponder.sail_frame.header": "UNLOCALIZED: Assembling Windmills using Sail Frames", - "create.ponder.sail_frame.text_1": "UNLOCALIZED: Sail Frames are handy blocks to create Windmills with", - "create.ponder.sail_frame.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", - "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", - "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", - "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", - "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", - "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", - - "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", - "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", - - "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", - "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", - - "create.ponder.smart_chute.header": "UNLOCALIZED: Filtering Items using Smart Chutes", - "create.ponder.smart_chute.text_1": "UNLOCALIZED: Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "UNLOCALIZED: Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "UNLOCALIZED: Use the Mouse Wheel to specify the extracted stack size", - "create.ponder.smart_chute.text_4": "UNLOCALIZED: Redstone power will prevent Smart Chutes from acting.", - - "create.ponder.smart_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Smart Pipes", - "create.ponder.smart_pipe.text_1": "UNLOCALIZED: Smart pipes can help control flows by fluid type", - "create.ponder.smart_pipe.text_2": "UNLOCALIZED: When placed directly at the source, they can specify the type of fluid to extract", - "create.ponder.smart_pipe.text_3": "UNLOCALIZED: Simply Right-Click their filter slot with any item containing the desired fluid", - "create.ponder.smart_pipe.text_4": "UNLOCALIZED: When placed further down a pipe network, smart pipes will only let matching fluids continue", - - "create.ponder.speedometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "UNLOCALIZED: The Speedometer displays the current Speed of the attached components", - "create.ponder.speedometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.speedometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Speedometer's measurements", - - "create.ponder.spout_filling.header": "UNLOCALIZED: Filling Items using a Spout", - "create.ponder.spout_filling.text_1": "UNLOCALIZED: The Spout can fill fluid holding items provided beneath it", - "create.ponder.spout_filling.text_2": "UNLOCALIZED: The content of a Spout cannot be accessed manually", - "create.ponder.spout_filling.text_3": "UNLOCALIZED: Instead, Pipes can be used to supply it with fluids", - "create.ponder.spout_filling.text_4": "UNLOCALIZED: The Input items can be placed on a Depot under the Spout", - "create.ponder.spout_filling.text_5": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.spout_filling.text_6": "UNLOCALIZED: The Spout will hold and process them automatically", - - "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", - "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", - "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", - "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", - "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", - "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", - "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", - "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", - "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", - - "create.ponder.stressometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Stressometer", - "create.ponder.stressometer.text_1": "UNLOCALIZED: The Stressometer displays the current Stress Capacity of the attached kinetic network", - "create.ponder.stressometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.stressometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Stressometer's measurements", - - "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", - "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue groups blocks together into moving contraptions", - "create.ponder.super_glue.text_2": "UNLOCALIZED: Clicking two endpoints creates a new 'glued' area", - "create.ponder.super_glue.text_3": "UNLOCALIZED: To remove a box, punch it with the glue item in hand", - "create.ponder.super_glue.text_4": "UNLOCALIZED: Adjacent blocks sharing an area will pull each other along", - "create.ponder.super_glue.text_5": "UNLOCALIZED: Overlapping glue volumes will move together", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", - - "create.ponder.valve_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Valves", - "create.ponder.valve_pipe.text_1": "UNLOCALIZED: Valve pipes help control fluids propagating through pipe networks", - "create.ponder.valve_pipe.text_2": "UNLOCALIZED: Their shaft input controls whether fluid is currently allowed through", - "create.ponder.valve_pipe.text_3": "UNLOCALIZED: Given Rotational Force in the opening direction, the valve will open up", - "create.ponder.valve_pipe.text_4": "UNLOCALIZED: It can be closed again by reversing the input rotation", - - "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", - "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", - - "create.ponder.weighted_ejector.header": "UNLOCALIZED: Using Weighted Ejectors", - "create.ponder.weighted_ejector.text_1": "UNLOCALIZED: Sneak and Right-Click holding an Ejector to select its target location", - "create.ponder.weighted_ejector.text_10": "UNLOCALIZED: It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "UNLOCALIZED: Other Entities will always trigger an Ejector when stepping on it", - "create.ponder.weighted_ejector.text_2": "UNLOCALIZED: The placed ejector will now launch objects to the marked location", - "create.ponder.weighted_ejector.text_3": "UNLOCALIZED: A valid target can be at any height or distance within range", - "create.ponder.weighted_ejector.text_4": "UNLOCALIZED: They cannot however be off to a side", - "create.ponder.weighted_ejector.text_5": "UNLOCALIZED: If no valid Target was selected, it will simply target the block directly in front", - "create.ponder.weighted_ejector.text_6": "UNLOCALIZED: Supply Rotational Force in order to charge it up", - "create.ponder.weighted_ejector.text_7": "UNLOCALIZED: Items placed on the ejector cause it to trigger", - "create.ponder.weighted_ejector.text_8": "UNLOCALIZED: If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "UNLOCALIZED: Using the Wrench, a required Stack Size can be configured", - - "create.ponder.weighted_ejector_redstone.header": "UNLOCALIZED: Controlling Weighted Ejectors with Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "UNLOCALIZED: Furthermore, Observers can detect when Ejectors activate", - - "create.ponder.weighted_ejector_tunnel.header": "UNLOCALIZED: Splitting item stacks using Weighted Ejectors", - "create.ponder.weighted_ejector_tunnel.text_1": "UNLOCALIZED: Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", - "create.ponder.weighted_ejector_tunnel.text_2": "UNLOCALIZED: First, configure the Brass Tunnel to 'Prefer Nearest', in order to prioritize its side output", - "create.ponder.weighted_ejector_tunnel.text_3": "UNLOCALIZED: The Stack Size set on the Ejector now determines the amount to be split off", - "create.ponder.weighted_ejector_tunnel.text_4": "UNLOCALIZED: While a new stack of the configured size exits the side output...", - "create.ponder.weighted_ejector_tunnel.text_5": "UNLOCALIZED: ...the remainder will continue on its path", - - "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", - "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", - "create.ponder.windmill_source.text_2": "UNLOCALIZED: Create a movable structure with the help of Super Glue", - "create.ponder.windmill_source.text_3": "UNLOCALIZED: If enough Sail-like blocks are included, this can act as a Windmill", - "create.ponder.windmill_source.text_4": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", - "create.ponder.windmill_source.text_5": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "UNLOCALIZED: Use a Wrench to configure its rotation direction", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", - "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/es_cl.json b/src/generated/resources/assets/create/lang/unfinished/es_cl.json deleted file mode 100644 index 1b1b97d227..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/es_cl.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 988", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Ventana de Acacia", - "block.create.acacia_window_pane": "Panel de Ventana de Acacia", - "block.create.adjustable_chain_gearshift": "Caja de Cambios en Cadena Ajustable", - "block.create.analog_lever": "Palanca Análoga", - "block.create.andesite_belt_funnel": "Ingreso para Cintas de Andesita", - "block.create.andesite_casing": "Cubierta de Andesita", - "block.create.andesite_encased_cogwheel": "UNLOCALIZED: Andesite Encased Cogwheel", - "block.create.andesite_encased_large_cogwheel": "UNLOCALIZED: Andesite Encased Large Cogwheel", - "block.create.andesite_encased_shaft": "Eje con Cubierta de Andesita", - "block.create.andesite_funnel": "Ingreso de Andesita", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "Pilar de Andesita", - "block.create.andesite_tunnel": "Túnel de Andesita", - "block.create.asurine": "UNLOCALIZED: Asurine", - "block.create.asurine_pillar": "UNLOCALIZED: Asurine Pillar", - "block.create.basin": "Tónel", - "block.create.belt": "Cinta", - "block.create.birch_window": "Ventana de Abedul", - "block.create.birch_window_pane": "Panel de Ventana de Abedul", - "block.create.black_nixie_tube": "Tubo Nixie Negro", - "block.create.black_sail": "Vela Negra", - "block.create.black_seat": "Asiento Negro", - "block.create.black_toolbox": "Caja de Herramientas Negra", - "block.create.black_valve_handle": "Válvula Negra", - "block.create.blaze_burner": "Mechero Blaze", - "block.create.blue_nixie_tube": "Tubo Nixie Azul", - "block.create.blue_sail": "Vela Azul", - "block.create.blue_seat": "Asiento Azul", - "block.create.blue_toolbox": "Caja de Herramientas Azul", - "block.create.blue_valve_handle": "Válvula Azul", - "block.create.brass_belt_funnel": "Ingreso para Cintas de Latón", - "block.create.brass_block": "Bloque de Latón", - "block.create.brass_casing": "Cubierta de Latón", - "block.create.brass_encased_cogwheel": "UNLOCALIZED: Brass Encased Cogwheel", - "block.create.brass_encased_large_cogwheel": "UNLOCALIZED: Brass Encased Large Cogwheel", - "block.create.brass_encased_shaft": "Eje con Cubierta de Latón", - "block.create.brass_funnel": "Ingreso de Latón", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "Túnel de Latón", - "block.create.brown_nixie_tube": "Tubo Nixie Marrón", - "block.create.brown_sail": "Vela Marrón", - "block.create.brown_seat": "Asiento Marrón", - "block.create.brown_toolbox": "Caja de Herramientas Marrón", - "block.create.brown_valve_handle": "Válvula Marrón", - "block.create.calcite_pillar": "UNLOCALIZED: Calcite Pillar", - "block.create.cart_assembler": "Ensambladora de Vagonetas", - "block.create.chocolate": "Chocolate", - "block.create.chute": "Tolvogán", - "block.create.clockwork_bearing": "Rodamiento De Relojería", - "block.create.clutch": "Embrague", - "block.create.cogwheel": "Engranaje", - "block.create.content_observer": "Observador de Contenidos", - "block.create.controller_rail": "Raíl Controlador", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "Tanque-Mochila de Cobre", - "block.create.copper_casing": "Cubierta de Cobre", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "UNLOCALIZED: Copper Shingle Slab", - "block.create.copper_shingle_stairs": "UNLOCALIZED: Copper Shingle Stairs", - "block.create.copper_shingles": "Tejas de Cobre", - "block.create.copper_tile_slab": "UNLOCALIZED: Copper Tile Slab", - "block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs", - "block.create.copper_tiles": "Baldosas de Cobre", - "block.create.copper_valve_handle": "Válvula de Cobre", - "block.create.creative_crate": "Cajón del Creativo", - "block.create.creative_fluid_tank": "Tanque de Fluidos del Creativo", - "block.create.creative_motor": "Motor del Creativo", - "block.create.crimsite": "UNLOCALIZED: Crimsite", - "block.create.crimsite_pillar": "UNLOCALIZED: Crimsite Pillar", - "block.create.crimson_window": "Ventana Carmesí", - "block.create.crimson_window_pane": "Panel de Ventana Carmesí", - "block.create.crushing_wheel": "Rueda Trituradora", - "block.create.crushing_wheel_controller": "Controladora de Rueda Trituradora", - "block.create.cuckoo_clock": "Reloj Cu-Cú", - "block.create.cut_andesite": "UNLOCALIZED: Cut Andesite", - "block.create.cut_andesite_brick_slab": "UNLOCALIZED: Cut Andesite Brick Slab", - "block.create.cut_andesite_brick_stairs": "UNLOCALIZED: Cut Andesite Brick Stairs", - "block.create.cut_andesite_brick_wall": "UNLOCALIZED: Cut Andesite Brick Wall", - "block.create.cut_andesite_bricks": "UNLOCALIZED: Cut Andesite Bricks", - "block.create.cut_andesite_slab": "UNLOCALIZED: Cut Andesite Slab", - "block.create.cut_andesite_stairs": "UNLOCALIZED: Cut Andesite Stairs", - "block.create.cut_andesite_wall": "UNLOCALIZED: Cut Andesite Wall", - "block.create.cut_asurine": "UNLOCALIZED: Cut Asurine", - "block.create.cut_asurine_brick_slab": "UNLOCALIZED: Cut Asurine Brick Slab", - "block.create.cut_asurine_brick_stairs": "UNLOCALIZED: Cut Asurine Brick Stairs", - "block.create.cut_asurine_brick_wall": "UNLOCALIZED: Cut Asurine Brick Wall", - "block.create.cut_asurine_bricks": "UNLOCALIZED: Cut Asurine Bricks", - "block.create.cut_asurine_slab": "UNLOCALIZED: Cut Asurine Slab", - "block.create.cut_asurine_stairs": "UNLOCALIZED: Cut Asurine Stairs", - "block.create.cut_asurine_wall": "UNLOCALIZED: Cut Asurine Wall", - "block.create.cut_calcite": "UNLOCALIZED: Cut Calcite", - "block.create.cut_calcite_brick_slab": "UNLOCALIZED: Cut Calcite Brick Slab", - "block.create.cut_calcite_brick_stairs": "UNLOCALIZED: Cut Calcite Brick Stairs", - "block.create.cut_calcite_brick_wall": "UNLOCALIZED: Cut Calcite Brick Wall", - "block.create.cut_calcite_bricks": "UNLOCALIZED: Cut Calcite Bricks", - "block.create.cut_calcite_slab": "UNLOCALIZED: Cut Calcite Slab", - "block.create.cut_calcite_stairs": "UNLOCALIZED: Cut Calcite Stairs", - "block.create.cut_calcite_wall": "UNLOCALIZED: Cut Calcite Wall", - "block.create.cut_crimsite": "UNLOCALIZED: Cut Crimsite", - "block.create.cut_crimsite_brick_slab": "UNLOCALIZED: Cut Crimsite Brick Slab", - "block.create.cut_crimsite_brick_stairs": "UNLOCALIZED: Cut Crimsite Brick Stairs", - "block.create.cut_crimsite_brick_wall": "UNLOCALIZED: Cut Crimsite Brick Wall", - "block.create.cut_crimsite_bricks": "UNLOCALIZED: Cut Crimsite Bricks", - "block.create.cut_crimsite_slab": "UNLOCALIZED: Cut Crimsite Slab", - "block.create.cut_crimsite_stairs": "UNLOCALIZED: Cut Crimsite Stairs", - "block.create.cut_crimsite_wall": "UNLOCALIZED: Cut Crimsite Wall", - "block.create.cut_deepslate": "UNLOCALIZED: Cut Deepslate", - "block.create.cut_deepslate_brick_slab": "UNLOCALIZED: Cut Deepslate Brick Slab", - "block.create.cut_deepslate_brick_stairs": "UNLOCALIZED: Cut Deepslate Brick Stairs", - "block.create.cut_deepslate_brick_wall": "UNLOCALIZED: Cut Deepslate Brick Wall", - "block.create.cut_deepslate_bricks": "UNLOCALIZED: Cut Deepslate Bricks", - "block.create.cut_deepslate_slab": "UNLOCALIZED: Cut Deepslate Slab", - "block.create.cut_deepslate_stairs": "UNLOCALIZED: Cut Deepslate Stairs", - "block.create.cut_deepslate_wall": "UNLOCALIZED: Cut Deepslate Wall", - "block.create.cut_diorite": "UNLOCALIZED: Cut Diorite", - "block.create.cut_diorite_brick_slab": "UNLOCALIZED: Cut Diorite Brick Slab", - "block.create.cut_diorite_brick_stairs": "UNLOCALIZED: Cut Diorite Brick Stairs", - "block.create.cut_diorite_brick_wall": "UNLOCALIZED: Cut Diorite Brick Wall", - "block.create.cut_diorite_bricks": "UNLOCALIZED: Cut Diorite Bricks", - "block.create.cut_diorite_slab": "UNLOCALIZED: Cut Diorite Slab", - "block.create.cut_diorite_stairs": "UNLOCALIZED: Cut Diorite Stairs", - "block.create.cut_diorite_wall": "UNLOCALIZED: Cut Diorite Wall", - "block.create.cut_dripstone": "UNLOCALIZED: Cut Dripstone", - "block.create.cut_dripstone_brick_slab": "UNLOCALIZED: Cut Dripstone Brick Slab", - "block.create.cut_dripstone_brick_stairs": "UNLOCALIZED: Cut Dripstone Brick Stairs", - "block.create.cut_dripstone_brick_wall": "UNLOCALIZED: Cut Dripstone Brick Wall", - "block.create.cut_dripstone_bricks": "UNLOCALIZED: Cut Dripstone Bricks", - "block.create.cut_dripstone_slab": "UNLOCALIZED: Cut Dripstone Slab", - "block.create.cut_dripstone_stairs": "UNLOCALIZED: Cut Dripstone Stairs", - "block.create.cut_dripstone_wall": "UNLOCALIZED: Cut Dripstone Wall", - "block.create.cut_granite": "UNLOCALIZED: Cut Granite", - "block.create.cut_granite_brick_slab": "UNLOCALIZED: Cut Granite Brick Slab", - "block.create.cut_granite_brick_stairs": "UNLOCALIZED: Cut Granite Brick Stairs", - "block.create.cut_granite_brick_wall": "UNLOCALIZED: Cut Granite Brick Wall", - "block.create.cut_granite_bricks": "UNLOCALIZED: Cut Granite Bricks", - "block.create.cut_granite_slab": "UNLOCALIZED: Cut Granite Slab", - "block.create.cut_granite_stairs": "UNLOCALIZED: Cut Granite Stairs", - "block.create.cut_granite_wall": "UNLOCALIZED: Cut Granite Wall", - "block.create.cut_limestone": "UNLOCALIZED: Cut Limestone", - "block.create.cut_limestone_brick_slab": "UNLOCALIZED: Cut Limestone Brick Slab", - "block.create.cut_limestone_brick_stairs": "UNLOCALIZED: Cut Limestone Brick Stairs", - "block.create.cut_limestone_brick_wall": "UNLOCALIZED: Cut Limestone Brick Wall", - "block.create.cut_limestone_bricks": "UNLOCALIZED: Cut Limestone Bricks", - "block.create.cut_limestone_slab": "UNLOCALIZED: Cut Limestone Slab", - "block.create.cut_limestone_stairs": "UNLOCALIZED: Cut Limestone Stairs", - "block.create.cut_limestone_wall": "UNLOCALIZED: Cut Limestone Wall", - "block.create.cut_ochrum": "UNLOCALIZED: Cut Ochrum", - "block.create.cut_ochrum_brick_slab": "UNLOCALIZED: Cut Ochrum Brick Slab", - "block.create.cut_ochrum_brick_stairs": "UNLOCALIZED: Cut Ochrum Brick Stairs", - "block.create.cut_ochrum_brick_wall": "UNLOCALIZED: Cut Ochrum Brick Wall", - "block.create.cut_ochrum_bricks": "UNLOCALIZED: Cut Ochrum Bricks", - "block.create.cut_ochrum_slab": "UNLOCALIZED: Cut Ochrum Slab", - "block.create.cut_ochrum_stairs": "UNLOCALIZED: Cut Ochrum Stairs", - "block.create.cut_ochrum_wall": "UNLOCALIZED: Cut Ochrum Wall", - "block.create.cut_scorchia": "UNLOCALIZED: Cut Scorchia", - "block.create.cut_scorchia_brick_slab": "UNLOCALIZED: Cut Scorchia Brick Slab", - "block.create.cut_scorchia_brick_stairs": "UNLOCALIZED: Cut Scorchia Brick Stairs", - "block.create.cut_scorchia_brick_wall": "UNLOCALIZED: Cut Scorchia Brick Wall", - "block.create.cut_scorchia_bricks": "UNLOCALIZED: Cut Scorchia Bricks", - "block.create.cut_scorchia_slab": "UNLOCALIZED: Cut Scorchia Slab", - "block.create.cut_scorchia_stairs": "UNLOCALIZED: Cut Scorchia Stairs", - "block.create.cut_scorchia_wall": "UNLOCALIZED: Cut Scorchia Wall", - "block.create.cut_scoria": "UNLOCALIZED: Cut Scoria", - "block.create.cut_scoria_brick_slab": "UNLOCALIZED: Cut Scoria Brick Slab", - "block.create.cut_scoria_brick_stairs": "UNLOCALIZED: Cut Scoria Brick Stairs", - "block.create.cut_scoria_brick_wall": "UNLOCALIZED: Cut Scoria Brick Wall", - "block.create.cut_scoria_bricks": "UNLOCALIZED: Cut Scoria Bricks", - "block.create.cut_scoria_slab": "UNLOCALIZED: Cut Scoria Slab", - "block.create.cut_scoria_stairs": "UNLOCALIZED: Cut Scoria Stairs", - "block.create.cut_scoria_wall": "UNLOCALIZED: Cut Scoria Wall", - "block.create.cut_tuff": "UNLOCALIZED: Cut Tuff", - "block.create.cut_tuff_brick_slab": "UNLOCALIZED: Cut Tuff Brick Slab", - "block.create.cut_tuff_brick_stairs": "UNLOCALIZED: Cut Tuff Brick Stairs", - "block.create.cut_tuff_brick_wall": "UNLOCALIZED: Cut Tuff Brick Wall", - "block.create.cut_tuff_bricks": "UNLOCALIZED: Cut Tuff Bricks", - "block.create.cut_tuff_slab": "UNLOCALIZED: Cut Tuff Slab", - "block.create.cut_tuff_stairs": "UNLOCALIZED: Cut Tuff Stairs", - "block.create.cut_tuff_wall": "UNLOCALIZED: Cut Tuff Wall", - "block.create.cut_veridium": "UNLOCALIZED: Cut Veridium", - "block.create.cut_veridium_brick_slab": "UNLOCALIZED: Cut Veridium Brick Slab", - "block.create.cut_veridium_brick_stairs": "UNLOCALIZED: Cut Veridium Brick Stairs", - "block.create.cut_veridium_brick_wall": "UNLOCALIZED: Cut Veridium Brick Wall", - "block.create.cut_veridium_bricks": "UNLOCALIZED: Cut Veridium Bricks", - "block.create.cut_veridium_slab": "UNLOCALIZED: Cut Veridium Slab", - "block.create.cut_veridium_stairs": "UNLOCALIZED: Cut Veridium Stairs", - "block.create.cut_veridium_wall": "UNLOCALIZED: Cut Veridium Wall", - "block.create.cyan_nixie_tube": "Tubo Nixie Cian", - "block.create.cyan_sail": "Vela Cian", - "block.create.cyan_seat": "Asiento Cian", - "block.create.cyan_toolbox": "Caja de Herramientas Cian", - "block.create.cyan_valve_handle": "Válvula Cian", - "block.create.dark_oak_window": "Ventana de Roble Oscuro", - "block.create.dark_oak_window_pane": "Panel de Ventana de Roble Oscuro", - "block.create.deepslate_pillar": "UNLOCALIZED: Deepslate Pillar", - "block.create.deepslate_zinc_ore": "UNLOCALIZED: Deepslate Zinc Ore", - "block.create.deployer": "Desplegador", - "block.create.depot": "Depósito", - "block.create.diorite_pillar": "Pilar de Diorita", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar", - "block.create.encased_chain_drive": "Conductor en Cadena Encubierto", - "block.create.encased_fan": "Ventilador Encubierto", - "block.create.encased_fluid_pipe": "Tubería de Fluidos Encubierta", - "block.create.exposed_copper_shingle_slab": "UNLOCALIZED: Exposed Copper Shingle Slab", - "block.create.exposed_copper_shingle_stairs": "UNLOCALIZED: Exposed Copper Shingle Stairs", - "block.create.exposed_copper_shingles": "UNLOCALIZED: Exposed Copper Shingles", - "block.create.exposed_copper_tile_slab": "UNLOCALIZED: Exposed Copper Tile Slab", - "block.create.exposed_copper_tile_stairs": "UNLOCALIZED: Exposed Copper Tile Stairs", - "block.create.exposed_copper_tiles": "UNLOCALIZED: Exposed Copper Tiles", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "Tubería de Fluidos", - "block.create.fluid_tank": "Tanque de Fluidos", - "block.create.fluid_valve": "Válvula de Fluidos", - "block.create.flywheel": "Volante de Inercia", - "block.create.framed_glass": "Vidrio Enmarcado", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "Panel de Vidrio Enmarcado", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "Carruaje de Grúa", - "block.create.gantry_shaft": "Eje de Grúa", - "block.create.gearbox": "Caja de Engranajes", - "block.create.gearshift": "Caja de Cambios", - "block.create.glass_fluid_pipe": "Tubería de Fluidos de Cristal", - "block.create.granite_pillar": "Pilar de Granito", - "block.create.gray_nixie_tube": "Tubo Nixie Gris", - "block.create.gray_sail": "vela Gris", - "block.create.gray_seat": "Asiento Gris", - "block.create.gray_toolbox": "Caja de Herrameintas Gris", - "block.create.gray_valve_handle": "Válvula Gris", - "block.create.green_nixie_tube": "Tubo Nixie Verde", - "block.create.green_sail": "Vela Verde", - "block.create.green_seat": "Asiento Verde", - "block.create.green_toolbox": "Caja de Herramientas Verde", - "block.create.green_valve_handle": "Válvula Verde", - "block.create.hand_crank": "Manivela", - "block.create.haunted_bell": "Campana Embrujada", - "block.create.honey": "Miel", - "block.create.horizontal_framed_glass": "Vidrio Enmarcado Horizontal", - "block.create.horizontal_framed_glass_pane": "Panel de Vidrio Enmarcado Horizontal", - "block.create.hose_pulley": "Polea Manguera", - "block.create.item_drain": "Drenaje", - "block.create.item_vault": "UNLOCALIZED: Item Vault", - "block.create.jungle_window": "Ventana de Jungla", - "block.create.jungle_window_pane": "Panel de Ventana de Jungla", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "Engranaje Grande", - "block.create.layered_andesite": "Capa de Andesita", - "block.create.layered_asurine": "UNLOCALIZED: Layered Asurine", - "block.create.layered_calcite": "UNLOCALIZED: Layered Calcite", - "block.create.layered_crimsite": "UNLOCALIZED: Layered Crimsite", - "block.create.layered_deepslate": "UNLOCALIZED: Layered Deepslate", - "block.create.layered_diorite": "Capa de Diorita", - "block.create.layered_dripstone": "UNLOCALIZED: Layered Dripstone", - "block.create.layered_granite": "Capa de Granito", - "block.create.layered_limestone": "Capa de Piedra Caliza", - "block.create.layered_ochrum": "UNLOCALIZED: Layered Ochrum", - "block.create.layered_scorchia": "UNLOCALIZED: Layered Scorchia", - "block.create.layered_scoria": "Capa de Escoria", - "block.create.layered_tuff": "UNLOCALIZED: Layered Tuff", - "block.create.layered_veridium": "UNLOCALIZED: Layered Veridium", - "block.create.lectern_controller": "Controlador de Atril", - "block.create.light_blue_nixie_tube": "Tubo Nixie Azul Claro", - "block.create.light_blue_sail": "Vela Azul Claro", - "block.create.light_blue_seat": "Asiento Azul Claro", - "block.create.light_blue_toolbox": "Caja de Herramientas Azul Claro", - "block.create.light_blue_valve_handle": "Válvula Azul Claro", - "block.create.light_gray_nixie_tube": "Tubo Nixie Gris Claro", - "block.create.light_gray_sail": "Vela Gris Claro", - "block.create.light_gray_seat": "Asiento Gris Claro", - "block.create.light_gray_toolbox": "Caja de Herramientas Gris Claro", - "block.create.light_gray_valve_handle": "Válvula Gris Claro", - "block.create.lime_nixie_tube": "Tubo Nixie Lima", - "block.create.lime_sail": "Vela Lima", - "block.create.lime_seat": "Asiento Lima", - "block.create.lime_toolbox": "Caja de herramientas Lima", - "block.create.lime_valve_handle": "Válvula Lima", - "block.create.limestone": "Piedra Caliza", - "block.create.limestone_pillar": "Pilar de Piedra Caliza", - "block.create.linear_chassis": "Chasis Lineal", - "block.create.lit_blaze_burner": "Quemador Blaze Encendido", - "block.create.magenta_nixie_tube": "Tubo Nixie Magenta", - "block.create.magenta_sail": "Vela Magenta", - "block.create.magenta_seat": "Asiento Magenta", - "block.create.magenta_toolbox": "Caja de Herramientas Magenta", - "block.create.magenta_valve_handle": "Válvula Magenta", - "block.create.mechanical_arm": "Brazo Mecánico", - "block.create.mechanical_bearing": "Rodamiento Mecánico", - "block.create.mechanical_crafter": "Crafteador Mecánico", - "block.create.mechanical_drill": "Taladro Mecánico", - "block.create.mechanical_harvester": "Cosechadora Mecánica", - "block.create.mechanical_mixer": "Mezcladora Mecánica", - "block.create.mechanical_piston": "Pistón Mecánico", - "block.create.mechanical_piston_head": "Cabeza de Pistón Mecánico", - "block.create.mechanical_plough": "Arador Mecánico", - "block.create.mechanical_press": "Prensa Mecánica", - "block.create.mechanical_pump": "Bomba Mecánica", - "block.create.mechanical_saw": "Sierra Mecánica", - "block.create.metal_bracket": "Soporte Metálico", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "Piedra de Molino", - "block.create.minecart_anchor": "Ancla de Vagoneta", - "block.create.mysterious_cuckoo_clock": "Reloj Cu-Cú", - "block.create.nixie_tube": "Tubo Nixie", - "block.create.nozzle": "Boquilla", - "block.create.oak_window": "Ventana de Roble", - "block.create.oak_window_pane": "Panel de Ventana de Roble", - "block.create.ochrum": "UNLOCALIZED: Ochrum", - "block.create.ochrum_pillar": "UNLOCALIZED: Ochrum Pillar", - "block.create.orange_sail": "Vela Naranja", - "block.create.orange_seat": "Asiento Naranja", - "block.create.orange_toolbox": "Caja de Herramientas Naranja", - "block.create.orange_valve_handle": "Válvula Naranja", - "block.create.ornate_iron_window": "Ventana de Hierro Adornada", - "block.create.ornate_iron_window_pane": "Panel de Ventana de Hierro Adornada", - "block.create.oxidized_copper_shingle_slab": "UNLOCALIZED: Oxidized Copper Shingle Slab", - "block.create.oxidized_copper_shingle_stairs": "UNLOCALIZED: Oxidized Copper Shingle Stairs", - "block.create.oxidized_copper_shingles": "UNLOCALIZED: Oxidized Copper Shingles", - "block.create.oxidized_copper_tile_slab": "UNLOCALIZED: Oxidized Copper Tile Slab", - "block.create.oxidized_copper_tile_stairs": "UNLOCALIZED: Oxidized Copper Tile Stairs", - "block.create.oxidized_copper_tiles": "UNLOCALIZED: Oxidized Copper Tiles", - "block.create.peculiar_bell": "Campana Peculiar", - "block.create.pink_nixie_tube": "Tubo Nixie Rosado", - "block.create.pink_sail": "Vela Rosada", - "block.create.pink_seat": "Asiento Rosado", - "block.create.pink_toolbox": "Caja de Herramientas Rosada", - "block.create.pink_valve_handle": "Válvula Rosada", - "block.create.piston_extension_pole": "Poste de Extensión de Pistón", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "UNLOCALIZED: Polished Cut Andesite", - "block.create.polished_cut_andesite_slab": "UNLOCALIZED: Polished Cut Andesite Slab", - "block.create.polished_cut_andesite_stairs": "UNLOCALIZED: Polished Cut Andesite Stairs", - "block.create.polished_cut_andesite_wall": "UNLOCALIZED: Polished Cut Andesite Wall", - "block.create.polished_cut_asurine": "UNLOCALIZED: Polished Cut Asurine", - "block.create.polished_cut_asurine_slab": "UNLOCALIZED: Polished Cut Asurine Slab", - "block.create.polished_cut_asurine_stairs": "UNLOCALIZED: Polished Cut Asurine Stairs", - "block.create.polished_cut_asurine_wall": "UNLOCALIZED: Polished Cut Asurine Wall", - "block.create.polished_cut_calcite": "UNLOCALIZED: Polished Cut Calcite", - "block.create.polished_cut_calcite_slab": "UNLOCALIZED: Polished Cut Calcite Slab", - "block.create.polished_cut_calcite_stairs": "UNLOCALIZED: Polished Cut Calcite Stairs", - "block.create.polished_cut_calcite_wall": "UNLOCALIZED: Polished Cut Calcite Wall", - "block.create.polished_cut_crimsite": "UNLOCALIZED: Polished Cut Crimsite", - "block.create.polished_cut_crimsite_slab": "UNLOCALIZED: Polished Cut Crimsite Slab", - "block.create.polished_cut_crimsite_stairs": "UNLOCALIZED: Polished Cut Crimsite Stairs", - "block.create.polished_cut_crimsite_wall": "UNLOCALIZED: Polished Cut Crimsite Wall", - "block.create.polished_cut_deepslate": "UNLOCALIZED: Polished Cut Deepslate", - "block.create.polished_cut_deepslate_slab": "UNLOCALIZED: Polished Cut Deepslate Slab", - "block.create.polished_cut_deepslate_stairs": "UNLOCALIZED: Polished Cut Deepslate Stairs", - "block.create.polished_cut_deepslate_wall": "UNLOCALIZED: Polished Cut Deepslate Wall", - "block.create.polished_cut_diorite": "UNLOCALIZED: Polished Cut Diorite", - "block.create.polished_cut_diorite_slab": "UNLOCALIZED: Polished Cut Diorite Slab", - "block.create.polished_cut_diorite_stairs": "UNLOCALIZED: Polished Cut Diorite Stairs", - "block.create.polished_cut_diorite_wall": "UNLOCALIZED: Polished Cut Diorite Wall", - "block.create.polished_cut_dripstone": "UNLOCALIZED: Polished Cut Dripstone", - "block.create.polished_cut_dripstone_slab": "UNLOCALIZED: Polished Cut Dripstone Slab", - "block.create.polished_cut_dripstone_stairs": "UNLOCALIZED: Polished Cut Dripstone Stairs", - "block.create.polished_cut_dripstone_wall": "UNLOCALIZED: Polished Cut Dripstone Wall", - "block.create.polished_cut_granite": "UNLOCALIZED: Polished Cut Granite", - "block.create.polished_cut_granite_slab": "UNLOCALIZED: Polished Cut Granite Slab", - "block.create.polished_cut_granite_stairs": "UNLOCALIZED: Polished Cut Granite Stairs", - "block.create.polished_cut_granite_wall": "UNLOCALIZED: Polished Cut Granite Wall", - "block.create.polished_cut_limestone": "UNLOCALIZED: Polished Cut Limestone", - "block.create.polished_cut_limestone_slab": "UNLOCALIZED: Polished Cut Limestone Slab", - "block.create.polished_cut_limestone_stairs": "UNLOCALIZED: Polished Cut Limestone Stairs", - "block.create.polished_cut_limestone_wall": "UNLOCALIZED: Polished Cut Limestone Wall", - "block.create.polished_cut_ochrum": "UNLOCALIZED: Polished Cut Ochrum", - "block.create.polished_cut_ochrum_slab": "UNLOCALIZED: Polished Cut Ochrum Slab", - "block.create.polished_cut_ochrum_stairs": "UNLOCALIZED: Polished Cut Ochrum Stairs", - "block.create.polished_cut_ochrum_wall": "UNLOCALIZED: Polished Cut Ochrum Wall", - "block.create.polished_cut_scorchia": "UNLOCALIZED: Polished Cut Scorchia", - "block.create.polished_cut_scorchia_slab": "UNLOCALIZED: Polished Cut Scorchia Slab", - "block.create.polished_cut_scorchia_stairs": "UNLOCALIZED: Polished Cut Scorchia Stairs", - "block.create.polished_cut_scorchia_wall": "UNLOCALIZED: Polished Cut Scorchia Wall", - "block.create.polished_cut_scoria": "UNLOCALIZED: Polished Cut Scoria", - "block.create.polished_cut_scoria_slab": "UNLOCALIZED: Polished Cut Scoria Slab", - "block.create.polished_cut_scoria_stairs": "UNLOCALIZED: Polished Cut Scoria Stairs", - "block.create.polished_cut_scoria_wall": "UNLOCALIZED: Polished Cut Scoria Wall", - "block.create.polished_cut_tuff": "UNLOCALIZED: Polished Cut Tuff", - "block.create.polished_cut_tuff_slab": "UNLOCALIZED: Polished Cut Tuff Slab", - "block.create.polished_cut_tuff_stairs": "UNLOCALIZED: Polished Cut Tuff Stairs", - "block.create.polished_cut_tuff_wall": "UNLOCALIZED: Polished Cut Tuff Wall", - "block.create.polished_cut_veridium": "UNLOCALIZED: Polished Cut Veridium", - "block.create.polished_cut_veridium_slab": "UNLOCALIZED: Polished Cut Veridium Slab", - "block.create.polished_cut_veridium_stairs": "UNLOCALIZED: Polished Cut Veridium Stairs", - "block.create.polished_cut_veridium_wall": "UNLOCALIZED: Polished Cut Veridium Wall", - "block.create.portable_fluid_interface": "Interfaz de Fluidos Portable", - "block.create.portable_storage_interface": "Interfaz de Almacenamientos Portable", - "block.create.powered_latch": "Cerrojo de Redstone", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "Cerrojo Palanca de Redstone", - "block.create.pulley_magnet": "Imán de la Polea", - "block.create.pulse_extender": "UNLOCALIZED: Pulse Extender", - "block.create.pulse_repeater": "Repetidor de Pulso", - "block.create.purple_nixie_tube": "Tubo Nixie Morado", - "block.create.purple_sail": "Vela Morada", - "block.create.purple_seat": "Asiento Morado", - "block.create.purple_toolbox": "Caja de Herramientas Morada", - "block.create.purple_valve_handle": "Válvula Morada", - "block.create.radial_chassis": "Chasis Radial", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "UNLOCALIZED: Block of Raw Zinc", - "block.create.red_nixie_tube": "Tubo Nixie Rojo", - "block.create.red_sail": "Vela Roja", - "block.create.red_seat": "Asiento Rojo", - "block.create.red_toolbox": "Caja de Herramientas Roja", - "block.create.red_valve_handle": "Válvula Roja", - "block.create.redstone_contact": "Contacto de Redstone", - "block.create.redstone_link": "Enlace de Redstone", - "block.create.refined_radiance_casing": "Cubierta Radiante", - "block.create.rope": "Cuerda", - "block.create.rope_pulley": "Polea de Cuerda", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "Controlador de Velocidad de Rotación", - "block.create.sail_frame": "Marco de Vela", - "block.create.schematic_table": "Mesa de Esquemas", - "block.create.schematicannon": "Esquemacañón", - "block.create.scorchia": "UNLOCALIZED: Scorchia", - "block.create.scorchia_pillar": "UNLOCALIZED: Scorchia Pillar", - "block.create.scoria": "Escoria", - "block.create.scoria_pillar": "Pilar de Escoria", - "block.create.secondary_linear_chassis": "Chasis Lineal Secundario", - "block.create.sequenced_gearshift": "Caja de Cambios Secuenciada", - "block.create.shadow_steel_casing": "Cubierta de Sombra", - "block.create.shaft": "Eje", - "block.create.small_andesite_brick_slab": "UNLOCALIZED: Small Andesite Brick Slab", - "block.create.small_andesite_brick_stairs": "UNLOCALIZED: Small Andesite Brick Stairs", - "block.create.small_andesite_brick_wall": "UNLOCALIZED: Small Andesite Brick Wall", - "block.create.small_andesite_bricks": "UNLOCALIZED: Small Andesite Bricks", - "block.create.small_asurine_brick_slab": "UNLOCALIZED: Small Asurine Brick Slab", - "block.create.small_asurine_brick_stairs": "UNLOCALIZED: Small Asurine Brick Stairs", - "block.create.small_asurine_brick_wall": "UNLOCALIZED: Small Asurine Brick Wall", - "block.create.small_asurine_bricks": "UNLOCALIZED: Small Asurine Bricks", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "UNLOCALIZED: Small Calcite Brick Slab", - "block.create.small_calcite_brick_stairs": "UNLOCALIZED: Small Calcite Brick Stairs", - "block.create.small_calcite_brick_wall": "UNLOCALIZED: Small Calcite Brick Wall", - "block.create.small_calcite_bricks": "UNLOCALIZED: Small Calcite Bricks", - "block.create.small_crimsite_brick_slab": "UNLOCALIZED: Small Crimsite Brick Slab", - "block.create.small_crimsite_brick_stairs": "UNLOCALIZED: Small Crimsite Brick Stairs", - "block.create.small_crimsite_brick_wall": "UNLOCALIZED: Small Crimsite Brick Wall", - "block.create.small_crimsite_bricks": "UNLOCALIZED: Small Crimsite Bricks", - "block.create.small_deepslate_brick_slab": "UNLOCALIZED: Small Deepslate Brick Slab", - "block.create.small_deepslate_brick_stairs": "UNLOCALIZED: Small Deepslate Brick Stairs", - "block.create.small_deepslate_brick_wall": "UNLOCALIZED: Small Deepslate Brick Wall", - "block.create.small_deepslate_bricks": "UNLOCALIZED: Small Deepslate Bricks", - "block.create.small_diorite_brick_slab": "UNLOCALIZED: Small Diorite Brick Slab", - "block.create.small_diorite_brick_stairs": "UNLOCALIZED: Small Diorite Brick Stairs", - "block.create.small_diorite_brick_wall": "UNLOCALIZED: Small Diorite Brick Wall", - "block.create.small_diorite_bricks": "UNLOCALIZED: Small Diorite Bricks", - "block.create.small_dripstone_brick_slab": "UNLOCALIZED: Small Dripstone Brick Slab", - "block.create.small_dripstone_brick_stairs": "UNLOCALIZED: Small Dripstone Brick Stairs", - "block.create.small_dripstone_brick_wall": "UNLOCALIZED: Small Dripstone Brick Wall", - "block.create.small_dripstone_bricks": "UNLOCALIZED: Small Dripstone Bricks", - "block.create.small_granite_brick_slab": "UNLOCALIZED: Small Granite Brick Slab", - "block.create.small_granite_brick_stairs": "UNLOCALIZED: Small Granite Brick Stairs", - "block.create.small_granite_brick_wall": "UNLOCALIZED: Small Granite Brick Wall", - "block.create.small_granite_bricks": "UNLOCALIZED: Small Granite Bricks", - "block.create.small_limestone_brick_slab": "UNLOCALIZED: Small Limestone Brick Slab", - "block.create.small_limestone_brick_stairs": "UNLOCALIZED: Small Limestone Brick Stairs", - "block.create.small_limestone_brick_wall": "UNLOCALIZED: Small Limestone Brick Wall", - "block.create.small_limestone_bricks": "UNLOCALIZED: Small Limestone Bricks", - "block.create.small_ochrum_brick_slab": "UNLOCALIZED: Small Ochrum Brick Slab", - "block.create.small_ochrum_brick_stairs": "UNLOCALIZED: Small Ochrum Brick Stairs", - "block.create.small_ochrum_brick_wall": "UNLOCALIZED: Small Ochrum Brick Wall", - "block.create.small_ochrum_bricks": "UNLOCALIZED: Small Ochrum Bricks", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "UNLOCALIZED: Small Scorchia Brick Slab", - "block.create.small_scorchia_brick_stairs": "UNLOCALIZED: Small Scorchia Brick Stairs", - "block.create.small_scorchia_brick_wall": "UNLOCALIZED: Small Scorchia Brick Wall", - "block.create.small_scorchia_bricks": "UNLOCALIZED: Small Scorchia Bricks", - "block.create.small_scoria_brick_slab": "UNLOCALIZED: Small Scoria Brick Slab", - "block.create.small_scoria_brick_stairs": "UNLOCALIZED: Small Scoria Brick Stairs", - "block.create.small_scoria_brick_wall": "UNLOCALIZED: Small Scoria Brick Wall", - "block.create.small_scoria_bricks": "UNLOCALIZED: Small Scoria Bricks", - "block.create.small_tuff_brick_slab": "UNLOCALIZED: Small Tuff Brick Slab", - "block.create.small_tuff_brick_stairs": "UNLOCALIZED: Small Tuff Brick Stairs", - "block.create.small_tuff_brick_wall": "UNLOCALIZED: Small Tuff Brick Wall", - "block.create.small_tuff_bricks": "UNLOCALIZED: Small Tuff Bricks", - "block.create.small_veridium_brick_slab": "UNLOCALIZED: Small Veridium Brick Slab", - "block.create.small_veridium_brick_stairs": "UNLOCALIZED: Small Veridium Brick Stairs", - "block.create.small_veridium_brick_wall": "UNLOCALIZED: Small Veridium Brick Wall", - "block.create.small_veridium_bricks": "UNLOCALIZED: Small Veridium Bricks", - "block.create.smart_chute": "Tolvogán Inteligente", - "block.create.smart_fluid_pipe": "Tubería de Fluidos Inteligente", - "block.create.speedometer": "Velocímetro", - "block.create.spout": "Surtidor", - "block.create.spruce_window": "Ventana de Abeto", - "block.create.spruce_window_pane": "Panel de Ventana de Abeto", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "Pegador", - "block.create.sticky_mechanical_piston": "Pistón Mecánico Pegajoso", - "block.create.stockpile_switch": "Interruptor de Reservas", - "block.create.stressometer": "Estresómetro", - "block.create.tiled_glass": "Vidrio Baldosa", - "block.create.tiled_glass_pane": "Panel de Vidrio Baldosa", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "UNLOCALIZED: Tuff Pillar", - "block.create.turntable": "Plato Giratorio", - "block.create.veridium": "UNLOCALIZED: Veridium", - "block.create.veridium_pillar": "UNLOCALIZED: Veridium Pillar", - "block.create.vertical_framed_glass": "Vidrio Baldosa Vertical", - "block.create.vertical_framed_glass_pane": "Panel de Vidrio Baldosa Vertical", - "block.create.warped_window": "Ventana Distorsionada", - "block.create.warped_window_pane": "Panel de Ventana Distorsionada", - "block.create.water_wheel": "Rueda de Agua", - "block.create.waxed_copper_shingle_slab": "UNLOCALIZED: Waxed Copper Shingle Slab", - "block.create.waxed_copper_shingle_stairs": "UNLOCALIZED: Waxed Copper Shingle Stairs", - "block.create.waxed_copper_shingles": "UNLOCALIZED: Waxed Copper Shingles", - "block.create.waxed_copper_tile_slab": "UNLOCALIZED: Waxed Copper Tile Slab", - "block.create.waxed_copper_tile_stairs": "UNLOCALIZED: Waxed Copper Tile Stairs", - "block.create.waxed_copper_tiles": "UNLOCALIZED: Waxed Copper Tiles", - "block.create.waxed_exposed_copper_shingle_slab": "UNLOCALIZED: Waxed Exposed Copper Shingle Slab", - "block.create.waxed_exposed_copper_shingle_stairs": "UNLOCALIZED: Waxed Exposed Copper Shingle Stairs", - "block.create.waxed_exposed_copper_shingles": "UNLOCALIZED: Waxed Exposed Copper Shingles", - "block.create.waxed_exposed_copper_tile_slab": "UNLOCALIZED: Waxed Exposed Copper Tile Slab", - "block.create.waxed_exposed_copper_tile_stairs": "UNLOCALIZED: Waxed Exposed Copper Tile Stairs", - "block.create.waxed_exposed_copper_tiles": "UNLOCALIZED: Waxed Exposed Copper Tiles", - "block.create.waxed_oxidized_copper_shingle_slab": "UNLOCALIZED: Waxed Oxidized Copper Shingle Slab", - "block.create.waxed_oxidized_copper_shingle_stairs": "UNLOCALIZED: Waxed Oxidized Copper Shingle Stairs", - "block.create.waxed_oxidized_copper_shingles": "UNLOCALIZED: Waxed Oxidized Copper Shingles", - "block.create.waxed_oxidized_copper_tile_slab": "UNLOCALIZED: Waxed Oxidized Copper Tile Slab", - "block.create.waxed_oxidized_copper_tile_stairs": "UNLOCALIZED: Waxed Oxidized Copper Tile Stairs", - "block.create.waxed_oxidized_copper_tiles": "UNLOCALIZED: Waxed Oxidized Copper Tiles", - "block.create.waxed_weathered_copper_shingle_slab": "UNLOCALIZED: Waxed Weathered Copper Shingle Slab", - "block.create.waxed_weathered_copper_shingle_stairs": "UNLOCALIZED: Waxed Weathered Copper Shingle Stairs", - "block.create.waxed_weathered_copper_shingles": "UNLOCALIZED: Waxed Weathered Copper Shingles", - "block.create.waxed_weathered_copper_tile_slab": "UNLOCALIZED: Waxed Weathered Copper Tile Slab", - "block.create.waxed_weathered_copper_tile_stairs": "UNLOCALIZED: Waxed Weathered Copper Tile Stairs", - "block.create.waxed_weathered_copper_tiles": "UNLOCALIZED: Waxed Weathered Copper Tiles", - "block.create.weathered_copper_shingle_slab": "UNLOCALIZED: Weathered Copper Shingle Slab", - "block.create.weathered_copper_shingle_stairs": "UNLOCALIZED: Weathered Copper Shingle Stairs", - "block.create.weathered_copper_shingles": "UNLOCALIZED: Weathered Copper Shingles", - "block.create.weathered_copper_tile_slab": "UNLOCALIZED: Weathered Copper Tile Slab", - "block.create.weathered_copper_tile_stairs": "UNLOCALIZED: Weathered Copper Tile Stairs", - "block.create.weathered_copper_tiles": "UNLOCALIZED: Weathered Copper Tiles", - "block.create.weighted_ejector": "Eyector por Peso", - "block.create.white_nixie_tube": "Tubo Nixie Blanco", - "block.create.white_sail": "Vela Blanca", - "block.create.white_seat": "Asiento Blanco", - "block.create.white_toolbox": "Caja de Herramientas Blanca", - "block.create.white_valve_handle": "Válvula Blanca", - "block.create.windmill_bearing": "Rodamiento de Molino de Viento", - "block.create.wooden_bracket": "Soporte de Madera", - "block.create.yellow_nixie_tube": "Tubo Nixie Amarillo", - "block.create.yellow_sail": "Vela Amarilla", - "block.create.yellow_seat": "Asiento Amarillo", - "block.create.yellow_toolbox": "Caja de Herramientas Amarilla", - "block.create.yellow_valve_handle": "Válvula Amarilla", - "block.create.zinc_block": "Bloque de Zinc", - "block.create.zinc_ore": "Mineral de Zinc", - - "enchantment.create.capacity": "Capacidad", - "enchantment.create.potato_recovery": "Recuperación de papas", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "Artefacto", - "entity.create.crafting_blueprint": "Crafteando Planos", - "entity.create.gantry_contraption": "Artefacto de Grúa", - "entity.create.potato_projectile": "Projectil de papa", - "entity.create.seat": "Asiento", - "entity.create.stationary_contraption": "Artefacto Estacionario", - "entity.create.super_glue": "La Gotita", - - "fluid.create.potion": "Poción", - "fluid.create.tea": "Té del Constructor", - - "item.create.andesite_alloy": "Aleación de Andesita", - "item.create.attribute_filter": "Filtro de Atributos", - "item.create.bar_of_chocolate": "Barra de Chocolate", - "item.create.belt_connector": "Cinta Mecánica", - "item.create.blaze_cake": "Pastel Blaze", - "item.create.blaze_cake_base": "Base del Pastel Blaze", - "item.create.brass_hand": "Mano de Latón", - "item.create.brass_ingot": "Lingote de Latón", - "item.create.brass_nugget": "Nugget de Latón", - "item.create.brass_sheet": "Plancha de Latón", - "item.create.builders_tea": "Té del Constructor", - "item.create.chest_minecart_contraption": "Contrapción de Vagoneta con Cofre", - "item.create.chocolate_bucket": "Balde de Chocolate", - "item.create.chocolate_glazed_berries": "Bayas Bañadas en Chocolate", - "item.create.chromatic_compound": "Compuesto Cromático", - "item.create.cinder_flour": "Harina de Cenizas", - "item.create.copper_backtank": "Mochila-Tanque de Cobre", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Nugget de Cobre", - "item.create.copper_sheet": "Plancha de Cobre", - "item.create.crafter_slot_cover": "Cubre Ranuras", - "item.create.crafting_blueprint": "Plano de Fabricación", - "item.create.creative_blaze_cake": "Pastel Blaze del Creativo", - "item.create.crushed_aluminum_ore": "Mineral de Aluminio Triturado", - "item.create.crushed_copper_ore": "Mineral de Cobre Triturado", - "item.create.crushed_gold_ore": "Mineral de Oro Triturado", - "item.create.crushed_iron_ore": "Mineral de Hierro Triturado", - "item.create.crushed_lead_ore": "Mineral de Plomo Triturado", - "item.create.crushed_nickel_ore": "Mineral de Níquel Triturado", - "item.create.crushed_osmium_ore": "Mineral de Osmio Triturado", - "item.create.crushed_platinum_ore": "Mineral de Platino Triturado", - "item.create.crushed_quicksilver_ore": "Mineral de Mercurio Triturado", - "item.create.crushed_silver_ore": "Mineral de Plata Triturado", - "item.create.crushed_tin_ore": "Mineral de Estaño Triturado", - "item.create.crushed_uranium_ore": "Mineral de Uranio Triturado", - "item.create.crushed_zinc_ore": "Mineral de Zinc Triturado", - "item.create.diving_boots": "Botas de Buceo", - "item.create.diving_helmet": "Casco de Buceo", - "item.create.dough": "Masa", - "item.create.electron_tube": "Tubo de Electrones", - "item.create.empty_blaze_burner": "Quemador Blaze Vacío", - "item.create.empty_schematic": "Esquema Vacío", - "item.create.experience_nugget": "UNLOCALIZED: Nugget of Experience", - "item.create.extendo_grip": "Agarrextensor", - "item.create.filter": "Filtro", - "item.create.furnace_minecart_contraption": "Contrapción de Vagoneta con Horno", - "item.create.goggles": "Lentes del Ingeniero", - "item.create.golden_sheet": "Plancha Dorada", - "item.create.handheld_worldshaper": "Forma Mundos del Creativo", - "item.create.honey_bucket": "Balde de Miel", - "item.create.honeyed_apple": "Manzana Enmielada", - "item.create.incomplete_precision_mechanism": "Mecanismo de Precisión Incompleto", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "Plancha de Hierro", - "item.create.linked_controller": "Controlador Vinculable", - "item.create.minecart_contraption": "Contrapción de Vagoneta", - "item.create.minecart_coupling": "Acoplamiento de Vagonetas", - "item.create.polished_rose_quartz": "Cuarzo Rosa Pulido", - "item.create.potato_cannon": "Cañón de Papas", - "item.create.powdered_obsidian": "Obsidiana Pulverizada", - "item.create.precision_mechanism": "Mecanismo de Precisión", - "item.create.propeller": "Hélice", - "item.create.raw_zinc": "UNLOCALIZED: Raw Zinc", - "item.create.red_sand_paper": "Papel de Arena Roja", - "item.create.refined_radiance": "Radiancia Refinada", - "item.create.rose_quartz": "Cuarzo Rosa", - "item.create.sand_paper": "Papel de Arena", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Esquema", - "item.create.schematic_and_quill": "Esquema con Pluma", - "item.create.shadow_steel": "Acero Sombrío", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "La Gotita", - "item.create.sweet_roll": "Rollito Dulce", - "item.create.tree_fertilizer": "Fertilizante Arbóreo", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Caja de Engranajes Vertical", - "item.create.wand_of_symmetry": "Vara de Simetría", - "item.create.wheat_flour": "Harina de Trigo", - "item.create.whisk": "Batidor", - "item.create.wrench": "Llave Inglesa", - "item.create.zinc_ingot": "Lingote de Zinc", - "item.create.zinc_nugget": "Nugget de Zinc", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bienvenido a Create", - "advancement.create.root.desc": "¡Es hora de empezar a construir algunas contrapciones increíbles!", - "advancement.create.andesite_alloy": "Aliteración Abundante", - "advancement.create.andesite_alloy.desc": "Los materiales de create tienen nombres raros. La Aleación de Andesita es uno de ellos.", - "advancement.create.andesite_casing": "La Edad de la Andesita", - "advancement.create.andesite_casing.desc": "Utilice un poco de madera y aleación de andesita para crear una cubierta básica.", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "Unidad de Algas", - "advancement.create.belt.desc": "Conecta dos ejes con una cinta mecánica.", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "Viniendose Abajo", - "advancement.create.chute.desc": "Coloca un tolvogán, la contraparte vertical de las cintas mecánicas.", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "Aprovechando la Hidráulica", - "advancement.create.water_wheel.desc": "¡Pon una rueda de agua e intenta hacer que gire!", - "advancement.create.windmill": "Una leve brisa", - "advancement.create.windmill.desc": "Arma un molino.", - "advancement.create.shifting_gears": "Engranajes Cambiantes", - "advancement.create.shifting_gears.desc": "Conecta un engranaje grande a uno pequeño, permitiendo cambiar la velocidad de tu contrapción.", - "advancement.create.millstone": "Trituradora de Bolsillo", - "advancement.create.millstone.desc": "Coloca y dale poder a una Piedra de Molino.", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "Pero, ¿qué tan estresado exactamente?", - "advancement.create.stressometer.desc": "Coloca y dale poder a un Estresómetro. Míralo con tus gafas para leer el número exacto.", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "¡Son Cintololos!", - "advancement.create.belt_funnel_kiss.desc": "Haz que dos ingresos montados en una cinta mecánica se besen.", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "La Edad del Cobre", - "advancement.create.copper_casing.desc": "Utiliza planchas de cobre y un poco de madera para crear cubiertas de cobre.", - "advancement.create.spout": "Splash", - "advancement.create.spout.desc": "Observa cómo se llena un objeto de líquido con un surtidor.", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "Flujo Espía", - "advancement.create.glass_pipe.desc": "Observa cómo se propaga el fluido a través de una tubería con ventana. Puedes añadir una ventana a una tubería recta con tu Llave Inglesa.", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "Derrame industrial", - "advancement.create.hose_pulley.desc": "Baja una polea manguera y observa cómo drena o llena un cuerpo de fluido.", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "Aleaciones de verdad", - "advancement.create.brass.desc": "Usa cobre triturado y zinc triturado para crear algo de latón.", - "advancement.create.brass_casing": "La Edad del Latón", - "advancement.create.brass_casing.desc": "Utiliza tu latón recién obtenido y un poco de madera para crear una cubierta más avanzada.", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "Toca, Coloca y Ataca", - "advancement.create.deployer.desc": "Coloca y dale poder a un Desplegador, la perfecta reflexión de tí mismo.", - "advancement.create.precision_mechanism": "Curiosidades Complejas", - "advancement.create.precision_mechanism.desc": "Ensambla un Mecanismo de Precisión.", - "advancement.create.speed_controller": "¡Los ingenieros lo odian!", - "advancement.create.speed_controller.desc": "Pon un Controlador de Velocidad de Rotación, el último dispositivo del mercado para el engranaje moderno.", - "advancement.create.mechanical_arm": "¡Manos Ocupadas!", - "advancement.create.mechanical_arm.desc": "Construye un brazo mecánico, selecciona entradas y salidas, colócalo y dale poder; entonces, observa como hace todo el trabajo por tí.", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "Un par de Gigantes", - "advancement.create.crushing_wheel.desc": "Crea ruedas trituradoras para descomponer los materiales de manera más efectiva.", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "Contrapción en Punto", - "advancement.create.clockwork_bearing.desc": "Ensambla una estructura montada sobre un rodamiento de relojería.", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "¡Fwoomp!", - "advancement.create.potato_cannon.desc": "Derrota a un enemigo con tu Cañón de Papas.", - "advancement.create.extendo_grip": "¡Boioioing!", - "advancement.create.extendo_grip.desc": "Sostén un Agarrextensor.", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "Combustrón 3001", - "advancement.create.arm_blaze_burner.desc": "Instruye a un brazo mecánico para que alimente tu Quemador Blaze.", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "Organizatrón 3000", - "advancement.create.arm_many_targets.desc": "Programa un brazo mecánico con 10 o más localizaciones de salida.", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "¡Dame el puño, hermano!", - "advancement.create.fist_bump.desc": "Haz que dos Desplegadores se golpeen con el puño.", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "¡Póneme mi tema principal!", - "advancement.create.musical_arm.desc": "Observa cómo un brazo mecánico opera un tocadiscos.", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create Palettes", - - "death.attack.create.crush": "%1$s fué procesado por Ruedas Trituradoras", - "death.attack.create.crush.player": "%1$sfue tirado dentro de Ruedas Trituradoras por %2$s", - "death.attack.create.fan_fire": "%1$s se ahumó con un Ventilador", - "death.attack.create.fan_fire.player": "%1$s fué tirado dentro de un ahumador por %2$s", - "death.attack.create.fan_lava": "%1$s fué incinerado por un Ventilador", - "death.attack.create.fan_lava.player": "%1$s fué tirado dentro de una derretidora por %2$s", - "death.attack.create.mechanical_drill": "%1$s fué empalado por un Taladro Mecánico", - "death.attack.create.mechanical_drill.player": "%1$s fué tirado en frente de un Taladro por %2$s", - "death.attack.create.mechanical_saw": "%1$s fué cortado por la mitad por Sierra Mecánica", - "death.attack.create.mechanical_saw.player": "%1$s fué lanzado dentro de una Sierra por %2$s", - "death.attack.create.potato_cannon": "%1$s fue disparado por el Cañón de Papas de %2$s", - "death.attack.create.potato_cannon.item": "%1$s fué disparado por %2$s usando %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s fué reventado por el reloj cu-cú manipulado", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s fué reventado por el reloj cu-cú manipulado", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "Un Desplegador pillo", - "create.block.cart_assembler.invalid": "Coloca tu ensamblador de Vagonetas en un bloque de rieles", - - "create.menu.return": "Volver al Menú", - "create.menu.configure": "Configurar...", - "create.menu.ponder_index": "Reflexionar el índice", - "create.menu.only_ingame": "Disponible en el menú de pausa", - "create.menu.report_bugs": "Reportar Problemas", - "create.menu.support": "Apóyanos", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Triturando", - "create.recipe.milling": "Moliendo", - "create.recipe.fan_washing": "Lavando", - "create.recipe.fan_washing.fan": "Ventilador detrás de una Corriente de Agua", - "create.recipe.fan_smoking": "Ahumado", - "create.recipe.fan_smoking.fan": "Ventilador tras Fuego", - "create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", - "create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", - "create.recipe.fan_blasting": "Fundición", - "create.recipe.fan_blasting.fan": "Ventilador tras Lava", - "create.recipe.pressing": "Prensando", - "create.recipe.mixing": "Mezclando", - "create.recipe.deploying": "Desplegando", - "create.recipe.automatic_shapeless": "Crafteo Automatizada sin Forma", - "create.recipe.automatic_brewing": "Preparación Automática", - "create.recipe.packing": "Compactando", - "create.recipe.automatic_packing": "Campactación Automática", - "create.recipe.sawing": "Aserrando", - "create.recipe.mechanical_crafting": "Crafteo Mecánico", - "create.recipe.automatic_shaped": "Crafteo Automático con Forma", - "create.recipe.block_cutting": "Cartando Bloques", - "create.recipe.wood_cutting": "Cortando Madera", - "create.recipe.sandpaper_polishing": "Pulido de Papel de Arena", - "create.recipe.mystery_conversion": "Conversión Misteriosa", - "create.recipe.spout_filling": "Llenado por Surtidor", - "create.recipe.draining": "Drenaje de Objeto", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "Ensamblaje Secuenciado", - "create.recipe.assembly.next": "Siguiente: %1$s", - "create.recipe.assembly.step": "Paso %1$s:", - "create.recipe.assembly.progress": "Progreso: %1$s/%2$s", - "create.recipe.assembly.pressing": "Procesar en prensa", - "create.recipe.assembly.spout_filling_fluid": "Surte %1$s", - "create.recipe.assembly.deploying_item": "Despliega %1$s", - "create.recipe.assembly.cutting": "Corta con Sierra", - "create.recipe.assembly.repeat": "Repetir Secuencia %1$s Veces", - "create.recipe.assembly.junk": "Chatarra Aleatoria", - "create.recipe.processing.chance": "%1$s%% Probabilidad", - "create.recipe.deploying.not_consumed": "No Consumido", - "create.recipe.heat_requirement.none": "No requiere calor", - "create.recipe.heat_requirement.heated": "Calentado", - "create.recipe.heat_requirement.superheated": "Super-Calentado", - - "create.generic.range": "Rango", - "create.generic.radius": "Radio", - "create.generic.width": "Ancho", - "create.generic.height": "Altura", - "create.generic.length": "Largo", - "create.generic.speed": "Velocidad", - "create.generic.delay": "Retraso", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Segundos", - "create.generic.unit.minutes": "Minutos", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "us", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "En sentido del Reloj", - "create.generic.counter_clockwise": "Al contrario del Reloj", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Rueda", - "create.action.confirm": "Confirmar", - "create.action.abort": "Abortar", - "create.action.saveToFile": "Guardar", - "create.action.discard": "Descartar", - - "create.keyinfo.toolmenu": "Fijarse en el Overlay del esquema", - "create.keyinfo.toolbelt": "Acceder a cajas de Herramientas cercanas", - "create.keyinfo.scrollup": "Simular Mousewheel Up (inworld)", - "create.keyinfo.scrolldown": "Simular Mousewheel Down (inworld)", - - "create.gui.scrollInput.defaultTitle": "Elije una opción:", - "create.gui.scrollInput.scrollToModify": "Rueda para modificar", - "create.gui.scrollInput.scrollToAdjustAmount": "Rueda para ajustar la cantidad", - "create.gui.scrollInput.scrollToSelect": "Rueda para selecionar", - "create.gui.scrollInput.shiftScrollsFaster": "Shiftea para rodar mas rápido", - "create.gui.toolmenu.focusKey": "Mantén [%1$s] para Fijarte", - "create.gui.toolmenu.cycle": "[SCROLL] para ciclar", - - "create.toolbox.unequip": "Desequipar: %1$s", - "create.toolbox.outOfRange": "Caja de Herramientas del objeto fuera de rango", - "create.toolbox.detach": "Detener búsqueda y mantener el objeto", - "create.toolbox.depositAll": "Devolver objetos a cajas de herramientas cercanas", - "create.toolbox.depositBox": "Devolver objetos a la caja de herramientas", - - "create.gui.symmetryWand.mirrorType": "Espejo", - "create.gui.symmetryWand.orientation": "Orientación", - - "create.symmetry.mirror.plane": "Reflejar una vez", - "create.symmetry.mirror.doublePlane": "Rectangular", - "create.symmetry.mirror.triplePlane": "Octagonal", - - "create.orientation.orthogonal": "Ortogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "En el eje Z", - "create.orientation.alongX": "en el eje X", - - "create.gui.terrainzapper.title": "Blockzapper de mano", - "create.gui.terrainzapper.searchDiagonal": "Seguir Diagonales", - "create.gui.terrainzapper.searchFuzzy": "Ignorar bordes de los materiales", - "create.gui.terrainzapper.patternSection": "Patrón", - "create.gui.terrainzapper.pattern.solid": "Solido", - "create.gui.terrainzapper.pattern.checkered": "Tablero de damas", - "create.gui.terrainzapper.pattern.inversecheckered": "Tablero de damas invertido", - "create.gui.terrainzapper.pattern.chance25": "Tiro de 25%", - "create.gui.terrainzapper.pattern.chance50": "Tiro de 50%", - "create.gui.terrainzapper.pattern.chance75": "Tiro de 75%", - "create.gui.terrainzapper.placement": "Colocación", - "create.gui.terrainzapper.placement.merged": "Fusionados", - "create.gui.terrainzapper.placement.attached": "Adjuntos", - "create.gui.terrainzapper.placement.inserted": "Insertados", - "create.gui.terrainzapper.brush": "Brocha", - "create.gui.terrainzapper.brush.cuboid": "Cuboide", - "create.gui.terrainzapper.brush.sphere": "Esfera", - "create.gui.terrainzapper.brush.cylinder": "Cilindro", - "create.gui.terrainzapper.brush.surface": "Superficie", - "create.gui.terrainzapper.brush.cluster": "Grupo", - "create.gui.terrainzapper.tool": "Herramienta", - "create.gui.terrainzapper.tool.fill": "Llenar", - "create.gui.terrainzapper.tool.place": "Colocar", - "create.gui.terrainzapper.tool.replace": "Reemplazar", - "create.gui.terrainzapper.tool.clear": "Borrar", - "create.gui.terrainzapper.tool.overlay": "Overlay", - "create.gui.terrainzapper.tool.flatten": "Aplanar", - - "create.terrainzapper.shiftRightClickToSet": "Shift-Click Derecho para Seleccionar una Forma", - "create.terrainzapper.usingBlock": "Usando: %1$s", - "create.terrainzapper.leftClickToSet": "Click Izquierdo a un Bloque para elegir Material", - - "create.minecart_coupling.two_couplings_max": "Las vagonetas no pueden tener mas de dos uniones cada una", - "create.minecart_coupling.unloaded": "Partes de tu tren parecen estar en chunks no cargados", - "create.minecart_coupling.no_loops": "Las uniones no puede formar un ciclo", - "create.minecart_coupling.removed": "Removidas todas las uniones de la vagoneta", - "create.minecart_coupling.too_far": "Las vagonetas estan muy separadas entre sí", - - "create.contraptions.movement_mode": "Modo de Movimiento", - "create.contraptions.movement_mode.move_place": "Siempre colocar cuando se Detiene", - "create.contraptions.movement_mode.move_place_returned": "Colocar solo en la Posición Inicial", - "create.contraptions.movement_mode.move_never_place": "Colocar solo cuando el anclaje se destruye", - "create.contraptions.movement_mode.rotate_place": "Colocar siempre que es detenido", - "create.contraptions.movement_mode.rotate_place_returned": "Colocar solo cerca del angulo inicial", - "create.contraptions.movement_mode.rotate_never_place": "Colocar solo cuando el anclaje es destruido", - "create.contraptions.cart_movement_mode": "Modo de Movimiento del Vagón", - "create.contraptions.cart_movement_mode.rotate": "Siempre apuntar en la dirección de movimiento", - "create.contraptions.cart_movement_mode.rotate_paused": "Pausar actores mientras rota", - "create.contraptions.cart_movement_mode.rotation_locked": "Bloquear Rotación", - "create.contraptions.windmill.rotation_direction": "Dirección de Rotación", - "create.contraptions.clockwork.clock_hands": "Manijas del Reloj", - "create.contraptions.clockwork.hour_first": "Horario Primero", - "create.contraptions.clockwork.minute_first": "Minutero Primero", - "create.contraptions.clockwork.hour_first_24": "24-horas Primero", - - "create.logistics.filter": "Filtro", - "create.logistics.recipe_filter": "Filtro de Recetas", - "create.logistics.fluid_filter": "Filtro de Fluidos", - "create.logistics.firstFrequency": "Frec. #1", - "create.logistics.secondFrequency": "Frec. #2", - "create.logistics.filter.apply": "Filtro Aplicado a %1$s.", - "create.logistics.filter.apply_click_again": "Filtro Aplicado a %1$s, haz click de nuevo para copiar la cantidad.", - "create.logistics.filter.apply_count": "Recuento de extracción aplicado al filtro.", - - "create.gui.goggles.generator_stats": "Estadísticas de Generación:", - "create.gui.goggles.kinetic_stats": "Estadísticas Kineticas:", - "create.gui.goggles.at_current_speed": "a la velocidad actual", - "create.gui.goggles.pole_length": "Largo del poste:", - "create.gui.goggles.fluid_container": "Informacion del Contenedor de Fluidos:", - "create.gui.goggles.fluid_container.capacity": "Capacidad: ", - "create.gui.assembly.exception": "Esta contrapción no se pudo ensamblar:", - "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s,%2$s,%3$s] no estaba en un chunk cargado", - "create.gui.assembly.exception.structureTooLarge": "Hay muchos bloques incluidos en la contrapción.\nEl máximo configurado es: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Hay muchos postes de extensión en este pistón.\nEl máximo configurado es: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Al pistón le faltan algunos postes de extensión", - "create.gui.assembly.exception.not_enough_sails": "La estructura adjunta no incluye suficientes bloques de vela: %1$s\nUn mínimo de %2$s son requeridos", - "create.gui.gauge.info_header": "Información del medidor:", - "create.gui.speedometer.title": "Velocidad de Rotación", - "create.gui.stressometer.title": "Estrés de la Red", - "create.gui.stressometer.capacity": "Capacidad Restante", - "create.gui.stressometer.overstressed": "Sobreestresado", - "create.gui.stressometer.no_rotation": "Sin Rotación", - "create.gui.contraptions.not_fast_enough": "Parece que este %1$s _no_ está rotando con _suficiente_ _velocidad_.", - "create.gui.contraptions.network_overstressed": "Parece que esta contrapción está _sobreestresada_. Añade más fuentes o _reduce_ la _velocidad_ de los componentes con gran _impacto_ en el _estrés_.", - "create.gui.adjustable_crate.title": "Cajón Ajustable", - "create.gui.adjustable_crate.storageSpace": "Espacio de Almacenamiento:", - "create.gui.stockpile_switch.title": "Interruptor de Reservas", - "create.gui.stockpile_switch.invert_signal": "Invertir Señal", - "create.gui.stockpile_switch.move_to_lower_at": "Mover a la línea inferior en %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Mover a la línea superior en %1$s%%", - "create.gui.sequenced_gearshift.title": "Caja de Cambios Secuenciada", - "create.gui.sequenced_gearshift.instruction": "Instrucción", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Girar en Ángulo", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Girar", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Ángulo", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Girar para mover Pistón/Polea/Grúa", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistón", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Retraso Cronometrado", - "create.gui.sequenced_gearshift.instruction.delay": "Retraso", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Duración", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Fin", - "create.gui.sequenced_gearshift.instruction.end": "Fin", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Esperar nuevo pulso de redstone", - "create.gui.sequenced_gearshift.instruction.await": "Esperar", - "create.gui.sequenced_gearshift.speed": "Velocidad, Dirección", - "create.gui.sequenced_gearshift.speed.forward": "Velocidad ingresada, Adelante", - "create.gui.sequenced_gearshift.speed.forward_fast": "Doble Velocidad, Adelante", - "create.gui.sequenced_gearshift.speed.back": "Velocidad ingresada, Revertido", - "create.gui.sequenced_gearshift.speed.back_fast": "Doble Velocidad, Revertido", - - "create.schematicAndQuill.dimensions": "Tamaño del esquema: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Primera posición establecida.", - "create.schematicAndQuill.secondPos": "Segunda posición establecida.", - "create.schematicAndQuill.noTarget": "Mantén [Ctrl] para Seleccionar Bloques Aéreos.", - "create.schematicAndQuill.abort": "Selección Removida.", - "create.schematicAndQuill.title": "Nombre del Esquema:", - "create.schematicAndQuill.convert": "Guardar y cargar inmediatamente", - "create.schematicAndQuill.fallbackName": "Mi Esquema", - "create.schematicAndQuill.saved": "Guardado como %1$s", - - "create.schematic.invalid": "[!] Objeto Invalido - Usa la Mesa de Esquemas", - "create.schematic.position": "Posición", - "create.schematic.rotation": "Rotación", - "create.schematic.rotation.none": "Ninguno", - "create.schematic.rotation.cw90": "Según las agujas del reloj en 90", - "create.schematic.rotation.cw180": "Según las agujas del reloj en 180", - "create.schematic.rotation.cw270": "Según las agujas del reloj en 270", - "create.schematic.mirror": "Reflejar", - "create.schematic.mirror.none": "Ninguno", - "create.schematic.mirror.frontBack": "Frente-Detrás", - "create.schematic.mirror.leftRight": "Izquierda-Derecha", - "create.schematic.tool.deploy": "Posición", - "create.schematic.tool.move": "Mover XZ", - "create.schematic.tool.movey": "Mover Y", - "create.schematic.tool.rotate": "Rotar", - "create.schematic.tool.print": "Imprimir", - "create.schematic.tool.flip": "Reflejar", - "create.schematic.tool.deploy.description.0": "Mueve la estructura a una ubicación.", - "create.schematic.tool.deploy.description.1": "Haz clic derecho en el suelo para colocar.", - "create.schematic.tool.deploy.description.2": "Mantén [Ctrl] para seleccionar a una distancia fija.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Rueda para seleccionar distancia.", - "create.schematic.tool.move.description.0": "Desplaza el esquema horizontalmente.", - "create.schematic.tool.move.description.1": "Apunta al esquema y [CTRL]-Rueda para empujarlo.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Desplaza el esquema verticalmente.", - "create.schematic.tool.movey.description.1": "[CTRL]-Rueda para moverlo arriba y abajo.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Rota el esquema sobre su centro.", - "create.schematic.tool.rotate.description.1": "[CTRL]-Rueda para rotarlo en 90 Grados.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Instantáneamente construye la estructura en el mundo.", - "create.schematic.tool.print.description.1": "[Click-Derecho] para confirmar la ubicación en la ubicación actual.", - "create.schematic.tool.print.description.2": "Solo en Creativo.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Gira el esquema a lo largo de la cara que seleccionaste.", - "create.schematic.tool.flip.description.1": "Apunta al esquema y [CTRL]-Rueda para voltearlo.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Sincronizando...", - "create.schematics.uploadTooLarge": "Tu esquema excede las limitaciones especificadas por el servidor.", - "create.schematics.maxAllowedSize": "El tamaño máximo de archivo de esquema permitido es:", - - "create.gui.schematicTable.refresh": "Refrescar Archivos", - "create.gui.schematicTable.open_folder": "Abrir Carpeta", - "create.gui.schematicTable.title": "Mesa de Esquemas", - "create.gui.schematicTable.availableSchematics": "Esquemas Disponibles", - "create.gui.schematicTable.noSchematics": "Sin Esquemas Guardados", - "create.gui.schematicTable.uploading": "Subiendo...", - "create.gui.schematicTable.finished": "¡Subida Finalizada!", - "create.gui.schematicannon.title": "Esquemacañón", - "create.gui.schematicannon.listPrinter": "Impresora de Lista de Objetos", - "create.gui.schematicannon.gunpowderLevel": "Polvora al %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Tiros restantes: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Con respaldo: %1$s", - "create.gui.schematicannon.optionEnabled": "Actualmente Activado", - "create.gui.schematicannon.optionDisabled": "Actualmente Desactivado", - "create.gui.schematicannon.showOptions": "Mostrar Configuraciones de la Impresora", - "create.gui.schematicannon.option.dontReplaceSolid": "No reemplazar Bloques Sólidos", - "create.gui.schematicannon.option.replaceWithSolid": "Reemplazar Sólido con Sólido", - "create.gui.schematicannon.option.replaceWithAny": "Reemplazar Sólido con cualquier cosa", - "create.gui.schematicannon.option.replaceWithEmpty": "Reemplazar Sólido con Vacío", - "create.gui.schematicannon.option.skipMissing": "Saltarse objetos faltantes", - "create.gui.schematicannon.option.skipTileEntities": "Proteject objetos con información", - "create.gui.schematicannon.slot.gunpowder": "Añade pólvora para alimentar el cañon", - "create.gui.schematicannon.slot.listPrinter": "Coloca libros aquí para imprimir una lista de verificación para tu esquema", - "create.gui.schematicannon.slot.schematic": "Pon tu Esquema aquí. Asegurate de haberlo desplegado en la ubicación deseada.", - "create.gui.schematicannon.option.skipMissing.description": "Si el cañón no puede encontrar un Bloque requerido para colocarlo, saltará a la siguiente Ubicación.", - "create.gui.schematicannon.option.skipTileEntities.description": "El cañón evitará reemplazar bloques con almacenamiento de datos como cofres o máquinas.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "El cañón nunca reemplazará ningún bloque sólido en su área de trabajo, solo no-sólidos y aire.", - "create.gui.schematicannon.option.replaceWithSolid.description": "El cañón solo reemplazará los bloques sólidos en su área de trabajo si el esquema contiene un bloque sólido en esa ubicación.", - "create.gui.schematicannon.option.replaceWithAny.description": "El cañón reemplazará los bloques sólidos en su área de trabajo si el esquema contiene algún bloque de cualquier tipo en la ubicación.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "El cañón reemplazará todos los bloques en su área de trabajo, incluidos los reemplazados por aire.", - - "create.schematicannon.status.idle": "Inactivo", - "create.schematicannon.status.ready": "Listo", - "create.schematicannon.status.running": "En Funcionamiento", - "create.schematicannon.status.finished": "Finalizado", - "create.schematicannon.status.paused": "Pausado", - "create.schematicannon.status.stopped": "Detenido", - "create.schematicannon.status.noGunpowder": "Sin Pólvora", - "create.schematicannon.status.targetNotLoaded": "Objetivo no cargado", - "create.schematicannon.status.targetOutsideRange": "Objetivo muy lejano", - "create.schematicannon.status.searching": "Buscando", - "create.schematicannon.status.skipping": "Saltando", - "create.schematicannon.status.missingBlock": "Objeto Faltante:", - "create.schematicannon.status.placing": "Colocando", - "create.schematicannon.status.clearing": "Limpiando Bloques", - "create.schematicannon.status.schematicInvalid": "Esquema Inválido", - "create.schematicannon.status.schematicNotPlaced": "Esquema no Posicionado", - "create.schematicannon.status.schematicExpired": "Archivo de Esquema Expirado", - - "create.materialChecklist": "Lista de verificación de materiales", - "create.materialChecklist.blocksNotLoaded": "* Descargo de responsabilidad *\n\nLa lista de materiales puede ser inexacta debido a chunks que no se cargan.", - - "create.gui.filter.deny_list": "Lista Negra", - "create.gui.filter.deny_list.description": "Los objetos pasan solo si NO coinciden con ninguno de los anteriores. Una lista negra vacía acepta todo.", - "create.gui.filter.allow_list": "Lista Blanca", - "create.gui.filter.allow_list.description": "Los objetos pasan solo si coinciden con alguno de los anteriores. Una lista blanca vacía rechaza todo.", - "create.gui.filter.respect_data": "Respetar Datos", - "create.gui.filter.respect_data.description": "Los objetos solo coinciden si su durabilidad, encantamientos y otros atributos también coinciden.", - "create.gui.filter.ignore_data": "Ignorar Datos", - "create.gui.filter.ignore_data.description": "Los objetos coinciden sin importar sus datos.", - - "create.item_attributes.placeable": "es colocable", - "create.item_attributes.placeable.inverted": "no es colocable", - "create.item_attributes.consumable": "puede ser consumido", - "create.item_attributes.consumable.inverted": "no puede ser consumido", - "create.item_attributes.fluid_container": "puede guardar fluidos", - "create.item_attributes.fluid_container.inverted": "no puede guardar fluidos", - "create.item_attributes.enchanted": "está encantado", - "create.item_attributes.enchanted.inverted": "está desencantado", - "create.item_attributes.max_enchanted": "está encantado al máximo", - "create.item_attributes.max_enchanted.inverted": "no está encantado al máximo", - "create.item_attributes.renamed": "tiene un nombre customizado", - "create.item_attributes.renamed.inverted": "no tiene un nombre customizado", - "create.item_attributes.damaged": "está dañado", - "create.item_attributes.damaged.inverted": "no está dañado", - "create.item_attributes.badly_damaged": "está muy dañado", - "create.item_attributes.badly_damaged.inverted": "no está muy dañado", - "create.item_attributes.not_stackable": "no se puede juntar en stacks", - "create.item_attributes.not_stackable.inverted": "se puede juntar en stacks", - "create.item_attributes.equipable": "puede ser equipado", - "create.item_attributes.equipable.inverted": "no puede ser equipado", - "create.item_attributes.furnace_fuel": "es combustible", - "create.item_attributes.furnace_fuel.inverted": "no es cumbustible", - "create.item_attributes.washable": "puede Lavarse", - "create.item_attributes.washable.inverted": "no puede Lavarse", - "create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", - "create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", - "create.item_attributes.crushable": "puede ser Triturado", - "create.item_attributes.crushable.inverted": "no puede ser Triturado", - "create.item_attributes.smeltable": "puede ser Derretido", - "create.item_attributes.smeltable.inverted": "no puede ser Derretido", - "create.item_attributes.smokable": "puede ser Ahumado", - "create.item_attributes.smokable.inverted": "no puede ser Ahumado", - "create.item_attributes.blastable": "puede ser cocinado en un Alto Horno", - "create.item_attributes.blastable.inverted": "no puede ser cocinado en un Alto Horno", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "es un shulker %1$s", - "create.item_attributes.shulker_level.inverted": "no es un shulker %1$s", - "create.item_attributes.shulker_level.full": "lleno", - "create.item_attributes.shulker_level.empty": "vacío", - "create.item_attributes.shulker_level.partial": "parcialmente lleno", - "create.item_attributes.in_tag": "tiene el tag %1$s", - "create.item_attributes.in_tag.inverted": "no tiene el tag %1$s", - "create.item_attributes.in_item_group": "está en el grupo '%1$s'", - "create.item_attributes.in_item_group.inverted": "no está en el grupo '%1$s'", - "create.item_attributes.added_by": "fué añadido por %1$s", - "create.item_attributes.added_by.inverted": "no fué añadido por %1$s", - "create.item_attributes.has_enchant": "está encantado con %1$s", - "create.item_attributes.has_enchant.inverted": "no está encantado con %1$s", - "create.item_attributes.color": "está tintado %1$s", - "create.item_attributes.color.inverted": "no está tintado %1$s", - "create.item_attributes.has_fluid": "contiene %1$s", - "create.item_attributes.has_fluid.inverted": "no contiene %1$s", - "create.item_attributes.has_name": "tiene el nombre custom %1$s", - "create.item_attributes.has_name.inverted": "no tiene el nombre custom %1$s", - "create.item_attributes.book_author": "fue escrito por %1$s", - "create.item_attributes.book_author.inverted": "no fue escrito por %1$s", - "create.item_attributes.book_copy_original": "wes un original", - "create.item_attributes.book_copy_original.inverted": "no es un original", - "create.item_attributes.book_copy_first": "es una copia de primera generación", - "create.item_attributes.book_copy_first.inverted": "no es una copia de primera generación", - "create.item_attributes.book_copy_second": "es una copia de segunda generación", - "create.item_attributes.book_copy_second.inverted": "no es una copia de segunda generación", - "create.item_attributes.book_copy_tattered": "es un desastre", - "create.item_attributes.book_copy_tattered.inverted": "no es un desastre", - "create.item_attributes.astralsorcery_amulet": "mejora %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "no mejora %1$s", - "create.item_attributes.astralsorcery_constellation": "está en sintonía con la constelación %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "no está en sintonía con la constelación %1$s", - "create.item_attributes.astralsorcery_crystal": "tiene el atributo de cristal %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "no tiene el atributo de cristal %1$s", - "create.item_attributes.astralsorcery_perk_gem": "tiene el atributo de mejora %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "no tiene el atributo de mejora %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Sin atributos seleccionados", - "create.gui.attribute_filter.selected_attributes": "Atributos seleccionados:", - "create.gui.attribute_filter.add_attribute": "Añadir atributo a la Lista", - "create.gui.attribute_filter.add_inverted_attribute": "Añadir atributo inverso a la Lista", - "create.gui.attribute_filter.allow_list_disjunctive": "Lista Permitida (Cualquiera)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Los objetos pasan si cumplen con uno de los atributos de la lista.", - "create.gui.attribute_filter.allow_list_conjunctive": "Lista Permitida (Todos)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Los objetos pasas si cumplen con TODOS los atributos de la lista.", - "create.gui.attribute_filter.deny_list": "Lista Denegada", - "create.gui.attribute_filter.deny_list.description": "Los objetos pasan si NO tienen ninguno de los atributos de la lista.", - "create.gui.attribute_filter.add_reference_item": "Añadir Objeto de Referencia", - - "create.tooltip.holdForDescription": "Mantén [%1$s] para Resumen", - "create.tooltip.holdForControls": "Mantén [%1$s] para Controles", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Requqrimiento de Velocidad: %1$s", - "create.tooltip.speedRequirement.none": "Ninguno", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "Moderado", - "create.tooltip.speedRequirement.fast": "Rápido", - "create.tooltip.stressImpact": "Impacto en el Estrés Cinético: %1$s", - "create.tooltip.stressImpact.low": "Bajo", - "create.tooltip.stressImpact.medium": "Moderado", - "create.tooltip.stressImpact.high": "Alto", - "create.tooltip.stressImpact.overstressed": "Sobreestresado", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Capacidad de Estrés Cinético: %1$s", - "create.tooltip.capacityProvided.low": "Pequeña", - "create.tooltip.capacityProvided.medium": "Mediana", - "create.tooltip.capacityProvided.high": "Grande", - "create.tooltip.generationSpeed": "Genera a %1$s %2$s", - "create.tooltip.analogStrength": "Fuerza Análoga: %1$s/15", - - "create.mechanical_arm.extract_from": "Toma objetos desde %1$s", - "create.mechanical_arm.deposit_to": "Deposita objetos en %1$s", - "create.mechanical_arm.summary": "Brazo Mecánico tiene %1$s entreda(s) y %2$s salida(s).", - "create.mechanical_arm.points_outside_range": "%1$s punto(s) de interacción seleccionados removidos debido a limitaciones de rango.", - - "create.weighted_ejector.target_set": "Objetivo Seleccionado", - "create.weighted_ejector.target_not_valid": "Eyectando a bloque adyacente (El objetivo no era Válido)", - "create.weighted_ejector.no_target": "Eyectando a bloque adyacente (Sin objetivo Seleccionado)", - "create.weighted_ejector.targeting": "Eyectando a [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Tamaño del stack eyectado", - - "create.logistics.when_multiple_outputs_available": "Cuando hay varias salidas disponibles", - - "create.mechanical_arm.selection_mode.round_robin": "Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "Round Robin Forzado", - "create.mechanical_arm.selection_mode.prefer_first": "Preferir Primer Objetivo", - - "create.tunnel.selection_mode.split": "Separar", - "create.tunnel.selection_mode.forced_split": "Separar Forzado", - "create.tunnel.selection_mode.round_robin": "Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "Round Robin Forzado", - "create.tunnel.selection_mode.prefer_nearest": "Preferir el Más Cercano", - "create.tunnel.selection_mode.randomize": "Aleatorizar", - "create.tunnel.selection_mode.synchronize": "Sincronizar Salidas", - - "create.tooltip.chute.header": "Información del Tolvogán", - "create.tooltip.chute.items_move_down": "Objetos van hacia Abajo", - "create.tooltip.chute.items_move_up": "Objetos van hacia Arriba", - "create.tooltip.chute.no_fans_attached": "Sin Ventiladores Adjuntos", - "create.tooltip.chute.fans_push_up": "Ventiladores empujando desde Abajo", - "create.tooltip.chute.fans_push_down": "Ventiladores empujando desde Arriba", - "create.tooltip.chute.fans_pull_up": "Ventiladores tirando desde arriba", - "create.tooltip.chute.fans_pull_down": "Ventiladores tirando desde abajo", - "create.tooltip.chute.contains": "Contiene: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Actualmente distribuyendo:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Click-Derecho para recuperar", - - "create.linked_controller.bind_mode": "Modo de vinculación activado", - "create.linked_controller.press_keybind": "Presiona %1$s, %2$s, %3$s, %4$s, %5$s o %6$s, para vincular esta frecuencia a la tecla respectiva", - "create.linked_controller.key_bound": "Frequencia vinculada a %1$s", - "create.linked_controller.frequency_slot_1": "Tecla vinculada: %1$s, Frec. #1", - "create.linked_controller.frequency_slot_2": "Tecla vinculada: %1$s, Frec. #2", - - "create.crafting_blueprint.crafting_slot": "Ranura de Ingredientes", - "create.crafting_blueprint.filter_items_viable": "Los Objetos de Filtro Avanzados son viables", - "create.crafting_blueprint.display_slot": "Ranura de Visualización", - "create.crafting_blueprint.inferred": "Inferido de la Receta", - "create.crafting_blueprint.manually_assigned": "Manualmente Asignado", - "create.crafting_blueprint.secondary_display_slot": "Ranura de Visualización Secundaria", - "create.crafting_blueprint.optional": "Opcional", - - "create.potato_cannon.ammo.attack_damage": "%1$s Daño de Ataque", - "create.potato_cannon.ammo.reload_ticks": "%1$s Ticks de Recarga", - "create.potato_cannon.ammo.knockback": "%1$s Retroceso", - - "create.hint.hose_pulley.title": "Suministro sin Fin", - "create.hint.hose_pulley": "El Fluido Objetivo se considera Infinito.", - "create.hint.mechanical_arm_no_targets.title": "Sin Objetivos", - "create.hint.mechanical_arm_no_targets": "Parece que a este _Brazo_ _Mecánico_ no se le asignó ningun _objetivo._ Selecciona cintas, depósitos, ingresos y otros bloques haciendo _click-derecho_ sobre ellos mientras _sostienes_ el _Brazo_ _Mecánico_ en tu _mano_.", - "create.hint.empty_bearing.title": "Actualizar Rodamiento", - "create.hint.empty_bearing": "Haz _Click-Derecho_ en el rodamiento con tu _mano_ _vacía_ para _unir_ la estructura que acabas de construir frente a él.", - "create.hint.full_deployer.title": "Desbordamiento de objetos del Desplegador", - "create.hint.full_deployer": "Parece que este _Desplegador_ contiene _objetos_ de _exceso_ que requieren ser _extraídos._ Usa una _tolva,_ _tolvogán_ u otros parecidos para librarlo del sobreflujo.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "Hola :)", - "create.gui.config.overlay2": "Este es un overlay de ejemplo", - "create.gui.config.overlay3": "Haz clic o arrastra con el mouse", - "create.gui.config.overlay4": "para mover esta previsualización", - "create.gui.config.overlay5": "Presiona ESC para salir de esta pantalla", - "create.gui.config.overlay6": "y guardar la nueva posición", - "create.gui.config.overlay7": "Ejecuta /create overlay reset", - "create.gui.config.overlay8": "para restablecer a la posición predeterminada", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Los ticks del servidor están actualmente siendo ralentizados por %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Los ticks del servidor se ralentizan por %s ms ahora >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Los ticks del servidor han vuelto a la velocidad normal :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: usa /killtps stop para devolver a los ticks del servidor a la velocidad normal", - "create.command.killTPSCommand.status.usage.1": "[Create]: usa /killtps start para ralentizar artificialmente los ticks del servidor", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Esta contrapción de vagoneta parece demasiado grande para recogerla", - "create.contraption.minecart_contraption_illegal_pickup": "Una fuerza mística está vinculando esta contrapción de vagoneta al mundo", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Contrapción se detiene", - "create.subtitle.peculiar_bell_use": "Campana Peculiar tañe", - "create.subtitle.worldshaper_place": "El Forma Mundos zapea", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "Sierra Mecánica se activa", - "create.subtitle.schematicannon_finish": "Esquemacañón campanea", - "create.subtitle.crafter_craft": "Crafteador craftea", - "create.subtitle.wrench_remove": "Componente se rompe", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "Engranajes suenan", - "create.subtitle.slime_added": "Slime chapotea", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "Esquemacañón dispara", - "create.subtitle.controller_take": "Atril se Vacía", - "create.subtitle.crafter_click": "Crafteador cliquea", - "create.subtitle.depot_plop": "Objeto aterriza", - "create.subtitle.confirm": "Ding afirmativo", - "create.subtitle.mixing": "Sonidos de mezcla", - "create.subtitle.mechanical_press_activation_belt": "Prensa Mecánica hace bonk", - "create.subtitle.fwoomp": "Lanza Patatas hace fwoom", - "create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", - "create.subtitle.crushing_1": "Sonidos de Trituración", - "create.subtitle.depot_slide": "Objeto se desliza", - "create.subtitle.blaze_munch": "Quemador Blaze mastica", - "create.subtitle.funnel_flap": "Ingreso aletea", - "create.subtitle.haunted_bell_use": "Campana Embrujada tañe", - "create.subtitle.scroll_value": "Sonidos de Clic", - "create.subtitle.controller_put": "Controlador golpetea", - "create.subtitle.cranking": "Manivela gira", - "create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", - "create.subtitle.wrench_rotate": "Llave Inglesa usada", - "create.subtitle.potato_hit": "Impactos vegetales", - "create.subtitle.saw_activate_wood": "Sierra Mecánica se activa", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "Campana Embrujada despierta", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "Boop denegante", - "create.subtitle.controller_click": "Controlador cliquea", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "Equipo de Buceo tintinea", - "create.subtitle.mechanical_press_activation": "Prensa Mecánica aplasta", - "create.subtitle.contraption_assemble": "Contración se mueve", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "SAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "SOPORTE DE MADERA", - "block.create.wooden_bracket.tooltip.summary": "_Decora_ tus _Ejes, Engranajes_ y _Tuberías_ con un acogedor refuerzo de madera.", - - "block.create.metal_bracket.tooltip": "SOPORTE DE METAL", - "block.create.metal_bracket.tooltip.summary": "_Decora_ tus _Ejes, Engranajes_ y _Tuberías_ con un robusto refuerzo industrial.", - - "block.create.seat.tooltip": "ASIENTO", - "block.create.seat.tooltip.summary": "¡Sientate y Disfruta del viaje! Anclará a un jugador en una _contrapción_ que se mueve. ¡Genial como mueve estático también! Viene en una variedad de colores.", - "block.create.seat.tooltip.condition1": "Click derecho en el Asiento", - "block.create.seat.tooltip.behaviour1": "Sienta al Jugador en el _Asiento_. Pulsa Shift-Izquierdo para dejar el _Asiento_.", - - "item.create.blaze_cake.tooltip": "PASTEL BLAZE", - "item.create.blaze_cake.tooltip.summary": "Un delicioso manjar para tus _Quemadores Blaze_. ¡Los pone en llamas!", - - "item.create.wand_of_symmetry.tooltip": "VARA DE SIMETRÍA", - "item.create.wand_of_symmetry.tooltip.summary": "Refleja perfectamente la ubicación de los bloques en los planos configurados.", - "item.create.wand_of_symmetry.tooltip.condition1": "En la Barra Rápida", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Se mantiene Activo", - "item.create.wand_of_symmetry.tooltip.control1": "Click-Derecho en el Suelo", - "item.create.wand_of_symmetry.tooltip.action1": "_Crea_ o _Mueve_ el Espejo", - "item.create.wand_of_symmetry.tooltip.control2": "Click-Derecho en el Aire", - "item.create.wand_of_symmetry.tooltip.action2": "_Remueve_ el Espejo activo", - "item.create.wand_of_symmetry.tooltip.control3": "Click-Derecho mientras te agachas", - "item.create.wand_of_symmetry.tooltip.action3": "Abre la _Interfaz de Configuración_", - - "item.create.handheld_worldshaper.tooltip": "FORMA MUNDOS DE MANO", - "item.create.handheld_worldshaper.tooltip.summary": "Útil herramienta para crear _paisajes_ y _terrenos_.", - "item.create.handheld_worldshaper.tooltip.control1": "Click-Izquierdo en un bloque", - "item.create.handheld_worldshaper.tooltip.action1": "Establece los bloques colocados por la herramienta en el bloque objetivo.", - "item.create.handheld_worldshaper.tooltip.control2": "Click-Derecho en un bloque", - "item.create.handheld_worldshaper.tooltip.action2": "Aplica la _Brocha_ y _Herramienta_ seleccionadas actualmente en la ubicación designada.", - "item.create.handheld_worldshaper.tooltip.control3": "Click-Derecho mientras te agachas", - "item.create.handheld_worldshaper.tooltip.action3": "Abre la _Interfaz de Configuración_", - - "item.create.tree_fertilizer.tooltip": "FERTILIZANTE ARBÓREO", - "item.create.tree_fertilizer.tooltip.summary": "Una poderosa combinación de minerales adecuada para acelerar el crecimiento de árboles comunes.", - "item.create.tree_fertilizer.tooltip.condition1": "Cuando se usa en un Brote", - "item.create.tree_fertilizer.tooltip.behaviour1": "Crece árboles _sin importar_ sus _condiciones de espacio_", - - "item.create.extendo_grip.tooltip": "AGARREXTENSOR", - "item.create.extendo_grip.tooltip.summary": "¡Boioioing! _Aumenta fuertemente el alcance_ del portador. Se puede alimentar con Aire Comprimido de una _Mochila-Tanque_ de _Cobre_", - "item.create.extendo_grip.tooltip.condition1": "En la mano contraria", - "item.create.extendo_grip.tooltip.behaviour1": "Aumenta el _alcance_ de los objetos usados en la _Mano Principal_.", - "item.create.extendo_grip.tooltip.condition2": "Mientras se utiliza una Mochila-Tanque", - "item.create.extendo_grip.tooltip.behaviour2": "_No_ se usará _durabilidad_. En cambio, _Aire_ _comprimido_ es drenado del Tanque", - - "item.create.potato_cannon.tooltip": "CAÑON DE PAPAS", - "item.create.potato_cannon.tooltip.summary": "¡Fwoomp! Lanza tus verduras cosechadas en casa a tus enemigos. Se puede alimentar con Aire Comprimido de una _Mochila-Tanque_ de _Cobre_", - "item.create.potato_cannon.tooltip.condition1": "Al hacer Click-Derecho", - "item.create.potato_cannon.tooltip.behaviour1": "_Dispara_ un objeto aceptable de tu _Inventario_.", - "item.create.potato_cannon.tooltip.condition2": "Mientras se usa una Mochila-Tanque", - "item.create.potato_cannon.tooltip.behaviour2": "_No_ se usará _durabilidad_. En cambio, _Aire_ _comprimido_ es drenado del Tanque", - - "item.create.filter.tooltip": "FILTRO", - "item.create.filter.tooltip.summary": "_Controla salidas_ y _entradas_ de dispositivos logísticos con más _precisión_, comparándolos contra un _grupo de objetos_ o varios _filtros_.", - "item.create.filter.tooltip.condition1": "En la ranura del filtro", - "item.create.filter.tooltip.behaviour1": "_Controla_ el flujo de objetos dependiendo de su _configuración_.", - "item.create.filter.tooltip.condition2": "Al hacer Click-Derecho", - "item.create.filter.tooltip.behaviour2": "Abre la _interfaz de configuración_.", - - "item.create.attribute_filter.tooltip": "FILTRO DE ATRIBUTOS", - "item.create.attribute_filter.tooltip.summary": "_Controla salidas_ y _entradas_ de dispositivos logísticos con más _precisión_, comparándolos contra un _grupo de atributos de objetos_ o varias _categorías_.", - "item.create.attribute_filter.tooltip.condition1": "En la ranura de filtro", - "item.create.attribute_filter.tooltip.behaviour1": "_Controla_ el flujo de objetos dependiendo de su _configuración_.", - "item.create.attribute_filter.tooltip.condition2": "Al hacer Click-Derecho", - "item.create.attribute_filter.tooltip.behaviour2": "Abre la _interfaz de configuración_.", - - "item.create.empty_schematic.tooltip": "ESQUEMA VACÍO", - "item.create.empty_schematic.tooltip.summary": "Se utiliza como ingrediente de receta y para escribir en la _Mesa de Esquemas_.", - - "item.create.schematic.tooltip": "ESQUEMA", - "item.create.schematic.tooltip.summary": "Contiene una estructura para ser posicionada y colocada en el mundo. Coloca el holograma como desees y usa un _Esquemacañón_ para construirlo.", - "item.create.schematic.tooltip.condition1": "Al sostenerlo", - "item.create.schematic.tooltip.behaviour1": "Se puede colocar usando las herramientas en pantalla.", - "item.create.schematic.tooltip.control1": "Click-Derecho mientras te agachas", - "item.create.schematic.tooltip.action1": "Abre una _Interfaz_ para ingresar _Coordenadas_ exactas.", - - "item.create.schematic_and_quill.tooltip": "ESQUEMA Y PLUMA", - "item.create.schematic_and_quill.tooltip.summary": "Se utiliza para guardar una estructura de tu mundo en un archivo .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Paso 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selecciona dos esquinas opuestas haciendo Click-Derecho", - "item.create.schematic_and_quill.tooltip.condition2": "Paso 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Rueda_ en las caras para ajustar el tamaño. Click-Derecho otra vez para guardar.", - "item.create.schematic_and_quill.tooltip.control1": "Click-Derecho", - "item.create.schematic_and_quill.tooltip.action1": "Selecciona una esquina / confirmar guardado.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Mantenido", - "item.create.schematic_and_quill.tooltip.action2": "Selecciona puntos en el _aire_. _Rueda_ para ajustar la distancia.", - "item.create.schematic_and_quill.tooltip.control3": "Click-Derecho mientras te agachas", - "item.create.schematic_and_quill.tooltip.action3": "_Reinicia_ y remueve la selección.", - - "block.create.schematicannon.tooltip": "ESQUEMACAÑÓN", - "block.create.schematicannon.tooltip.summary": "Dispara bloques para recrear un _Esquema_ desplegado en el Mundo. Utiliza objetos de inventarios adyacentes y _Pólvora_ como combustible.", - "block.create.schematicannon.tooltip.condition1": "Al hacer Click-Derecho", - "block.create.schematicannon.tooltip.behaviour1": "Abre la _Interfaz_", - - "block.create.schematic_table.tooltip": "MESA DE ESQUEMAS", - "block.create.schematic_table.tooltip.summary": "Escribe esquemás guardados en un _Esquema Vacío_.", - "block.create.schematic_table.tooltip.condition1": "Al darle un Esquema Vacío", - "block.create.schematic_table.tooltip.behaviour1": "Carga un archivo elegido de tu carpeta de esquemas.", - - "item.create.goggles.tooltip": "LENTES", - "item.create.goggles.tooltip.summary": "Un par de anteojos para aumentar tu visión con _información cinética_ util.", - "item.create.goggles.tooltip.condition1": "Al equiparlas", - "item.create.goggles.tooltip.behaviour1": "Muestra _indicadores de colores_ correspondientes al _Nivel de Velocidad_ de un componente cinético colocado, así como el _Impacto de Estrés_ y la _Capacidad_ de los componentes individuales.", - "item.create.goggles.tooltip.condition2": "Al mirar un indicador", - "item.create.goggles.tooltip.behaviour2": "Muestra información detallada sobre la _Velocidad_ o el _Estrés_ de la red a la que el medidor está conectado.", - "item.create.goggles.tooltip.condition3": "Al mirar contenedores de fluidos", - "item.create.goggles.tooltip.behaviour3": "Muestra información detallada sobre la _Capacidad_ del bloque y de cualquier _Fluido_ guardado dentro.", - - "item.create.wrench.tooltip": "LLAVE INGLESA", - "item.create.wrench.tooltip.summary": "Una útil herramienta para trabajar en contrapciones. Puede _Rotar_, _Desmantelar_ y _Configurar_ componentes.", - "item.create.wrench.tooltip.control1": "Click-Derecho en un componente cinético", - "item.create.wrench.tooltip.action1": "_Rota componentes_ hacia o lejos de la cara en la que se interactuó.", - "item.create.wrench.tooltip.control2": "Click-Derecho mientras te agachas", - "item.create.wrench.tooltip.action2": "_Desmantela componentes Cinéticos_ y los devuelve a _tu inventario_.", - - "block.create.nozzle.tooltip": "BOQUILLA", - "block.create.nozzle.tooltip.summary": "Ponla en frende de un _Ventilador_ Para distribuir su efecto en Entidades en _todas direcciones_.", - - "block.create.cuckoo_clock.tooltip": "RELOJ CU-CU", - "block.create.cuckoo_clock.tooltip.summary": "Artesanía fina para _decorar_ un espacio y _hacer un seguimiento del tiempo_.", - "block.create.cuckoo_clock.tooltip.condition1": "Al darle energía cinética", - "block.create.cuckoo_clock.tooltip.behaviour1": "Muestra la _hora actual_ y toca una melodía dos veces al día. _Se activa_ una vez al _mediodía_ y al anochecer, apenas los _jugadores puedan dormir_.", - - "block.create.turntable.tooltip": "PLATO GIRATORIO", - "block.create.turntable.tooltip.summary": "Convierte la _Fuerza Rotacional_ en Cinetosis refinada .", - - "block.create.toolbox.tooltip": "CAJA DE HERRAMIENTAS", - "block.create.toolbox.tooltip.summary": "La compañía mas querida de todo inventor. Convenientemente _sostiene_ una gran cantidad de _8 Diferentes_ tipos de objeto.", - "block.create.toolbox.tooltip.condition1": "Al recogerla", - "block.create.toolbox.tooltip.behaviour1": "_Mantiene_ los _Contenidos_ del inventario .", - "block.create.toolbox.tooltip.condition2": "Al colocarla en un rango", - "block.create.toolbox.tooltip.behaviour2": "_Jugadores_ _Cercanos_ pueden mantener la _tecla_ de la _Caja de Herramientas_ para acceder a sus contenidos _Remotamente_.", - "block.create.toolbox.tooltip.condition3": "Al hacer Click-Derecho", - "block.create.toolbox.tooltip.behaviour3": "Abre la _Interfaz de Contenedor_.", - - "block.create.stockpile_switch.tooltip": "INTERRUPTOR DE RESERVAS", - "block.create.stockpile_switch.tooltip.summary": "Da una señal de redstone basado en cuántos _Objetos Guardados_ o _Fluidos_ hay en el contenedor adjunto. Viene con un útil filtro. A diferencia de un _Comparador,_ el _Interruptor de Reservas_ permite configurar los _límites,_ a los cuales las señales se invierten.", - "block.create.stockpile_switch.tooltip.condition1": "Al hacer Click-Derecho", - "block.create.stockpile_switch.tooltip.behaviour1": "Abre la _Interfaz de Configuración_.", - - "block.create.content_observer.tooltip": "OBSERVADOR DE CONTENIDOS", - "block.create.content_observer.tooltip.summary": "_Detecta Objetos_ o _Fluidos_ dentro de _contenedores_, _tuberías_ o _transportadores_ haciendo coincidir un _filtro_ configurado.", - "block.create.content_observer.tooltip.condition1": "Al observar un contenedor", - "block.create.content_observer.tooltip.behaviour1": "Emite una _Señal de Redstone_ mientras que el contenedor observado tenga _contenido_ _coincidible_.", - "block.create.content_observer.tooltip.condition2": "Al observar un Ingreso", - "block.create.content_observer.tooltip.behaviour2": "Emite un _Pulso de Redstone_ cuando un objeto _coincidible_ es _transferido_.", - - "block.create.creative_crate.tooltip": "EL CAJON SIN FIN", - "block.create.creative_crate.tooltip.summary": "Este _Contenedor de Objetos_ permite la replicación infinita de cualquier objeto. Ponlo al lado de un _Esquemacañón_ para remover cualquier requerimiento material.", - "block.create.creative_crate.tooltip.condition1": "Cuando un objeto está en la ranura del filtro", - "block.create.creative_crate.tooltip.behaviour1": "Cualquier cosa que _extraiga_ de este contenedor dará una _Fuente Infinita_ del objeto especificado. Objetos _insertados_ dentro del cajón serán _Eliminados._", - - "item.create.creative_blaze_cake.tooltip": "PASTEL CREATIVO", - "item.create.creative_blaze_cake.tooltip.summary": "Un verdadero manjar para tus _Quemadores Blaze_ que permite _controlar su nivel de calor_. Despues de comer este pastel, los Quemadores Blaze _nunca se quedarán sin combustible_.", - "item.create.creative_blaze_cake.tooltip.condition1": "Click-Derecho en el Quemador Blaze", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Bloquea_ el nivel de calor del Quemador. Si se usa de nuevo, _cicla_ el nivel de calor del Quemador", - - "block.create.controller_rail.tooltip": "RAIL CONTROLADOR", - "block.create.controller_rail.tooltip.summary": "Un _raíl propulsado unidireccional_ capaz de _controlar con precisión_ la _velocidad de movimiento_ de una vagoneta.", - "block.create.controller_rail.tooltip.condition1": "Al darle una señal de Redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Acelera_ o _Desacelera_ _vagonetas_ correspondiente a la _fuerza del pulso_. Propaga la señal de redstone a railes controladores adyacentes. Darle poder a dos raíles controladores provocará que los raíles entre estos interpolen su señal.", - - "item.create.sand_paper.tooltip": "PAPEL DE ARENA", - "item.create.sand_paper.tooltip.summary": "Un papel duro que sirve para _pulir materiales_. Puede usarse automaticamente con un Desplegador.", - "item.create.sand_paper.tooltip.condition1": "Al usarlo", - "item.create.sand_paper.tooltip.behaviour1": "Aplica pulido a objetos en la _mano alternativa_ o que están en el _suelo_ al _mirarlos_", - - "item.create.builders_tea.tooltip": "TE DEL CONSTRUCTOR", - "item.create.builders_tea.tooltip.summary": "La mejor bebida para comenzar tu día- _Motivante_ y _Saturante._", - - "item.create.refined_radiance.tooltip": "RADIANCIA REFINADA", - "item.create.refined_radiance.tooltip.summary": "Un material Cromático forjado con _luz absorbida_.", - "item.create.refined_radiance.tooltip.condition1": "Trabajo en Proceso", - "item.create.refined_radiance.tooltip.behaviour1": "Los usos de este material estarán disponibles en una versión futura.", - - "item.create.shadow_steel.tooltip": "ACERO SOMBRÍO", - "item.create.shadow_steel.tooltip.summary": "Un material Cromático forjado _en el vacío_.", - "item.create.shadow_steel.tooltip.condition1": "Trabajo en Progreso", - "item.create.shadow_steel.tooltip.behaviour1": "Los usos de este material estarán disponibles en una versión futura.", - - "item.create.linked_controller.tooltip": "CONTROLADOR VINCULABLE", - "item.create.linked_controller.tooltip.summary": "Permite _control_ _manual_ sobre frecuencias de un _Enlace de Redstone_ asignadas a sus _seis_ _botones_.", - "item.create.linked_controller.tooltip.condition1": "Click-Derecho", - "item.create.linked_controller.tooltip.behaviour1": "_Alterna_ el controlador. Los _controles_ de _movimiento_ se toman el control mientras está activo.", - "item.create.linked_controller.tooltip.condition2": "Click-Derecho mientras te agachas", - "item.create.linked_controller.tooltip.behaviour2": "Abre el manual _Configuración de Interfaz_.", - "item.create.linked_controller.tooltip.condition3": "Clcik-Derecho en un Receptor de Enlace de Redstone", - "item.create.linked_controller.tooltip.behaviour3": "Activa el _Modo de Enlace_, pulsa uno de los _seis controles_ para vincularlo a una de las _Frecuencias_.", - "item.create.linked_controller.tooltip.condition4": "Click-Derecho en un atril", - "item.create.linked_controller.tooltip.behaviour4": "Coloca el controlador en el atril para una activación más sencilla. (Click-Derecho mientras te agashas para recuperarlo)", - - "item.create.diving_helmet.tooltip": "CASCO DE BUCEO", - "item.create.diving_helmet.tooltip.summary": "Junto con un _Tanque_ de _Cobre_, permite al portados _respirar_ bajo el _agua_ por un periodo de tiempo extendido", - "item.create.diving_helmet.tooltip.condition1": "Al equiparlo", - "item.create.diving_helmet.tooltip.behaviour1": "Da el efecto de _Respiración Acuática_, drenando _Aire Comprimido_ lentamente del Tanque.", - - "item.create.copper_backtank.tooltip": "TANQUEMOCHILA DE COBRE", - "item.create.copper_backtank.tooltip.summary": "Un _Tanque_ _Equipable_ para llevar Aire Comprimido.", - "item.create.copper_backtank.tooltip.condition1": "Al Equiparlo", - "item.create.copper_backtank.tooltip.behaviour1": "Proporciona _Aire_ _Comprimido_ al Equipamiento que lo requiere.", - "item.create.copper_backtank.tooltip.condition2": "Al colocarlo, y darle Cinética", - "item.create.copper_backtank.tooltip.behaviour2": "_Recolecta_ _Aire_ _Comprimido_ a una velocidad dependiente de la velocidad de rotación.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "BOTAS DE BUCEO", - "item.create.diving_boots.tooltip.summary": "Un par de _botas_ _pesadas_, permitiendo un mejor recorrido del suelo oceánico.", - "item.create.diving_boots.tooltip.condition1": "Al equiparlas", - "item.create.diving_boots.tooltip.behaviour1": "El portador se _hunde_ _rápido_ y _no puede_ _nadar_. Permite la habilidad de _caminar_ y _saltar_ bajo el agua. El portador tampoco es afectado por las _Cintas_ _Transportadoras_.", - - "item.create.crafting_blueprint.tooltip": "PLANO DE FABRICACIÓN", - "item.create.crafting_blueprint.tooltip.summary": "_Colocado_ en una pared, de puede usar para _especificar_ _orden_ de _ingredientes_ para un crafteo manual mas sencillo. Cada espacio representa una receta.", - "item.create.crafting_blueprint.condition1": "Click-Derecho en un espacio vacío", - "item.create.crafting_blueprint.behaviour1": "Abre un _Menú_ de _Crafteo_ permitiendote _configurar_ una _receta_ y objetos a mostrar.", - "item.create.crafting_blueprint.condition2": "Click-Derecho en un espacio configurado", - "item.create.crafting_blueprint.behaviour2": "_Aplica_ la _receta_ _configurada_ con ingredientes coincidentes que se encuentren en tu _Inventario_. _Agachate_ para craftear un _Stack_ de objetos.", - - "item.create.minecart_coupling.tooltip": "UNION DE VAGONETAS", - "item.create.minecart_coupling.tooltip.summary": "_Encadena_ todas tus _Vagonetas_ o _Contrapciones de Carruago_ juntas para formar un Tren majestuoso.", - "item.create.minecart_coupling.tooltip.condition1": "Al usar en una Vagoneta", - "item.create.minecart_coupling.tooltip.behaviour1": "_Une_ dos Vagonetas juntas, intentando mantenerlas a una _distancia constante_ mientrar se mueven.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "CAMPANA PECULIAR", - "block.create.peculiar_bell.tooltip.summary": "Una _Campana de Latón_ decorativa. Ponerla justo sobre _Fuego de Almas_ podría causar efectos secundarios...", - - "block.create.haunted_bell.tooltip": "CAMPANA EMBRUAJADA", - "block.create.haunted_bell.tooltip.summary": "Una _Campana Embrujada_ perseguida por las almas perdidas del Nether.", - "block.create.haunted_bell.tooltip.condition1": "Al sostenerla o colgarla", - "block.create.haunted_bell.tooltip.behaviour1": "Destaca _Puntos no Iluminados_ cercanos en los que _Criaturas Hostiles_ pueden aparecer.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "Este comportamiento se puede modificar con una llave inglesa", - "create.ponder.shared.storage_on_contraption": "Los inventarios adjuntos a la contrapción recogerán los objetos automáticamente", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "Fuente: 16 RPM", - "create.ponder.shared.movement_anchors": "Con la ayuda de Chasis o La Gotita, se pueden mover estructuras más grandes.", - "create.ponder.tag.redstone": "Componentes Lógicos", - "create.ponder.tag.redstone.description": "Componentes que ayudan con la ingeniería de redstone", - "create.ponder.tag.contraption_assembly": "Utilidad para adjuntar bloques", - "create.ponder.tag.contraption_assembly.description": "Herramientas y componentes utilizados para ensamblar estructuras movibles como una contrapción animada", - "create.ponder.tag.fluids": "Manipuladores de Fluido", - "create.ponder.tag.fluids.description": "Componentes que ayudan a transmitir y hacer uso de los fluidos", - "create.ponder.tag.decoration": "Estética", - "create.ponder.tag.decoration.description": "Componentes usados, generalmente, con un fin estético", - "create.ponder.tag.windmill_sails": "Velas para rodamientos de molino de viento", - "create.ponder.tag.windmill_sails.description": "Bloques que cuentan para calcular la fuerza de una contrapción de molino de viento cuando se ensambla. Todos tienen la misma eficacia.", - "create.ponder.tag.arm_targets": "Objetivos para brazos mecánicos", - "create.ponder.tag.arm_targets.description": "Componentes que se pueden seleccionar como entradas o salidas de brazo mecánico", - "create.ponder.tag.kinetic_appliances": "Aplicaciones Cinéticas", - "create.ponder.tag.kinetic_appliances.description": "Componentes que hacen uso de la Energía rotacional", - "create.ponder.tag.kinetic_sources": "Fuentes Cinéticas", - "create.ponder.tag.kinetic_sources.description": "Componentes que generan fuerza rotacional", - "create.ponder.tag.movement_anchor": "Anclajes de movimiento", - "create.ponder.tag.movement_anchor.description": "Componentes que permiten la creación de contrapciones móviles, animando una estructura adjunta de distintas formas", - "create.ponder.tag.kinetic_relays": "Bloques Cinéticos", - "create.ponder.tag.kinetic_relays.description": "Componentes que ayudan a transmitir la fuerza de rotación a otros lugares", - "create.ponder.tag.contraption_actor": "Actores de Contrapción", - "create.ponder.tag.contraption_actor.description": "Componentes que exponen un comportamiento especial cuando se adjuntan a una contrapción en movimiento", - "create.ponder.tag.creative": "Modo Creativo", - "create.ponder.tag.creative.description": "Componentes no usualmente disponibles en Modo Supervivencia", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "Transportación de Objetos", - "create.ponder.tag.logistics.description": "Componentes que ayudan a mover objetos", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "Controlando señales usando la Palanca Análoga", - "create.ponder.analog_lever.text_1": "Las Palancas Análogas son una fuente compacta y precisa de redstone", - "create.ponder.analog_lever.text_2": "Click-Derecho para incrementar la salida análoga", - "create.ponder.analog_lever.text_3": "Click-Derecho mientras te agachas para decrementar la salida de nuevo", - - "create.ponder.andesite_tunnel.header": "Usando Túneles de Andesita", - "create.ponder.andesite_tunnel.text_1": "Los Túneles de Andesita pueden ser usados para cubrir tus cintas", - "create.ponder.andesite_tunnel.text_2": "Cuando un Túnel de Andesita tiene conexiones laterales...", - "create.ponder.andesite_tunnel.text_3": "...separarán exactamente un objeto de cualquier stack que pase a través", - "create.ponder.andesite_tunnel.text_4": "Lo restante continuará en su camino", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "Procesando Objetos en el tónel", - "create.ponder.basin.text_1": "Un tónel puede sostener Objetos y Fluidos para ser Procesados", - "create.ponder.basin.text_2": "Despues de un procesado, los tóneles intentarán dar salida a un lado y hacia abajo", - "create.ponder.basin.text_3": "Cuando un componente válido está presente, el tónel mostrará un grifo de salida", - "create.ponder.basin.text_4": "Un número de opciones son aplicables aqui", - "create.ponder.basin.text_5": "Los objetos salientes serán atrapados por el inventario debajo", - "create.ponder.basin.text_6": "Sin un grifo, el tónel retendra los objetos procesados dentro", - "create.ponder.basin.text_7": "Esto puede ser útil si los resultados deben ser reusados como ingredientes", - "create.ponder.basin.text_8": "Los objetos de salida deseados tendrán que ser retirados del tónel", - "create.ponder.basin.text_9": "Un Filtro podría ser necesario para evitar sacar objetos sin procesar", - - "create.ponder.bearing_modes.header": "Modos de movimiento del Rodamiento Mecánico", - "create.ponder.bearing_modes.text_1": "Al ser detenido, el Rodamiento colocará la estructura en el ángulo alineado más cercano", - "create.ponder.bearing_modes.text_2": "Puede ser configurado que nunca se vuela a bloques sólidos, o solo hacerlo cerca del ángulo inicial", - - "create.ponder.belt_casing.header": "Cubriendo Cintas", - "create.ponder.belt_casing.text_1": "Cubiertas de Latón y Andesita pueden usarse para decorar tus Cintas Mecánicas", - "create.ponder.belt_casing.text_2": "Una llave inglesa se puede usar para remover la cubierta", - - "create.ponder.belt_connector.header": "Usando Cintas Mecánicas", - "create.ponder.belt_connector.text_1": "Haciendo Click-Derecho en dos ejes con una cinta en la mano los conectará", - "create.ponder.belt_connector.text_2": "Las selecciones equivocadas pueden ser eliminadas con Click-Derecho mientras te agachas", - "create.ponder.belt_connector.text_3": "Ejes Adicionales se pueden añadir a lo largo de la cinta", - "create.ponder.belt_connector.text_4": "Los ejes conectados via Cintas rotarán con Velocidad y Dirección idénticas", - "create.ponder.belt_connector.text_5": "los Ejes adicionales se pueden remover con la Llave Inglesa", - "create.ponder.belt_connector.text_6": "Las Cintas Mecánicas se pueden tintar para fines estéticos", - - "create.ponder.belt_directions.header": "Orientaciones Válidas para las Cintas Mecánicas", - "create.ponder.belt_directions.text_1": "Las cintas no se pueden conectar en direcciones arbitrarias", - "create.ponder.belt_directions.text_2": "1. Se conectan horizontalmente", - "create.ponder.belt_directions.text_3": "2. Se conectan diagonalmente", - "create.ponder.belt_directions.text_4": "3. Se conectan verticalmente", - "create.ponder.belt_directions.text_5": "4. Y pueden conectar Ejes verticales Horizontalmente", - "create.ponder.belt_directions.text_6": "Esas son todas las direcciones posibles. Las cintas pueden unir cualquier distancia entre 2 y 20 bloques", - - "create.ponder.belt_transport.header": "Usando Cintas Mecánicas para Logisticas", - "create.ponder.belt_transport.text_1": "Las cintas que se mueven pueden transportar objetos y entidades", - "create.ponder.belt_transport.text_2": "Hacer Click-Derecho con una mano vacía sacará los objetos de la cinta", - - "create.ponder.blaze_burner.header": "Alimentando Quemadores Blaze", - "create.ponder.blaze_burner.text_1": "Los Quemadores Blaze dan calor a los objetos para ser procesados en el tónel", - "create.ponder.blaze_burner.text_2": "Para esto, deber alimentar al Blaze con objetos combustibles", - "create.ponder.blaze_burner.text_3": "Con un Pastel Blaze, el Quemador puede alcanzar un nivel incluso mayor de calor", - "create.ponder.blaze_burner.text_4": "El proceso de alimentación puede ser automatizado usando Desplegadores o Brazos Mecánicos", - - "create.ponder.brass_funnel.header": "El Ingreso de Latón", - "create.ponder.brass_funnel.text_1": "Los Ingresos de Andesita solo pueden retirar 1 objeto a la vez.", - "create.ponder.brass_funnel.text_2": "Los Ingresos de Latón pueden extraer hasta un Stack completo.", - "create.ponder.brass_funnel.text_3": "Rodando por la ranura de filtro permite mayor control sobre el tamaño del stack extraído.", - "create.ponder.brass_funnel.text_4": "Usar objetos en la ranura de filtro restringirá el ingreso a solo transferir ese tipo de objeto", - - "create.ponder.brass_tunnel.header": "Usando Túneles de Latón", - "create.ponder.brass_tunnel.text_1": "Los Túneles de Latón se pueden usar para cubrir tus Cintas", - "create.ponder.brass_tunnel.text_2": "Los Túneles de Latón tienen ranuras para filtros en cada lado abierto", - "create.ponder.brass_tunnel.text_3": "Los Filtros en conexiones entrantes simplemente bloquean los elementos que no coinciden", - "create.ponder.brass_tunnel.text_4": "Los Filtros en conexiones pueden ser usados para organizar los objetos", - "create.ponder.brass_tunnel.text_5": "Cuando un objeto tiene varias salidas posibles, el modo de distribución decidirá como manejarlo", - "create.ponder.brass_tunnel.text_6": "Los túneles de latón en cinturones paralelos formarán un grupo", - "create.ponder.brass_tunnel.text_7": "Los objetos entrantes ahora serán distribuidos por todas las salidas disponibles", - "create.ponder.brass_tunnel.text_8": "Para esto, los objetos también pueden ser insertados en el bloque de Túnel directamente", - - "create.ponder.brass_tunnel_modes.header": "Modos de Distribución del Túnel de Latón", - "create.ponder.brass_tunnel_modes.text_1": "Usando una Llave, el comporatamiento de la ddistribución de los Túneles de Latón se puede configurar", - "create.ponder.brass_tunnel_modes.text_10": "'Sincronizar Salidas' es una opción única de los Túneles de Latón", - "create.ponder.brass_tunnel_modes.text_11": "Los objetos solo pueden pasar si todos los Túneles en el grupo tienen un objetos en espera", - "create.ponder.brass_tunnel_modes.text_12": "Esto te asegura que todas las cintas suministran objetos a la vez", - "create.ponder.brass_tunnel_modes.text_2": "'Seprarar' intentará distribuir el stack de manera uniforme por todas las salidsa", - "create.ponder.brass_tunnel_modes.text_3": "Si una salida no puede recibir más objetos, será saltada", - "create.ponder.brass_tunnel_modes.text_4": "'Separar Forzado' nunca se saltará salidas, y esperará a que todas estén libres", - "create.ponder.brass_tunnel_modes.text_5": "'Round Robin' mantiene los stacks completos, y los cicla iterativamente a traves de las salidas", - "create.ponder.brass_tunnel_modes.text_6": "Otra Vez, si una salida no puede recibir más objetos, será saltada", - "create.ponder.brass_tunnel_modes.text_7": "'Round Robin Forzado' nunca se salta salidas", - "create.ponder.brass_tunnel_modes.text_8": "'Preferir Cercano' prioritiza las salidas más cercanas de la ubicacion de entrada del objeto", - "create.ponder.brass_tunnel_modes.text_9": "'Aleatorizar' distribuirá los stacks completos al azar entre las salidas", - - "create.ponder.cart_assembler.header": "Moviendo Estructuras usando la Ensambladora de Vagonetas", - "create.ponder.cart_assembler.text_1": "Las Ensambladoras de Vagonetas Potenciadas montan las estructuras adyacentes a las Vagonetas Pasantes", - "create.ponder.cart_assembler.text_2": "Sin una señal de Redstone, desensamblará las contrapciones de vagoneta de vuelta a bloques", - "create.ponder.cart_assembler.text_3": "Usando una Llave en la Vagoneta te permitirá llevar la contrapción a otra parte", - - "create.ponder.cart_assembler_dual.header": "Ensamblando Contrapciones de Carruaje", - "create.ponder.cart_assembler_dual.text_1": "Cuando dos Ensambladores de Vagoneta comparten una estructura adjunta...", - "create.ponder.cart_assembler_dual.text_2": "Darle poder a ambos creará una Contrapción de Carruaje", - "create.ponder.cart_assembler_dual.text_3": "Los carritos se comportarán como los que se conectan via Uniones de Vagoneta", - - "create.ponder.cart_assembler_modes.header": "Configuración de Orientación para las Contrapciones de Vagonetas", - "create.ponder.cart_assembler_modes.text_1": "Las Contrapciones de Vagoneta colo rotarán hacia donde está el movimiento de la vagoneta", - "create.ponder.cart_assembler_modes.text_2": "Esta Flecha indica que lado de la Estructura se considerará el frente", - "create.ponder.cart_assembler_modes.text_3": "Si el Ensamblador está configurado para Bloquear Rotación, la orientación de la contrapción nunca cambiará", - - "create.ponder.cart_assembler_rails.header": "Otros tipos de Vagonetas y Raíles", - "create.ponder.cart_assembler_rails.text_1": "Los Ensambladores de Carrito en las vías normales no afectarán el movimiento de las vagonetas", - "create.ponder.cart_assembler_rails.text_2": "Cuando están en un raíl controlador o potenciado, los carros se mantendrán en su lugar hasta que se encienda", - "create.ponder.cart_assembler_rails.text_3": "Otros tipos de vagonetas se pueden usar como anclaje", - "create.ponder.cart_assembler_rails.text_4": "Los carros con horno se mantendrán alimentados, extrayendo combustible de los inventarios adjuntos", - - "create.ponder.chain_drive.header": "Transmitiendo Fuerza Rotacional con Conductores en Cadena", - "create.ponder.chain_drive.text_1": "Los Conductores en Cadena mantienen la rotación a las otras en fila", - "create.ponder.chain_drive.text_2": "Todos los ejes conectados de esta forma rotarán en la misma dirección", - "create.ponder.chain_drive.text_3": "Cualquier parte de la fila se puede girar en 90 grados", - - "create.ponder.chain_gearshift.header": "Control de la Velocidad de Rotación con la Caja de Cambios en Cadena", - "create.ponder.chain_gearshift.text_1": "Las Cajas de Cambio despotenciadas se comportan igual a los Conductores en Cadena", - "create.ponder.chain_gearshift.text_2": "Al recibir Redstone, la Velocidad transmitida a las otras Cajas de Cambio en la fila es doblada", - "create.ponder.chain_gearshift.text_3": "Cuando la Caja de Cambios no está en la fuente, su velocidad será la mitad", - "create.ponder.chain_gearshift.text_4": "En ambos casos, los Conductores en Cadena en la fila siempre irán al doble la velocidad de las Cajas de Cambios", - "create.ponder.chain_gearshift.text_5": "Usando señales análogas, la razón se puede ajustar más precisamente entre 1 y 2", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "Transportando Objetos a través de Tolvoganes Verticales", - "create.ponder.chute.text_1": "Los tolvoganes pueden transportar artículos verticalmente desde y hacia los inventarios.", - "create.ponder.chute.text_2": "Usando la Llave, una ventana se puede crear", - "create.ponder.chute.text_3": "Colocar tolvoganes apuntando a las caras laterales de otro lo hará diagonal", - - "create.ponder.chute_upward.header": "Transportando objetos hacia arriba usando Tolvoganes", - "create.ponder.chute_upward.text_1": "Usando Ventiladores desde abajo o arriba, un tolvogán puede transportar objetos hacia arriba", - "create.ponder.chute_upward.text_2": "Inspeccionar tolvoganes con los lentes del ingeniero revela información sobre la dirección de movimiento", - "create.ponder.chute_upward.text_3": "'Por el otro lado', los objetos tendrán que ser insertados/retirados por los lados.", - - "create.ponder.clockwork_bearing.header": "Animando estructuras con Rodamientos de Relojería", - "create.ponder.clockwork_bearing.text_1": "Los Rodamientos de Relojería se adjuntan a los bloques en frente", - "create.ponder.clockwork_bearing.text_2": "Al recibir Fuerza Rotacional, la estructura será rotada acorde a la hora del día", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "Haz Click-Derecho en el rodamiento para comenzar o detener la estructura", - "create.ponder.clockwork_bearing.text_6": "En frente del horario, una segunda estructura se puede añadir", - "create.ponder.clockwork_bearing.text_7": "Asegúrate de que las dos estructuras no estén unidas la una a la otra con La Gotita o un similar", - "create.ponder.clockwork_bearing.text_8": "La Segunda Estructura ahora rotará como el Minutero", - - "create.ponder.clutch.header": "Controlando la fuerza Rotacional con un Embrague", - "create.ponder.clutch.text_1": "Los Embragues mantienen la rotación en una línea recta", - "create.ponder.clutch.text_2": "Al ser potenciados con redstone, rompen la conexión", - - "create.ponder.cog_speedup.header": "Cambiando marchas con Engranajes", - "create.ponder.cog_speedup.text_1": "Engranajes grandes y pequeños pueden ser conectados diagonalmente", - "create.ponder.cog_speedup.text_2": "Al cambiar de uno grande a otro pequeño, la velocidad será doblada", - "create.ponder.cog_speedup.text_3": "Al cambiar de uno pequeño a uno grande, la velocidad será la mitad", - - "create.ponder.cogwheel.header": "Transmitiendo Fuerza Rotacional mediante Engranajes", - "create.ponder.cogwheel.text_1": "Los Engranajes transmiten su rotación a los adyacentes", - "create.ponder.cogwheel.text_2": "Los ejes vecinos conectados de esta forma girarán en direcciones opuestas", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "Tanques de Fluido del Creativo", - "create.ponder.creative_fluid_tank.text_1": "Los Tanques de Fluido del Creativo se pueden utilizar para proporcionar un suministro de fluido sin fin", - "create.ponder.creative_fluid_tank.text_2": "Haz Click-Derecho con un objeto que contenga un fluido para configurarlo", - "create.ponder.creative_fluid_tank.text_3": "Las redes de tuberías ahora pueden retirar infinitamente el fluido asignado al tanque", - "create.ponder.creative_fluid_tank.text_4": "Cualquier fluido empujado dentro del tanque será eliminado", - - "create.ponder.creative_motor.header": "Generando Energía Rotacional usando Motores del Creativo", - "create.ponder.creative_motor.text_1": "Los Motores del Creativo son una fuente compacta y configurable de fuerza rotacional.", - "create.ponder.creative_motor.text_2": "Rodar por el panel posterior cambia las RPM de salida de rotación de los motores", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "Procesando Objetos usando Ruedas Trituradoras", - "create.ponder.crushing_wheels.text_1": "Un par de Ruedas Trituradoras pueden triturar objetos muy efectivamente", - "create.ponder.crushing_wheels.text_2": "Su ingreso rotacional tiene que hacerlas girar la una contra la otra", - "create.ponder.crushing_wheels.text_3": "Los objetos insertados o tirados encima serán procesados", - "create.ponder.crushing_wheels.text_4": "Los objetos también se pueden insertar y recoger a través de medios automatizados", - - "create.ponder.deployer.header": "Usando el Desplegador", - "create.ponder.deployer.text_1": "Al darle fuerza rotacional, un Desplegador puede imitar acciones humanas", - "create.ponder.deployer.text_10": "Haz clic con Click-Derecho al frente para entregarle un Objeto", - "create.ponder.deployer.text_11": "Los objetos tambien se pueden entregar Automáticamente", - "create.ponder.deployer.text_12": "Los Desplegadores tienen una ranura de filtro", - "create.ponder.deployer.text_13": "Cuando un filtro es configurado, se activa solo mientras sostiene un elemento coincidente", - "create.ponder.deployer.text_14": "Ahora solo se pueden insertar elementos que coincidan con el filtro...", - "create.ponder.deployer.text_15": "...y solo se extraerán los elementos que no coincidan", - "create.ponder.deployer.text_2": "Siempre interactuará con la pocisión 2 bloques en frente de sí mismo.", - "create.ponder.deployer.text_3": "Los bloques directamente en frente no lo obstruirán", - "create.ponder.deployer.text_4": "Los desplegadores pueden:", - "create.ponder.deployer.text_5": "Poner Bloques,", - "create.ponder.deployer.text_6": "Usar Objetos,", - "create.ponder.deployer.text_7": "Activar Bloques,", - "create.ponder.deployer.text_8": "Cosechar Bloques", - "create.ponder.deployer.text_9": "y Atacar Entidades", - - "create.ponder.deployer_contraption.header": "Usando Desplegadores en Contrapciones", - "create.ponder.deployer_contraption.text_1": "Siempre que los Desplegadores se muevan como parte de una contrapción animada...", - "create.ponder.deployer_contraption.text_2": "Se acivarán en cada localización visitada, usando elementos de inventarios en cualquier lugar del artilugio", - "create.ponder.deployer_contraption.text_3": "La ranura de filtro se puede utilizar para especificar qué elementos extraer", - - "create.ponder.deployer_modes.header": "Modos del Desplegador", - "create.ponder.deployer_modes.text_1": "Por defecto, un Desplegador imita una interacción de Click-Derecho", - "create.ponder.deployer_modes.text_2": "Usando una Llave, se puede configurar para imitar un Click-izquierdo en su lugar", - - "create.ponder.deployer_processing.header": "Procesando Objetos usando Desplegadores", - "create.ponder.deployer_processing.text_1": "Con un Objeto retenido adecuado, los Desplegadores pueden procesar elementos proporcionados debajo de ellos", - "create.ponder.deployer_processing.text_2": "Los Objetos de Entrada se pueden soltar o colocar en un depósito debajo del Desplegador", - "create.ponder.deployer_processing.text_3": "Cuando los objetos pasan por una cinta...", - "create.ponder.deployer_processing.text_4": "El Desplegador los mantendrá y procesará automáticamente", - - "create.ponder.deployer_redstone.header": "Controlando Desplegadores con Redstone", - "create.ponder.deployer_redstone.text_1": "Al potenciarlos con Redstone, los Desplegadores no se Activarán", - "create.ponder.deployer_redstone.text_2": "Antes de detenerse, el Desplegador terminará sus ciclos comenzados", - "create.ponder.deployer_redstone.text_3": "Asi mismo, se puede utilizar un pulso negativo para activar exactamente un ciclo de activación", - - "create.ponder.depot.header": "Usando Depósitos", - "create.ponder.depot.text_1": "Los depósitos pueden servir como elementos de cinta 'estacionarios'", - "create.ponder.depot.text_2": "Haz clic con el Click-Derecho para colocar o eliminar objetos manualmente", - "create.ponder.depot.text_3": "Al igual que las Cintas Mecánicas, pueden proporcionar objetos para procesar.", - "create.ponder.depot.text_4": "...así como proporcionar objetos a los brazos mecánicos", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "Usando Quemadores Blaze vacíos", - "create.ponder.empty_blaze_burner.text_1": "Haz Click-Derecho en un Blaze con el quemador vacío para capturarlo", - "create.ponder.empty_blaze_burner.text_2": "Alternativamente, los Blazes se pueden conseguir directamente del Spawner", - "create.ponder.empty_blaze_burner.text_3": "Ahora tienes una fuente de calor ideal para varias máquinas", - "create.ponder.empty_blaze_burner.text_4": "Para Motivos Estéticos, los Quemadores Vacíos también se pueden encender con un Mechero.", - "create.ponder.empty_blaze_burner.text_5": "La llama se puede transformar con un objeto infundido con almas.", - "create.ponder.empty_blaze_burner.text_6": "Aun así, sin un Blaze no son aptos para la calefacción industrial", - - "create.ponder.encased_fluid_pipe.header": "Encubriendo Tuberías de Fluido", - "create.ponder.encased_fluid_pipe.text_1": "Las Cubiertas de Cobre se pueden utilizar para decorar tus Tuberías de Fluido.", - "create.ponder.encased_fluid_pipe.text_2": "Además de estar ocultas, las tuberías encubiertas se bloquearán en su estado de conectividad", - "create.ponder.encased_fluid_pipe.text_3": "Ya no reaccionará a los bloques vecinos que se agreguen o eliminen.", - - "create.ponder.fan_direction.header": "Flujo de Aire de los Ventiladores", - "create.ponder.fan_direction.text_1": "Los Ventiladores usan el Aire para crear una corriente de aire", - "create.ponder.fan_direction.text_2": "La Fuerza y ​​la Dirección del flujo dependen de la fuerza rotacional entregada", - - "create.ponder.fan_processing.header": "Procesando Objetos Usando Ventiladores", - "create.ponder.fan_processing.text_1": "Al pasar a través de Lava, El Flujo de Aire se vuelve caliente", - "create.ponder.fan_processing.text_2": "Los objetos que pasen a través serán fundidos", - "create.ponder.fan_processing.text_3": "La comida tirada aquí sería incinerada", - "create.ponder.fan_processing.text_4": "En cambio, se debe usar una configuración de ahumado usando fuego.", - "create.ponder.fan_processing.text_5": "Los Flujos de Aire que atraviesen Agua crearán una configuración de lavado", - "create.ponder.fan_processing.text_6": "Se puede hacer algún procesamiento nuevo e interesante con él.", - "create.ponder.fan_processing.text_7": "La velocidad del ventilador NO afecta la velocidad de procesamiento, solo su rango", - "create.ponder.fan_processing.text_8": "El Procesamiento por Ventilador también se puede aplicar a objetos en depósitos y cintas", - - "create.ponder.fluid_pipe_flow.header": "Moviendo fluidos usando Tuberías de Cobre", - "create.ponder.fluid_pipe_flow.text_1": "Las tuberías de fluidos pueden conectar dos o más fuentes de fluidos y objetivos", - "create.ponder.fluid_pipe_flow.text_2": "Con una llave, se puede añadir una ventana a un segmento de tubería recto", - "create.ponder.fluid_pipe_flow.text_3": "Las tuberías con ventana no se conectarán a ningún otro segmento de tubería adyacente.", - "create.ponder.fluid_pipe_flow.text_4": "Alimentadas por bombas mecánicas, las tuberías pueden transportar fluidos.", - "create.ponder.fluid_pipe_flow.text_5": "Ningún fluido se extrae al inicio", - "create.ponder.fluid_pipe_flow.text_6": "Una vez el flujo las conecta, los puntos de conexión transfieren gradualmente su contenido", - "create.ponder.fluid_pipe_flow.text_7": "Por lo tanto, los bloques de tuberías nunca contienen `` físicamente '' ningún fluido.", - - "create.ponder.fluid_pipe_interaction.header": "Drenando y Llenando objetos Contenedores de Fluido", - "create.ponder.fluid_pipe_interaction.text_1": "Los puntos de conexión de una red de tuberías pueden interactuar con una variedad de bloques", - "create.ponder.fluid_pipe_interaction.text_2": "Cualquier bloque con capacidad de almacenamiento de fluidos se puede llenar o drenar", - "create.ponder.fluid_pipe_interaction.text_3": "Se pueden recoger bloques de Fuente justo en frente de un extremo abierto...", - "create.ponder.fluid_pipe_interaction.text_4": "...mientras que se derrama en espacios vacíos puede crear fuentes de fluidos", - "create.ponder.fluid_pipe_interaction.text_5": "Las tuberías también pueden extraer fluidos de un puñado de otros bloques directamente", - - "create.ponder.fluid_tank_sizes.header": "Dimensiones de un Tanque de Fluidos", - "create.ponder.fluid_tank_sizes.text_1": "Los tanques de fluido se pueden combinar para aumentar la capacidad total", - "create.ponder.fluid_tank_sizes.text_2": "Su cuadrado de base puede tener hasta 3 bloques de ancho....", - "create.ponder.fluid_tank_sizes.text_3": "...y pueden crecer en altura en más de 30 capas adicionales", - "create.ponder.fluid_tank_sizes.text_4": "Usando una llave, las ventanas del tanque se pueden alternar", - - "create.ponder.fluid_tank_storage.header": "Guardando Fluidos en Tanques de Fluido", - "create.ponder.fluid_tank_storage.text_1": "Los tanques de Fluido se pueden utilizar para almacenar grandes cantidades de líquidos.", - "create.ponder.fluid_tank_storage.text_2": "Las redes de tuberías pueden empujar y tirar fluidos desde cualquier bloque", - "create.ponder.fluid_tank_storage.text_3": "El líquido contenido se puede medir con un comparador", - "create.ponder.fluid_tank_storage.text_4": "Sin embargo, en el modo Supervivencia, los Fluidos no se pueden agregar ni tomar manualmente", - "create.ponder.fluid_tank_storage.text_5": "Puedes usar tóneles, drenajes y surtidores para drenar o llenar objetos contenedores de líquido", - - "create.ponder.funnel_compat.header": "Compatibilidad de Ingresos", - "create.ponder.funnel_compat.text_1": "Los ingresos también deberían interactuar bien con un puñado de otros componentes.", - "create.ponder.funnel_compat.text_2": "Sierras Verticales", - "create.ponder.funnel_compat.text_3": "Depósitos", - "create.ponder.funnel_compat.text_4": "Drenajes", - - "create.ponder.funnel_direction.header": "Dirección de Tranferencia", - "create.ponder.funnel_direction.text_1": "Colocado normalmente, extrae objetos del inventario.", - "create.ponder.funnel_direction.text_2": "Colocado mientras te agachas, pone objetos en el inventario.", - "create.ponder.funnel_direction.text_3": "Con una Llave Inglesa, el ingreso se puede alternar después de la colocación.", - "create.ponder.funnel_direction.text_4": "Se aplican las mismas reglas para la mayoría de las orientaciones.", - "create.ponder.funnel_direction.text_5": "Los ingresos en las sintas extraerán/insertarán dependiendo de la dirección de movimiento.", - - "create.ponder.funnel_intro.header": "Usando Ingresos", - "create.ponder.funnel_intro.text_1": "Los Ingresos son ideales para transferir artículos desde y hacia inventarios.", - - "create.ponder.funnel_redstone.header": "Control de Restone", - "create.ponder.funnel_redstone.text_1": "Las señales de Redstone evitarán que actúe cualquier ingreso", - - "create.ponder.funnel_transfer.header": "Transferencia Directa", - "create.ponder.funnel_transfer.text_1": "Los Ingresos nunca pueden transferir directamente entre inventarios cerrados.", - "create.ponder.funnel_transfer.text_2": "Los tolvoganes o tolvoganes inteligentes podrían ser más adecuados para tales fines.", - "create.ponder.funnel_transfer.text_3": "Lo mismo se aplica al movimiento horizontal. Una cinta mecánica debería ayudar aquí.", - - "create.ponder.gantry_carriage.header": "Usando Carruajes de Grúa", - "create.ponder.gantry_carriage.text_1": "Los Carruajes de Grúa pueden montarse y deslizarse sobre los Ejes de Grúa.", - "create.ponder.gantry_carriage.text_2": "Las Configuraciones de Carruaje pueden mover bloques adjuntos.", - - "create.ponder.gantry_cascaded.header": "Grúas en cascada", - "create.ponder.gantry_cascaded.text_1": "Los ejes de grúa se adhieren a un carruaje sin la necesidad de La Gotita", - "create.ponder.gantry_cascaded.text_2": "Lo mismo se aplica a los carruajes en ejes de grúa movidos", - "create.ponder.gantry_cascaded.text_3": "Por lo tanto, un sistema de carruajes se puede conectar en cascada para cubrir múltiples ejes de movimiento.", - - "create.ponder.gantry_direction.header": "Dirección de Movimiento del Carruaje", - "create.ponder.gantry_direction.text_1": "Los ejes de grúa pueden tener orientaciones opuestas", - "create.ponder.gantry_direction.text_2": "La dirección de movimiento de los Carruajes depende de la orientación de los ejes.", - "create.ponder.gantry_direction.text_3": "...así como la dirección de rotación del eje", - "create.ponder.gantry_direction.text_4": "Se aplican las mismas reglas para la rotación propagada.", - - "create.ponder.gantry_redstone.header": "Propagación de Energía de la Grúa", - "create.ponder.gantry_redstone.text_1": "Los ejes de grúa impulsados ​​por Redstone dejan de mover sus carros", - "create.ponder.gantry_redstone.text_2": "En cambio, su fuerza rotacional se transmite al eje de salida de los carruajes.", - - "create.ponder.gantry_shaft.header": "Usando Ejes de Grúa", - "create.ponder.gantry_shaft.text_1": "Los ejes de grúa forman la base de una configuración de grúa. Los carruajes adjuntos se moverán a lo largo de ellos.", - "create.ponder.gantry_shaft.text_2": "Las Configuraciones de Carruaje pueden mover bloques adjuntos.", - - "create.ponder.gearbox.header": "Transmitiendo Energía Rotacional usando Cajas de Engranajes", - "create.ponder.gearbox.text_1": "Saltar entre ejes de rotación puede volverse pesado rápidamente", - "create.ponder.gearbox.text_2": "Una caja de cambios es el equivalente más compacto de esta configuración.", - "create.ponder.gearbox.text_3": "Los ejes alrededor de las esquinas giran en direcciones simétricas", - "create.ponder.gearbox.text_4": "Las conexiones rectas se invertirán", - - "create.ponder.gearshift.header": "Controlando Fuerza Rotacional usando una Caja de Cambios", - "create.ponder.gearshift.text_1": "Las Cajas de Cambio mantienen la Energía Rotacional en línea recta", - "create.ponder.gearshift.text_2": "Cuando recibe una señal de Redstone, invierte la transmisión", - - "create.ponder.hand_crank.header": "Generando fuerza rotacional mediante manivelas", - "create.ponder.hand_crank.text_1": "Las manivelas pueden ser usadas por los jugadores para generar energía rotacional manualmente", - "create.ponder.hand_crank.text_2": "Mantén presionado el Click-Derecho para girarlo en sentido antihorario", - "create.ponder.hand_crank.text_3": "Su velocidad es relativamente alta", - "create.ponder.hand_crank.text_4": "Agáchate y mantén el Click-Derecho para girarlo en el sentido de las agujas del reloj", - - "create.ponder.hose_pulley.header": "Drenaje y LLenado de Fuentes usando Poleas Manguera", - "create.ponder.hose_pulley.text_1": "Las Poleas Manguera se pueden usar para llenar o drenar grandes cantidades de fluido", - "create.ponder.hose_pulley.text_2": "A través de la Entrada Cinética, se puede controlar la altura de la manguera de las poleas", - "create.ponder.hose_pulley.text_3": "La Polea se retrae al invertir la dirección de Rotación", - "create.ponder.hose_pulley.text_4": "En el lado opuesto, las tuberías se pueden conectar al bloque principal", - "create.ponder.hose_pulley.text_5": "Las redes de tuberías adjuntas pueden proporcionar fluido a la manguera...", - "create.ponder.hose_pulley.text_6": "...o tirar de él, drenando la piscina en su lugar", - "create.ponder.hose_pulley.text_7": "La velocidad de llenado y drenaje de la manguera depende completamente de las redes de tuberías.", - - "create.ponder.hose_pulley_infinite.header": "Drenaje y Llenado pasivo de grandes cantidades de líquido", - "create.ponder.hose_pulley_infinite.text_1": "Al desplegar la Polea Manguera en un océano lo suficientemente grande...", - "create.ponder.hose_pulley_infinite.text_2": "Proporcionará/eliminará fluidos sin afectar la fuente", - "create.ponder.hose_pulley_infinite.text_3": "Las redes de tuberías pueden llevar fluidos ilimitadamente desde o hacia dichas poleas.", - - "create.ponder.hose_pulley_level.header": "Nivel de llenado y drenaje de Poleas Manguera", - "create.ponder.hose_pulley_level.text_1": "Mientras está completamente retraída, la Polea Manguera no puede funcionar", - "create.ponder.hose_pulley_level.text_2": "El drenaje corre de arriba a abajo", - "create.ponder.hose_pulley_level.text_3": "El nivel de la superficie terminará justo debajo de donde termina la manguera.", - "create.ponder.hose_pulley_level.text_4": "El llenado corre de abajo hacia arriba", - "create.ponder.hose_pulley_level.text_5": "La piscina llena no crecerá más allá de la capa sobre el extremo de la manguera.", - - "create.ponder.item_drain.header": "Vaciando Contenedores de Fluido mediante Drenajes", - "create.ponder.item_drain.text_1": "Los Drenajes pueden extraer fluidos de los objetos", - "create.ponder.item_drain.text_2": "Haz Click-Derecho para verter los fluidos del objeto en tu mano en él", - "create.ponder.item_drain.text_3": "Cuando los Objetos se insertan desde el lateral...", - "create.ponder.item_drain.text_4": "...ruedan, vaciando su líquido contenido", - "create.ponder.item_drain.text_5": "Las redes de tuberías ahora pueden extraer el fluido del búfer interno de los Drenajes.", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "Transmitiendo la fuerza rotacional mediante engranajes grandes", - "create.ponder.large_cogwheel.text_1": "Los engranajes grandes se pueden conectar entre sí en ángulo recto", - "create.ponder.large_cogwheel.text_2": "Te ayudará a transmitir la velocidad transportada a otros ejes de rotación", - - "create.ponder.linear_chassis_attachment.header": "Fijando bloques mediante Chasis Lineal", - "create.ponder.linear_chassis_attachment.text_1": "Las caras abiertas de un Chasis Lineal se pueden volver pegajosas", - "create.ponder.linear_chassis_attachment.text_2": "Haz clic de nuevo para hacer el lado opuesto pegajoso", - "create.ponder.linear_chassis_attachment.text_3": "Agáchate y haz Click-Derecho con la mano vacía para eliminar el slime.", - "create.ponder.linear_chassis_attachment.text_4": "Las caras pegadas del Chasis Lineal unirán una línea de bloques frente a él.", - "create.ponder.linear_chassis_attachment.text_5": "Usando una llave, se puede especificar un rango preciso para el Chasis", - "create.ponder.linear_chassis_attachment.text_6": "Mantener presionada la tecla CTRL y mover la rueda del mouse ajusta el rango de todos los bloques de Chasis adjuntos", - "create.ponder.linear_chassis_attachment.text_7": "La colocación de bloques en cualquier otro lado requiere el uso de La Gotita", - "create.ponder.linear_chassis_attachment.text_8": "Usando estas mecánicas, las estructuras de cualquier forma pueden moverse como una contrapción.", - - "create.ponder.linear_chassis_group.header": "Moviendo Chasis Lineales en grupo", - "create.ponder.linear_chassis_group.text_1": "El Chasis Lineal se conecta a bloques de Chasis idénticos junto a ellos", - "create.ponder.linear_chassis_group.text_2": "Cuando uno es movido por una Contrapción, los demás son arrastrados con él.", - "create.ponder.linear_chassis_group.text_3": "El Chasis de un tipo diferente o que mira en otra dirección no se acoplará", - - "create.ponder.mechanical_arm.header": "Configuración de Brazos Mecánicos", - "create.ponder.mechanical_arm.text_1": "Los Brazos Mecánicos deben tener asignadas sus entradas y salidas antes de colocarlos.", - "create.ponder.mechanical_arm.text_2": "Haz Click.Derecho en los inventarios mientras sostienes el brazo para asignarlos como objetivos", - "create.ponder.mechanical_arm.text_3": "Haz Click-Derecho de nuevo para alternar entre Entrada (azul) y Salida (naranja)", - "create.ponder.mechanical_arm.text_4": "Haz Click-Izquierdo en los componentes para eliminar su selección", - "create.ponder.mechanical_arm.text_5": "Una vez colocado, el Brazo Mecánico apuntará a los bloques seleccionados previamente", - "create.ponder.mechanical_arm.text_6": "Pueden tener cualquier cantidad de entradas y salidas dentro de su rango", - "create.ponder.mechanical_arm.text_7": "Sin embargo, no se puede interactuar directamente con todos los tipos de inventario", - "create.ponder.mechanical_arm.text_8": "Los ingresos y depósitos pueden ayudar a sobrepasar esa brecha", - - "create.ponder.mechanical_arm_filtering.header": "Filtrando Salidas del Brazo Mecánico", - "create.ponder.mechanical_arm_filtering.text_1": "Entradas", - "create.ponder.mechanical_arm_filtering.text_2": "Salidas", - "create.ponder.mechanical_arm_filtering.text_3": "A veces es preferible restringir los objetivos del brazo haciendo coincidir un filtro", - "create.ponder.mechanical_arm_filtering.text_4": "Los brazos mecánicos por sí mismos no ofrecen ninguna opción para filtrar", - "create.ponder.mechanical_arm_filtering.text_5": "Los embudos de latón como objetivos, sin embargo, comunican su propio filtro al brazo.", - "create.ponder.mechanical_arm_filtering.text_6": "El brazo es lo suficientemente inteligente como para no recoger artículos que no puede distribuir.", - - "create.ponder.mechanical_arm_modes.header": "Modos de Distribución del Brazo Mecánico", - "create.ponder.mechanical_arm_modes.text_1": "Entrada", - "create.ponder.mechanical_arm_modes.text_2": "Salida", - "create.ponder.mechanical_arm_modes.text_3": "Siempre que un brazo tiene que elegir entre múltiples salidas válidas...", - "create.ponder.mechanical_arm_modes.text_4": "...actuará de acuerdo a su entorno", - "create.ponder.mechanical_arm_modes.text_5": "Rodar con una Llave Inglesa te permite configurarlo", - "create.ponder.mechanical_arm_modes.text_6": "El modo Round Robin simplemente recorre todas las salidas que están disponibles.", - "create.ponder.mechanical_arm_modes.text_7": "Si una salida no puede aceptar más elementos, se omitirá.", - "create.ponder.mechanical_arm_modes.text_8": "El modo Round Robin forzado nunca se saltará salidas, y esperará hasta que la siguiente esté disponible", - "create.ponder.mechanical_arm_modes.text_9": "Preferir el Primero prioriza las salidas seleccionadas primero al configurar el brazo", - - "create.ponder.mechanical_arm_redstone.header": "Controlando Brazos Mecánicos con Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "Cuando reciben una señal de Redstone, los brazos mecánicos no se activan", - "create.ponder.mechanical_arm_redstone.text_2": "Antes de detenerse, termina el ciclo restante", - "create.ponder.mechanical_arm_redstone.text_3": "Asi mismo, se puede utilizar un pulso negativo para activar exactamente un ciclo de activación", - - "create.ponder.mechanical_bearing.header": "Moviendo Estructuras con un Rodamiento Mecánico", - "create.ponder.mechanical_bearing.text_1": "Los Rodamientos Mecánicos se unen al bloque frente a ellos.", - "create.ponder.mechanical_bearing.text_2": "Al recibir Fuerza Rotacional, se ensamblará en una contrapción giratoria.", - - "create.ponder.mechanical_crafter.header": "Configurando Crafteadores Mecánicos", - "create.ponder.mechanical_crafter.text_1": "Se puede usar una variedad de Crafteadores Mecánicos para automatizar cualquier receta de elaboración.", - "create.ponder.mechanical_crafter.text_2": "Usando una llave inglesa, los caminos de los Crafteadores se pueden ordenar", - "create.ponder.mechanical_crafter.text_3": "Para una configuración válida, todas las rutas deben converger en una salida en cualquier lado", - "create.ponder.mechanical_crafter.text_4": "Las salidas se colocarán en el inventario a la salida.", - "create.ponder.mechanical_crafter.text_5": "Los Crafteadores Mecánicos requieren fuerza rotacional para operar", - "create.ponder.mechanical_crafter.text_6": "Haz Click-Derecho al frente para insertar objetos manualmente", - "create.ponder.mechanical_crafter.text_7": "Una vez que cada espacio de una ruta contiene un objeto, comenzará el proceso de elaboración.", - "create.ponder.mechanical_crafter.text_8": "Para las recetas que no ocupan completamente la configuración del crafteador, el inicio se puede forzar usando un Pulso de Redstone", - - "create.ponder.mechanical_crafter_connect.header": "Conectando los Inventarios de los Crafteadores", - "create.ponder.mechanical_crafter_connect.text_1": "Los Objetos se pueden insertar en Crafters automáticamente", - "create.ponder.mechanical_crafter_connect.text_2": "Usando la llave en sus espaldas, las entradas de los Crafteadores Mecánicos se pueden combinar", - "create.ponder.mechanical_crafter_connect.text_3": "Ahora se puede acceder a todos los Crafteadores conectados desde la misma ubicación de entrada", - - "create.ponder.mechanical_crafter_covers.header": "Cubriendo ranuras de Crafteadores Mecánicos", - "create.ponder.mechanical_crafter_covers.text_1": "Algunas recetas requerirán creafteadores adicionales para cerrar brechas en el camino.", - "create.ponder.mechanical_crafter_covers.text_2": "Usando Cubre Ranuras, los Crafteadores se pueden configurar para que actúen como un espacio vacío en el Crafteo", - "create.ponder.mechanical_crafter_covers.text_3": "Las entradas compartidas creadas con la Llave Inglesa en la parte trasera también pueden llegar a los Crafteadores Cubiertos.", - - "create.ponder.mechanical_drill.header": "Rompiendo Bloques con el Taladro Mecánico", - "create.ponder.mechanical_drill.text_1": "Cuando se le entrega Energía Rotacional, un taladro mecánico romperá bloques directamente en frente de él", - "create.ponder.mechanical_drill.text_2": "Su velocidad de extracción depende de la velocidad de entrada rotacional.", - - "create.ponder.mechanical_drill_contraption.header": "Usando Taladros Mecánicos en Contrapciones", - "create.ponder.mechanical_drill_contraption.text_1": "Cuando los taladros se mueven como parte de una contrapción animada...", - "create.ponder.mechanical_drill_contraption.text_2": "...romperán los bloques con los que se encuentren", - - "create.ponder.mechanical_harvester.header": "Usando Cosechadoras Mecánicas en Contrapciones", - "create.ponder.mechanical_harvester.text_1": "Cuando las Cosechadoras se mueven como parte de una Contrapción animada...", - "create.ponder.mechanical_harvester.text_2": "Cosecharán y reiniciaran cualcuier cultivo maduro en su camino", - - "create.ponder.mechanical_mixer.header": "Procesando Objetos con una Mezcladora Mecánica", - "create.ponder.mechanical_mixer.text_1": "Con una Mezcladora y un tónel, algunas recetas de elaboración se pueden automatizar", - "create.ponder.mechanical_mixer.text_2": "Las recetas disponibles incluyen cualquier Crafteo sin Forma Definida, más un par de recetas adicionales.", - "create.ponder.mechanical_mixer.text_3": "Algunas de esas recetas podrían requerir el calor de un Quemador Blaze", - "create.ponder.mechanical_mixer.text_4": "La ranura del filtro se puede utilizar en caso de que dos recetas estén en conflicto.", - - "create.ponder.mechanical_piston.header": "Moviendo Estructuras con el Pistón Mecánico", - "create.ponder.mechanical_piston.text_1": "Los pistones mecánicos pueden mover bloques delante de ellos.", - "create.ponder.mechanical_piston.text_2": "La velocidad y la dirección de movimiento dependen de la velocidad y sentido de entrada rotacional", - "create.ponder.mechanical_piston.text_3": "Los Pistones Mecánicos Pegajosos pueden tirar de los bloques adjuntos hacia atrás", - - "create.ponder.mechanical_piston_modes.header": "Modos de Movimiento de los Pistones Mecánicos", - "create.ponder.mechanical_piston_modes.text_1": "Siempre que los pistones dejan de moverse, la estructura movida se convierte en bloques.", - "create.ponder.mechanical_piston_modes.text_2": "Se puede configurar para que nunca vuelva a bloques sólidos, o solo lo haga en la ubicación en la que comenzó.", - - "create.ponder.mechanical_plough.header": "Usando Aradores Mecánicos den Contrapciones", - "create.ponder.mechanical_plough.text_1": "Cuando los Aradores se mueven siendo parte de una contrapción...", - "create.ponder.mechanical_plough.text_2": "...romperán bloques sin un hitbox de colisión sólido", - "create.ponder.mechanical_plough.text_3": "Adicionalmente, los Aradores crean tierra plantable", - "create.ponder.mechanical_plough.text_4": "...también pueden lanzar entidades sin dañarlas", - - "create.ponder.mechanical_press.header": "Procesando Objetos con la Prensa Mecánica", - "create.ponder.mechanical_press.text_1": "La Prensa Mecánica puede procesar los objetos proporcionados debajo de ella.", - "create.ponder.mechanical_press.text_2": "Los objetos entrantes se pueden soltar o colocar en un depósito debajo de la prensa", - "create.ponder.mechanical_press.text_3": "Cuando los objetos pasan por una cinta mecánica...", - "create.ponder.mechanical_press.text_4": "La prensa los mantendrá y procesará automáticamente", - - "create.ponder.mechanical_press_compacting.header": "Compactando objetos con una prensa mecánica", - "create.ponder.mechanical_press_compacting.text_1": "Al Prensar objetos retenidos en un tónel, se compactarán", - "create.ponder.mechanical_press_compacting.text_2": "La compactación incluye cualquier receta de elaboración de 2x2 o 3x3 rellena, más algunas extra", - "create.ponder.mechanical_press_compacting.text_3": "Algunas de esas recetas podrían requerir el calor de un quemador Blaze", - "create.ponder.mechanical_press_compacting.text_4": "La ranura del filtro se puede utilizar en caso de que dos recetas estén en conflicto.", - - "create.ponder.mechanical_pump_flow.header": "Transporte de fluidos mediante Bombas Mecánicas", - "create.ponder.mechanical_pump_flow.text_1": "Las Bombas Mecánicas gobiernan el flujo de fluídos en las redes de tuberías", - "create.ponder.mechanical_pump_flow.text_2": "Cuando se encienden, su flecha indica la dirección del flujo", - "create.ponder.mechanical_pump_flow.text_3": "La red detrás ahora está extrayendo fluidos...", - "create.ponder.mechanical_pump_flow.text_4": "...mientras la red de enfrente lo está transfiriendo hacia afuera", - "create.ponder.mechanical_pump_flow.text_5": "Invertir la rotación invierte la dirección del flujo", - "create.ponder.mechanical_pump_flow.text_6": "Utiliza una Llave Inglesa para invertir la orientación de las bombas manualmente", - - "create.ponder.mechanical_pump_speed.header": "Rendimiento de las Bombas Mecánicas", - "create.ponder.mechanical_pump_speed.text_1": "Sin importar la velocidad, Las bombas mecánicas afectan a las tuberías conectadas hasta a 16 bloques de distancia", - "create.ponder.mechanical_pump_speed.text_2": "Acelerar la rotación de entrada cambia la velocidad de propagación del flujo....", - "create.ponder.mechanical_pump_speed.text_3": "...así como la rapidez con la que se transfieren los fluidos", - "create.ponder.mechanical_pump_speed.text_4": "Las bombas pueden combinar sus rendimientos dentro de las redes de tuberías compartidas", - "create.ponder.mechanical_pump_speed.text_5": "Alternar su orientación puede ayudar a alinear las direcciones de flujo.", - - "create.ponder.mechanical_saw_breaker.header": "Cortando árboles con la Sierra Mecánica", - "create.ponder.mechanical_saw_breaker.text_1": "Cuando se alimenta con Fuerza Rotacional, una Sierra Mecánica cortará los arboles en frente suya", - "create.ponder.mechanical_saw_breaker.text_2": "Para cortar el árbol por completo, la sierra tiene que romper el último bloque que lo conecta al suelo.", - - "create.ponder.mechanical_saw_contraption.header": "Usando Sierras Mecánicas en Contrapciones", - "create.ponder.mechanical_saw_contraption.text_1": "Cuando las sierras se muevan como parte de una contrapción animada...", - "create.ponder.mechanical_saw_contraption.text_2": "...cortarán cualquier arbol que se interponga en el paso de la contrapción", - - "create.ponder.mechanical_saw_processing.header": "Procesando objetos en la Sierra Mecánica", - "create.ponder.mechanical_saw_processing.text_1": "Las Sierras Mecánicas orientadas hacia arriba pueden procesar una variedad de objetos", - "create.ponder.mechanical_saw_processing.text_2": "El Objeto procesado siempre se mueve en contra del sentido rotacional de la Sierra.", - "create.ponder.mechanical_saw_processing.text_3": "Las Sierras pueden trabajar en línea junto con Cintas Mecánicas", - "create.ponder.mechanical_saw_processing.text_4": "Cuando un ingrediente tiene múltiples resultados posibles, la ranura de filtro puede especificar el resultado.", - "create.ponder.mechanical_saw_processing.text_5": "Sin un filtro, la Sierra ciclará por todos los resultados en su lugar", - - "create.ponder.millstone.header": "Procesando objetos en la Piedra de Molino", - "create.ponder.millstone.text_1": "Las Piedras de Molino procesan los artículos moliéndolos", - "create.ponder.millstone.text_2": "Se pueden accionar desde el lado mediante Engranajes.", - "create.ponder.millstone.text_3": "Lanza o Inserta objetos desde la parte superior", - "create.ponder.millstone.text_4": "Despues de un rato, el resultado se puede obtener haciendo Click-Derecho", - "create.ponder.millstone.text_5": "Las salidas también se pueden extraer mediante automatización", - - "create.ponder.nixie_tube.header": "Usando Tubos Nixie", - "create.ponder.nixie_tube.text_1": "Al recibir señales de Redstone, los Tubos Nixie mostrarán la fuerza de la señal de redstone", - "create.ponder.nixie_tube.text_2": "Usando etiquetas editadas con un yunque, se puede mostrar Texto Personalizado", - "create.ponder.nixie_tube.text_3": "Haz Click-Derecho con un Tinte para cambiar su color de visualización", - - "create.ponder.piston_pole.header": "Postes de Extensión de Pistón", - "create.ponder.piston_pole.text_1": "Sin postes adjuntos, un Pistón Mecanico no se puede mover", - "create.ponder.piston_pole.text_2": "La longitud del poste agregado en su parte posterior determina el rango de extensión", - - "create.ponder.portable_fluid_interface.header": "Intercambio de Fluidos en Contrapciones", - "create.ponder.portable_fluid_interface.text_1": "No se puede acceder a los Tanques de Fluido de una Contrapción en movimiento por ninguna tubería", - "create.ponder.portable_fluid_interface.text_2": "Este componente puede interactuar con los Tanques de Fluidos sin necesidad de detener la contrapción.", - "create.ponder.portable_fluid_interface.text_3": "Coloca un segundo con una distancia de 1 o 2 bloques", - "create.ponder.portable_fluid_interface.text_4": "Cada vez que se crucen, entablarán una conexión.", - "create.ponder.portable_fluid_interface.text_5": "Mientras está activada, la interfaz estacionaria representará a TODOS los tanques en el contrapción", - "create.ponder.portable_fluid_interface.text_6": "El fluido ahora puede ser insertado...", - "create.ponder.portable_fluid_interface.text_7": "...o extraído de la contrapción", - "create.ponder.portable_fluid_interface.text_8": "Después de que no se haya intercambiado ningún contenido durante un tiempo, la contrapción continuará su camino.", - - "create.ponder.portable_storage_interface.header": "Intercambio de Almacenamiento en Contrapciones", - "create.ponder.portable_storage_interface.text_1": "No se puede acceder a los Inventarios de una Contrapción en movimiento por ningún jugador.", - "create.ponder.portable_storage_interface.text_2": "Este componente puede interactuar con los Inventarios sin necesidad de detener la contrapción.", - "create.ponder.portable_storage_interface.text_3": "Coloca un segundo con una distancia de 1 o 2 bloques", - "create.ponder.portable_storage_interface.text_4": "Cada vez que se crucen, entablarán una conexión.", - "create.ponder.portable_storage_interface.text_5": "Mientras está activada, la interfaz estacionaria representará a TODOS los inventarios en el contrapciónWhile engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "Ahora puedes insertar objetos...", - "create.ponder.portable_storage_interface.text_7": "...o extraerlos de la contrapción", - "create.ponder.portable_storage_interface.text_8": "Después de que no se haya intercambiado ningún objeto durante un tiempo, la contrapción continuará su camino.", - - "create.ponder.portable_storage_interface_redstone.header": "Control de Redstone", - "create.ponder.portable_storage_interface_redstone.text_1": "La Redstone evitará que la interfaz estacionaria se active", - - "create.ponder.powered_latch.header": "Control de señales usando el Cerrojo de Redstone", - "create.ponder.powered_latch.text_1": "Los Cerrojos de Redstone son palancas controlables de Redstone", - "create.ponder.powered_latch.text_2": "Las señales en la parte trasera lo encienden", - "create.ponder.powered_latch.text_3": "Las señales laterales lo apagan", - "create.ponder.powered_latch.text_4": "Los Cerrojos de Redstone también se pueden alternar manualmente", - - "create.ponder.powered_toggle_latch.header": "Control de señales usando el Cerrojo Palanca de Redstone", - "create.ponder.powered_toggle_latch.text_1": "Los Cerrojos Palanca de Redstone son palancas controlables de Redstone", - "create.ponder.powered_toggle_latch.text_2": "Las señales en la parte posterior cambiarán su estado", - "create.ponder.powered_toggle_latch.text_3": "...entre encendido y apagado", - "create.ponder.powered_toggle_latch.text_4": "Los Cerrojos Palanca de Redstone también se pueden alternar manualmente", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "Controlando Señales con Repetidores de Pulso", - "create.ponder.pulse_repeater.text_1": "Los Repetidores de Pulso acortarán cualquier señal de redstone a un solo pulso", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "Uniendo Bloques con el Chasis Radial", - "create.ponder.radial_chassis.text_1": "El chasis radial se conecta a bloques de chasis idénticos en una fila", - "create.ponder.radial_chassis.text_2": "Cuando uno es movido por una contrapción, los demás son arrastrados con él.", - "create.ponder.radial_chassis.text_3": "Las caras laterales de un Chasis Radial se pueden hacer pegajosas", - "create.ponder.radial_chassis.text_4": "Cliquea de nuevo para hacer la otra cara pegajosa", - "create.ponder.radial_chassis.text_5": "Agachate y haz Click-Derecho con la mano vacía para eliminar el slime.", - "create.ponder.radial_chassis.text_6": "Siempre que un bloque esté al lado de una cara pegajosa...", - "create.ponder.radial_chassis.text_7": "...adjuntará todos los bloques alcanzables dentro de un radio en esa capa", - "create.ponder.radial_chassis.text_8": "Usando una Llave Inglesa, se puede especificar un radio preciso para este chasis", - "create.ponder.radial_chassis.text_9": "Los bloques a los que no puede acceder ninguna cara adhesiva no se adhieren", - - "create.ponder.redstone_contact.header": "Contactos de Redstone", - "create.ponder.redstone_contact.text_1": "Los Contactos de Redstone que estén uno frente al otro emitirán una señal de redstone.", - "create.ponder.redstone_contact.text_2": "Esto todavía se aplica cuando uno de ellos es parte de una contrapción en movimiento.", - - "create.ponder.redstone_link.header": "Usando Enlaces de Redstone", - "create.ponder.redstone_link.text_1": "Los enlaces de Redstone pueden transmitir señales de redstone de forma inalámbrica", - "create.ponder.redstone_link.text_2": "Agachate y haz Click-Derecho para alternar el modo de recepción", - "create.ponder.redstone_link.text_3": "Un simple Click-Derecho con una Llave Inglesa puede hacer lo mismo", - "create.ponder.redstone_link.text_4": "Los Receptores emiten la potencia de redstone de los Transmisores dentro de un radio de 128 bloques", - "create.ponder.redstone_link.text_5": "Colocar objetos en las dos ranuras puede especificar una frecuencia", - "create.ponder.redstone_link.text_6": "Solo los enlaces con frecuencias coincidentes se comunicarán entre sí", - - "create.ponder.rope_pulley.header": "Moviendo Estructuras con Poleas de Cuerda", - "create.ponder.rope_pulley.text_1": "Las poleas de Cuerda mueven Bloques de manera vertical al recibir Energía Rotacional", - "create.ponder.rope_pulley.text_2": "La Dirección y la Velocidad del movimiento dependen de la entrada rotacional", - - "create.ponder.rope_pulley_attachment.header": "Moviendo Poleas como parte de una Contrapción", - "create.ponder.rope_pulley_attachment.text_1": "Siempre que las poleas sean movidas por una contrapción...", - "create.ponder.rope_pulley_attachment.text_2": "...la estructura unida a ellas será arrastrada", - "create.ponder.rope_pulley_attachment.text_3": "Ten en cuenta que las poleas solo se pueden mover cuando están paradas", - - "create.ponder.rope_pulley_modes.header": "Modos de Movimiento de las Poleas de Cuerda", - "create.ponder.rope_pulley_modes.text_1": "Siempre que las poleas dejan de moverse, la estructura movida se convierte en Bloques", - "create.ponder.rope_pulley_modes.text_2": "Puede configurarse que nunca vuelva a bloques, o que solo lo haga en la ubicación inicial", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "Usando el Controlador de Velocidad de Rotación", - "create.ponder.rotation_speed_controller.text_1": "Los Controladores de Vel. de Rotación transmiten la rotación desde su eje a un Engranaje Grande encima de ellos", - "create.ponder.rotation_speed_controller.text_2": "Usando la entrada de rueda en su lado, la velocidad transportada se puede configurar", - - "create.ponder.sail.header": "Ensamblando Molinos de Viento con Velas", - "create.ponder.sail.text_1": "Las velas son bloques útiles para crear Molinos de Viento", - "create.ponder.sail.text_2": "Se adhieren a los bloques y entre sí sin la necesidad de La Gotita o Bloques de Chasis.", - "create.ponder.sail.text_3": "Haz Click-Derecho con Tinte para pintarlas", - "create.ponder.sail.text_4": "Haz Click-Derecho con Tijeras para convertirlas de nuevo en Marcos.", - - "create.ponder.sail_frame.header": "Ensamblando Molinos con Marcos de Vela", - "create.ponder.sail_frame.text_1": "Los Marcos de Vela son bloques útiles para crear Molinos de Viento", - "create.ponder.sail_frame.text_2": "Se adhieren a los bloques y entre sí sin la necesidad de La Gotita o Bloques de Chasis.", - - "create.ponder.sequenced_gearshift.header": "Control de la velocidad de rotación mediante Cajas de Cambio Secuenciadas", - "create.ponder.sequenced_gearshift.text_1": "Las Cajas de Cambios Sec. transmiten la rotación siguiendo una lista cronometrada de instrucciones", - "create.ponder.sequenced_gearshift.text_2": "Haz Click-Derecho para abrir la interfaz de usuario de configuración", - "create.ponder.sequenced_gearshift.text_3": "Al recibir una señal de Redstone, comenzará a ejecutar su secuencia configurada", - "create.ponder.sequenced_gearshift.text_4": "Una vez terminado, esperará la próxima señal de Redstone y comenzará de nuevo.", - "create.ponder.sequenced_gearshift.text_5": "Se puede usar un Comparador de Redstone para leer el progreso actual", - - "create.ponder.shaft.header": "Transmitiendo Fuerza Rotacional con Ejes", - "create.ponder.shaft.text_1": "Los ejes transmitirán la rotación en línea recta.", - - "create.ponder.shaft_casing.header": "Cubriendo Ejes", - "create.ponder.shaft_casing.text_1": "Puedes usar Cubiertas de Latón y Andesita para decorar tus Ejes", - - "create.ponder.smart_chute.header": "Filtrando Objetos usando Tolvoganes Inteligentes", - "create.ponder.smart_chute.text_1": "Los Tolvoganes Inteligentes son conductos verticales con control adicional", - "create.ponder.smart_chute.text_2": "Los Objetos en la ranura del filtro especifican qué es exactamente lo que pueden extraer y transferir.", - "create.ponder.smart_chute.text_3": "Usa la rueda del mouse para especificar el tamaño de la pila extraída", - "create.ponder.smart_chute.text_4": "Una señal de Redstone evitará que el tolvogán actúe.", - - "create.ponder.smart_pipe.header": "Controlando el Flujo del Fluido mediante Tuberías Inteligentes", - "create.ponder.smart_pipe.text_1": "Las Tuberías Inteligentes pueden ayudar a controlar los Flujos por tipo de Fluido", - "create.ponder.smart_pipe.text_2": "Cuando se colocan directamente en la fuente, pueden especificar el tipo de fluido a extraer.", - "create.ponder.smart_pipe.text_3": "Simplemente haz Click-Derecho en la ranura de filtro con cualquier elemento que contenga el fluido deseado", - "create.ponder.smart_pipe.text_4": "Cuando se colocan más adelante en una red de tuberías, las Tuberías Inteligentes solo permitirán que continúen los fluidos coincidentes", - - "create.ponder.speedometer.header": "Supervisando Información Cinética con el Velocímetro", - "create.ponder.speedometer.text_1": "El velocímetro muestra la velocidad actual de los componentes conectados", - "create.ponder.speedometer.text_2": "Al usar los lentes del ingeniero, el jugador puede obtener información más detallada del indicador.", - "create.ponder.speedometer.text_3": "Los comparadores pueden emitir señales de Redstone analógicas en relación con las mediciones del Velocímetro", - - "create.ponder.spout_filling.header": "Llenando Objetos con el Surtidor", - "create.ponder.spout_filling.text_1": "El Surtidos puede llenar los objetos contenedores de líquidos que se encuentran debajo", - "create.ponder.spout_filling.text_2": "No se puede acceder manualmente al contenido de un Surtidor ", - "create.ponder.spout_filling.text_3": "En cambio, tuberías se deben usar para llenarlos con Fluidos", - "create.ponder.spout_filling.text_4": "Los Objetos de Entrada se pueden colocar en un depósito debajo del Surtidor", - "create.ponder.spout_filling.text_5": "Cuando los Objetos se encuentran en una cinta...", - "create.ponder.spout_filling.text_6": "El Surtidor los mantendrá y procesará autoráticamente", - - "create.ponder.stabilized_bearings.header": "Contrapciones Estabilizadas", - "create.ponder.stabilized_bearings.text_1": "Siempre que los rodamientos mecánicos formen parte de una estructura en movimiento..", - "create.ponder.stabilized_bearings.text_2": "..intentarán mantenerse erguidos", - "create.ponder.stabilized_bearings.text_3": "Una vez más, el rodamiento se unirá al bloque enfrente a él.", - "create.ponder.stabilized_bearings.text_4": "Como resultado, toda la sub-contrapción permanecerá en posición vertical.", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "Colocación de bloques con el Pegador", - "create.ponder.sticker.text_1": "Los Pegadores son ideales para la fijación de bloques controlada por Redstone", - "create.ponder.sticker.text_2": "Al recibir señal, alternarán de estado", - "create.ponder.sticker.text_3": "Si se mueve en una contrapción, el bloque se moverá con él.", - "create.ponder.sticker.text_4": "Alternando una vez más, el bloque ya no se adjunta.", - - "create.ponder.stressometer.header": "Supervisando Información Cinética con el Estresómetro", - "create.ponder.stressometer.text_1": "El Estresómetro muestra la capacidad de estrés actual de la red cinética adjunta", - "create.ponder.stressometer.text_2": "Al usar lentes de ingeniero, el jugador puede obtener información más detallada del indicador.", - "create.ponder.stressometer.text_3": "Los comparadores pueden emitir señales de Redstone analógicas en relación con las mediciones del Estresómetro", - - "create.ponder.super_glue.header": "Adjuntando bloques usando La Gotita", - "create.ponder.super_glue.text_1": "La Gotita se puede usar entre 2 bloques", - "create.ponder.super_glue.text_2": "Los bloques unidos se moverán juntos cuando se ensamblen en una contrapción.", - "create.ponder.super_glue.text_3": "Siempre que se sostenga La Gotita en la mano izquierda...", - "create.ponder.super_glue.text_4": "...los bloques añadidos se pegarán a la cara en la que se colocaron automáticamente", - "create.ponder.super_glue.text_5": "La Gotita se puede quitar con Click-Izquierdo", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "Generación Fuerza Rotacional mediante Válvulas de Cobre", - "create.ponder.valve_handle.text_1": "Los jugadores pueden usar las Válvulas para aplicar fuerza de rotación manualmente", - "create.ponder.valve_handle.text_2": "Mantén presionado el Click-Derecho para girarla en sentido antihorario", - "create.ponder.valve_handle.text_3": "Su velocidad de transporte es lenta y precisa.", - "create.ponder.valve_handle.text_4": "Agáchate y mantén Click-Derecho para girarla en el sentido de las agujas del reloj", - "create.ponder.valve_handle.text_5": "Las Válvulas se pueden teñir con fines estéticos.", - - "create.ponder.valve_pipe.header": "Controlando el Flujo de Fluido mediante Válvulas", - "create.ponder.valve_pipe.text_1": "Las Tuberías de Válvula ayudan a controlar los fluidos que se propagan a través de las redes de tuberías", - "create.ponder.valve_pipe.text_2": "Su entrada de eje controla si al fluido se le permite pasar", - "create.ponder.valve_pipe.text_3": "Dada la fuerza de rotación en la dirección de apertura, la Válvula se abrirá", - "create.ponder.valve_pipe.text_4": "Se puede volver a cerrar invirtiendo la rotación.", - - "create.ponder.water_wheel.header": "Generando fuerza rotacional usando ruedas de agua", - "create.ponder.water_wheel.text_1": "Las ruedas de agua extraen fuerza de las corrientes de agua adyacentes", - "create.ponder.water_wheel.text_2": "MIentras más caras estén siendo empujadas, más rapido rotará", - "create.ponder.water_wheel.text_3": "Las palas de la rueda deben estar orientadas contra el flujo", - "create.ponder.water_wheel.text_4": "De lo contrario, no serán tan efectivas.", - - "create.ponder.weighted_ejector.header": "Usando Eyectores por Peso", - "create.ponder.weighted_ejector.text_1": "Agáchate y haz Click-Derecho sosteniendo un eyector para seleccionar su ubicación de destino", - "create.ponder.weighted_ejector.text_10": "Ahora está limitado a este tamaño de stack y solo se activa cuando su stack retenido alcanza esta cantidad.", - "create.ponder.weighted_ejector.text_11": "Otras entidades siempre activarán un eyector al pisarlo", - "create.ponder.weighted_ejector.text_2": "El Eyector colocado ahora lanzará objetos a la ubicación marcada", - "create.ponder.weighted_ejector.text_3": "Un objetivo válido puede estar a cualquier altura o distancia dentro del alcance", - "create.ponder.weighted_ejector.text_4": "Sin embargo, no pueden estar a un lateral", - "create.ponder.weighted_ejector.text_5": "Si no se seleccionó un objetivo válido, simplemente apuntará al bloque directamente al frente", - "create.ponder.weighted_ejector.text_6": "Suministrale Fuerza Rotacional para cargarlo.", - "create.ponder.weighted_ejector.text_7": "Los objetos colocados en el Eyector hacen que se active", - "create.ponder.weighted_ejector.text_8": "Si se apunta a Inventarios, el Eyector esperará hasta que haya espacio", - "create.ponder.weighted_ejector.text_9": "Con la Llave Inglesa, se puede configurar un tamaño de stack requerido", - - "create.ponder.weighted_ejector_redstone.header": "Controlando Eyectores por Peso con Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "Al recibir señales de Redstone, los Eyectores no se activarán", - "create.ponder.weighted_ejector_redstone.text_2": "Además, los observadores pueden detectar cuándo se activan los Eyectores.", - - "create.ponder.weighted_ejector_tunnel.header": "División de Stacks de Objetos con Eyectores por Peso", - "create.ponder.weighted_ejector_tunnel.text_1": "En combinación con los Túneles de Latón, los Eyectores pueden dividir las pilas de objetos en cantidades específicas", - "create.ponder.weighted_ejector_tunnel.text_2": "Primero, configura el Túnel de Latón a 'Preferir el más Cercano', para priorizar su salida lateral", - "create.ponder.weighted_ejector_tunnel.text_3": "El tamaño de Stack establecido en el Eyector ahora determina la cantidad que se Dividirá", - "create.ponder.weighted_ejector_tunnel.text_4": "Mientras que un nuevo stack del tamaño configurado sale de la salida lateral...", - "create.ponder.weighted_ejector_tunnel.text_5": "...el restante continuará su camino", - - "create.ponder.windmill_source.header": "Generando Fuerza Rotacional mediante Rodamientos de Molino de Viento", - "create.ponder.windmill_source.text_1": "Los Rodamientos de Molino de Viento se unen al bloque delante de ellos", - "create.ponder.windmill_source.text_2": "Si se unen suficientes Bloques de Vela al bloque, puede actuar como un molino de viento", - "create.ponder.windmill_source.text_3": "Activado con Click-Derecho, el Rodamiento de Molino de Viento comenzará a proporcionar Fuerza Rotacional", - "create.ponder.windmill_source.text_4": "La cantidad de Bloques de Velas determina su velocidad de rotación.", - "create.ponder.windmill_source.text_5": "Usa una Llave Inglesa para configurar su dirección de rotación", - "create.ponder.windmill_source.text_6": "Haz Click-Derecho en el Rodamiento en cualquier momento para detener y editar la estructura nuevamente", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "Contrapciones de Molino de Viento", - "create.ponder.windmill_structure.text_1": "Cualquier estructura puede contar como un molino de viento válido, siempre que contenga al menos 8 Bloques de Vela.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json deleted file mode 100644 index 5c55d77842..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 9", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Ventana de acacia", - "block.create.acacia_window_pane": "Panel de ventana de acacia", - "block.create.adjustable_chain_gearshift": "Cadena de transmisión ajustable", - "block.create.analog_lever": "Palanca analógica", - "block.create.andesite_belt_funnel": "Embudo lateral de andesita", - "block.create.andesite_casing": "Revestidor de andesita", - "block.create.andesite_encased_cogwheel": "Engranaje revestido de andesita", - "block.create.andesite_encased_large_cogwheel": "Engranaje grande revestido de andesita", - "block.create.andesite_encased_shaft": "Eje revestido de andesita", - "block.create.andesite_funnel": "Embudo de andesita", - "block.create.andesite_ladder": "Escalera de mano de andesita", - "block.create.andesite_pillar": "Pilar de andesita", - "block.create.andesite_tunnel": "Túnel de Andesita", - "block.create.asurine": "Azurina", - "block.create.asurine_pillar": "Pilar de azurina", - "block.create.basin": "Cuenca", - "block.create.belt": "Cinta", - "block.create.birch_window": "Ventana de abedul", - "block.create.birch_window_pane": "Panel de ventana de abedul", - "block.create.black_nixie_tube": "Tubo Nixie negro", - "block.create.black_sail": "Vela negra", - "block.create.black_seat": "Asiento negro", - "block.create.black_toolbox": "Caja de herramientas negra", - "block.create.black_valve_handle": "Asa de válvula negra", - "block.create.blaze_burner": "Quemador de Blaze", - "block.create.blue_nixie_tube": "Tubo Nixie azul", - "block.create.blue_sail": "Vela azul", - "block.create.blue_seat": "Asiento azul", - "block.create.blue_toolbox": "Caja de herramientas azul", - "block.create.blue_valve_handle": "Asa de válvula azul", - "block.create.brass_belt_funnel": "Embudo lateral de latón", - "block.create.brass_block": "Bloque de latón", - "block.create.brass_casing": "Revestidor de latón", - "block.create.brass_encased_cogwheel": "Engranaje revestido de latón", - "block.create.brass_encased_large_cogwheel": "Engranaje grande revestido de latón", - "block.create.brass_encased_shaft": "Eje revestido de latón", - "block.create.brass_funnel": "Embudo de latón", - "block.create.brass_ladder": "Escalera de mano de latón", - "block.create.brass_tunnel": "Túnel de latón", - "block.create.brown_nixie_tube": "Tubo Nixie marrón", - "block.create.brown_sail": "Vela marrón", - "block.create.brown_seat": "Asiento marrón", - "block.create.brown_toolbox": "Caja de herramientas marrón", - "block.create.brown_valve_handle": "Asa de válvula marrón", - "block.create.calcite_pillar": "Pilar de calcita", - "block.create.cart_assembler": "Ensamblador de vagonetas", - "block.create.chocolate": "Chocolate", - "block.create.chute": "Ducto", - "block.create.clockwork_bearing": "Rodamiento tipo reloj", - "block.create.clutch": "Embrague", - "block.create.cogwheel": "Engranaje", - "block.create.content_observer": "Observador de contenidos", - "block.create.controller_rail": "Raíl de control", - "block.create.controls": "Controles de tren", - "block.create.copper_backtank": "Depósito trasero de cobre", - "block.create.copper_casing": "Revestidor de caliza", - "block.create.copper_ladder": "Escalera de mano de cobre", - "block.create.copper_shingle_slab": "Losa de tejas de cobre", - "block.create.copper_shingle_stairs": "Escaleras de tejas de cobre", - "block.create.copper_shingles": "Bloque de tejas de cobre", - "block.create.copper_tile_slab": "Losa de baldosas de cobre", - "block.create.copper_tile_stairs": "Escaleras de baldosas de cobre", - "block.create.copper_tiles": "Bloque de baldosas de cobre", - "block.create.copper_valve_handle": "Asa de válvula de cobre", - "block.create.creative_crate": "Caja creativa", - "block.create.creative_fluid_tank": "Tanque de fluidos creativo", - "block.create.creative_motor": "Motor creativo", - "block.create.crimsite": "Carmesina", - "block.create.crimsite_pillar": "Pilar de carmesina", - "block.create.crimson_window": "Ventana carmesí", - "block.create.crimson_window_pane": "Panel de ventana carmesí", - "block.create.crushing_wheel": "Rueda trituradora", - "block.create.crushing_wheel_controller": "Controlador de Rueda trituradora", - "block.create.cuckoo_clock": "Reloj de cuco", - "block.create.cut_andesite": "Andesita cortada", - "block.create.cut_andesite_brick_slab": "Losa de ladrillos de andesita cortada", - "block.create.cut_andesite_brick_stairs": "Escaleras de ladrillos de andesita cortada", - "block.create.cut_andesite_brick_wall": "Muro de ladrillos de andesita cortada", - "block.create.cut_andesite_bricks": "Ladrillos de andesita cortada", - "block.create.cut_andesite_slab": "Losa de andesita cortada", - "block.create.cut_andesite_stairs": "Escaleras de andesite cortada", - "block.create.cut_andesite_wall": "Muro de andesita cortada", - "block.create.cut_asurine": "Azurina cortada", - "block.create.cut_asurine_brick_slab": "Losa de ladrillos de azurina cortada", - "block.create.cut_asurine_brick_stairs": "Escaleras de ladrillos de azurina cortada", - "block.create.cut_asurine_brick_wall": "Muro de ladrillos de azurina cortada", - "block.create.cut_asurine_bricks": "Ladrillos de azurina cortada", - "block.create.cut_asurine_slab": "Losa de azurina cortada", - "block.create.cut_asurine_stairs": "Escaleras de azurina cortada", - "block.create.cut_asurine_wall": "Muro de azurina cortada", - "block.create.cut_calcite": "Calcita cortada", - "block.create.cut_calcite_brick_slab": "Losa de ladrillos de calcita cortada", - "block.create.cut_calcite_brick_stairs": "Escaleras de ladrillos de calcita cortada", - "block.create.cut_calcite_brick_wall": "Muro de ladrillos de calcita cortada", - "block.create.cut_calcite_bricks": "Ladrillos de calcita cortada", - "block.create.cut_calcite_slab": "Losa de calcita cortada", - "block.create.cut_calcite_stairs": "Escaleras de calcita cortada", - "block.create.cut_calcite_wall": "Muro de calcita cortada", - "block.create.cut_crimsite": "Carmesina cortada", - "block.create.cut_crimsite_brick_slab": "Losa de ladrillos de carmesina cortada", - "block.create.cut_crimsite_brick_stairs": "Escaleras de ladrillos de carmesina cortada", - "block.create.cut_crimsite_brick_wall": "Muro de ladrillos de carmesina cortada", - "block.create.cut_crimsite_bricks": "Ladrillos de carmesina cortada", - "block.create.cut_crimsite_slab": "Losa de carmesina cortada", - "block.create.cut_crimsite_stairs": "Escaleras de carmesina cortada", - "block.create.cut_crimsite_wall": "Muro de carmesina cortada", - "block.create.cut_deepslate": "Pizarra profunda cortada", - "block.create.cut_deepslate_brick_slab": "Losa de ladrillos de pizarra profunda cortada", - "block.create.cut_deepslate_brick_stairs": "Escaleras de ladrillos de pizarra profunda cortada", - "block.create.cut_deepslate_brick_wall": "Muro de ladrillos de pizarra profunda cortada", - "block.create.cut_deepslate_bricks": "Ladrillos de pizarra profunda cortada", - "block.create.cut_deepslate_slab": "Losa de pizarra profunda cortada", - "block.create.cut_deepslate_stairs": "Escaleras de pizarra profunda cortada", - "block.create.cut_deepslate_wall": "Muro de pizarra profunda cortada", - "block.create.cut_diorite": "Diorita cortada", - "block.create.cut_diorite_brick_slab": "Losa de ladrillos de diorita cortada", - "block.create.cut_diorite_brick_stairs": "Escaleras de ladrillos de diorita cortada", - "block.create.cut_diorite_brick_wall": "Muro de ladrillos de diorita cortada", - "block.create.cut_diorite_bricks": "Ladrillos de diorita cortada", - "block.create.cut_diorite_slab": "Losa de diorita cortada", - "block.create.cut_diorite_stairs": "Escaleras de diorita cortada", - "block.create.cut_diorite_wall": "Muro de diorita cortada", - "block.create.cut_dripstone": "Bloque de espeleotema cortado", - "block.create.cut_dripstone_brick_slab": "Losa de ladrillos de espeleotema cortado", - "block.create.cut_dripstone_brick_stairs": "Escaleras de ladrillos de espeleotema cortado", - "block.create.cut_dripstone_brick_wall": "Muro de ladrillos de espeleotema cortado", - "block.create.cut_dripstone_bricks": "Ladrillos de espeleotema cortado", - "block.create.cut_dripstone_slab": "Losa de espeleotema cortado", - "block.create.cut_dripstone_stairs": "Escaleras de espeleotema cortado", - "block.create.cut_dripstone_wall": "Muro de espeleotema cortado", - "block.create.cut_granite": "Granito cortado", - "block.create.cut_granite_brick_slab": "Losa de ladrillos de granito cortado", - "block.create.cut_granite_brick_stairs": "Escaleras de ladrillos de granito cortado", - "block.create.cut_granite_brick_wall": "Muro de ladrillos de granito cortado", - "block.create.cut_granite_bricks": "Ladrillos de granito cortado", - "block.create.cut_granite_slab": "Losa de granito cortado", - "block.create.cut_granite_stairs": "Escaleras de granito cortado", - "block.create.cut_granite_wall": "Muro de granito cortado", - "block.create.cut_limestone": "Piedra caliza cortada", - "block.create.cut_limestone_brick_slab": "Losa de ladrillos de piedra caliza cortada", - "block.create.cut_limestone_brick_stairs": "Escaleras de ladrillos de piedra caliza cortada", - "block.create.cut_limestone_brick_wall": "Muro de ladrillos de piedra caliza cortada", - "block.create.cut_limestone_bricks": "Ladrillos de piedra caliza cortada", - "block.create.cut_limestone_slab": "Losa de piedra caliza cortada", - "block.create.cut_limestone_stairs": "Escaleras de piedra caliza cortada", - "block.create.cut_limestone_wall": "Muro de piedra caliza cortada", - "block.create.cut_ochrum": "Ocre cortado", - "block.create.cut_ochrum_brick_slab": "Losa de ladrillos de ocre cortado", - "block.create.cut_ochrum_brick_stairs": "Escaleras de ladrillos de ocre cortado", - "block.create.cut_ochrum_brick_wall": "Muro de ladrillos de ocre cortado", - "block.create.cut_ochrum_bricks": "Ladrillos de ocre cortado", - "block.create.cut_ochrum_slab": "Losa de ocre cortado", - "block.create.cut_ochrum_stairs": "Escaleras de ocre cortado", - "block.create.cut_ochrum_wall": "Muro de ocre cortado", - "block.create.cut_scorchia": "Escoria oscura cortada", - "block.create.cut_scorchia_brick_slab": "Losa de ladrillos de escoria oscura cortada", - "block.create.cut_scorchia_brick_stairs": "Escaleras de ladrillos de escoria oscura cortada", - "block.create.cut_scorchia_brick_wall": "Muro de ladrillos de escoria oscura cortada", - "block.create.cut_scorchia_bricks": "Ladrillos de escoria oscura cortada", - "block.create.cut_scorchia_slab": "Losa de escoria oscura cortada", - "block.create.cut_scorchia_stairs": "Escaleras de escoria oscura cortada", - "block.create.cut_scorchia_wall": "Muro de escoria oscura cortada", - "block.create.cut_scoria": "Escoria cortada", - "block.create.cut_scoria_brick_slab": "Losa de ladrillos de escoria cortada", - "block.create.cut_scoria_brick_stairs": "Escaleras de ladrillos de escoria cortada", - "block.create.cut_scoria_brick_wall": "Muro de ladrillos de escoria cortada", - "block.create.cut_scoria_bricks": "Ladrillos de escoria cortada", - "block.create.cut_scoria_slab": "Losa de escoria cortada", - "block.create.cut_scoria_stairs": "Escaleras de escoria cortada", - "block.create.cut_scoria_wall": "Muro de escoria cortada", - "block.create.cut_tuff": "Toba cortada", - "block.create.cut_tuff_brick_slab": "Losa de ladrillos de toba cortada", - "block.create.cut_tuff_brick_stairs": "Escaleras de ladrillos de toba cortada", - "block.create.cut_tuff_brick_wall": "Muro de ladrillos de toba cortada", - "block.create.cut_tuff_bricks": "Ladrillos de toba cortada", - "block.create.cut_tuff_slab": "Losa de toba cortada", - "block.create.cut_tuff_stairs": "Escaleras de toba cortada", - "block.create.cut_tuff_wall": "Muro de toba cortada", - "block.create.cut_veridium": "Veridio cortado", - "block.create.cut_veridium_brick_slab": "Losa de ladrillos de veridio cortado", - "block.create.cut_veridium_brick_stairs": "Escaleras de ladrillos de veridio cortado", - "block.create.cut_veridium_brick_wall": "Muro de ladrillos de veridio cortado", - "block.create.cut_veridium_bricks": "Ladrillos de veridio cortado", - "block.create.cut_veridium_slab": "Losa de veridio cortado", - "block.create.cut_veridium_stairs": "Escaleras de veridio cortado", - "block.create.cut_veridium_wall": "Muro de veridio cortado", - "block.create.cyan_nixie_tube": "Tubo Nixie cian", - "block.create.cyan_sail": "Vela cian", - "block.create.cyan_seat": "Asiento cian", - "block.create.cyan_toolbox": "Caja de herramientas cian", - "block.create.cyan_valve_handle": "Asa de válvula cian", - "block.create.dark_oak_window": "Ventana de roble oscuro", - "block.create.dark_oak_window_pane": "Panel de ventana de roble oscuro", - "block.create.deepslate_pillar": "Pilar de pizarra profunda", - "block.create.deepslate_zinc_ore": "Mena de cinc de pizarra profunda", - "block.create.deployer": "Desplegador", - "block.create.depot": "Depósito", - "block.create.diorite_pillar": "Pilar de diorita", - "block.create.display_board": "Pantalla de visualización", - "block.create.display_link": "Enlace de pantalla", - "block.create.dripstone_pillar": "Pilar de espeleotema", - "block.create.encased_chain_drive": "Cadena de transmisión revestida", - "block.create.encased_fan": "Ventilador revestido", - "block.create.encased_fluid_pipe": "Tubería de fluidos de cobre reforzada", - "block.create.exposed_copper_shingle_slab": "Losa de tejas de cobre expuesto", - "block.create.exposed_copper_shingle_stairs": "Escaleras de tejas de cobre expuesto", - "block.create.exposed_copper_shingles": "Bloque de tejas de cobre expuesto", - "block.create.exposed_copper_tile_slab": "Losa de baldosas de cobre expuesto", - "block.create.exposed_copper_tile_stairs": "Escaleras de baldosas de cobre expuesto", - "block.create.exposed_copper_tiles": "Blooque de baldosas de cobre expuesto", - "block.create.fake_track": "Indicador de vía para mapas", - "block.create.fluid_pipe": "Tubería de fluidos de cobre", - "block.create.fluid_tank": "Depósito de fluidos", - "block.create.fluid_valve": "Válvula de fluidos", - "block.create.flywheel": "Rueda de inercia", - "block.create.framed_glass": "Cristal enmarcado", - "block.create.framed_glass_door": "Puerta de cristal enmarcado", - "block.create.framed_glass_pane": "Panel de cristal enmarcado", - "block.create.framed_glass_trapdoor": "Trampilla de cristal enmarcado", - "block.create.gantry_carriage": "Carro de grúa", - "block.create.gantry_shaft": "Eje de grúa", - "block.create.gearbox": "Caja de transmisión", - "block.create.gearshift": "Caja de cambios", - "block.create.glass_fluid_pipe": "Tubería de fluidos de cristal", - "block.create.granite_pillar": "Pilar de granito", - "block.create.gray_nixie_tube": "Tubo Nixie gris", - "block.create.gray_sail": "Vela gris", - "block.create.gray_seat": "Asiento gris", - "block.create.gray_toolbox": "Caja de herramientas gris", - "block.create.gray_valve_handle": "Asa de válvula gris", - "block.create.green_nixie_tube": "Tubo Nixie verde", - "block.create.green_sail": "Vela verde", - "block.create.green_seat": "Asiento verde", - "block.create.green_toolbox": "Caja de herramientas verde", - "block.create.green_valve_handle": "Asa de válvula verde", - "block.create.hand_crank": "Manivela", - "block.create.haunted_bell": "Campana maldita", - "block.create.honey": "Miel", - "block.create.horizontal_framed_glass": "Cristal con marco horizontal", - "block.create.horizontal_framed_glass_pane": "Panel de cristal con marco horizontal", - "block.create.hose_pulley": "Polea de manguera", - "block.create.item_drain": "Drenador de objetos", - "block.create.item_vault": "Bóveda de objetos", - "block.create.jungle_window": "Ventana de jungla", - "block.create.jungle_window_pane": "Panel de ventana de jungla", - "block.create.large_bogey": "Vagón grande", - "block.create.large_cogwheel": "Engranaje grande", - "block.create.layered_andesite": "Andesita estratificada", - "block.create.layered_asurine": "Azurina estratificada", - "block.create.layered_calcite": "Calcita estratificada", - "block.create.layered_crimsite": "Carmesina estratificada", - "block.create.layered_deepslate": "Pizarra profunda estratificada", - "block.create.layered_diorite": "Diorita estratificada", - "block.create.layered_dripstone": "Bloque de espeleotema estratificado", - "block.create.layered_granite": "Granito estratificado", - "block.create.layered_limestone": "Piedra caliza estratificada", - "block.create.layered_ochrum": "Ocre estratificado", - "block.create.layered_scorchia": "Escoria oscura estratificada", - "block.create.layered_scoria": "Escoria estratificada", - "block.create.layered_tuff": "Toba estratificada", - "block.create.layered_veridium": "Veridio estratificado", - "block.create.lectern_controller": "Controlador de atril", - "block.create.light_blue_nixie_tube": "Tubo Nixie azul claro", - "block.create.light_blue_sail": "Vela azul claro", - "block.create.light_blue_seat": "Asiento azul claro", - "block.create.light_blue_toolbox": "Caja de herramientas azul claro", - "block.create.light_blue_valve_handle": "Asa de válvula azul claro", - "block.create.light_gray_nixie_tube": "Tubo Nixie gris claro", - "block.create.light_gray_sail": "Vela gris claro", - "block.create.light_gray_seat": "Asiento gris claro", - "block.create.light_gray_toolbox": "Caja de herramientas gris claro", - "block.create.light_gray_valve_handle": "Asa de válvula gris claro", - "block.create.lime_nixie_tube": "Tubo Nixie lima", - "block.create.lime_sail": "Vela lima", - "block.create.lime_seat": "Asiento lima", - "block.create.lime_toolbox": "Caja de herramientas lima", - "block.create.lime_valve_handle": "Asa de válvula lima", - "block.create.limestone": "Piedra caliza", - "block.create.limestone_pillar": "Pilar de piedra caliza", - "block.create.linear_chassis": "Chasis lineal", - "block.create.lit_blaze_burner": "Quemador de Blaze encendido", - "block.create.magenta_nixie_tube": "Tubo Nixie magenta", - "block.create.magenta_sail": "Vela magenta", - "block.create.magenta_seat": "Asiento magenta", - "block.create.magenta_toolbox": "Caja de herramientas magenta", - "block.create.magenta_valve_handle": "Asa de válvula magenta", - "block.create.mechanical_arm": "Brazo mecánico", - "block.create.mechanical_bearing": "Rodamiento mecánico", - "block.create.mechanical_crafter": "Ensamblador mecánico", - "block.create.mechanical_drill": "Taladro mecánico", - "block.create.mechanical_harvester": "Cosechadora mecánica", - "block.create.mechanical_mixer": "Mezcladora mecánica", - "block.create.mechanical_piston": "Pistón mecánico", - "block.create.mechanical_piston_head": "Cabezal de pistón mecánico", - "block.create.mechanical_plough": "Arado mecánico", - "block.create.mechanical_press": "Prensa mecánica", - "block.create.mechanical_pump": "Bomba mecánica", - "block.create.mechanical_saw": "Sierra mecánica", - "block.create.metal_bracket": "Soporte de metal para ejes", - "block.create.metal_girder": "Viga de metal", - "block.create.metal_girder_encased_shaft": "Eje revestido con viga de metal", - "block.create.millstone": "Piedra de molino", - "block.create.minecart_anchor": "Ancla de vagonetas", - "block.create.mysterious_cuckoo_clock": "Reloj de cuco", - "block.create.nixie_tube": "Tubo Nixie", - "block.create.nozzle": "Boquilla", - "block.create.oak_window": "Ventana de roble", - "block.create.oak_window_pane": "Panel de ventana de roble", - "block.create.ochrum": "Ocre", - "block.create.ochrum_pillar": "Pilar de ocre", - "block.create.orange_sail": "Vela naranja", - "block.create.orange_seat": "Asiento naranja", - "block.create.orange_toolbox": "Caja de herramientas naranja", - "block.create.orange_valve_handle": "Asa de válvula naranja", - "block.create.ornate_iron_window": "Ventana de hierro ornamentada", - "block.create.ornate_iron_window_pane": "Panel de ventana de hierro ornamentada", - "block.create.oxidized_copper_shingle_slab": "Losa de tejas de cobre oxidado", - "block.create.oxidized_copper_shingle_stairs": "Escaleras de tejas de cobre oxidado", - "block.create.oxidized_copper_shingles": "Bloque de tejas de cobre oxidado", - "block.create.oxidized_copper_tile_slab": "Losa de baldosas de cobre oxidado", - "block.create.oxidized_copper_tile_stairs": "Escaleras de baldosas de cobre oxidado", - "block.create.oxidized_copper_tiles": "Bloque de baldosas de cobre oxidado", - "block.create.peculiar_bell": "Campana peculiar", - "block.create.pink_nixie_tube": "Tubo Nixie rosa", - "block.create.pink_sail": "Vela rosa", - "block.create.pink_seat": "Asiento rosa", - "block.create.pink_toolbox": "Caja de herramientas rosa", - "block.create.pink_valve_handle": "Asa de válvula rosa", - "block.create.piston_extension_pole": "Pértiga de extensión de pistón", - "block.create.placard": "Pancarta", - "block.create.polished_cut_andesite": "Andesita cortada pulida", - "block.create.polished_cut_andesite_slab": "Losa de andesita cortada pulida", - "block.create.polished_cut_andesite_stairs": "Escaleras de andesita cortada pulida", - "block.create.polished_cut_andesite_wall": "Muro de andesita cortada pulida", - "block.create.polished_cut_asurine": "Azurina cortada pulida", - "block.create.polished_cut_asurine_slab": "Losa de azurina cortada pulida", - "block.create.polished_cut_asurine_stairs": "Escaleras de azurina cortada pulida", - "block.create.polished_cut_asurine_wall": "Muro de azurina cortada pulida", - "block.create.polished_cut_calcite": "Calcita cortada pulida", - "block.create.polished_cut_calcite_slab": "Losa de calcita cortada pulida", - "block.create.polished_cut_calcite_stairs": "Escaleras de calcita cortada pulida", - "block.create.polished_cut_calcite_wall": "Muro de calcita cortada pulida", - "block.create.polished_cut_crimsite": "Carmesina cortada pulida", - "block.create.polished_cut_crimsite_slab": "Losa de carmesina cortada pulida", - "block.create.polished_cut_crimsite_stairs": "Escaleras de carmesina cortada pulida", - "block.create.polished_cut_crimsite_wall": "Muro de carmesina cortada pulida", - "block.create.polished_cut_deepslate": "Pizarra profunda cortada pulida", - "block.create.polished_cut_deepslate_slab": "Losa de pizarra profunda cortada pulida", - "block.create.polished_cut_deepslate_stairs": "Escaleras de pizarra profunda cortada pulida", - "block.create.polished_cut_deepslate_wall": "Muro de pizarra profunda cortada pulida", - "block.create.polished_cut_diorite": "Diorita cortada pulida", - "block.create.polished_cut_diorite_slab": "Losa de diorita cortada pulida", - "block.create.polished_cut_diorite_stairs": "Escaleras de diorita cortada pulida", - "block.create.polished_cut_diorite_wall": "Muro de diorita cortada pulida", - "block.create.polished_cut_dripstone": "Bloque de espeleotema cortado pulido", - "block.create.polished_cut_dripstone_slab": "Losa de espeleotema cortado pulido", - "block.create.polished_cut_dripstone_stairs": "Escaleras de espeleotema cortado pulido", - "block.create.polished_cut_dripstone_wall": "Muro de espeleotema cortado pulido", - "block.create.polished_cut_granite": "Granito cortado pulido", - "block.create.polished_cut_granite_slab": "Losa de granito cortado pulido", - "block.create.polished_cut_granite_stairs": "Escaleras de granito cortado pulido", - "block.create.polished_cut_granite_wall": "Muro de granito cortado pulido", - "block.create.polished_cut_limestone": "Piedra caliza cortada pulida", - "block.create.polished_cut_limestone_slab": "Losa de piedra caliza cortada pulida", - "block.create.polished_cut_limestone_stairs": "Escaleras de piedra caliza cortada pulida", - "block.create.polished_cut_limestone_wall": "Muro de piedra caliza cortada pulida", - "block.create.polished_cut_ochrum": "Ocre cortado pulido", - "block.create.polished_cut_ochrum_slab": "Losa de ocre cortado pulido", - "block.create.polished_cut_ochrum_stairs": "Escaleras de ocre cortado pulido", - "block.create.polished_cut_ochrum_wall": "Muro de ocre cortado pulido", - "block.create.polished_cut_scorchia": "Escoria oscura cortada pulida", - "block.create.polished_cut_scorchia_slab": "Losa de escoria oscura cortada pulida", - "block.create.polished_cut_scorchia_stairs": "Escalera de escoria oscura cortada pulida", - "block.create.polished_cut_scorchia_wall": "Muro de escoria oscura cortada pulida", - "block.create.polished_cut_scoria": "Escoria cortada pulida", - "block.create.polished_cut_scoria_slab": "Losa de escoria cortada pulida", - "block.create.polished_cut_scoria_stairs": "Escaleras de escoria cortada pulida", - "block.create.polished_cut_scoria_wall": "Muro de escoria cortada pulida", - "block.create.polished_cut_tuff": "Toba cortada pulida", - "block.create.polished_cut_tuff_slab": "Losa de toba cortada pulida", - "block.create.polished_cut_tuff_stairs": "Escaleras de toba cortada pulida", - "block.create.polished_cut_tuff_wall": "Muro de toba cortada pulida", - "block.create.polished_cut_veridium": "Veridio cortado pulido", - "block.create.polished_cut_veridium_slab": "Losa de veridio cortado pulido", - "block.create.polished_cut_veridium_stairs": "Escaleras de veridio cortado pulido", - "block.create.polished_cut_veridium_wall": "Muro de veridio cortado pulido", - "block.create.portable_fluid_interface": "Interfaz de fluidos portátil", - "block.create.portable_storage_interface": "Interfaz de almacenamiento portátil", - "block.create.powered_latch": "Palanca motorizada", - "block.create.powered_shaft": "Eje motorizado", - "block.create.powered_toggle_latch": "Palanca de cierre motorizada", - "block.create.pulley_magnet": "Imán de la polea", - "block.create.pulse_extender": "Extensor de pulso", - "block.create.pulse_repeater": "Repetidor de pulsos de redstone", - "block.create.purple_nixie_tube": "Tubo Nixie morado", - "block.create.purple_sail": "Vela morada", - "block.create.purple_seat": "Asiento morado", - "block.create.purple_toolbox": "Caja de herramientas púrpura", - "block.create.purple_valve_handle": "Asa de válvula morada", - "block.create.radial_chassis": "Chasis radial", - "block.create.railway_casing": "Revestidor de tren", - "block.create.raw_zinc_block": "Bloque de cinc en bruto", - "block.create.red_nixie_tube": "Tubo Nixie rojo", - "block.create.red_sail": "Vela roja", - "block.create.red_seat": "Asiento rojo", - "block.create.red_toolbox": "Caja de herramientas roja", - "block.create.red_valve_handle": "Asa de válvula roja", - "block.create.redstone_contact": "Contacto de redstone", - "block.create.redstone_link": "Enlace de redstone", - "block.create.refined_radiance_casing": "Revestidor radiante", - "block.create.rope": "Cuerda", - "block.create.rope_pulley": "Polea de cuerda", - "block.create.rose_quartz_block": "Bloque de cuarzo rosado", - "block.create.rose_quartz_lamp": "Lámpara de cuarzo rosado", - "block.create.rose_quartz_tiles": "Baldosas de cuarzo rosado", - "block.create.rotation_speed_controller": "Controlador de velocidad rotacional", - "block.create.sail_frame": "Marco de vela", - "block.create.schematic_table": "Tabla de esquemas", - "block.create.schematicannon": "Esquematicañón", - "block.create.scorchia": "Escoria oscura", - "block.create.scorchia_pillar": "Pilar de escoria oscura", - "block.create.scoria": "Escoria", - "block.create.scoria_pillar": "Pilar de escoria", - "block.create.secondary_linear_chassis": "Chasis lineal secundario", - "block.create.sequenced_gearshift": "Caja de cambios secuencial", - "block.create.shadow_steel_casing": "Revestidor sombrío", - "block.create.shaft": "Eje", - "block.create.small_andesite_brick_slab": "Losa de ladrillos pequeños de andesita", - "block.create.small_andesite_brick_stairs": "Escaleras de ladrillos pequeños de andesita", - "block.create.small_andesite_brick_wall": "Muro de ladrillos pequeños de andesita", - "block.create.small_andesite_bricks": "Ladrillos pequeños de andesita", - "block.create.small_asurine_brick_slab": "Losa de ladrillos pequeños de azurina", - "block.create.small_asurine_brick_stairs": "Escaleras de ladrillos pequeños de azurina", - "block.create.small_asurine_brick_wall": "Muro de ladrillos pequeños de azurina", - "block.create.small_asurine_bricks": "Ladrillos pequeños de azurina", - "block.create.small_bogey": "Vagón pequeño", - "block.create.small_calcite_brick_slab": "Losa de ladrillos pequeños de calcita", - "block.create.small_calcite_brick_stairs": "Escaleras de ladrillos pequeños de calcita", - "block.create.small_calcite_brick_wall": "Muro de ladrillos pequeños de calcita", - "block.create.small_calcite_bricks": "Ladrillos pequeños de calcita", - "block.create.small_crimsite_brick_slab": "Losa de ladrillos pequeños de carmesina", - "block.create.small_crimsite_brick_stairs": "Escaleras de ladrillos pequeños de carmesina", - "block.create.small_crimsite_brick_wall": "Muro de ladrillos pequeños de carmesina", - "block.create.small_crimsite_bricks": "Ladrillos pequeños de carmesina", - "block.create.small_deepslate_brick_slab": "Losa de ladrillos pequeños de pizarra profunda", - "block.create.small_deepslate_brick_stairs": "Escaleras de ladrillos pequeños de pizarra profunda", - "block.create.small_deepslate_brick_wall": "Muro de ladrillos pequeños de pizarra profunda", - "block.create.small_deepslate_bricks": "Ladrillos pequeños de pizarra profunda", - "block.create.small_diorite_brick_slab": "Losa de ladrillos pequeños de diorita", - "block.create.small_diorite_brick_stairs": "Escaleras de ladrillos pequeños de diorita", - "block.create.small_diorite_brick_wall": "Muro de ladrillos pequeños de diorita", - "block.create.small_diorite_bricks": "Ladrillos pequeños de diorita", - "block.create.small_dripstone_brick_slab": "Losa de ladrillos pequeños de espeleotema", - "block.create.small_dripstone_brick_stairs": "Escaleras de ladrillos pequeños de espeleotema", - "block.create.small_dripstone_brick_wall": "Muro de ladrillos pequeños de espeleotema", - "block.create.small_dripstone_bricks": "Ladrillos pequeños de espeleotema", - "block.create.small_granite_brick_slab": "Losa de ladrillos pequeños de granito", - "block.create.small_granite_brick_stairs": "Escaleras de ladrillos pequeños de granito", - "block.create.small_granite_brick_wall": "Muro de ladrillos pequeños de granito", - "block.create.small_granite_bricks": "Ladrillos pequeños de granito", - "block.create.small_limestone_brick_slab": "Losa de ladrillos pequeños de piedra caliza", - "block.create.small_limestone_brick_stairs": "Escaleras de ladrillos pequeños de piedra caliza", - "block.create.small_limestone_brick_wall": "Muro de ladrillos pequeños de piedra caliza", - "block.create.small_limestone_bricks": "Ladrillos pequeños de piedra caliza", - "block.create.small_ochrum_brick_slab": "Losa de ladrillos pequeños de ocre", - "block.create.small_ochrum_brick_stairs": "Escalera de ladrillos pequeños de ocre", - "block.create.small_ochrum_brick_wall": "Muro de ladrillos pequeños de ocre", - "block.create.small_ochrum_bricks": "Ladrillos pequeños de ocre", - "block.create.small_rose_quartz_tiles": "Baldosas pequeñas de cuarzo rosado", - "block.create.small_scorchia_brick_slab": "Losa de ladrillos pequeños de escoria oscura", - "block.create.small_scorchia_brick_stairs": "Escaleras de ladrillos pequeños de escoria oscura", - "block.create.small_scorchia_brick_wall": "Muro de ladrillos pequeños de escoria oscura", - "block.create.small_scorchia_bricks": "Ladrillos pequeños de escoria oscura", - "block.create.small_scoria_brick_slab": "Losa de ladrillos pequeños de escoria", - "block.create.small_scoria_brick_stairs": "Escaleras de ladrillos pequeños de escoria", - "block.create.small_scoria_brick_wall": "Muro de ladrillos pequeños de escoria", - "block.create.small_scoria_bricks": "Ladrillos pequeños de escoria", - "block.create.small_tuff_brick_slab": "Losa de ladrillos pequeños de toba", - "block.create.small_tuff_brick_stairs": "Escaleras de ladrillos pequeños de toba", - "block.create.small_tuff_brick_wall": "Muro de ladrillos pequeños de toba", - "block.create.small_tuff_bricks": "Ladrillos pequeños de toba", - "block.create.small_veridium_brick_slab": "Losa de ladrillos pequeños de veridio", - "block.create.small_veridium_brick_stairs": "Escaleras de ladrillos pequeños de veridio", - "block.create.small_veridium_brick_wall": "Muro de ladrillos pequeños de veridio", - "block.create.small_veridium_bricks": "Ladrillos pequeños de veridio", - "block.create.smart_chute": "Ducto inteligente", - "block.create.smart_fluid_pipe": "Tubería de fluidos inteligente", - "block.create.speedometer": "Velocímetro", - "block.create.spout": "Surtidor", - "block.create.spruce_window": "Ventana de abeto", - "block.create.spruce_window_pane": "Panel de ventana de abeto", - "block.create.steam_engine": "Motor de vapor", - "block.create.steam_whistle": "Silbato de vapor", - "block.create.steam_whistle_extension": "Extensión de silbato de vapor", - "block.create.sticker": "Pegatina", - "block.create.sticky_mechanical_piston": "Pistón mecánico pegajoso", - "block.create.stockpile_switch": "Interruptor de acopio", - "block.create.stressometer": "Estresómetro", - "block.create.tiled_glass": "Vidrio esmaltado", - "block.create.tiled_glass_pane": "Panel de vidrio esmaltado", - "block.create.track": "Vía de tren", - "block.create.track_observer": "Observador de tren", - "block.create.track_signal": "Señal de tren", - "block.create.track_station": "Estación de tren", - "block.create.train_door": "Puerta de tren", - "block.create.train_trapdoor": "Trampilla de tren", - "block.create.tuff_pillar": "Pilar de toba", - "block.create.turntable": "Plataforma giratoria mecánica", - "block.create.veridium": "Veridio", - "block.create.veridium_pillar": "Pilar de veridio", - "block.create.vertical_framed_glass": "Vidrio esmaltado vertical", - "block.create.vertical_framed_glass_pane": "Panel de vidrio esmaltado vertical", - "block.create.warped_window": "Ventana distorsionada", - "block.create.warped_window_pane": "Panel de ventana distorsionada", - "block.create.water_wheel": "Rueda hidráulica mecánica", - "block.create.waxed_copper_shingle_slab": "Losa de tejas de cobre encerado", - "block.create.waxed_copper_shingle_stairs": "Escaleras de tejas de cobre encerado", - "block.create.waxed_copper_shingles": "Bloque de tejas de cobre encerado", - "block.create.waxed_copper_tile_slab": "Losa de baldosas de cobre encerado", - "block.create.waxed_copper_tile_stairs": "Escaleras de baldosas de cobre encerado", - "block.create.waxed_copper_tiles": "Bloque de baldosas de cobre encerado", - "block.create.waxed_exposed_copper_shingle_slab": "Losa de tejas de cobre expuesto encerado", - "block.create.waxed_exposed_copper_shingle_stairs": "Escaleras de tejas de cobre expuesto encerado", - "block.create.waxed_exposed_copper_shingles": "Bloque de tejas de cobre expuesto encerado", - "block.create.waxed_exposed_copper_tile_slab": "Losa de baldosas de cobre expuesto encerado", - "block.create.waxed_exposed_copper_tile_stairs": "Escaleras de baldosas de cobre expuesto encerado", - "block.create.waxed_exposed_copper_tiles": "Bloque de baldosas de cobre expuesto encerado", - "block.create.waxed_oxidized_copper_shingle_slab": "Losa de tejas de cobre oxidado encerado", - "block.create.waxed_oxidized_copper_shingle_stairs": "Escaleras de tejas de cobre oxidado encerado", - "block.create.waxed_oxidized_copper_shingles": "Bloque de tejas de cobre oxidado encerado", - "block.create.waxed_oxidized_copper_tile_slab": "Losa de baldosas de cobre oxidado encerado", - "block.create.waxed_oxidized_copper_tile_stairs": "Escaleras de baldosas de cobre oxidado encerado", - "block.create.waxed_oxidized_copper_tiles": "Bloque de baldosas de cobre oxidado encerado", - "block.create.waxed_weathered_copper_shingle_slab": "Losa de tejas de cobre degradado encerado", - "block.create.waxed_weathered_copper_shingle_stairs": "Escaleras de tejas de cobre degradado encerado", - "block.create.waxed_weathered_copper_shingles": "Bloque de tejas de cobre degradado encerado", - "block.create.waxed_weathered_copper_tile_slab": "Losa de baldosas de cobre degradado encerado", - "block.create.waxed_weathered_copper_tile_stairs": "Escaleras de baldosas de cobre degradado encerado", - "block.create.waxed_weathered_copper_tiles": "Bloque de baldosas de cobre degradado encerado", - "block.create.weathered_copper_shingle_slab": "Losa de tejas de cobre degradado", - "block.create.weathered_copper_shingle_stairs": "Escaleras de tejas de cobre degradado", - "block.create.weathered_copper_shingles": "Bloque de tejas de cobre degradado", - "block.create.weathered_copper_tile_slab": "Losa de baldosas de cobre degradado", - "block.create.weathered_copper_tile_stairs": "Escaleras de baldosas de cobre degradado", - "block.create.weathered_copper_tiles": "Bloque de baldosas de cobre degradado", - "block.create.weighted_ejector": "Eyector de peso", - "block.create.white_nixie_tube": "Tubo Nixie blanco", - "block.create.white_sail": "Vela blanca", - "block.create.white_seat": "Asiento blanco", - "block.create.white_toolbox": "Caja de herramientas blanca", - "block.create.white_valve_handle": "Asa de válvula blanco", - "block.create.windmill_bearing": "Rodamiento de molino de viento", - "block.create.wooden_bracket": "Soporte de madera para ejes", - "block.create.yellow_nixie_tube": "Tubo Nixie amarillo", - "block.create.yellow_sail": "Vela amarilla", - "block.create.yellow_seat": "Asiento amarillo", - "block.create.yellow_toolbox": "Caja de herramientas amarilla", - "block.create.yellow_valve_handle": "Asa de válvula amarillo", - "block.create.zinc_block": "Bloque de cinc", - "block.create.zinc_ore": "Mena de cinc", - - "enchantment.create.capacity": "Capacidad", - "enchantment.create.potato_recovery": "Recuperación de patatas", - - "entity.create.carriage_contraption": "Artefacto animado de carruaje", - "entity.create.contraption": "Artefacto animado", - "entity.create.crafting_blueprint": "Plano de elaboración", - "entity.create.gantry_contraption": "Artefacto móvil de grúa", - "entity.create.potato_projectile": "Proyectil de patata", - "entity.create.seat": "Asiento", - "entity.create.stationary_contraption": "Artefacto estacionario", - "entity.create.super_glue": "Pegamento", - - "fluid.create.potion": "Poción", - "fluid.create.tea": "Té del Constructor", - - "item.create.andesite_alloy": "Aleación de andesita", - "item.create.attribute_filter": "Filtro de atributos", - "item.create.bar_of_chocolate": "Barra de chocolate", - "item.create.belt_connector": "Correa mecánica", - "item.create.blaze_cake": "Pastel de blaze", - "item.create.blaze_cake_base": "Base de pastel de blaze", - "item.create.brass_hand": "Mano de latón", - "item.create.brass_ingot": "Lingote de latón", - "item.create.brass_nugget": "Pepita de latón", - "item.create.brass_sheet": "Lámina de latón", - "item.create.builders_tea": "Té del Constructor", - "item.create.chest_minecart_contraption": "Artefacto móvil de vagoneta con cofre", - "item.create.chocolate_bucket": "Cubo con chocolate", - "item.create.chocolate_glazed_berries": "Bayas glaseadas con chocolate", - "item.create.chromatic_compound": "Compuesto cromático", - "item.create.cinder_flour": "Harina del Nether", - "item.create.copper_backtank": "Depósito trasero de cobre", - "item.create.copper_backtank_placeable": "Depósito de cobre colocable", - "item.create.copper_nugget": "Pepita de cobre", - "item.create.copper_sheet": "Lámina de cobre", - "item.create.crafter_slot_cover": "Tapa de ranura del ensamblador mecánico", - "item.create.crafting_blueprint": "Plano de elaboración", - "item.create.creative_blaze_cake": "Pastel de blaze creativo", - "item.create.crushed_aluminum_ore": "Mineral de aluminio molido", - "item.create.crushed_copper_ore": "Mineral de cobre molido", - "item.create.crushed_gold_ore": "Mineral de oro molido", - "item.create.crushed_iron_ore": "Mineral de hierro molido", - "item.create.crushed_lead_ore": "Mineral de plomo molido", - "item.create.crushed_nickel_ore": "Mineral de níquel molido", - "item.create.crushed_osmium_ore": "Mineral de osmio molido", - "item.create.crushed_platinum_ore": "Mineral de platino molido", - "item.create.crushed_quicksilver_ore": "Mineral de mercurio molido", - "item.create.crushed_silver_ore": "Mineral de plata molido", - "item.create.crushed_tin_ore": "Mineral de estaño molido", - "item.create.crushed_uranium_ore": "Mineral de uranio molido", - "item.create.crushed_zinc_ore": "Mineral de cinc molido", - "item.create.diving_boots": "Botas de buceo", - "item.create.diving_helmet": "Casco de buceo", - "item.create.dough": "Masa", - "item.create.electron_tube": "Tubo de electrones", - "item.create.empty_blaze_burner": "Quemador de blaze vacío", - "item.create.empty_schematic": "Esquema vacío", - "item.create.experience_nugget": "Pepita de experiencia", - "item.create.extendo_grip": "Agarre extendido", - "item.create.filter": "Filtro", - "item.create.furnace_minecart_contraption": "Artefacto móvil de vagoneta con horno", - "item.create.goggles": "Gafas del ingeniero", - "item.create.golden_sheet": "Lámina de oro", - "item.create.handheld_worldshaper": "Moldeador de mundos", - "item.create.honey_bucket": "Cubo con miel", - "item.create.honeyed_apple": "Manzana con miel", - "item.create.incomplete_precision_mechanism": "Mecanismo de precisión incompleto", - "item.create.incomplete_track": "Vía incompleta", - "item.create.iron_sheet": "Lámina de hierro", - "item.create.linked_controller": "Controlador enlazado", - "item.create.minecart_contraption": "Artefacto móvil de vagoneta", - "item.create.minecart_coupling": "Acoplamiento de vagoneta", - "item.create.polished_rose_quartz": "Cuarzo rosado pulido", - "item.create.potato_cannon": "Cañón de patatas", - "item.create.powdered_obsidian": "Polvo de obsidiana", - "item.create.precision_mechanism": "Mecanismo de precisión", - "item.create.propeller": "Hélice", - "item.create.raw_zinc": "Cinc en bruto", - "item.create.red_sand_paper": "Papel de lija rojo", - "item.create.refined_radiance": "Resplandor refinado", - "item.create.rose_quartz": "Cuarzo rosado", - "item.create.sand_paper": "Papel de lija", - "item.create.schedule": "Programación de tren", - "item.create.schematic": "Esquema", - "item.create.schematic_and_quill": "Esquema y pluma", - "item.create.shadow_steel": "Acero sombrío", - "item.create.sturdy_sheet": "Lámina robusta", - "item.create.super_glue": "Pegamento", - "item.create.sweet_roll": "Ensaimada", - "item.create.tree_fertilizer": "Fertilizante para árboles", - "item.create.unprocessed_obsidian_sheet": "Lámina de obsidiana sin procesar", - "item.create.vertical_gearbox": "Caja de transmisión vertical", - "item.create.wand_of_symmetry": "Varita de simetría", - "item.create.wheat_flour": "Harina de trigo", - "item.create.whisk": "Batidora", - "item.create.wrench": "Llave inglesa", - "item.create.zinc_ingot": "Lingote de cinc", - "item.create.zinc_nugget": "Pepita de cinc", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bienvenido a Create", - "advancement.create.root.desc": "¡Es hora de empezar a construir increíbles artefactos animados!", - "advancement.create.andesite_alloy": "Aliteraciones a montones", - "advancement.create.andesite_alloy.desc": "Los materiales de Create tienen nombres extraños, la aleación de andesita es uno de ellos.", - "advancement.create.andesite_casing": "La edad de la andesita", - "advancement.create.andesite_casing.desc": "Utiliza un poco de aleación de andesita y madera para crear un revestimiento básico.", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "Crea láminas en una prensa mecánica", - "advancement.create.encased_fan": "Fabricante de viento", - "advancement.create.encased_fan.desc": "Coloca y activa un ventilador revestido", - "advancement.create.fan_processing": "Procesado por partículas", - "advancement.create.fan_processing.desc": "Usa un ventilador revestido para procesar materiales", - "advancement.create.saw_processing": "El más temido del taller", - "advancement.create.saw_processing.desc": "Usa una sierra mecánica boca arriba para procesar materiales", - "advancement.create.compacting": "Compactificación", - "advancement.create.compacting.desc": "Usa una prensa y una cuenca para crear pocos objetos de muchos objetos", - "advancement.create.belt": "Paseo de algas", - "advancement.create.belt.desc": "Conecta dos ejes con una cinta.", - "advancement.create.funnel": "Estética de aeropuerto", - "advancement.create.funnel.desc": "Extrae o inserta objetos en un contenedor usando un embudo", - "advancement.create.chute": "Caída en picado", - "advancement.create.chute.desc": "Coloque un ducto, la contrapartida vertical de la cinta mecánica.", - "advancement.create.mechanical_mixer": "Bien mezcladito", - "advancement.create.mechanical_mixer.desc": "Combina ingredientes en una mezcladora mecánica", - "advancement.create.burner": "Hoguera con sentimientos", - "advancement.create.burner.desc": "Obtén un quemador de blaze", - "advancement.create.water_wheel": "Aprovechar la hidráulica", - "advancement.create.water_wheel.desc": "Coloca una rueda hidráulica e intenta hacerla girar.", - "advancement.create.windmill": "Una suave brisa", - "advancement.create.windmill.desc": "Monta un molino de viento.", - "advancement.create.shifting_gears": "Cambiando de marcha", - "advancement.create.shifting_gears.desc": "Conecta un engranaje grande a una pequeña, lo que te permitirá cambiar la velocidad rotacional.", - "advancement.create.millstone": "Triturador de bolsillo", - "advancement.create.millstone.desc": "Coloca y alimenta una piedra de molino.", - "advancement.create.super_glue": "Área de conexión", - "advancement.create.super_glue.desc": "Pega varios bloques en un grupo", - "advancement.create.contraption_actors": "Moviéndose con un propósito", - "advancement.create.contraption_actors.desc": "Crea un artefacto móvil que contenga taladros, sierras o cosechadoras", - "advancement.create.portable_storage_interface": "Intercambio de autoservicio", - "advancement.create.portable_storage_interface.desc": "Usa una interfaz de almacenamiento portátil para introducir o extraer objetos de un artefacto móvil", - "advancement.create.wrench_goggles": "Equipado", - "advancement.create.wrench_goggles.desc": "Equípate las gafas del ingeniero y una llave inglesa", - "advancement.create.stressometer": "Pero, ¿cuán estresado exactamente?", - "advancement.create.stressometer.desc": "Coloca y alimenta un estresómetro. Míralo a través de las gafas del ingeniero para leer su valor exacto.", - "advancement.create.cuckoo_clock": "¿Llegó la hora?", - "advancement.create.cuckoo_clock.desc": "Sé testigo del reloj de cuco avisando la hora de dormir", - "advancement.create.windmill_maxed": "Una fuerte brisa", - "advancement.create.windmill_maxed.desc": "Ensambla un molino de viento de máxima potencia", - "advancement.create.ejector_maxed": "Campeón de trampolín", - "advancement.create.ejector_maxed.desc": "Haz que un eyector de peso te lance mas allá de 30 bloques", - "advancement.create.pulley_maxed": "Cuerda huida", - "advancement.create.pulley_maxed.desc": "Usa una polea de cuerda por más de 200 bloques", - "advancement.create.cart_pickup": "Brazos fuertes", - "advancement.create.cart_pickup.desc": "Recoge un artefacto móvil de vagoneta de al menos 200 bloques", - "advancement.create.anvil_plough": "Artillería de herrero", - "advancement.create.anvil_plough.desc": "Lanza un yunque con un eyector de peso", - "advancement.create.lava_wheel_00000": "Rueda de magma", - "advancement.create.lava_wheel_00000.desc": "No debería de haber funcionado§7\n(Logro oculto)", - "advancement.create.hand_crank_000": "Sesión de entrenamiento", - "advancement.create.hand_crank_000.desc": "Usa una manivela hasta que te agotes por completo§7\n(Logro Oculto)", - "advancement.create.belt_funnel_kiss": "Los loros y las aletas", - "advancement.create.belt_funnel_kiss.desc": "Haz que se besen dos embudos montados en una cinta mecánica.", - "advancement.create.stressometer_maxed": "Perfectamente estresado", - "advancement.create.stressometer_maxed.desc": "Obtén una lectura de 100% de un estresómetro§7\n(Logro oculto)", - "advancement.create.copper": "Rocas más robustas", - "advancement.create.copper.desc": "Consigue cobre para tus explocationes en la manipulación de fluidos", - "advancement.create.copper_casing": "La Edad de Cobre", - "advancement.create.copper_casing.desc": "Utiliza algunas láminas de cobre y madera para crear algunos revestimientos de cobre.", - "advancement.create.spout": "¡Paf!", - "advancement.create.spout.desc": "Observa como se llena un objeto con algún fluido usando una boquilla.", - "advancement.create.drain": "Tambor de drenaje", - "advancement.create.drain.desc": "Mira cómo un objeto que contiene un fluido se vacía usando un drenador de objetos", - "advancement.create.steam_engine": "La central eléctrica", - "advancement.create.steam_engine.desc": "Usa un motor de vapor para generar torque", - "advancement.create.steam_whistle": "Voz angelical", - "advancement.create.steam_whistle.desc": "Activa un silbato de vapor", - "advancement.create.backtank": "¡Qué presión!", - "advancement.create.backtank.desc": "Crea un depósito trasero de cobre y haz que acumule presión de aire", - "advancement.create.diving_suit": "Preparado para las profundidades", - "advancement.create.diving_suit.desc": "Equípate un casco de buceo junto a tu depósito trasero y sumérgete en el agua", - "advancement.create.mechanical_pump_0": "Bajo presión", - "advancement.create.mechanical_pump_0.desc": "Coloca y activa una bomba mecánica", - "advancement.create.glass_pipe": "Espía del flujo", - "advancement.create.glass_pipe.desc": "Observa cómo se propaga el fluido a través de un tubo de fluidos con ventanas. Los tubos de fluido rectos se convierten en ventanas cuando se utiliza una llave inglesa en ellas.", - "advancement.create.water_supply": "Colector de charcos", - "advancement.create.water_supply.desc": "Usa el final de una tubería para recoger o verter agua", - "advancement.create.hose_pulley": "Vertidos industriales", - "advancement.create.hose_pulley.desc": "Baja una polea de manguera y ve cómo se vacía o se llena un cuerpo de líquido.", - "advancement.create.chocolate_bucket": "Un mundo de imaginación", - "advancement.create.chocolate_bucket.desc": "Obtén un cubo de chocolate derretido", - "advancement.create.honey_drain": "Apicultura autónoma", - "advancement.create.honey_drain.desc": "Usa tuberías para sacar miel de una colmena o apiario", - "advancement.create.hose_pulley_lava": "Tocando el manto", - "advancement.create.hose_pulley_lava.desc": "Extrae lava de una piscina de lava suficientemente grande para considerarse infinita", - "advancement.create.steam_engine_maxed": "A todo vapor", - "advancement.create.steam_engine_maxed.desc": "Ten una caldera al niveo de potencia máximo", - "advancement.create.foods": "Dieta balanceada", - "advancement.create.foods.desc": "Crea bayas glaseadas con chocolate, una manzana con miel y una ensaimada; todas por la misma boquilla", - "advancement.create.diving_suit_lava": "Nadando con los lavagantes", - "advancement.create.diving_suit_lava.desc": "Intenta bucear en lava con tu equipo de buceo§7\n(Logro oculto)", - "advancement.create.chained_drain": "On a Roll", - "advancement.create.chained_drain.desc": "Watch an Item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "Don't cross the Streams!", - "advancement.create.cross_streams.desc": "Mira cómo dos fluidos se encuentran en tu sistema de tuberías§7\n(Logro oculto)", - "advancement.create.pipe_organ": "Órgano de tuberías", - "advancement.create.pipe_organ.desc": "Coloca 12 silbatos de vapor con un tono único al mismo depósito de fluidos§7\n(Logro oculto)", - "advancement.create.brass": "Aleaciones reales", - "advancement.create.brass.desc": "Utiliza cobre molido y cinc molido para crear algo de latón.", - "advancement.create.brass_casing": "La Edad de Latón", - "advancement.create.brass_casing.desc": "Utiliza el latón recién obtenido y algo de madera para crear un revestimiento más avanzado.", - "advancement.create.rose_quartz": "Diamantes rosas", - "advancement.create.rose_quartz.desc": "Pule cuarzo rosado", - "advancement.create.deployer": "Picar, colocar y atacar", - "advancement.create.deployer.desc": "Coloca y potencia un desplegador, el reflejo perfecto de ti mismo.", - "advancement.create.precision_mechanism": "Curiosidades complejas", - "advancement.create.precision_mechanism.desc": "Monta un mecanismo de precisión.", - "advancement.create.speed_controller": "¡Los ingenieros lo odian!", - "advancement.create.speed_controller.desc": "Coloca un controlador de velocidad rotacional, el dispositivo definitivo para cambiar de marcha.", - "advancement.create.mechanical_arm": "¡Manos ocupadas!", - "advancement.create.mechanical_arm.desc": "Crea un brazo mecánico, selecciona las entradas y salidas, colócalo en el suelo y dale energía; luego observa cómo hace todo el trabajo por ti.", - "advancement.create.mechanical_crafter": "Montaje automatizado", - "advancement.create.mechanical_crafter.desc": "Coloca y activa unos ensambladores mecánicos", - "advancement.create.crushing_wheel": "Un par de gigantes", - "advancement.create.crushing_wheel.desc": "Crea algunas ruedas de trituración para descomponer más materiales de forma más eficaz.", - "advancement.create.haunted_bell": "Sentido sombrío", - "advancement.create.haunted_bell.desc": "Toca una campana maldita", - "advancement.create.clockwork_bearing": "Las artefacto en punto", - "advancement.create.clockwork_bearing.desc": "Ensamblar una estructura montada sobre un rodamiento tipo reloj.", - "advancement.create.display_link": "Big Data", - "advancement.create.display_link.desc": "Usa un enlace de pantalla para visualizar información", - "advancement.create.potato_cannon": "¡Fwoomp!", - "advancement.create.potato_cannon.desc": "Derrota a un enemigo con tu cañón de patatas.", - "advancement.create.extendo_grip": "¡Boioioing!", - "advancement.create.extendo_grip.desc": "Hazte con un agarre extentido.", - "advancement.create.linked_controller": "Activación remota", - "advancement.create.linked_controller.desc": "Activa un enlace de redstone usando un controlador enlazado", - "advancement.create.arm_blaze_burner": "Combust-o-Tron", - "advancement.create.arm_blaze_burner.desc": "Instruya un brazo mecánico para alimentar su quemador de blaze.", - "advancement.create.crusher_maxed_0000": "Triturándolo", - "advancement.create.crusher_maxed_0000.desc": "Usa un par de ruedas trituradoras a máxima velocidad", - "advancement.create.arm_many_targets": "Organiz-o-Tron", - "advancement.create.arm_many_targets.desc": "Programa un brazo mecánico con diez o más posiciones de salida.", - "advancement.create.potato_cannon_collide": "Fuegos artificiales veganos", - "advancement.create.potato_cannon_collide.desc": "Haz que diferentes proyectiles del lanzapatatas choquen en el aire", - "advancement.create.self_deploying": "Vagoneta autónoma", - "advancement.create.self_deploying.desc": "Crea un artefacto móvil de vagoneta que coloca raíles a su paso", - "advancement.create.fist_bump": "¡Pégale, hermano!", - "advancement.create.fist_bump.desc": "Haz que dos desplegadores se den un puñetazo.", - "advancement.create.crafter_lazy_000": "Medidas desesperadas", - "advancement.create.crafter_lazy_000.desc": "Ralentiza bruscamente un ensamblador mecánico para procrastinar la construcción de una infraestructura decente§7\n(Logro oculto)", - "advancement.create.extendo_grip_dual": "Hasta el infinito y más allá", - "advancement.create.extendo_grip_dual.desc": "Equípate dos agarres extensibles para un alcance inhumano§7\n(Logro oculto)", - "advancement.create.musical_arm": "¡Tócame la melodía!", - "advancement.create.musical_arm.desc": "Vea cómo un brazo mecánico maneja su tocadiscos.", - "advancement.create.sturdy_sheet": "Las rocas más robustas", - "advancement.create.sturdy_sheet.desc": "Ensambla una lámina robusta refinando obsidiana molida", - "advancement.create.train_casing_00": "La era logística", - "advancement.create.train_casing_00.desc": "Usa láminas robustas para crear revestimientos para los componentes de ferrocarril", - "advancement.create.train": "¡Todos a bordo!", - "advancement.create.train.desc": "Ensambla tu primer tren", - "advancement.create.conductor": "Instructor de autoescuela", - "advancement.create.conductor.desc": "Instruye un conductor de tren con una procramación", - "advancement.create.track_signal": "Control de tráfico", - "advancement.create.track_signal.desc": "Coloca una señal de tráfico", - "advancement.create.display_board_0": "Horarios dinámicos", - "advancement.create.display_board_0.desc": "Prevee la llegada de un tren en una pantalla de visualización con ayuda de enlaces de visualización", - "advancement.create.track_0": "Un nuevo calibre", - "advancement.create.track_0.desc": "Obtén vías de tren", - "advancement.create.train_whistle": "¡Chu chuu!", - "advancement.create.train_whistle.desc": "Ensambla un silbato de vapor en tu tren y actívalo mientras lo conduces", - "advancement.create.train_portal": "Pasajero dimensional", - "advancement.create.train_portal.desc": "Monta en un tren a través de un portal del Nether", - "advancement.create.track_crafting_factory": "Fábrica de vías", - "advancement.create.track_crafting_factory.desc": "Produce más de 1000 vías de tren en la misma prensa mecánica", - "advancement.create.long_bend": "La curva más larga", - "advancement.create.long_bend.desc": "Crea una sección de vías curva que se expanda por más de 30 bloques de largo", - "advancement.create.long_train": "Esfuerzos ambiciosos", - "advancement.create.long_train.desc": "Crea un tren con al menos 6 carruajes", - "advancement.create.long_travel": "Excursión al campo", - "advancement.create.long_travel.desc": "Sal de un asiento de tren después de más de 5000 bloques desde que empezaste el recorrido", - "advancement.create.train_roadkill": "Muerte en carretera", - "advancement.create.train_roadkill.desc": "Atropella a un enemigo con tu tren§7\n(Logro oculto)", - "advancement.create.red_signal": "Conductor experto", - "advancement.create.red_signal.desc": "Sáltate una señal roja con un tren§7\n(Logro oculto)", - "advancement.create.train_crash": "Un pésimo servicio", - "advancement.create.train_crash.desc": "Sé testigo de un accidente de tren siendo un pasajero§7\n(Logro oculto)", - "advancement.create.train_crash_backwards": "Ángulo muerto", - "advancement.create.train_crash_backwards.desc": "Ten un accidente con otro tren yendo marcha atrás§7\n(Logro oculto)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Paletas", - - "death.attack.create.crush": "%1$s se procesó en las ruedas de trituración", - "death.attack.create.crush.player": "%1$s fue arrojado a las ruedas de trituración por %2$s", - "death.attack.create.fan_fire": "%1$s murió quemado por el aire caliente", - "death.attack.create.fan_fire.player": "%1$s fue arrojado a un ahumador por %2$s", - "death.attack.create.fan_lava": "%1$s murió quemado por un abanico de lava", - "death.attack.create.fan_lava.player": "%1$s fue arrojado a una fundición por %2$s", - "death.attack.create.mechanical_drill": "%1$s fue empalado por un taladro mecánico", - "death.attack.create.mechanical_drill.player": "%1$s fue lanzado frente a un taladro por %2$s", - "death.attack.create.mechanical_saw": "%1$s fue cortado por la mitad por una sierra mecánica", - "death.attack.create.mechanical_saw.player": "%1$s fue arrojado a una sierra por %2$s", - "death.attack.create.potato_cannon": "%1$s fue disparado por el cañón de patatas de %2$s's", - "death.attack.create.potato_cannon.item": "%1$s fue disparado por %2$s utilizando %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s fue volado por los aires por un reloj de cuco manipulado", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s fue volado por un reloj de cuco manipulado", - "death.attack.create.run_over": "%1$s ha sido atropellado por %2$s", - - "create.block.deployer.damage_source_name": "Un desplegador rebelde", - "create.block.cart_assembler.invalid": "Coloque su Ensamblador de vagonetas en un bloque de Raíles", - - "create.menu.return": "Regresar al menú", - "create.menu.configure": "Configurar...", - "create.menu.ponder_index": "Índice", - "create.menu.only_ingame": "Disponible en el menú de pausa", - "create.menu.report_bugs": "Reportar problemas", - "create.menu.support": "Apóyenos", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Trituración", - "create.recipe.milling": "Fresado", - "create.recipe.fan_washing": "Lavado a granel", - "create.recipe.fan_washing.fan": "Ventilador detrás del agua fluyente", - "create.recipe.fan_smoking": "Ahumador a granel", - "create.recipe.fan_smoking.fan": "Ventilador detrás del fuego", - "create.recipe.fan_haunting": "Maldecidor a granel", - "create.recipe.fan_haunting.fan": "Ventilador detrás del fuego de alma", - "create.recipe.fan_blasting": "Voladuras a granel", - "create.recipe.fan_blasting.fan": "Ventilador detrás de la lava", - "create.recipe.pressing": "Prensando", - "create.recipe.mixing": "Mezclando", - "create.recipe.deploying": "Desplegando", - "create.recipe.automatic_shapeless": "Elaboración automatizada de productos sin forma", - "create.recipe.automatic_brewing": "Elaboración de cerveza automatizada", - "create.recipe.packing": "Compactando", - "create.recipe.automatic_packing": "Embalaje automatizado", - "create.recipe.sawing": "Aserrando", - "create.recipe.mechanical_crafting": "Elaboración mecánica", - "create.recipe.automatic_shaped": "Elaboración automatizada de productos con forma", - "create.recipe.block_cutting": "Corte de bloques", - "create.recipe.wood_cutting": "Corte de maderas", - "create.recipe.sandpaper_polishing": "Pulido con papel de lija", - "create.recipe.mystery_conversion": "Conversión misteriosa", - "create.recipe.spout_filling": "Llenar por el pico", - "create.recipe.draining": "Drenador de objetos", - "create.recipe.item_application": "Aplicación manual de objetos", - "create.recipe.item_application.any_axe": "Cualquier hacha", - "create.recipe.sequenced_assembly": "Montaje secuenciado", - "create.recipe.assembly.next": "Siguiente: %1$s", - "create.recipe.assembly.step": "Fase %1$s:", - "create.recipe.assembly.progress": "Progreso: %1$s/%2$s", - "create.recipe.assembly.pressing": "Proceso en prensa", - "create.recipe.assembly.spout_filling_fluid": "Pico %1$s", - "create.recipe.assembly.deploying_item": "Despliegue %1$s", - "create.recipe.assembly.cutting": "Corte con sierra", - "create.recipe.assembly.repeat": "Repetir la secuencia %1$s veces", - "create.recipe.assembly.junk": "Basura aleatoria", - "create.recipe.processing.chance": "%1$s%% Chance", - "create.recipe.deploying.not_consumed": "No consumido", - "create.recipe.heat_requirement.none": "No es necesario calentar", - "create.recipe.heat_requirement.heated": "Calentado", - "create.recipe.heat_requirement.superheated": "Súper-Calentado", - - "create.generic.range": "Rango", - "create.generic.radius": "Radio", - "create.generic.width": "Ancho", - "create.generic.height": "Alto", - "create.generic.length": "Largo", - "create.generic.speed": "Velocidad", - "create.generic.delay": "Retraso", - "create.generic.duration": "Duración", - "create.generic.timeUnit": "Unidad de tiempo", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Segundos", - "create.generic.unit.minutes": "Minutos", - "create.generic.daytime.hour": "Hora", - "create.generic.daytime.minute": "Minuto", - "create.generic.daytime.second": "Segundo", - "create.generic.daytime.pm": "pm", - "create.generic.daytime.am": "am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "UE", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "C", - "create.generic.clockwise": "En el sentido de las agujas del reloj", - "create.generic.counter_clockwise": "En sentido contrario a las agujas del reloj", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "Tono: %1$s", - "create.generic.notes": "Fa#;Fa;Mi;Re#;Re;Do#;Do;Si;La#;La;Sol#;Sol", - - "create.action.scroll": "Desplazar", - "create.action.confirm": "Confirmar", - "create.action.abort": "Abortar", - "create.action.saveToFile": "Guardar", - "create.action.discard": "Descartar", - - "create.keyinfo.toolmenu": "Menú de la Herramienta de Enfoque", - "create.keyinfo.toolbelt": "Acceder a las cajas de herramientas cercanas", - "create.keyinfo.scrollup": "Simular usar la rueda del ratón hacia arriba (en el mundo)", - "create.keyinfo.scrolldown": "Simular usar la rueda del ratón hacia abajo (en el mundo)", - - "create.gui.scrollInput.defaultTitle": "Seleccione una opción:", - "create.gui.scrollInput.scrollToModify": "Usa la rueda del ratón para modificar", - "create.gui.scrollInput.scrollToAdjustAmount": "Usa la rueda del ratón para ajustar la cantidad", - "create.gui.scrollInput.scrollToSelect": "Usa la rueda del ratón para seleccionar", - "create.gui.scrollInput.shiftScrollsFaster": "Mayús izdo. para usar la rueda del ratón más rápido", - "create.gui.toolmenu.focusKey": "Mantén [%1$s] para enfocar", - "create.gui.toolmenu.cycle": "[RUEDA DEL RATÓN] para el ciclo", - - "create.toolbox.unequip": "Desequipar: %1$s", - "create.toolbox.outOfRange": "La caja de herramientas del objeto en uso no está en el rango", - "create.toolbox.detach": "Dejar de rastrear y conservar el objeto", - "create.toolbox.depositAll": "Devuelve objetos a las cajas de herramientas cercanas", - "create.toolbox.depositBox": "Devolver elementos a la caja de herramientas", - - "create.gui.symmetryWand.mirrorType": "Espejado", - "create.gui.symmetryWand.orientation": "Orientación", - - "create.symmetry.mirror.plane": "Plano de espejo", - "create.symmetry.mirror.doublePlane": "Rectangular", - "create.symmetry.mirror.triplePlane": "Octogonal", - - "create.orientation.orthogonal": "Ortogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "A lo largo de Z", - "create.orientation.alongX": "A lo largo de X", - - "create.gui.terrainzapper.title": "Handheld Blockzapper", - "create.gui.terrainzapper.searchDiagonal": "Seguir diagonales", - "create.gui.terrainzapper.searchFuzzy": "Ignorar los bordes del material", - "create.gui.terrainzapper.patternSection": "Patrón", - "create.gui.terrainzapper.pattern.solid": "Sólido", - "create.gui.terrainzapper.pattern.checkered": "Tablero de ajedrez", - "create.gui.terrainzapper.pattern.inversecheckered": "Tablero de ajedrez invertido", - "create.gui.terrainzapper.pattern.chance25": "25% Probabilidad", - "create.gui.terrainzapper.pattern.chance50": "50% Probabilidad", - "create.gui.terrainzapper.pattern.chance75": "75% Probabilidad", - "create.gui.terrainzapper.placement": "Ubicación", - "create.gui.terrainzapper.placement.merged": "Fusionado", - "create.gui.terrainzapper.placement.attached": "Adjuntado", - "create.gui.terrainzapper.placement.inserted": "Insertado", - "create.gui.terrainzapper.brush": "Pincel", - "create.gui.terrainzapper.brush.cuboid": "Cuboide", - "create.gui.terrainzapper.brush.sphere": "Esfera", - "create.gui.terrainzapper.brush.cylinder": "Cilindro", - "create.gui.terrainzapper.brush.surface": "Superficie", - "create.gui.terrainzapper.brush.cluster": "Grupo", - "create.gui.terrainzapper.tool": "Herramienta", - "create.gui.terrainzapper.tool.fill": "Llenar", - "create.gui.terrainzapper.tool.place": "Ubicar", - "create.gui.terrainzapper.tool.replace": "Reemplazar", - "create.gui.terrainzapper.tool.clear": "Eliminar", - "create.gui.terrainzapper.tool.overlay": "Superponer", - "create.gui.terrainzapper.tool.flatten": "Aplanar", - - "create.terrainzapper.shiftRightClickToSet": "Mayús izdo. + clic derecho para seleccionar una forma", - "create.terrainzapper.usingBlock": "Usando: %1$s", - "create.terrainzapper.leftClickToSet": "Clic izquierdo a un bloque para establecer el material", - - "create.minecart_coupling.two_couplings_max": "Las vagonetas no pueden tener más de dos enganches cada una", - "create.minecart_coupling.unloaded": "Algunas partes de su tren parecen estar en chunks no cargados", - "create.minecart_coupling.no_loops": "Los acoplamientos no pueden formar un bucle", - "create.minecart_coupling.removed": "Se han retirado todos los acoplamientos de la vagoneta", - "create.minecart_coupling.too_far": "Las vagonetas están demasiado separadas", - - "create.contraptions.movement_mode": "Modo de movimiento", - "create.contraptions.movement_mode.move_place": "Colocar siempre al detenerse", - "create.contraptions.movement_mode.move_place_returned": "Colocar sólo en la posición inicial", - "create.contraptions.movement_mode.move_never_place": "Colocar sólo cuando se destruye el ancla", - "create.contraptions.movement_mode.rotate_place": "Colocar siempre al detenerse", - "create.contraptions.movement_mode.rotate_place_returned": "Colocar sólo cerca del ángulo inicial", - "create.contraptions.movement_mode.rotate_never_place": "Colocar sólo cuando se destruye el ancla", - "create.contraptions.cart_movement_mode": "Modo de movimiento de la vagoneta", - "create.contraptions.cart_movement_mode.rotate": "Siempre de cara al movimiento", - "create.contraptions.cart_movement_mode.rotate_paused": "Pausar a los actores mientras giran", - "create.contraptions.cart_movement_mode.rotation_locked": "Bloquear rotación", - "create.contraptions.windmill.rotation_direction": "Dirección de rotación", - "create.contraptions.clockwork.clock_hands": "Manecillas de reloj", - "create.contraptions.clockwork.hour_first": "La manecilla de las horas primero", - "create.contraptions.clockwork.minute_first": "La manecilla de los minutos primero", - "create.contraptions.clockwork.hour_first_24": "La manecilla del día primero", - - "create.logistics.filter": "Filtro", - "create.logistics.recipe_filter": "Filtro para recetas", - "create.logistics.fluid_filter": "Filtro para fluidos", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Filtro aplicado a %1$s.", - "create.logistics.filter.apply_click_again": "Filtro aplicado a %1$s, haga clic de nuevo para copiar la cantidad.", - "create.logistics.filter.apply_count": "Aplicado recuento de extracciones al filtro.", - - "create.gui.goggles.generator_stats": "Estadísticas del generador:", - "create.gui.goggles.kinetic_stats": "Estadísticas cinéticas:", - "create.gui.goggles.at_current_speed": "con la velocidad actual", - "create.gui.goggles.pole_length": "Longitud del poste:", - "create.gui.goggles.fluid_container": "Información sobre el contenedor de fluidos:", - "create.gui.goggles.fluid_container.capacity": "Capacidad: ", - "create.gui.assembly.exception": "Este artefacto animado no se pudo montar:", - "create.gui.assembly.exception.unmovableBlock": "Bloque inamovible (%4$s) en [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "El bloque en [%1$s,%2$s,%3$s] no estaba en un chunk cargado", - "create.gui.assembly.exception.structureTooLarge": "Hay demasiados bloques incluídos en el artefacto animado.\nEl máximo configurado es: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Hay demasiadas Pértigas de extensión conectadas a este Pistón.\nEl máximo configurado es: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Faltan pértigas de extensión para el pistón", - "create.gui.assembly.exception.not_enough_sails": "La estructura adjunta no incluye suficientes bloques tipo vela: %1$s\nSe requiere un mínimo de %2$s", - "create.gui.gauge.info_header": "Información sobre el medidor:", - "create.gui.speedometer.title": "Velocidad de rotación", - "create.gui.stressometer.title": "Estrés de la red", - "create.gui.stressometer.capacity": "Capacidad restante", - "create.gui.stressometer.overstressed": "Sobrecargado", - "create.gui.stressometer.no_rotation": "Sin rotación", - "create.gui.contraptions.not_fast_enough": "Parece que este %1$s no está girando con _suficiente_ velocidad_.", - "create.gui.contraptions.network_overstressed": "Parece que este sistema está _sobrecargado_. Añade más fuentes o _desacelera_ los componentes con un _impacto de estrés alto_.", - "create.gui.adjustable_crate.title": "Caja ajustable", - "create.gui.adjustable_crate.storageSpace": "Espacio de almacenamiento", - "create.gui.stockpile_switch.title": "Interruptor de acopio", - "create.gui.stockpile_switch.invert_signal": "Invertir señal", - "create.gui.stockpile_switch.move_to_lower_at": "Pasar al carril inferior en %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Pasar al carril superior en %1$s%%", - "create.gui.sequenced_gearshift.title": "Cambio de marchas secuenciado", - "create.gui.sequenced_gearshift.instruction": "Instrucción", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Giro por ángulo", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Giro", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Ángulo", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Giro para mover el pistón/polea/grúa", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistón", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Tiempo de retraso", - "create.gui.sequenced_gearshift.instruction.delay": "Retraso", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Duración", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Fin", - "create.gui.sequenced_gearshift.instruction.end": "Fin", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "En espera de un pulso de redstone", - "create.gui.sequenced_gearshift.instruction.await": "En espera", - "create.gui.sequenced_gearshift.speed": "Velocidad, Dirección", - "create.gui.sequenced_gearshift.speed.forward": "Velocidad de entrada, hacia adelante", - "create.gui.sequenced_gearshift.speed.forward_fast": "Doble velocidad, hacia adelante", - "create.gui.sequenced_gearshift.speed.back": "Velocidad de entrada, Invertida", - "create.gui.sequenced_gearshift.speed.back_fast": "Doble velocidad, Invertida", - - "create.schematicAndQuill.dimensions": "Tamaño del esquema: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Primera posición fijada.", - "create.schematicAndQuill.secondPos": "Segunda posición fijada.", - "create.schematicAndQuill.noTarget": "Mantén [Ctrl] para seleccionar los bloques del aire.", - "create.schematicAndQuill.abort": "Selección eliminada.", - "create.schematicAndQuill.title": "Nombre del esquema:", - "create.schematicAndQuill.convert": "Guardar y desplegar inmediatamente", - "create.schematicAndQuill.fallbackName": "Mi esquema", - "create.schematicAndQuill.saved": "Guardado como %1$s", - - "create.schematic.invalid": "[!] Elemento no válido - Utilice la tabla de esquemas en su lugar", - "create.schematic.position": "Posición", - "create.schematic.rotation": "Rotación", - "create.schematic.rotation.none": "Ninguno", - "create.schematic.rotation.cw90": "En el sentido de las agujas del reloj 90", - "create.schematic.rotation.cw180": "En el sentido de las agujas del reloj 180", - "create.schematic.rotation.cw270": "En el sentido de las agujas del reloj 270", - "create.schematic.mirror": "Espejado", - "create.schematic.mirror.none": "Ninguno", - "create.schematic.mirror.frontBack": "Delante-Detrás", - "create.schematic.mirror.leftRight": "Izquierda-Derecha", - "create.schematic.tool.deploy": "Despliegue", - "create.schematic.tool.move": "Mover XZ", - "create.schematic.tool.movey": "Mover Y", - "create.schematic.tool.rotate": "Rotar", - "create.schematic.tool.print": "Imprimir", - "create.schematic.tool.flip": "Voltear", - "create.schematic.tool.deploy.description.0": "Mueve la estructura a un lugar.", - "create.schematic.tool.deploy.description.1": "Haz clic con el botón derecho del ratón en el suelo para colocarla.", - "create.schematic.tool.deploy.description.2": "Mantén [Ctrl] para seleccionar a una distancia fija.", - "create.schematic.tool.deploy.description.3": "[Ctrl] + [RUEDA DEL RATÓN] para cambiar la distancia.", - "create.schematic.tool.move.description.0": "Desplaza el esquema horizontalmente.", - "create.schematic.tool.move.description.1": "Apunta al esquema y [Ctrl] + [RUEDA DEL RATÓN] para ponerlo.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Desplaza el esquema verticalmente..", - "create.schematic.tool.movey.description.1": "[Ctrl] + [RUEDA DEL RATÓN] para moverlo hacia arriba/abajo.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Gira el esquema alrededor de su centro.", - "create.schematic.tool.rotate.description.1": "[Ctrl] + [RUEDA DEL RATÓN] para girar 90 grados.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Sitúa instantáneamente la estructura en el mundo.", - "create.schematic.tool.print.description.1": "[Clic derecho] para confirmar la colocación en el lugar actual.", - "create.schematic.tool.print.description.2": "Esta herramienta es sólo para el Modo Creativo.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Voltea el esquema a lo largo de la cara que seleccione.", - "create.schematic.tool.flip.description.1": "Apunta al esquema y [Ctrl] + [RUEDA DEL RATÓN] para voltearlo.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Sincronizando...", - "create.schematics.uploadTooLarge": "Tu esquema excede las limitaciones especificadas por el servidor.", - "create.schematics.maxAllowedSize": "El tamaño máximo permitido del archivo del esquema es:", - - "create.gui.schematicTable.refresh": "Refrescar archivos", - "create.gui.schematicTable.open_folder": "Abrir carpeta", - "create.gui.schematicTable.title": "Tabla de esquemas", - "create.gui.schematicTable.availableSchematics": "Esquemas disponibles", - "create.gui.schematicTable.noSchematics": "No hay esquemas guardados", - "create.gui.schematicTable.uploading": "Subiendo...", - "create.gui.schematicTable.finished": "¡Subida finalizada!", - "create.gui.schematicannon.title": "Esquematicañón", - "create.gui.schematicannon.listPrinter": "Lista de control de la impresora", - "create.gui.schematicannon.gunpowderLevel": "Pólvora %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Disparos restantes: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Con respaldo: %1$s", - "create.gui.schematicannon.optionEnabled": "Actualmente habilitado", - "create.gui.schematicannon.optionDisabled": "Actualmente deshabilitado", - "create.gui.schematicannon.showOptions": "Mostrar la configuración de la impresora", - "create.gui.schematicannon.option.dontReplaceSolid": "No sustituír los bloques sólidos", - "create.gui.schematicannon.option.replaceWithSolid": "Sustituir sólido por sólido", - "create.gui.schematicannon.option.replaceWithAny": "Sustituir sólido por cualquiera", - "create.gui.schematicannon.option.replaceWithEmpty": "Sustituir sólido por vacío", - "create.gui.schematicannon.option.skipMissing": "Omitir los bloques que faltan", - "create.gui.schematicannon.option.skipTileEntities": "Proteger a las entidades", - "create.gui.schematicannon.slot.gunpowder": "Añade pólvora para alimentar el cañón", - "create.gui.schematicannon.slot.listPrinter": "Coloque los libros aquí para imprimir una lista de comprobación para su esquema", - "create.gui.schematicannon.slot.schematic": "Añada su esquema aquí. Asegúrese de que se despliega en un lugar específico.", - "create.gui.schematicannon.option.skipMissing.description": "Si el cañón no encuentra un bloque necesario para su colocación, continuará en la siguiente ubicación.", - "create.gui.schematicannon.option.skipTileEntities.description": "El cañón evitará reemplazar los bloques que contienen datos, como los cofres.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "El cañón nunca sustituirá ningún bloque sólido en su zona de trabajo, sólo los no sólidos y el aire.", - "create.gui.schematicannon.option.replaceWithSolid.description": "El cañón sólo reemplazará los bloques sólidos en su área de trabajo si el esquema contiene un bloque sólido en la ubicación.", - "create.gui.schematicannon.option.replaceWithAny.description": "El cañón reemplazará los bloques sólidos en su área de trabajo si el esquema contiene algún bloque en la ubicación.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "El cañón eliminará todos los bloques de su zona de trabajo, incluidos los sustituidos por aire.", - - "create.schematicannon.status.idle": "Inactivo", - "create.schematicannon.status.ready": "Listo", - "create.schematicannon.status.running": "Funcionando", - "create.schematicannon.status.finished": "Finalizado", - "create.schematicannon.status.paused": "Pausado", - "create.schematicannon.status.stopped": "Detenido", - "create.schematicannon.status.noGunpowder": "Sin pólvora", - "create.schematicannon.status.targetNotLoaded": "El objetivo no está cargado", - "create.schematicannon.status.targetOutsideRange": "Objetivo demasiado lejano", - "create.schematicannon.status.searching": "Buscando", - "create.schematicannon.status.skipping": "Omitiendo", - "create.schematicannon.status.missingBlock": "Elementos perdidos:", - "create.schematicannon.status.placing": "Colocando", - "create.schematicannon.status.clearing": "Limpiando bloques", - "create.schematicannon.status.schematicInvalid": "Esquema inválido", - "create.schematicannon.status.schematicNotPlaced": "Esquema no desplegado", - "create.schematicannon.status.schematicExpired": "Archivo de esquemas caducado", - - "create.materialChecklist": "Lista de control del material", - "create.materialChecklist.blocksNotLoaded": "* Descargo de Responsabilidad *\n\nLa lista de materiales puede ser inexacta debido a que no se han cargado los chunks pertinentes.", - - "create.gui.filter.deny_list": "Lista de denegados", - "create.gui.filter.deny_list.description": "Los objetos pasan si NO coinciden con ninguno de los anteriores. Una lista de denegación vacía acepta todo.", - "create.gui.filter.allow_list": "Lista de permitidos", - "create.gui.filter.allow_list.description": "Los objetos pasan si coinciden con alguno de los anteriores. Una lista de permitidos vacía rechaza todo.", - "create.gui.filter.respect_data": "Respetar datos", - "create.gui.filter.respect_data.description": "Los objetos sólo coinciden si su durabilidad, encantos y otros atributos también coinciden.", - "create.gui.filter.ignore_data": "Ignorar datos", - "create.gui.filter.ignore_data.description": "Los objetos coinciden independientemente de sus atributos.", - - "create.item_attributes.placeable": "se puede colocar", - "create.item_attributes.placeable.inverted": "no se puede colocar", - "create.item_attributes.consumable": "se puede comer", - "create.item_attributes.consumable.inverted": "no se puede comer", - "create.item_attributes.fluid_container": "puede almacenar fluidos", - "create.item_attributes.fluid_container.inverted": "puede almacenar fluidos", - "create.item_attributes.enchanted": "está encantado", - "create.item_attributes.enchanted.inverted": "no está encantado", - "create.item_attributes.max_enchanted": "está encantado en el nivel máximo", - "create.item_attributes.max_enchanted.inverted": "no está encantado en el nivel máximo", - "create.item_attributes.renamed": "tiene un nombre personalizado", - "create.item_attributes.renamed.inverted": "no tiene un nombre personalizado", - "create.item_attributes.damaged": "está dañado", - "create.item_attributes.damaged.inverted": "no está dañado", - "create.item_attributes.badly_damaged": "está muy dañado", - "create.item_attributes.badly_damaged.inverted": "no está muy dañado", - "create.item_attributes.not_stackable": "no se puede apilar", - "create.item_attributes.not_stackable.inverted": "se puede apilar", - "create.item_attributes.equipable": "se puede equipar", - "create.item_attributes.equipable.inverted": "no se puede equipar", - "create.item_attributes.furnace_fuel": "es combustible para hornos", - "create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos", - "create.item_attributes.washable": "se puede lavar", - "create.item_attributes.washable.inverted": "no se puede lavar", - "create.item_attributes.hauntable": "puede ser maldito", - "create.item_attributes.hauntable.inverted": "no puede ser maldito", - "create.item_attributes.crushable": "puede ser molido", - "create.item_attributes.crushable.inverted": "no puede ser molido", - "create.item_attributes.smeltable": "se puede fundir", - "create.item_attributes.smeltable.inverted": "no se puede fundir", - "create.item_attributes.smokable": "puede ser ahumado", - "create.item_attributes.smokable.inverted": "no puede ser ahumado", - "create.item_attributes.blastable": "es fundible en el alto horno", - "create.item_attributes.blastable.inverted": "no es fundible en el alto horno", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "es shulker %1$s", - "create.item_attributes.shulker_level.inverted": "no es shulker %1$s", - "create.item_attributes.shulker_level.full": "lleno", - "create.item_attributes.shulker_level.empty": "vacío", - "create.item_attributes.shulker_level.partial": "parcialmente lleno", - "create.item_attributes.in_tag": "está etiquetado %1$s", - "create.item_attributes.in_tag.inverted": "no está etiquetado %1$s", - "create.item_attributes.in_item_group": "está en el grupo '%1$s'", - "create.item_attributes.in_item_group.inverted": "no está en el grupo '%1$s'", - "create.item_attributes.added_by": "fue añadido por %1$s", - "create.item_attributes.added_by.inverted": "no fue añadida por %1$s", - "create.item_attributes.has_enchant": "está encantado con %1$s", - "create.item_attributes.has_enchant.inverted": "no está encantado con %1$s", - "create.item_attributes.color": "Está teñido %1$s", - "create.item_attributes.color.inverted": "No está teñido %1$s", - "create.item_attributes.has_fluid": "contiene %1$s", - "create.item_attributes.has_fluid.inverted": "no contiene %1$s", - "create.item_attributes.has_name": "tiene el nombre personalizado %1$s", - "create.item_attributes.has_name.inverted": "no tiene el nombre personalizado %1$s", - "create.item_attributes.book_author": "es obra de %1$s", - "create.item_attributes.book_author.inverted": "no es es obra de %1$s", - "create.item_attributes.book_copy_original": "es un original", - "create.item_attributes.book_copy_original.inverted": "no es un original", - "create.item_attributes.book_copy_first": "es una copia de primera generación", - "create.item_attributes.book_copy_first.inverted": "no es una copia de primera generación", - "create.item_attributes.book_copy_second": "es una copia de segunda generación", - "create.item_attributes.book_copy_second.inverted": "no es una copia de segunda generación", - "create.item_attributes.book_copy_tattered": "es un desordenado desastre", - "create.item_attributes.book_copy_tattered.inverted": "no es un desordenado desastre", - "create.item_attributes.astralsorcery_amulet": "mejora %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "no mejora %1$s", - "create.item_attributes.astralsorcery_constellation": "está en sintonía con %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "no está en sintonía con %1$s", - "create.item_attributes.astralsorcery_crystal": "tiene el atributo de cristal %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "no tiene atributo de cristal %1$s", - "create.item_attributes.astralsorcery_perk_gem": "tiene el atributo ventaja %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "no tiene el atributo ventaja %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "No hay atributos seleccionados", - "create.gui.attribute_filter.selected_attributes": "Atributos seleccionados:", - "create.gui.attribute_filter.add_attribute": "Añadir atributo a la lista", - "create.gui.attribute_filter.add_inverted_attribute": "Añadir atributo invertido a la Lista", - "create.gui.attribute_filter.allow_list_disjunctive": "Lista de permitidos (Cualquiera)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Los objetos pasan si tienen alguno de los atributos seleccionados", - "create.gui.attribute_filter.allow_list_conjunctive": "Lista de permitidos (Todos)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Los objetos pasan sólo si tienen TODOS los atributos seleccionados", - "create.gui.attribute_filter.deny_list": "Lista de denegados", - "create.gui.attribute_filter.deny_list.description": "Los objetos pasan si NO tienen ninguno de los atributos seleccionados", - "create.gui.attribute_filter.add_reference_item": "Añadir elemento de referencia", - - "create.tooltip.holdForDescription": "Mantén [%1$s] para mas información", - "create.tooltip.holdForControls": "Mantén [%1$s] para ver los controles", - "create.tooltip.keyShift": "Mayús izdo.", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Requisitos de velocidad: %1$s", - "create.tooltip.speedRequirement.none": "Ninguno", - "create.tooltip.speedRequirement.slow": "Lento", - "create.tooltip.speedRequirement.medium": "Moderado", - "create.tooltip.speedRequirement.fast": "Rápido", - "create.tooltip.stressImpact": "Impacto de estrés: %1$s", - "create.tooltip.stressImpact.low": "Bajo", - "create.tooltip.stressImpact.medium": "Moderado", - "create.tooltip.stressImpact.high": "Alto", - "create.tooltip.stressImpact.overstressed": "Sobrecargado", - "create.tooltip.up_to": "Hasta %1$s", - "create.tooltip.capacityProvided": "Capacidad de estrés: %1$s", - "create.tooltip.capacityProvided.low": "Pequeña", - "create.tooltip.capacityProvided.medium": "Media", - "create.tooltip.capacityProvided.high": "Grande", - "create.tooltip.generationSpeed": "Generada en %1$s %2$s", - "create.tooltip.analogStrength": "Fuerza analógica: %1$s/15", - - "create.mechanical_arm.extract_from": "Extraer objetos de %1$s", - "create.mechanical_arm.deposit_to": "Depositar objetos en %1$s", - "create.mechanical_arm.summary": "El brazo mecánico tiene %1$s entrada(s) y %2$s salida(s)", - "create.mechanical_arm.points_outside_range": "%1$s punto(s) de interacción seleccionado(s) eliminado(s) debido a las limitaciones de rango", - - "create.weighted_ejector.target_set": "Objetivo seleccionado", - "create.weighted_ejector.target_not_valid": "Expulsión al bloque adyacente (el objetivo no era válido)", - "create.weighted_ejector.no_target": "Expulsión al bloque adyacente (no se ha seleccionado ningún objetivo)", - "create.weighted_ejector.targeting": "Expulsión a [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Tamaño de la pila expulsada", - - "create.logistics.when_multiple_outputs_available": "Cuando hay múltiples salidas disponibles", - - "create.mechanical_arm.selection_mode.round_robin": "Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "Round Robin forzado", - "create.mechanical_arm.selection_mode.prefer_first": "Preferir el primero", - - "create.tunnel.selection_mode.split": "División", - "create.tunnel.selection_mode.forced_split": "División forzada", - "create.tunnel.selection_mode.round_robin": "Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "Round Robin forzado", - "create.tunnel.selection_mode.prefer_nearest": "Preferir el más cercano", - "create.tunnel.selection_mode.randomize": "Aleatorizar", - "create.tunnel.selection_mode.synchronize": "Sincronizar entradas", - - "create.tooltip.chute.header": "Información del ducto", - "create.tooltip.chute.items_move_down": "Los objetos se mueven hacia abajo", - "create.tooltip.chute.items_move_up": "Los objetos se mueven hacia arriba", - "create.tooltip.chute.no_fans_attached": "No hay ventiladores adjuntos", - "create.tooltip.chute.fans_push_up": "Los ventiladores empujan desde abajo", - "create.tooltip.chute.fans_push_down": "Los ventiladores empujan desde arriba", - "create.tooltip.chute.fans_pull_up": "Los ventiladores tiran desde arriba", - "create.tooltip.chute.fans_pull_down": "Los ventiladores tiran desde abajo", - "create.tooltip.chute.contains": "Contiene: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Actualmente distribuye:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Haga clic derecho para recuperar", - - "create.linked_controller.bind_mode": "Modo de enlace activo", - "create.linked_controller.press_keybind": "Presiona %1$s, %2$s, %3$s, %4$s, %5$s o %6$s, para vincular esta frecuencia a la tecla correspondiente", - "create.linked_controller.key_bound": "Frecuencia ligada a %1$s", - "create.linked_controller.frequency_slot_1": "Enlace de teclas: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "Enlace de teclas: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "Ranura para ingredientes", - "create.crafting_blueprint.filter_items_viable": "Los objetos del filtro avanzado son viables", - "create.crafting_blueprint.display_slot": "Ranura de pantalla", - "create.crafting_blueprint.inferred": "A partir de la receta", - "create.crafting_blueprint.manually_assigned": "Asignado manualmente", - "create.crafting_blueprint.secondary_display_slot": "Ranura de pantalla secundaria", - "create.crafting_blueprint.optional": "Opcional", - - "create.potato_cannon.ammo.attack_damage": "%1$s Daño de ataque", - "create.potato_cannon.ammo.reload_ticks": "%1$s Recarga por Ticks", - "create.potato_cannon.ammo.knockback": "%1$s Golpe de efecto", - - "create.hint.hose_pulley.title": "Suministro ilimitado", - "create.hint.hose_pulley": "La masa de fluido objetivo se considera infinita.", - "create.hint.mechanical_arm_no_targets.title": "Sin objetivos", - "create.hint.mechanical_arm_no_targets": "Parece que a este _brazo mecánico_ no se le ha asignado ningún objetivo. Selecciona _cintas mecánicas_, _depósitos_, _embudos_ u otros bloques haciendo clic derecho sobre ellos mientras _sostienes_ el _brazo mecánico_ en tu mano...", - "create.hint.empty_bearing.title": "Actualización del rodamiento", - "create.hint.empty_bearing": "Haz clic derecho sobre el rodamiento con la _mano vacía_ para _adjuntar_ la estructura que acabas de construir delante de él.", - "create.hint.full_deployer.title": "Exceso de objetos en el desplegador", - "create.hint.full_deployer": "Parece que este _desplegador_ contiene _exceso_ de objetos que necesitan ser _extraídos._ Usa una _tolva_, _embudo_ u otro medio para liberarlo de su excedente.", - - "create.backtank.low": "Presión de depósito trasero baja", - "create.backtank.depleted": "Presión de depósito trasero agotada", - - "create.hint.derailed_train.title": "Tren descarrilado", - "create.hint.derailed_train": "Parece que este _tren_ ya no se encuentra en un tramo de vía conectada. Usa _clic derecho_ usando una _llave inglesa_ para volver a colocarlo en una vía cercana.", - - "create.boiler.status": "Estado de la caldera: %1$s", - "create.boiler.status_short": "Caldera: %1$s", - "create.boiler.passive": "Pasivo", - "create.boiler.idle": "Inactivo", - "create.boiler.lvl": "Nivel %1$s", - "create.boiler.max_lvl": "Máximo", - "create.boiler.size": "Tamaño", - "create.boiler.size_dots": "....... ", - "create.boiler.water": "Agua", - "create.boiler.water_dots": "... ", - "create.boiler.heat": "Calor", - "create.boiler.heat_dots": "...... ", - "create.boiler.via_one_engine": "a través de 1 motor", - "create.boiler.via_engines": "a través de %1$s motores", - - "create.gui.schedule.lmb_edit": "Clic izquierdo para editar", - "create.gui.schedule.rmb_remove": "Clic derecho para eliminar", - "create.gui.schedule.duplicate": "Duplicar", - "create.gui.schedule.remove_entry": "Eliminar acción", - "create.gui.schedule.add_entry": "Añadir acción", - "create.gui.schedule.move_up": "Mover arriba", - "create.gui.schedule.move_down": "Mover abajo", - "create.gui.schedule.add_condition": "Añadir condición", - "create.gui.schedule.alternative_condition": "Condición alternativa", - - "create.schedule.instruction_type": "Siguiente acción:", - "create.schedule.instruction.editor": "Editor de instrucciones", - "create.schedule.instruction.destination": "Viajar a la estación", - "create.schedule.instruction.destination.summary": "Siguiente parada:", - "create.schedule.instruction.filter_edit_box": "Nombre de la estación", - "create.schedule.instruction.filter_edit_box_1": "Usa * como una letra o cifra comodín", - "create.schedule.instruction.filter_edit_box_2": "Ejemplo: 'Mi estación, Andén *'", - "create.schedule.instruction.filter_edit_box_3": "Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "Renombrar título de la programación", - "create.schedule.instruction.rename.summary": "Nuevo título:", - "create.schedule.instruction.name_edit_box": "Título de la programación", - "create.schedule.instruction.name_edit_box_1": "Afecta al texto que se muestra por pantallas", - "create.schedule.instruction.name_edit_box_2": "Por defecto se usa el nombre del próximo destino", - "create.schedule.instruction.throttle": "Cambiar aceleración", - "create.schedule.instruction.throttle.summary": "Cambiar la aceleración a %1$s", - "create.schedule.instruction.throttle_edit_box": "Aceleración", - "create.schedule.instruction.throttle_edit_box_1": "Afecta a la velocidad máxima del tren", - "create.schedule.condition_type": "Continuar si/después de:", - "create.schedule.condition.editor": "Editor de condiciones", - "create.schedule.condition.delay": "Demora programada", - "create.schedule.condition.delay_short": "Esperar: %1$s", - "create.schedule.condition.delay.status": "Parte en %1$s", - "create.schedule.condition.idle": "Inactividad de cargamento", - "create.schedule.condition.idle_short": "Cargamento inactivo: %1$s", - "create.schedule.condition.idle.status": "Cargamento inactivo por %1$s", - "create.schedule.condition.for_x_time": "por %1$s", - "create.schedule.condition.unloaded": "Chunk descargado", - "create.schedule.condition.unloaded.status": "Esperando a la descarga de chunk", - "create.schedule.condition.powered": "Estación activada", - "create.schedule.condition.powered.status": "Esperando a la redstone", - "create.schedule.condition.time_of_day": "Hora del día", - "create.schedule.condition.time_of_day.scheduled": "Tiempo programado: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "Rotación", - "create.schedule.condition.time_of_day.rotation.every_24": "Cada día", - "create.schedule.condition.time_of_day.rotation.every_12": "Cada 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "Cada 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "Cada 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "Cada 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "Cada 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "Cada 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "Cada 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "Cada 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "Cada 0:15", - "create.schedule.condition.time_of_day.status": "Parte hacia ", - "create.schedule.condition.threshold.train_holds": "El tren contiene %1$s", - "create.schedule.condition.threshold.greater": "más que", - "create.schedule.condition.threshold.less": "menos que", - "create.schedule.condition.threshold.equal": "exactamente", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$s de %3$s", - "create.schedule.condition.threshold.matching_content": "Contenido coincidente", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "Medición de objetos", - "create.schedule.condition.threshold.items": "Objetos", - "create.schedule.condition.threshold.stacks": "Pilas de objetos", - "create.schedule.condition.threshold.buckets": "Cubos", - "create.schedule.condition.threshold.status": "Cargamento: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "Objeto de referencia", - "create.schedule.condition.threshold.place_item_2": "Los filtros se pueden usar", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "Condición de cargamento de fluidos", - "create.schedule.condition.item_threshold": "Condición de cargamento de objetos", - "create.schedule.condition.redstone_link": "Enlace de redstone", - "create.schedule.condition.redstone_link.status": "Esperando al enlace de redstone", - "create.schedule.condition.redstone_link_on": "Enlace encendido", - "create.schedule.condition.redstone_link_off": "Enlace apagado", - "create.schedule.condition.redstone_link.powered": "Activado", - "create.schedule.condition.redstone_link.unpowered": "Desactivado", - "create.schedule.condition.redstone_link.frequency_state": "Estado de la frecuencia:", - "create.schedule.condition.redstone_link.frequency_powered": "Frecuencia activada:", - "create.schedule.condition.redstone_link.frequency_unpowered": "Frecuencia desactivada:", - "create.schedule.condition.player_count": "Jugadores sentados", - "create.schedule.condition.player_count.summary": "%1$s Jugador", - "create.schedule.condition.player_count.summary_plural": "%1$s Jugadores", - "create.schedule.condition.player_count.seated": "%1$s sentado(s)", - "create.schedule.condition.player_count.players": "Jugadores", - "create.schedule.condition.player_count.condition": "Condicional", - "create.schedule.condition.player_count.exactly": "Exactamente", - "create.schedule.condition.player_count.or_above": "O superior", - "create.schedule.condition.player_count.status": "Pasajeros: %1$s/%2$s", - "create.schedule.loop": "Bucle indefinido", - "create.schedule.loop1": "La programación comienza desde cero", - "create.schedule.loop2": "cuando se completa", - "create.schedule.reset": "Reiniciar progreso", - "create.schedule.skip": "Saltar la parada actual", - "create.schedule.applied_to_train": "El tren ahora sigue esta programación", - "create.schedule.non_controlling_seat": "El conductor se tiene que sentar en frente del bloque de controles del tren", - "create.schedule.remove_with_empty_hand": "Elimina la programación actual con la mano vacía", - "create.schedule.auto_removed_from_train": "Autoprogramación descartada", - "create.schedule.removed_from_train": "Programación del tren recuperada", - "create.schedule.no_stops": "Esta programación todavía no tiene ninguna parada", - "create.schedule.continued": "Programación reanudada", - - "create.track.selection_cleared": "Selección borrada", - "create.track.valid_connection": "Puede conectarse ✔", - "create.track.second_point": "Coloca una vía o selecciona un segundo punto", - "create.track.too_far": "Demasiado lejos", - "create.track.original_missing": "Bloque original eliminado, usa mayús izdo. + clic para reiniciarlo", - "create.track.perpendicular": "No se puede conectar perpendicularmente", - "create.track.ascending_s_curve": "No se pueden crear curvas en S inclinadas", - "create.track.too_sharp": "Curva demasiado cerrada", - "create.track.too_steep": "Cuesta demasiado empinada", - "create.track.slope_turn": "No se puede entrar o salir de una pendiente en una curva", - "create.track.opposing_slopes": "No se pueden conectar pendientes opuestas", - "create.track.leave_slope_ascending": "No se puede abandonar la pendiente mientras asciende", - "create.track.leave_slope_descending": "No se puede abandonar la pendiente mientras desciende", - "create.track.turn_90": "Solo se puede girar hasta 90 grados", - "create.track.junction_start": "No puedes comenzar una conexión en una intersección", - "create.track.turn_start": "No puedes comenzar una conexión en una curva", - "create.track.not_enough_tracks": "No llevas suficientes vías", - "create.track.not_enough_pavement": "No llevas suficientes bloques para el pavimento", - - "create.portal_track.failed": "No se puede colocar una vía en el portal:", - "create.portal_track.missing": "El otro portal no se ha generado todavía", - "create.portal_track.blocked": "Posición objetivo bloqueada (%1$s,%2$s,%3$s)", - - "create.station.idle": "La estación está inactiva", - "create.station.assembly_title": "Ensamblaje de tren", - "create.station.close": "Cerrar ventana", - "create.station.cancel": "Cancelar ensamblaje", - "create.station.failed": "El ensamblaje ha fallado", - "create.station.icon_type": "Tipo de icono", - "create.station.create_train": "Crear un nuevo tren", - "create.station.assemble_train": "Ensamblar tren", - "create.station.disassemble_train": "Desensamblar tren", - "create.station.remove_schedule": "Recuperar programación", - "create.station.remove_auto_schedule": "Descartar autoprogramación", - "create.station.no_assembly_diagonal": "No se pueden construir trenes", - "create.station.no_assembly_diagonal_1": "en vías diagonales", - "create.station.no_assembly_curve": "No se pueden construir trenes", - "create.station.no_assembly_curve_1": "en vías curvas", - "create.station.train_not_aligned": "No se puede desensamblar,", - "create.station.train_not_aligned_1": "no están todos los carruajes alineados", - "create.station.carriage_number": "Carruaje %1$s:", - "create.station.retry": "Soluciona esto y reinténtalo", - "create.station.no_bogeys": "Ningún vagón", - "create.station.one_bogey": "1 vagón", - "create.station.more_bogeys": "%1$s vagones", - "create.station.how_to": "Usa revestimientos de tren en vías marcadas para crear vagones.", - "create.station.how_to_1": "Elimina vagones rompiendo el bloque de arriba.", - "create.station.how_to_2": "Construye carruajes unidos a uno o dos vagones.", - - "create.train_assembly.too_many_bogeys": "Demasiados vagones enlazados: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "El primer vagón debe estar en la marca de la estación", - "create.train_assembly.no_bogeys": "Ningún vagón encontrado", - "create.train_assembly.not_connected_in_order": "Los vagones no están conectados en orden", - "create.train_assembly.bogeys_too_close": "Los vagones %1$s y %2$s están demasiado cerca entre ellos", - "create.train_assembly.single_bogey_carriage": "Este vagón no puede soportar un carruaje él solo", - "create.train_assembly.nothing_attached": "No hay ninguna estructura pegada al vagón %1$s", - "create.train_assembly.no_controls": "Es necesario que haya al menos unps controles de tren en frente de ti", - "create.train_assembly.sideways_controls": "Hay unos controles de tren puestos de lado", - "create.train_assembly.bogey_created": "Vagón creado. Haz clic para cambiar el tipo de vagón", - "create.train_assembly.requires_casing": "Usa revestimientos de tren para crear vagones en las vías", - - "create.track_target.set": "Vía objetivo seleccionada", - "create.track_target.success": "Vinculado con éxito a la vía objetivo", - "create.track_target.clear": "Selección de vía borrada", - "create.track_target.missing": "Primero haz clic derecho en la vía objetivo", - "create.track_target.too_far": "La vía objetivo está demasiado lejos", - "create.track_target.no_junctions": "La vía objetivo no puede ser una intersección", - "create.track_target.occupied": "La vía objetivo está ocupada", - "create.track_target.invalid": "No se puede marcar esta vía como objetivo", - - "create.train.unnamed": "Tren sin nombre", - "create.train.cannot_relocate_moving": "No se puede reubicar un tren en movimiento", - "create.train.relocate": "Haz clic en una vía para reubicar el tren %1$s. Mayús izdo. + clic para abortar", - "create.train.relocate.abort": "Reubicación abortada", - "create.train.relocate.success": "Reubicación exitosa", - "create.train.relocate.valid": "Se puede reubicar aquí, haz clic para confirmar", - "create.train.relocate.invalid": "No se puede reubicar el tren aquí", - "create.train.relocate.too_far": "No se puede reubicar el tren tan lejos", - "create.train.departing_from": "Saliendo de %1$s", - "create.train.arrived_at": "Llegada a %1$s", - "create.train.status": " Información sobre el tren: %1$s", - "create.train.status.back_on_track": "Tren de vuelta a la vía", - "create.train.status.collision": "Choque con otro tren", - "create.train.status.end_of_track": "Un carruaje ha llegado al final de la vía", - "create.train.status.double_portal": "Un carruaje no puede entrar en un portal mientras sale de otro", - "create.train.status.coupling_stress": "Parada forzada debido al estrés en los acoplamientos", - "create.train.status.track_missing": "No hay vías debajo del tren", - "create.train.status.paused_for_manual": "La programación se ha pausado para usar los controles manuales", - "create.train.status.opposite_driver": "Esta trayectoria requiere que el conductor está mirando en la dirección opuesta", - "create.train.status.missing_driver": "El conductor ha desaparecido", - "create.train.status.found_driver": "Se ha encontrado un nuevo conductor", - "create.train.status.navigation_success": "Navegación exitosa", - "create.train.status.no_match": "No station on graph matches '%1$s'", - "create.train.status.no_path": "No se ha encontrado ninguna trayectoria para ir a la siguiente parada programada", - - "create.track_signal.cannot_change_mode": "No se puede cambiar el modo de esta señal", - "create.track_signal.mode_change.entry_signal": "-> Permitir entrada si la sección está desocupada", - "create.track_signal.mode_change.cross_signal": "-> Permitir entrada si la sección se puede atravesar por completo", - - "create.contraption.controls.start_controlling": "Controlando actualmente: %1$s", - "create.contraption.controls.stop_controlling": "Se ha parado de controlar el artefacto móvil", - "create.contraption.controls.approach_station": "Mantén %1$s para acercarte a %2$s", - - "create.display_link.set": "Posición objetivo seleccionada", - "create.display_link.success": "Posición objetivo vinculada con éxito", - "create.display_link.clear": "Posición seleccionada eliminada", - "create.display_link.too_far": "La posición objetivo está demasiado lejos de aquí", - "create.display_link.invalid": "El enlace no tiene un objetivo válido, prueba colocándolo de nuevo", - "create.display_link.title": "Enlace de pantalla", - "create.display_link.no_source": "Not a Display Source", - "create.display_link.no_target": "Not a Display Target", - "create.display_link.reading_from": "Leer de:", - "create.display_link.writing_to": "Enviar a:", - "create.display_link.attached_side": "Block on attached side", - "create.display_link.targeted_location": "Block in targeted location", - "create.display_link.view_compatible": "Haz clic para ver todos los compatibles", - "create.display_link.information_type": "Tipo de información", - "create.display_link.display_on": "Escribir datos en:", - "create.display_link.display_on_multiline": "Empezar escribiendo en:", - - "create.display_source.label": "Attached Label", - "create.display_source.combine_item_names": "Combinar nombres de objetos", - "create.display_source.count_items": "Cantidad de objetos equivalentes", - "create.display_source.list_items": "Lista de objetos equivalentes", - "create.display_source.fluid_amount": "Cantidad de fluidos equivalentes", - "create.display_source.list_fluids": "Lista de fluidos equivalentes", - "create.display_source.nixie_tube": "Copiar tubos nixie", - "create.display_source.fill_level": "Container Fill Level", - "create.display_source.fill_level.display": "Formato de visualización", - "create.display_source.fill_level.percent": "Porcentaje", - "create.display_source.fill_level.progress_bar": "Barra de progreso", - "create.display_source.value_list.display": "Valor de visualización", - "create.display_source.value_list.shortened": "Acortado", - "create.display_source.value_list.full_number": "Full Number", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "Muertes del jugador", - "create.display_source.scoreboard": "Marcador", - "create.display_source.scoreboard.objective": "ID objetivo", - "create.display_source.scoreboard.objective_not_found": "'%1$s' no encontrado", - "create.display_source.scoreboard.objective.deaths": "Muertes del jugador", - "create.display_source.time_of_day": "Hora del día", - "create.display_source.stop_watch": "Cronómetro", - "create.display_source.time.format": "Formato de tiempo", - "create.display_source.time.12_hour": "12-horas", - "create.display_source.time.24_hour": "24-horas", - "create.display_source.accumulate_items": "Acumular conteo de objetos", - "create.display_source.item_throughput": "Rendimiento de objetos", - "create.display_source.item_throughput.interval": "Intervalo", - "create.display_source.item_throughput.interval.second": "por segundo", - "create.display_source.item_throughput.interval.minute": "por minuto", - "create.display_source.item_throughput.interval.hour": "por hora", - "create.display_source.train_status": "Estado de la programación del tren", - "create.display_source.station_summary": "Resumen de la estación de tren", - "create.display_source.station_summary.filter": "Filtro de nombre de estación", - "create.display_source.station_summary.train_name_column": "Train column size", - "create.display_source.station_summary.platform_column": "Platform column size", - "create.display_source.station_summary.now": "ahora", - "create.display_source.station_summary.minutes": " min", - "create.display_source.station_summary.seconds": "%1$ss", - "create.display_source.observed_train_name": "Nombre del tren detectado", - "create.display_source.max_enchant_level": "Coste máximo de encantamiento", - "create.display_source.boiler_status": "Estado de la caldera", - "create.display_source.entity_name": "Nombre de la entidad", - "create.display_source.kinetic_speed": "Velocidad de rotación (RPM)", - "create.display_source.kinetic_speed.absolute": "Ignorar dirección", - "create.display_source.kinetic_speed.directional": "Incluir dirección", - "create.display_source.kinetic_stress": "Estrés del sistema", - "create.display_source.kinetic_stress.display": "Información expuesta", - "create.display_source.kinetic_stress.progress_bar": "Barra de progreso", - "create.display_source.kinetic_stress.percent": "Porcentaje", - "create.display_source.kinetic_stress.current": "Estrés en UE", - "create.display_source.kinetic_stress.max": "Capacidad total", - "create.display_source.kinetic_stress.remaining": "UE restantes", - "create.display_source.redstone_power": "Redstone Power", - "create.display_source.redstone_power.display": "Formato de visualización", - "create.display_source.redstone_power.number": "Número", - "create.display_source.redstone_power.progress_bar": "Barra de progreso", - "create.display_source.boiler.not_enough_space": "No hay suficiente espacio ", - "create.display_source.boiler.for_boiler_status": "para el estado de la caldera", - - "create.display_target.line": "Fila %1$s", - "create.display_target.page": "Página %1$s", - "create.display_target.single_line": "Fila única", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;Ñ;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;ahora;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mC;C ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "El área seleccionada es demasiado grande", - "create.super_glue.cannot_reach": "Los bloques seleccionados deben de estar conectados", - "create.super_glue.click_to_confirm": "Haz clic de nuevo para confirmar", - "create.super_glue.click_to_discard": "Mayús izdo. + clic para descartar la selección", - "create.super_glue.first_pos": "Primera posición seleccionada", - "create.super_glue.abort": "Selección descartada", - "create.super_glue.not_enough": "Pegamento insuficiente", - "create.super_glue.success": "Aplicando pegamento...", - - "create.gui.config.overlay1": "Hola :)", - "create.gui.config.overlay2": "Esta es una muestra de la superposición", - "create.gui.config.overlay3": "Haga clic o arrastre con el ratón", - "create.gui.config.overlay4": "para mover esta vista previa", - "create.gui.config.overlay5": "Pulsar ESC para salir de esta pantalla", - "create.gui.config.overlay6": "y guardar la nueva posición", - "create.gui.config.overlay7": "Ejecute /create overlay reset", - "create.gui.config.overlay8": "para restablecer la posición por defecto", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: El tick del servidor está actualmente ralentizado en %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: El tick del servidor está ralentizado en %s ms ahora >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: El tick del servidor ha vuelto a su velocidad normal :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: usa /killtps stop para que el servidor vuelva a la velocidad normal", - "create.command.killTPSCommand.status.usage.1": "[Create]: usa /killtps start para ralentizar artificialmente el tick del servidor", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Este artefacto móvil de vagoneta parece demasiado grande para recogerlo", - "create.contraption.minecart_contraption_illegal_pickup": "Una fuerza mística está atando este artefacto móvil de vagoneta al mundo", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Artefacto animado se para", - "create.subtitle.peculiar_bell_use": "Campana peculiar suena", - "create.subtitle.worldshaper_place": "Moldeador de mundos coloca bloques", - "create.subtitle.whistle_train_manual": "Tren toca la bocina", - "create.subtitle.steam": "Ruidos de vapor", - "create.subtitle.saw_activate_stone": "Sierra mecánica activada", - "create.subtitle.schematicannon_finish": "Esquematicañón suena", - "create.subtitle.crafter_craft": "Ensamblador mecánico acaba", - "create.subtitle.wrench_remove": "Componente se rompe", - "create.subtitle.train3": "Ruedas del vagón retumban amortiguadamente", - "create.subtitle.whistle": "Silbido", - "create.subtitle.cogs": "Engranajes retumban", - "create.subtitle.slime_added": "Pegamento chapotea", - "create.subtitle.whistle_train_low": "Silbido agudo", - "create.subtitle.schematicannon_launch_block": "Esquematicañón dispara", - "create.subtitle.controller_take": "Atril vaciándose", - "create.subtitle.crafter_click": "Ensamblador mecánico suena", - "create.subtitle.depot_plop": "Objeto aterriza", - "create.subtitle.confirm": "Campaneo afirmativo", - "create.subtitle.mixing": "Mezclando", - "create.subtitle.mechanical_press_activation_belt": "Prensa mecánica apisona", - "create.subtitle.fwoomp": "Cañón de patatas sonando", - "create.subtitle.sanding_long": "Lijando", - "create.subtitle.crushing_1": "Triturando", - "create.subtitle.depot_slide": "Objeto desliza", - "create.subtitle.blaze_munch": "Quemador de blaze masca", - "create.subtitle.funnel_flap": "Embudo aletea", - "create.subtitle.haunted_bell_use": "Campana maldita suena", - "create.subtitle.scroll_value": "Rueda del ratón clica", - "create.subtitle.controller_put": "Controlador teclea", - "create.subtitle.cranking": "Manivela gira", - "create.subtitle.sanding_short": "Lijando", - "create.subtitle.wrench_rotate": "Llave inglesa usada", - "create.subtitle.potato_hit": "Impacto de vegetal", - "create.subtitle.saw_activate_wood": "Sierra mecánica activada", - "create.subtitle.whistle_high": "Silbido grave", - "create.subtitle.whistle_train_manual_low": "Tren toca la bocina", - "create.subtitle.whistle_train": "Silbido", - "create.subtitle.haunted_bell_convert": "Campana maldita se despierta", - "create.subtitle.train": "Ruedas del vagón retumban", - "create.subtitle.deny": "Pitido denegante", - "create.subtitle.controller_click": "Controlador clica", - "create.subtitle.whistle_low": "Silbido agudo", - "create.subtitle.copper_armor_equip": "Equipo de buceo tintinea", - "create.subtitle.mechanical_press_activation": "Prensa mecánica apisona", - "create.subtitle.contraption_assemble": "Artefacto animado se mueve", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EJEMPLO DE OBJETO (sólo un marcador de que este consejo existe)", - "item.create.example_item.tooltip.summary": "Una breve descripción del objeto. Los puntajes bajos resaltan un término", - "item.create.example_item.tooltip.condition1": "Cuando pasa esto", - "item.create.example_item.tooltip.behaviour1": "Entonces este objeto hace esto. (los comportamientos se muestran en el turno)", - "item.create.example_item.tooltip.condition2": "Y cuando ocurre esto otro", - "item.create.example_item.tooltip.behaviour2": "Puedes añadir tantos comportamientos como quieras", - "item.create.example_item.tooltip.control1": "Cuando se pulsa [Ctrl]", - "item.create.example_item.tooltip.action1": "Se muestran estos controles", - - "block.create.wooden_bracket.tooltip": "SOPORTE DE MADERA PARA EJES", - "block.create.wooden_bracket.tooltip.summary": "Decora tus _ejes_, _engranajes_ y _ductos_ con un acogedor refuerzo de madera.", - - "block.create.metal_bracket.tooltip": "SOPORTE DE METAL PARA EJES", - "block.create.metal_bracket.tooltip.summary": "Decora tus _ejes_, _engranajes_ y _ductos_ con un poco de robusto refuerzo industrial.", - - "block.create.seat.tooltip": "ASIENTO", - "block.create.seat.tooltip.summary": "¡Siéntate y disfruta del viaje! Anclará al jugador en un artefacto animado. También es ideal para muebles estáticos. Viene en una variedad de colores.", - "block.create.seat.tooltip.condition1": "Cuando se hace clic derecho en el asiento", - "block.create.seat.tooltip.behaviour1": "Sienta al jugador en el _asiento_. Pulsa Mayús izdo. para dejar el asiento.", - - "item.create.blaze_cake.tooltip": "PASTEL DE BLAZE", - "item.create.blaze_cake.tooltip.summary": "Un delicioso regalo para sus esforzados _quemadores de blaze_. ¡Los pone en marcha!.", - - "item.create.wand_of_symmetry.tooltip": "VARITA DE SIMETRÍA", - "item.create.wand_of_symmetry.tooltip.summary": "Refleja perfectamente la colocación de bloques en los planos configurados.", - "item.create.wand_of_symmetry.tooltip.condition1": "Mientras está en el inventario de acceso rápido", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Permanece activo.", - "item.create.wand_of_symmetry.tooltip.control1": "Cuando se hace clic derecho en el suelo", - "item.create.wand_of_symmetry.tooltip.action1": "_Crea_ o _mueve_ el espejo.", - "item.create.wand_of_symmetry.tooltip.control2": "Cuando se hace clic derecho en el aire", - "item.create.wand_of_symmetry.tooltip.action2": "_Quita_ el espejo activo.", - "item.create.wand_of_symmetry.tooltip.control3": "Mayús izdo. + clic derecho", - "item.create.wand_of_symmetry.tooltip.action3": "Abre la interfaz de configuración.", - - "item.create.handheld_worldshaper.tooltip": "MOLDEADOR DE MUNDOS", - "item.create.handheld_worldshaper.tooltip.summary": "Práctica herramienta para crear _paisajes_ y _características del terreno_.", - "item.create.handheld_worldshaper.tooltip.control1": "Cuando se hace clic izquierdo en un bloque", - "item.create.handheld_worldshaper.tooltip.action1": "Selecciona ese bloque para que lo replique la herramienta.", - "item.create.handheld_worldshaper.tooltip.control2": "Cuando se hace clic derecho en un bloque", - "item.create.handheld_worldshaper.tooltip.action2": "Aplica el _pincel_ y la _herramienta_ actualmente seleccionadas en el lugar deseado.", - "item.create.handheld_worldshaper.tooltip.control3": "Mayús izdo. + clic derecho", - "item.create.handheld_worldshaper.tooltip.action3": "Abre la interfaz de configuración.", - - "item.create.tree_fertilizer.tooltip": "FERTILIZANTE PARA ÁRBOLES", - "item.create.tree_fertilizer.tooltip.summary": "Una potente combinación de minerales adecuada para acelerar el crecimiento de los tipos de árboles más comunes.", - "item.create.tree_fertilizer.tooltip.condition1": "Cuando se utiliza en un árbol joven", - "item.create.tree_fertilizer.tooltip.behaviour1": "Hace crecer los árboles _independientemente_ de sus condiciones de _espacio_.", - - "item.create.extendo_grip.tooltip": "AGARRE EXTENDIDO", - "item.create.extendo_grip.tooltip.summary": "¡Boioioing! Aumenta enormemente la _distancia de alcance_ del portador. Se puede alimentar con la presión de aire de un _depósito trasero de cobre_", - "item.create.extendo_grip.tooltip.condition1": "Cuando está fuera de la mano", - "item.create.extendo_grip.tooltip.behaviour1": "Aumenta la _distancia de alcance_ de los objetos usados en la _mano principal_.", - "item.create.extendo_grip.tooltip.condition2": "Mientras se usa un depósito trasero de cobre", - "item.create.extendo_grip.tooltip.behaviour2": "No se utilizará _durabilidad_. En su lugar, la _presión del aire_ se drena desde el tanque", - - "item.create.potato_cannon.tooltip": "CANÓN DE PATATAS", - "item.create.potato_cannon.tooltip.summary": "¡Buuum! Lanza verduras caseras a tus enemigos. Se puede alimentar con la presión de aire de un _depósito trasero de cobre_", - "item.create.potato_cannon.tooltip.condition1": "Cuando se usa clic derecho", - "item.create.potato_cannon.tooltip.behaviour1": "_Dispara_ un objeto adecuado desde tu _inventario_.", - "item.create.potato_cannon.tooltip.condition2": "Mientras se usa un depósito trasero de cobre", - "item.create.potato_cannon.tooltip.behaviour2": "No se utilizará _durabilidad_. En su lugar, la _presión del aire_ se drena del tanque", - - "item.create.filter.tooltip": "FILTRO", - "item.create.filter.tooltip.summary": "Controla las _salidas_ y _entradas_ de los _dispositivos logísticos_ con más precisión, comparándolas con un _conjunto de objetos_ o varios _filtros anidados_.", - "item.create.filter.tooltip.condition1": "Cuando está en la ranura de filtros", - "item.create.filter.tooltip.behaviour1": "Controla el flujo de objetos según su _configuración_.", - "item.create.filter.tooltip.condition2": "Cuando se hace clic derecho", - "item.create.filter.tooltip.behaviour2": "Abre la interfaz de configuración.", - - "item.create.attribute_filter.tooltip": "FILTRO DE ATRIBUTOS", - "item.create.attribute_filter.tooltip.summary": "Controla las _salidas_ y las _entradas_ de los _dispositivos logísticos_ con más precisión, comparándolas con un _conjunto de atributos_ y _categorías_ de objetos.", - "item.create.attribute_filter.tooltip.condition1": "Cuando está en la ranura de filtros", - "item.create.attribute_filter.tooltip.behaviour1": "Controla el flujo de objetos según su _configuración_.", - "item.create.attribute_filter.tooltip.condition2": "Cuando se hace clic derecho", - "item.create.attribute_filter.tooltip.behaviour2": "Abre la interfaz de configuración.", - - "item.create.empty_schematic.tooltip": "ESQUEMA VACÍO", - "item.create.empty_schematic.tooltip.summary": "Se utiliza como 'ingrediente' de las recetas y para escribir en la _tabla de esquemas_.", - - "item.create.schematic.tooltip": "ESQUEMA", - "item.create.schematic.tooltip.summary": "Contiene una estructura para ser posicionada y colocada en el mundo. Posiciona el holograma como desees y utiliza un _esquematicañón_ para construirla.", - "item.create.schematic.tooltip.condition1": "Cuando se sostiene en la mano", - "item.create.schematic.tooltip.behaviour1": "Se puede posicionar utilizando las herramientas en pantalla.", - "item.create.schematic.tooltip.control1": "Mayús izdo. + clic derecho", - "item.create.schematic.tooltip.action1": "Abre una _interfaz_ para introducir las _coordenadas_ exactas.", - - "item.create.schematic_and_quill.tooltip": "ESQUEMA Y PLUMA", - "item.create.schematic_and_quill.tooltip.summary": "Se utiliza para guardar una estructura de tu mundo en un archivo .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Paso 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selecciona dos puntos de esquina usando clic derecho.", - "item.create.schematic_and_quill.tooltip.condition2": "Paso 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "[Ctrl] + [RUEDA DEL RATÓN] en las caras para ajustar el tamaño. Clic derecho de nuevo para guardar.", - "item.create.schematic_and_quill.tooltip.control1": "Cuando se hace clic derecho", - "item.create.schematic_and_quill.tooltip.action1": "Selecciona un punto de esquina / confirmar guardar.", - "item.create.schematic_and_quill.tooltip.control2": "Cuando mantiene [Ctrl]", - "item.create.schematic_and_quill.tooltip.action2": "Selecciona puntos en _medio del aire_. Rueda del ratón para ajustar la distancia.", - "item.create.schematic_and_quill.tooltip.control3": "Mayús izdo. + clic derecho", - "item.create.schematic_and_quill.tooltip.action3": "_Reinicia_ y elimina la selección.", - - "block.create.schematicannon.tooltip": "ESQUEMATICAÑÓN", - "block.create.schematicannon.tooltip.summary": "Dispara bloques para recrear un _esquema_ desplegado en el mundo. Utiliza objetos de los inventarios adyacentes y _pólvora_ como combustible.", - "block.create.schematicannon.tooltip.condition1": "Cuando se hace clic derecho", - "block.create.schematicannon.tooltip.behaviour1": "Abre la interfaz.", - - "block.create.schematic_table.tooltip": "TABLA DE ESQUEMAS", - "block.create.schematic_table.tooltip.summary": "Escribe los esquemas guardados en un _esquema vacío_.", - "block.create.schematic_table.tooltip.condition1": "Cuando se da un esquema vacío", - "block.create.schematic_table.tooltip.behaviour1": "Carga un archivo elegido de la carpeta de esquemas.", - - "item.create.goggles.tooltip": "GAFAS DEL INGENIERO", - "item.create.goggles.tooltip.summary": "Un par de gafas para aumentar tu visión con útil información _cinética_.", - "item.create.goggles.tooltip.condition1": "Cuando se llevan puestas", - "item.create.goggles.tooltip.behaviour1": "Muestra _indicadores de color_ correspondientes al _nivel de velocidad_ de un componente cinético colocado, así como el _impacto de estrés_ y la _carga_ de los componentes individuales.", - "item.create.goggles.tooltip.condition2": "Al mirar un medidor", - "item.create.goggles.tooltip.behaviour2": "Muestra información detallada sobre _velocidad_ o _estrés_ de la red a la que está conectado el medidor.", - "item.create.goggles.tooltip.condition3": "Al mirar un contenedor de fluidos", - "item.create.goggles.tooltip.behaviour3": "Muestra información detallada sobre la _carga_ del bloque y los _líquidos_ almacenados en su interior.", - - "item.create.wrench.tooltip": "LLAVE INGLESA", - "item.create.wrench.tooltip.summary": "Una herramienta útil para trabajar en sistemas cinéticos. Se puede utilizar para _rotar_, _desmantelar_ y para _configurar_ componentes.", - "item.create.wrench.tooltip.control1": "Cuando se hace clic derecho en un bloque cinético", - "item.create.wrench.tooltip.action1": "Rota los componentes hacia o desde la cara con la que ha interactuado.", - "item.create.wrench.tooltip.control2": "Mayús izdo. + clic derecho", - "item.create.wrench.tooltip.action2": "Desmonta los _componentes cinéticos_ y los devuelve a tu inventario_.", - - "block.create.nozzle.tooltip": "BOQUILLA", - "block.create.nozzle.tooltip.summary": "Se acopla a la parte delantera de un _ventilador revestido_ para distribuir su efecto sobre las entidades en _todas las direcciones_.", - - "block.create.cuckoo_clock.tooltip": "RELOJ DE CUCO", - "block.create.cuckoo_clock.tooltip.summary": "Fina artesanía para decorar un espacio y contar el tiempo.", - "block.create.cuckoo_clock.tooltip.condition1": "Cuando es alimentado por cinética", - "block.create.cuckoo_clock.tooltip.behaviour1": "Muestra la _hora actual_ y toca una melodía dos veces al día. Se activa una vez al mediodía y al anochecer, _en cuanto los jugadores pueden dormir_.", - - "block.create.turntable.tooltip": "PLATAFORMA GIRATORIA", - "block.create.turntable.tooltip.summary": "Convierte la _fuerza rotacional_ en un refinado mareo.", - - "block.create.toolbox.tooltip": "CAJA DE HERRAMIENTAS", - "block.create.toolbox.tooltip.summary": "El compañero más querido de todo inventor. Mantiene una gran cantidad de 8 tipos de objetos diferentes.", - "block.create.toolbox.tooltip.condition1": "Cuando se recoge...", - "block.create.toolbox.tooltip.behaviour1": "Conserva el contenido del inventario.", - "block.create.toolbox.tooltip.condition2": "Cuando se coloca en el rango...", - "block.create.toolbox.tooltip.behaviour2": "Los jugadores cercanos pueden utilizar el enlace de teclas de la caja de herramientas para acceder a su contenido de forma remota.", - "block.create.toolbox.tooltip.condition3": "Cuando se hace clic derecho...", - "block.create.toolbox.tooltip.behaviour3": "Abre la interfaz del contenedor.", - - "block.create.stockpile_switch.tooltip": "INTERRUPTOR DE ACOPIO", - "block.create.stockpile_switch.tooltip.summary": "Activa una señal de redstone en función de la cantidad de _objetos almacenados_ en el _contenedor_ adjunto. Viene con un práctico filtro. A diferencia de un _comparador, el _interruptor de acopio_ permite la configuración de _umbrales_, a partir de los cuales se invierten las señales.", - "block.create.stockpile_switch.tooltip.condition1": "Cuando se hace clic derecho", - "block.create.stockpile_switch.tooltip.behaviour1": "Abre la interfaz de configuración.", - - "block.create.content_observer.tooltip": "OBSERVADOR DE CONTENIDO", - "block.create.content_observer.tooltip.summary": "_Detecta objetos_ o _fluidos_ dentro de _contenedores_, _tuberías_ o _cintas mecánicas_ que coincidan con un _filtro_ configurado.", - "block.create.content_observer.tooltip.condition1": "Al observar un contenedor", - "block.create.content_observer.tooltip.behaviour1": "Emite una señal de Redstone mientras que el contenedor observado contenga lo mismo.", - "block.create.content_observer.tooltip.condition2": "Al observar un embudo", - "block.create.content_observer.tooltip.behaviour2": "Emite un pulso de Redstone cuando se transfiere un objeto que coincide.", - - "block.create.creative_crate.tooltip": "CAJA CREATIVA", - "block.create.creative_crate.tooltip.summary": "Este _contenedor de objetos_ permite la replicación infinita de cualquier objeto. Colócalo junto a un _esquematicañón_ para eliminar cualquier requisito de material.", - "block.create.creative_crate.tooltip.condition1": "Cuando el objeto está en la ranura para filtros", - "block.create.creative_crate.tooltip.behaviour1": "Todo lo que se _extraiga_ de este contenedor proporcionará un suministro _ilimitado_ del objeto especificado. Los objetos _insertados_ en esta caja serán _evitados_.", - - "item.create.creative_blaze_cake.tooltip": "PASTEL CREATIVO", - "item.create.creative_blaze_cake.tooltip.summary": "Un regalo muy especial para los _Quemadores de Blaze_ que permite _controlar su nivel de calor_. Después de comer este pastel, los Quemadores de blaze _nunca se quedarán sin combustible_.", - "item.create.creative_blaze_cake.tooltip.condition1": "Clic derecho en un Quemador de blaze", - "item.create.creative_blaze_cake.tooltip.behaviour1": "Bloquea el nivel de calor del Quemador de blaze. Si se utiliza de nuevo, _cicla_ el nivel de calor del Quemador de blaze.", - - "block.create.controller_rail.tooltip": "RAÍL DE CONTROL", - "block.create.controller_rail.tooltip.summary": "Un raíl energizado _unidireccional_ capaz de _controlar con precisión_ la _velocidad de movimiento_ de una vagoneta.", - "block.create.controller_rail.tooltip.condition1": "Cuando es alimentado con redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Acelera_ o _desacelera_ pasando _vagonetas_ correspondientes a la _fuerza de la señal_. Propaga la energía de redstone a los raíles de control adyacentes. Al alimentar dos raíles de control con diferentes intensidades, los carriles entre ellos interpolarán su señal.", - - "item.create.sand_paper.tooltip": "PAPEL DE LIJA", - "item.create.sand_paper.tooltip.summary": "Un papel rugoso que se puede utilizar para _pulir materiales_. Se puede aplicar automáticamente con el _desplegador_.", - "item.create.sand_paper.tooltip.condition1": "Cuando se usa", - "item.create.sand_paper.tooltip.behaviour1": "Aplica un pulido a los objetos sostenidos en la _mano libre_ o tirados en el _suelo_ cuando se _miran_.", - - "item.create.builders_tea.tooltip": "TÉ DEL CONSTRUCTOR", - "item.create.builders_tea.tooltip.summary": "La bebida perfecta para empezar el día. Motivante y saturante.", - - "item.create.refined_radiance.tooltip": "RESPLANDOR REFINADO", - "item.create.refined_radiance.tooltip.summary": "Un material cromático forjado a partir de la _luz absorbida_.", - "item.create.refined_radiance.tooltip.condition1": "Trabajo en progreso", - "item.create.refined_radiance.tooltip.behaviour1": "Los usos para este material estarán disponibles en un próximo lanzamiento.", - - "item.create.shadow_steel.tooltip": "ACERO SOMBRÍO", - "item.create.shadow_steel.tooltip.summary": "Un material cromático forjado en el _vacío_.", - "item.create.shadow_steel.tooltip.condition1": "Trabajo en curso", - "item.create.shadow_steel.tooltip.behaviour1": "Los usos de este material estarán disponibles en una futura versión.", - - "item.create.linked_controller.tooltip": "CONTROLADOR ENLAZADO", - "item.create.linked_controller.tooltip.summary": "Permite el control manual de las frecuencias de _enlaces de redstone_ asignadas a sus seis botones.", - "item.create.linked_controller.tooltip.condition1": "Al hacer clic derecho", - "item.create.linked_controller.tooltip.behaviour1": "Activa el _controlador_. Los _controles de movimiento_ se adquieren mientras está activo.", - "item.create.linked_controller.tooltip.condition2": "Al usar Mayús izdo. + clic derecho", - "item.create.linked_controller.tooltip.behaviour2": "Abre la interfaz de configuración manual.", - "item.create.linked_controller.tooltip.condition3": "Al usar clic derecho en un receptor de enlaces de redstone", - "item.create.linked_controller.tooltip.behaviour3": "Activa el _modo de vinculación_, pulsa uno de los _seis controles_ para vincularlo a la _frecuencia de los enlaces_.", - "item.create.linked_controller.tooltip.condition4": "Clic derecho en un atril", - "item.create.linked_controller.tooltip.behaviour4": "Coloca el controlador en el atril para facilitar su activación. (Clic derecho + Mayús izdo. para recuperarlo)", - - "item.create.diving_helmet.tooltip": "CASCO DE BUCEO", - "item.create.diving_helmet.tooltip.summary": "Junto con un _depósito trasero de cobre_, permite que el usuario pueda respirar bajo el agua durante un tiempo prolongado.", - "item.create.diving_helmet.tooltip.condition1": "Cuando se lleva puesto", - "item.create.diving_helmet.tooltip.behaviour1": "Proporciona el efecto de _respiración acuática_, drenando lentamente la presión de aire del _depósito trasero_.", - - "item.create.copper_backtank.tooltip": "DEPÓSITO TRASERO DE COBRE", - "item.create.copper_backtank.tooltip.summary": "Un tanque portátil para transportar _aire presurizado_.", - "item.create.copper_backtank.tooltip.condition1": "Cuando se lleva puesto", - "item.create.copper_backtank.tooltip.behaviour1": "Proporciona _aire presurizado_ a los equipos que lo requieran.", - "item.create.copper_backtank.tooltip.condition2": "Cuando se coloca y es alimentado por cinética", - "item.create.copper_backtank.tooltip.behaviour2": "Recoge _aire presurizado_ a un ritmo que depende de la velocidad rotacional.", - - "block.create.placard.tooltip": "Pancarta", - "block.create.placard.tooltip.summary": "_Enmarca_ tus _objetos_ en latón usando este fantástico mural. ¡Seguro para artefactos móviles!", - "block.create.placard.tooltip.condition1": "Cuando se usa clic derecho con un objeto", - "block.create.placard.tooltip.behaviour1": "_Añade_ el _objeto_ que sostienes a la pancarta. _Emite_ una breve señal de _Redstone_ si ya se encontraba ese mismo objeto.", - "block.create.placard.tooltip.condition2": "Cuando se golpea", - "block.create.placard.tooltip.behaviour2": "_Retira_ el _objeto_ actual del marco.", - - "block.create.flywheel.tooltip": "Rueda de inercia", - "block.create.flywheel.tooltip.summary": "_Embellece_ tus _máquinas_ con la imponente rueda de latón.", - "block.create.flywheel.tooltip.condition1": "Cuando se activa cinéticamente", - "block.create.flywheel.tooltip.behaviour1": "empieza a girar.", - - "item.create.diving_boots.tooltip": "BOTAS DE BUCEO", - "item.create.diving_boots.tooltip.summary": "Un par de _botas_ pesadas, que permiten atravesar mejor el suelo del océano.", - "item.create.diving_boots.tooltip.condition1": "Cuando se llevan puestas", - "item.create.diving_boots.tooltip.behaviour1": "El portador se hunde rápido y no puede nadar. Concede la capacidad de caminar y saltar bajo el agua. Al portador no le afectarán las _cintas mecánicas_.", - - "item.create.crafting_blueprint.tooltip": "PLANO DE ELABORACIÓN", - "item.create.crafting_blueprint.tooltip.summary": "Colocado en una pared, puede utilizarse para especificar la disposición de los ingredientes para facilitar la elaboración manual. Cada ranura representa una receta", - "item.create.crafting_blueprint.condition1": "Al hacer clic derecho en una ranura vacía", - "item.create.crafting_blueprint.behaviour1": "Abre un menú que permite configurar una receta y los objetos a mostrar.", - "item.create.crafting_blueprint.condition2": "Al hacer clic derecho en una ranura configurada", - "item.create.crafting_blueprint.behaviour2": "Aplica la receta configurada con los ingredientes que se encuentran en tu inventario. Se puede utilizar para fabricar hasta una pila de objetos.", - - "item.create.minecart_coupling.tooltip": "ENSAMBLADOR DE VAGONETAS", - "item.create.minecart_coupling.tooltip.summary": "_Encadena_ todas tus _vagonetas_ o _artefactos móviles de vagoneta_ para formar un majestuoso _tren_.", - "item.create.minecart_coupling.tooltip.condition1": "Cuando se utiliza en vagonetas", - "item.create.minecart_coupling.tooltip.behaviour1": "_Acopla_ dos vagonetas, intentando mantenerlas a una _distancia constante_ mientras se mueven.", - - "item.create.experience_nugget.tooltip": "PEPITA DE EXPERIENCIA", - "item.create.experience_nugget.tooltip.summary": "_¡Ding!_ Una partícula de _inspiración_ de tus fantásticas invenciones.", - "item.create.experience_nugget.tooltip.condition1": "Cuando se usa", - "item.create.experience_nugget.tooltip.behaviour1": "_Otorga_ los puntos de _experiencia_ contenidos.", - - "block.create.peculiar_bell.tooltip": "CAMPANA PECULIAR", - "block.create.peculiar_bell.tooltip.summary": "Una campana decorativa de latón. Al colocarla sobre un _Fuego del alma_ o una _Fogata del alma_ puede producirse una transformación espeluznante...", - - "block.create.haunted_bell.tooltip": "CAMPANA MALDITA", - "block.create.haunted_bell.tooltip.summary": "Una _campana maldita_ perseguida por las almas perdidas del Nether", - "block.create.haunted_bell.tooltip.condition1": "Cuando se sostiene o suena", - "block.create.haunted_bell.tooltip.behaviour1": "Resalta los _puntos sin luz_ cercanos en los que pueden aparecer las _criaturas hostiles_.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "Este comportamiento puede modificarse mediante una llave inglesa", - "create.ponder.shared.storage_on_contraption": "Los inventarios unidos a un artefacto animado recogerán sus producciones automáticamente", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "Fuente: 16 RPM", - "create.ponder.shared.movement_anchors": "Con la ayuda de un chasis o pegamento, se pueden mover estructuras más grandes.", - "create.ponder.tag.redstone": "Componentes lógicos", - "create.ponder.tag.redstone.description": "Componentes que ayudan a la ingeniería de redstone", - "create.ponder.tag.contraption_assembly": "Utilidades para adjuntar bloques", - "create.ponder.tag.contraption_assembly.description": "Herramientas y componentes utilizados para montar artefactos animados", - "create.ponder.tag.fluids": "Manipuladores de fluidos", - "create.ponder.tag.fluids.description": "Componentes que ayudan a transportar y utilizar fluidos", - "create.ponder.tag.decoration": "Estética", - "create.ponder.tag.decoration.description": "Componentes utilizados principalmente con fines decorativos", - "create.ponder.tag.windmill_sails": "Velas para los rodamientos de los molinos de viento", - "create.ponder.tag.windmill_sails.description": "Bloques que cuentan para la fuerza de un artefacto estacionario de molino de viento cuando se ensamblan. Cada uno de ellos tiene la misma eficacia al hacerlo.", - "create.ponder.tag.arm_targets": "Objetivos para los brazos mecánicos", - "create.ponder.tag.arm_targets.description": "Componentes que pueden seleccionarse como entradas o salidas del brazo mecánico", - "create.ponder.tag.kinetic_appliances": "Dispositivos cinéticos", - "create.ponder.tag.kinetic_appliances.description": "Componentes que utilizan la fuerza rotacional", - "create.ponder.tag.kinetic_sources": "Fuentes cinéticas", - "create.ponder.tag.kinetic_sources.description": "Componentes que generan fuerza rotacional", - "create.ponder.tag.movement_anchor": "Anclas de movimiento", - "create.ponder.tag.movement_anchor.description": "Componentes que permiten crear artefactos en movimiento, animando una estructura anexa de diversas maneras", - "create.ponder.tag.kinetic_relays": "Transmisores cinéticos", - "create.ponder.tag.kinetic_relays.description": "Componentes que ayudan a transmitir la fuerza rotacional en otro lugar", - "create.ponder.tag.contraption_actor": "Actores de artefactos animados", - "create.ponder.tag.contraption_actor.description": "Componentes que tienen un comportamiento especial cuando están unidos a un artefacto animado", - "create.ponder.tag.creative": "Modo creativo", - "create.ponder.tag.creative.description": "Componentes que no suelen estar disponibles para el Modo Supervivencia", - "create.ponder.tag.display_sources": "Fuentes para los enlaces de visualización", - "create.ponder.tag.display_sources.description": "Componentes o bloques que ofrecen cierta información que puede ser leída por enlaces de visualización", - "create.ponder.tag.logistics": "Transporte de objetos", - "create.ponder.tag.logistics.description": "Componentes que ayudan a desplazar los objetos", - "create.ponder.tag.display_targets": "Objetivos para los enlaces de visualización", - "create.ponder.tag.display_targets.description": "Componentes o bloques que pueden procesar y mostrar la información recibida de enlaces de visualización", - "create.ponder.tag.train_related": "Equipamiento de ferrocarril", - "create.ponder.tag.train_related.description": "Componentes usados en la construcción y gestión de trenes", - - "create.ponder.analog_lever.header": "Controlar señales mediante la palanca analógica", - "create.ponder.analog_lever.text_1": "Las palancas analógicas son una fuente compacta y precisa de energía de redstone", - "create.ponder.analog_lever.text_2": "Haz clic derecho para aumentar su potencia analógica", - "create.ponder.analog_lever.text_3": "Usa Mayús izdo. + clic derecho para volver a disminuir su potencia", - - "create.ponder.andesite_tunnel.header": "Usar túneles de andesita", - "create.ponder.andesite_tunnel.text_1": "Los túneles de andesita se pueden utilizar para tapar las cintas mecánicas", - "create.ponder.andesite_tunnel.text_2": "Siempre que un túnel de andesita tenga conexiones a los lados...", - "create.ponder.andesite_tunnel.text_3": "...dividirá exactamente un objeto de cualquier pila que pase", - "create.ponder.andesite_tunnel.text_4": "El resto continuará su camino", - - "create.ponder.auto_schedule.header": "Estaciones y programaciones", - "create.ponder.auto_schedule.text_1": "Las programaciones pueden usarse para proporcionar un destino a los conductores", - "create.ponder.auto_schedule.text_2": "Los comparadores recibirán una señal cuando haya un tren presente", - "create.ponder.auto_schedule.text_3": "Ten en cuenta que solo puedes acercarte a una estación desde la dirección indicada", - "create.ponder.auto_schedule.text_4": "Las estaciones también pueden usarse para asignar nuevas programaciones automáticamente", - "create.ponder.auto_schedule.text_5": "Si colocas una programación en una estación, se copiará automáticamente en los trenes presentes", - "create.ponder.auto_schedule.text_6": "Al contrario de hacerlo manualmente, los conductores no consumirán la programación de la estación", - - "create.ponder.basin.header": "Procesar objetos en la cuenca", - "create.ponder.basin.text_1": "Una cuenca puede contener objetos y fluidos para su procesamiento", - "create.ponder.basin.text_2": "Después de un paso de procesamamiento, las cuencas intentan descargar por debajo a un lado de ellas", - "create.ponder.basin.text_3": "Cuando un ingrediente válido está presente, la cuenca mostrará un conducto de salida", - "create.ponder.basin.text_4": "Aquí se pueden aplicar varias opciones", - "create.ponder.basin.text_5": "Las salidas serán capturadas por el inventario que está por debajo", - "create.ponder.basin.text_6": "Sin conducto de salida, la cuenca retendrá los objetos creados en su procesamiento", - "create.ponder.basin.text_7": "Esto puede ser útil si las salidas deben ser reutilizadas como ingredientes", - "create.ponder.basin.text_8": "Las salidas deseadas tendrán que ser extraídas de la cuenca", - "create.ponder.basin.text_9": "Podría ser necesario un filtro para evitar sacar los objetos no procesados", - - "create.ponder.bearing_modes.header": "Modos de movimiento del rodamiento mecánico", - "create.ponder.bearing_modes.text_1": "Cuando se detenga, el rodamiento mecánico colocará la estructura en el ángulo más cercano alineado con la cuadrícula", - "create.ponder.bearing_modes.text_2": "Se puede configurar para que nunca vuelva a los bloques sólidos, o sólo cerca del ángulo en el que comenzó", - - "create.ponder.belt_casing.header": "Correas revestidas", - "create.ponder.belt_casing.text_1": "Se puede utilizar revestidor de latón o andesita para decorar las cintas mecánicas", - "create.ponder.belt_casing.text_2": "Se puede utilizar una llave inglesa para quitar el revestimiento", - - "create.ponder.belt_connector.header": "El uso de las cintas", - "create.ponder.belt_connector.text_1": "Al hacer clic derecho en dos ejes con una cinta, se conectarán entre sí", - "create.ponder.belt_connector.text_2": "Las selecciones accidentales pueden ser canceladas con Mayús izdo. + clic derecho", - "create.ponder.belt_connector.text_3": "Se pueden añadir ejes adicionales en toda la cinta mecánica", - "create.ponder.belt_connector.text_4": "Los ejes conectados a través de cintas mecánicas girarán con velocidad y dirección idénticas", - "create.ponder.belt_connector.text_5": "Los ejes añadidos se pueden quitar con la llave inglesa", - "create.ponder.belt_connector.text_6": "Las cintas mecánicas se pueden teñir con fines estéticos", - - "create.ponder.belt_directions.header": "Orientaciones válidas para las cintas mecánicas", - "create.ponder.belt_directions.text_1": "Las cintas no pueden conectarse en direcciones arbitrarias", - "create.ponder.belt_directions.text_2": "1. Pueden conectarse horizontalmente", - "create.ponder.belt_directions.text_3": "2. Pueden conectarse en diagonal", - "create.ponder.belt_directions.text_4": "3. Pueden conectarse verticalmente", - "create.ponder.belt_directions.text_5": "4. Y pueden conectar ejes verticales horizontalmente", - "create.ponder.belt_directions.text_6": "Estas son todas las direcciones posibles. Pueden abarcar cualquier longitud entre 2 y 20 bloques", - - "create.ponder.belt_transport.header": "El uso de las cintas mecánicas para la logística", - "create.ponder.belt_transport.text_1": "Las cintas mecánicas transportan objetos y otras entidades", - "create.ponder.belt_transport.text_2": "Haz clic derecho con la mano vacía para sacar objetos de una cinta mecánica", - - "create.ponder.blaze_burner.header": "Alimentar quemadores de blaze", - "create.ponder.blaze_burner.text_1": "Los quemadores de blaze pueden proporcionar calor a los objetos procesados en una cuenca", - "create.ponder.blaze_burner.text_2": "Para ello, el blaze tiene que ser alimentado con objetos inflamables", - "create.ponder.blaze_burner.text_3": "Con un pastel de blaze, el quemador puede alcanzar un mayor nivel de calor", - "create.ponder.blaze_burner.text_4": "El proceso de alimentación puede automatizarse utilizando desplegadores o brazos mecánicos", - - "create.ponder.brass_funnel.header": "El embudo de latón", - "create.ponder.brass_funnel.text_1": "Los embudos de andesita sólo pueden extraer objetos individuales", - "create.ponder.brass_funnel.text_2": "Los embudos de latón pueden extraer hasta una pila completa", - "create.ponder.brass_funnel.text_3": "Usar la rueda de desplazamiento del ratón en la ranura para filtros permite un control preciso del tamaño de la pila extraída.", - "create.ponder.brass_funnel.text_4": "El uso de objetos en la ranura de filtrado restringirá el embudo para transferir sólo las pilas que coincidan.", - - "create.ponder.brass_tunnel.header": "Usar túneles de latón", - "create.ponder.brass_tunnel.text_1": "Los túneles de latón pueden utilizarse para tapar cintas mecánicas", - "create.ponder.brass_tunnel.text_2": "Tienen ranuras de filtro en cada lado abierto", - "create.ponder.brass_tunnel.text_3": "Los filtros en las conexiones de entrada simplemente bloquean los objetos que no coincidan", - "create.ponder.brass_tunnel.text_4": "Los filtros en las conexiones de salida pueden utilizarse para ordenar los objetos por tipo", - "create.ponder.brass_tunnel.text_5": "Siempre que un objeto de paso tenga múltiples salidas válidas, el modo de distribución decidirá cómo manejarlo", - "create.ponder.brass_tunnel.text_6": "Los túneles de latón en bandas paralelas formarán un grupo", - "create.ponder.brass_tunnel.text_7": "Los objetos entrantes se distribuirán ahora por todas las salidas conectadas", - "create.ponder.brass_tunnel.text_8": "Para ello, los objetos también pueden insertarse en el bloque del túnel directamente", - - "create.ponder.brass_tunnel_modes.header": "Modos de distribución del túnel de latón", - "create.ponder.brass_tunnel_modes.text_1": "Mediante una llave inglesa se puede configurar el comportamiento de distribución de los túneles de latón", - "create.ponder.brass_tunnel_modes.text_10": "'Sincronizar entradas' es una configuración única de los túneles de latón", - "create.ponder.brass_tunnel_modes.text_11": "Las entradas sólo pueden pasar si cada túnel del grupo tiene una en espera", - "create.ponder.brass_tunnel_modes.text_12": "Esto asegura que todas las cintas mecánicas afectadas suministren objetos al mismo tiempo", - "create.ponder.brass_tunnel_modes.text_2": "El modo División intentará distribuir la pila uniformemente entre las salidas disponibles", - "create.ponder.brass_tunnel_modes.text_3": "Si una salida no puede tomar más objetos, se saltará", - "create.ponder.brass_tunnel_modes.text_4": "El modo División forzada nunca saltará las salidas, y en su lugar esperará hasta que estén libres", - "create.ponder.brass_tunnel_modes.text_5": "El modo Round Robin mantiene las pilas enteras, y recorre las salidas de forma iterativa", - "create.ponder.brass_tunnel_modes.text_6": "Una vez más, si una salida no puede aceptar más objetos, se saltará", - "create.ponder.brass_tunnel_modes.text_7": "El modo Round Robin forzado nunca omite salidas", - "create.ponder.brass_tunnel_modes.text_8": "El modo Preferir el más cercano prioriza las salidas más cercanas a la ubicación de entrada de los objetos", - "create.ponder.brass_tunnel_modes.text_9": "El modo Aleatorizar distribuirá pilas enteras a salidas elegidas al azar", - - "create.ponder.cart_assembler.header": "Mover estructuras usando ensambladores de vagonetas", - "create.ponder.cart_assembler.text_1": "Los ensambladores de vagonetas montan estructuras adjuntas a las vagonetas que pasan", - "create.ponder.cart_assembler.text_2": "Sin una señal de redstone, desmonta los artefactos móviles de vagoneta que pasan de nuevo en bloques", - "create.ponder.cart_assembler.text_3": "El uso de una llave inglesa en una vagoneta te permitirá llevarte el artefacto móvil a otro lugar", - - "create.ponder.cart_assembler_dual.header": "Montando artefactos móviles de vagoneta", - "create.ponder.cart_assembler_dual.text_1": "Siempre que dos ensambladores de vagoneta compartan una estructura adjunta...", - "create.ponder.cart_assembler_dual.text_2": "...al alimentar a cualquiera de ellos se creará un artefacto móvil de vagoneta", - "create.ponder.cart_assembler_dual.text_3": "Las vagonetas se comportarán como las conectadas a través del acoplamiento de vagoneta", - - "create.ponder.cart_assembler_modes.header": "Configurar la orientación de los artefactos móviles de vagonetas", - "create.ponder.cart_assembler_modes.text_1": "Los artefactos móviles de vagonetas girarán para orientarse hacia el movimiento de sus vagonetas", - "create.ponder.cart_assembler_modes.text_2": "Esta flecha indica qué lado de la estructura se considerará la parte delantera", - "create.ponder.cart_assembler_modes.text_3": "Si el ensamblador está configurado para bloquear la rotación, la orientación de los artefactos móviles nunca cambiará", - - "create.ponder.cart_assembler_rails.header": "Otros tipos de vagonetas y raíles", - "create.ponder.cart_assembler_rails.text_1": "Los ensambladores de vagonetas en raíles normales no afectarán el movimiento de las vagonetas que pasen", - "create.ponder.cart_assembler_rails.text_2": "Cuando se encuentre en un raíl motorizado o en un raíl de control, las vagonetas se mantendrán en su sitio hasta que sea motorizado", - "create.ponder.cart_assembler_rails.text_3": "Se pueden utilizar otros tipos de vagonetas como anclaje", - "create.ponder.cart_assembler_rails.text_4": "Los artefactos móviles de vagonetas de horno se mantendrán alimentados a sí mismos, sacando combustible de cualquier inventario adjunto", - - "create.ponder.chain_drive.header": "Transmitir fuerza rotacional con las cadenas de transmisión", - "create.ponder.chain_drive.text_1": "Las cadenas de transmisión transmiten la rotación entre sí en fila", - "create.ponder.chain_drive.text_2": "Todos los ejes conectados así girarán en la misma dirección", - "create.ponder.chain_drive.text_3": "Cualquier parte de la fila puede girar 90 grados usando una llave inglesa", - - "create.ponder.chain_gearshift.header": "Controlar la velocidad de rotación con la cadena de transmisión ajustable", - "create.ponder.chain_gearshift.text_1": "Las cadenas de transmisión ajustables sin alimentación se comportan exactamente como las cadenas de transmisión", - "create.ponder.chain_gearshift.text_2": "Cuando están alimentadas, la velocidad transmitida a las demás cadenas de transmisión de la fila se duplica", - "create.ponder.chain_gearshift.text_3": "Siempre que la cadena de transmisión alimentada no esté en el origen, su velocidad se reducirá a la mitad", - "create.ponder.chain_gearshift.text_4": "En ambos casos, las cadenas de transmisión de la fila siempre funcionan al doble de la velocidad de la cadena de transmisión alimentada", - "create.ponder.chain_gearshift.text_5": "Utilizando señales analógicas, la relación puede ajustarse con mayor precisión, entre 1 y 2", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "Transportar objetos hacia abajo a través de ductos", - "create.ponder.chute.text_1": "Los ductos pueden transportar objetos verticalmente desde y hacia los inventarios", - "create.ponder.chute.text_2": "Usando la llave inglesa, se puede crear una ventana", - "create.ponder.chute.text_3": "Colocar ductos apuntando a las caras laterales de otro lo hará en diagonal", - - "create.ponder.chute_upward.header": "Transportar objetos hacia arriba mediante ductos", - "create.ponder.chute_upward.text_1": "Usando ventiladores revestidos en la parte superior o inferior, un ducto puede transportar objetos hacia arriba", - "create.ponder.chute_upward.text_2": "Al inspeccionar los ductos con las gafas del ingeniero, se revela información sobre la dirección del movimiento", - "create.ponder.chute_upward.text_3": "En el extremo 'bloqueado', los objetos tendrán que ser insertados/sacados de los lados", - - "create.ponder.clockwork_bearing.header": "Animar estructuras con rodamientos tipo reloj", - "create.ponder.clockwork_bearing.text_1": "Los rodamientos tipo reloj se fijan a los bloques que tienen delante", - "create.ponder.clockwork_bearing.text_2": "Al recibir fuerza rotacional, la estructura girará según la hora del día", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "Haz clic derecho en el rodamiento para iniciar o detener la animación de la estructura", - "create.ponder.clockwork_bearing.text_6": "Delante de la manecilla de las horas se puede añadir una segunda estructura", - "create.ponder.clockwork_bearing.text_7": "Asegúrese de que las dos estructuras no están unidas entre sí con pegamento o algo similar", - "create.ponder.clockwork_bearing.text_8": "La segunda estructura ahora girará como el minutero", - - "create.ponder.clutch.header": "Controlar la fuerza rotacional mediante un embrague", - "create.ponder.clutch.text_1": "Los embragues transmitirán la rotación en línea recta", - "create.ponder.clutch.text_2": "Cuando se alimentan con redstone, rompen la conexión", - - "create.ponder.cog_speedup.header": "Cambiar de marchas con engranajes", - "create.ponder.cog_speedup.text_1": "Los engranajes grandes y normales pueden conectarse en diagonal", - "create.ponder.cog_speedup.text_2": "Al cambiar de engranajes grandes a normales, la velocidad rotacional se duplicará", - "create.ponder.cog_speedup.text_3": "Inversamente, la velocidad rotacional se reducirá a la mitad", - - "create.ponder.cogwheel.header": "Transmitir fuerza rotacional mediante engranajes", - "create.ponder.cogwheel.text_1": "Los engranajes transmitirán la rotación a otros engranajes adyacentes", - "create.ponder.cogwheel.text_2": "Los ejes adyacentes conectados así, girarán en direcciones opuestas", - - "create.ponder.cogwheel_casing.header": "Revestir engranajes", - "create.ponder.cogwheel_casing.text_1": "Los revestimientos de latón o andesita pueden ser usados para decorar los engranajes", - "create.ponder.cogwheel_casing.text_2": "Los componentes que se añadan por la salida del eje no se conectarán", - "create.ponder.cogwheel_casing.text_3": "La llave inglesa puede usarse para alternar las conexiones", - - "create.ponder.creative_fluid_tank.header": "Tanque de fluidos creativo", - "create.ponder.creative_fluid_tank.text_1": "Los depósitos de fluidos creativos pueden utilizarse para proporcionar un suministro de fluidos sin fondo", - "create.ponder.creative_fluid_tank.text_2": "Haga clic con el botón derecho en un objeto que contenga fluido para configurarlo", - "create.ponder.creative_fluid_tank.text_3": "Las redes de tuberías pueden ahora extraer sin cesar el fluido asignado del depósito", - "create.ponder.creative_fluid_tank.text_4": "Cualquier fluido empujado de vuelta a un tanque de fluido creativo será anulado", - - "create.ponder.creative_motor.header": "Generar fuerza rotacional con motores creativos", - "create.ponder.creative_motor.text_1": "Los motores creativos son una fuente compacta y configurable de fuerza rotacional", - "create.ponder.creative_motor.text_2": "Usar la rueda de desplazamiento del ratón en su parte trasera cambia las RPM de la salida rotacional", - - "create.ponder.creative_motor_mojang.header": "El enigma de Mojang", - - "create.ponder.crushing_wheels.header": "Procesar objetos con las ruedas trituradoras", - "create.ponder.crushing_wheels.text_1": "Un par de ruedas trituradoras pueden moler objetos de forma muy eficaz", - "create.ponder.crushing_wheels.text_2": "Su fuerza rotacional tiene que hacerlas girar una contra otra", - "create.ponder.crushing_wheels.text_3": "Los objetos lanzados o insertados en la parte superior serán procesados", - "create.ponder.crushing_wheels.text_4": "Los objetos también pueden ser insertados y recogidos a través de medios automatizados", - - "create.ponder.deployer.header": "Usar el desplegador", - "create.ponder.deployer.text_1": "Dada la fuerza rotacional, un desplegador puede imitar las interacciones de los jugadores", - "create.ponder.deployer.text_10": "Haz clic derecho en el frente para darle un objeto a utilizar", - "create.ponder.deployer.text_11": "Los objetos también pueden ser insertados automáticamente", - "create.ponder.deployer.text_12": "Los desplegadores llevan una ranura de filtro", - "create.ponder.deployer.text_13": "Cuando se establece un filtro, sólo se activa mientras se mantiene un objeto coincidente", - "create.ponder.deployer.text_14": "Ahora sólo se pueden insertar los objetos que coincidan con el filtro...", - "create.ponder.deployer.text_15": "...y sólo se extraerán los objetos que no coincidan", - "create.ponder.deployer.text_2": "Siempre interactuará con la posición 2 bloques delante de sí mismo", - "create.ponder.deployer.text_3": "Los bloques situados directamente delante no lo obstruirán", - "create.ponder.deployer.text_4": "Los desplegadores pueden:", - "create.ponder.deployer.text_5": "Colocar bloques,", - "create.ponder.deployer.text_6": "Usar objetos,", - "create.ponder.deployer.text_7": "Activar bloques,", - "create.ponder.deployer.text_8": "Cosechar bloques", - "create.ponder.deployer.text_9": "Y atacar criaturas", - - "create.ponder.deployer_contraption.header": "Usar desplegadores en artefactos animados", - "create.ponder.deployer_contraption.text_1": "Siempre que los desplegadores se muevan como parte de un artefacto animado...", - "create.ponder.deployer_contraption.text_2": "Se activan en cada ubicación visitada, utilizando objetos de los inventarios de cualquier parte del artefacto", - "create.ponder.deployer_contraption.text_3": "La ranura para filtros se puede utilizar para especificar qué objetos tirar", - - "create.ponder.deployer_modes.header": "Modos del desplegador", - "create.ponder.deployer_modes.text_1": "Por defecto, un desplegador imita la interacción del clic derecho del ratón", - "create.ponder.deployer_modes.text_2": "Usando una llave inglesa, se puede configurar para imitar un clic izquierdo en su lugar", - - "create.ponder.deployer_processing.header": "Procesar objetos mediante desplegadores", - "create.ponder.deployer_processing.text_1": "Cuando sujetan el objeto adecuado, los desplegadores pueden procesar los objetos proporcionados por debajo de ellos", - "create.ponder.deployer_processing.text_2": "Los objetos de entrada pueden soltarse o colocarse en un depósito bajo el desplegador", - "create.ponder.deployer_processing.text_3": "Cuando los objetos se disponen en una cinta mecánica...", - "create.ponder.deployer_processing.text_4": "El desplegador los retendrá y procesará automáticamente", - - "create.ponder.deployer_redstone.header": "Controlar desplegadores con redstone", - "create.ponder.deployer_redstone.text_1": "Al controlar los desplegadores con redstone, éstos no se activarán", - "create.ponder.deployer_redstone.text_2": "Antes de detenerse, el desplegador terminará cualquier ciclo iniciado", - "create.ponder.deployer_redstone.text_3": "Por lo tanto, un pulso negativo puede ser utilizado para desencadenar exactamente un ciclo de activación", - - "create.ponder.depot.header": "Usar depósitos", - "create.ponder.depot.text_1": "Los depósitos pueden servir como elementos fijos de una cinta mecánica", - "create.ponder.depot.text_2": "Haz clic derecho para colocar o eliminar manualmente objetos del mismo", - "create.ponder.depot.text_3": "Al igual que en las cintas mecánicas, pueden procesarse objetos", - "create.ponder.depot.text_4": "...así como proporcionar objetos a los brazos mecánicos", - - "create.ponder.display_board.header": "Usar pantallas de visualización", - "create.ponder.display_board.text_1": "Las pantallas de visualización son una alternativa a los carteles", - "create.ponder.display_board.text_2": "Requieren fuerza rotacional para funcionar", - "create.ponder.display_board.text_3": "Se puede mostrar texto usando etiquetas...", - "create.ponder.display_board.text_4": "...o mediante el uso de enlaces de visualización", - "create.ponder.display_board.text_5": "Se pueden aplicar tintes individualmente a cada fila de las pantallas", - "create.ponder.display_board.text_6": "Las filas se pueden reiniciar haciendo clic con una mano vacía", - - "create.ponder.display_link.header": "Configurar enlaces de visualización", - "create.ponder.display_link.text_1": "Los enlaces de visualizacion pueden usarse para obtener información dinámica", - "create.ponder.display_link.text_2": "Primero, haz clic derecho donde quieras que se muestre la información...", - "create.ponder.display_link.text_3": "...después únelo al bloque del que quieras información", - "create.ponder.display_link.text_4": "Abre la interfaz para seleccionar y configurar la información enviada", - "create.ponder.display_link.text_5": "La pantalla recibirá información del enlace", - "create.ponder.display_link.text_6": "No todos los bloques pueden actuar como una fuente de información", - "create.ponder.display_link.text_7": "Cada bloque compatible proporciona información única", - "create.ponder.display_link.text_8": "Un enlace de visualización puede funcionar con diferentes salidas", - - "create.ponder.display_link_redstone.header": "Control de redstone", - "create.ponder.display_link_redstone.text_1": "Cuando se activa con redstone, los enlaces de visualización dejarán de enviar información", - "create.ponder.display_link_redstone.text_2": "Una vez desactivado, el contador se reinicia y se vuelve a enviar información inmediatamente", - "create.ponder.display_link_redstone.text_3": "Las señales procedentes de la fuente de información no afectan al enlace", - - "create.ponder.empty_blaze_burner.header": "Usar quemadores de blaze vacíos", - "create.ponder.empty_blaze_burner.text_1": "Haz clic derecho en un blaze con el quemador vacío para capturarlo", - "create.ponder.empty_blaze_burner.text_2": "Alternativamente, los blaze pueden ser recogidos de sus spawners directamente", - "create.ponder.empty_blaze_burner.text_3": "Ahora tienes una fuente de calor ideal para varias máquinas", - "create.ponder.empty_blaze_burner.text_4": "Por motivos estéticos, los quemadores de blaze vacíos también se pueden encender con pedernal y acero", - "create.ponder.empty_blaze_burner.text_5": "La llama puede transformarse utilizando un objeto con alma", - "create.ponder.empty_blaze_burner.text_6": "Sin embargo, no son adecuados para la calefacción industrial", - - "create.ponder.encased_fluid_pipe.header": "Revestir tuberías de fluidos", - "create.ponder.encased_fluid_pipe.text_1": "El revestidor de cobre puede utilizarse para decorar las tuberías de fluidos", - "create.ponder.encased_fluid_pipe.text_2": "Además de estar ocultas, las tuberías revestidas están bloqueadas en su estado de conectividad", - "create.ponder.encased_fluid_pipe.text_3": "Ya no reaccionará a los bloques vecinos que se añadan o eliminen", - - "create.ponder.fan_direction.header": "El flujo de aire de los ventiladores revestidos", - "create.ponder.fan_direction.text_1": "Los ventiladores revestidos utilizan la fuerza rotacional para crear una corriente de aire", - "create.ponder.fan_direction.text_2": "La fuerza y la dirección del flujo dependen de la fuerza rotacional suministrada", - - "create.ponder.fan_processing.header": "Procesar objetos mediante ventiladores revestidos", - "create.ponder.fan_processing.text_1": "Al pasar por lava, el flujo de aire se calienta", - "create.ponder.fan_processing.text_2": "Los objetos capturados en la zona serán fundidos", - "create.ponder.fan_processing.text_3": "Los objetos de comida arrojados aquí serán incinerados", - "create.ponder.fan_processing.text_4": "En su lugar, se debería utilizar una instalación de ahumado, usando fuego", - "create.ponder.fan_processing.text_5": "Los flujos de aire que pasan por el agua crean una instalación de lavado", - "create.ponder.fan_processing.text_6": "Se puede hacer un nuevo e interesante procesamiento con él", - "create.ponder.fan_processing.text_7": "La velocidad del ventilador NO afecta a la velocidad de procesamiento, sólo a su rango", - "create.ponder.fan_processing.text_8": "El procesamiento del ventilador también puede aplicarse a los objetos de los depósitos y las cintas mecánicas", - - "create.ponder.fluid_pipe_flow.header": "Transportar fluidos mediante tuberías de cobre", - "create.ponder.fluid_pipe_flow.text_1": "Las tuberías de fluidos pueden conectar dos o más fuentes y objetivos de fluidos", - "create.ponder.fluid_pipe_flow.text_2": "Utilizando una llave, se puede dar a un segmento de tubo recto una ventana", - "create.ponder.fluid_pipe_flow.text_3": "Las tuberías con ventanas no se conectarán a ningún otro segmento de tubería adyacente", - "create.ponder.fluid_pipe_flow.text_4": "Accionadas por bombas mecánicas, las tuberías pueden transportar fluidos", - "create.ponder.fluid_pipe_flow.text_5": "Al principio no se extrae ningún líquido", - "create.ponder.fluid_pipe_flow.text_6": "Una vez que el flujo los conecta, los puntos finales transfieren gradualmente su contenido", - "create.ponder.fluid_pipe_flow.text_7": "Así, los bloques de tuberías nunca contienen 'físicamente' ningún fluido", - - "create.ponder.fluid_pipe_interaction.header": "Drenaje y llenado de contenedores de fluidos", - "create.ponder.fluid_pipe_interaction.text_1": "Los puntos finales de una red de tuberías pueden interactuar con una variedad de bloques", - "create.ponder.fluid_pipe_interaction.text_2": "Cualquier bloque con capacidad para almacenar fluidos puede ser llenado o vaciado", - "create.ponder.fluid_pipe_interaction.text_3": "Los bloques de origen justo delante de un extremo abierto pueden ser recogidos...", - "create.ponder.fluid_pipe_interaction.text_4": "...mientras que el derrame en espacios vacíos puede crear fuentes de fluidos", - "create.ponder.fluid_pipe_interaction.text_5": "Las tuberías también pueden extraer fluidos de un puñado de otros bloques directamente", - - "create.ponder.fluid_tank_sizes.header": "Dimensiones de un depósito de fluidos", - "create.ponder.fluid_tank_sizes.text_1": "Los depósitos de fluidos pueden combinarse para aumentar la capacidad total", - "create.ponder.fluid_tank_sizes.text_2": "Su cuadrado base puede tener hasta 3 bloques de ancho...", - "create.ponder.fluid_tank_sizes.text_3": "...y crecen en altura en más de 30 capas adicionales", - "create.ponder.fluid_tank_sizes.text_4": "Con una llave inglesa, se puede cambiar la ventana de un tanque", - - "create.ponder.fluid_tank_storage.header": "Almacenar fluidos en depósitos de fluidos", - "create.ponder.fluid_tank_storage.text_1": "Los depósitos de fluidos pueden utilizarse para almacenar grandes cantidades de fluidos", - "create.ponder.fluid_tank_storage.text_2": "Las redes de tuberías pueden empujar y arrastrar fluidos desde cualquier lado", - "create.ponder.fluid_tank_storage.text_3": "El fluido contenido puede ser medido por un Comparador", - "create.ponder.fluid_tank_storage.text_4": "Sin embargo, en el Modo Supervivencia no se pueden añadir o tomar fluidos manualmente", - "create.ponder.fluid_tank_storage.text_5": "Puede utilizar cuencas, drenadores de objetos y tuberías para vaciar o llenar objetos que contengan líquido", - - "create.ponder.funnel_compat.header": "Compatibilidades con el embudo", - "create.ponder.funnel_compat.text_1": "Los embudos deberían interactuar bien con un puñado de otros componentes", - "create.ponder.funnel_compat.text_2": "Sierras verticales", - "create.ponder.funnel_compat.text_3": "Depósitos", - "create.ponder.funnel_compat.text_4": "Drenadores de objetos", - - "create.ponder.funnel_direction.header": "Dirección de la transferencia", - "create.ponder.funnel_direction.text_1": "Colocado normalmente, extrae objetos del inventario", - "create.ponder.funnel_direction.text_2": "Colocado mientras pulsas Mayús izdo., pone objetos en el inventario", - "create.ponder.funnel_direction.text_3": "Usando una llave inglesa, el embudo puede ser volteado después de su colocación", - "create.ponder.funnel_direction.text_4": "Se aplicarán las mismas reglas para la mayoría de las orientaciones", - "create.ponder.funnel_direction.text_5": "Los embudos en las cintas mecánicas extraerán/insertarán dependiendo de su dirección de movimiento", - - "create.ponder.funnel_intro.header": "Usar embudos", - "create.ponder.funnel_intro.text_1": "Los embudos son ideales para transferir objetos desde y hacia los inventarios", - - "create.ponder.funnel_redstone.header": "Embudos alimentados con redstone", - "create.ponder.funnel_redstone.text_1": "La energía de redstone impedirá la actuación de cualquier embudo", - - "create.ponder.funnel_transfer.header": "Transferencia directa", - "create.ponder.funnel_transfer.text_1": "Los embudos no pueden transferir nunca entre inventarios cerrados directamente", - "create.ponder.funnel_transfer.text_2": "Los ductos o los ductos inteligentes podrían ser más adecuados para estos fines", - "create.ponder.funnel_transfer.text_3": "Lo mismo se aplica para el movimiento horizontal. Una cinta mecánica debería ayudar aquí", - - "create.ponder.gantry_carriage.header": "Usar carros de grúa", - "create.ponder.gantry_carriage.text_1": "Los carros de grúa pueden montarse y deslizarse a lo largo de un eje de grúa", - "create.ponder.gantry_carriage.text_2": "Las instalaciones de grúa pueden mover bloques adjuntos", - - "create.ponder.gantry_cascaded.header": "Grúas en cascada", - "create.ponder.gantry_cascaded.text_1": "Los ejes de grúas se unen a un carro de grúa sin necesidad de pegamento", - "create.ponder.gantry_cascaded.text_2": "Lo mismo se aplica a los carros de grúa en los ejes de grúas desplazados", - "create.ponder.gantry_cascaded.text_3": "Así, un sistema de grúas puede estar en cascada para cubrir múltiples ejes de movimiento", - - "create.ponder.gantry_direction.header": "Dirección del movimiento de la grúa", - "create.ponder.gantry_direction.text_1": "Los ejes de grúa pueden tener orientaciones opuestas", - "create.ponder.gantry_direction.text_2": "La dirección de movimiento de los carros de grúa depende de la orientación de sus ejes", - "create.ponder.gantry_direction.text_3": "...así como de su sentido de rotación", - "create.ponder.gantry_direction.text_4": "Se aplican las mismas reglas para la rotación propagada", - - "create.ponder.gantry_redstone.header": "Propagación de la potencia de la grúa", - "create.ponder.gantry_redstone.text_1": "Los ejes de grúa alimentados con redstone dejan de mover sus carros", - "create.ponder.gantry_redstone.text_2": "En su lugar, su fuerza rotacional se transmite al eje de salida de los carros", - - "create.ponder.gantry_shaft.header": "Usar ejes de grúa", - "create.ponder.gantry_shaft.text_1": "Los ejes de grúa forman la base de una instalación de grúas. Los carros adjuntos se moverán a lo largo de ellos", - "create.ponder.gantry_shaft.text_2": "Las instalaciones de grúas pueden mover los bloques adjuntos", - - "create.ponder.gearbox.header": "Transmitir fuerza rotacional mediante cajas de transmisión", - "create.ponder.gearbox.text_1": "Saltar entre ejes de rotación puede volverse voluminoso rápidamente", - "create.ponder.gearbox.text_2": "Una caja de transmisión es el equivalente más compacto de esta configuración", - "create.ponder.gearbox.text_3": "Los ejes giran en las direcciones reflejadas...", - "create.ponder.gearbox.text_4": "...esto quiere decir que las conexiones rectas se invierten", - - "create.ponder.gearshift.header": "Controlar la dirección rotacional mediante una caja de cambios", - "create.ponder.gearshift.text_1": "La caja de cambios transmitirá la rotación en línea recta", - "create.ponder.gearshift.text_2": "Cuando es alimentada con redstone, invierte la transmisión", - - "create.ponder.hand_crank.header": "Generar fuerza rotacional mediante manivelas", - "create.ponder.hand_crank.text_1": "Las manivelas pueden ser utilizadas para aplicar fuerza rotacional manualmente", - "create.ponder.hand_crank.text_2": "Mantén pulsado clic derecho para girar en sentido antihorario", - "create.ponder.hand_crank.text_3": "Su velocidad de transmisión es relativamente alta", - "create.ponder.hand_crank.text_4": "Mayús izdo. + clic derecho pulsado para girar en sentido horario", - - "create.ponder.hose_pulley.header": "Llenado y vaciado de fuentes mediante poleas de manguera", - "create.ponder.hose_pulley.text_1": "Las poleas para mangueras pueden utilizarse para llenar o drenar grandes masas de fluido", - "create.ponder.hose_pulley.text_2": "Con entrada cinética, se puede controlar la altura de la manguera de las poleas", - "create.ponder.hose_pulley.text_3": "La polea se retrae mientras la rotación de entrada se invierte", - "create.ponder.hose_pulley.text_4": "En el lado opuesto, se pueden conectar las tuberías", - "create.ponder.hose_pulley.text_5": "Las redes de tuberías conectadas pueden proporcionar fluido a la manguera...", - "create.ponder.hose_pulley.text_6": "...o tirar de él, vaciando la piscina en su lugar", - "create.ponder.hose_pulley.text_7": "La velocidad de llenado y vaciado de la polea depende totalmente del caudal de las redes de fluidos", - - "create.ponder.hose_pulley_infinite.header": "Llenado y drenaje pasivo de grandes masas de fluido", - "create.ponder.hose_pulley_infinite.text_1": "Al desplegar la polea de manguera en un océano lo suficientemente grande...", - "create.ponder.hose_pulley_infinite.text_2": "Proporcionará/eliminará fluidos sin afectar a la fuente", - "create.ponder.hose_pulley_infinite.text_3": "Las redes de tuberías pueden llevar fluidos de forma ilimitada desde/hacia dichas poleas", - - "create.ponder.hose_pulley_level.header": "Nivel de llenado y vaciado de las poleas de las mangueras", - "create.ponder.hose_pulley_level.text_1": "Mientras esté totalmente retraída, la polea de la manguera no puede funcionar", - "create.ponder.hose_pulley_level.text_2": "El drenaje va de arriba a abajo", - "create.ponder.hose_pulley_level.text_3": "El nivel de la superficie terminará justo debajo de donde termina la manguera", - "create.ponder.hose_pulley_level.text_4": "El llenado va de abajo a arriba", - "create.ponder.hose_pulley_level.text_5": "La piscina llena no crecerá más allá de la capa por encima del extremo de la manguera", - - "create.ponder.item_drain.header": "Vaciar contenedores de fluidos mediante drenajes de objetos", - "create.ponder.item_drain.text_1": "Los drenajes de objetos pueden extraer los fluidos de los objetos", - "create.ponder.item_drain.text_2": "Haz clic derecho para verter los fluidos de tu objeto retenido en él", - "create.ponder.item_drain.text_3": "Cuando los objetos se insertan desde lateralmente...", - "create.ponder.item_drain.text_4": "...ruedan a través, vaciando su líquido contenido", - "create.ponder.item_drain.text_5": "Las redes de tuberías pueden ahora extraer el fluido del buffer interno de los desagües", - - "create.ponder.item_vault_sizes.header": "Bóveda de objetos", - "create.ponder.item_vault_sizes.text_1": "Las bóvedas de objetos pueden combinarse para aumentar su capacidad total", - "create.ponder.item_vault_sizes.text_2": "Su base cuadrada puede ser de hasta 3 bloques de ancho...", - "create.ponder.item_vault_sizes.text_3": "...y pueden aumentar hasta 3 veces su diámetro", - - "create.ponder.item_vault_storage.header": "Almacenar objetos en las bóvedas", - "create.ponder.item_vault_storage.text_1": "Las bóvedas de objetos pueden usarse para almacenar grandes cantidades de objetos", - "create.ponder.item_vault_storage.text_2": "Sin embargo, los contenidos no pueden introducirse ni sacarse manualmente", - "create.ponder.item_vault_storage.text_3": "Cualquier componente para transferencia de objetos puede tanto introducir...", - "create.ponder.item_vault_storage.text_4": "...como sacar objetos de este contenedor", - - "create.ponder.large_cogwheel.header": "Transmitir fuerza rotacional mediante engranajes grandes", - "create.ponder.large_cogwheel.text_1": "Los engranajes grandes pueden conectarse entre sí en ángulo recto", - "create.ponder.large_cogwheel.text_2": "Ayudarán a transmitir la velocidad transportada a otros ejes de rotación.", - - "create.ponder.linear_chassis_attachment.header": "Fijar bloques mediante el chasis lineal", - "create.ponder.linear_chassis_attachment.text_1": "Las caras abiertas de un chasis lineal pueden hacerse pegajosas", - "create.ponder.linear_chassis_attachment.text_2": "Haz clic de nuevo para que se pegue el lado opuesto", - "create.ponder.linear_chassis_attachment.text_3": "Mayús izdo. + clic derecho con la mano vacía para eliminar el pegamento", - "create.ponder.linear_chassis_attachment.text_4": "Las caras pegadas del chasis lineal fijarán una línea de bloques delante de él", - "create.ponder.linear_chassis_attachment.text_5": "Utilizando una llave inglesa, se puede especificar un rango preciso", - "create.ponder.linear_chassis_attachment.text_6": "Manteniendo pulsada la tecla [Ctrl] y usando la rueda central del ratón, se ajusta el rango de todos los bloques de chasis adjuntos", - "create.ponder.linear_chassis_attachment.text_7": "Para fijar los bloques a cualquier otro lado es necesario utilizar pegamento", - "create.ponder.linear_chassis_attachment.text_8": "Utilizando esta mecánica, las estructuras de cualquier forma pueden ser parte del artefacto animado", - - "create.ponder.linear_chassis_group.header": "Mover chasis lineales en grupos", - "create.ponder.linear_chassis_group.text_1": "Los chasis lineales se conectan a los bloques de chasis idénticos que se encuentren a su lado", - "create.ponder.linear_chassis_group.text_2": "Cuando uno es movido por un artefacto animado, los otros son arrastrados con él", - "create.ponder.linear_chassis_group.text_3": "Los chasis de otro tipo u orientados en otra dirección no se fijan", - - "create.ponder.mechanical_arm.header": "Configurar los brazos mecánicos", - "create.ponder.mechanical_arm.text_1": "A los brazos mecánicos hay que asignarles sus entradas y salidas antes de colocarlos", - "create.ponder.mechanical_arm.text_2": "Clic derecho en los inventarios mientras mantiene el brazo mecánico para asignarlos como objetivos", - "create.ponder.mechanical_arm.text_3": "Clic derecho denuevo para alternar entre la entrada (azul) y la salida (naranja)", - "create.ponder.mechanical_arm.text_4": "Clic izquierdo en los componentes para eliminar su selección", - "create.ponder.mechanical_arm.text_5": "Una vez colocado, el brazo mecánico apuntará a los bloques seleccionados previamente", - "create.ponder.mechanical_arm.text_6": "Pueden tener cualquier cantidad de entradas y salidas dentro de su rango", - "create.ponder.mechanical_arm.text_7": "Sin embargo, no se puede interactuar directamente con todos los tipos de inventario", - "create.ponder.mechanical_arm.text_8": "Los embudos y depósitos pueden ayudar a salvar esa distancia", - - "create.ponder.mechanical_arm_filtering.header": "Filtrar salidas del brazo mecánico", - "create.ponder.mechanical_arm_filtering.text_1": "Entradas", - "create.ponder.mechanical_arm_filtering.text_2": "Salidas", - "create.ponder.mechanical_arm_filtering.text_3": "A veces es conveniente restringir los objetivos del brazo mecánico haciendo coincidir un filtro", - "create.ponder.mechanical_arm_filtering.text_4": "Por sí mismos no ofrecen ninguna opción de filtrado", - "create.ponder.mechanical_arm_filtering.text_5": "Sin embargo, los embudos de latón como objetivos comunican su propio filtro al brazo", - "create.ponder.mechanical_arm_filtering.text_6": "El brazo mecánico es lo suficientemente inteligente como para no recoger objetos que no podría distribuir", - - "create.ponder.mechanical_arm_modes.header": "Modos de distribución del brazo mecánico", - "create.ponder.mechanical_arm_modes.text_1": "Entradas", - "create.ponder.mechanical_arm_modes.text_2": "Salidas", - "create.ponder.mechanical_arm_modes.text_3": "Siempre que un brazo tenga que elegir entre varias salidas válidas...", - "create.ponder.mechanical_arm_modes.text_4": "...funcionará según su configuración", - "create.ponder.mechanical_arm_modes.text_5": "Usando la rueda del ratón con una llave inglesa te permitirá configurarlo", - "create.ponder.mechanical_arm_modes.text_6": "El modo Round Robin simplemente hace un ciclo a través de todas las salidas que están disponibles", - "create.ponder.mechanical_arm_modes.text_7": "Si una salida no puede admitir más objetos, se omitirá", - "create.ponder.mechanical_arm_modes.text_8": "El modo Round Robin forzado nunca omitirá las salidas, sino que esperará a que estén libres", - "create.ponder.mechanical_arm_modes.text_9": "Preferir el primero da prioridad a las salidas seleccionadas anteriormente al configurar este brazo", - - "create.ponder.mechanical_arm_redstone.header": "Controlar brazos mecánicos con redstone", - "create.ponder.mechanical_arm_redstone.text_1": "Cuando se alimentan con redstone, los brazos mecánicos no se activan", - "create.ponder.mechanical_arm_redstone.text_2": "Antes de detenerse, terminará los ciclos iniciados", - "create.ponder.mechanical_arm_redstone.text_3": "Así, un pulso negativo puede utilizarse para activar exactamente un ciclo de activación", - - "create.ponder.mechanical_bearing.header": "Mover estructuras mediante el rodamiento mecánico", - "create.ponder.mechanical_bearing.text_1": "Los rodamientos mecánicos se fijan al bloque que tienen delante", - "create.ponder.mechanical_bearing.text_2": "Al recibir fuerza rotacional, la ensamblará en un artefacto estacionario", - - "create.ponder.mechanical_crafter.header": "Configurar ensambladores mecánicos", - "create.ponder.mechanical_crafter.text_1": "Se puede utilizar una serie de ensambladores mecánicos para automatizar cualquier receta de elaboración.", - "create.ponder.mechanical_crafter.text_2": "Usando una llave inglesa, puedes establecer los caminos de los ensambladores ", - "create.ponder.mechanical_crafter.text_3": "Para que la configuración sea válida, todos los caminos tienen que converger en una salida, en cualquiera de los lados", - "create.ponder.mechanical_crafter.text_4": "Los puertos de salida de objetos se colocarán en un inventario a la salida", - "create.ponder.mechanical_crafter.text_5": "Los ensambladores mecánicos requieren fuerza rotacional para funcionar", - "create.ponder.mechanical_crafter.text_6": "Haga clic derecho en la parte delantera para insertar objetos manualmente", - "create.ponder.mechanical_crafter.text_7": "Una vez que cada ranura de una ruta contenga un objeto, comenzará el proceso de elaboración", - "create.ponder.mechanical_crafter.text_8": "Para las recetas que no ocupen totalmente la instalación del ensamblador, se puede forzar el arranque utilizando un pulso de redstone", - - "create.ponder.mechanical_crafter_connect.header": "Conectar inventarios a los ensambladores mecánicos", - "create.ponder.mechanical_crafter_connect.text_1": "Los objetos pueden ser insertados a los ensambladores mecánicos automáticamente", - "create.ponder.mechanical_crafter_connect.text_2": "Utilizando la llave inglesa a sus espaldas, las entradas pueden combinarse", - "create.ponder.mechanical_crafter_connect.text_3": "Ahora se puede acceder a todos los ensambladores mecánicos conectados por la misma ubicación de entrada", - - "create.ponder.mechanical_crafter_covers.header": "Cubrir las ranuras de los ensambladores mecánicos", - "create.ponder.mechanical_crafter_covers.text_1": "Algunas recetas requerirán ensambladores mecánicos adicionales para salvar las brechas en el camino", - "create.ponder.mechanical_crafter_covers.text_2": "Utilizando las tapas de ranuras del ensamblador mecánico, pueden actuar como una ranura vacía a su disposición", - "create.ponder.mechanical_crafter_covers.text_3": "Las entradas compartidas creadas con la llave inglesa en la parte posterior también pueden llegar a través de los ensambladores revestidos", - - "create.ponder.mechanical_drill.header": "Romper bloques con el taladro mecánico", - "create.ponder.mechanical_drill.text_1": "Cuando se le aplica fuerza rotacional, el taladro mecánico rompe los bloques que tiene delante.", - "create.ponder.mechanical_drill.text_2": "Su velocidad de trabajo depende de la fuerza rotacional suministrada", - - "create.ponder.mechanical_drill_contraption.header": "Usar taladros mecánicos en artefactos animados", - "create.ponder.mechanical_drill_contraption.text_1": "Siempre que los taladros mecánicos se muevan como parte de un artefacto animado...", - "create.ponder.mechanical_drill_contraption.text_2": "...romperán los bloques por los que artefacto los hace pasar", - - "create.ponder.mechanical_harvester.header": "Utilizar cosechadoras mecánicas en artefactos animados", - "create.ponder.mechanical_harvester.text_1": "Siempre que las cosechadoras mecánicas se muevan como parte de un artefacto animado...", - "create.ponder.mechanical_harvester.text_2": "...recogerán y repondrán los cultivos maduros en su camino", - - "create.ponder.mechanical_mixer.header": "Procesar objetos con la mezcladora mecánica", - "create.ponder.mechanical_mixer.text_1": "Con una mezcladora mecánica y una cuenca, se pueden automatizar algunas recetas", - "create.ponder.mechanical_mixer.text_2": "Las recetas disponibles incluyen cualquier receta de elaboración amorfa, además de un par de recetas adicionales", - "create.ponder.mechanical_mixer.text_3": "Algunas de esas recetas pueden requerir el calor de un quemador de blaze", - "create.ponder.mechanical_mixer.text_4": "La ranura para filtros se puede utilizar en caso de que dos recetas sean conflictivas.", - - "create.ponder.mechanical_piston.header": "Mover estructuras mediante pistones mecánicos", - "create.ponder.mechanical_piston.text_1": "Los pistones mecánicos pueden mover los bloques que tienen delante", - "create.ponder.mechanical_piston.text_2": "La velocidad y la dirección del movimiento dependen de la fuerza rotacional suministrada", - "create.ponder.mechanical_piston.text_3": "Los pistones mecánicos pegajosos pueden tirar de los bloques unidos hacia atrás", - - "create.ponder.mechanical_piston_modes.header": "Modos de movimiento del pistón mecánico", - "create.ponder.mechanical_piston_modes.text_1": "Cuando los pistones mecánicos dejan de moverse, la estructura movida vuelve a los bloques", - "create.ponder.mechanical_piston_modes.text_2": "Puede configurarse para que no vuelva nunca a los bloques sólidos, o sólo en la ubicación en la que comenzó", - - "create.ponder.mechanical_plough.header": "Utilizar arados mecánicos en los artefactos animados", - "create.ponder.mechanical_plough.text_1": "Cuando los arados mecánicos se mueven como parte de un artefacto animado...", - "create.ponder.mechanical_plough.text_2": "...romperán los bloques con una hitbox menor a la de un bloque completo", - "create.ponder.mechanical_plough.text_3": "Además, pueden crear tierras de cultivo", - "create.ponder.mechanical_plough.text_4": "...también pueden lanzar entidades sin dañarlas", - - "create.ponder.mechanical_press.header": "Procesar objetos con la prensa mecánica", - "create.ponder.mechanical_press.text_1": "La prensa mecánica puede procesar los objetos proporcionados por debajo de ella", - "create.ponder.mechanical_press.text_2": "Los objetos de entrada pueden soltarse o colocarse en un depósito bajo la prensa", - "create.ponder.mechanical_press.text_3": "Cuando los objetos se proporcionan en una cinta mecánica...", - "create.ponder.mechanical_press.text_4": "...la prensa mecánica los retendrá y procesará automáticamente", - - "create.ponder.mechanical_press_compacting.header": "Compactar objetos con la prensa mecánica", - "create.ponder.mechanical_press_compacting.text_1": "Al presionar los objetos que se encuentran en una cuenca, éstos se compactan.", - "create.ponder.mechanical_press_compacting.text_2": "La compactación incluye cualquier receta de elaboración de 2x2 o 3x3 rellena, además de un par extra", - "create.ponder.mechanical_press_compacting.text_3": "Algunas de esas recetas pueden requerir el calor de un quemador de blaze", - "create.ponder.mechanical_press_compacting.text_4": "La ranura para filtros se puede utilizar en caso de que dos recetas sean conflictivas.", - - "create.ponder.mechanical_pump_flow.header": "Transportar fluidos mediante bombas mecánicas", - "create.ponder.mechanical_pump_flow.text_1": "Las bombas mecánicas gobiernan el flujo de sus redes de tuberías anexas", - "create.ponder.mechanical_pump_flow.text_2": "Cuando están alimentadas, su flecha indica la dirección del flujo", - "create.ponder.mechanical_pump_flow.text_3": "La red de atrás está ahora tirando de fluidos...", - "create.ponder.mechanical_pump_flow.text_4": "...mientras la red de enfrente la transfiere hacia el exterior", - "create.ponder.mechanical_pump_flow.text_5": "Al invertir la rotación de la entrada se invierte el sentido del flujo", - "create.ponder.mechanical_pump_flow.text_6": "Utilice una llave inglesa para invertir la orientación de las bombas manualmente", - - "create.ponder.mechanical_pump_speed.header": "Rendimiento de las bombas mecánicas", - "create.ponder.mechanical_pump_speed.text_1": "Independientemente de la velocidad, las bombas mecánicas afectan a las tuberías conectadas hasta 16 bloques de distancia", - "create.ponder.mechanical_pump_speed.text_2": "Acelerar la rotación de entrada cambia la velocidad de propagación del flujo...", - "create.ponder.mechanical_pump_speed.text_3": "...así como la rapidez con la que se transfieren los fluidos", - "create.ponder.mechanical_pump_speed.text_4": "Las bombas pueden combinar sus rendimientos en redes de tuberías compartidas", - "create.ponder.mechanical_pump_speed.text_5": "Alternar su orientación puede ayudar a alinear sus direcciones de flujo", - - "create.ponder.mechanical_saw_breaker.header": "Cortar árboles con la sierra mecánica", - "create.ponder.mechanical_saw_breaker.text_1": "Cuando se le da una fuerza rotacional, la sierra mecánica cortará los árboles que estén directamente frente a ella", - "create.ponder.mechanical_saw_breaker.text_2": "Para poder cortar el árbol por completo, la sierra tiene que romper el último bloque que lo une al suelo", - - "create.ponder.mechanical_saw_contraption.header": "Utilizar sierras mecánicas en artefactos animados", - "create.ponder.mechanical_saw_contraption.text_1": "Cuando las sierras mecánicas se mueven como parte de un artefactos animado...", - "create.ponder.mechanical_saw_contraption.text_2": "...cortarán cualquier árbol con el se topen", - - "create.ponder.mechanical_saw_processing.header": "Procesar objetos en la sierra mecánica", - "create.ponder.mechanical_saw_processing.text_1": "Las sierras mecánicas orientadas hacia arriba pueden procesar una variedad de objetos", - "create.ponder.mechanical_saw_processing.text_2": "El objeto procesado siempre se mueve en contra de la fuerza rotacional de la sierra", - "create.ponder.mechanical_saw_processing.text_3": "Las sierras mecánicas pueden trabajar en línea con las cinta mecánicas", - "create.ponder.mechanical_saw_processing.text_4": "Cuando un ingrediente tiene varios resultados posibles, la ranura para filtros puede especificarlo", - "create.ponder.mechanical_saw_processing.text_5": "Sin filtro, al contrario, la sierra mecánica pasaría por todos los resultados", - - "create.ponder.millstone.header": "Procesar objetos en la piedra de molino", - "create.ponder.millstone.text_1": "Las piedras de molino procesan los objetos mediante la molienda", - "create.ponder.millstone.text_2": "Se pueden accionar lateralmente mediante engranajes...", - "create.ponder.millstone.text_3": "... y tirar o insertar objetos en la parte superior", - "create.ponder.millstone.text_4": "Después de un tiempo, el resultado se puede obtener usando el clic derecho del ratón", - "create.ponder.millstone.text_5": "Las salidas también pueden extraerse mediante la automatización", - - "create.ponder.nixie_tube.header": "Usar los tubos Nixie", - "create.ponder.nixie_tube.text_1": "Cuando son alimentados con redstone, los tubos nixie mostrarán la fuerza de las señales de redstone", - "create.ponder.nixie_tube.text_2": "Con las etiquetas editadas en un yunque, pueden mostar un texto personalizado", - "create.ponder.nixie_tube.text_3": "Haga clic derecho con un tinte para cambiar su color de visualización", - - "create.ponder.piston_pole.header": "Pértigas de extensión de pistones", - "create.ponder.piston_pole.text_1": "Sin las pértigas de extensión unidas, un pistón mecánico no puede moverse", - "create.ponder.piston_pole.text_2": "La longitud de la pértiga añadida en su parte posterior determina el rango de alcance", - - "create.ponder.portable_fluid_interface.header": "Interfaz de fluidos portátil", - "create.ponder.portable_fluid_interface.text_1": "No se puede acceder a los depósitos de fluidos de los artefactos en movimiento por ninguna tubería", - "create.ponder.portable_fluid_interface.text_2": "Este componente puede interactuar con los depósitos de fluidos sin necesidad de detener el artefacto", - "create.ponder.portable_fluid_interface.text_3": "Coloca una segunda con un espacio de 1 o 2 bloques entre ellas", - "create.ponder.portable_fluid_interface.text_4": "Cada vez que pasen por delante de la otra, entablarán una conexión", - "create.ponder.portable_fluid_interface.text_5": "Mientras esté activada, la interfaz estacionaria representará TODOS los tanques del artefacto", - "create.ponder.portable_fluid_interface.text_6": "Ahora se puede introducir el fluido...", - "create.ponder.portable_fluid_interface.text_7": "...o extraerlo del artefacto", - "create.ponder.portable_fluid_interface.text_8": "Cuando no se intercambien contenidos durante un tiempo, el artefacto seguirá su camino", - - "create.ponder.portable_storage_interface.header": "Interfaz de almacenamiento portátil", - "create.ponder.portable_storage_interface.text_1": "Los jugadores no pueden acceder a los inventarios de los artefactos en movimiento.", - "create.ponder.portable_storage_interface.text_2": "Este componente puede interactuar con el almacenamiento sin necesidad de detener el artefacto.", - "create.ponder.portable_storage_interface.text_3": "Coloca una segunda unidad con un espacio de 1 o 2 bloques entre ellas", - "create.ponder.portable_storage_interface.text_4": "Cada vez que pasen por delante del otro, entablarán una conexión", - "create.ponder.portable_storage_interface.text_5": "Mientras esté conectada, la interfaz fija representará TODOS los inventarios del artefacto", - "create.ponder.portable_storage_interface.text_6": "Ahora pueden insertarse objetos...", - "create.ponder.portable_storage_interface.text_7": "...o extraerse", - "create.ponder.portable_storage_interface.text_8": "Cuando no se hayan intercambiado objetos durante un tiempo, el artefacto seguirá su camino", - - "create.ponder.portable_storage_interface_redstone.header": "Interfaz de almacenamiento portátil controlada por redstone", - "create.ponder.portable_storage_interface_redstone.text_1": "La energía de redstone impedirá que las interfaces de almacenamiento portátil se conecten", - - "create.ponder.powered_latch.header": "Controlar señales mediante la palanca motorizada", - "create.ponder.powered_latch.text_1": "Las palancas motorizadas son palancas controlables por redstone", - "create.ponder.powered_latch.text_2": "Las señales en la parte trasera la encienden", - "create.ponder.powered_latch.text_3": "Las señales sobre un lateral la vuelven a apagar", - "create.ponder.powered_latch.text_4": "Las palancas motorizadas también se pueden accionar manualmente", - - "create.ponder.powered_toggle_latch.header": "Controlar señales mediante la palanca de cierre motorizada", - "create.ponder.powered_toggle_latch.text_1": "Las palancas de cierre motorizadas son palancas controlables por redstone", - "create.ponder.powered_toggle_latch.text_2": "Las señales en la parte trasera cambiarán su estado...", - "create.ponder.powered_toggle_latch.text_3": "...encender y apagar", - "create.ponder.powered_toggle_latch.text_4": "Las palancas de cierre motorizadas también se pueden accionar manualmente", - - "create.ponder.pulse_extender.header": "Controlar señales usando extensores de pulso", - "create.ponder.pulse_extender.text_1": "Los extensores de pulso pueden alargar una señal", - "create.ponder.pulse_extender.text_2": "Se activan después de un breve retraso...", - "create.ponder.pulse_extender.text_3": "...y tienen un enfriamiento igual a la cantidad configurada", - "create.ponder.pulse_extender.text_4": "Utilizando la rueda del ratón, el enfriamiento se puede configurar", - "create.ponder.pulse_extender.text_5": "La duración configurada puede alcanzar hasta los 30 minutos", - - "create.ponder.pulse_repeater.header": "Controlar señales mediante repetidores de pulsos", - "create.ponder.pulse_repeater.text_1": "Los repetidores de pulsos acortan cualquier señal de redstone a un solo pulso", - "create.ponder.pulse_repeater.text_2": "Utilizando la rueda del ratón, el tiempo de carga se puede configurar", - "create.ponder.pulse_repeater.text_3": "Los retrasos configurados pueden alcanzar hasta los 30 minutos", - - "create.ponder.radial_chassis.header": "Fijar bloques mediante chasis radiales", - "create.ponder.radial_chassis.text_1": "Los chasis radiales se conectan a bloques de chasis idénticos en una fila", - "create.ponder.radial_chassis.text_2": "Cuando uno es movido por un artefacto, los otros son arrastrados con él", - "create.ponder.radial_chassis.text_3": "Las caras laterales de un chasis radial pueden hacerse adhesivas", - "create.ponder.radial_chassis.text_4": "Haga clic de nuevo para que todos los demás lados sean pegajosos", - "create.ponder.radial_chassis.text_5": "Mayús izdo. + clic derecho con la mano vacía para eliminar el pegamento", - "create.ponder.radial_chassis.text_6": "Cada vez que un bloque está junto a una cara pegajosa...", - "create.ponder.radial_chassis.text_7": "...adjuntará todos los bloques alcanzables dentro de un radio en esa capa", - "create.ponder.radial_chassis.text_8": "Con una llave inglesa y usando la rueda de desplazamiento del ratón se puede especificar un radio preciso", - "create.ponder.radial_chassis.text_9": "Los bloques no alcanzables por ninguna cara adhesiva no se fijarán", - - "create.ponder.redstone_contact.header": "Contactos de redstone", - "create.ponder.redstone_contact.text_1": "Los contactos de redstone enfrentados emitirán una señal de redstone", - "create.ponder.redstone_contact.text_2": "Esto sigue siendo válido cuando uno de ellos forma parte de un artefacto en movimiento", - - "create.ponder.redstone_link.header": "Usar los enlaces de redstone", - "create.ponder.redstone_link.text_1": "Los enlaces de redstone pueden transmitir señales redstone de forma inalámbrica", - "create.ponder.redstone_link.text_2": "Mayús izdo. + clic derecho para cambiar el modo de recepción", - "create.ponder.redstone_link.text_3": "Un simple clic derecho con una llave inglesa puede hacer lo mismo", - "create.ponder.redstone_link.text_4": "Los receptores emiten la potencia de redstone de los transmisores en 128 bloques", - "create.ponder.redstone_link.text_5": "Colocando objetos en las dos ranuras puede especificar una frecuencia", - "create.ponder.redstone_link.text_6": "Sólo se comunicarán los enlaces con frecuencias coincidentes", - - "create.ponder.rope_pulley.header": "Mover estructuras con poleas de cuerda", - "create.ponder.rope_pulley.text_1": "Las poleas de cuerda pueden mover los bloques verticalmente cuando se les aplica una fuerza rotacional", - "create.ponder.rope_pulley.text_2": "La dirección y la velocidad del movimiento dependen de la fuerza rotacional suministrada", - - "create.ponder.rope_pulley_attachment.header": "Mover poleas como parte de un artefacto", - "create.ponder.rope_pulley_attachment.text_1": "Siempre que las poleas de cuerda sean movidas por un artefacto...", - "create.ponder.rope_pulley_attachment.text_2": "...su estructura adjunta será arrastrada con ella", - "create.ponder.rope_pulley_attachment.text_3": "Tenga en cuenta que las poleas de cuerda sólo se mueven cuando están paradas", - - "create.ponder.rope_pulley_modes.header": "Modos de movimiento de la polea de cuerda", - "create.ponder.rope_pulley_modes.text_1": "Cuando las poleas de cuerda dejan de moverse, la estructura movida vuelve a los bloques", - "create.ponder.rope_pulley_modes.text_2": "Puede configurarse para que no vuelva nunca a los bloques sólidos, o sólo en la ubicación en la que comenzó", - - "create.ponder.rose_quartz_lamp.header": "Lámparas de cuarzo rosado", - "create.ponder.rose_quartz_lamp.text_1": "Las lámparas de cuarzo rosado se activan con una señal de redstone", - "create.ponder.rose_quartz_lamp.text_2": "Continuarán emitiendo una señal de redstone", - "create.ponder.rose_quartz_lamp.text_3": "Cuando hay varias lámparas juntas...", - "create.ponder.rose_quartz_lamp.text_4": "...activar una lámpara hará que todas las demás se desactiven", - "create.ponder.rose_quartz_lamp.text_5": "Los comparadores emitirán una señal dependiendo de la distancia a la lámpara que está activada", - "create.ponder.rose_quartz_lamp.text_6": "Las lámparas también se pueden manejar manualmente con una llave inglesa", - - "create.ponder.rotation_speed_controller.header": "Usar el controlador de velocidad rotacional", - "create.ponder.rotation_speed_controller.text_1": "Los controladores de velocidad rotacional transmiten la rotación de su eje a un engranaje grande situado encima.", - "create.ponder.rotation_speed_controller.text_2": "Utilizando la rueda de desplazamiento del ratón, puede configurarse la velocidad rotacional", - - "create.ponder.sail.header": "Montar molinos de viento usando velas", - "create.ponder.sail.text_1": "Las velas son bloques muy útiles para crear molinos de viento", - "create.ponder.sail.text_2": "Se fijarán a los bloques y entre sí sin necesidad de pegamento o bloques de chasis", - "create.ponder.sail.text_3": "Clic derecho con un tinte para pintarlas", - "create.ponder.sail.text_4": "Clic derecho con una tijera para volver a convertirlas en marcos", - - "create.ponder.sail_frame.header": "Montar molinos de viento con marcos de vela", - "create.ponder.sail_frame.text_1": "Los marcos de vela son prácticos bloques para crear molinos de viento", - "create.ponder.sail_frame.text_2": "Se fijarán a los bloques y entre sí sin necesidad de pegamento o bloques de chasis", - - "create.ponder.sequenced_gearshift.header": "Controlar la velocidad de rotación mediante la caja de cambios secuenciales", - "create.ponder.sequenced_gearshift.text_1": "La caja de cambios secuencial retransmite la rotación siguiendo una lista cronometrada de instrucciones", - "create.ponder.sequenced_gearshift.text_2": "Haga clic con el botón derecho para abrir la interfaz de configuración", - "create.ponder.sequenced_gearshift.text_3": "Al recibir una señal de redstone, comenzará a ejecutar su secuencia configurada", - "create.ponder.sequenced_gearshift.text_4": "Una vez terminado, espera la siguiente señal de redstone y vuelve a empezar", - "create.ponder.sequenced_gearshift.text_5": "Se puede utilizar un comparador de redstone para leer el progreso actual", - - "create.ponder.shaft.header": "Transmitir fuerza rotacional mediante ejes", - "create.ponder.shaft.text_1": "Los ejes transmiten la rotación en línea recta.", - - "create.ponder.shaft_casing.header": "Ejes revestidos", - "create.ponder.shaft_casing.text_1": "Puedes utilizar el revestidor de latón o de andesita para decorar tus ejes", - - "create.ponder.smart_chute.header": "Filtrar objetos mediante ductos inteligentes", - "create.ponder.smart_chute.text_1": "Los ductos inteligentes son ductos verticales con control adicional", - "create.ponder.smart_chute.text_2": "Los objetos en la ranura para filtros especifican lo que pueden extraer y transferir exactamente", - "create.ponder.smart_chute.text_3": "Usa la rueda del ratón para especificar el tamaño de la pila extraída", - "create.ponder.smart_chute.text_4": "La energía de redstone impedirá que funcionen.", - - "create.ponder.smart_pipe.header": "Controlar el flujo de fluidos mediante tuberías inteligentes", - "create.ponder.smart_pipe.text_1": "Las tuberías inteligentes pueden ayudar a controlar los flujos por tipo de fluido", - "create.ponder.smart_pipe.text_2": "Cuando se colocan directamente en la fuente, pueden especificar el tipo de fluido a extraer", - "create.ponder.smart_pipe.text_3": "Simplemente haga clic derecho en su ranura de filtro con cualquier objeto que contenga el fluido deseado", - "create.ponder.smart_pipe.text_4": "Cuando se colocan detrás de una red de tuberías, las tuberías inteligentes sólo dejan que los fluidos coincidentes continúen", - - "create.ponder.speedometer.header": "Controlar la información cinética mediante el velocímetro", - "create.ponder.speedometer.text_1": "El velocímetro muestra la velocidad actual de los componentes conectados", - "create.ponder.speedometer.text_2": "Cuando se usan las gafas del ingeniero, el jugador puede obtener información más detallada del medidor", - "create.ponder.speedometer.text_3": "Los comparadores pueden emitir señales analógicas de redstone en relación con las mediciones del velocímetro", - - "create.ponder.spout_filling.header": "Llenar objetos con un surtidor", - "create.ponder.spout_filling.text_1": "El surtidor puede llenar los objetos capaces de retener fluidos que se encuentren debajo de él", - "create.ponder.spout_filling.text_2": "No se puede acceder manualmente al contenido de un surtidor", - "create.ponder.spout_filling.text_3": "En su lugar, se pueden utilizar tuberías para suministrarle fluidos", - "create.ponder.spout_filling.text_4": "Los objetos de entrada pueden colocarse en un depósito bajo el surtidor", - "create.ponder.spout_filling.text_5": "Cuando los objetos se proporcionan en una cinta...", - "create.ponder.spout_filling.text_6": "El surtidor los retendrá y procesará automáticamente", - - "create.ponder.stabilized_bearings.header": "Estabilizar artefactos estacionarios", - "create.ponder.stabilized_bearings.text_1": "Siempre que los rodamientos mecánicos formen parte de una estructura móvil...", - "create.ponder.stabilized_bearings.text_2": "...intentarán mantenerse derechos", - "create.ponder.stabilized_bearings.text_3": "Una vez más, el rodamiento se unirá al bloque de enfrente", - "create.ponder.stabilized_bearings.text_4": "Como resultado, todo el sub-artefacto se mantendrá en posición vertical", - - "create.ponder.steam_engine.header": "Instalación de motores de vapor", - "create.ponder.steam_engine.text_1": "Los motores de vapor se pueden colocar en depósitos de fluidos", - "create.ponder.steam_engine.text_10": "Nivel 4", - "create.ponder.steam_engine.text_11": "4 Motores", - "create.ponder.steam_engine.text_12": "Nivel 8", - "create.ponder.steam_engine.text_13": "8 Motores", - "create.ponder.steam_engine.text_2": "Haciendo clic en el motor con un eje se crea una salida cinética", - "create.ponder.steam_engine.text_3": "Con suficiente calor, agua y espacio de la caldera...", - "create.ponder.steam_engine.text_4": "...general fuerza rotacional", - "create.ponder.steam_engine.text_5": "Como mínimo se necesitan 4 depósitos de fluidos", - "create.ponder.steam_engine.text_6": "Con la ayuda de quemadores de blaze, la potencia resultante se puede incrementar", - "create.ponder.steam_engine.text_7": "Una mayor potencia requiere más agua, tamaño y calor", - "create.ponder.steam_engine.text_8": "La potencia de la caldera se puede inspeccionar con las gafas del ingeniero", - "create.ponder.steam_engine.text_9": "Con cada nivel de potencia que se añada, un motor adicional puede estar funcionando a su capacidad máxima", - - "create.ponder.steam_whistle.header": "Instalar silbatos de vapor", - "create.ponder.steam_whistle.text_1": "Los silbatos de vapor pueden colocarse en depósitos de fluidos", - "create.ponder.steam_whistle.text_2": "Si el depósito recibe suficiente calor...", - "create.ponder.steam_whistle.text_3": "...el silbato tocará una nota cuando sea activado", - "create.ponder.steam_whistle.text_4": "Usa el objeto del silbato en el bloque para bajar su tono", - "create.ponder.steam_whistle.text_5": "Cambia entre 3 octavas diferentes usando la llave inglesa", - "create.ponder.steam_whistle.text_6": "Las gafas del ingeniero te pueden ayudar a conocer el tono del silbato", - - "create.ponder.sticker.header": "Fijar bloques con pegatinas", - "create.ponder.sticker.text_1": "Las pegatinas son ideales para la fijación controlada por redstone de bloques", - "create.ponder.sticker.text_2": "Al recibir una señal, cambiará su estado", - "create.ponder.sticker.text_3": "Si ahora se mueve en un artefacto animado, el bloque se moverá con él", - "create.ponder.sticker.text_4": "Si se vuelve a activar, el bloque dejará de estar fijado", - - "create.ponder.stressometer.header": "Supervisar la información cinética con el estresómetro", - "create.ponder.stressometer.text_1": "El estresómetro muestra la capacidad de estrés actual de la red cinética conectada", - "create.ponder.stressometer.text_2": "Cuando se usan las gafas del ingeniero, el jugador puede obtener información más detallada del medidor", - "create.ponder.stressometer.text_3": "Los comparadores pueden emitir señales analógicas de redstone en relación con las mediciones del estresómetro", - - "create.ponder.super_glue.header": "Fijar bloques con pegamento", - "create.ponder.super_glue.text_1": "Se puede utilizar pegamento entre dos bloques cualquiera", - "create.ponder.super_glue.text_2": "Los bloques fijados se moverán juntos cuando se ensamblen en un artefacto", - "create.ponder.super_glue.text_3": "Cada vez que el pegamento es sostenido en la mano secundaria...", - "create.ponder.super_glue.text_4": "...los bloques añadidos se pegarán a la cara en la que fueron colocados automáticamente", - "create.ponder.super_glue.text_5": "El pegamento se puede quitar con un clic izquierdo", - "create.ponder.super_glue.text_6": "Bloques que cuelgan de otros normalmente no requieren pegamento", - - "create.ponder.track_chunks.header": "Atravesando chunks descargados", - "create.ponder.track_chunks.text_1": "Las vías siguen funcionando fuera de chunks cargados", - "create.ponder.track_chunks.text_2": "Los trenes atraviesan partes inactivas del mundo sin problemas", - "create.ponder.track_chunks.text_3": "Seguirán parándose en estaciones o en señales rojas", - "create.ponder.track_chunks.text_4": "Sin embargo, taladros y demás máquinas a bordo no estarán operativas", - "create.ponder.track_chunks.text_5": "Una vez está cerca de un jugador, el tren reaparecerá", - - "create.ponder.track_observer.header": "Detectar trenes", - "create.ponder.track_observer.text_1": "Selecciona una vía de tren y coloca el observador cerca", - "create.ponder.track_observer.text_2": "El observador detectará cualquier tren que pase por la marca", - "create.ponder.track_observer.text_3": "Los observadores pueden filtrar trenes con cierta mercancía", - - "create.ponder.track_placement.header": "Colocar vías de tren", - "create.ponder.track_placement.text_1": "Un nuevo tipo de raíl diseñado para trenes", - "create.ponder.track_placement.text_2": "Para colocar filas de vías en grandes cantidades, haz clic en una vía existente", - "create.ponder.track_placement.text_3": "Después coloca o selecciona una segunda vía", - "create.ponder.track_placement.text_4": "Las vías también se pueden colocar a modo de curvas o cuestas", - "create.ponder.track_placement.text_5": "Cuando se conectan, las vías intentarán hacer cada curva de igual tamaño", - "create.ponder.track_placement.text_6": "Manteniendo [Ctrl] mientras se conectan...", - "create.ponder.track_placement.text_7": "...creará adecuadamente la curva más larga posible", - "create.ponder.track_placement.text_8": "Los materiales en la mano secundaria serán enlosados debajo de las vías automáticamente", - - "create.ponder.track_portal.header": "Vías y el Nether", - "create.ponder.track_portal.text_1": "Las vías que se colocan mirando hacia un portal del nether...", - "create.ponder.track_portal.text_2": "...intentarán crear una vía enlazada al otro lado", - "create.ponder.track_portal.text_3": "Los trenes en este tipo de vías son ahora capaces de viajar entre dimensiones", - - "create.ponder.train_assembly.header": "Ensamblar trenes", - "create.ponder.train_assembly.text_1": "Selecciona una vía de tren y coloca la estación cerca", - "create.ponder.train_assembly.text_10": "Todo tren necesita controles de tren a bordo", - "create.ponder.train_assembly.text_11": "Opcionalmente puedes añadir otros controles de tren para poder ir en ambas direcciones", - "create.ponder.train_assembly.text_12": "Abre la interfaz de la estación y confirma el proceso de ensamblaje", - "create.ponder.train_assembly.text_13": "Los trenes solo pueden desensamblarse de nuevo en bloques en estaciones", - "create.ponder.train_assembly.text_14": "Cuando se usa sobre una estación, los mapas añaden un marcador en esa posición", - "create.ponder.train_assembly.text_15": "Los trenes ensamblados pueden reubicarse a vías cercanas usando la llave inglesa", - "create.ponder.train_assembly.text_2": "Las estaciones son los puntos de referencia de tu sistema de vías", - "create.ponder.train_assembly.text_3": "Para crear un nuevo tren, abre la interfaz y cambia al modo de ensamblaje", - "create.ponder.train_assembly.text_4": "Mientras se esté ensamblando un tren, ningún tren programado se acercará a esa estación", - "create.ponder.train_assembly.text_5": "Crea nuevos vagones usando revestidores de trenes sobre vías", - "create.ponder.train_assembly.text_6": "Haz clic sobre la vía de nuevo para cambiar el diseño del vagón", - "create.ponder.train_assembly.text_7": "Usa pegamento para unir bloques al vagón", - "create.ponder.train_assembly.text_8": "Los trenes ensamblados irán más rápido si encuentran combustible en los cofres o barriles del propio tren", - "create.ponder.train_assembly.text_9": "El combustible que se encuentre en bóvedas no se consumirá", - - "create.ponder.train_controls.header": "Controlar trenes", - "create.ponder.train_controls.text_1": "Los controladores de trenes son necesarios en cada artefacto móvil de tren", - "create.ponder.train_controls.text_2": "Una vez ensamblados, haz clic derecho en el bloque para empezar a conducir", - "create.ponder.train_controls.text_3": "Acelera y dirige el tren usando las teclas de movimiento", - "create.ponder.train_controls.text_4": "Si se desea, la velocidad máxima se puede afinar con la rueda del ratón", - "create.ponder.train_controls.text_5": "Mantén la barra espaciadora para acercarte a la estación más cercana", - "create.ponder.train_controls.text_6": "Los trenes solo pueden desensamblar en bloques en estaciones", - "create.ponder.train_controls.text_7": "Los silbatos de vapor a bordo pueden activarte con [Ctrl]", - "create.ponder.train_controls.text_8": "Usa mayús izdo. o clic de nuevo para parar de controlar el tren", - - "create.ponder.train_schedule.header": "Usar programaciones de tren", - "create.ponder.train_schedule.text_1": "Las programaciones permiten a los trenes ser controlados por otros conductores", - "create.ponder.train_schedule.text_2": "Haz clic derecho con el objeto en la mano para abrir la interfaz", - "create.ponder.train_schedule.text_3": "Una vez configurado, la programación puede usarse en el conductor", - "create.ponder.train_schedule.text_4": "Cualquier mob o quemador de blaze sentado en frente de los controles de tren es un posible conductor", - "create.ponder.train_schedule.text_5": "Las criaturas en riendas pueden adquirir su asiento de forma más conveniente", - "create.ponder.train_schedule.text_6": "Las programaciones pueden recuperarse de los conductores en cualquier momento", - - "create.ponder.train_signal_placement.header": "Colocar señales de tren", - "create.ponder.train_signal_placement.text_1": "Selecciona una vía de tren y coloca la señal cerca", - "create.ponder.train_signal_placement.text_2": "Las señales controlan el flujo de trenes no conducidos por jugadores", - "create.ponder.train_signal_placement.text_3": "Los trenes programados nunca cruzarán señales en la dirección opuesta", - "create.ponder.train_signal_placement.text_4": "...a menos que una segunda señal esté mirando el la posición opuesta.", - "create.ponder.train_signal_placement.text_5": "Los tubos nixie se pueden adherir para hacer que las señales sean más visibles", - - "create.ponder.train_signal_redstone.header": "Señales y redstone", - "create.ponder.train_signal_redstone.text_1": "Se puede forzar que una señal esté en rojo con una señal de redstone", - "create.ponder.train_signal_redstone.text_2": "De forma inversa, las señales rojas emiten una señal mediante comparador", - - "create.ponder.train_signal_signaling.header": "Prevención de colisiones con señales", - "create.ponder.train_signal_signaling.text_1": "Las señales de tren dividen una vía en segmentos", - "create.ponder.train_signal_signaling.text_2": "Si un segmento está ocupado, no se le permitirá el paso a ningún otro tren", - "create.ponder.train_signal_signaling.text_3": "Por lo tanto, cada segmento solo puede albergar un tren", - "create.ponder.train_signal_signaling.text_4": "Un segundo modo de señalización está disponible usando la llave inglesa", - "create.ponder.train_signal_signaling.text_5": "Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "Esta señal especial puede hacer que se paren trenes bajo una segunda condición", - "create.ponder.train_signal_signaling.text_7": "Parará a trenes, los cuales cuando entren...", - "create.ponder.train_signal_signaling.text_8": "...no serán capaces de abandonar ese segmento inmediatamente", - "create.ponder.train_signal_signaling.text_9": "Esto ayuda a que los trenes tengan un orden en segmentos muy concurridos", - - "create.ponder.valve_handle.header": "Generar fuerza rotacional mediante asas de válvula", - "create.ponder.valve_handle.text_1": "Los jugadores pueden utilizar las asas de válvulas para aplicar fuerza rotacional manualmente", - "create.ponder.valve_handle.text_2": "Mantén pulsado el clic derecho para rotar en sentido contrario a las agujas del reloj", - "create.ponder.valve_handle.text_3": "Su velocidad de transmisión es lenta y precisa", - "create.ponder.valve_handle.text_4": "Mayús izdo. + clic derecho para rotar en el sentido de las agujas del reloj", - "create.ponder.valve_handle.text_5": "Las asas de las válvulas pueden teñirse con fines estéticos", - - "create.ponder.valve_pipe.header": "Controlar el flujo de fluidos mediante válvulas", - "create.ponder.valve_pipe.text_1": "Las tuberías con válvulas ayudan a controlar los fluidos que se propagan por las redes de tuberías", - "create.ponder.valve_pipe.text_2": "La entrada con eje controla si el fluido puede pasar", - "create.ponder.valve_pipe.text_3": "Dada una fuerza de rotación en la dirección de apertura, la válvula se abrirá", - "create.ponder.valve_pipe.text_4": "Se puede volver a cerrar invirtiendo el sentido del eje", - - "create.ponder.water_wheel.header": "Generar fuerza rotacional mediante ruedas hidráulicas", - "create.ponder.water_wheel.text_1": "Las ruedas hidráulicas extraen la fuerza de las corrientes de agua adyacentes", - "create.ponder.water_wheel.text_2": "Cuantas más caras se alimenten, más rápido girará", - "create.ponder.water_wheel.text_3": "Las paletas de las ruedas deben estar orientadas en contra del flujo", - "create.ponder.water_wheel.text_4": "Orientadas hacia el lado contrario, no serán tan eficaces", - - "create.ponder.weighted_ejector.header": "Usar eyectores de peso", - "create.ponder.weighted_ejector.text_1": "Mayús izdo. + clic derecho sosteniendo un eyector de peso para seleccionar la ubicación de destino", - "create.ponder.weighted_ejector.text_10": "Ahora estára limitado a este tamaño de pila, y sólo se activara cuando su pila retenida alcance esta cantidad", - "create.ponder.weighted_ejector.text_11": "Otras entidades activarán el eyector al pisarlos", - "create.ponder.weighted_ejector.text_2": "El eyector colocado lanzará ahora los objetos al lugar marcado", - "create.ponder.weighted_ejector.text_3": "Un objetivo válido puede estar a cualquier altura o distancia dentro del alcance", - "create.ponder.weighted_ejector.text_4": "Sin embargo, no pueden estar a un costado", - "create.ponder.weighted_ejector.text_5": "Si no se ha seleccionado ningún objetivo válido, simplemente se dirigirá al bloque que se encuentra justo delante", - "create.ponder.weighted_ejector.text_6": "Suminístralo fuerza rotacional para cargarlo", - "create.ponder.weighted_ejector.text_7": "Los objetos colocados en el eyector hacen que se dispare", - "create.ponder.weighted_ejector.text_8": "Si se dirigen a un inventario, el eyector esperará hasta que haya espacio", - "create.ponder.weighted_ejector.text_9": "Con la llave inglesa se puede configurar el tamaño de pila requerido", - - "create.ponder.weighted_ejector_redstone.header": "Controlar los eyectores de peso con redstone", - "create.ponder.weighted_ejector_redstone.text_1": "Cuando se alimentan con redstone, los eyectores no se activan", - "create.ponder.weighted_ejector_redstone.text_2": "Además, los observadores de contenido pueden detectar cuando los eyectores se activan", - - "create.ponder.weighted_ejector_tunnel.header": "Dividir pilas de objetos mediante eyectores de peso", - "create.ponder.weighted_ejector_tunnel.text_1": "En combinación con los túneles de latón, los eyectores de peso pueden dividir las pilas de objetos en cantidades específicas", - "create.ponder.weighted_ejector_tunnel.text_2": "En primer lugar, configure el túnel de latón en 'Preferir lo más cercano', para dar prioridad a su salida lateral", - "create.ponder.weighted_ejector_tunnel.text_3": "El tamaño de la pila fijado en el eyector determina ahora la cantidad que se va a dividir", - "create.ponder.weighted_ejector_tunnel.text_4": "Mientras una nueva pila del tamaño configurado se expulse por la salida lateral...", - "create.ponder.weighted_ejector_tunnel.text_5": "...el resto seguirá su camino", - - "create.ponder.windmill_source.header": "Generar fuerza rotacional mediante rodamientos de molino de viento", - "create.ponder.windmill_source.text_1": "Los rodamientos del molino de viento se fijan al bloque que tienen delante", - "create.ponder.windmill_source.text_2": "Crea una estructura móvil con la ayuda del pegamento", - "create.ponder.windmill_source.text_3": "Si se unen suficientes velas al bloque, éste puede actuar como un molino de viento", - "create.ponder.windmill_source.text_4": "Activado con un clic derecho, el rodamiento de molino de viento comenzará a proporcionar fuerza rotacional", - "create.ponder.windmill_source.text_5": "La cantidad de velas determina su velocidad de rotación", - "create.ponder.windmill_source.text_6": "Utiliza una llave inglesa para configurar su sentido de rotación", - "create.ponder.windmill_source.text_7": "Haga clic derecho sobre el rodamiento de molino de viento en cualquier momento para detener y editar la estructura de nuevo", - - "create.ponder.windmill_structure.header": "Artefactos estacionarios de molinos de viento", - "create.ponder.windmill_structure.text_1": "Cualquier estructura puede contar como un molino de viento válido, siempre que contenga al menos 8 velas.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json deleted file mode 100644 index 8bef61bc57..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 2120", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Fenêtre en acacia", - "block.create.acacia_window_pane": "Vitre en acacia", - "block.create.adjustable_chain_gearshift": "UNLOCALIZED: Adjustable Chain Gearshift", - "block.create.analog_lever": "Levier analogique", - "block.create.andesite_belt_funnel": "Entonnoir en andésite pour tapis roulant", - "block.create.andesite_casing": "Revêtement en andésite", - "block.create.andesite_encased_cogwheel": "UNLOCALIZED: Andesite Encased Cogwheel", - "block.create.andesite_encased_large_cogwheel": "UNLOCALIZED: Andesite Encased Large Cogwheel", - "block.create.andesite_encased_shaft": "Rotor dans un revêtement en andésite", - "block.create.andesite_funnel": "Entonnoir en andésite", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "Pilier en andésite", - "block.create.andesite_tunnel": "Tunnel en andésite", - "block.create.asurine": "UNLOCALIZED: Asurine", - "block.create.asurine_pillar": "UNLOCALIZED: Asurine Pillar", - "block.create.basin": "Bassin", - "block.create.belt": "Tapis roulant", - "block.create.birch_window": "Fenêtre en bouleau", - "block.create.birch_window_pane": "Vitre en bouleau", - "block.create.black_nixie_tube": "UNLOCALIZED: Black Nixie Tube", - "block.create.black_sail": "Voile noire", - "block.create.black_seat": "Siège noir", - "block.create.black_toolbox": "UNLOCALIZED: Black Toolbox", - "block.create.black_valve_handle": "Vanne noire", - "block.create.blaze_burner": "Brûleur à blaze", - "block.create.blue_nixie_tube": "UNLOCALIZED: Blue Nixie Tube", - "block.create.blue_sail": "Voile bleue", - "block.create.blue_seat": "Siège bleu", - "block.create.blue_toolbox": "UNLOCALIZED: Blue Toolbox", - "block.create.blue_valve_handle": "Vanne bleue", - "block.create.brass_belt_funnel": "Entonnoir en laiton pour tapis roulant", - "block.create.brass_block": "Bloc de laiton", - "block.create.brass_casing": "Revêtement en laiton", - "block.create.brass_encased_cogwheel": "UNLOCALIZED: Brass Encased Cogwheel", - "block.create.brass_encased_large_cogwheel": "UNLOCALIZED: Brass Encased Large Cogwheel", - "block.create.brass_encased_shaft": "Rotor dans un revêtement en laiton", - "block.create.brass_funnel": "Entonnoir en laiton", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "Tunnel en laiton", - "block.create.brown_nixie_tube": "UNLOCALIZED: Brown Nixie Tube", - "block.create.brown_sail": "Voile brune", - "block.create.brown_seat": "Siège brun", - "block.create.brown_toolbox": "UNLOCALIZED: Brown Toolbox", - "block.create.brown_valve_handle": "Vanne brune", - "block.create.calcite_pillar": "UNLOCALIZED: Calcite Pillar", - "block.create.cart_assembler": "Assembleur de wagon", - "block.create.chocolate": "Chocolat", - "block.create.chute": "Glissière", - "block.create.clockwork_bearing": "Roulement mécanique horloger", - "block.create.clutch": "Embrayage", - "block.create.cogwheel": "Roue dentée", - "block.create.content_observer": "Observateur de contenu", - "block.create.controller_rail": "Rails controlleurs", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "UNLOCALIZED: Copper Backtank", - "block.create.copper_casing": "Revêtement en cuivre", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "UNLOCALIZED: Copper Shingle Slab", - "block.create.copper_shingle_stairs": "UNLOCALIZED: Copper Shingle Stairs", - "block.create.copper_shingles": "Bardeaux de cuivre", - "block.create.copper_tile_slab": "UNLOCALIZED: Copper Tile Slab", - "block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs", - "block.create.copper_tiles": "Tuiles en cuivre", - "block.create.copper_valve_handle": "Vanne en cuivre", - "block.create.creative_crate": "Créateur de schémacanon", - "block.create.creative_fluid_tank": "Réservoir créatif", - "block.create.creative_motor": "Moteur", - "block.create.crimsite": "UNLOCALIZED: Crimsite", - "block.create.crimsite_pillar": "UNLOCALIZED: Crimsite Pillar", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", - "block.create.crushing_wheel": "Roue de concassage", - "block.create.crushing_wheel_controller": "Contrôleur de roue de concassage", - "block.create.cuckoo_clock": "Horloge à coucou", - "block.create.cut_andesite": "UNLOCALIZED: Cut Andesite", - "block.create.cut_andesite_brick_slab": "UNLOCALIZED: Cut Andesite Brick Slab", - "block.create.cut_andesite_brick_stairs": "UNLOCALIZED: Cut Andesite Brick Stairs", - "block.create.cut_andesite_brick_wall": "UNLOCALIZED: Cut Andesite Brick Wall", - "block.create.cut_andesite_bricks": "UNLOCALIZED: Cut Andesite Bricks", - "block.create.cut_andesite_slab": "UNLOCALIZED: Cut Andesite Slab", - "block.create.cut_andesite_stairs": "UNLOCALIZED: Cut Andesite Stairs", - "block.create.cut_andesite_wall": "UNLOCALIZED: Cut Andesite Wall", - "block.create.cut_asurine": "UNLOCALIZED: Cut Asurine", - "block.create.cut_asurine_brick_slab": "UNLOCALIZED: Cut Asurine Brick Slab", - "block.create.cut_asurine_brick_stairs": "UNLOCALIZED: Cut Asurine Brick Stairs", - "block.create.cut_asurine_brick_wall": "UNLOCALIZED: Cut Asurine Brick Wall", - "block.create.cut_asurine_bricks": "UNLOCALIZED: Cut Asurine Bricks", - "block.create.cut_asurine_slab": "UNLOCALIZED: Cut Asurine Slab", - "block.create.cut_asurine_stairs": "UNLOCALIZED: Cut Asurine Stairs", - "block.create.cut_asurine_wall": "UNLOCALIZED: Cut Asurine Wall", - "block.create.cut_calcite": "UNLOCALIZED: Cut Calcite", - "block.create.cut_calcite_brick_slab": "UNLOCALIZED: Cut Calcite Brick Slab", - "block.create.cut_calcite_brick_stairs": "UNLOCALIZED: Cut Calcite Brick Stairs", - "block.create.cut_calcite_brick_wall": "UNLOCALIZED: Cut Calcite Brick Wall", - "block.create.cut_calcite_bricks": "UNLOCALIZED: Cut Calcite Bricks", - "block.create.cut_calcite_slab": "UNLOCALIZED: Cut Calcite Slab", - "block.create.cut_calcite_stairs": "UNLOCALIZED: Cut Calcite Stairs", - "block.create.cut_calcite_wall": "UNLOCALIZED: Cut Calcite Wall", - "block.create.cut_crimsite": "UNLOCALIZED: Cut Crimsite", - "block.create.cut_crimsite_brick_slab": "UNLOCALIZED: Cut Crimsite Brick Slab", - "block.create.cut_crimsite_brick_stairs": "UNLOCALIZED: Cut Crimsite Brick Stairs", - "block.create.cut_crimsite_brick_wall": "UNLOCALIZED: Cut Crimsite Brick Wall", - "block.create.cut_crimsite_bricks": "UNLOCALIZED: Cut Crimsite Bricks", - "block.create.cut_crimsite_slab": "UNLOCALIZED: Cut Crimsite Slab", - "block.create.cut_crimsite_stairs": "UNLOCALIZED: Cut Crimsite Stairs", - "block.create.cut_crimsite_wall": "UNLOCALIZED: Cut Crimsite Wall", - "block.create.cut_deepslate": "UNLOCALIZED: Cut Deepslate", - "block.create.cut_deepslate_brick_slab": "UNLOCALIZED: Cut Deepslate Brick Slab", - "block.create.cut_deepslate_brick_stairs": "UNLOCALIZED: Cut Deepslate Brick Stairs", - "block.create.cut_deepslate_brick_wall": "UNLOCALIZED: Cut Deepslate Brick Wall", - "block.create.cut_deepslate_bricks": "UNLOCALIZED: Cut Deepslate Bricks", - "block.create.cut_deepslate_slab": "UNLOCALIZED: Cut Deepslate Slab", - "block.create.cut_deepslate_stairs": "UNLOCALIZED: Cut Deepslate Stairs", - "block.create.cut_deepslate_wall": "UNLOCALIZED: Cut Deepslate Wall", - "block.create.cut_diorite": "UNLOCALIZED: Cut Diorite", - "block.create.cut_diorite_brick_slab": "UNLOCALIZED: Cut Diorite Brick Slab", - "block.create.cut_diorite_brick_stairs": "UNLOCALIZED: Cut Diorite Brick Stairs", - "block.create.cut_diorite_brick_wall": "UNLOCALIZED: Cut Diorite Brick Wall", - "block.create.cut_diorite_bricks": "UNLOCALIZED: Cut Diorite Bricks", - "block.create.cut_diorite_slab": "UNLOCALIZED: Cut Diorite Slab", - "block.create.cut_diorite_stairs": "UNLOCALIZED: Cut Diorite Stairs", - "block.create.cut_diorite_wall": "UNLOCALIZED: Cut Diorite Wall", - "block.create.cut_dripstone": "UNLOCALIZED: Cut Dripstone", - "block.create.cut_dripstone_brick_slab": "UNLOCALIZED: Cut Dripstone Brick Slab", - "block.create.cut_dripstone_brick_stairs": "UNLOCALIZED: Cut Dripstone Brick Stairs", - "block.create.cut_dripstone_brick_wall": "UNLOCALIZED: Cut Dripstone Brick Wall", - "block.create.cut_dripstone_bricks": "UNLOCALIZED: Cut Dripstone Bricks", - "block.create.cut_dripstone_slab": "UNLOCALIZED: Cut Dripstone Slab", - "block.create.cut_dripstone_stairs": "UNLOCALIZED: Cut Dripstone Stairs", - "block.create.cut_dripstone_wall": "UNLOCALIZED: Cut Dripstone Wall", - "block.create.cut_granite": "UNLOCALIZED: Cut Granite", - "block.create.cut_granite_brick_slab": "UNLOCALIZED: Cut Granite Brick Slab", - "block.create.cut_granite_brick_stairs": "UNLOCALIZED: Cut Granite Brick Stairs", - "block.create.cut_granite_brick_wall": "UNLOCALIZED: Cut Granite Brick Wall", - "block.create.cut_granite_bricks": "UNLOCALIZED: Cut Granite Bricks", - "block.create.cut_granite_slab": "UNLOCALIZED: Cut Granite Slab", - "block.create.cut_granite_stairs": "UNLOCALIZED: Cut Granite Stairs", - "block.create.cut_granite_wall": "UNLOCALIZED: Cut Granite Wall", - "block.create.cut_limestone": "UNLOCALIZED: Cut Limestone", - "block.create.cut_limestone_brick_slab": "UNLOCALIZED: Cut Limestone Brick Slab", - "block.create.cut_limestone_brick_stairs": "UNLOCALIZED: Cut Limestone Brick Stairs", - "block.create.cut_limestone_brick_wall": "UNLOCALIZED: Cut Limestone Brick Wall", - "block.create.cut_limestone_bricks": "UNLOCALIZED: Cut Limestone Bricks", - "block.create.cut_limestone_slab": "UNLOCALIZED: Cut Limestone Slab", - "block.create.cut_limestone_stairs": "UNLOCALIZED: Cut Limestone Stairs", - "block.create.cut_limestone_wall": "UNLOCALIZED: Cut Limestone Wall", - "block.create.cut_ochrum": "UNLOCALIZED: Cut Ochrum", - "block.create.cut_ochrum_brick_slab": "UNLOCALIZED: Cut Ochrum Brick Slab", - "block.create.cut_ochrum_brick_stairs": "UNLOCALIZED: Cut Ochrum Brick Stairs", - "block.create.cut_ochrum_brick_wall": "UNLOCALIZED: Cut Ochrum Brick Wall", - "block.create.cut_ochrum_bricks": "UNLOCALIZED: Cut Ochrum Bricks", - "block.create.cut_ochrum_slab": "UNLOCALIZED: Cut Ochrum Slab", - "block.create.cut_ochrum_stairs": "UNLOCALIZED: Cut Ochrum Stairs", - "block.create.cut_ochrum_wall": "UNLOCALIZED: Cut Ochrum Wall", - "block.create.cut_scorchia": "UNLOCALIZED: Cut Scorchia", - "block.create.cut_scorchia_brick_slab": "UNLOCALIZED: Cut Scorchia Brick Slab", - "block.create.cut_scorchia_brick_stairs": "UNLOCALIZED: Cut Scorchia Brick Stairs", - "block.create.cut_scorchia_brick_wall": "UNLOCALIZED: Cut Scorchia Brick Wall", - "block.create.cut_scorchia_bricks": "UNLOCALIZED: Cut Scorchia Bricks", - "block.create.cut_scorchia_slab": "UNLOCALIZED: Cut Scorchia Slab", - "block.create.cut_scorchia_stairs": "UNLOCALIZED: Cut Scorchia Stairs", - "block.create.cut_scorchia_wall": "UNLOCALIZED: Cut Scorchia Wall", - "block.create.cut_scoria": "UNLOCALIZED: Cut Scoria", - "block.create.cut_scoria_brick_slab": "UNLOCALIZED: Cut Scoria Brick Slab", - "block.create.cut_scoria_brick_stairs": "UNLOCALIZED: Cut Scoria Brick Stairs", - "block.create.cut_scoria_brick_wall": "UNLOCALIZED: Cut Scoria Brick Wall", - "block.create.cut_scoria_bricks": "UNLOCALIZED: Cut Scoria Bricks", - "block.create.cut_scoria_slab": "UNLOCALIZED: Cut Scoria Slab", - "block.create.cut_scoria_stairs": "UNLOCALIZED: Cut Scoria Stairs", - "block.create.cut_scoria_wall": "UNLOCALIZED: Cut Scoria Wall", - "block.create.cut_tuff": "UNLOCALIZED: Cut Tuff", - "block.create.cut_tuff_brick_slab": "UNLOCALIZED: Cut Tuff Brick Slab", - "block.create.cut_tuff_brick_stairs": "UNLOCALIZED: Cut Tuff Brick Stairs", - "block.create.cut_tuff_brick_wall": "UNLOCALIZED: Cut Tuff Brick Wall", - "block.create.cut_tuff_bricks": "UNLOCALIZED: Cut Tuff Bricks", - "block.create.cut_tuff_slab": "UNLOCALIZED: Cut Tuff Slab", - "block.create.cut_tuff_stairs": "UNLOCALIZED: Cut Tuff Stairs", - "block.create.cut_tuff_wall": "UNLOCALIZED: Cut Tuff Wall", - "block.create.cut_veridium": "UNLOCALIZED: Cut Veridium", - "block.create.cut_veridium_brick_slab": "UNLOCALIZED: Cut Veridium Brick Slab", - "block.create.cut_veridium_brick_stairs": "UNLOCALIZED: Cut Veridium Brick Stairs", - "block.create.cut_veridium_brick_wall": "UNLOCALIZED: Cut Veridium Brick Wall", - "block.create.cut_veridium_bricks": "UNLOCALIZED: Cut Veridium Bricks", - "block.create.cut_veridium_slab": "UNLOCALIZED: Cut Veridium Slab", - "block.create.cut_veridium_stairs": "UNLOCALIZED: Cut Veridium Stairs", - "block.create.cut_veridium_wall": "UNLOCALIZED: Cut Veridium Wall", - "block.create.cyan_nixie_tube": "UNLOCALIZED: Cyan Nixie Tube", - "block.create.cyan_sail": "Voile cyan", - "block.create.cyan_seat": "Siège cyan", - "block.create.cyan_toolbox": "UNLOCALIZED: Cyan Toolbox", - "block.create.cyan_valve_handle": "Vanne cyan", - "block.create.dark_oak_window": "fenêtre en chêne sombre", - "block.create.dark_oak_window_pane": "Vitre en chêne sombre", - "block.create.deepslate_pillar": "UNLOCALIZED: Deepslate Pillar", - "block.create.deepslate_zinc_ore": "UNLOCALIZED: Deepslate Zinc Ore", - "block.create.deployer": "Déployeur", - "block.create.depot": "Dépot", - "block.create.diorite_pillar": "UNLOCALIZED: Diorite Pillar", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar", - "block.create.encased_chain_drive": "Chaine de transmission", - "block.create.encased_fan": "Ventilateur enchâssé", - "block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe", - "block.create.exposed_copper_shingle_slab": "UNLOCALIZED: Exposed Copper Shingle Slab", - "block.create.exposed_copper_shingle_stairs": "UNLOCALIZED: Exposed Copper Shingle Stairs", - "block.create.exposed_copper_shingles": "UNLOCALIZED: Exposed Copper Shingles", - "block.create.exposed_copper_tile_slab": "UNLOCALIZED: Exposed Copper Tile Slab", - "block.create.exposed_copper_tile_stairs": "UNLOCALIZED: Exposed Copper Tile Stairs", - "block.create.exposed_copper_tiles": "UNLOCALIZED: Exposed Copper Tiles", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "UNLOCALIZED: Fluid Pipe", - "block.create.fluid_tank": "UNLOCALIZED: Fluid Tank", - "block.create.fluid_valve": "UNLOCALIZED: Fluid Valve", - "block.create.flywheel": "Volant d'inertie", - "block.create.framed_glass": "Grande fenêtre en verre", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "Grande vitre encadrée", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", - "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", - "block.create.gearbox": "Boîte à roue dentée", - "block.create.gearshift": "Décaleur de rotation", - "block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe", - "block.create.granite_pillar": "UNLOCALIZED: Granite Pillar", - "block.create.gray_nixie_tube": "UNLOCALIZED: Gray Nixie Tube", - "block.create.gray_sail": "UNLOCALIZED: Gray Sail", - "block.create.gray_seat": "UNLOCALIZED: Gray Seat", - "block.create.gray_toolbox": "UNLOCALIZED: Gray Toolbox", - "block.create.gray_valve_handle": "UNLOCALIZED: Gray Valve Handle", - "block.create.green_nixie_tube": "UNLOCALIZED: Green Nixie Tube", - "block.create.green_sail": "UNLOCALIZED: Green Sail", - "block.create.green_seat": "UNLOCALIZED: Green Seat", - "block.create.green_toolbox": "UNLOCALIZED: Green Toolbox", - "block.create.green_valve_handle": "UNLOCALIZED: Green Valve Handle", - "block.create.hand_crank": "Manivelle", - "block.create.haunted_bell": "UNLOCALIZED: Haunted Bell", - "block.create.honey": "UNLOCALIZED: Honey", - "block.create.horizontal_framed_glass": "Fenêtre en verre horizontale", - "block.create.horizontal_framed_glass_pane": "Vitre encadrée horizontale", - "block.create.hose_pulley": "UNLOCALIZED: Hose Pulley", - "block.create.item_drain": "UNLOCALIZED: Item Drain", - "block.create.item_vault": "UNLOCALIZED: Item Vault", - "block.create.jungle_window": "UNLOCALIZED: Jungle Window", - "block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "Grande roue dentée", - "block.create.layered_andesite": "UNLOCALIZED: Layered Andesite", - "block.create.layered_asurine": "UNLOCALIZED: Layered Asurine", - "block.create.layered_calcite": "UNLOCALIZED: Layered Calcite", - "block.create.layered_crimsite": "UNLOCALIZED: Layered Crimsite", - "block.create.layered_deepslate": "UNLOCALIZED: Layered Deepslate", - "block.create.layered_diorite": "UNLOCALIZED: Layered Diorite", - "block.create.layered_dripstone": "UNLOCALIZED: Layered Dripstone", - "block.create.layered_granite": "UNLOCALIZED: Layered Granite", - "block.create.layered_limestone": "UNLOCALIZED: Layered Limestone", - "block.create.layered_ochrum": "UNLOCALIZED: Layered Ochrum", - "block.create.layered_scorchia": "UNLOCALIZED: Layered Scorchia", - "block.create.layered_scoria": "UNLOCALIZED: Layered Scoria", - "block.create.layered_tuff": "UNLOCALIZED: Layered Tuff", - "block.create.layered_veridium": "UNLOCALIZED: Layered Veridium", - "block.create.lectern_controller": "UNLOCALIZED: Lectern Controller", - "block.create.light_blue_nixie_tube": "UNLOCALIZED: Light Blue Nixie Tube", - "block.create.light_blue_sail": "UNLOCALIZED: Light Blue Sail", - "block.create.light_blue_seat": "UNLOCALIZED: Light Blue Seat", - "block.create.light_blue_toolbox": "UNLOCALIZED: Light Blue Toolbox", - "block.create.light_blue_valve_handle": "UNLOCALIZED: Light Blue Valve Handle", - "block.create.light_gray_nixie_tube": "UNLOCALIZED: Light Gray Nixie Tube", - "block.create.light_gray_sail": "UNLOCALIZED: Light Gray Sail", - "block.create.light_gray_seat": "UNLOCALIZED: Light Gray Seat", - "block.create.light_gray_toolbox": "UNLOCALIZED: Light Gray Toolbox", - "block.create.light_gray_valve_handle": "UNLOCALIZED: Light Gray Valve Handle", - "block.create.lime_nixie_tube": "UNLOCALIZED: Lime Nixie Tube", - "block.create.lime_sail": "UNLOCALIZED: Lime Sail", - "block.create.lime_seat": "UNLOCALIZED: Lime Seat", - "block.create.lime_toolbox": "UNLOCALIZED: Lime Toolbox", - "block.create.lime_valve_handle": "UNLOCALIZED: Lime Valve Handle", - "block.create.limestone": "Calcaire", - "block.create.limestone_pillar": "Pillier de calcaire", - "block.create.linear_chassis": "Châssis linéaire", - "block.create.lit_blaze_burner": "UNLOCALIZED: Lit Blaze Burner", - "block.create.magenta_nixie_tube": "UNLOCALIZED: Magenta Nixie Tube", - "block.create.magenta_sail": "UNLOCALIZED: Magenta Sail", - "block.create.magenta_seat": "UNLOCALIZED: Magenta Seat", - "block.create.magenta_toolbox": "UNLOCALIZED: Magenta Toolbox", - "block.create.magenta_valve_handle": "UNLOCALIZED: Magenta Valve Handle", - "block.create.mechanical_arm": "UNLOCALIZED: Mechanical Arm", - "block.create.mechanical_bearing": "Roulement mécanique", - "block.create.mechanical_crafter": "Établi mécanique", - "block.create.mechanical_drill": "Perceuse mécanique", - "block.create.mechanical_harvester": "Récolteuse mécanique", - "block.create.mechanical_mixer": "Mixeur mécanique", - "block.create.mechanical_piston": "Piston mécanique", - "block.create.mechanical_piston_head": "Tête de piston mécanique", - "block.create.mechanical_plough": "UNLOCALIZED: Mechanical Plough", - "block.create.mechanical_press": "Presse mécanique", - "block.create.mechanical_pump": "UNLOCALIZED: Mechanical Pump", - "block.create.mechanical_saw": "Scie mécanique", - "block.create.metal_bracket": "UNLOCALIZED: Metal Bracket", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "UNLOCALIZED: Millstone", - "block.create.minecart_anchor": "UNLOCALIZED: Minecart Anchor", - "block.create.mysterious_cuckoo_clock": "UNLOCALIZED: Cuckoo Clock", - "block.create.nixie_tube": "UNLOCALIZED: Nixie Tube", - "block.create.nozzle": "Buse", - "block.create.oak_window": "UNLOCALIZED: Oak Window", - "block.create.oak_window_pane": "UNLOCALIZED: Oak Window Pane", - "block.create.ochrum": "UNLOCALIZED: Ochrum", - "block.create.ochrum_pillar": "UNLOCALIZED: Ochrum Pillar", - "block.create.orange_sail": "UNLOCALIZED: Orange Sail", - "block.create.orange_seat": "UNLOCALIZED: Orange Seat", - "block.create.orange_toolbox": "UNLOCALIZED: Orange Toolbox", - "block.create.orange_valve_handle": "UNLOCALIZED: Orange Valve Handle", - "block.create.ornate_iron_window": "UNLOCALIZED: Ornate Iron Window", - "block.create.ornate_iron_window_pane": "UNLOCALIZED: Ornate Iron Window Pane", - "block.create.oxidized_copper_shingle_slab": "UNLOCALIZED: Oxidized Copper Shingle Slab", - "block.create.oxidized_copper_shingle_stairs": "UNLOCALIZED: Oxidized Copper Shingle Stairs", - "block.create.oxidized_copper_shingles": "UNLOCALIZED: Oxidized Copper Shingles", - "block.create.oxidized_copper_tile_slab": "UNLOCALIZED: Oxidized Copper Tile Slab", - "block.create.oxidized_copper_tile_stairs": "UNLOCALIZED: Oxidized Copper Tile Stairs", - "block.create.oxidized_copper_tiles": "UNLOCALIZED: Oxidized Copper Tiles", - "block.create.peculiar_bell": "UNLOCALIZED: Peculiar Bell", - "block.create.pink_nixie_tube": "UNLOCALIZED: Pink Nixie Tube", - "block.create.pink_sail": "UNLOCALIZED: Pink Sail", - "block.create.pink_seat": "UNLOCALIZED: Pink Seat", - "block.create.pink_toolbox": "UNLOCALIZED: Pink Toolbox", - "block.create.pink_valve_handle": "UNLOCALIZED: Pink Valve Handle", - "block.create.piston_extension_pole": "Barre d'extension de piston", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "UNLOCALIZED: Polished Cut Andesite", - "block.create.polished_cut_andesite_slab": "UNLOCALIZED: Polished Cut Andesite Slab", - "block.create.polished_cut_andesite_stairs": "UNLOCALIZED: Polished Cut Andesite Stairs", - "block.create.polished_cut_andesite_wall": "UNLOCALIZED: Polished Cut Andesite Wall", - "block.create.polished_cut_asurine": "UNLOCALIZED: Polished Cut Asurine", - "block.create.polished_cut_asurine_slab": "UNLOCALIZED: Polished Cut Asurine Slab", - "block.create.polished_cut_asurine_stairs": "UNLOCALIZED: Polished Cut Asurine Stairs", - "block.create.polished_cut_asurine_wall": "UNLOCALIZED: Polished Cut Asurine Wall", - "block.create.polished_cut_calcite": "UNLOCALIZED: Polished Cut Calcite", - "block.create.polished_cut_calcite_slab": "UNLOCALIZED: Polished Cut Calcite Slab", - "block.create.polished_cut_calcite_stairs": "UNLOCALIZED: Polished Cut Calcite Stairs", - "block.create.polished_cut_calcite_wall": "UNLOCALIZED: Polished Cut Calcite Wall", - "block.create.polished_cut_crimsite": "UNLOCALIZED: Polished Cut Crimsite", - "block.create.polished_cut_crimsite_slab": "UNLOCALIZED: Polished Cut Crimsite Slab", - "block.create.polished_cut_crimsite_stairs": "UNLOCALIZED: Polished Cut Crimsite Stairs", - "block.create.polished_cut_crimsite_wall": "UNLOCALIZED: Polished Cut Crimsite Wall", - "block.create.polished_cut_deepslate": "UNLOCALIZED: Polished Cut Deepslate", - "block.create.polished_cut_deepslate_slab": "UNLOCALIZED: Polished Cut Deepslate Slab", - "block.create.polished_cut_deepslate_stairs": "UNLOCALIZED: Polished Cut Deepslate Stairs", - "block.create.polished_cut_deepslate_wall": "UNLOCALIZED: Polished Cut Deepslate Wall", - "block.create.polished_cut_diorite": "UNLOCALIZED: Polished Cut Diorite", - "block.create.polished_cut_diorite_slab": "UNLOCALIZED: Polished Cut Diorite Slab", - "block.create.polished_cut_diorite_stairs": "UNLOCALIZED: Polished Cut Diorite Stairs", - "block.create.polished_cut_diorite_wall": "UNLOCALIZED: Polished Cut Diorite Wall", - "block.create.polished_cut_dripstone": "UNLOCALIZED: Polished Cut Dripstone", - "block.create.polished_cut_dripstone_slab": "UNLOCALIZED: Polished Cut Dripstone Slab", - "block.create.polished_cut_dripstone_stairs": "UNLOCALIZED: Polished Cut Dripstone Stairs", - "block.create.polished_cut_dripstone_wall": "UNLOCALIZED: Polished Cut Dripstone Wall", - "block.create.polished_cut_granite": "UNLOCALIZED: Polished Cut Granite", - "block.create.polished_cut_granite_slab": "UNLOCALIZED: Polished Cut Granite Slab", - "block.create.polished_cut_granite_stairs": "UNLOCALIZED: Polished Cut Granite Stairs", - "block.create.polished_cut_granite_wall": "UNLOCALIZED: Polished Cut Granite Wall", - "block.create.polished_cut_limestone": "UNLOCALIZED: Polished Cut Limestone", - "block.create.polished_cut_limestone_slab": "UNLOCALIZED: Polished Cut Limestone Slab", - "block.create.polished_cut_limestone_stairs": "UNLOCALIZED: Polished Cut Limestone Stairs", - "block.create.polished_cut_limestone_wall": "UNLOCALIZED: Polished Cut Limestone Wall", - "block.create.polished_cut_ochrum": "UNLOCALIZED: Polished Cut Ochrum", - "block.create.polished_cut_ochrum_slab": "UNLOCALIZED: Polished Cut Ochrum Slab", - "block.create.polished_cut_ochrum_stairs": "UNLOCALIZED: Polished Cut Ochrum Stairs", - "block.create.polished_cut_ochrum_wall": "UNLOCALIZED: Polished Cut Ochrum Wall", - "block.create.polished_cut_scorchia": "UNLOCALIZED: Polished Cut Scorchia", - "block.create.polished_cut_scorchia_slab": "UNLOCALIZED: Polished Cut Scorchia Slab", - "block.create.polished_cut_scorchia_stairs": "UNLOCALIZED: Polished Cut Scorchia Stairs", - "block.create.polished_cut_scorchia_wall": "UNLOCALIZED: Polished Cut Scorchia Wall", - "block.create.polished_cut_scoria": "UNLOCALIZED: Polished Cut Scoria", - "block.create.polished_cut_scoria_slab": "UNLOCALIZED: Polished Cut Scoria Slab", - "block.create.polished_cut_scoria_stairs": "UNLOCALIZED: Polished Cut Scoria Stairs", - "block.create.polished_cut_scoria_wall": "UNLOCALIZED: Polished Cut Scoria Wall", - "block.create.polished_cut_tuff": "UNLOCALIZED: Polished Cut Tuff", - "block.create.polished_cut_tuff_slab": "UNLOCALIZED: Polished Cut Tuff Slab", - "block.create.polished_cut_tuff_stairs": "UNLOCALIZED: Polished Cut Tuff Stairs", - "block.create.polished_cut_tuff_wall": "UNLOCALIZED: Polished Cut Tuff Wall", - "block.create.polished_cut_veridium": "UNLOCALIZED: Polished Cut Veridium", - "block.create.polished_cut_veridium_slab": "UNLOCALIZED: Polished Cut Veridium Slab", - "block.create.polished_cut_veridium_stairs": "UNLOCALIZED: Polished Cut Veridium Stairs", - "block.create.polished_cut_veridium_wall": "UNLOCALIZED: Polished Cut Veridium Wall", - "block.create.portable_fluid_interface": "UNLOCALIZED: Portable Fluid Interface", - "block.create.portable_storage_interface": "Interface de stockage portable", - "block.create.powered_latch": "Verrou alimenté", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "Verrou alimenté à bascule", - "block.create.pulley_magnet": "Aimant de poulie", - "block.create.pulse_extender": "UNLOCALIZED: Pulse Extender", - "block.create.pulse_repeater": "Répéteur d'impulsions", - "block.create.purple_nixie_tube": "UNLOCALIZED: Purple Nixie Tube", - "block.create.purple_sail": "UNLOCALIZED: Purple Sail", - "block.create.purple_seat": "UNLOCALIZED: Purple Seat", - "block.create.purple_toolbox": "UNLOCALIZED: Purple Toolbox", - "block.create.purple_valve_handle": "UNLOCALIZED: Purple Valve Handle", - "block.create.radial_chassis": "Châssis radial", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "UNLOCALIZED: Block of Raw Zinc", - "block.create.red_nixie_tube": "UNLOCALIZED: Red Nixie Tube", - "block.create.red_sail": "UNLOCALIZED: Red Sail", - "block.create.red_seat": "UNLOCALIZED: Red Seat", - "block.create.red_toolbox": "UNLOCALIZED: Red Toolbox", - "block.create.red_valve_handle": "UNLOCALIZED: Red Valve Handle", - "block.create.redstone_contact": "Contact de redstone", - "block.create.redstone_link": "Liaison Redstone", - "block.create.refined_radiance_casing": "UNLOCALIZED: Radiant Casing", - "block.create.rope": "Corde", - "block.create.rope_pulley": "Poulie à corde", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "Contrôleur de vitesse de rotation", - "block.create.sail_frame": "UNLOCALIZED: Sail Frame", - "block.create.schematic_table": "Table à schéma", - "block.create.schematicannon": "Schémacanon", - "block.create.scorchia": "UNLOCALIZED: Scorchia", - "block.create.scorchia_pillar": "UNLOCALIZED: Scorchia Pillar", - "block.create.scoria": "Scorie", - "block.create.scoria_pillar": "Pillier de scorie", - "block.create.secondary_linear_chassis": "UNLOCALIZED: Secondary Linear Chassis", - "block.create.sequenced_gearshift": "Décaleur de rotation séquencé", - "block.create.shadow_steel_casing": "UNLOCALIZED: Shadow Casing", - "block.create.shaft": "Rotor", - "block.create.small_andesite_brick_slab": "UNLOCALIZED: Small Andesite Brick Slab", - "block.create.small_andesite_brick_stairs": "UNLOCALIZED: Small Andesite Brick Stairs", - "block.create.small_andesite_brick_wall": "UNLOCALIZED: Small Andesite Brick Wall", - "block.create.small_andesite_bricks": "UNLOCALIZED: Small Andesite Bricks", - "block.create.small_asurine_brick_slab": "UNLOCALIZED: Small Asurine Brick Slab", - "block.create.small_asurine_brick_stairs": "UNLOCALIZED: Small Asurine Brick Stairs", - "block.create.small_asurine_brick_wall": "UNLOCALIZED: Small Asurine Brick Wall", - "block.create.small_asurine_bricks": "UNLOCALIZED: Small Asurine Bricks", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "UNLOCALIZED: Small Calcite Brick Slab", - "block.create.small_calcite_brick_stairs": "UNLOCALIZED: Small Calcite Brick Stairs", - "block.create.small_calcite_brick_wall": "UNLOCALIZED: Small Calcite Brick Wall", - "block.create.small_calcite_bricks": "UNLOCALIZED: Small Calcite Bricks", - "block.create.small_crimsite_brick_slab": "UNLOCALIZED: Small Crimsite Brick Slab", - "block.create.small_crimsite_brick_stairs": "UNLOCALIZED: Small Crimsite Brick Stairs", - "block.create.small_crimsite_brick_wall": "UNLOCALIZED: Small Crimsite Brick Wall", - "block.create.small_crimsite_bricks": "UNLOCALIZED: Small Crimsite Bricks", - "block.create.small_deepslate_brick_slab": "UNLOCALIZED: Small Deepslate Brick Slab", - "block.create.small_deepslate_brick_stairs": "UNLOCALIZED: Small Deepslate Brick Stairs", - "block.create.small_deepslate_brick_wall": "UNLOCALIZED: Small Deepslate Brick Wall", - "block.create.small_deepslate_bricks": "UNLOCALIZED: Small Deepslate Bricks", - "block.create.small_diorite_brick_slab": "UNLOCALIZED: Small Diorite Brick Slab", - "block.create.small_diorite_brick_stairs": "UNLOCALIZED: Small Diorite Brick Stairs", - "block.create.small_diorite_brick_wall": "UNLOCALIZED: Small Diorite Brick Wall", - "block.create.small_diorite_bricks": "UNLOCALIZED: Small Diorite Bricks", - "block.create.small_dripstone_brick_slab": "UNLOCALIZED: Small Dripstone Brick Slab", - "block.create.small_dripstone_brick_stairs": "UNLOCALIZED: Small Dripstone Brick Stairs", - "block.create.small_dripstone_brick_wall": "UNLOCALIZED: Small Dripstone Brick Wall", - "block.create.small_dripstone_bricks": "UNLOCALIZED: Small Dripstone Bricks", - "block.create.small_granite_brick_slab": "UNLOCALIZED: Small Granite Brick Slab", - "block.create.small_granite_brick_stairs": "UNLOCALIZED: Small Granite Brick Stairs", - "block.create.small_granite_brick_wall": "UNLOCALIZED: Small Granite Brick Wall", - "block.create.small_granite_bricks": "UNLOCALIZED: Small Granite Bricks", - "block.create.small_limestone_brick_slab": "UNLOCALIZED: Small Limestone Brick Slab", - "block.create.small_limestone_brick_stairs": "UNLOCALIZED: Small Limestone Brick Stairs", - "block.create.small_limestone_brick_wall": "UNLOCALIZED: Small Limestone Brick Wall", - "block.create.small_limestone_bricks": "UNLOCALIZED: Small Limestone Bricks", - "block.create.small_ochrum_brick_slab": "UNLOCALIZED: Small Ochrum Brick Slab", - "block.create.small_ochrum_brick_stairs": "UNLOCALIZED: Small Ochrum Brick Stairs", - "block.create.small_ochrum_brick_wall": "UNLOCALIZED: Small Ochrum Brick Wall", - "block.create.small_ochrum_bricks": "UNLOCALIZED: Small Ochrum Bricks", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "UNLOCALIZED: Small Scorchia Brick Slab", - "block.create.small_scorchia_brick_stairs": "UNLOCALIZED: Small Scorchia Brick Stairs", - "block.create.small_scorchia_brick_wall": "UNLOCALIZED: Small Scorchia Brick Wall", - "block.create.small_scorchia_bricks": "UNLOCALIZED: Small Scorchia Bricks", - "block.create.small_scoria_brick_slab": "UNLOCALIZED: Small Scoria Brick Slab", - "block.create.small_scoria_brick_stairs": "UNLOCALIZED: Small Scoria Brick Stairs", - "block.create.small_scoria_brick_wall": "UNLOCALIZED: Small Scoria Brick Wall", - "block.create.small_scoria_bricks": "UNLOCALIZED: Small Scoria Bricks", - "block.create.small_tuff_brick_slab": "UNLOCALIZED: Small Tuff Brick Slab", - "block.create.small_tuff_brick_stairs": "UNLOCALIZED: Small Tuff Brick Stairs", - "block.create.small_tuff_brick_wall": "UNLOCALIZED: Small Tuff Brick Wall", - "block.create.small_tuff_bricks": "UNLOCALIZED: Small Tuff Bricks", - "block.create.small_veridium_brick_slab": "UNLOCALIZED: Small Veridium Brick Slab", - "block.create.small_veridium_brick_stairs": "UNLOCALIZED: Small Veridium Brick Stairs", - "block.create.small_veridium_brick_wall": "UNLOCALIZED: Small Veridium Brick Wall", - "block.create.small_veridium_bricks": "UNLOCALIZED: Small Veridium Bricks", - "block.create.smart_chute": "UNLOCALIZED: Smart Chute", - "block.create.smart_fluid_pipe": "UNLOCALIZED: Smart Fluid Pipe", - "block.create.speedometer": "Compteur de vitesse", - "block.create.spout": "UNLOCALIZED: Spout", - "block.create.spruce_window": "UNLOCALIZED: Spruce Window", - "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "UNLOCALIZED: Sticker", - "block.create.sticky_mechanical_piston": "Piston mécanique collant", - "block.create.stockpile_switch": "Détecteur de stockage", - "block.create.stressometer": "Stressomètre", - "block.create.tiled_glass": "Verre carrelé", - "block.create.tiled_glass_pane": "Vitre carrelé", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "UNLOCALIZED: Tuff Pillar", - "block.create.turntable": "Plaque tournante", - "block.create.veridium": "UNLOCALIZED: Veridium", - "block.create.veridium_pillar": "UNLOCALIZED: Veridium Pillar", - "block.create.vertical_framed_glass": "Fenêtre en verre verticale", - "block.create.vertical_framed_glass_pane": "Vitre encadrée verticale", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", - "block.create.water_wheel": "Roue à eau", - "block.create.waxed_copper_shingle_slab": "UNLOCALIZED: Waxed Copper Shingle Slab", - "block.create.waxed_copper_shingle_stairs": "UNLOCALIZED: Waxed Copper Shingle Stairs", - "block.create.waxed_copper_shingles": "UNLOCALIZED: Waxed Copper Shingles", - "block.create.waxed_copper_tile_slab": "UNLOCALIZED: Waxed Copper Tile Slab", - "block.create.waxed_copper_tile_stairs": "UNLOCALIZED: Waxed Copper Tile Stairs", - "block.create.waxed_copper_tiles": "UNLOCALIZED: Waxed Copper Tiles", - "block.create.waxed_exposed_copper_shingle_slab": "UNLOCALIZED: Waxed Exposed Copper Shingle Slab", - "block.create.waxed_exposed_copper_shingle_stairs": "UNLOCALIZED: Waxed Exposed Copper Shingle Stairs", - "block.create.waxed_exposed_copper_shingles": "UNLOCALIZED: Waxed Exposed Copper Shingles", - "block.create.waxed_exposed_copper_tile_slab": "UNLOCALIZED: Waxed Exposed Copper Tile Slab", - "block.create.waxed_exposed_copper_tile_stairs": "UNLOCALIZED: Waxed Exposed Copper Tile Stairs", - "block.create.waxed_exposed_copper_tiles": "UNLOCALIZED: Waxed Exposed Copper Tiles", - "block.create.waxed_oxidized_copper_shingle_slab": "UNLOCALIZED: Waxed Oxidized Copper Shingle Slab", - "block.create.waxed_oxidized_copper_shingle_stairs": "UNLOCALIZED: Waxed Oxidized Copper Shingle Stairs", - "block.create.waxed_oxidized_copper_shingles": "UNLOCALIZED: Waxed Oxidized Copper Shingles", - "block.create.waxed_oxidized_copper_tile_slab": "UNLOCALIZED: Waxed Oxidized Copper Tile Slab", - "block.create.waxed_oxidized_copper_tile_stairs": "UNLOCALIZED: Waxed Oxidized Copper Tile Stairs", - "block.create.waxed_oxidized_copper_tiles": "UNLOCALIZED: Waxed Oxidized Copper Tiles", - "block.create.waxed_weathered_copper_shingle_slab": "UNLOCALIZED: Waxed Weathered Copper Shingle Slab", - "block.create.waxed_weathered_copper_shingle_stairs": "UNLOCALIZED: Waxed Weathered Copper Shingle Stairs", - "block.create.waxed_weathered_copper_shingles": "UNLOCALIZED: Waxed Weathered Copper Shingles", - "block.create.waxed_weathered_copper_tile_slab": "UNLOCALIZED: Waxed Weathered Copper Tile Slab", - "block.create.waxed_weathered_copper_tile_stairs": "UNLOCALIZED: Waxed Weathered Copper Tile Stairs", - "block.create.waxed_weathered_copper_tiles": "UNLOCALIZED: Waxed Weathered Copper Tiles", - "block.create.weathered_copper_shingle_slab": "UNLOCALIZED: Weathered Copper Shingle Slab", - "block.create.weathered_copper_shingle_stairs": "UNLOCALIZED: Weathered Copper Shingle Stairs", - "block.create.weathered_copper_shingles": "UNLOCALIZED: Weathered Copper Shingles", - "block.create.weathered_copper_tile_slab": "UNLOCALIZED: Weathered Copper Tile Slab", - "block.create.weathered_copper_tile_stairs": "UNLOCALIZED: Weathered Copper Tile Stairs", - "block.create.weathered_copper_tiles": "UNLOCALIZED: Weathered Copper Tiles", - "block.create.weighted_ejector": "UNLOCALIZED: Weighted Ejector", - "block.create.white_nixie_tube": "UNLOCALIZED: White Nixie Tube", - "block.create.white_sail": "UNLOCALIZED: White Sail", - "block.create.white_seat": "UNLOCALIZED: White Seat", - "block.create.white_toolbox": "UNLOCALIZED: White Toolbox", - "block.create.white_valve_handle": "UNLOCALIZED: White Valve Handle", - "block.create.windmill_bearing": "UNLOCALIZED: Windmill Bearing", - "block.create.wooden_bracket": "UNLOCALIZED: Wooden Bracket", - "block.create.yellow_nixie_tube": "UNLOCALIZED: Yellow Nixie Tube", - "block.create.yellow_sail": "UNLOCALIZED: Yellow Sail", - "block.create.yellow_seat": "UNLOCALIZED: Yellow Seat", - "block.create.yellow_toolbox": "UNLOCALIZED: Yellow Toolbox", - "block.create.yellow_valve_handle": "UNLOCALIZED: Yellow Valve Handle", - "block.create.zinc_block": "Bloc de zinc", - "block.create.zinc_ore": "Minerai de zinc", - - "enchantment.create.capacity": "UNLOCALIZED: Capacity", - "enchantment.create.potato_recovery": "UNLOCALIZED: Potato Recovery", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "Engin", - "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", - "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", - "entity.create.potato_projectile": "UNLOCALIZED: Potato Projectile", - "entity.create.seat": "Siège", - "entity.create.stationary_contraption": "Engin stationnaire", - "entity.create.super_glue": "Colle extra-forte", - - "fluid.create.potion": "Potion", - "fluid.create.tea": "Thé du constructeur", - - "item.create.andesite_alloy": "Alliage d'andésite", - "item.create.attribute_filter": "Filtre d'attribut", - "item.create.bar_of_chocolate": "Barre de chocolat", - "item.create.belt_connector": "Tapis roulant", - "item.create.blaze_cake": "Cake au blaze", - "item.create.blaze_cake_base": "Base d'un cake au blase", - "item.create.brass_hand": "Main", - "item.create.brass_ingot": "Lingot de laiton", - "item.create.brass_nugget": "Pépite de laiton", - "item.create.brass_sheet": "Plaques de laiton", - "item.create.builders_tea": "Thé du constructeur", - "item.create.chest_minecart_contraption": "Engin de wagonnet avec coffre", - "item.create.chocolate_bucket": "Seau de chocolat", - "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", - "item.create.chromatic_compound": "Composé chromatique", - "item.create.cinder_flour": "Farine de braise", - "item.create.copper_backtank": "UNLOCALIZED: Copper Backtank", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Pépite de cuivre", - "item.create.copper_sheet": "Plaques de cuivre", - "item.create.crafter_slot_cover": "Couvercle", - "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", - "item.create.creative_blaze_cake": "UNLOCALIZED: Creative Blaze Cake", - "item.create.crushed_aluminum_ore": "Aluminium concassé", - "item.create.crushed_copper_ore": "Cuivre concassé", - "item.create.crushed_gold_ore": "Or concassé", - "item.create.crushed_iron_ore": "Fer concassé", - "item.create.crushed_lead_ore": "Plomb concassé", - "item.create.crushed_nickel_ore": "Nickel concassé", - "item.create.crushed_osmium_ore": "Osmium concassé", - "item.create.crushed_platinum_ore": "Platinium concassé", - "item.create.crushed_quicksilver_ore": "Vif-argent concassé", - "item.create.crushed_silver_ore": "Argent concassé", - "item.create.crushed_tin_ore": "Etain concassé", - "item.create.crushed_uranium_ore": "Uranium concassé", - "item.create.crushed_zinc_ore": "Zinc concassé", - "item.create.diving_boots": "UNLOCALIZED: Diving Boots", - "item.create.diving_helmet": "UNLOCALIZED: Diving Helmet", - "item.create.dough": "Pâte", - "item.create.electron_tube": "Tube électronique", - "item.create.empty_blaze_burner": "Brûleur à blaze vide", - "item.create.empty_schematic": "Schéma vide", - "item.create.experience_nugget": "UNLOCALIZED: Nugget of Experience", - "item.create.extendo_grip": "Extendo Grip", - "item.create.filter": "Filtre", - "item.create.furnace_minecart_contraption": "Engin de wagon avec fourneau", - "item.create.goggles": "Lunettes d'ingénieur", - "item.create.golden_sheet": "Feuille d'or", - "item.create.handheld_worldshaper": "Térraformeur portable", - "item.create.honey_bucket": "Seau de miel", - "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", - "item.create.incomplete_precision_mechanism": "UNLOCALIZED: Incomplete Precision Mechanism", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "Plaque de Fer", - "item.create.linked_controller": "UNLOCALIZED: Linked Controller", - "item.create.minecart_contraption": "Engin de wagonnet", - "item.create.minecart_coupling": "Lien pour wagonnet", - "item.create.polished_rose_quartz": "Quartz rose poli", - "item.create.potato_cannon": "UNLOCALIZED: Potato Cannon", - "item.create.powdered_obsidian": "Obsidienne concassée", - "item.create.precision_mechanism": "UNLOCALIZED: Precision Mechanism", - "item.create.propeller": "Hélice", - "item.create.raw_zinc": "UNLOCALIZED: Raw Zinc", - "item.create.red_sand_paper": "Papier de verre rouge", - "item.create.refined_radiance": "Éclat raffiné", - "item.create.rose_quartz": "Quartz rose", - "item.create.sand_paper": "Papier de verre", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Schéma", - "item.create.schematic_and_quill": "Schéma et plume", - "item.create.shadow_steel": "Acier sombre", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "Colle extra-forte", - "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", - "item.create.tree_fertilizer": "Engrais pour arbres", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Boîte de transfert verticale", - "item.create.wand_of_symmetry": "Bâton de symétrie", - "item.create.wheat_flour": "Farine", - "item.create.whisk": "Fouet", - "item.create.wrench": "Clé", - "item.create.zinc_ingot": "Barre de zinc", - "item.create.zinc_nugget": "Pépite de zinc", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bienvenue dans Create.", - "advancement.create.root.desc": "Le temps de la redstone est révolu!", - "advancement.create.andesite_alloy": "UNLOCALIZED: Sturdier Rocks", - "advancement.create.andesite_alloy.desc": "Certains matériaux de Create ont des noms bizzares; l'alliage d'andésite est l'un d'entre eux.", - "advancement.create.andesite_casing": "UNLOCALIZED: The Andesite Age", - "advancement.create.andesite_casing.desc": "UNLOCALIZED: Apply Andesite Alloy to stripped wood, creating a basic casing for your machines", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "UNLOCALIZED: Kelp Drive", - "advancement.create.belt.desc": "UNLOCALIZED: Connect two Shafts with a Mechanical Belt", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "UNLOCALIZED: Vertical Logistics", - "advancement.create.chute.desc": "UNLOCALIZED: Transport some items by Chute", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "UNLOCALIZED: Harnessed Hydraulics", - "advancement.create.water_wheel.desc": "UNLOCALIZED: Place a Water Wheel and use it to generate torque", - "advancement.create.windmill": "Une brise moyenne...", - "advancement.create.windmill.desc": "Construire un moulin à vent", - "advancement.create.shifting_gears": "rotor de transmission", - "advancement.create.shifting_gears.desc": "Connectez une roue dentée à une grande roue dentée afin de changer la vitesse de votre engin", - "advancement.create.millstone": "UNLOCALIZED: Embrace the Grind", - "advancement.create.millstone.desc": "UNLOCALIZED: Use a Millstone to pulverise materials", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "UNLOCALIZED: Stress for Nerds", - "advancement.create.stressometer.desc": "UNLOCALIZED: Get an exact readout with the help of Engineer's Goggles and a Stressometer", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "UNLOCALIZED: The Parrots and the Flaps", - "advancement.create.belt_funnel_kiss.desc": "UNLOCALIZED: Make two Belt-mounted Funnels kiss§7\n(Hidden Advancement)", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "UNLOCALIZED: The Copper Age", - "advancement.create.copper_casing.desc": "UNLOCALIZED: Apply Copper Ingots to stripped wood, creating a waterproof casing for your machines", - "advancement.create.spout": "UNLOCALIZED: Sploosh", - "advancement.create.spout.desc": "UNLOCALIZED: Watch a fluid-containing item be filled by a Spout", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "UNLOCALIZED: Flow Discovery", - "advancement.create.glass_pipe.desc": "UNLOCALIZED: Use your Wrench on a pipe that contains a fluid", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "UNLOCALIZED: Industrial Spillage", - "advancement.create.hose_pulley.desc": "UNLOCALIZED: Lower a Hose Pulley and watch it drain or fill a body of fluid", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "UNLOCALIZED: Real Alloys", - "advancement.create.brass.desc": "UNLOCALIZED: Create Brass Ingots by alloying Copper and Zinc Ingots in your Blaze-heated Mechanical Mixer", - "advancement.create.brass_casing": "UNLOCALIZED: The Brass Age", - "advancement.create.brass_casing.desc": "UNLOCALIZED: Apply Brass Ingots to stripped wood, creating a casing for more sophisticated machines", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "UNLOCALIZED: Artificial Intelligence", - "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself", - "advancement.create.precision_mechanism": "UNLOCALIZED: Complex Curiosities", - "advancement.create.precision_mechanism.desc": "UNLOCALIZED: Assemble a Precision Mechanism", - "advancement.create.speed_controller": "UNLOCALIZED: Engineers Hate Him!", - "advancement.create.speed_controller.desc": "UNLOCALIZED: Fine-tune your Contraption with a Rotation Speed Controller", - "advancement.create.mechanical_arm": "UNLOCALIZED: Busy Hands", - "advancement.create.mechanical_arm.desc": "UNLOCALIZED: Watch your Mechanical Arm transport its first item", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", - "advancement.create.crushing_wheel.desc": "UNLOCALIZED: Place and power a set of Crushing Wheels", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "UNLOCALIZED: Contraption O'Clock", - "advancement.create.clockwork_bearing.desc": "UNLOCALIZED: Assemble a structure mounted on a Clockwork Bearing", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "UNLOCALIZED: Fwoomp!", - "advancement.create.potato_cannon.desc": "UNLOCALIZED: Defeat an enemy with your Potato Cannon", - "advancement.create.extendo_grip": "UNLOCALIZED: Boioioing!", - "advancement.create.extendo_grip.desc": "UNLOCALIZED: Get hold of an Extendo Grip", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "UNLOCALIZED: Combust-o-Tron", - "advancement.create.arm_blaze_burner.desc": "UNLOCALIZED: Instruct a Mechanical Arm to feed your Blaze Burner", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "UNLOCALIZED: Organize-o-Tron", - "advancement.create.arm_many_targets.desc": "UNLOCALIZED: Program a Mechanical Arm with 10 or more output locations", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", - "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump§7\n(Hidden Advancement)", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "UNLOCALIZED: DJ Mechanico", - "advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox§7\n(Hidden Advancement)", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create Palettes", - - "death.attack.create.crush": "%1$s a été concassé.e", - "death.attack.create.crush.player": "UNLOCALIZED: %1$s was thrown into Crushing Wheels by %2$s", - "death.attack.create.fan_fire": "%1$s a été brûlé à mort par l'air chaud", - "death.attack.create.fan_fire.player": "UNLOCALIZED: %1$s was thrown into a smoker by %2$s", - "death.attack.create.fan_lava": "%1$s a été brûlé à mort par un ventilateur de lave", - "death.attack.create.fan_lava.player": "UNLOCALIZED: %1$s was thrown into a smelter by %2$s", - "death.attack.create.mechanical_drill": "%1$s a été empalé par une perceuse mécanique", - "death.attack.create.mechanical_drill.player": "UNLOCALIZED: %1$s was thrown in front of a Drill by %2$s", - "death.attack.create.mechanical_saw": "%1$s a été coupé en deux par une scie mécanique", - "death.attack.create.mechanical_saw.player": "UNLOCALIZED: %1$s was thrown into a Saw by %2$s", - "death.attack.create.potato_cannon": "UNLOCALIZED: %1$s was shot by %2$s's Potato Cannon", - "death.attack.create.potato_cannon.item": "UNLOCALIZED: %1$s was shot by %2$s using %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s a été explosé par un coucou trafiquée", - "death.attack.create.cuckoo_clock_explosion.player": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "un déployeur voyou", - "create.block.cart_assembler.invalid": "UNLOCALIZED: Place your Cart Assembler on a rail block", - - "create.menu.return": "UNLOCALIZED: Return to Menu", - "create.menu.configure": "UNLOCALIZED: Configure...", - "create.menu.ponder_index": "UNLOCALIZED: Ponder Index", - "create.menu.only_ingame": "UNLOCALIZED: Available in the Pause Menu", - "create.menu.report_bugs": "UNLOCALIZED: Report Issues", - "create.menu.support": "UNLOCALIZED: Support Us", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Ecrasement", - "create.recipe.milling": "Mouture", - "create.recipe.fan_washing": "Lavage", - "create.recipe.fan_washing.fan": "Ventilateur derrière de l'eau", - "create.recipe.fan_smoking": "Fumage", - "create.recipe.fan_smoking.fan": "Ventilateur derrière du feu", - "create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", - "create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", - "create.recipe.fan_blasting": "Fonte", - "create.recipe.fan_blasting.fan": "Ventilateur derrière de la lave", - "create.recipe.pressing": "Pressage", - "create.recipe.mixing": "Mixage", - "create.recipe.deploying": "UNLOCALIZED: Deploying", - "create.recipe.automatic_shapeless": "UNLOCALIZED: Automated Shapeless Crafting", - "create.recipe.automatic_brewing": "Alchimie automatisée", - "create.recipe.packing": "Compactage", - "create.recipe.automatic_packing": "Compactage automatisé", - "create.recipe.sawing": "Sciage", - "create.recipe.mechanical_crafting": "Fabrication mécanique", - "create.recipe.automatic_shaped": "UNLOCALIZED: Automated Shaped Crafting", - "create.recipe.block_cutting": "Coupe de bloc", - "create.recipe.wood_cutting": "UNLOCALIZED: Wood Cutting", - "create.recipe.sandpaper_polishing": "Polissage au papier de verre", - "create.recipe.mystery_conversion": "Métamorphose chromatique", - "create.recipe.spout_filling": "Remplissage par un bec verseur", - "create.recipe.draining": "UNLOCALIZED: Item Draining", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "UNLOCALIZED: Recipe Sequence", - "create.recipe.assembly.next": "UNLOCALIZED: Next: %1$s", - "create.recipe.assembly.step": "UNLOCALIZED: Step %1$s:", - "create.recipe.assembly.progress": "UNLOCALIZED: Progress: %1$s/%2$s", - "create.recipe.assembly.pressing": "UNLOCALIZED: Process in Press", - "create.recipe.assembly.spout_filling_fluid": "UNLOCALIZED: Spout %1$s", - "create.recipe.assembly.deploying_item": "UNLOCALIZED: Deploy %1$s", - "create.recipe.assembly.cutting": "UNLOCALIZED: Cut with Saw", - "create.recipe.assembly.repeat": "UNLOCALIZED: Repeat Sequence %1$s Times", - "create.recipe.assembly.junk": "UNLOCALIZED: Random salvage", - "create.recipe.processing.chance": "%1$s%% de chance", - "create.recipe.deploying.not_consumed": "UNLOCALIZED: Not Consumed", - "create.recipe.heat_requirement.none": "Pas de chauffage requis", - "create.recipe.heat_requirement.heated": "Chauffé", - "create.recipe.heat_requirement.superheated": "Surchauffé", - - "create.generic.range": "Portée", - "create.generic.radius": "Rayon", - "create.generic.width": "Largeur", - "create.generic.height": "Hauteur", - "create.generic.length": "Longueur", - "create.generic.speed": "Vitesse", - "create.generic.delay": "Delai", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Secondes", - "create.generic.unit.minutes": "Minutes", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "tr/min", - "create.generic.unit.stress": "us", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smS", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "dans le sens horaire", - "create.generic.counter_clockwise": "dans le sens anti-horaire", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Faire défiler", - "create.action.confirm": "Confirmer", - "create.action.abort": "Abandonner", - "create.action.saveToFile": "Sauvegarder", - "create.action.discard": "Annuler", - - "create.keyinfo.toolmenu": "Focus sur le menu de l'outil", - "create.keyinfo.toolbelt": "UNLOCALIZED: Access Nearby Toolboxes", - "create.keyinfo.scrollup": "UNLOCALIZED: Simulate Mousewheel Up (inworld)", - "create.keyinfo.scrolldown": "UNLOCALIZED: Simulate Mousewheel Down (inworld)", - - "create.gui.scrollInput.defaultTitle": "Choisissez une option:", - "create.gui.scrollInput.scrollToModify": "Faites défiler pour modifier", - "create.gui.scrollInput.scrollToAdjustAmount": "Faites défiler pour ajuster le montant", - "create.gui.scrollInput.scrollToSelect": "Faites défiler pour sélectionner", - "create.gui.scrollInput.shiftScrollsFaster": "Maj pour défiler plus rapidement", - "create.gui.toolmenu.focusKey": "Enfoncez [%1$s] pour focus", - "create.gui.toolmenu.cycle": "[SCROLL] pour cycler", - - "create.toolbox.unequip": "UNLOCALIZED: Unequip: %1$s", - "create.toolbox.outOfRange": "UNLOCALIZED: Toolbox of held item not in Range", - "create.toolbox.detach": "UNLOCALIZED: Stop tracking and keep item", - "create.toolbox.depositAll": "UNLOCALIZED: Return items to nearby Toolboxes", - "create.toolbox.depositBox": "UNLOCALIZED: Return items to Toolbox", - - "create.gui.symmetryWand.mirrorType": "Mirroir", - "create.gui.symmetryWand.orientation": "Orientation", - - "create.symmetry.mirror.plane": "Miroir une fois", - "create.symmetry.mirror.doublePlane": "Rectangulaire", - "create.symmetry.mirror.triplePlane": "Octogonal", - - "create.orientation.orthogonal": "Orthogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "Sur Z", - "create.orientation.alongX": "Sur X", - - "create.gui.terrainzapper.title": "Térraformeur portable", - "create.gui.terrainzapper.searchDiagonal": "UNLOCALIZED: Follow Diagonals", - "create.gui.terrainzapper.searchFuzzy": "UNLOCALIZED: Ignore Material Borders", - "create.gui.terrainzapper.patternSection": "UNLOCALIZED: Pattern", - "create.gui.terrainzapper.pattern.solid": "UNLOCALIZED: Solid", - "create.gui.terrainzapper.pattern.checkered": "UNLOCALIZED: Checkerboard", - "create.gui.terrainzapper.pattern.inversecheckered": "UNLOCALIZED: Inverted Checkerboard", - "create.gui.terrainzapper.pattern.chance25": "UNLOCALIZED: 25% Roll", - "create.gui.terrainzapper.pattern.chance50": "UNLOCALIZED: 50% Roll", - "create.gui.terrainzapper.pattern.chance75": "UNLOCALIZED: 75% Roll", - "create.gui.terrainzapper.placement": "Placement", - "create.gui.terrainzapper.placement.merged": "Fusionner", - "create.gui.terrainzapper.placement.attached": "Attacher", - "create.gui.terrainzapper.placement.inserted": "Inserer", - "create.gui.terrainzapper.brush": "Pinceau", - "create.gui.terrainzapper.brush.cuboid": "Cuboïde", - "create.gui.terrainzapper.brush.sphere": "Sphère", - "create.gui.terrainzapper.brush.cylinder": "Cylindre", - "create.gui.terrainzapper.brush.surface": "UNLOCALIZED: Surface", - "create.gui.terrainzapper.brush.cluster": "UNLOCALIZED: Cluster", - "create.gui.terrainzapper.tool": "Outil", - "create.gui.terrainzapper.tool.fill": "Remplir", - "create.gui.terrainzapper.tool.place": "Placer", - "create.gui.terrainzapper.tool.replace": "Remplacer", - "create.gui.terrainzapper.tool.clear": "Effacer", - "create.gui.terrainzapper.tool.overlay": "Recouvrir", - "create.gui.terrainzapper.tool.flatten": "Applatir", - - "create.terrainzapper.shiftRightClickToSet": "Maj + clic droit pour sélectionner une forme", - "create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s", - "create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material", - - "create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each", - "create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks", - "create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop", - "create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart", - "create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart", - - "create.contraptions.movement_mode": "Mode de mouvement", - "create.contraptions.movement_mode.move_place": "Toujours placer à l'arrêt", - "create.contraptions.movement_mode.move_place_returned": "Placer uniquement en position de départ", - "create.contraptions.movement_mode.move_never_place": "Ne placer que Quand l'ancre est détruite", - "create.contraptions.movement_mode.rotate_place": "Toujours placer à l'arrêt", - "create.contraptions.movement_mode.rotate_place_returned": "Placer uniquement près de l'angle initial", - "create.contraptions.movement_mode.rotate_never_place": "Ne placer que Quand l'ancre est détruite", - "create.contraptions.cart_movement_mode": "UNLOCALIZED: Cart Movement Mode", - "create.contraptions.cart_movement_mode.rotate": "UNLOCALIZED: Always face toward motion", - "create.contraptions.cart_movement_mode.rotate_paused": "UNLOCALIZED: Pause actors while rotating", - "create.contraptions.cart_movement_mode.rotation_locked": "UNLOCALIZED: Lock rotation", - "create.contraptions.windmill.rotation_direction": "UNLOCALIZED: Rotation Direction", - "create.contraptions.clockwork.clock_hands": "UNLOCALIZED: Clock Hands", - "create.contraptions.clockwork.hour_first": "UNLOCALIZED: Hour hand first", - "create.contraptions.clockwork.minute_first": "UNLOCALIZED: Minute hand first", - "create.contraptions.clockwork.hour_first_24": "UNLOCALIZED: 24-Hour hand first", - - "create.logistics.filter": "Filtre", - "create.logistics.recipe_filter": "Filtre de recettes", - "create.logistics.fluid_filter": "Filtre de fuides", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Filtre appliqué à %1$s.", - "create.logistics.filter.apply_click_again": "Filtre appliqué à %1$s, appuiez de nouveau pour copier le montant", - "create.logistics.filter.apply_count": "Montant d'extraction appliqué au filtre", - - "create.gui.goggles.generator_stats": "Statistiques du générateur:", - "create.gui.goggles.kinetic_stats": "Statistiques cinétiques:", - "create.gui.goggles.at_current_speed": "À la vitesse actuelle", - "create.gui.goggles.pole_length": "Longueur de la barre", - "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", - "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", - "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", - "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", - "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", - "create.gui.gauge.info_header": "Informations sur la jauge:", - "create.gui.speedometer.title": "Vitesse de rotation", - "create.gui.stressometer.title": "Stress du réseau", - "create.gui.stressometer.capacity": "Capacité restante", - "create.gui.stressometer.overstressed": "Surmenée", - "create.gui.stressometer.no_rotation": "Pas de rotation", - "create.gui.contraptions.not_fast_enough": "Il semblerais que ce.t.te %1$s ne tourne _pas_ à la _vitesse_ _suffisante_.", - "create.gui.contraptions.network_overstressed": "UNLOCALIZED: It appears that this contraption is _overstressed_. Add more sources or _slow_ _down_ the components with a high _stress_ _impact_.", - "create.gui.adjustable_crate.title": "Caisse réglable", - "create.gui.adjustable_crate.storageSpace": "Espace de stockage", - "create.gui.stockpile_switch.title": "Commutateur de stockage", - "create.gui.stockpile_switch.invert_signal": "Inverser le signal", - "create.gui.stockpile_switch.move_to_lower_at": "Bouger sur la ligne du bas à %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Bouger sur la ligne de haut à %1$s%%", - "create.gui.sequenced_gearshift.title": "Décaleur de rotation séquencé", - "create.gui.sequenced_gearshift.instruction": "Instructions", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "UNLOCALIZED: Turn by angle", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Tourner", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angle", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "UNLOCALIZED: Turn to move Piston/Pulley/Gantry", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Piston", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distance", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "UNLOCALIZED: Timed Delay", - "create.gui.sequenced_gearshift.instruction.delay": "UNLOCALIZED: Delay", - "create.gui.sequenced_gearshift.instruction.delay.duration": "UNLOCALIZED: Duration", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "UNLOCALIZED: End", - "create.gui.sequenced_gearshift.instruction.end": "Fin", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "UNLOCALIZED: Await new Redstone Pulse", - "create.gui.sequenced_gearshift.instruction.await": "UNLOCALIZED: Await", - "create.gui.sequenced_gearshift.speed": "Vitesse, direction", - "create.gui.sequenced_gearshift.speed.forward": "Vitesse d'entrée, normal", - "create.gui.sequenced_gearshift.speed.forward_fast": "Vitesse double, normal", - "create.gui.sequenced_gearshift.speed.back": "Vitesse d'entrée, inversé", - "create.gui.sequenced_gearshift.speed.back_fast": "Vitesse double, inversée", - - "create.schematicAndQuill.dimensions": "Taille du schéma: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Première position définie.", - "create.schematicAndQuill.secondPos": "Seconde position définie.", - "create.schematicAndQuill.noTarget": "Enfoncez [Ctrl] pour sélectionner les blocs d'air.", - "create.schematicAndQuill.abort": "Sélection supprimée.", - "create.schematicAndQuill.title": "Nom du schéma:", - "create.schematicAndQuill.convert": "Enregistrer et déployer immédiatement", - "create.schematicAndQuill.fallbackName": "Mon schéma", - "create.schematicAndQuill.saved": "Sauvegardé en tant que %1$s", - - "create.schematic.invalid": "[!] objet invalide - Utilisez plutôt la table à schéma", - "create.schematic.position": "Position", - "create.schematic.rotation": "Rotation", - "create.schematic.rotation.none": "Aucune", - "create.schematic.rotation.cw90": "Sens horaire 90", - "create.schematic.rotation.cw180": "Sens horaire 180", - "create.schematic.rotation.cw270": "Sens horaire 270", - "create.schematic.mirror": "Mirroir", - "create.schematic.mirror.none": "Aucun", - "create.schematic.mirror.frontBack": "Avant-Arrière", - "create.schematic.mirror.leftRight": "Gauche-Droite", - "create.schematic.tool.deploy": "Déployer", - "create.schematic.tool.move": "Déplacer XZ", - "create.schematic.tool.movey": "Déplacer Y", - "create.schematic.tool.rotate": "Tourner", - "create.schematic.tool.print": "Imprimer", - "create.schematic.tool.flip": "Retourner", - "create.schematic.tool.deploy.description.0": "Déplace la structure vers un emplacement.", - "create.schematic.tool.deploy.description.1": "Clic droit sur le sol pour placer.", - "create.schematic.tool.deploy.description.2": "Maintenez [Ctrl] pour sélectionner à une distance fixe.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Défiler pour changer la distance.", - "create.schematic.tool.move.description.0": "Décale le schéma horizontalement.", - "create.schematic.tool.move.description.1": "Pointez sur le schéma et [CTRL]-Défiler pour le pousser.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Décale le schéma verticalement.", - "create.schematic.tool.movey.description.1": "[CTRL]-Défiler pour le déplacer vers le haut / bas.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Fait pivoter le schéma autour de son centre.", - "create.schematic.tool.rotate.description.1": "[CTRL]-Défiler pour faire une rotation de 90 degrés.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Place instantanément la structure dans le monde.", - "create.schematic.tool.print.description.1": "[Clic droit] pour confirmer le placement à l'emplacement actuel.", - "create.schematic.tool.print.description.2": "Cet outil est uniquement pour le mode créatif.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Retourne le schéma le long de la face que vous sélectionnez.", - "create.schematic.tool.flip.description.1": "Pointez sur le schéma et [CTRL]-Défiler pour le retourner.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Synchronisation...", - "create.schematics.uploadTooLarge": "Votre schéma est trop grand.", - "create.schematics.maxAllowedSize": "La taille de fichier schématique maximale autorisée est:", - - "create.gui.schematicTable.refresh": "Actualiser les fichiers", - "create.gui.schematicTable.open_folder": "Ouvrir le dossier", - "create.gui.schematicTable.title": "Table à schéma", - "create.gui.schematicTable.availableSchematics": "Schémas disponibles", - "create.gui.schematicTable.noSchematics": "Aucun schéma enregistré", - "create.gui.schematicTable.uploading": "Téléchargement...", - "create.gui.schematicTable.finished": "Téléchargement terminé!", - "create.gui.schematicannon.title": "Schémacanon", - "create.gui.schematicannon.listPrinter": "Imprimante de liste de matériaux", - "create.gui.schematicannon.gunpowderLevel": "Poudre à canon à %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Tirs restants: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Avec sauvegarde: %1$s", - "create.gui.schematicannon.optionEnabled": "Actuellement activé", - "create.gui.schematicannon.optionDisabled": "Actuellement désactivé", - "create.gui.schematicannon.showOptions": "Afficher les paramètres d'impression", - "create.gui.schematicannon.option.dontReplaceSolid": "Ne remplacez pas les blocs solides", - "create.gui.schematicannon.option.replaceWithSolid": "Remplacer solide par solide", - "create.gui.schematicannon.option.replaceWithAny": "Remplacer le solide par n'importe quoi", - "create.gui.schematicannon.option.replaceWithEmpty": "Remplacer le solide par rien", - "create.gui.schematicannon.option.skipMissing": "Ignorer les blocs manquants", - "create.gui.schematicannon.option.skipTileEntities": "Protéger les Tile Entities", - "create.gui.schematicannon.slot.gunpowder": "Ajouter de la poudre a canon pour alimenter le canon", - "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", - "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", - "create.gui.schematicannon.option.skipMissing.description": "Si le canon ne peut pas trouver un bloc requis pour le placement, il continuera au prochain emplacement.", - "create.gui.schematicannon.option.skipTileEntities.description": "Le canon évitera de remplacer les blocs de stockage de données tels que les coffres.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Le canon ne remplacera jamais les blocs solides dans sa zone de travail, seulement non solides et air.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Le canon ne remplacera les blocs solides dans sa zone de travail que si le schéma contient un bloc solide à l'emplacement.", - "create.gui.schematicannon.option.replaceWithAny.description": "Le canon remplacera les blocs solides dans sa zone de travail si le schéma contient un bloc à l'emplacement.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Le canon effacera tous les blocs dans sa zone de travail, y compris ceux remplacés par de l'air.", - - "create.schematicannon.status.idle": "Repos", - "create.schematicannon.status.ready": "Prêt", - "create.schematicannon.status.running": "En cours", - "create.schematicannon.status.finished": "Terminé", - "create.schematicannon.status.paused": "Pausé", - "create.schematicannon.status.stopped": "Arrêté", - "create.schematicannon.status.noGunpowder": "Plus de poudre à canon", - "create.schematicannon.status.targetNotLoaded": "Le bloc n'est pas chargé", - "create.schematicannon.status.targetOutsideRange": "Cible trop lointaine", - "create.schematicannon.status.searching": "Recherche", - "create.schematicannon.status.skipping": "Saut", - "create.schematicannon.status.missingBlock": "Blocs manquants:", - "create.schematicannon.status.placing": "Placement", - "create.schematicannon.status.clearing": "Suppression des blocs", - "create.schematicannon.status.schematicInvalid": "Schéma non valide", - "create.schematicannon.status.schematicNotPlaced": "Schéma non déployé", - "create.schematicannon.status.schematicExpired": "Fichier de schéma arrivé à expiration", - - "create.materialChecklist": "Liste des matériaux", - "create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", - - "create.gui.filter.deny_list": "Liste noire", - "create.gui.filter.deny_list.description": "Les articles réussissent s'ils ne correspondent à AUCUN des éléments ci-dessus. Une liste noire vide accepte tout.", - "create.gui.filter.allow_list": "Liste blanche", - "create.gui.filter.allow_list.description": "Les éléments réussissent s'ils correspondent à l'un des éléments ci-dessus. Une liste blanche vide rejette tout.", - "create.gui.filter.respect_data": "Respect des données", - "create.gui.filter.respect_data.description": "Les objets ne correspondent que si leur durabilité, leurs enchantements et autres attributs correspondent également.", - "create.gui.filter.ignore_data": "Ignorer les données", - "create.gui.filter.ignore_data.description": "Les éléments correspondent indépendamment de leurs attributs.", - - "create.item_attributes.placeable": "est placeable", - "create.item_attributes.placeable.inverted": "n'est pas plaçable", - "create.item_attributes.consumable": "peut être mangé", - "create.item_attributes.consumable.inverted": "ne peut pas être mangé", - "create.item_attributes.fluid_container": "UNLOCALIZED: can store fluids", - "create.item_attributes.fluid_container.inverted": "UNLOCALIZED: cannot store fluids", - "create.item_attributes.enchanted": "est enchanté", - "create.item_attributes.enchanted.inverted": "n'est pas enchanté", - "create.item_attributes.max_enchanted": "UNLOCALIZED: is enchanted at max level", - "create.item_attributes.max_enchanted.inverted": "UNLOCALIZED: is not enchanted at max level", - "create.item_attributes.renamed": "UNLOCALIZED: has a custom name", - "create.item_attributes.renamed.inverted": "UNLOCALIZED: does not have a custom name", - "create.item_attributes.damaged": "est endommagé", - "create.item_attributes.damaged.inverted": "n'est pas endomagé", - "create.item_attributes.badly_damaged": "est fortement damaged", - "create.item_attributes.badly_damaged.inverted": "n'est pas fortement endomagé", - "create.item_attributes.not_stackable": "ne peut pas s'empiler", - "create.item_attributes.not_stackable.inverted": "peut être empilé", - "create.item_attributes.equipable": "peut être équipé", - "create.item_attributes.equipable.inverted": "ne peut pas être équipé", - "create.item_attributes.furnace_fuel": "est du combustible", - "create.item_attributes.furnace_fuel.inverted": "n'est pas un combustible", - "create.item_attributes.washable": "peut être lavé", - "create.item_attributes.washable.inverted": "ne peut pas être lavé", - "create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", - "create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", - "create.item_attributes.crushable": "peut être concassé", - "create.item_attributes.crushable.inverted": "ne peut pas être concassé", - "create.item_attributes.smeltable": "peut être fondu", - "create.item_attributes.smeltable.inverted": "ne peut pas être fondu", - "create.item_attributes.smokable": "peut être fumé", - "create.item_attributes.smokable.inverted": "ne peut pas être fumé", - "create.item_attributes.blastable": "est fondable dans un Haut fourneau", - "create.item_attributes.blastable.inverted": "n'est pas fondable dans un Haut fourneau", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "UNLOCALIZED: is shulker %1$s", - "create.item_attributes.shulker_level.inverted": "UNLOCALIZED: is shulker not %1$s", - "create.item_attributes.shulker_level.full": "UNLOCALIZED: full", - "create.item_attributes.shulker_level.empty": "UNLOCALIZED: empty", - "create.item_attributes.shulker_level.partial": "UNLOCALIZED: partially filled", - "create.item_attributes.in_tag": "est étiqueté %1$s", - "create.item_attributes.in_tag.inverted": "n'est pas étiqueté", - "create.item_attributes.in_item_group": "appartient à %1$s", - "create.item_attributes.in_item_group.inverted": "n'appartient pas à %1$s'", - "create.item_attributes.added_by": "a été ajouté par %1$s", - "create.item_attributes.added_by.inverted": "n'a pas été ajouté par %1$s", - "create.item_attributes.has_enchant": "est enchanté %1$s", - "create.item_attributes.has_enchant.inverted": "n'est pas enchenté %1$s", - "create.item_attributes.color": "UNLOCALIZED: is dyed %1$s", - "create.item_attributes.color.inverted": "UNLOCALIZED: is not dyed %1$s", - "create.item_attributes.has_fluid": "contient %1$s", - "create.item_attributes.has_fluid.inverted": "ne contient pas %1$s", - "create.item_attributes.has_name": "est renommé %1$s", - "create.item_attributes.has_name.inverted": "n'est pas renommé %1$s", - "create.item_attributes.book_author": "a été écrit par %1$s", - "create.item_attributes.book_author.inverted": "n'a pas été écrit par %1$s", - "create.item_attributes.book_copy_original": "est originel", - "create.item_attributes.book_copy_original.inverted": "n'est pas originel", - "create.item_attributes.book_copy_first": "UNLOCALIZED: is a first-generation copy", - "create.item_attributes.book_copy_first.inverted": "UNLOCALIZED: is not a first-generation copy", - "create.item_attributes.book_copy_second": "UNLOCALIZED: is a second-generation copy", - "create.item_attributes.book_copy_second.inverted": "UNLOCALIZED: is not a second-generation copy", - "create.item_attributes.book_copy_tattered": "UNLOCALIZED: is a tattered mess", - "create.item_attributes.book_copy_tattered.inverted": "UNLOCALIZED: is not a tattered mess", - "create.item_attributes.astralsorcery_amulet": "UNLOCALIZED: improves %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "UNLOCALIZED: does not improve %1$s", - "create.item_attributes.astralsorcery_constellation": "UNLOCALIZED: is attuned to %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "UNLOCALIZED: is not attuned to %1$s", - "create.item_attributes.astralsorcery_crystal": "UNLOCALIZED: has crystal attribute %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "UNLOCALIZED: does not have crystal attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem": "UNLOCALIZED: has perk attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "UNLOCALIZED: does not have perk attribute %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Aucun attribut sélectionné", - "create.gui.attribute_filter.selected_attributes": "Attributs sélectionnés:", - "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", - "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", - "create.gui.attribute_filter.allow_list_disjunctive": "Liste blanche (n'importe)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Les objets réussissent s'ils possèdent l'un des attributs sélectionnés.", - "create.gui.attribute_filter.allow_list_conjunctive": "Liste blanche (tout)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Les objets ne passent que s'ils ont TOUS les attributs sélectionnés.", - "create.gui.attribute_filter.deny_list": "Liste noire", - "create.gui.attribute_filter.deny_list.description": "Les éléments réussissent s'ils n'ont AUCUN des attributs sélectionnés.", - "create.gui.attribute_filter.add_reference_item": "Ajouter un objet de référence", - - "create.tooltip.holdForDescription": "UNLOCALIZED: Hold [%1$s] for Summary", - "create.tooltip.holdForControls": "UNLOCALIZED: Hold [%1$s] for Controls", - "create.tooltip.keyShift": "Maj", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Vitesse requise: %1$s", - "create.tooltip.speedRequirement.none": "Aucune", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "Modérée", - "create.tooltip.speedRequirement.fast": "Rapide", - "create.tooltip.stressImpact": "Impact du stress: %1$s", - "create.tooltip.stressImpact.low": "Faible", - "create.tooltip.stressImpact.medium": "Modéré", - "create.tooltip.stressImpact.high": "Elevé", - "create.tooltip.stressImpact.overstressed": "Surmené", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Capacité de stress: %1$s", - "create.tooltip.capacityProvided.low": "Petite", - "create.tooltip.capacityProvided.medium": "Moyenne", - "create.tooltip.capacityProvided.high": "Grande", - "create.tooltip.generationSpeed": "Génère à %1$s %2$s", - "create.tooltip.analogStrength": "Force analogique: %1$s/15", - - "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", - "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", - "create.mechanical_arm.summary": "UNLOCALIZED: Mechanical Arm has %1$s input(s) and %2$s output(s).", - "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", - - "create.weighted_ejector.target_set": "UNLOCALIZED: Target Selected", - "create.weighted_ejector.target_not_valid": "UNLOCALIZED: Ejecting to Adjacent block (Target was not Valid)", - "create.weighted_ejector.no_target": "UNLOCALIZED: Ejecting to Adjacent block (No Target was Selected)", - "create.weighted_ejector.targeting": "UNLOCALIZED: Ejecting to [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "UNLOCALIZED: Ejected Stack Size", - - "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", - - "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.mechanical_arm.selection_mode.prefer_first": "UNLOCALIZED: Prefer First Target", - - "create.tunnel.selection_mode.split": "UNLOCALIZED: Split", - "create.tunnel.selection_mode.forced_split": "UNLOCALIZED: Forced Split", - "create.tunnel.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", - "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", - "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", - - "create.tooltip.chute.header": "UNLOCALIZED: Chute Information", - "create.tooltip.chute.items_move_down": "UNLOCALIZED: Items move Downward", - "create.tooltip.chute.items_move_up": "UNLOCALIZED: Items move Upward", - "create.tooltip.chute.no_fans_attached": "UNLOCALIZED: No attached fans", - "create.tooltip.chute.fans_push_up": "UNLOCALIZED: Fans push from Below", - "create.tooltip.chute.fans_push_down": "UNLOCALIZED: Fans push from Above", - "create.tooltip.chute.fans_pull_up": "UNLOCALIZED: Fans pull from Above", - "create.tooltip.chute.fans_pull_down": "UNLOCALIZED: Fans pull from Below", - "create.tooltip.chute.contains": "UNLOCALIZED: Contains: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "UNLOCALIZED: Currently distributing:", - "create.tooltip.brass_tunnel.contains_entry": "UNLOCALIZED: > %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "UNLOCALIZED: Right-Click to retrieve", - - "create.linked_controller.bind_mode": "UNLOCALIZED: Bind mode active", - "create.linked_controller.press_keybind": "UNLOCALIZED: Press %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, to bind this frequency to the respective key", - "create.linked_controller.key_bound": "UNLOCALIZED: Frequency bound to %1$s", - "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", - "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", - "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", - "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", - "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", - "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", - "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", - - "create.potato_cannon.ammo.attack_damage": "UNLOCALIZED: %1$s Attack Damage", - "create.potato_cannon.ammo.reload_ticks": "UNLOCALIZED: %1$s Reload Ticks", - "create.potato_cannon.ammo.knockback": "UNLOCALIZED: %1$s Knockback", - - "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", - "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", - "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", - "create.hint.mechanical_arm_no_targets": "UNLOCALIZED: It appears this _Mechanical_ _Arm_ has not been assigned any _targets._ Select belts, depots, funnels and other blocks by _right-clicking_ them while _holding_ the _Mechanical_ _Arm_ in your _hand_.", - "create.hint.empty_bearing.title": "UNLOCALIZED: Update Bearing", - "create.hint.empty_bearing": "UNLOCALIZED: _Right-click_ the bearing with an _empty_ _hand_ to _attach_ the structure you just built in front of it.", - "create.hint.full_deployer.title": "UNLOCALIZED: Deployer Item Overflow", - "create.hint.full_deployer": "UNLOCALIZED: It appears this _Deployer_ contains _excess_ _items_ that need to be _extracted._ Use a _hopper,_ _funnel_ or other means to free it from its overflow.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", - "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", - "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", - "create.gui.config.overlay4": "UNLOCALIZED: to move this preview", - "create.gui.config.overlay5": "UNLOCALIZED: Press ESC to exit this screen", - "create.gui.config.overlay6": "UNLOCALIZED: and save the new position", - "create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset", - "create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server tick is currently slowed by %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Server tick is slowed by %s ms now >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Server tick is back to regular speed :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: use /killtps stop to bring back server tick to regular speed", - "create.command.killTPSCommand.status.usage.1": "[Create]: use /killtps start to artificially slow down the server tick", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "UNLOCALIZED: This Cart Contraption seems too big to pick up", - "create.contraption.minecart_contraption_illegal_pickup": "UNLOCALIZED: A mystical force is binding this Cart Contraption to the world", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "UNLOCALIZED: Contraption stops", - "create.subtitle.peculiar_bell_use": "UNLOCALIZED: Peculiar Bell tolls", - "create.subtitle.worldshaper_place": "UNLOCALIZED: Worldshaper zaps", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.schematicannon_finish": "Fin de schémacanon", - "create.subtitle.crafter_craft": "UNLOCALIZED: Crafter crafts", - "create.subtitle.wrench_remove": "UNLOCALIZED: Component breaks", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "UNLOCALIZED: Cogwheels rumble", - "create.subtitle.slime_added": "Bruit de slime", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "Tir de schémacanon", - "create.subtitle.controller_take": "UNLOCALIZED: Lectern empties", - "create.subtitle.crafter_click": "UNLOCALIZED: Crafter clicks", - "create.subtitle.depot_plop": "UNLOCALIZED: Item lands", - "create.subtitle.confirm": "UNLOCALIZED: Affirmative ding", - "create.subtitle.mixing": "UNLOCALIZED: Mixing noises", - "create.subtitle.mechanical_press_activation_belt": "UNLOCALIZED: Mechanical Press bonks", - "create.subtitle.fwoomp": "UNLOCALIZED: Potato Launcher fwoomps", - "create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", - "create.subtitle.crushing_1": "UNLOCALIZED: Crushing noises", - "create.subtitle.depot_slide": "UNLOCALIZED: Item slides", - "create.subtitle.blaze_munch": "UNLOCALIZED: Blaze Burner munches", - "create.subtitle.funnel_flap": "UNLOCALIZED: Funnel flaps", - "create.subtitle.haunted_bell_use": "UNLOCALIZED: Haunted Bell tolls", - "create.subtitle.scroll_value": "UNLOCALIZED: Scroll-input clicks", - "create.subtitle.controller_put": "UNLOCALIZED: Controller thumps", - "create.subtitle.cranking": "UNLOCALIZED: Hand Crank turns", - "create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", - "create.subtitle.wrench_rotate": "UNLOCALIZED: Wrench used", - "create.subtitle.potato_hit": "UNLOCALIZED: Vegetable impacts", - "create.subtitle.saw_activate_wood": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "UNLOCALIZED: Haunted Bell awakens", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "UNLOCALIZED: Declining boop", - "create.subtitle.controller_click": "UNLOCALIZED: Controller clicks", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "UNLOCALIZED: Diving equipment clinks", - "create.subtitle.mechanical_press_activation": "Activation de la presse mechanique", - "create.subtitle.contraption_assemble": "UNLOCALIZED: Contraption moves", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "OBJET EXEMPLE (juste une indication que cette info-bulle existe)", - "item.create.example_item.tooltip.summary": "Une brève description de l'objet. Les _underscores_ surligne les mots.", - "item.create.example_item.tooltip.condition1": "Quand ceci", - "item.create.example_item.tooltip.behaviour1": "Donc cet objet fait ceci. (les comportements sont affichés avec shift)", - "item.create.example_item.tooltip.condition2": "Et quand cela", - "item.create.example_item.tooltip.behaviour2": "Vous pouvez ajouter autant de comportements que vous le souhaitez", - "item.create.example_item.tooltip.control1": "Quand Ctrl enfoncé", - "item.create.example_item.tooltip.action1": "Ces commandes sont affichées.", - - "block.create.wooden_bracket.tooltip": "UNLOCALIZED: WOODEN BRACKET", - "block.create.wooden_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with a cozy and wooden bit of reinforcement.", - - "block.create.metal_bracket.tooltip": "UNLOCALIZED: METAL BRACKET", - "block.create.metal_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with an industrial and sturdy bit of reinforcement.", - - "block.create.seat.tooltip": "UNLOCALIZED: SEAT", - "block.create.seat.tooltip.summary": "UNLOCALIZED: Sit yourself down and enjoy the ride! Will anchor a player onto a moving _contraption_. Great for static furniture too! Comes in a variety of colours.", - "block.create.seat.tooltip.condition1": "UNLOCALIZED: Right click on Seat", - "block.create.seat.tooltip.behaviour1": "UNLOCALIZED: Sits the player on the _Seat_. Press L-shift to leave the _Seat_.", - - "item.create.blaze_cake.tooltip": "UNLOCALIZED: BLAZE CAKE", - "item.create.blaze_cake.tooltip.summary": "UNLOCALIZED: A Delicious treat for your hard-working _Blaze Burners_. Gets them all fired up!", - - "item.create.wand_of_symmetry.tooltip": "BÂTON DE SYMÉTRIE", - "item.create.wand_of_symmetry.tooltip.summary": "Reflète parfaitement le placement des blocs sur les plans configurés.", - "item.create.wand_of_symmetry.tooltip.condition1": "Quand positionné dans la barre active", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Reste actif", - "item.create.wand_of_symmetry.tooltip.control1": "Clic droit au sol", - "item.create.wand_of_symmetry.tooltip.action1": "_Créé_ ou _déplace_ le mirroir", - "item.create.wand_of_symmetry.tooltip.control2": "Clic droit dans les airs", - "item.create.wand_of_symmetry.tooltip.action2": "_Retire_ le mirroir actif", - "item.create.wand_of_symmetry.tooltip.control3": "Clic droit en étant accroupi", - "item.create.wand_of_symmetry.tooltip.action3": "Ouvre l'_interface_ _de_ _configuration_", - - "item.create.handheld_worldshaper.tooltip": "TERRAFORMEUR", - "item.create.handheld_worldshaper.tooltip.summary": "Outil pratique pour créer des _paysage_ et _caractéristiques_ _de_ _terrain_.", - "item.create.handheld_worldshaper.tooltip.control1": "Clic gauche sur un bloc", - "item.create.handheld_worldshaper.tooltip.action1": "Définit les blocs placés par l'outil sur le bloc ciblé.", - "item.create.handheld_worldshaper.tooltip.control2": "Clic droit sur un bloc", - "item.create.handheld_worldshaper.tooltip.action2": "Applique le _pinceau_ et l'_outil_ actuellement sélectionnés à l'emplacement ciblé.", - "item.create.handheld_worldshaper.tooltip.control3": "Clic droit en étant accroupi", - "item.create.handheld_worldshaper.tooltip.action3": "Ouvre l'_interface_ _de_ _configuration_", - - "item.create.tree_fertilizer.tooltip": "ENGRAIS POUR ARBRES", - "item.create.tree_fertilizer.tooltip.summary": "Une puissante combinaison de minéraux adaptée pour accélérer la croissance des types d'rotors communs.", - "item.create.tree_fertilizer.tooltip.condition1": "Lorsqu'utilisé sur une pousse d'rotor", - "item.create.tree_fertilizer.tooltip.behaviour1": "Fait pousser des rotors _indépendamment_ de leurs _conditions_ _d'emplacement_", - - "item.create.extendo_grip.tooltip": "UNLOCALIZED: EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "UNLOCALIZED: Boioioing! Greatly _increases reach distance_ of the wielder. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.extendo_grip.tooltip.condition1": "UNLOCALIZED: When in Off-Hand", - "item.create.extendo_grip.tooltip.behaviour1": "UNLOCALIZED: Increases _reach distance_ of items used in the _Main-Hand_.", - "item.create.extendo_grip.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.extendo_grip.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.potato_cannon.tooltip": "UNLOCALIZED: POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "UNLOCALIZED: Fwoomp! Launch your home-grown vegetables at your Enemies. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.potato_cannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "item.create.potato_cannon.tooltip.behaviour1": "UNLOCALIZED: _Shoots_ a suitable item from your _Inventory_.", - "item.create.potato_cannon.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.potato_cannon.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.filter.tooltip": "FILTRE", - "item.create.filter.tooltip.summary": "_Contrôle_ les _sorties_ et _entrées_ de dispositifs logistiques avec plus de _précision_, en les comparant à un _ensemble_ _d'objets_ ou à plusieurs _filtres_ _imbriqués_.", - "item.create.filter.tooltip.condition1": "Quand dans l'emplacement de filtre", - "item.create.filter.tooltip.behaviour1": "_Contrôle_ le flux d'object selon sa _configuration_.", - "item.create.filter.tooltip.condition2": "Clic droit", - "item.create.filter.tooltip.behaviour2": "Ouvre l'_interface_ _de_ _configuration_.", - - "item.create.attribute_filter.tooltip": "FILTRE D'ATTRIBUTS", - "item.create.attribute_filter.tooltip.summary": "_Contrôle_ les _sorties_ et les _entrées_ de dispositifs logistiques avec plus de _précision_, en les comparant à un _ensemble_ _d'objets_ ou à plusieurs _filtres_ _imbriqués_.", - "item.create.attribute_filter.tooltip.condition1": "Quand dans l'emplacement de filtre", - "item.create.attribute_filter.tooltip.behaviour1": "_Contrôle_ le flux d'object selon sa _configuration_.", - "item.create.attribute_filter.tooltip.condition2": "Clic droit", - "item.create.attribute_filter.tooltip.behaviour2": "Ouvre l'_interface_ _de_ _configuration_.", - - "item.create.empty_schematic.tooltip": "SCHÉMA VIDE", - "item.create.empty_schematic.tooltip.summary": "Utilisé comme ingrédient de recette et pour écrire à la _table_ _à_ _schéma_.", - - "item.create.schematic.tooltip": "SCHÉMA", - "item.create.schematic.tooltip.summary": "Contient une structure à positionner et à placer dans le monde. Positionnez l'hologramme comme vous le souhaitez et utilisez un _schémacanon_ pour le construire.", - "item.create.schematic.tooltip.condition1": "Quand tenu en main", - "item.create.schematic.tooltip.behaviour1": "Peut être positionné à l'aide des outils à l'écran.", - "item.create.schematic.tooltip.control1": "Clic droit en étant accroupi", - "item.create.schematic.tooltip.action1": "Ouvre une _interface_ pour rentrer les _coordonées_ correctes.", - - "item.create.schematic_and_quill.tooltip": "SCHÉMA ET PLUME", - "item.create.schematic_and_quill.tooltip.summary": "Utilisé pour enregistrer une structure de votre monde dans un fichier .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Étape 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Sélectionnez deux points d'angle à l'aide du clic droit.", - "item.create.schematic_and_quill.tooltip.condition2": "Étape 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Défilement_ sur les faces pour ajuster la taille. Cliquez à nouveau pour enregistrer.", - "item.create.schematic_and_quill.tooltip.control1": "Clic droit", - "item.create.schematic_and_quill.tooltip.action1": "Sélectionnez un point d'angle / confirmez la sauvegarde.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl maintenu", - "item.create.schematic_and_quill.tooltip.action2": "Sélectionnez des points _dans_ _les_ _airs_. Faites défiler pour régler la distance.", - "item.create.schematic_and_quill.tooltip.control3": "Clic droit en étant accroupi", - "item.create.schematic_and_quill.tooltip.action3": "_Réinitialise_ et supprime la sélection.", - - "block.create.schematicannon.tooltip": "SCHÉMACANON", - "block.create.schematicannon.tooltip.summary": "Tire des blocs pour recréer un _schéma_ déployé dans le monde. Utilise des objets des inventaires adjacents et de la _poudre_ _à_ _canon_ comme carburant.", - "block.create.schematicannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "block.create.schematicannon.tooltip.behaviour1": "UNLOCALIZED: Opens the _Interface_", - - "block.create.schematic_table.tooltip": "TABLE À SCHÉMA", - "block.create.schematic_table.tooltip.summary": "Écrit les schémas enregistrés dans un _schéma_ _vide_.", - "block.create.schematic_table.tooltip.condition1": "Quand donné un schéma vide", - "block.create.schematic_table.tooltip.behaviour1": "Télécharge un fichier choisi à partir de votre dossier de schémas.", - - "item.create.goggles.tooltip": "LUNETTES", - "item.create.goggles.tooltip.summary": "Une paire de lunettes pour augmenter votre vision avec des _informations_ _kinétiques_ utiles.", - "item.create.goggles.tooltip.condition1": "Quand portées", - "item.create.goggles.tooltip.behaviour1": "Affiche des _indicateurs_ _colorés_ correspondants au _niveau_ _de_ _vitesse_ d'un composant cinétique placé ainsi que _l'impact_ du _stress_ et la _capacité_ des composants individuels.", - "item.create.goggles.tooltip.condition2": "Quand vision portée sur une jauge", - "item.create.goggles.tooltip.behaviour2": "Affiche des informations détaillées sur la _vitesse_ ou le _stress_ du réseau auquel la jauge est connectée.", - "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", - "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", - - "item.create.wrench.tooltip": "CLÉ", - "item.create.wrench.tooltip.summary": "Un outil utile pour travailler sur les engins cinétiques. Peut être utilisé pour _tourner_, _démonter_ et _configurer_ les composants.", - "item.create.wrench.tooltip.control1": "Clic droit sur un bloc de Create", - "item.create.wrench.tooltip.action1": "_Tourne_ le _composant_ le long de l'axe dépendant de la face avec lequel vous avez interagi.", - "item.create.wrench.tooltip.control2": "Clic droit en étant accroupi", - "item.create.wrench.tooltip.action2": "_Démonte_ les _composants_ _cinétiques_ et les replace dans _votre_ _inventaire_.", - - "block.create.nozzle.tooltip": "BUSE", - "block.create.nozzle.tooltip.summary": "Attachez-le à l'avant d'un _ventilateur_ enchâssé_ pour répartir son effet sur les entités dans _toutes_ les _directions_.", - - "block.create.cuckoo_clock.tooltip": "COUCOU", - "block.create.cuckoo_clock.tooltip.summary": "Un bel artisanat pour _décorer_ un espace et _garder_ la _notion_ _du_ _temps_.", - "block.create.cuckoo_clock.tooltip.condition1": "Quand tourné", - "block.create.cuckoo_clock.tooltip.behaviour1": "Affiche le _temps_ _présent_ et joue une mélodie deux fois par jour. _S'active_ une fois le _midi_ et une fois au crépuscule, dès que les _joueurs_ _peuvent_ _dormir_.", - - "block.create.turntable.tooltip": "PLAQUE TOURNANTE", - "block.create.turntable.tooltip.summary": "Transforme la _force_ _de_ _rotation_ en énergie cinétique.", - - "block.create.toolbox.tooltip": "UNLOCALIZED: TOOLBOX", - "block.create.toolbox.tooltip.summary": "UNLOCALIZED: Every Inventors' dearest Companion. Conveniently _holds_ a large amount of _8 Different_ item types.", - "block.create.toolbox.tooltip.condition1": "UNLOCALIZED: When Picked Up", - "block.create.toolbox.tooltip.behaviour1": "UNLOCALIZED: _Retains_ Inventory _Contents_.", - "block.create.toolbox.tooltip.condition2": "UNLOCALIZED: When placed in Range", - "block.create.toolbox.tooltip.behaviour2": "UNLOCALIZED: _Nearby_ _Players_ can hold the _Toolbox_ _Keybind_ to access its contents _Remotely_.", - "block.create.toolbox.tooltip.condition3": "UNLOCALIZED: When R-Clicked", - "block.create.toolbox.tooltip.behaviour3": "UNLOCALIZED: Opens the _Container Interface_.", - - "block.create.stockpile_switch.tooltip": "DÉTÉCTEUR DE STOCKAGE", - "block.create.stockpile_switch.tooltip.summary": "Bascule un signal Redstone basé sur _l'espace_ _de_ _stockage_ dans le conteneur attaché.", - "block.create.stockpile_switch.tooltip.condition1": "Lorsqu'en dessous de la limite de stockage minimum", - "block.create.stockpile_switch.tooltip.behaviour1": "Arrête de fournir de _l'énergie_", - - "block.create.content_observer.tooltip": "OBSERVATEUR DE CONTENU", - "block.create.content_observer.tooltip.summary": "_Détecte les objets_ à l'intérieur des _conteneurs_ et des _transporteurs_ correspondant à un _filtre_ configuré. Tant que l'_inventaire_, le _tapis roulant_ ou la _glissière_ observé _contient_ un objet correspondant, ce composant émet un _signal de redstone_. Quand un _entonnoir_ observé _transfère_ un objet correspondant, ce composant émet une _impulsion de redstone_.", - "block.create.content_observer.tooltip.condition1": "UNLOCALIZED: When observing a Container", - "block.create.content_observer.tooltip.behaviour1": "UNLOCALIZED: Emits a _Redstone Signal_ while the observed container has _matching_ _content_.", - "block.create.content_observer.tooltip.condition2": "UNLOCALIZED: When observing a Funnel", - "block.create.content_observer.tooltip.behaviour2": "UNLOCALIZED: Emits a _Redstone Pulse_ when a _matching_ Item is _transferred_.", - - "block.create.creative_crate.tooltip": "CAISSE CRÉATIVE", - "block.create.creative_crate.tooltip.summary": "Fournit une réserve infinie de blocs aux _Schémacanons_ adjacents.", - "block.create.creative_crate.tooltip.condition1": "Quand un objet se trouve dans l'emplacement de filtrage", - "block.create.creative_crate.tooltip.behaviour1": "Tout ce qui _extrait_ de ce conteneur aura une _alimentation illimitée_ de l'objet spécifié. Les objets _insérés_ dans cette caisse seront _éliminés_.", - - "item.create.creative_blaze_cake.tooltip": "UNLOCALIZED: CREATIVE CAKE", - "item.create.creative_blaze_cake.tooltip.summary": "UNLOCALIZED: A very special treat for your _Blaze Burners_. After eating this cake, Blaze Burners will _never run out of fuel_.", - "item.create.creative_blaze_cake.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.creative_blaze_cake.tooltip.behaviour1": "UNLOCALIZED: _Cycles_ a Blaze Burner's heat level.", - - "block.create.controller_rail.tooltip": "UNLOCALIZED: CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "UNLOCALIZED: A _uni-directional powered rail_ capable of _fine control_ over a minecarts' _movement speed_.", - "block.create.controller_rail.tooltip.condition1": "UNLOCALIZED: When Powered by Redstone", - "block.create.controller_rail.tooltip.behaviour1": "UNLOCALIZED: _Accelerates_ or _Decelerates_ passing _minecarts_ corresponding to the _signal strength_. Propagates redstone power to adjacent controller rails. Powering two controller rails with different strengths will cause tracks between them to interpolate their signal.", - - "item.create.sand_paper.tooltip": "PAPIER DE VERRE", - "item.create.sand_paper.tooltip.summary": "Un papier rugueux qui peut être utilisé pour _polir des matériaux_. Peut être appliqué automatiquement à l'aide du déployeur.", - "item.create.sand_paper.tooltip.condition1": "Quand utilisé", - "item.create.sand_paper.tooltip.behaviour1": "Polit les objets qui se tenus dans la _main secondaire_ ou par terre quand on les _regarde_.", - - "item.create.builders_tea.tooltip": "THÉ DU CONSTRUCTEUR", - "item.create.builders_tea.tooltip.summary": "La boisson parfaite pour commencer la journée - _motivante_ et _rasasiante_.", - - "item.create.refined_radiance.tooltip": "ÉCLAT RAFFINÉ", - "item.create.refined_radiance.tooltip.summary": "Un matériau chromatique forgé à partir de _lumière_ _absorbée_.", - "item.create.refined_radiance.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.shadow_steel.tooltip": "ACIER SOMBRE", - "item.create.shadow_steel.tooltip.summary": "Un matériau chromatique forgé _dans_ _le_ _néant_.", - "item.create.shadow_steel.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.linked_controller.tooltip": "UNLOCALIZED: LINKED CONTROLLER", - "item.create.linked_controller.tooltip.summary": "UNLOCALIZED: Grants _handheld_ _control_ over _Redstone Link_ frequencies assigned to its _six_ _buttons_.", - "item.create.linked_controller.tooltip.condition1": "UNLOCALIZED: R-Click", - "item.create.linked_controller.tooltip.behaviour1": "UNLOCALIZED: _Toggles_ the controller. _Movement_ _controls_ are taken over while its active.", - "item.create.linked_controller.tooltip.condition2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.linked_controller.tooltip.behaviour2": "UNLOCALIZED: Opens the manual _Configuration Interface_.", - "item.create.linked_controller.tooltip.condition3": "UNLOCALIZED: R-Click on Redstone Link Receiver", - "item.create.linked_controller.tooltip.behaviour3": "UNLOCALIZED: Enables _Bind Mode_, press one of the _six controls_ to bind it to the _Links' Frequency_.", - "item.create.linked_controller.tooltip.condition4": "UNLOCALIZED: R-Click on Lectern", - "item.create.linked_controller.tooltip.behaviour4": "UNLOCALIZED: Places the Controller into the Lectern for easy activation. (R-Click while Sneaking to retrieve it)", - - "item.create.diving_helmet.tooltip": "UNLOCALIZED: DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "UNLOCALIZED: Together with a _Copper_ _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", - "item.create.diving_helmet.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_helmet.tooltip.behaviour1": "UNLOCALIZED: Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", - - "item.create.copper_backtank.tooltip": "UNLOCALIZED: COPPER BACKTANK", - "item.create.copper_backtank.tooltip.summary": "UNLOCALIZED: A _Wearable_ _Tank_ for carrying Pressurized Air.", - "item.create.copper_backtank.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.copper_backtank.tooltip.behaviour1": "UNLOCALIZED: Provides _Pressurized_ _Air_ to Equipment that requires it.", - "item.create.copper_backtank.tooltip.condition2": "UNLOCALIZED: When placed, Powered by Kinetics", - "item.create.copper_backtank.tooltip.behaviour2": "UNLOCALIZED: _Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "VOLANT D'INERTIE", - "block.create.flywheel.tooltip.summary": "Une grande roue métallique pour _exploiter_ _et_ _stabiliser_ la force générée par un _moteur_ _attaché_. Les volants d'inertie se connectent aux moteurs s'ils sont séparés _d'un_ _mètre_ et tournés à un _angle_ de _90°_ les uns des autres.", - "block.create.flywheel.tooltip.condition1": "Lorsqu'attaché à un moteur en marche", - "block.create.flywheel.tooltip.behaviour1": "Fournit une _force_ _de_ rotation_ à un engin connecté basé sur la force et la vitesse du générateur.", - - "item.create.diving_boots.tooltip": "UNLOCALIZED: DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "UNLOCALIZED: A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", - "item.create.diving_boots.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_boots.tooltip.behaviour1": "UNLOCALIZED: Wielder _sinks_ _faster_ and _cannot_ _swim_. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", - - "item.create.crafting_blueprint.tooltip": "UNLOCALIZED: CRAFTING BLUEPRINT", - "item.create.crafting_blueprint.tooltip.summary": "UNLOCALIZED: _Placed_ on a wall, it can be used to _specify_ _ingredient_ _arrangements_ for easier manual crafting. Each slot represents a Recipe.", - "item.create.crafting_blueprint.condition1": "UNLOCALIZED: R-Click empty Slot", - "item.create.crafting_blueprint.behaviour1": "UNLOCALIZED: Opens a _Crafting_ _menu_ allowing you to _configure_ a _recipe_ and items to display.", - "item.create.crafting_blueprint.condition2": "UNLOCALIZED: R-Click configured Slot", - "item.create.crafting_blueprint.behaviour2": "UNLOCALIZED: _Applies_ the _configured_ _recipe_ with matching Ingredients found in your _Inventory_. _Sneak_ to craft up to a _Stack_ of items.", - - "item.create.minecart_coupling.tooltip": "LIEN POUR WAGONS", - "item.create.minecart_coupling.tooltip.summary": "UNLOCALIZED: _Chains_ all your _Minecarts_ or _Carriage Contraptions_ together to form a majestic Train.", - "item.create.minecart_coupling.tooltip.condition1": "UNLOCALIZED: When Used on Minecart", - "item.create.minecart_coupling.tooltip.behaviour1": "UNLOCALIZED: _Couples_ two Minecarts together, attempting to keep them at a _constant distance_ while moving.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "UNLOCALIZED: PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "UNLOCALIZED: A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may cause side-effects...", - - "block.create.haunted_bell.tooltip": "UNLOCALIZED: HAUNTED BELL", - "block.create.haunted_bell.tooltip.summary": "UNLOCALIZED: A _Cursed Bell_ haunted by lost souls of the Nether.", - "block.create.haunted_bell.tooltip.condition1": "UNLOCALIZED: When Held or Rang", - "block.create.haunted_bell.tooltip.behaviour1": "UNLOCALIZED: Highlights nearby _Lightless Spots_ on which _Hostile Mobs_ can spawn.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", - "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", - "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", - "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", - "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", - "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Super Glue, larger structures can be moved.", - "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", - "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", - "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", - "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", - "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", - "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", - "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", - "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", - "create.ponder.tag.windmill_sails": "UNLOCALIZED: Sails for Windmill Bearings", - "create.ponder.tag.windmill_sails.description": "UNLOCALIZED: Blocks that count towards the strength of a Windmill Contraption when assembled. Each of these have equal efficiency in doing so.", - "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", - "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", - "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", - "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", - "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", - "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", - "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", - "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", - "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", - "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", - "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", - "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", - "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", - "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", - "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", - "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", - "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", - "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", - - "create.ponder.andesite_tunnel.header": "UNLOCALIZED: Using Andesite Tunnels", - "create.ponder.andesite_tunnel.text_1": "UNLOCALIZED: Andesite Tunnels can be used to cover up your belts", - "create.ponder.andesite_tunnel.text_2": "UNLOCALIZED: Whenever an Andesite Tunnel has connections to the sides...", - "create.ponder.andesite_tunnel.text_3": "UNLOCALIZED: ...they will split exactly one item off of any passing stacks", - "create.ponder.andesite_tunnel.text_4": "UNLOCALIZED: The remainder will continue on its path", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "UNLOCALIZED: Processing Items in the Basin", - "create.ponder.basin.text_1": "UNLOCALIZED: A Basin can hold Items and Fluids for Processing", - "create.ponder.basin.text_2": "UNLOCALIZED: After a processing step, basins try to output below to the side of them", - "create.ponder.basin.text_3": "UNLOCALIZED: When a valid component is present, the Basin will show an output faucet", - "create.ponder.basin.text_4": "UNLOCALIZED: A number of options are applicable here", - "create.ponder.basin.text_5": "UNLOCALIZED: Outputs will be caught by the inventory below", - "create.ponder.basin.text_6": "UNLOCALIZED: Without output faucet, the Basin will retain items created in its processing", - "create.ponder.basin.text_7": "UNLOCALIZED: This can be useful if outputs should be re-used as ingredients", - "create.ponder.basin.text_8": "UNLOCALIZED: Desired outputs will then have to be extracted from the basin", - "create.ponder.basin.text_9": "UNLOCALIZED: A Filter might be necessary to avoid pulling out un-processed items", - - "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", - "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", - "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", - - "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", - "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", - "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", - - "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", - "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", - "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", - "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", - "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", - "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", - "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", - - "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", - "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", - "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", - "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", - "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", - "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", - "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions. Belts can span any Length between 2 and 20 blocks", - - "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", - "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", - "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", - - "create.ponder.blaze_burner.header": "UNLOCALIZED: Feeding Blaze Burners", - "create.ponder.blaze_burner.text_1": "UNLOCALIZED: Blaze Burners can provide Heat to Items processed in a Basin", - "create.ponder.blaze_burner.text_2": "UNLOCALIZED: For this, the Blaze has to be fed with flammable items", - "create.ponder.blaze_burner.text_3": "UNLOCALIZED: With a Blaze Cake, the Burner can reach an even stronger level of heat", - "create.ponder.blaze_burner.text_4": "UNLOCALIZED: The feeding process can be automated using Deployers or Mechanical Arms", - - "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", - "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", - "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", - "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", - - "create.ponder.brass_tunnel.header": "UNLOCALIZED: Using Brass Tunnels", - "create.ponder.brass_tunnel.text_1": "UNLOCALIZED: Brass Tunnels can be used to cover up your belts", - "create.ponder.brass_tunnel.text_2": "UNLOCALIZED: Brass Tunnels have filter slots on each open side", - "create.ponder.brass_tunnel.text_3": "UNLOCALIZED: Filters on inbound connections simply block non-matching items", - "create.ponder.brass_tunnel.text_4": "UNLOCALIZED: Filters on outbound connections can be used to sort items by type", - "create.ponder.brass_tunnel.text_5": "UNLOCALIZED: Whenever a passing item has multiple valid exits, the distribution mode will decide how to handle it", - "create.ponder.brass_tunnel.text_6": "UNLOCALIZED: Brass Tunnels on parallel belts will form a group", - "create.ponder.brass_tunnel.text_7": "UNLOCALIZED: Incoming Items will now be distributed across all connected exits", - "create.ponder.brass_tunnel.text_8": "UNLOCALIZED: For this, items can also be inserted into the Tunnel block directly", - - "create.ponder.brass_tunnel_modes.header": "UNLOCALIZED: Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "UNLOCALIZED: Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", - "create.ponder.brass_tunnel_modes.text_10": "UNLOCALIZED: 'Synchronize Inputs' is a unique setting for Brass Tunnels", - "create.ponder.brass_tunnel_modes.text_11": "UNLOCALIZED: Items are only allowed past if every tunnel in the group has one waiting", - "create.ponder.brass_tunnel_modes.text_12": "UNLOCALIZED: This ensures that all affected belts supply items at the same rate", - "create.ponder.brass_tunnel_modes.text_2": "UNLOCALIZED: 'Split' will attempt to distribute the stack evenly between available outputs", - "create.ponder.brass_tunnel_modes.text_3": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_4": "UNLOCALIZED: 'Forced Split' will never skip outputs, and instead wait until they are free", - "create.ponder.brass_tunnel_modes.text_5": "UNLOCALIZED: 'Round Robin' keeps stacks whole, and cycles through outputs iteratively", - "create.ponder.brass_tunnel_modes.text_6": "UNLOCALIZED: Once Again, if an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_7": "UNLOCALIZED: 'Forced Round Robin' never skips outputs", - "create.ponder.brass_tunnel_modes.text_8": "UNLOCALIZED: 'Prefer Nearest' prioritizes the outputs closest to the items' input location", - "create.ponder.brass_tunnel_modes.text_9": "UNLOCALIZED: 'Randomize' will distribute whole stacks to randomly picked outputs", - - "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", - "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", - "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", - "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", - - "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", - "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", - "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", - "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", - - "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", - "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", - "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: This Arrow indicates which side of the Structure will be considered the front", - "create.ponder.cart_assembler_modes.text_3": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", - - "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", - "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", - "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", - "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", - "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", - - "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", - "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", - "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", - "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", - - "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", - "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exactly like Chain Drives", - "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", - "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", - "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", - "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", - "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", - - "create.ponder.chute.header": "UNLOCALIZED: Transporting Items downward via Chutes", - "create.ponder.chute.text_1": "UNLOCALIZED: Chutes can transport items vertically from and to inventories", - "create.ponder.chute.text_2": "UNLOCALIZED: Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "UNLOCALIZED: Placing chutes targeting the side faces of another will make it diagonal", - - "create.ponder.chute_upward.header": "UNLOCALIZED: Transporting Items upward via Chutes", - "create.ponder.chute_upward.text_1": "UNLOCALIZED: Using Encased Fans at the top or bottom, a Chute can move items upward", - "create.ponder.chute_upward.text_2": "UNLOCALIZED: Inspecting chutes with Engineers' Goggles reveals information about the movement direction", - "create.ponder.chute_upward.text_3": "UNLOCALIZED: On the 'blocked' end, items will have to be inserted/taken from the sides", - - "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", - "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", - "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", - "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", - "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", - "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", - "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", - "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure that the two Structures are not glued to each other", - "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", - - "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", - "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", - "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", - - "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", - "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", - "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", - "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", - - "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", - "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", - "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "UNLOCALIZED: Creative Fluid Tanks", - "create.ponder.creative_fluid_tank.text_1": "UNLOCALIZED: Creative Fluid Tanks can be used to provide a bottomless supply of fluid", - "create.ponder.creative_fluid_tank.text_2": "UNLOCALIZED: Right-Click with a fluid containing item to configure it", - "create.ponder.creative_fluid_tank.text_3": "UNLOCALIZED: Pipe Networks can now endlessly draw the assigned fluid from the tank", - "create.ponder.creative_fluid_tank.text_4": "UNLOCALIZED: Any Fluids pushed back into a Creative Fluid Tank will be voided", - - "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", - "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "UNLOCALIZED: Processing Items with Crushing Wheels", - "create.ponder.crushing_wheels.text_1": "UNLOCALIZED: A pair of Crushing Wheels can grind items very effectively", - "create.ponder.crushing_wheels.text_2": "UNLOCALIZED: Their Rotational Input has to make them spin into each other", - "create.ponder.crushing_wheels.text_3": "UNLOCALIZED: Items thrown or inserted into the top will get processed", - "create.ponder.crushing_wheels.text_4": "UNLOCALIZED: Items can be inserted and picked up through automated means as well", - - "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", - "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", - "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", - "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", - "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", - "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", - "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", - "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", - "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", - "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", - "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", - "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", - "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", - "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", - "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", - "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", - - "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", - "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", - "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", - "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", - - "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", - "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", - "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", - - "create.ponder.deployer_processing.header": "UNLOCALIZED: Processing Items using Deployers", - "create.ponder.deployer_processing.text_1": "UNLOCALIZED: With a fitting held item, Deployers can process items provided beneath them", - "create.ponder.deployer_processing.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Deployer", - "create.ponder.deployer_processing.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.deployer_processing.text_4": "UNLOCALIZED: The Deployer will hold and process them automatically", - - "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", - "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", - "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", - "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.depot.header": "UNLOCALIZED: Using Depots", - "create.ponder.depot.text_1": "UNLOCALIZED: Depots can serve as 'stationary' belt elements", - "create.ponder.depot.text_2": "UNLOCALIZED: Right-Click to manually place or remove Items from it", - "create.ponder.depot.text_3": "UNLOCALIZED: Just like Mechanical Belts, it can provide items to processing", - "create.ponder.depot.text_4": "UNLOCALIZED: ...as well as provide Items to Mechanical Arms", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "UNLOCALIZED: Using Empty Blaze Burners", - "create.ponder.empty_blaze_burner.text_1": "UNLOCALIZED: Right-click a Blaze with the empty burner to capture it", - "create.ponder.empty_blaze_burner.text_2": "UNLOCALIZED: Alternatively, Blazes can be collected from their Spawners directly", - "create.ponder.empty_blaze_burner.text_3": "UNLOCALIZED: You now have an ideal heat source for various machines", - "create.ponder.empty_blaze_burner.text_4": "UNLOCALIZED: For Aesthetic purposes, Empty Blaze Burners can also be lit using Flint and Steel", - "create.ponder.empty_blaze_burner.text_5": "UNLOCALIZED: The flame can be transformed using a soul-infused item", - "create.ponder.empty_blaze_burner.text_6": "UNLOCALIZED: However, without a blaze they are not suitable for industrial heating", - - "create.ponder.encased_fluid_pipe.header": "UNLOCALIZED: Encasing Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_1": "UNLOCALIZED: Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "UNLOCALIZED: Aside from being conceiled, Encased Pipes are locked into their connectivity state", - "create.ponder.encased_fluid_pipe.text_3": "UNLOCALIZED: It will no longer react to any neighbouring blocks being added or removed", - - "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", - "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", - - "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", - "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", - "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", - "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", - "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", - "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", - "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", - "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", - - "create.ponder.fluid_pipe_flow.header": "UNLOCALIZED: Moving Fluids using Copper Pipes", - "create.ponder.fluid_pipe_flow.text_1": "UNLOCALIZED: Fluid Pipes can connect two or more fluid sources and targets", - "create.ponder.fluid_pipe_flow.text_2": "UNLOCALIZED: Using a wrench, a straight pipe segment can be given a window", - "create.ponder.fluid_pipe_flow.text_3": "UNLOCALIZED: Windowed pipes will not connect to any other adjacent pipe segments", - "create.ponder.fluid_pipe_flow.text_4": "UNLOCALIZED: Powered by Mechanical Pumps, the Pipes can transport Fluids", - "create.ponder.fluid_pipe_flow.text_5": "UNLOCALIZED: No fluid is being extracted at first", - "create.ponder.fluid_pipe_flow.text_6": "UNLOCALIZED: Once the flow connects them, the endpoints gradually transfer their contents", - "create.ponder.fluid_pipe_flow.text_7": "UNLOCALIZED: Thus, the Pipe blocks themselves never 'physically' contain any fluid", - - "create.ponder.fluid_pipe_interaction.header": "UNLOCALIZED: Draining and Filling fluid containers", - "create.ponder.fluid_pipe_interaction.text_1": "UNLOCALIZED: Endpoints of a pipe network can interact with a variety of blocks", - "create.ponder.fluid_pipe_interaction.text_2": "UNLOCALIZED: Any block with fluid storage capabilities can be filled or drained", - "create.ponder.fluid_pipe_interaction.text_3": "UNLOCALIZED: Source blocks right in front of an open end can be picked up...", - "create.ponder.fluid_pipe_interaction.text_4": "UNLOCALIZED: ...while spilling into empty spaces can create fluid sources", - "create.ponder.fluid_pipe_interaction.text_5": "UNLOCALIZED: Pipes can also extract fluids from a handful of other blocks directly", - - "create.ponder.fluid_tank_sizes.header": "UNLOCALIZED: Dimensions of a Fluid tank", - "create.ponder.fluid_tank_sizes.text_1": "UNLOCALIZED: Fluid Tanks can be combined to increase the total capacity", - "create.ponder.fluid_tank_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.fluid_tank_sizes.text_3": "UNLOCALIZED: ...and grow in height by more than 30 additional layers", - "create.ponder.fluid_tank_sizes.text_4": "UNLOCALIZED: Using a Wrench, a tanks' window can be toggled", - - "create.ponder.fluid_tank_storage.header": "UNLOCALIZED: Storing Fluids in Fluid Tanks", - "create.ponder.fluid_tank_storage.text_1": "UNLOCALIZED: Fluid Tanks can be used to store large amounts of fluid", - "create.ponder.fluid_tank_storage.text_2": "UNLOCALIZED: Pipe networks can push and pull fluids from any side", - "create.ponder.fluid_tank_storage.text_3": "UNLOCALIZED: The contained fluid can be measured by a Comparator", - "create.ponder.fluid_tank_storage.text_4": "UNLOCALIZED: However, in Survival Mode Fluids cannot be added or taken manually", - "create.ponder.fluid_tank_storage.text_5": "UNLOCALIZED: You can use Basins, Item Drains and Spouts to drain or fill fluid containing items", - - "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", - "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", - "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", - "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", - "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", - - "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", - "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", - "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", - "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", - "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", - "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", - - "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", - "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", - - "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", - "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting", - - "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", - "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", - "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", - "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement. A mechanical belt should help here.", - - "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", - "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", - "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", - "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", - "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", - "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", - - "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", - "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", - "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", - "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", - "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", - - "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", - "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", - "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", - - "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", - "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", - "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", - "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", - "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", - "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", - "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", - - "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", - "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", - "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", - - "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", - "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", - "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - - "create.ponder.hose_pulley.header": "UNLOCALIZED: Source Filling and Draining using Hose Pulleys", - "create.ponder.hose_pulley.text_1": "UNLOCALIZED: Hose Pulleys can be used to fill or drain large bodies of Fluid", - "create.ponder.hose_pulley.text_2": "UNLOCALIZED: With the Kinetic Input, the height of the pulleys' hose can be controlled", - "create.ponder.hose_pulley.text_3": "UNLOCALIZED: The Pulley retracts while the input rotation is inverted", - "create.ponder.hose_pulley.text_4": "UNLOCALIZED: On the opposite side, pipes can be connected", - "create.ponder.hose_pulley.text_5": "UNLOCALIZED: Attached pipe networks can either provide fluid to the hose...", - "create.ponder.hose_pulley.text_6": "UNLOCALIZED: ...or pull from it, draining the pool instead", - "create.ponder.hose_pulley.text_7": "UNLOCALIZED: Fill and Drain speed of the pulley depends entirely on the fluid networks' throughput", - - "create.ponder.hose_pulley_infinite.header": "UNLOCALIZED: Passively Filling and Draining large bodies of Fluid", - "create.ponder.hose_pulley_infinite.text_1": "UNLOCALIZED: When deploying the Hose Pulley into a large enough ocean...", - "create.ponder.hose_pulley_infinite.text_2": "UNLOCALIZED: It will provide/dispose fluids without affecting the source", - "create.ponder.hose_pulley_infinite.text_3": "UNLOCALIZED: Pipe networks can limitlessly take fluids from/to such pulleys", - - "create.ponder.hose_pulley_level.header": "UNLOCALIZED: Fill and Drain level of Hose Pulleys", - "create.ponder.hose_pulley_level.text_1": "UNLOCALIZED: While fully retracted, the Hose Pulley cannot operate", - "create.ponder.hose_pulley_level.text_2": "UNLOCALIZED: Draining runs from top to bottom", - "create.ponder.hose_pulley_level.text_3": "UNLOCALIZED: The surface level will end up just below where the hose ends", - "create.ponder.hose_pulley_level.text_4": "UNLOCALIZED: Filling runs from bottom to top", - "create.ponder.hose_pulley_level.text_5": "UNLOCALIZED: The filled pool will not grow beyond the layer above the hose end", - - "create.ponder.item_drain.header": "UNLOCALIZED: Emptying Fluid Containers using Item Drains", - "create.ponder.item_drain.text_1": "UNLOCALIZED: Item Drains can extract fluids from items", - "create.ponder.item_drain.text_2": "UNLOCALIZED: Right-click it to pour fluids from your held item into it", - "create.ponder.item_drain.text_3": "UNLOCALIZED: When items are inserted from the side...", - "create.ponder.item_drain.text_4": "UNLOCALIZED: ...they roll across, emptying out their contained fluid", - "create.ponder.item_drain.text_5": "UNLOCALIZED: Pipe Networks can now pull the fluid from the drains' internal buffer", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", - "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", - "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", - - "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", - "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", - "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", - "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", - "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", - "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", - - "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "UNLOCALIZED: Setting up Mechanical Arms", - "create.ponder.mechanical_arm.text_1": "UNLOCALIZED: Mechanical Arms have to be assigned their in- and outputs before they are placed", - "create.ponder.mechanical_arm.text_2": "UNLOCALIZED: Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "UNLOCALIZED: Right-Click again to toggle between Input (Blue) and Output (Orange)", - "create.ponder.mechanical_arm.text_4": "UNLOCALIZED: Left-Click components to remove their Selection", - "create.ponder.mechanical_arm.text_5": "UNLOCALIZED: Once placed, the Mechanical Arm will target the blocks selected previously", - "create.ponder.mechanical_arm.text_6": "UNLOCALIZED: They can have any amount of in- and outputs within their range", - "create.ponder.mechanical_arm.text_7": "UNLOCALIZED: However, not every type of Inventory can be interacted with directly", - "create.ponder.mechanical_arm.text_8": "UNLOCALIZED: Funnels and Depots can help to Bridge that gap", - - "create.ponder.mechanical_arm_filtering.header": "UNLOCALIZED: Filtering Outputs of the Mechanical Arm", - "create.ponder.mechanical_arm_filtering.text_1": "UNLOCALIZED: Inputs", - "create.ponder.mechanical_arm_filtering.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_filtering.text_3": "UNLOCALIZED: Sometimes it is desirable to restrict targets of the Arm by matching a filter", - "create.ponder.mechanical_arm_filtering.text_4": "UNLOCALIZED: Mechanical Arms by themselves do not provide any options for filtering", - "create.ponder.mechanical_arm_filtering.text_5": "UNLOCALIZED: Brass Funnels as Targets do however communicate their own filter to the Arm", - "create.ponder.mechanical_arm_filtering.text_6": "UNLOCALIZED: The Arm is smart enough not to pick up items it couldn't distribute", - - "create.ponder.mechanical_arm_modes.header": "UNLOCALIZED: Distribution modes of the Mechanical Arm", - "create.ponder.mechanical_arm_modes.text_1": "UNLOCALIZED: Input", - "create.ponder.mechanical_arm_modes.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_modes.text_3": "UNLOCALIZED: Whenever an Arm has to choose between multiple valid outputs...", - "create.ponder.mechanical_arm_modes.text_4": "UNLOCALIZED: ...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "UNLOCALIZED: Scrolling with a Wrench will allow you to configure it", - "create.ponder.mechanical_arm_modes.text_6": "UNLOCALIZED: Round Robin mode simply cycles through all outputs that are available", - "create.ponder.mechanical_arm_modes.text_7": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.mechanical_arm_modes.text_8": "UNLOCALIZED: Forced Round Robin mode will never skip outputs, and instead wait until they are free", - "create.ponder.mechanical_arm_modes.text_9": "UNLOCALIZED: Prefer First prioritizes the outputs selected earliest when configuring this Arm", - - "create.ponder.mechanical_arm_redstone.header": "UNLOCALIZED: Controlling Mechanical Arms with Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Mechanical Arms will not activate", - "create.ponder.mechanical_arm_redstone.text_2": "UNLOCALIZED: Before stopping, it will finish any started cycles", - "create.ponder.mechanical_arm_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", - "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", - "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", - - "create.ponder.mechanical_crafter.header": "UNLOCALIZED: Setting up Mechanical Crafters", - "create.ponder.mechanical_crafter.text_1": "UNLOCALIZED: An array of Mechanical Crafters can be used to automate any Crafting Recipe", - "create.ponder.mechanical_crafter.text_2": "UNLOCALIZED: Using a Wrench, the Crafters' paths can be arranged", - "create.ponder.mechanical_crafter.text_3": "UNLOCALIZED: For a valid setup, all paths have to converge into one exit at any side", - "create.ponder.mechanical_crafter.text_4": "UNLOCALIZED: The outputs will be placed into the inventory at the exit", - "create.ponder.mechanical_crafter.text_5": "UNLOCALIZED: Mechanical Crafters require Rotational Force to operate", - "create.ponder.mechanical_crafter.text_6": "UNLOCALIZED: Right-Click the front to insert Items manually", - "create.ponder.mechanical_crafter.text_7": "UNLOCALIZED: Once every slot of a path contains an Item, the crafting process will begin", - "create.ponder.mechanical_crafter.text_8": "UNLOCALIZED: For recipes not fully occupying the crafter setup, the start can be forced using a Redstone Pulse", - - "create.ponder.mechanical_crafter_connect.header": "UNLOCALIZED: Connecting Inventories of Crafters", - "create.ponder.mechanical_crafter_connect.text_1": "UNLOCALIZED: Items can be inserted to Crafters automatically", - "create.ponder.mechanical_crafter_connect.text_2": "UNLOCALIZED: Using the Wrench at their backs, Mechanical Crafter inputs can be combined", - "create.ponder.mechanical_crafter_connect.text_3": "UNLOCALIZED: All connected Crafters can now be accessed by the same input location", - - "create.ponder.mechanical_crafter_covers.header": "UNLOCALIZED: Covering slots of Mechanical Crafters", - "create.ponder.mechanical_crafter_covers.text_1": "UNLOCALIZED: Some recipes will require additional Crafters to bridge gaps in the path", - "create.ponder.mechanical_crafter_covers.text_2": "UNLOCALIZED: Using Slot Covers, Crafters can be set to act as an Empty Slot in the arrangement", - "create.ponder.mechanical_crafter_covers.text_3": "UNLOCALIZED: Shared Inputs created with the Wrench at the back can also reach across covered Crafters", - - "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", - "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", - "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", - - "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", - "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", - "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", - - "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", - "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", - "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", - - "create.ponder.mechanical_mixer.header": "UNLOCALIZED: Processing Items with the Mechanical Mixer", - "create.ponder.mechanical_mixer.text_1": "UNLOCALIZED: With a Mixer and Basin, some Crafting Recipes can be automated", - "create.ponder.mechanical_mixer.text_2": "UNLOCALIZED: Available recipes include any Shapeless Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_mixer.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_mixer.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", - "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", - "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", - "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", - - "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", - "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", - "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", - "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", - "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", - "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", - "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", - - "create.ponder.mechanical_press.header": "UNLOCALIZED: Processing Items with the Mechanical Press", - "create.ponder.mechanical_press.text_1": "UNLOCALIZED: The Mechanical Press can process items provided beneath it", - "create.ponder.mechanical_press.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Press", - "create.ponder.mechanical_press.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.mechanical_press.text_4": "UNLOCALIZED: The Press will hold and process them automatically", - - "create.ponder.mechanical_press_compacting.header": "UNLOCALIZED: Compacting items with the Mechanical Press", - "create.ponder.mechanical_press_compacting.text_1": "UNLOCALIZED: Pressing items held in a Basin will cause them to be Compacted", - "create.ponder.mechanical_press_compacting.text_2": "UNLOCALIZED: Compacting includes any filled 2x2 or 3x3 Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_press_compacting.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_press_compacting.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_pump_flow.header": "UNLOCALIZED: Fluid Transportation using Mechanical Pumps", - "create.ponder.mechanical_pump_flow.text_1": "UNLOCALIZED: Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "UNLOCALIZED: When powered, their arrow indicates the direction of flow", - "create.ponder.mechanical_pump_flow.text_3": "UNLOCALIZED: The network behind is now pulling fluids...", - "create.ponder.mechanical_pump_flow.text_4": "UNLOCALIZED: ...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "UNLOCALIZED: Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "UNLOCALIZED: Use a Wrench to reverse the orientation of pumps manually", - - "create.ponder.mechanical_pump_speed.header": "UNLOCALIZED: Throughput of Mechanical Pumps", - "create.ponder.mechanical_pump_speed.text_1": "UNLOCALIZED: Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", - "create.ponder.mechanical_pump_speed.text_2": "UNLOCALIZED: Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "UNLOCALIZED: ...aswell as how quickly fluids are transferred", - "create.ponder.mechanical_pump_speed.text_4": "UNLOCALIZED: Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "UNLOCALIZED: Alternating their orientation can help align their flow directions", - - "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", - "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", - "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", - - "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", - "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", - "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", - - "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", - "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", - "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", - "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", - "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", - "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", - - "create.ponder.millstone.header": "UNLOCALIZED: Processing Items in the Millstone", - "create.ponder.millstone.text_1": "UNLOCALIZED: Millstones process items by grinding them", - "create.ponder.millstone.text_2": "UNLOCALIZED: They can be powered from the side using cogwheels", - "create.ponder.millstone.text_3": "UNLOCALIZED: Throw or Insert items at the top", - "create.ponder.millstone.text_4": "UNLOCALIZED: After some time, the result can be obtained via Right-click", - "create.ponder.millstone.text_5": "UNLOCALIZED: The outputs can also be extracted by automation", - - "create.ponder.nixie_tube.header": "UNLOCALIZED: Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "UNLOCALIZED: When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "UNLOCALIZED: Using name tags edited with an anvil, custom text can be displayed", - "create.ponder.nixie_tube.text_3": "UNLOCALIZED: Right-Click with Dye to change their display colour", - - "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", - "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", - "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", - - "create.ponder.portable_fluid_interface.header": "UNLOCALIZED: Contraption Fluid Exchange", - "create.ponder.portable_fluid_interface.text_1": "UNLOCALIZED: Fluid Tanks on moving contraptions cannot be accessed by any pipes", - "create.ponder.portable_fluid_interface.text_2": "UNLOCALIZED: This component can interact with fluid tanks without the need to stop the contraption", - "create.ponder.portable_fluid_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_fluid_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_fluid_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL Tanks on the contraption", - "create.ponder.portable_fluid_interface.text_6": "UNLOCALIZED: Fluid can now be inserted...", - "create.ponder.portable_fluid_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_fluid_interface.text_8": "UNLOCALIZED: After no contents have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", - "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", - "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", - "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", - - "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", - "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", - "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", - "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", - "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", - - "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", - "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", - "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", - "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", - "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", - "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", - "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", - "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", - "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", - "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", - "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", - "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", - - "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", - "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", - "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", - - "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", - "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", - "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", - "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", - "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", - "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", - "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", - - "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", - "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", - "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", - - "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", - "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", - "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", - "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", - - "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", - "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", - "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", - "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", - - "create.ponder.sail.header": "UNLOCALIZED: Assembling Windmills using Sails", - "create.ponder.sail.text_1": "UNLOCALIZED: Sails are handy blocks to create Windmills with", - "create.ponder.sail.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - "create.ponder.sail.text_3": "UNLOCALIZED: Right-Click with Dye to paint them", - "create.ponder.sail.text_4": "UNLOCALIZED: Right-Click with Shears to turn them back into frames", - - "create.ponder.sail_frame.header": "UNLOCALIZED: Assembling Windmills using Sail Frames", - "create.ponder.sail_frame.text_1": "UNLOCALIZED: Sail Frames are handy blocks to create Windmills with", - "create.ponder.sail_frame.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", - "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", - "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", - "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", - "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", - "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", - - "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", - "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", - - "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", - "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", - - "create.ponder.smart_chute.header": "UNLOCALIZED: Filtering Items using Smart Chutes", - "create.ponder.smart_chute.text_1": "UNLOCALIZED: Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "UNLOCALIZED: Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "UNLOCALIZED: Use the Mouse Wheel to specify the extracted stack size", - "create.ponder.smart_chute.text_4": "UNLOCALIZED: Redstone power will prevent Smart Chutes from acting.", - - "create.ponder.smart_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Smart Pipes", - "create.ponder.smart_pipe.text_1": "UNLOCALIZED: Smart pipes can help control flows by fluid type", - "create.ponder.smart_pipe.text_2": "UNLOCALIZED: When placed directly at the source, they can specify the type of fluid to extract", - "create.ponder.smart_pipe.text_3": "UNLOCALIZED: Simply Right-Click their filter slot with any item containing the desired fluid", - "create.ponder.smart_pipe.text_4": "UNLOCALIZED: When placed further down a pipe network, smart pipes will only let matching fluids continue", - - "create.ponder.speedometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "UNLOCALIZED: The Speedometer displays the current Speed of the attached components", - "create.ponder.speedometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.speedometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Speedometer's measurements", - - "create.ponder.spout_filling.header": "UNLOCALIZED: Filling Items using a Spout", - "create.ponder.spout_filling.text_1": "UNLOCALIZED: The Spout can fill fluid holding items provided beneath it", - "create.ponder.spout_filling.text_2": "UNLOCALIZED: The content of a Spout cannot be accessed manually", - "create.ponder.spout_filling.text_3": "UNLOCALIZED: Instead, Pipes can be used to supply it with fluids", - "create.ponder.spout_filling.text_4": "UNLOCALIZED: The Input items can be placed on a Depot under the Spout", - "create.ponder.spout_filling.text_5": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.spout_filling.text_6": "UNLOCALIZED: The Spout will hold and process them automatically", - - "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", - "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", - "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", - "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", - "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", - "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", - "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", - "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", - "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", - - "create.ponder.stressometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Stressometer", - "create.ponder.stressometer.text_1": "UNLOCALIZED: The Stressometer displays the current Stress Capacity of the attached kinetic network", - "create.ponder.stressometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.stressometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Stressometer's measurements", - - "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", - "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue groups blocks together into moving contraptions", - "create.ponder.super_glue.text_2": "UNLOCALIZED: Clicking two endpoints creates a new 'glued' area", - "create.ponder.super_glue.text_3": "UNLOCALIZED: To remove a box, punch it with the glue item in hand", - "create.ponder.super_glue.text_4": "UNLOCALIZED: Adjacent blocks sharing an area will pull each other along", - "create.ponder.super_glue.text_5": "UNLOCALIZED: Overlapping glue volumes will move together", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", - - "create.ponder.valve_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Valves", - "create.ponder.valve_pipe.text_1": "UNLOCALIZED: Valve pipes help control fluids propagating through pipe networks", - "create.ponder.valve_pipe.text_2": "UNLOCALIZED: Their shaft input controls whether fluid is currently allowed through", - "create.ponder.valve_pipe.text_3": "UNLOCALIZED: Given Rotational Force in the opening direction, the valve will open up", - "create.ponder.valve_pipe.text_4": "UNLOCALIZED: It can be closed again by reversing the input rotation", - - "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", - "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", - - "create.ponder.weighted_ejector.header": "UNLOCALIZED: Using Weighted Ejectors", - "create.ponder.weighted_ejector.text_1": "UNLOCALIZED: Sneak and Right-Click holding an Ejector to select its target location", - "create.ponder.weighted_ejector.text_10": "UNLOCALIZED: It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "UNLOCALIZED: Other Entities will always trigger an Ejector when stepping on it", - "create.ponder.weighted_ejector.text_2": "UNLOCALIZED: The placed ejector will now launch objects to the marked location", - "create.ponder.weighted_ejector.text_3": "UNLOCALIZED: A valid target can be at any height or distance within range", - "create.ponder.weighted_ejector.text_4": "UNLOCALIZED: They cannot however be off to a side", - "create.ponder.weighted_ejector.text_5": "UNLOCALIZED: If no valid Target was selected, it will simply target the block directly in front", - "create.ponder.weighted_ejector.text_6": "UNLOCALIZED: Supply Rotational Force in order to charge it up", - "create.ponder.weighted_ejector.text_7": "UNLOCALIZED: Items placed on the ejector cause it to trigger", - "create.ponder.weighted_ejector.text_8": "UNLOCALIZED: If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "UNLOCALIZED: Using the Wrench, a required Stack Size can be configured", - - "create.ponder.weighted_ejector_redstone.header": "UNLOCALIZED: Controlling Weighted Ejectors with Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "UNLOCALIZED: Furthermore, Observers can detect when Ejectors activate", - - "create.ponder.weighted_ejector_tunnel.header": "UNLOCALIZED: Splitting item stacks using Weighted Ejectors", - "create.ponder.weighted_ejector_tunnel.text_1": "UNLOCALIZED: Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", - "create.ponder.weighted_ejector_tunnel.text_2": "UNLOCALIZED: First, configure the Brass Tunnel to 'Prefer Nearest', in order to prioritize its side output", - "create.ponder.weighted_ejector_tunnel.text_3": "UNLOCALIZED: The Stack Size set on the Ejector now determines the amount to be split off", - "create.ponder.weighted_ejector_tunnel.text_4": "UNLOCALIZED: While a new stack of the configured size exits the side output...", - "create.ponder.weighted_ejector_tunnel.text_5": "UNLOCALIZED: ...the remainder will continue on its path", - - "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", - "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", - "create.ponder.windmill_source.text_2": "UNLOCALIZED: Create a movable structure with the help of Super Glue", - "create.ponder.windmill_source.text_3": "UNLOCALIZED: If enough Sail-like blocks are included, this can act as a Windmill", - "create.ponder.windmill_source.text_4": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", - "create.ponder.windmill_source.text_5": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "UNLOCALIZED: Use a Wrench to configure its rotation direction", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", - "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json deleted file mode 100644 index 8567104e05..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 3", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Finestra di acacia", - "block.create.acacia_window_pane": "Pannello di finestra di acacia", - "block.create.adjustable_chain_gearshift": "Cambio a catena regolabile", - "block.create.analog_lever": "Leva analogica", - "block.create.andesite_belt_funnel": "Imbuto di andesite su nastro", - "block.create.andesite_casing": "Rivestimento di andesite", - "block.create.andesite_encased_cogwheel": "Ingranaggio rivestito in andesite", - "block.create.andesite_encased_large_cogwheel": "Ingranaggio grande rivestito in andesite", - "block.create.andesite_encased_shaft": "Asse rivestita in andesite", - "block.create.andesite_funnel": "Imbuto di andesite", - "block.create.andesite_ladder": "Scala a pioli in andesite", - "block.create.andesite_pillar": "Pilastro di andesite", - "block.create.andesite_tunnel": "Tunnel di andesite", - "block.create.asurine": "Azurite", - "block.create.asurine_pillar": "Pilastro di azurite", - "block.create.basin": "Vasca", - "block.create.belt": "Nastro", - "block.create.birch_window": "Finestra di betulla", - "block.create.birch_window_pane": "Pannello di finestra di betulla", - "block.create.black_nixie_tube": "Tubo Nixie nero", - "block.create.black_sail": "Vela nera", - "block.create.black_seat": "Sedile nero", - "block.create.black_toolbox": "Cassetta degli attrezzi nera", - "block.create.black_valve_handle": "Maniglia per valvola nera", - "block.create.blaze_burner": "Inceneritore a blaze", - "block.create.blue_nixie_tube": "Tubo Nixie blu", - "block.create.blue_sail": "Vela blu", - "block.create.blue_seat": "Sedile blu", - "block.create.blue_toolbox": "Cassetta degli attrezzi blu", - "block.create.blue_valve_handle": "Maniglia per valvola blu", - "block.create.brass_belt_funnel": "Imbuto di ottone su nastro", - "block.create.brass_block": "Blocco di ottone", - "block.create.brass_casing": "Rivestimento di ottone", - "block.create.brass_encased_cogwheel": "Ingranaggio rivestito in ottone", - "block.create.brass_encased_large_cogwheel": "Ingranaggio grande rivestito in ottone", - "block.create.brass_encased_shaft": "Asse rivestita in ottone", - "block.create.brass_funnel": "Imbuto di ottone", - "block.create.brass_ladder": "Scala a pioli in ottone", - "block.create.brass_tunnel": "Tunnel di ottone", - "block.create.brown_nixie_tube": "Tubo Nixie marrone", - "block.create.brown_sail": "Vela marrone", - "block.create.brown_seat": "Sedile marrone", - "block.create.brown_toolbox": "Cassetta degli attrezzi marrone", - "block.create.brown_valve_handle": "Maniglia per valvola marrone", - "block.create.calcite_pillar": "Pilastro di calcite", - "block.create.cart_assembler": "Assemblatore di carrelli", - "block.create.chocolate": "Cioccolato", - "block.create.chute": "Scivolo", - "block.create.clockwork_bearing": "Supporto per orologi", - "block.create.clutch": "Frizione", - "block.create.cogwheel": "Ingranaggio", - "block.create.content_observer": "Osservatore di contenuti", - "block.create.controller_rail": "Binario di controllo", - "block.create.controls": "Comandi del treno", - "block.create.copper_backtank": "Zaino serbatoio", - "block.create.copper_casing": "Rivestimento di rame", - "block.create.copper_ladder": "Scala a pioli in rame", - "block.create.copper_shingle_slab": "Lastra di tegole di rame", - "block.create.copper_shingle_stairs": "Scalini di tegole di rame", - "block.create.copper_shingles": "Tegole di rame", - "block.create.copper_tile_slab": "Lastra di mattonelle di rame", - "block.create.copper_tile_stairs": "Scalini di mattonelle di rame", - "block.create.copper_tiles": "Piastrelle di rame", - "block.create.copper_valve_handle": "Maniglia per valvola di rame", - "block.create.creative_crate": "Cassa (creativa)", - "block.create.creative_fluid_tank": "Serbatoio per fluidi (creativa)", - "block.create.creative_motor": "Motore (creativa)", - "block.create.crimsite": "Crimsite", - "block.create.crimsite_pillar": "Pilastro di crimsite", - "block.create.crimson_window": "Finestra cremisi", - "block.create.crimson_window_pane": "Lastra di finestra cremisi", - "block.create.crushing_wheel": "Ruota frantumatrice", - "block.create.crushing_wheel_controller": "Nucleo di ruota frantumatrice", - "block.create.cuckoo_clock": "Orologio a cucù", - "block.create.cut_andesite": "Andesite tagliata", - "block.create.cut_andesite_brick_slab": "Lastra di mattoni di andesite tagliata", - "block.create.cut_andesite_brick_stairs": "Scalini di mattoni di andesite tagliata", - "block.create.cut_andesite_brick_wall": "Muretto di mattoni di andesite tagliata", - "block.create.cut_andesite_bricks": "Mattoni di andesite tagliata", - "block.create.cut_andesite_slab": "Lastra di andesite tagliata", - "block.create.cut_andesite_stairs": "Scalini di andesite tagliata", - "block.create.cut_andesite_wall": "Muretto di andesite tagliata", - "block.create.cut_asurine": "Asurina tagliata", - "block.create.cut_asurine_brick_slab": "Lastra di mattoni di asurina tagliata", - "block.create.cut_asurine_brick_stairs": "Scalini di mattoni di asurina tagliata", - "block.create.cut_asurine_brick_wall": "Muretto di mattoni di asurina tagliata", - "block.create.cut_asurine_bricks": "Mattoni di asurina tagliata", - "block.create.cut_asurine_slab": "Lastra di asurina tagliata", - "block.create.cut_asurine_stairs": "Scalini di asurina tagliata", - "block.create.cut_asurine_wall": "Muretto di asurina tagliata", - "block.create.cut_calcite": "Calcite tagliata", - "block.create.cut_calcite_brick_slab": "Lastra di mattoni di calcite tagliata", - "block.create.cut_calcite_brick_stairs": "Scalini di mattoni di calcite tagliata", - "block.create.cut_calcite_brick_wall": "Muretto di mattoni di calcite tagliata", - "block.create.cut_calcite_bricks": "Mattoni di calcite tagliata", - "block.create.cut_calcite_slab": "Lastra di calcite tagliata", - "block.create.cut_calcite_stairs": "Scalini di calcite tagliata", - "block.create.cut_calcite_wall": "Muretto di calcite tagliata", - "block.create.cut_crimsite": "Crimsite tagliata", - "block.create.cut_crimsite_brick_slab": "Lastra di mattoni di crimsite tagliata", - "block.create.cut_crimsite_brick_stairs": "Scalini di mattoni di crimsite tagliata", - "block.create.cut_crimsite_brick_wall": "Muretto di mattoni di crimsite tagliata", - "block.create.cut_crimsite_bricks": "Mattoni di crimsite tagliata", - "block.create.cut_crimsite_slab": "Lastra di crimsite tagliata", - "block.create.cut_crimsite_stairs": "Scalini di crimsite tagliata", - "block.create.cut_crimsite_wall": "Muretto di crimsite tagliata", - "block.create.cut_deepslate": "Ardesia profonda tagliata", - "block.create.cut_deepslate_brick_slab": "Lastra di mattoni di ardesia profonda tagliata", - "block.create.cut_deepslate_brick_stairs": "Scalini di mattoni di ardesia profonda tagliata", - "block.create.cut_deepslate_brick_wall": "Lastra di mattoni di ardesia profonda tagliata", - "block.create.cut_deepslate_bricks": "Mattoni di ardesia profonda tagliata", - "block.create.cut_deepslate_slab": "Lastra di ardesia profonda tagliata", - "block.create.cut_deepslate_stairs": "Scalini di ardesia profonda tagliata", - "block.create.cut_deepslate_wall": "Muretto di ardesia profonda tagliata", - "block.create.cut_diorite": "Diorite tagliata", - "block.create.cut_diorite_brick_slab": "Lastra di mattoni di diorite tagliata", - "block.create.cut_diorite_brick_stairs": "Scalini di mattoni di diorite tagliata", - "block.create.cut_diorite_brick_wall": "Muretto di mattoni di diorite tagliata", - "block.create.cut_diorite_bricks": "Mattoni di diorite tagliata", - "block.create.cut_diorite_slab": "Lastra di diorite tagliata", - "block.create.cut_diorite_stairs": "Scalini di diorite tagliata", - "block.create.cut_diorite_wall": "Muretto di diorite tagliata", - "block.create.cut_dripstone": "Speleotema tagliato", - "block.create.cut_dripstone_brick_slab": "Lastra di mattoni di speleotema tagliato", - "block.create.cut_dripstone_brick_stairs": "Scalini di mattoni di speleotema tagliato", - "block.create.cut_dripstone_brick_wall": "Muretto di mattoni di speleotema tagliato", - "block.create.cut_dripstone_bricks": "Mattoni di speleotema tagliato", - "block.create.cut_dripstone_slab": "Lastra di speleotema tagliato", - "block.create.cut_dripstone_stairs": "Scalini di speleotema tagliato", - "block.create.cut_dripstone_wall": "Muretto di speleotema tagliato", - "block.create.cut_granite": "Granito tagliato", - "block.create.cut_granite_brick_slab": "Lastra di mattoni di granito tagliato", - "block.create.cut_granite_brick_stairs": "Scalini di mattoni di granito tagliato", - "block.create.cut_granite_brick_wall": "Muretto di mattoni di granito tagliato", - "block.create.cut_granite_bricks": "Mattoni di granito tagliato", - "block.create.cut_granite_slab": "Lastra di granito tagliato", - "block.create.cut_granite_stairs": "Scalini di granito tagliato", - "block.create.cut_granite_wall": "Muretto di granito tagliato", - "block.create.cut_limestone": "Calcare tagliato", - "block.create.cut_limestone_brick_slab": "Lastra di mattoni di calcare tagliato", - "block.create.cut_limestone_brick_stairs": "Scalini di mattoni di calcare tagliato", - "block.create.cut_limestone_brick_wall": "Muretto di mattoni di calcare tagliato", - "block.create.cut_limestone_bricks": "Mattoni di calcare tagliato", - "block.create.cut_limestone_slab": "Lastra di calcare tagliato", - "block.create.cut_limestone_stairs": "Scalini di calcare tagliato", - "block.create.cut_limestone_wall": "Muretto di calcare tagliato", - "block.create.cut_ochrum": "Ocrite tagliata", - "block.create.cut_ochrum_brick_slab": "Lastra di mattoni di ocrite tagliata", - "block.create.cut_ochrum_brick_stairs": "Scalini di mattoni di ocrite tagliata", - "block.create.cut_ochrum_brick_wall": "Muretto di mattoni di ocrite tagliata", - "block.create.cut_ochrum_bricks": "Mattoni di ocrite tagliata", - "block.create.cut_ochrum_slab": "Lastra di ocrite tagliata", - "block.create.cut_ochrum_stairs": "Scalini di ocrite tagliata", - "block.create.cut_ochrum_wall": "Muretto di ocrite tagliata", - "block.create.cut_scorchia": "Scoria bruciata tagliata", - "block.create.cut_scorchia_brick_slab": "Lastra di mattoni di scoria bruciata tagliata", - "block.create.cut_scorchia_brick_stairs": "Scalini di mattoni di scoria bruciata tagliata", - "block.create.cut_scorchia_brick_wall": "Muretto di mattoni di scoria bruciata tagliata", - "block.create.cut_scorchia_bricks": "Mattoni di scoria bruciata tagliata", - "block.create.cut_scorchia_slab": "Lastra di scoria bruciata tagliata", - "block.create.cut_scorchia_stairs": "Scalini di scoria bruciata tagliata", - "block.create.cut_scorchia_wall": "Muretto di scoria bruciata tagliata", - "block.create.cut_scoria": "Scoria tagliata", - "block.create.cut_scoria_brick_slab": "Lastra di mattoni di scoria tagliata", - "block.create.cut_scoria_brick_stairs": "Scalini di mattoni di scoria tagliata", - "block.create.cut_scoria_brick_wall": "Muretto di mattoni di scoria tagliata", - "block.create.cut_scoria_bricks": "Mattoni di scoria tagliata", - "block.create.cut_scoria_slab": "Lastra di scoria tagliata", - "block.create.cut_scoria_stairs": "Scalini di scoria tagliata", - "block.create.cut_scoria_wall": "Muretto di scoria tagliata", - "block.create.cut_tuff": "Tufo tagliato", - "block.create.cut_tuff_brick_slab": "Lastra di mattoni di tufo tagliato", - "block.create.cut_tuff_brick_stairs": "Scalini di mattoni di tufo tagliato", - "block.create.cut_tuff_brick_wall": "Muretto di mattoni di tufo tagliato", - "block.create.cut_tuff_bricks": "Mattoni di tufo tagliato", - "block.create.cut_tuff_slab": "Lastra di tufo tagliato", - "block.create.cut_tuff_stairs": "Scalini di tufo tagliato", - "block.create.cut_tuff_wall": "Muretto di tufo tagliato", - "block.create.cut_veridium": "Veridio tagliato", - "block.create.cut_veridium_brick_slab": "Lastra di mattoni di veridio tagliato", - "block.create.cut_veridium_brick_stairs": "Scalini di mattoni di veridio tagliato", - "block.create.cut_veridium_brick_wall": "Muretto di mattoni di veridio tagliato", - "block.create.cut_veridium_bricks": "Mattoni di veridio tagliato", - "block.create.cut_veridium_slab": "Lastra di veridio tagliato", - "block.create.cut_veridium_stairs": "Scalini di veridio tagliato", - "block.create.cut_veridium_wall": "Muretto di veridio tagliato", - "block.create.cyan_nixie_tube": "Tubo Nixie ciano", - "block.create.cyan_sail": "Vela ciano", - "block.create.cyan_seat": "Sedile ciano", - "block.create.cyan_toolbox": "Cassetta degli attrezzi ciano", - "block.create.cyan_valve_handle": "Maniglia per valvola ciano", - "block.create.dark_oak_window": "Finestra di quercia scura", - "block.create.dark_oak_window_pane": "Pannello di finestra di quercia scura", - "block.create.deepslate_pillar": "Pilastro di ardesia profonda", - "block.create.deepslate_zinc_ore": "Minerali di zinco in ardesia profonda", - "block.create.deployer": "Installatore", - "block.create.depot": "Stazione per oggetti", - "block.create.diorite_pillar": "Pilastro di diorite", - "block.create.display_board": "Tabellone", - "block.create.display_link": "Lettore di dati", - "block.create.dripstone_pillar": "Pilastro di speleotema", - "block.create.encased_chain_drive": "Trasmissione a catena", - "block.create.encased_fan": "Ventilatore", - "block.create.encased_fluid_pipe": "Tubo per fluidi rivestito", - "block.create.exposed_copper_shingle_slab": "Lastra di tegole di rame esposto", - "block.create.exposed_copper_shingle_stairs": "Scalini di tegole di rame esposto", - "block.create.exposed_copper_shingles": "Tegole di rame esposto", - "block.create.exposed_copper_tile_slab": "Lastra di mattonelle di rame esposto", - "block.create.exposed_copper_tile_stairs": "Scalini di mattonelle di rame esposto", - "block.create.exposed_copper_tiles": "Mattonelle di rame esposto", - "block.create.fake_track": "Marcatore di rotaia per mappe", - "block.create.fluid_pipe": "Tubo per fluidi", - "block.create.fluid_tank": "Serbatoio per fluidi", - "block.create.fluid_valve": "Valvola per fluidi", - "block.create.flywheel": "Volano", - "block.create.framed_glass": "Finestra di vetro", - "block.create.framed_glass_door": "Porta di vetro", - "block.create.framed_glass_pane": "Pannello di finestra di vetro", - "block.create.framed_glass_trapdoor": "Botola di vetro", - "block.create.gantry_carriage": "Carrello da gru", - "block.create.gantry_shaft": "Asse da gru", - "block.create.gearbox": "Invertitore", - "block.create.gearshift": "Cambio", - "block.create.glass_fluid_pipe": "Tubo per fluidi con vetrata", - "block.create.granite_pillar": "Pilastro di granito", - "block.create.gray_nixie_tube": "Tubo Nixie grigio", - "block.create.gray_sail": "Vela grigia", - "block.create.gray_seat": "Sedile grigio", - "block.create.gray_toolbox": "Cassetta degli attrezzi grigia", - "block.create.gray_valve_handle": "Maniglia per valvola grigia", - "block.create.green_nixie_tube": "Tubo Nixie verde", - "block.create.green_sail": "Vela verde", - "block.create.green_seat": "Sedile verde", - "block.create.green_toolbox": "Cassetta degli attrezzi verde", - "block.create.green_valve_handle": "Maniglia per valvola verde", - "block.create.hand_crank": "Manovella", - "block.create.haunted_bell": "Campana infestata", - "block.create.honey": "Miele", - "block.create.horizontal_framed_glass": "Finestra di vetro orizzontale", - "block.create.horizontal_framed_glass_pane": "Pannello di finestra di vetro orizzontale", - "block.create.hose_pulley": "Carrucola per fluidi", - "block.create.item_drain": "Prosciugatore di oggetti", - "block.create.item_vault": "Container", - "block.create.jungle_window": "Finestra della giungla", - "block.create.jungle_window_pane": "Pannello di finestra della giungla", - "block.create.large_bogey": "Carrello grande", - "block.create.large_cogwheel": "Ingranaggio grande", - "block.create.layered_andesite": "Andesite stratificata", - "block.create.layered_asurine": "Azurite stratificata", - "block.create.layered_calcite": "Calcite stratificata", - "block.create.layered_crimsite": "Crimsite stratificata", - "block.create.layered_deepslate": "Ardesia profonda stratificata", - "block.create.layered_diorite": "Diorite stratificata", - "block.create.layered_dripstone": "Speleotema stratificato", - "block.create.layered_granite": "Granito stratificato", - "block.create.layered_limestone": "Calcare stratificato", - "block.create.layered_ochrum": "Ocrite stratificata", - "block.create.layered_scorchia": "Scoria bruciata stratificata", - "block.create.layered_scoria": "Scoria stratificata", - "block.create.layered_tuff": "Tufo stratificato", - "block.create.layered_veridium": "Veridio stratificato", - "block.create.lectern_controller": "Leggio con pulsantiera", - "block.create.light_blue_nixie_tube": "Tubo Nixie azzurro", - "block.create.light_blue_sail": "Vela azzurra", - "block.create.light_blue_seat": "Sedile azzurro", - "block.create.light_blue_toolbox": "Cassetta degli attrezzi azzurra", - "block.create.light_blue_valve_handle": "Maniglia per valvola azzurra", - "block.create.light_gray_nixie_tube": "Tubo Nixie grigio chiaro", - "block.create.light_gray_sail": "Vela grigio chiaro", - "block.create.light_gray_seat": "Sedile grigio chiaro", - "block.create.light_gray_toolbox": "Cassetta degli attrezzi grigia chiaro", - "block.create.light_gray_valve_handle": "Maniglia per valvola grigio chiaro", - "block.create.lime_nixie_tube": "Tubo Nixie lime", - "block.create.lime_sail": "Vela lime", - "block.create.lime_seat": "Sedile lime", - "block.create.lime_toolbox": "Cassetta degli attrezzi lime", - "block.create.lime_valve_handle": "Maniglia per valvola lime", - "block.create.limestone": "Calcare", - "block.create.limestone_pillar": "Pilastro di calcare", - "block.create.linear_chassis": "Telaio lineare", - "block.create.lit_blaze_burner": "Inceneritore a blaze acceso", - "block.create.magenta_nixie_tube": "Tubo Nixie magenta", - "block.create.magenta_sail": "Vela magenta", - "block.create.magenta_seat": "Sedile magenta", - "block.create.magenta_toolbox": "Cassetta degli attrezzi magenta", - "block.create.magenta_valve_handle": "Maniglia per valvola magenta", - "block.create.mechanical_arm": "Braccio meccanico", - "block.create.mechanical_bearing": "Supporto meccanico", - "block.create.mechanical_crafter": "Fabbricatore meccanico", - "block.create.mechanical_drill": "Trivella meccanica", - "block.create.mechanical_harvester": "Mietitrice meccanica", - "block.create.mechanical_mixer": "Frullatore meccanico", - "block.create.mechanical_piston": "Pistone meccanico", - "block.create.mechanical_piston_head": "Testa di pistone meccanico", - "block.create.mechanical_plough": "Aratro meccanico", - "block.create.mechanical_press": "Pressa meccanica", - "block.create.mechanical_pump": "Pompa meccanica", - "block.create.mechanical_saw": "Sega meccanica", - "block.create.metal_bracket": "Supporto di metallo", - "block.create.metal_girder": "Trave di metallo", - "block.create.metal_girder_encased_shaft": "Asse rivestita da trave di metallo", - "block.create.millstone": "Macina", - "block.create.minecart_anchor": "Ancora per carrello da miniera", - "block.create.mysterious_cuckoo_clock": "Orologio a cucù misterioso", - "block.create.nixie_tube": "Tubo Nixie", - "block.create.nozzle": "Dispersore", - "block.create.oak_window": "Finestra di quercia", - "block.create.oak_window_pane": "Pannello di finestra di quercia", - "block.create.ochrum": "Ocrite", - "block.create.ochrum_pillar": "Pilastro di ocrite", - "block.create.orange_sail": "Vela arancione", - "block.create.orange_seat": "Sedile arancione", - "block.create.orange_toolbox": "Cassetta degli attrezzi arancione", - "block.create.orange_valve_handle": "Maniglia per valvola arancione", - "block.create.ornate_iron_window": "Finestra di ferro ornata", - "block.create.ornate_iron_window_pane": "Pannello di finestra di ferro ornata", - "block.create.oxidized_copper_shingle_slab": "Lastra di tegole di rame ossidato", - "block.create.oxidized_copper_shingle_stairs": "Scalini di tegole di rame ossidato", - "block.create.oxidized_copper_shingles": "Tegole di rame ossidato", - "block.create.oxidized_copper_tile_slab": "Lastra di mattonelle di rame ossidato", - "block.create.oxidized_copper_tile_stairs": "Scalini di mattonelle di rame ossidato", - "block.create.oxidized_copper_tiles": "Mattonelle di rame ossidato", - "block.create.peculiar_bell": "Campana peculiare", - "block.create.pink_nixie_tube": "Tubo Nixie rosa", - "block.create.pink_sail": "Vela rosa", - "block.create.pink_seat": "Sedile rosa", - "block.create.pink_toolbox": "Cassetta degli attrezzi rosa", - "block.create.pink_valve_handle": "Maniglia per valvola rosa", - "block.create.piston_extension_pole": "Palo di pistone", - "block.create.placard": "Cornice di ottone", - "block.create.polished_cut_andesite": "Andesite tagliata levigata", - "block.create.polished_cut_andesite_slab": "Lastra di andesite tagliata levigata", - "block.create.polished_cut_andesite_stairs": "Scalini di andesite tagliata levigata", - "block.create.polished_cut_andesite_wall": "Muretto di andesite tagliata levigata", - "block.create.polished_cut_asurine": "Azurite tagliata levigata", - "block.create.polished_cut_asurine_slab": "Lastra di azurite tagliata levigata", - "block.create.polished_cut_asurine_stairs": "Scalini di azurite tagliata levigata", - "block.create.polished_cut_asurine_wall": "Muretto di azurite tagliata levigata", - "block.create.polished_cut_calcite": "Calcite tagliata levigata", - "block.create.polished_cut_calcite_slab": "Lastra di calcite tagliata levigata", - "block.create.polished_cut_calcite_stairs": "Scalini di calcite tagliata levigata", - "block.create.polished_cut_calcite_wall": "Muretto di calcite tagliata levigata", - "block.create.polished_cut_crimsite": "Crimsite tagliata levigata", - "block.create.polished_cut_crimsite_slab": "Lastra di crimsite tagliata levigata", - "block.create.polished_cut_crimsite_stairs": "Scalini di crimsite tagliata levigata", - "block.create.polished_cut_crimsite_wall": "Muretto di crimsite tagliata levigata", - "block.create.polished_cut_deepslate": "Ardesia profonda tagliata levigata", - "block.create.polished_cut_deepslate_slab": "Lastra di ardesia profonda tagliata levigata", - "block.create.polished_cut_deepslate_stairs": "Scalini di ardesia profonda tagliata levigata", - "block.create.polished_cut_deepslate_wall": "Muretto di ardesia profonda tagliata levigata", - "block.create.polished_cut_diorite": "Diorite tagliata levigata", - "block.create.polished_cut_diorite_slab": "Lastra di diorite tagliata levigata", - "block.create.polished_cut_diorite_stairs": "Scalini di diorite tagliata levigata", - "block.create.polished_cut_diorite_wall": "Muretto di diorite tagliata levigata", - "block.create.polished_cut_dripstone": "Speleotema tagliato levigato", - "block.create.polished_cut_dripstone_slab": "Lastra di speleotema tagliato levigato", - "block.create.polished_cut_dripstone_stairs": "Scalini di speleotema tagliato levigato", - "block.create.polished_cut_dripstone_wall": "Muretto di speleotema tagliato levigato", - "block.create.polished_cut_granite": "Granito tagliato levigato", - "block.create.polished_cut_granite_slab": "Lastra di granito tagliato levigato", - "block.create.polished_cut_granite_stairs": "Scalini di franito tagliato levigato", - "block.create.polished_cut_granite_wall": "Muretto di granito tagliato levigato", - "block.create.polished_cut_limestone": "Calcare tagliato levigato", - "block.create.polished_cut_limestone_slab": "Lastra di calcare tagliato levigato", - "block.create.polished_cut_limestone_stairs": "Scalini di calcare tagliato levigato", - "block.create.polished_cut_limestone_wall": "Muretto di calcare tagliato levigato", - "block.create.polished_cut_ochrum": "Ocrite tagliata levigata", - "block.create.polished_cut_ochrum_slab": "Lastra di ocrite tagliata levigata", - "block.create.polished_cut_ochrum_stairs": "Scalini di ocrite tagliata levigata", - "block.create.polished_cut_ochrum_wall": "Muretto di ocrite tagliata levigata", - "block.create.polished_cut_scorchia": "Scoria bruciata tagliata levigata", - "block.create.polished_cut_scorchia_slab": "Lastra di scoria bruciata tagliata levigata", - "block.create.polished_cut_scorchia_stairs": "Scalini di scoria bruciata tagliata levigata", - "block.create.polished_cut_scorchia_wall": "Muretto di scoria bruciata tagliata levigata", - "block.create.polished_cut_scoria": "Scoria tagliata levigata", - "block.create.polished_cut_scoria_slab": "Lastra di scoria tagliata levigata", - "block.create.polished_cut_scoria_stairs": "Scalini di scoria tagliata levigata", - "block.create.polished_cut_scoria_wall": "Muretto di scoria tagliata levigata", - "block.create.polished_cut_tuff": "Tufo tagliato levigato", - "block.create.polished_cut_tuff_slab": "Lastra di tufo tagliato levigato", - "block.create.polished_cut_tuff_stairs": "Scalini di tufo tagliato levigato", - "block.create.polished_cut_tuff_wall": "Muretto di tufo tagliato levigato", - "block.create.polished_cut_veridium": "Veridio tagliato levigato", - "block.create.polished_cut_veridium_slab": "Lastra di veridio tagliato levigato", - "block.create.polished_cut_veridium_stairs": "Scalini di veridio tagliato levigato", - "block.create.polished_cut_veridium_wall": "Muretto di veridio tagliato levigato", - "block.create.portable_fluid_interface": "Interfaccia per fluidi portatile", - "block.create.portable_storage_interface": "Interfaccia di stoccaggio portatile", - "block.create.powered_latch": "Circuito redstone bi-stato", - "block.create.powered_shaft": "Gru alimentata", - "block.create.powered_toggle_latch": "Alternatore redstone", - "block.create.pulley_magnet": "Magnete della carrucola", - "block.create.pulse_extender": "Estensore di impulsi", - "block.create.pulse_repeater": "Ripetitore di impulsi", - "block.create.purple_nixie_tube": "Tubo Nixie viola", - "block.create.purple_sail": "Vela viola", - "block.create.purple_seat": "Sedile viola", - "block.create.purple_toolbox": "Cassetta degli attrezzi viola", - "block.create.purple_valve_handle": "Maniglia per valvola viola", - "block.create.radial_chassis": "Telaio radiale", - "block.create.railway_casing": "Rivestimento di treno", - "block.create.raw_zinc_block": "Blocco di zinco grezzo", - "block.create.red_nixie_tube": "Tubo Nixie rosso", - "block.create.red_sail": "Vela rossa", - "block.create.red_seat": "Sedile rosso", - "block.create.red_toolbox": "Cassetta degli attrezzi rossa", - "block.create.red_valve_handle": "Maniglia per valvola rossa", - "block.create.redstone_contact": "Contatto redstone", - "block.create.redstone_link": "Connettore redstone", - "block.create.refined_radiance_casing": "Rivestimento di splendore raffinato", - "block.create.rope": "Corda", - "block.create.rope_pulley": "Carrucola per corde", - "block.create.rose_quartz_block": "Blocco di quarzo rosa", - "block.create.rose_quartz_lamp": "Lampada di quarzo rosa", - "block.create.rose_quartz_tiles": "Mattonelle di quarzo rosa", - "block.create.rotation_speed_controller": "Regolatore di velocità di rotazione", - "block.create.sail_frame": "Cornice di vela", - "block.create.schematic_table": "Banco dei progetti", - "block.create.schematicannon": "Spara-progetti", - "block.create.scorchia": "Scoria bruciata", - "block.create.scorchia_pillar": "Pilastro di scoria bruciata", - "block.create.scoria": "Scoria", - "block.create.scoria_pillar": "Pilastro di scoria", - "block.create.secondary_linear_chassis": "Telaio lineare secondario", - "block.create.sequenced_gearshift": "Cambio sequenziale", - "block.create.shadow_steel_casing": "Rivestimento di acciaio oscuro", - "block.create.shaft": "Asse", - "block.create.small_andesite_brick_slab": "Lastra di mattoncini di andesite", - "block.create.small_andesite_brick_stairs": "Scalini di mattoncini di andesite", - "block.create.small_andesite_brick_wall": "Muretto di mattoncini di andesite", - "block.create.small_andesite_bricks": "Mattoncini di andesite", - "block.create.small_asurine_brick_slab": "Lastra di mattoncini di azurite", - "block.create.small_asurine_brick_stairs": "Scalini di mattoncini di azurite", - "block.create.small_asurine_brick_wall": "Muretto di mattoncini di azurite", - "block.create.small_asurine_bricks": "Mattoncini di azurite", - "block.create.small_bogey": "Carrello piccolo", - "block.create.small_calcite_brick_slab": "Lastra di mattoncini di calcite", - "block.create.small_calcite_brick_stairs": "Scalini di mattoncini di calcite", - "block.create.small_calcite_brick_wall": "Muretto di mattoncini di calcite", - "block.create.small_calcite_bricks": "Mattoncini di calcite", - "block.create.small_crimsite_brick_slab": "Lastra di mattoncini di crimsite", - "block.create.small_crimsite_brick_stairs": "Scalini di mattoncini di crimsite", - "block.create.small_crimsite_brick_wall": "Muretto di mattoncini di crimsite", - "block.create.small_crimsite_bricks": "Mattoncini di crimsite", - "block.create.small_deepslate_brick_slab": "Lastra di mattoncini di ardesia profonda", - "block.create.small_deepslate_brick_stairs": "Scalini di mattoncini di ardesia profonda", - "block.create.small_deepslate_brick_wall": "Muretto di mattoncini di ardesia profonda", - "block.create.small_deepslate_bricks": "Mattoncini di ardesia profonda", - "block.create.small_diorite_brick_slab": "Lastra di mattoncini di diorite", - "block.create.small_diorite_brick_stairs": "Scalini di mattoncini di diorite", - "block.create.small_diorite_brick_wall": "Muretto di mattoncini di diorite", - "block.create.small_diorite_bricks": "Mattoncini di diorite", - "block.create.small_dripstone_brick_slab": "Lastra di mattoncini di speleotema", - "block.create.small_dripstone_brick_stairs": "Scalini di mattoncini di speleotema", - "block.create.small_dripstone_brick_wall": "Muretto di mattoncini di speleotema", - "block.create.small_dripstone_bricks": "Mattoncini di speleotema", - "block.create.small_granite_brick_slab": "Lastra di mattoncini di granito", - "block.create.small_granite_brick_stairs": "Scalini di mattoncini di granito", - "block.create.small_granite_brick_wall": "Muretto di mattoncini di granito", - "block.create.small_granite_bricks": "Mattoncini di granito", - "block.create.small_limestone_brick_slab": "Lastra di mattoncini di calcare", - "block.create.small_limestone_brick_stairs": "Scalini di mattoncini di calcare", - "block.create.small_limestone_brick_wall": "Muretto di mattoncini di calcare", - "block.create.small_limestone_bricks": "Mattoncini di calcare", - "block.create.small_ochrum_brick_slab": "Lastra di mattoncini di ocrite", - "block.create.small_ochrum_brick_stairs": "Scalini di mattoncini di ocrite", - "block.create.small_ochrum_brick_wall": "Muretto di mattoncini di ocrite", - "block.create.small_ochrum_bricks": "Mattoncini di ocrite", - "block.create.small_rose_quartz_tiles": "Piccole mattonelle di quarzo rosa", - "block.create.small_scorchia_brick_slab": "Lastra di mattoncini di scoria bruciata", - "block.create.small_scorchia_brick_stairs": "Scalini di mattoncini di scoria bruciata", - "block.create.small_scorchia_brick_wall": "Muretto di mattoncini di scoria bruciata", - "block.create.small_scorchia_bricks": "Mattoncini di scoria bruciata", - "block.create.small_scoria_brick_slab": "Lastra di mattoncini di scoria", - "block.create.small_scoria_brick_stairs": "Scalini di mattoncini di scoria", - "block.create.small_scoria_brick_wall": "Muretto di mattoncini di scoria", - "block.create.small_scoria_bricks": "Mattoncini di scoria", - "block.create.small_tuff_brick_slab": "Lastra di mattoncini di tufo", - "block.create.small_tuff_brick_stairs": "Scalini di mattoncini di tufo", - "block.create.small_tuff_brick_wall": "Muretto di mattoncini di tufo", - "block.create.small_tuff_bricks": "Mattoncini di tufo", - "block.create.small_veridium_brick_slab": "Lastra di mattoncini di veridio", - "block.create.small_veridium_brick_stairs": "Scalini di mattoncini di veridio", - "block.create.small_veridium_brick_wall": "Muretto di mattoncini di veridio", - "block.create.small_veridium_bricks": "Mattoncini di veridio", - "block.create.smart_chute": "Scivolo intelligente", - "block.create.smart_fluid_pipe": "Tubo per fluidi intelligente", - "block.create.speedometer": "Tachimetro", - "block.create.spout": "Spruzzatore", - "block.create.spruce_window": "Finestra di abete", - "block.create.spruce_window_pane": "Pannello di finestra di abete", - "block.create.steam_engine": "Motore a vapore", - "block.create.steam_whistle": "Fischio a vapore", - "block.create.steam_whistle_extension": "Estensione di fischio a vapore", - "block.create.sticker": "Incollatore", - "block.create.sticky_mechanical_piston": "Pistone meccanico appiccicoso", - "block.create.stockpile_switch": "Interruttore a riempimento", - "block.create.stressometer": "Stressometro", - "block.create.tiled_glass": "Vetro piastrellato", - "block.create.tiled_glass_pane": "Pannello di vetro piastrellato", - "block.create.track": "Rotaia", - "block.create.track_observer": "Osservatore ferroviario", - "block.create.track_signal": "Semaforo ferroviario", - "block.create.track_station": "Stazione ferroviaria", - "block.create.train_door": "Porta per treni", - "block.create.train_trapdoor": "Botola per treni", - "block.create.tuff_pillar": "Pilastro di tufo", - "block.create.turntable": "Piattaforma girevole", - "block.create.veridium": "Veridio", - "block.create.veridium_pillar": "Pilastro di veridio", - "block.create.vertical_framed_glass": "Finestra di vetro verticale", - "block.create.vertical_framed_glass_pane": "Pannello di finestra di vetro verticale", - "block.create.warped_window": "Finestra distorta", - "block.create.warped_window_pane": "Pannello di finestra distorta", - "block.create.water_wheel": "Mulino ad acqua", - "block.create.waxed_copper_shingle_slab": "Lastra di tegole di rame cerato", - "block.create.waxed_copper_shingle_stairs": "Scalini di tegole di rame cerato", - "block.create.waxed_copper_shingles": "Tegole di rame cerato", - "block.create.waxed_copper_tile_slab": "Lastra di mattonelle di rame cerato", - "block.create.waxed_copper_tile_stairs": "Scalini di mattonelle di rame cerato", - "block.create.waxed_copper_tiles": "Mattonelle di rame ossidato cerato", - "block.create.waxed_exposed_copper_shingle_slab": "Lastra di tegole di rame esposto cerato", - "block.create.waxed_exposed_copper_shingle_stairs": "Scalini di tegole di rame cerato", - "block.create.waxed_exposed_copper_shingles": "Tegole di rame cerato", - "block.create.waxed_exposed_copper_tile_slab": "Lastra di mattonelle di rame ossidato cerato", - "block.create.waxed_exposed_copper_tile_stairs": "Scalini di mattonelle di rame esposto cerato", - "block.create.waxed_exposed_copper_tiles": "Mattonelle di rame esposto cerato", - "block.create.waxed_oxidized_copper_shingle_slab": "Lastra di tegole di rame ossidato cerato", - "block.create.waxed_oxidized_copper_shingle_stairs": "Scalini di tegole di rame ossidato cerato", - "block.create.waxed_oxidized_copper_shingles": "Tegole di rame ossidato cerato", - "block.create.waxed_oxidized_copper_tile_slab": "Lastra di mattonelle di rame ossidato cerato", - "block.create.waxed_oxidized_copper_tile_stairs": "Scalini di mattonelle di rame ossidato cerato", - "block.create.waxed_oxidized_copper_tiles": "Mattonelle di rame ossidato cerato", - "block.create.waxed_weathered_copper_shingle_slab": "Lastra di tegole di rame corroso cerato", - "block.create.waxed_weathered_copper_shingle_stairs": "Scalini di tegole di rame corroso cerato", - "block.create.waxed_weathered_copper_shingles": "Tegole di rame corroso cerato", - "block.create.waxed_weathered_copper_tile_slab": "Lastra di mattonelle di rame corroso cerato", - "block.create.waxed_weathered_copper_tile_stairs": "Scalini di mattonelle di rame corroso cerato", - "block.create.waxed_weathered_copper_tiles": "Mattonelle di rame corroso cerato", - "block.create.weathered_copper_shingle_slab": "Lastra di tegole di rame corroso", - "block.create.weathered_copper_shingle_stairs": "Lastra di tegole di rame corroso", - "block.create.weathered_copper_shingles": "Tegole di rame corroso", - "block.create.weathered_copper_tile_slab": "Lastra di mattonelle di rame corroso", - "block.create.weathered_copper_tile_stairs": "Scalini di mattonelle di rame corroso", - "block.create.weathered_copper_tiles": "Mattonelle di rame corroso", - "block.create.weighted_ejector": "Espulsore di pesi", - "block.create.white_nixie_tube": "Tubo Nixie bianco", - "block.create.white_sail": "Vela bianca", - "block.create.white_seat": "Sedile bianco", - "block.create.white_toolbox": "Cassetta degli attrezzi bianca", - "block.create.white_valve_handle": "Maniglia per valvola bianca", - "block.create.windmill_bearing": "Supporto per mulino a vento", - "block.create.wooden_bracket": "Supporto di legno", - "block.create.yellow_nixie_tube": "Tubo Nixie giallo", - "block.create.yellow_sail": "Vela gialla", - "block.create.yellow_seat": "Sedile giallo", - "block.create.yellow_toolbox": "Cassetta degli attrezzi gialla", - "block.create.yellow_valve_handle": "Maniglia per valvola gialla", - "block.create.zinc_block": "Blocco di zinco", - "block.create.zinc_ore": "Zinco grezzo", - - "enchantment.create.capacity": "Capacità", - "enchantment.create.potato_recovery": "Recupero vegetale", - - "entity.create.carriage_contraption": "Carrozza", - "entity.create.contraption": "Macchinario", - "entity.create.crafting_blueprint": "Progetto di fabbricazione", - "entity.create.gantry_contraption": "Macchinario da gru", - "entity.create.potato_projectile": "Proiettile Vegetale", - "entity.create.seat": "Sedile", - "entity.create.stationary_contraption": "Macchinario stazionario", - "entity.create.super_glue": "Super colla", - - "fluid.create.potion": "Pozione", - "fluid.create.tea": "Tè del costruttore", - - "item.create.andesite_alloy": "Lega di andesite", - "item.create.attribute_filter": "Filtro attributi", - "item.create.bar_of_chocolate": "Barretta di cioccolato", - "item.create.belt_connector": "Nastro meccanico", - "item.create.blaze_cake": "Torta per blaze", - "item.create.blaze_cake_base": "Base della torta per blaze", - "item.create.brass_hand": "Mano di ottone", - "item.create.brass_ingot": "Lingotto di ottone", - "item.create.brass_nugget": "Pepita di ottone", - "item.create.brass_sheet": "Lamiera di ottone", - "item.create.builders_tea": "Tè del costruttore", - "item.create.chest_minecart_contraption": "Macchinario con carrello da miniera con baule", - "item.create.chocolate_bucket": "Secchio di cioccolata", - "item.create.chocolate_glazed_berries": "Bacche glassate al cioccolato", - "item.create.chromatic_compound": "Composto cromatico", - "item.create.cinder_flour": "Cenere farinosa", - "item.create.copper_backtank": "Zaino serbatoio", - "item.create.copper_backtank_placeable": "Zaino serbatoio posizionabile", - "item.create.copper_nugget": "Pepita di rame", - "item.create.copper_sheet": "Lamiera di rame", - "item.create.crafter_slot_cover": "Copertura per slot di fabbricazione", - "item.create.crafting_blueprint": "Progetto di fabbricazione", - "item.create.creative_blaze_cake": "Torta per blaze (creativa)", - "item.create.crushed_aluminum_ore": "Alluminio grezzo frantumato", - "item.create.crushed_copper_ore": "Rame grezzo frantumato", - "item.create.crushed_gold_ore": "Oro grezzo frantumato", - "item.create.crushed_iron_ore": "Ferro grezzo frantumato", - "item.create.crushed_lead_ore": "Piombo grezzo frantumato", - "item.create.crushed_nickel_ore": "Nichel grezzo frantumato", - "item.create.crushed_osmium_ore": "Osmio grezzo frantumato", - "item.create.crushed_platinum_ore": "Platino grezzo frantumato", - "item.create.crushed_quicksilver_ore": "Mercurio grezzo frantumato", - "item.create.crushed_silver_ore": "Argento grezzo frantumato", - "item.create.crushed_tin_ore": "Stagno grezzo frantumato", - "item.create.crushed_uranium_ore": "Uranio grezzo frantumato", - "item.create.crushed_zinc_ore": "Zinco grezzo frantumato", - "item.create.diving_boots": "Stivali da immersione", - "item.create.diving_helmet": "Elmo da immersione", - "item.create.dough": "Impasto", - "item.create.electron_tube": "Tubo a vuoto", - "item.create.empty_blaze_burner": "Inceneritore vuoto", - "item.create.empty_schematic": "Progetto vuoto", - "item.create.experience_nugget": "Pepita di esperienza", - "item.create.extendo_grip": "Braccio allungabile", - "item.create.filter": "Filtro", - "item.create.furnace_minecart_contraption": "Macchinario con carrello da miniera con fornace", - "item.create.goggles": "Occhiali da ingegnere", - "item.create.golden_sheet": "Lamiera d'oro", - "item.create.handheld_worldshaper": "Plasmatore del mondo portatile", - "item.create.honey_bucket": "Secchio di miele", - "item.create.honeyed_apple": "Mela caramellata", - "item.create.incomplete_precision_mechanism": "Meccanismo di precisione imcompleto", - "item.create.incomplete_track": "Rotaia incompleta", - "item.create.iron_sheet": "Lamiera di ferro", - "item.create.linked_controller": "Pulsantiera di comando", - "item.create.minecart_contraption": "Macchinario con carrello da miniera", - "item.create.minecart_coupling": "Aggancio per carrelli da miniera", - "item.create.polished_rose_quartz": "Quarzo rosa levigato", - "item.create.potato_cannon": "Cannone a patate", - "item.create.powdered_obsidian": "Ossidiana in polvere", - "item.create.precision_mechanism": "Meccanismo di precisione", - "item.create.propeller": "Elica", - "item.create.raw_zinc": "Zinco grezzo", - "item.create.red_sand_paper": "Carta vetrata rossa", - "item.create.refined_radiance": "Splendore raffinato", - "item.create.rose_quartz": "Quarzo rosa", - "item.create.sand_paper": "Carta vetrata", - "item.create.schedule": "Tabella di marcia", - "item.create.schematic": "Progetto", - "item.create.schematic_and_quill": "Pogetto e penna", - "item.create.shadow_steel": "Acciaio oscuro", - "item.create.sturdy_sheet": "Lamiera rinforzata", - "item.create.super_glue": "Super colla", - "item.create.sweet_roll": "Pane dolce", - "item.create.tree_fertilizer": "Fertilizzante per alberi", - "item.create.unprocessed_obsidian_sheet": "Lastra di ossidiana non processata", - "item.create.vertical_gearbox": "Invertitore verticale", - "item.create.wand_of_symmetry": "Scettro della Simmetria", - "item.create.wheat_flour": "Farina di grano", - "item.create.whisk": "Frusta", - "item.create.wrench": "Chiave a pappagallo", - "item.create.zinc_ingot": "Lingotto di zinco", - "item.create.zinc_nugget": "Pepita di zinco", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Benvenuti alla Create", - "advancement.create.root.desc": "È ora di iniziare a costruire marchingegni fantastici!", - "advancement.create.andesite_alloy": "Rocce più dure", - "advancement.create.andesite_alloy.desc": "Crea della Lega di andesite, la risorsa più importante di tutta la Create.", - "advancement.create.andesite_casing": "L'era dell'andesite", - "advancement.create.andesite_casing.desc": "Usa della lega di andesite e del legno per creare un Rivestimento basilare.", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "Crea delle lamiere in una Pressa meccanica", - "advancement.create.encased_fan": "Dominatore dell'aria", - "advancement.create.encased_fan.desc": "Posiziona e attiva un Ventilatore", - "advancement.create.fan_processing": "Processo Particellare", - "advancement.create.fan_processing.desc": "Usa un Ventilatore per processare dei materiali", - "advancement.create.saw_processing": "La parte più temuta", - "advancement.create.saw_processing.desc": "Usa una Sega meccanica rivolta verso l'alto per processare dei materiali", - "advancement.create.compacting": "Compattazione", - "advancement.create.compacting.desc": "Usa una Pressa e una Vasca per creare meno oggetti a partire da più oggetti", - "advancement.create.belt": "Nastro trasportatore", - "advancement.create.belt.desc": "Connetti due alberi con un nastro meccanico.", - "advancement.create.funnel": "Estetica da aeroporto", - "advancement.create.funnel.desc": "Estrai o inserisci oggetti in un contenitore usando un imbuto", - "advancement.create.chute": "Giù per il tubo", - "advancement.create.chute.desc": "Piazza uno scivolo, la controparte verticale del nastro.", - "advancement.create.mechanical_mixer": "Mischiamo tutto insieme!", - "advancement.create.mechanical_mixer.desc": "Combina degli ingredienti usando un Frullatore meccanico", - "advancement.create.burner": "Focolaio senziente", - "advancement.create.burner.desc": "Ottieni un Inceneritore a blaze", - "advancement.create.water_wheel": "Ingegneria idraulica", - "advancement.create.water_wheel.desc": "Piazza un Mulino ad acqua e prova a farlo girare!", - "advancement.create.windmill": "Una lieve brezza", - "advancement.create.windmill.desc": "Assembla un mulino a vento.", - "advancement.create.shifting_gears": "Meccanismi moventi", - "advancement.create.shifting_gears.desc": "Aggancia una ruota dentata grande con una piccola, permettendoti di cambiare la velocità.", - "advancement.create.millstone": "Frantumatore portatile", - "advancement.create.millstone.desc": "Piazza e alimenta una macina.", - "advancement.create.super_glue": "Connessione forte", - "advancement.create.super_glue.desc": "Unisci un gruppo di blocchi con la Super colla", - "advancement.create.contraption_actors": "Movimento sensato", - "advancement.create.contraption_actors.desc": "Crea un macchinario che contenga trapani, seghe o mietitrici", - "advancement.create.portable_storage_interface": "Passaggio al drive-through", - "advancement.create.portable_storage_interface.desc": "Usa una Interfaccia di stoccaggio portatile per inserire o rimuovere oggetti dall'interno di un macchinario", - "advancement.create.wrench_goggles": "Attrezzato", - "advancement.create.wrench_goggles.desc": "Equipaggia degli Occhiali da ingegnere e una Chiave a pappagallo", - "advancement.create.stressometer": "Che stress!", - "advancement.create.stressometer.desc": "Piazza e alimenta un tachimetro. Guardalo con gli occhiali per leggere il suo esatto valore.", - "advancement.create.cuckoo_clock": "È il momento?", - "advancement.create.cuckoo_clock.desc": "Sii presente al richiamo del tuo Orologio a cucù", - "advancement.create.windmill_maxed": "Una forte brezza", - "advancement.create.windmill_maxed.desc": "Costruisci un mulino a vento di potenza massima", - "advancement.create.ejector_maxed": "Medaglia di salto in lungo", - "advancement.create.ejector_maxed.desc": "Fai un salto di almeno 30 blocchi di lunghezza usando un Espulsore di pesi", - "advancement.create.pulley_maxed": "Una corda lunghissima", - "advancement.create.pulley_maxed.desc": "Allunga la corda di una Carrucola per almeno 200 blocchi", - "advancement.create.cart_pickup": "Braccia forti", - "advancement.create.cart_pickup.desc": "Raccogli un Macchinario con carrello da miniera composto da almeno 200 blocchi", - "advancement.create.anvil_plough": "Artiglieria da fabbro", - "advancement.create.anvil_plough.desc": "Lancia una Incudine con un Aratro meccanico", - "advancement.create.lava_wheel_00000": "Ruota lavica", - "advancement.create.lava_wheel_00000.desc": "Non è così che dovrebbe funzionare§7\n(Progresso segreto)", - "advancement.create.hand_crank_000": "Sessione di allenamento", - "advancement.create.hand_crank_000.desc": "Usa una manovella fino ad essere esausto§7\n(Progresso segreto)", - "advancement.create.belt_funnel_kiss": "Che dolce...", - "advancement.create.belt_funnel_kiss.desc": "Fai in modo che due imbuti montati su un nastro si 'bacino'.", - "advancement.create.stressometer_maxed": "Ce la fa ancora?", - "advancement.create.stressometer_maxed.desc": "Leggi esattamente 100% stress su uno Stressometro§7\n(Progresso segreto)", - "advancement.create.copper": "Rocce ancora più dure", - "advancement.create.copper.desc": "Accumula del rame per poter poi manipolare i fluidi.", - "advancement.create.copper_casing": "L'era del rame", - "advancement.create.copper_casing.desc": "Usa delle lamiere di ottone e del legno per creare involucri di ottone.", - "advancement.create.spout": "SPLASH", - "advancement.create.spout.desc": "Guarda mentre un fluido viene versato da uno Spruzzatore.", - "advancement.create.drain": "Asciugatura perfetta", - "advancement.create.drain.desc": "Guarda mentre un oggetto viene drenato da un Prosciugatore.", - "advancement.create.steam_engine": "Massima potenza", - "advancement.create.steam_engine.desc": "Genera energia cinetica usando un Motore a vapore.", - "advancement.create.steam_whistle": "Voce angelica", - "advancement.create.steam_whistle.desc": "Attiva un Fischio a vapore.", - "advancement.create.backtank": "Pressione portatile", - "advancement.create.backtank.desc": "Accumula Aria pressurizzata in uno Zaino serbatoio.", - "advancement.create.diving_suit": "Attrezzatura da immersione", - "advancement.create.diving_suit.desc": "Equipagia uno Zaino serbatoio e un Elmo da immersione e tuffati in acqua.", - "advancement.create.mechanical_pump_0": "Sotto Pressione", - "advancement.create.mechanical_pump_0.desc": "Posiziona e attiva una Pompa meccanica.", - "advancement.create.glass_pipe": "Spiare il flusso", - "advancement.create.glass_pipe.desc": "Guarda mentre un fluido si propaga attraverso un tubo per fluidi con vetrata. Puoi aggiungere una vetrata cliccando con una chiave a pappagallo sui tubi per fluidi dritti.", - "advancement.create.water_supply": "Collezionista di pozzanghere", - "advancement.create.water_supply.desc": "Usa una pompa o un tubo con pressione entrante per assorbire un blocco d'acqua.", - "advancement.create.hose_pulley": "Risucchio industriale", - "advancement.create.hose_pulley.desc": "Tira giù una carrucola per fluidi e guardala drenare o riempire un corpo dal fluido.", - "advancement.create.chocolate_bucket": "La Fabbrica di Cioccolato", - "advancement.create.chocolate_bucket.desc": "Ottieni un secchio di Cioccolato fuso.", - "advancement.create.honey_drain": "Apicoltura automatizzata", - "advancement.create.honey_drain.desc": "Usa dei tubi per estrarre del Miele da un Alveare o Arnia.", - "advancement.create.hose_pulley_lava": "Sotto la crosta", - "advancement.create.hose_pulley_lava.desc": "Estrai lava da una sorgente abbastanza grande da essere considerata ininita.", - "advancement.create.steam_engine_maxed": "A tutta velocità", - "advancement.create.steam_engine_maxed.desc": "Fai funzionare una caldaia alla massima potenza", - "advancement.create.foods": "Dieta bilanciata", - "advancement.create.foods.desc": "Crea Bacche glassate, una Mela caramellata e del Pane dolce, tutti dallo stesso Spruzzatore", - "advancement.create.diving_suit_lava": "Nuotando con gli Strider", - "advancement.create.diving_suit_lava.desc": "Prova a tuffarti nella lava con le tue attrezzature da immersione§7\n(Progresso segreto)", - "advancement.create.chained_drain": "Inarrestabile", - "advancement.create.chained_drain.desc": "Guarda mentre un oggetto supera un'intera fila di Prosciugatori§7\n(Progresso segreto)", - "advancement.create.cross_streams": "Non incrociate i flussi!", - "advancement.create.cross_streams.desc": "Guarda mentre due fluidi si incontrano§7\n(Progresso segreto)", - "advancement.create.pipe_organ": "Organo a canne", - "advancement.create.pipe_organ.desc": "Connetti 12 Fischi a un singolo serbatoio e impostali ognuno ad una nota diversa §7\n(Progresso segreto)", - "advancement.create.brass": "L'ottone", - "advancement.create.brass.desc": "Usa il rame e lo zinco per creare dell'ottone.", - "advancement.create.brass_casing": "L'era dell'ottone", - "advancement.create.brass_casing.desc": "Usa l'ottone e del legno per creare involucri più avanzati.", - "advancement.create.rose_quartz": "Diamanti rosa", - "advancement.create.rose_quartz.desc": "Leviga del quarzo rosa.", - "advancement.create.deployer": "Piazza e attacca", - "advancement.create.deployer.desc": "Piazza e alimenta un installatore, il riflesso perfetto di te stesso.", - "advancement.create.precision_mechanism": "Curiosità complesse", - "advancement.create.precision_mechanism.desc": "Assembra un Meccanismo di Precisione.", - "advancement.create.speed_controller": "Gli ingegneri lo odiano", - "advancement.create.speed_controller.desc": "Posiziona un regolatore di velocità di rotazione, il dispositivo più avanzato in termini di meccanica.", - "advancement.create.mechanical_arm": "Mani occupate!", - "advancement.create.mechanical_arm.desc": "Costruisci un braccio meccanico, seleziona gli input e gli output, piazzalo e alimentalo; poi guardalo mentre fa il lavoro sporco al tuo posto.", - "advancement.create.mechanical_crafter": "Assemblaggio Automatico", - "advancement.create.mechanical_crafter.desc": "Posiziona e attiva dei Fabbricatori meccanici.", - "advancement.create.crushing_wheel": "Una coppia di giganti", - "advancement.create.crushing_wheel.desc": "Crea delle ruote di frantumazione per frantumare i materiali.", - "advancement.create.haunted_bell": "Senso oscuro", - "advancement.create.haunted_bell.desc": "Suona una Campana infestata.", - "advancement.create.clockwork_bearing": "Tic toc tic toc", - "advancement.create.clockwork_bearing.desc": "Assembla una struttura montata su un Supporto per orologi.", - "advancement.create.display_link": "Informazioni dettagliate", - "advancement.create.display_link.desc": "Usa un Connettore divino per visualizzare informazioni.", - "advancement.create.potato_cannon": "Fwoomp!", - "advancement.create.potato_cannon.desc": "Sconfiggi un nemico con il tuo Cannone a patate.", - "advancement.create.extendo_grip": "BOIOIOING", - "advancement.create.extendo_grip.desc": "Procurati un Braccio allungabile.", - "advancement.create.linked_controller": "Attivazione da remoto", - "advancement.create.linked_controller.desc": "Attiva un Connettore redstone usando una Pulsantiera di comando.", - "advancement.create.arm_blaze_burner": "Combustione automatizzata", - "advancement.create.arm_blaze_burner.desc": "Istruisci il tuo braccio meccanico ad alimentare un inceneritore a blaze.", - "advancement.create.crusher_maxed_0000": "Schiacciante", - "advancement.create.crusher_maxed_0000.desc": "Fai girare una coppia di Ruote frantumatrici alla massima velocità.", - "advancement.create.arm_many_targets": "Organizzatore seriale", - "advancement.create.arm_many_targets.desc": "Programma un braccio meccanico con 10 o più posizioni di output.", - "advancement.create.potato_cannon_collide": "Verdura d'artificio", - "advancement.create.potato_cannon_collide.desc": "Fai in modo che due diversi proiettili di Cannone a patate si scontrino.", - "advancement.create.self_deploying": "Carrello a guida autonoma", - "advancement.create.self_deploying.desc": "Crea un Macchinario con carrello da miniera che posiziona binari di fronte a sé.", - "advancement.create.fist_bump": "Mano a mano!", - "advancement.create.fist_bump.desc": "Metti uno contro l'altro due installatori.", - "advancement.create.crafter_lazy_000": "Manovre disperate", - "advancement.create.crafter_lazy_000.desc": "Rallenta il più possibile un Fabbricatore meccanico e continua a procrastinare un generatore decente§7\n(Progresso segret)", - "advancement.create.extendo_grip_dual": "Più lungo possibile", - "advancement.create.extendo_grip_dual.desc": "Equipaggia due Prolunghe per avere una portata sovrumana§7\n(Progresso segreto)", - "advancement.create.musical_arm": "DJ, metti su la musica!", - "advancement.create.musical_arm.desc": "Guarda mentre un braccio meccanico attiva un giradischi.", - "advancement.create.sturdy_sheet": "Rocce durissime", - "advancement.create.sturdy_sheet.desc": "Assembla una Lamiera rinforzata raffinando dell'ossidiana in polvere.", - "advancement.create.train_casing_00": "L'Era Logistica", - "advancement.create.train_casing_00.desc": "Usa delle Lamiere rinforzate per creare dei componenti per treni.", - "advancement.create.train": "Tutti a bordo!", - "advancement.create.train.desc": "Assembla il tuo primo treno.", - "advancement.create.conductor": "Istruttore di conduttori", - "advancement.create.conductor.desc": "Consegna una Tabella di marcia ad un conduttore.", - "advancement.create.track_signal": "Controllo del traffico", - "advancement.create.track_signal.desc": "Posiziona un Semaforo ferroviario.", - "advancement.create.display_board_0": "Tabella dinamica", - "advancement.create.display_board_0.desc": "Annuncia l'arrivo di un treno su un Tabellone usando un Lettore di dati.", - "advancement.create.track_0": "Miglioramento netto", - "advancement.create.track_0.desc": "Ottieni delle Rotaie.", - "advancement.create.train_whistle": "Choo choo!", - "advancement.create.train_whistle.desc": "Assembla un Fischio come parte di un treno e attivalo mentre guidi.", - "advancement.create.train_portal": "Pendolare interdimensionale", - "advancement.create.train_portal.desc": "Attraversa un Portale del Nether a bordo di un treno.", - "advancement.create.track_crafting_factory": "Fabbrica di Rotaie", - "advancement.create.track_crafting_factory.desc": "Produci più di 1000 Rotaie con la stessa Pressa.", - "advancement.create.long_bend": "Curva enorme", - "advancement.create.long_bend.desc": "Crea una sezione curva di Rotaie lunga almeno 30 blocchi.", - "advancement.create.long_train": "Trasporto pesante", - "advancement.create.long_train.desc": "Crea un treno composto da almeno 6 carrozze.", - "advancement.create.long_travel": "Viaggio rilassante", - "advancement.create.long_travel.desc": "Alzati da un Sedile a più di 5000 blocchi da dove ti ci sei seduto.", - "advancement.create.train_roadkill": "Uccisione stradale", - "advancement.create.train_roadkill.desc": "Investi un nemico con il tuo treno§7\n(Progresso segreto)", - "advancement.create.red_signal": "Autista esperto", - "advancement.create.red_signal.desc": "Passa con il rosso con il tuo treno§7\n(Progresso segreto)", - "advancement.create.train_crash": "Servizio scadente", - "advancement.create.train_crash.desc": "Fai esperienza di un incidente ferroviario mentre sei tra i passeggeri§7\n(Progresso segreto)", - "advancement.create.train_crash_backwards": "Punto cieco", - "advancement.create.train_crash_backwards.desc": "Colpisci un altro treno mentre vai in retromarcia§7\n(Progresso segreto)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create: Blocchi", - - "death.attack.create.crush": "%1$s è stato frantumato", - "death.attack.create.crush.player": "%1$s è stato gettato tra delle Ruote frantumatrici da %2$s", - "death.attack.create.fan_fire": "%1$s è stato cotto a puntino", - "death.attack.create.fan_fire.player": "%1$s è stato gettato in un affumicatore da %2$s", - "death.attack.create.fan_lava": "%1$s è stato carbonizzato in una fonderia", - "death.attack.create.fan_lava.player": "%1$s è stato gettato in una fonderia da %2$s", - "death.attack.create.mechanical_drill": "%1$s è stato trafitto da una trivella meccanica", - "death.attack.create.mechanical_drill.player": "%1$s è stato gettato di fronte a una trivella da by %2$s", - "death.attack.create.mechanical_saw": "%1$s è stato tagliato a metà", - "death.attack.create.mechanical_saw.player": "%1$s è stato gettato su una Sega meccanica da %2$s", - "death.attack.create.potato_cannon": "%1$s è stato ucciso dal Cannone a patate di %2$s", - "death.attack.create.potato_cannon.item": "%1$s è stato ucciso da %2$s usando %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s è saltato in aria a causa di un orologio a cucù manomesso", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s è saltato in aria a causa di un orologio a cucù manomesso", - "death.attack.create.run_over": "%1$s è stato travolto da %2$s", - - "create.block.deployer.damage_source_name": "una mano impazzita", - "create.block.cart_assembler.invalid": "Piazza il tuo assemblatore di carrelli su un binario", - - "create.menu.return": "Torna al menù", - "create.menu.configure": "Configura...", - "create.menu.ponder_index": "Riflessione", - "create.menu.only_ingame": "Disponibile nel menù di pausa", - "create.menu.report_bugs": "Segnala problemi", - "create.menu.support": "Supportaci", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Frantumazione", - "create.recipe.milling": "Macinatura", - "create.recipe.fan_washing": "Lavaggio di massa", - "create.recipe.fan_washing.fan": "Ventilatore dietro l'acqua corrente", - "create.recipe.fan_smoking": "Affumicatura di massa", - "create.recipe.fan_smoking.fan": "Ventilatore dietro al fuoco", - "create.recipe.fan_haunting": "Infestazione di massa", - "create.recipe.fan_haunting.fan": "Ventilatore dietro al fuoco delle anime", - "create.recipe.fan_blasting": "Fusione di massa", - "create.recipe.fan_blasting.fan": "Ventilatore dietro la lava", - "create.recipe.pressing": "Pressatura", - "create.recipe.mixing": "Mescolamento", - "create.recipe.deploying": "Installazione", - "create.recipe.automatic_shapeless": "Fabbricazione automatizzata senza forma", - "create.recipe.automatic_brewing": "Fermentazione automatizzata", - "create.recipe.packing": "Compattazione", - "create.recipe.automatic_packing": "Imballaggio automatizzato", - "create.recipe.sawing": "Segatura", - "create.recipe.mechanical_crafting": "Fabbricazione meccanica", - "create.recipe.automatic_shaped": "Fabbricazione automatizzata con forma", - "create.recipe.block_cutting": "Taglio di blocchi", - "create.recipe.wood_cutting": "Taglio di legna", - "create.recipe.sandpaper_polishing": "Levigamento da carta vetrata", - "create.recipe.mystery_conversion": "Metamorfosi misteriosa", - "create.recipe.spout_filling": "Riempimento", - "create.recipe.draining": "Drenaggio", - "create.recipe.item_application": "Applicazione manuale", - "create.recipe.item_application.any_axe": "Qualunque ascia", - "create.recipe.sequenced_assembly": "Installazione sequenziale", - "create.recipe.assembly.next": "Prossimo: %1$s", - "create.recipe.assembly.step": "Passo %1$s:", - "create.recipe.assembly.progress": "Progresso: %1$s/%2$s", - "create.recipe.assembly.pressing": "Pressatura", - "create.recipe.assembly.spout_filling_fluid": "Riempi con %1$s", - "create.recipe.assembly.deploying_item": "Installa %1$s", - "create.recipe.assembly.cutting": "Taglia con Sega", - "create.recipe.assembly.repeat": "Ripeti sequenza %1$s volte", - "create.recipe.assembly.junk": "Scarto casuale", - "create.recipe.processing.chance": "%1$s%% di probabilità", - "create.recipe.deploying.not_consumed": "Non consumato", - "create.recipe.heat_requirement.none": "Nessun riscaldamento", - "create.recipe.heat_requirement.heated": "Riscaldamento", - "create.recipe.heat_requirement.superheated": "Super riscaldamento", - - "create.generic.range": "Portata", - "create.generic.radius": "Raggio", - "create.generic.width": "Larghezza", - "create.generic.height": "Altezza", - "create.generic.length": "Lunghezza", - "create.generic.speed": "Velocità", - "create.generic.delay": "Ritardo", - "create.generic.duration": "Durata", - "create.generic.timeUnit": "Unità di tempo", - "create.generic.unit.ticks": "Tick", - "create.generic.unit.seconds": "Secondi", - "create.generic.unit.minutes": "Minuti", - "create.generic.daytime.hour": "Ore", - "create.generic.daytime.minute": "Minuti", - "create.generic.daytime.second": "Secondi", - "create.generic.daytime.pm": "PM", - "create.generic.daytime.am": "AM", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "SU", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$s mB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "Senso orario", - "create.generic.counter_clockwise": "Senso anti-orario", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "Intonazione: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Scorri", - "create.action.confirm": "Conferma", - "create.action.abort": "Annulla", - "create.action.saveToFile": "Salva", - "create.action.discard": "Scarta", - - "create.keyinfo.toolmenu": "Focalizzazione sul menù degli strumenti", - "create.keyinfo.toolbelt": "Accedi a cassette degli attrezzi vicine", - "create.keyinfo.scrollup": "Simula rotellina del mouse verso su (nel mondo)", - "create.keyinfo.scrolldown": "Simula rotellina del mouse verso giù (nel mondo)", - - "create.gui.scrollInput.defaultTitle": "Scegli un'opzione:", - "create.gui.scrollInput.scrollToModify": "Scorri per modificare", - "create.gui.scrollInput.scrollToAdjustAmount": "Scorri per regolare il valore", - "create.gui.scrollInput.scrollToSelect": "Scorri per selezionare", - "create.gui.scrollInput.shiftScrollsFaster": "Premi shift per scorrere più velocemente", - "create.gui.toolmenu.focusKey": "Premi [%1$s] per aprire il menù", - "create.gui.toolmenu.cycle": "[SCORRI] per navigare", - - "create.toolbox.unequip": "Rimuovi: %1$s", - "create.toolbox.outOfRange": "Cassetta con l'oggetto in mano fuori portata", - "create.toolbox.detach": "Smetti di monitorare e tieni l'oggetto", - "create.toolbox.depositAll": "Deposita gli oggetti nelle cassette vicine", - "create.toolbox.depositBox": "Posa l'oggetto nella cassetta", - - "create.gui.symmetryWand.mirrorType": "Specchio", - "create.gui.symmetryWand.orientation": "Orientamento", - - "create.symmetry.mirror.plane": "Singolo", - "create.symmetry.mirror.doublePlane": "Rettangolare", - "create.symmetry.mirror.triplePlane": "Ottagonale", - - "create.orientation.orthogonal": "Ortogonale", - "create.orientation.diagonal": "Diagonale", - "create.orientation.horizontal": "Orizzontale", - "create.orientation.alongZ": "Lungo Z", - "create.orientation.alongX": "Lungo X", - - "create.gui.terrainzapper.title": "Plasmatore del mondo", - "create.gui.terrainzapper.searchDiagonal": "Segui diagonali", - "create.gui.terrainzapper.searchFuzzy": "Ignora bordi", - "create.gui.terrainzapper.patternSection": "Motivo", - "create.gui.terrainzapper.pattern.solid": "Solido", - "create.gui.terrainzapper.pattern.checkered": "Scacchiera", - "create.gui.terrainzapper.pattern.inversecheckered": "Scacchiera invertita", - "create.gui.terrainzapper.pattern.chance25": "Casuale al 25%", - "create.gui.terrainzapper.pattern.chance50": "Casuale al 50%", - "create.gui.terrainzapper.pattern.chance75": "Casuale al 75%", - "create.gui.terrainzapper.placement": "Piazzamento", - "create.gui.terrainzapper.placement.merged": "Fuso", - "create.gui.terrainzapper.placement.attached": "Attaccato", - "create.gui.terrainzapper.placement.inserted": "Inserito", - "create.gui.terrainzapper.brush": "Pennello", - "create.gui.terrainzapper.brush.cuboid": "Cuboide", - "create.gui.terrainzapper.brush.sphere": "Sferico", - "create.gui.terrainzapper.brush.cylinder": "Cilindrico", - "create.gui.terrainzapper.brush.surface": "Superficie", - "create.gui.terrainzapper.brush.cluster": "Aggregato", - "create.gui.terrainzapper.tool": "Strumento", - "create.gui.terrainzapper.tool.fill": "Riempi", - "create.gui.terrainzapper.tool.place": "Piazza", - "create.gui.terrainzapper.tool.replace": "Sostituisci", - "create.gui.terrainzapper.tool.clear": "Ripulisci", - "create.gui.terrainzapper.tool.overlay": "Ricopri", - "create.gui.terrainzapper.tool.flatten": "Appiattisci", - - "create.terrainzapper.shiftRightClickToSet": "Shift-click destro per impostare la forma", - "create.terrainzapper.usingBlock": "Blocco in uso: %1$s", - "create.terrainzapper.leftClickToSet": "Fai click sinistro su un blocco per scegliere il materiale", - - "create.minecart_coupling.two_couplings_max": "I carrelli da miniera non possono avere più di due agganci ciascuno", - "create.minecart_coupling.unloaded": "Parti del tuo Macchinario sembrano essere in mezzo a chunk non caricati", - "create.minecart_coupling.no_loops": "Gli agganci non possono creare un loop", - "create.minecart_coupling.removed": "Agganci rimossi dai carrelli da miniera", - "create.minecart_coupling.too_far": "Carrelli da miniera troppo distanti", - - "create.contraptions.movement_mode": "Modalità di movimento", - "create.contraptions.movement_mode.move_place": "Posiziona sempre quando è fermo", - "create.contraptions.movement_mode.move_place_returned": "Posiziona solo nella direzione iniziale", - "create.contraptions.movement_mode.move_never_place": "Posiziona solo quando distrutto", - "create.contraptions.movement_mode.rotate_place": "Ruota sempre quando è fermo", - "create.contraptions.movement_mode.rotate_place_returned": "Ruota solo vicino all'angolo iniziale", - "create.contraptions.movement_mode.rotate_never_place": "Ruota solo quando l'ancora viene distrutta", - "create.contraptions.cart_movement_mode": "Modalità di movimento del carrello", - "create.contraptions.cart_movement_mode.rotate": "Sempre rivolto verso il movimento", - "create.contraptions.cart_movement_mode.rotate_paused": "Pausa durante la rotazione", - "create.contraptions.cart_movement_mode.rotation_locked": "Blocca rotazione", - "create.contraptions.windmill.rotation_direction": "Direzione di rotazione", - "create.contraptions.clockwork.clock_hands": "Lancette dell'orologio", - "create.contraptions.clockwork.hour_first": "Prima lancetta delle ore", - "create.contraptions.clockwork.minute_first": "Prima lancetta dei minuti", - "create.contraptions.clockwork.hour_first_24": "Prima lancetta delle 24 ore", - - "create.logistics.filter": "Filtro", - "create.logistics.recipe_filter": "Filtro ricette", - "create.logistics.fluid_filter": "Filtro fluidi", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Filtro applicato a %1$s.", - "create.logistics.filter.apply_click_again": "Filtro applicato a %1$s, clicca di nuovo per copiare.", - "create.logistics.filter.apply_count": "Conteggio estrazione applicato ai filtri.", - - "create.gui.goggles.generator_stats": "Statistiche del generatore:", - "create.gui.goggles.kinetic_stats": "Statistiche cinetiche:", - "create.gui.goggles.at_current_speed": "alla velocità attuale", - "create.gui.goggles.pole_length": "Lunghezza palo:", - "create.gui.goggles.fluid_container": "Statistiche del contenitore di fluidi:", - "create.gui.goggles.fluid_container.capacity": "Capacità: ", - "create.gui.assembly.exception": "Questo Macchinario non può essere assemblato:", - "create.gui.assembly.exception.unmovableBlock": "Blocco inamovibile (%4$s) alle coordinate [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Il blocco di coordinate [%1$s,%2$s,%3$s] non era in un chunk caricato", - "create.gui.assembly.exception.structureTooLarge": "Ci sono troppi blocchi inclusi nel Macchinario.\nIl massimo è impostato a: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Ci sono troppi Pali di pistone attaccati a questo Pistone.\nIl massimo èimpostato a: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Questo Pistone non ha Pali per pistone attaccati", - "create.gui.assembly.exception.not_enough_sails": "La struttura attaccata non include abbastanza blocchi simili a vele: %1$s\nNe servono un minimo di %2$s", - "create.gui.gauge.info_header": "Informazioni sul sistema:", - "create.gui.speedometer.title": "Velocità di rotazione", - "create.gui.stressometer.title": "Stress della rete", - "create.gui.stressometer.capacity": "Capacità rimanente", - "create.gui.stressometer.overstressed": "Sovraccarico", - "create.gui.stressometer.no_rotation": "Nessuna rotazione", - "create.gui.contraptions.not_fast_enough": "Sembra che questo %1$s _non_ stia girando con una _velocità_ _sufficiente_.", - "create.gui.contraptions.network_overstressed": "Sembra che questo sistema sia _sovraccarico_. Aggiungi più generatori o _rallenta_ i componenti con un forte _impatto_ _sullo_ _stress_.", - "create.gui.adjustable_crate.title": "Baule regolabile", - "create.gui.adjustable_crate.storageSpace": "Spazio di immagazzinamento", - "create.gui.stockpile_switch.title": "Interruttore a riempimento", - "create.gui.stockpile_switch.invert_signal": "Inverti segnale", - "create.gui.stockpile_switch.move_to_lower_at": "Muovi giù al %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Muovi su al %1$s%%", - "create.gui.sequenced_gearshift.title": "Cambio sequenziale", - "create.gui.sequenced_gearshift.instruction": "Istruzione", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Ruota ad angolo", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Gira", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angolo", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Ruota per muovere Pistone/Gru/Carrucola", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistone", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distanza", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Attendi", - "create.gui.sequenced_gearshift.instruction.delay": "Attesa", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Durata", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Fine", - "create.gui.sequenced_gearshift.instruction.end": "Fine", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Attendi impulso redstone", - "create.gui.sequenced_gearshift.instruction.await": "Redstone", - "create.gui.sequenced_gearshift.speed": "Velocità, direzione", - "create.gui.sequenced_gearshift.speed.forward": "Velocità di ingresso, avanti", - "create.gui.sequenced_gearshift.speed.forward_fast": "Doppia velocità, avanti", - "create.gui.sequenced_gearshift.speed.back": "Velocità di ingresso, invertita", - "create.gui.sequenced_gearshift.speed.back_fast": "Doppia velocità, invertita", - - "create.schematicAndQuill.dimensions": "Dimensione progetto: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Prima posizione impostata.", - "create.schematicAndQuill.secondPos": "Seconda posizione impostata.", - "create.schematicAndQuill.noTarget": "Premi [Ctrl] per selezionare un blocco d'aria.", - "create.schematicAndQuill.abort": "Selezione rimossa.", - "create.schematicAndQuill.title": "Nome progetto:", - "create.schematicAndQuill.convert": "Salva e piazza immediatamente", - "create.schematicAndQuill.fallbackName": "Il mio progetto", - "create.schematicAndQuill.saved": "Salvato come %1$s", - - "create.schematic.invalid": "[!] Oggetto non valido - utilizza il banco dei progetti", - "create.schematic.position": "Posizione", - "create.schematic.rotation": "Rotazione", - "create.schematic.rotation.none": "Nessuna", - "create.schematic.rotation.cw90": "Senso orario 90", - "create.schematic.rotation.cw180": "Senso orario 180", - "create.schematic.rotation.cw270": "Senso orario 270", - "create.schematic.mirror": "Specchio", - "create.schematic.mirror.none": "Nessuno", - "create.schematic.mirror.frontBack": "Fronte-retro", - "create.schematic.mirror.leftRight": "Sinistra-destra", - "create.schematic.tool.deploy": "Posiziona", - "create.schematic.tool.move": "Muovi XZ", - "create.schematic.tool.movey": "Muovi Y", - "create.schematic.tool.rotate": "Ruota", - "create.schematic.tool.print": "Installa", - "create.schematic.tool.flip": "Capovolgi", - "create.schematic.tool.deploy.description.0": "Sposta la struttura in una posizione.", - "create.schematic.tool.deploy.description.1": "Click destro sul terreno per posizionare la struttura.", - "create.schematic.tool.deploy.description.2": "Premi [Ctrl] per selezionare a distanza fissa.", - "create.schematic.tool.deploy.description.3": "[Ctrl] e scorri per cambiare la distanza.", - "create.schematic.tool.move.description.0": "Sposta il progetto in orizzontale.", - "create.schematic.tool.move.description.1": "Indica il progetto e premi [Ctrl] mentre scorri per spingerlo.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Sposta il progetto verticalmente.", - "create.schematic.tool.movey.description.1": "[Ctrl] e scorri per spostarlo su/giù.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Ruota il progetto attorno al suo centro.", - "create.schematic.tool.rotate.description.1": "[Ctrl] e scorri per ruotarlo di 90 gradi.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Posiziona istantaneamente la struttura nel mondo.", - "create.schematic.tool.print.description.1": "Click destro per confermare la posizione corrente.", - "create.schematic.tool.print.description.2": "Questo strumento è solo per la modalità creativa.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Capovolge il progetto lungo la faccia selezionata.", - "create.schematic.tool.flip.description.1": "Indica il progetto e premi [Ctrl] mentre scorri per capovolgerla.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Sincronizzazione...", - "create.schematics.uploadTooLarge": "Il progetto è troppo grande.", - "create.schematics.maxAllowedSize": "La dimensione massima consentita del file di progetto è:", - - "create.gui.schematicTable.refresh": "Ricarica file", - "create.gui.schematicTable.open_folder": "Apri cartella", - "create.gui.schematicTable.title": "Banco dei progetti", - "create.gui.schematicTable.availableSchematics": "Progetti disponibili", - "create.gui.schematicTable.noSchematics": "Nessun progetto salvato", - "create.gui.schematicTable.uploading": "Caricamento...", - "create.gui.schematicTable.finished": "Caricamento completato!", - "create.gui.schematicannon.title": "Spara-progetti", - "create.gui.schematicannon.listPrinter": "Stampante lista dei materiali", - "create.gui.schematicannon.gunpowderLevel": "Polvere da sparo al %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Spari rimanenti: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Con il backup: %1$s", - "create.gui.schematicannon.optionEnabled": "Opzione attiva", - "create.gui.schematicannon.optionDisabled": "Opzione inattiva", - "create.gui.schematicannon.showOptions": "Mostra impostazioni stampante", - "create.gui.schematicannon.option.dontReplaceSolid": "Non sostituire i blocchi solidi", - "create.gui.schematicannon.option.replaceWithSolid": "Sostituisci solidi con solidi", - "create.gui.schematicannon.option.replaceWithAny": "Sostituisci solidi con qualsiasi", - "create.gui.schematicannon.option.replaceWithEmpty": "Sostituisci solidi con il vuoto", - "create.gui.schematicannon.option.skipMissing": "Salta i blocchi mancanti", - "create.gui.schematicannon.option.skipTileEntities": "Proteggi i blocchi entità", - "create.gui.schematicannon.slot.gunpowder": "Aggiungi polvere da sparo per alimentare il cannone", - "create.gui.schematicannon.slot.listPrinter": "Piazza qui i libri per stampare una lista di controllo per il tuo progetto", - "create.gui.schematicannon.slot.schematic": "Aggiungi qui il tuo progetto. Assicurati che sia piazzato in una posizione specifica.", - "create.gui.schematicannon.option.skipMissing.description": "Se il cannone non riesce a trovare un blocco richiesto per il posizionamento, continuerà nella posizione successiva.", - "create.gui.schematicannon.option.skipTileEntities.description": "Il cannone eviterà di sostituire i blocchi entità come bauli o fornaci.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Il cannone non sostituirà mai alcun blocco solido nella sua area di lavoro, solo non-solidi e aria.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Il cannone sostituirà i blocchi solidi nella sua area di lavoro se lo schema contiene un blocco solido in quella posizione.", - "create.gui.schematicannon.option.replaceWithAny.description": "Il cannone sostituirà i blocchi solidi nella sua area di lavoro se lo schema contiene un blocco qualunque in quella posizione.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Il cannone eliminerà tutti i blocchi nell'area di lavoro, compresi quelli che nel progetto sono solo aria.", - - "create.schematicannon.status.idle": "Inattivo", - "create.schematicannon.status.ready": "Pronto", - "create.schematicannon.status.running": "In esecuzione", - "create.schematicannon.status.finished": "Finito", - "create.schematicannon.status.paused": "In pausa", - "create.schematicannon.status.stopped": "Fermo", - "create.schematicannon.status.noGunpowder": "Polvere da sparo mancante", - "create.schematicannon.status.targetNotLoaded": "Il blocco non è caricato", - "create.schematicannon.status.targetOutsideRange": "Obiettivo troppo lontano", - "create.schematicannon.status.searching": "Ricerca", - "create.schematicannon.status.skipping": "Skip", - "create.schematicannon.status.missingBlock": "Blocco mancante:", - "create.schematicannon.status.placing": "Piazzamento", - "create.schematicannon.status.clearing": "Cancellazione blocchi", - "create.schematicannon.status.schematicInvalid": "Progetto non valido", - "create.schematicannon.status.schematicNotPlaced": "Bersaglio non impostato", - "create.schematicannon.status.schematicExpired": "File progetto mancante", - - "create.materialChecklist": "Lista dei materiali", - "create.materialChecklist.blocksNotLoaded": "* Attenzione *\n\nLa lista dei materiali potrebbe non essere accurata a causa di molti chunk non caricati.", - - "create.gui.filter.deny_list": "Lista nera", - "create.gui.filter.deny_list.description": "Gli oggetti passano se NON corrispondono a nessuno di quelli nel filtro. Una lista nera vuota accetta tutto.", - "create.gui.filter.allow_list": "Lista bianca", - "create.gui.filter.allow_list.description": "Gli oggetti passano se corrispondono a qualcuno di quelli nel filtro. Una lista bianca vuota rifiuta tutto.", - "create.gui.filter.respect_data": "Rispetta dati", - "create.gui.filter.respect_data.description": "Gli oggetti corrispondono solo se la loro durata, incantesimi e altri attributi corrispondono.", - "create.gui.filter.ignore_data": "Ignora dati", - "create.gui.filter.ignore_data.description": "Gli oggetti corrispondono indipendentemente dai loro attributi.", - - "create.item_attributes.placeable": "è posizionabile", - "create.item_attributes.placeable.inverted": "non è posizionabile", - "create.item_attributes.consumable": "è commestibile", - "create.item_attributes.consumable.inverted": "non è commestibile", - "create.item_attributes.fluid_container": "può contenere fluidi", - "create.item_attributes.fluid_container.inverted": "non può contenere fluidi", - "create.item_attributes.enchanted": "è incantato", - "create.item_attributes.enchanted.inverted": "non è incantato", - "create.item_attributes.max_enchanted": "è incantanto al massimo livello", - "create.item_attributes.max_enchanted.inverted": "non è incantanto al massimo livello", - "create.item_attributes.renamed": "ha un nome personalizzato", - "create.item_attributes.renamed.inverted": "non ha un nome personalizzato", - "create.item_attributes.damaged": "è danneggiato", - "create.item_attributes.damaged.inverted": "non è danneggiato", - "create.item_attributes.badly_damaged": "è gravemente danneggiato", - "create.item_attributes.badly_damaged.inverted": "non è gravemente danneggiato", - "create.item_attributes.not_stackable": "non è impilabile", - "create.item_attributes.not_stackable.inverted": "è impilabile", - "create.item_attributes.equipable": "può essere equipaggiato", - "create.item_attributes.equipable.inverted": "non può essere equipaggiato", - "create.item_attributes.furnace_fuel": "è un combustibile per fornace", - "create.item_attributes.furnace_fuel.inverted": "non è un combustibile per fornace", - "create.item_attributes.washable": "può essere lavato", - "create.item_attributes.washable.inverted": "non può essere lavato", - "create.item_attributes.hauntable": "può essere infestato", - "create.item_attributes.hauntable.inverted": "non può essere infestato", - "create.item_attributes.crushable": "può essere frantumato", - "create.item_attributes.crushable.inverted": "non può essere frantumato", - "create.item_attributes.smeltable": "può essere fuso", - "create.item_attributes.smeltable.inverted": "non può essere fuso", - "create.item_attributes.smokable": "può essere affumicato", - "create.item_attributes.smokable.inverted": "non può essere affumicato", - "create.item_attributes.blastable": "è fondibile in un forno fusorio", - "create.item_attributes.blastable.inverted": "non è fondibile in un forno fusorio", - "create.item_attributes.compostable": "può essere gettato in una compstiera", - "create.item_attributes.compostable.inverted": "non può essere gettato in una compstiera", - "create.item_attributes.shulker_level": "è uno shulker %1$s", - "create.item_attributes.shulker_level.inverted": "non è uno shulker %1$s", - "create.item_attributes.shulker_level.full": "pieno", - "create.item_attributes.shulker_level.empty": "vuoto", - "create.item_attributes.shulker_level.partial": "parzialmente pieno", - "create.item_attributes.in_tag": "è etichettato %1$s", - "create.item_attributes.in_tag.inverted": "non è etichettato %1$s", - "create.item_attributes.in_item_group": "appartiene al gruppo %1$s", - "create.item_attributes.in_item_group.inverted": "non appartiene al gruppo '%1$s'", - "create.item_attributes.added_by": "è stato aggiunto da %1$s", - "create.item_attributes.added_by.inverted": "non è stato aggiunto da %1$s", - "create.item_attributes.has_enchant": "è stato incantato con %1$s", - "create.item_attributes.has_enchant.inverted": "non è stato incantato con %1$s", - "create.item_attributes.color": "è di colore %1$s", - "create.item_attributes.color.inverted": "non è di colore %1$s", - "create.item_attributes.has_fluid": "contiene %1$s", - "create.item_attributes.has_fluid.inverted": "non contiene %1$s", - "create.item_attributes.has_name": "è stato rinominato in %1$s", - "create.item_attributes.has_name.inverted": "non è stato rinominato in %1$s", - "create.item_attributes.book_author": "è stato firmato da %1$s", - "create.item_attributes.book_author.inverted": "non è stato firmato da %1$s", - "create.item_attributes.book_copy_original": "è una copia originale", - "create.item_attributes.book_copy_original.inverted": "non è una copia originale", - "create.item_attributes.book_copy_first": "è una copia di prima generazione", - "create.item_attributes.book_copy_first.inverted": "non è una copia di prima generazione", - "create.item_attributes.book_copy_second": "è una copia di seconda generazione", - "create.item_attributes.book_copy_second.inverted": "non è una copia di seconda generazione", - "create.item_attributes.book_copy_tattered": "è in condizioni precarie", - "create.item_attributes.book_copy_tattered.inverted": "non è in condizioni precarie", - "create.item_attributes.astralsorcery_amulet": "migliora %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "non migliora %1$s", - "create.item_attributes.astralsorcery_constellation": "è in sintonia con %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "non è in sintonia con %1$s", - "create.item_attributes.astralsorcery_crystal": "ha l'attributo del cristallo %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "non ha l'attributo del cristallo %1$s", - "create.item_attributes.astralsorcery_perk_gem": "ha l'attributo benefico %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "non ha l'attributo benefico %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Nessun attributo selezionato", - "create.gui.attribute_filter.selected_attributes": "Attributi selezionati:", - "create.gui.attribute_filter.add_attribute": "Aggiungi attributi alla lista", - "create.gui.attribute_filter.add_inverted_attribute": "Aggiungi attributo opposto alla lista", - "create.gui.attribute_filter.allow_list_disjunctive": "Lista bianca (qualsiasi)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Gli oggetti passano se hanno almeno uno degli attributi selezionati.", - "create.gui.attribute_filter.allow_list_conjunctive": "Lista Bianca (tutti)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Gli oggetti passano solo se hanno TUTTI gli attributi selezionati.", - "create.gui.attribute_filter.deny_list": "Lista nera", - "create.gui.attribute_filter.deny_list.description": "Gli oggetti passano se NON hanno nessuno degli attributi selezionati.", - "create.gui.attribute_filter.add_reference_item": "Aggiungi riferimento", - - "create.tooltip.holdForDescription": "Tieni premuto [%1$s] per un riepilogo", - "create.tooltip.holdForControls": "Tieni premuto [%1$s] per i comandi", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Velocità richiesta: %1$s", - "create.tooltip.speedRequirement.none": "Nessuna", - "create.tooltip.speedRequirement.slow": "Lenta", - "create.tooltip.speedRequirement.medium": "Moderata", - "create.tooltip.speedRequirement.fast": "Veloce", - "create.tooltip.stressImpact": "Impatto sullo stress: %1$s", - "create.tooltip.stressImpact.low": "Basso", - "create.tooltip.stressImpact.medium": "Medio", - "create.tooltip.stressImpact.high": "Alto", - "create.tooltip.stressImpact.overstressed": "Sovraccarico", - "create.tooltip.up_to": "Fino a %1$s", - "create.tooltip.capacityProvided": "Capacità di stress: %1$s", - "create.tooltip.capacityProvided.low": "Piccola", - "create.tooltip.capacityProvided.medium": "Media", - "create.tooltip.capacityProvided.high": "Grande", - "create.tooltip.generationSpeed": "Genera %1$s %2$s", - "create.tooltip.analogStrength": "Forza analogica: %1$s/15", - - "create.mechanical_arm.extract_from": "Prendi oggetti da %1$s", - "create.mechanical_arm.deposit_to": "Deposita oggetti su %1$s", - "create.mechanical_arm.summary": "Il braccio meccanico ha %1$s input e %2$s output.", - "create.mechanical_arm.points_outside_range": "%1$s punti di interazione selezionati rimossi per limiti di portata.", - - "create.weighted_ejector.target_set": "Bersaglio selezionato", - "create.weighted_ejector.target_not_valid": "Impostato su blocco adiacente (Bersaglio non valido)", - "create.weighted_ejector.no_target": "Impostato su blocco adiacente (Nessun bersaglio selezionato)", - "create.weighted_ejector.targeting": "Impostato su [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Grandezza stack da lanciare", - - "create.logistics.when_multiple_outputs_available": "Se esistono più output validi", - - "create.mechanical_arm.selection_mode.round_robin": "Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "Round Robin forzato", - "create.mechanical_arm.selection_mode.prefer_first": "Dai precedenza al primo", - - "create.tunnel.selection_mode.split": "Dividi", - "create.tunnel.selection_mode.forced_split": "Dividi forzatamente", - "create.tunnel.selection_mode.round_robin": "Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "Round Robin forzato", - "create.tunnel.selection_mode.prefer_nearest": "Dai precedenza al più vicino", - "create.tunnel.selection_mode.randomize": "Distribuisci casualmente", - "create.tunnel.selection_mode.synchronize": "Sincronizza input", - - "create.tooltip.chute.header": "Informazioni sullo scivolo", - "create.tooltip.chute.items_move_down": "Gli oggetti si spostano verso il basso", - "create.tooltip.chute.items_move_up": "Gli oggetti si spostano verso l'alto", - "create.tooltip.chute.no_fans_attached": "Nessun ventilatore collegato", - "create.tooltip.chute.fans_push_up": "Il ventilatore spinge da sotto", - "create.tooltip.chute.fans_push_down": "Il ventilatore spinge da sopra", - "create.tooltip.chute.fans_pull_up": "Il ventilatore tira da sopra", - "create.tooltip.chute.fans_pull_down": "Il ventilatore tira da sotto", - "create.tooltip.chute.contains": "Contiene: %1$s x%2$s", - "create.tooltip.deployer.header": "Informazioni sull'Installatore", - "create.tooltip.deployer.using": "Modalità: Utilizzo", - "create.tooltip.deployer.punching": "Modalità: Attacco", - "create.tooltip.deployer.contains": "Oggetto: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Sta distribuendo:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Click destro per recuperare", - - "create.linked_controller.bind_mode": "Modalità associa-tasti attivata", - "create.linked_controller.press_keybind": "Premi %1$s, %2$s, %3$s, %4$s, %5$s o %6$s per associare questa frequenza al tasto scelto", - "create.linked_controller.key_bound": "Frequenza associata a: %1$s", - "create.linked_controller.frequency_slot_1": "Pulsante %1$s, Frequenza #1", - "create.linked_controller.frequency_slot_2": "Pulsante %1$s, Frequenza #2", - - "create.crafting_blueprint.crafting_slot": "Slot ingredienti", - "create.crafting_blueprint.filter_items_viable": "È permesso usare Filtri", - "create.crafting_blueprint.display_slot": "Slot visivo", - "create.crafting_blueprint.inferred": "Estratto dalla ricetta", - "create.crafting_blueprint.manually_assigned": "Assegnato manualmente", - "create.crafting_blueprint.secondary_display_slot": "Slot visivo secondario", - "create.crafting_blueprint.optional": "Opzionale", - - "create.potato_cannon.ammo.attack_damage": "Danni per colpo: %1$s", - "create.potato_cannon.ammo.reload_ticks": "Ricarica: %1$s ticks", - "create.potato_cannon.ammo.knockback": "Contraccolpo: %1$s", - - "create.hint.hose_pulley.title": "Fonte infinita", - "create.hint.hose_pulley": "Il fluido da cui stai estraendo è considerato infinito.", - "create.hint.mechanical_arm_no_targets.title": "Nessun bersaglio", - "create.hint.mechanical_arm_no_targets": "Sembra che questo _braccio_ _meccanico_ non sia stato assegnato a nessun _bersaglio_. Seleziona nastri, Stazioni per oggetti, imbuti e altri blocchi _cliccandoli_ _con_ _il_ _pulsante_ _destro_ mentre _hai_ _in_ _mano_ il _braccio_ _meccanico_.", - "create.hint.empty_bearing.title": "Attiva il supporto", - "create.hint.empty_bearing": "_Fai_ _clic_ _destro_ sul supporto con una _mano_ _vuota_ per _connetterlo_ alla struttura che hai costruito davanti ad esso.", - "create.hint.full_deployer.title": "Overflow di oggetti dell'installatore", - "create.hint.full_deployer": "Sembra che questo _installatore_ contenga _oggetti_ _eccessivi_ che necessitano di essere _estratti_. Usa una _tramoggia_, un _imbuto_ o altro per liberarlo dall'overflow.", - - "create.backtank.low": "Pressione bassa nello Zaino serbatoio", - "create.backtank.depleted": "Pressione esaurita nello Zaino serbatoio", - - "create.hint.derailed_train.title": "Treno deragliato", - "create.hint.derailed_train": "Sembra che questo _Treno_ non si trovi più sopra delle Rotaie. Fai _Click_ _destro_ con una _chiave_ _inglese_ per riportarlo su una Rotaia vicina.", - - "create.boiler.status": "Status della caldaia: %1$s", - "create.boiler.status_short": "Caldaia: %1$s", - "create.boiler.passive": "Passivo", - "create.boiler.idle": "Inattivo", - "create.boiler.lvl": "Lv %1$s", - "create.boiler.max_lvl": "Max", - "create.boiler.size": "Spazio", - "create.boiler.size_dots": "..................... ", - "create.boiler.water": "Acqua", - "create.boiler.water_dots": "...................... ", - "create.boiler.heat": "Temperatura", - "create.boiler.heat_dots": "..... ", - "create.boiler.via_one_engine": "tramite 1 motore", - "create.boiler.via_engines": "tramite %1$s motori", - - "create.gui.schedule.lmb_edit": "Click sinistro per modificare", - "create.gui.schedule.rmb_remove": "Click destro per rimuovere", - "create.gui.schedule.duplicate": "Duplica", - "create.gui.schedule.remove_entry": "Rimuovi azione", - "create.gui.schedule.add_entry": "Aggiungi azione", - "create.gui.schedule.move_up": "Sposta in alto", - "create.gui.schedule.move_down": "Sposta in basso", - "create.gui.schedule.add_condition": "Aggiungi condizione (AND)", - "create.gui.schedule.alternative_condition": "Condizione alternativa (OR)", - - "create.schedule.instruction_type": "Prossima azione:", - "create.schedule.instruction.editor": "Editor di Istruzioni", - "create.schedule.instruction.destination": "Raggiungi stazione", - "create.schedule.instruction.destination.summary": "Prossima Fremata:", - "create.schedule.instruction.filter_edit_box": "Nome della stazione", - "create.schedule.instruction.filter_edit_box_1": "Usa * come testo jolly.", - "create.schedule.instruction.filter_edit_box_2": "Ad esempio, se scrivi 'Stazione Centrale, Binario *',", - "create.schedule.instruction.filter_edit_box_3": "il treno sceglierà la stazione libera corrispondente più vicina.", - "create.schedule.instruction.rename": "Cambia nome tabella", - "create.schedule.instruction.rename.summary": "Nuovo nome:", - "create.schedule.instruction.name_edit_box": "Nome della tabella di marcia", - "create.schedule.instruction.name_edit_box_1": "Modifica il testo letto dai Lettori di dati.", - "create.schedule.instruction.name_edit_box_2": "Normalmente impostato al nome della stazione di destinazione.", - "create.schedule.instruction.throttle": "Cambia velocità massima", - "create.schedule.instruction.throttle.summary": "Imposta velocità massima a %1$s", - "create.schedule.instruction.throttle_edit_box": "Velocità", - "create.schedule.instruction.throttle_edit_box_1": "Modifica la velocità massima raggiunta dal treno.", - "create.schedule.condition_type": "Continua se/dopo:", - "create.schedule.condition.editor": "Editor di Condizioni", - "create.schedule.condition.delay": "Attesa fissa", - "create.schedule.condition.delay_short": "Attendi: %1$s", - "create.schedule.condition.delay.status": "Parte tra %1$s", - "create.schedule.condition.idle": "Inattività del carico", - "create.schedule.condition.idle_short": "Fermo per: %1$s", - "create.schedule.condition.idle.status": "Carico fermo per %1$s", - "create.schedule.condition.for_x_time": "per %1$s", - "create.schedule.condition.unloaded": "Chunk non caricato", - "create.schedule.condition.unloaded.status": "In attesa del decaricamento del chunk", - "create.schedule.condition.powered": "Segn. redstone in Stazione", - "create.schedule.condition.powered.status": "In attesa di redstone", - "create.schedule.condition.time_of_day": "Orario", - "create.schedule.condition.time_of_day.scheduled": "Orario di partenza: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "Ripeti", - "create.schedule.condition.time_of_day.rotation.every_24": "ogni giorno", - "create.schedule.condition.time_of_day.rotation.every_12": "ogni 12 ore", - "create.schedule.condition.time_of_day.rotation.every_6": "ogni 6 ore", - "create.schedule.condition.time_of_day.rotation.every_4": "ogni 4 ore", - "create.schedule.condition.time_of_day.rotation.every_3": "ogni 3 ore", - "create.schedule.condition.time_of_day.rotation.every_2": "ogni 2 ore", - "create.schedule.condition.time_of_day.rotation.every_1": "ogni ora", - "create.schedule.condition.time_of_day.rotation.every_0_45": "ogni 45 min", - "create.schedule.condition.time_of_day.rotation.every_0_30": "ogni 30 min", - "create.schedule.condition.time_of_day.rotation.every_0_15": "ogni 15 min", - "create.schedule.condition.time_of_day.status": "In partenza alle:", - "create.schedule.condition.threshold.train_holds": "Il treno contiene %1$s", - "create.schedule.condition.threshold.greater": "più di", - "create.schedule.condition.threshold.less": "meno di", - "create.schedule.condition.threshold.equal": "esattamente", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$s di %3$s", - "create.schedule.condition.threshold.matching_content": "Contenuto corrispondente", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "Misura", - "create.schedule.condition.threshold.items": "Oggetti", - "create.schedule.condition.threshold.stacks": "Stack", - "create.schedule.condition.threshold.buckets": "Secchi", - "create.schedule.condition.threshold.status": "Carico: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "Oggetto di riferimento", - "create.schedule.condition.threshold.place_item_2": "È permesso usare Filtri", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "Carico di fluidi", - "create.schedule.condition.item_threshold": "Carico di oggetti", - "create.schedule.condition.redstone_link": "Connessione redstone", - "create.schedule.condition.redstone_link.status": "In attesa di segnale", - "create.schedule.condition.redstone_link_on": "Segnale On", - "create.schedule.condition.redstone_link_off": "Segnale Off", - "create.schedule.condition.redstone_link.powered": "Segnale acceso", - "create.schedule.condition.redstone_link.unpowered": "Segnale spento", - "create.schedule.condition.redstone_link.frequency_state": "Stato della frequenza:", - "create.schedule.condition.redstone_link.frequency_powered": "Frequenza accesa:", - "create.schedule.condition.redstone_link.frequency_unpowered": "Frequenza spenta:", - "create.schedule.condition.player_count": "Giocatori seduti", - "create.schedule.condition.player_count.summary": "%1$s giocatore", - "create.schedule.condition.player_count.summary_plural": "%1$s giocatori", - "create.schedule.condition.player_count.seated": "%1$s seduti", - "create.schedule.condition.player_count.players": "Giocatori", - "create.schedule.condition.player_count.condition": "Condizione", - "create.schedule.condition.player_count.exactly": "Esattamente", - "create.schedule.condition.player_count.or_above": "O superiore", - "create.schedule.condition.player_count.status": "Passeggeri: %1$s/%2$s", - "create.schedule.loop": "Ripeti all'infinito", - "create.schedule.loop1": "La tabella di marcia", - "create.schedule.loop2": "ricomincia dopo aver finito", - "create.schedule.reset": "Azzera progressi", - "create.schedule.skip": "Salta fermata attuale", - "create.schedule.applied_to_train": "Il treno seguirà questa Tabella di marcia", - "create.schedule.non_controlling_seat": "Il conducente deve essere seduto davanti ai Comandi del treno", - "create.schedule.remove_with_empty_hand": "Rimuovi la Tabella di marcia attuale con una mano vuota", - "create.schedule.auto_removed_from_train": "Tabella di marcia rimossa", - "create.schedule.removed_from_train": "Tabella di marcia recuperata", - "create.schedule.no_stops": "Questa Tabella di marcia non ha ancora fermate", - "create.schedule.continued": "Tabella di marcia ripresa", - - "create.track.selection_cleared": "Selezione rimossa", - "create.track.valid_connection": "Connessione possibile ✔", - "create.track.second_point": "Posiziona una rotaia o seleziona un secondo punto", - "create.track.too_far": "Troppo lontano", - "create.track.original_missing": "Blocco originale rimosso. Premi da accovacciato per resettare", - "create.track.perpendicular": "Non puoi connettere perpendicolarmente", - "create.track.ascending_s_curve": "Impossibile creare curve a S in salita o discesa", - "create.track.too_sharp": "Curva troppo stretta", - "create.track.too_steep": "Tratto troppo ripido", - "create.track.slope_turn": "Impossibile iniziare o terminare un dislivello in curva", - "create.track.opposing_slopes": "Impossibile connettere dislivelli opposti", - "create.track.leave_slope_ascending": "Impossibile terminare questo dislivello durante la salita", - "create.track.leave_slope_descending": "Impossibile terminare questo dislivello durante la discesa", - "create.track.turn_90": "Puoi girare solo 90 gradi alla volta", - "create.track.junction_start": "Non puoi iniziare una connessione ad un incrocio", - "create.track.turn_start": "Non puoi iniziare una connessione su una curva", - "create.track.not_enough_tracks": "Non hai abbastanza Rotaie", - "create.track.not_enough_pavement": "Non hai abbastanza blocchi per la pavimentazione", - - "create.portal_track.failed": "Impossibile posizionare il binario nel portale:", - "create.portal_track.missing": "Portale di uscita non ancora generato", - "create.portal_track.blocked": "Destinazione bloccata (%1$s,%2$s,%3$s)", - - "create.station.idle": "Stazione in attesa", - "create.station.assembly_title": "Assemblaggio treni", - "create.station.close": "Chiudi finestra", - "create.station.cancel": "Annulla assemblaggio", - "create.station.failed": "Assemblaggio fallito", - "create.station.icon_type": "Tipo di icona", - "create.station.create_train": "Crea nuovo treno", - "create.station.assemble_train": "Assembla treno", - "create.station.disassemble_train": "Smonta treno", - "create.station.remove_schedule": "Recupera Tabella di marcia", - "create.station.remove_auto_schedule": "Scarta tabella di marcia automatica", - "create.station.no_assembly_diagonal": "Impossibile costruire treni", - "create.station.no_assembly_diagonal_1": "su Binari diagonali", - "create.station.no_assembly_curve": "Impossibile costruire treni", - "create.station.no_assembly_curve_1": "su una curva", - "create.station.train_not_aligned": "Impossibile smontare se le carrozze", - "create.station.train_not_aligned_1": "non sono tutte allineate", - "create.station.carriage_number": "Carrozza %1$s:", - "create.station.retry": "Risolvi e riprova", - "create.station.no_bogeys": "0 carrelli presenti", - "create.station.one_bogey": "1 carrello", - "create.station.more_bogeys": "%1$s carrelli", - "create.station.how_to": "Usa un Riv. di treno sulle Rotaie per creare un carrello.", - "create.station.how_to_1": "Rompi un carrello mirando al blocco superiore.", - "create.station.how_to_2": "Le carrozze si collegano con fino a due carrelli ognuna.", - - "create.train_assembly.too_many_bogeys": "Troppi carrelli connessi insieme: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "Il carrello di testa deve essere appena dietro ad un marcatore di stazione", - "create.train_assembly.no_bogeys": "Nessun carrello trovato", - "create.train_assembly.not_connected_in_order": "I carrelli non sono connessi in ordine", - "create.train_assembly.bogeys_too_close": "I carrelli %1$s e %2$s sono troppo vicini tra loro", - "create.train_assembly.single_bogey_carriage": "Questo tipo di carrello non può sorreggere una carrozzada solo", - "create.train_assembly.nothing_attached": "Non c'è nessuna struttura connessa al carrello %1$s", - "create.train_assembly.no_controls": "Devi montare sul treno almeno un blocco di Controlli ruotato in avanti", - "create.train_assembly.sideways_controls": "Ci sono dei Comandi del treno montati perpendicolarmente", - "create.train_assembly.bogey_created": "Carrello creato. Pemi ancora per cambiare tipo", - "create.train_assembly.requires_casing": "Usa dei Telai di treno per creare dei carrelli", - - "create.track_target.set": "Rotaia selezionata", - "create.track_target.success": "Connesso con successo alla Rotaia selezionata", - "create.track_target.clear": "Selezione rimossa", - "create.track_target.missing": "Fai prima click destro su una Rotaia", - "create.track_target.too_far": "La Rotaia selezionata è troppo lontata", - "create.track_target.no_junctions": "Non puoi selezionare un'intersezione", - "create.track_target.occupied": "La Rotaia selezionata è occupata", - "create.track_target.invalid": "Non puoi selezionare questa Rotaia in questo punto", - - "create.train.unnamed": "Treno senza nome", - "create.train.cannot_relocate_moving": "Non puoi spostare un treno in corsa", - "create.train.relocate": "Fai click su una Rotaia per spostare %1$s su di essa. Shift-click per annullare", - "create.train.relocate.abort": "Spostamento annullato", - "create.train.relocate.success": "Treno spostato con successo", - "create.train.relocate.valid": "Destinazione valida. Premi per confermare", - "create.train.relocate.invalid": "Impossibile spostare il treno qui", - "create.train.relocate.too_far": "Impossibile spostare così lontano", - "create.train.departing_from": "In partenza da %1$s", - "create.train.arrived_at": "Arrivo a %1$s", - "create.train.status": " Informazioni su questo treno: %1$s", - "create.train.status.back_on_track": "Il treno è tornato sulle Rotaie", - "create.train.status.collision": "Collisione con un altro treno", - "create.train.status.end_of_track": "Una carrozza ha raggiunto la fine della Rotaia", - "create.train.status.double_portal": "Una carrozza non può entrare in un portale senza aver prima lasciato il precedente", - "create.train.status.coupling_stress": "Fermata forzata a causa dello stress eccessivo", - "create.train.status.track_missing": "Rotaie mancanti al di sotto del treno", - "create.train.status.paused_for_manual": "Tabella di marcia in pausa a causa dei controlli manuali", - "create.train.status.opposite_driver": "Il percorso richiede un conducente in direzione opposta", - "create.train.status.missing_driver": "Il conducente è scomparso", - "create.train.status.found_driver": "Nuovo conducente trovato", - "create.train.status.navigation_success": "Navigazione conclusa con successo", - "create.train.status.no_match": "Nessuna stazione corrisponde a '%1$s'", - "create.train.status.no_path": "Nessun percorso trovato verso la prossima destinazione", - - "create.track_signal.cannot_change_mode": "Impossibile cambiare la modalità del segnale", - "create.track_signal.mode_change.entry_signal": "-> Permetti il passaggio se la sezione è libera", - "create.track_signal.mode_change.cross_signal": "-> Permetti il passaggio se la sezione è completamente attraversabile", - - "create.contraption.controls.start_controlling": "Al comando di: %1$s", - "create.contraption.controls.stop_controlling": "Hai smesso di guidare il macchinario", - "create.contraption.controls.approach_station": "Tieni premuto %1$s per fermarti a %2$s", - - "create.display_link.set": "Bersaglio selezionato", - "create.display_link.success": "Connesso con successo alla posizione selezionata", - "create.display_link.clear": "Selezione rimossa", - "create.display_link.too_far": "La posizione selezionata è troppo distante", - "create.display_link.invalid": "Il Connettore non ha bersagli validi, prova a piazzarlo di nuovo", - "create.display_link.title": "Lettore di dati", - "create.display_link.no_source": "Non una fonte di dati", - "create.display_link.no_target": "Non un visual. di dati", - "create.display_link.reading_from": "Lettura da:", - "create.display_link.writing_to": "Invio a:", - "create.display_link.attached_side": "Blocco sul lato agganciato", - "create.display_link.targeted_location": "Blocco nella posizione bersaglio", - "create.display_link.view_compatible": "Premi per vedere blocchi compatibili", - "create.display_link.information_type": "Tipo di informazione", - "create.display_link.display_on": "Scrivi in:", - "create.display_link.display_on_multiline": "Inizia a scrivere da:", - - "create.display_source.label": "Aggiungi etichetta", - "create.display_source.combine_item_names": "Combina nome oggetti", - "create.display_source.count_items": "Numero di oggetti filtrati", - "create.display_source.list_items": "Lista di oggetti filtrati", - "create.display_source.fluid_amount": "Quantità di fluidi filtrati", - "create.display_source.list_fluids": "Lista di fluidi filtrati", - "create.display_source.nixie_tube": "Copia Tubo Nixie", - "create.display_source.fill_level": "Livello di riempimento", - "create.display_source.fill_level.display": "Formato di visualizzazione", - "create.display_source.fill_level.percent": "Percentuale", - "create.display_source.fill_level.progress_bar": "Barra dei progressi", - "create.display_source.value_list.display": "Visualizzazione numero", - "create.display_source.value_list.shortened": "Abbreviato", - "create.display_source.value_list.full_number": "Num. intero", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "Morti dei giocatori", - "create.display_source.scoreboard": "Punteggio", - "create.display_source.scoreboard.objective": "ID dell'Obiettivo", - "create.display_source.scoreboard.objective_not_found": "'%1$s' not trovato", - "create.display_source.scoreboard.objective.deaths": "Morti dei giocatori", - "create.display_source.time_of_day": "Orario giornaliero", - "create.display_source.stop_watch": "Cronometro", - "create.display_source.time.format": "Formato dell'ora", - "create.display_source.time.12_hour": "12 ore", - "create.display_source.time.24_hour": "24 ore", - "create.display_source.accumulate_items": "Num. di oggetti accumulati", - "create.display_source.item_throughput": "Freq. di attraversamento", - "create.display_source.item_throughput.interval": "Intervallo", - "create.display_source.item_throughput.interval.second": "al secondo", - "create.display_source.item_throughput.interval.minute": "al minuto", - "create.display_source.item_throughput.interval.hour": "all'ora", - "create.display_source.train_status": "Stato Tabella di marcia", - "create.display_source.station_summary": "Riepilogo Stazione", - "create.display_source.station_summary.filter": "Filtro nomi stazione", - "create.display_source.station_summary.train_name_column": "Lunghezza colonna treno", - "create.display_source.station_summary.platform_column": "Lunghezza colonna binario", - "create.display_source.station_summary.now": "ora", - "create.display_source.station_summary.minutes": "min", - "create.display_source.station_summary.seconds": "%1$ss", - "create.display_source.observed_train_name": "Nome treno individuato", - "create.display_source.max_enchant_level": "Livello massimo", - "create.display_source.boiler_status": "Stato della Caldaia", - "create.display_source.entity_name": "Nome entità", - "create.display_source.kinetic_speed": "Velocità di rotazione", - "create.display_source.kinetic_speed.absolute": "Ignora direzione", - "create.display_source.kinetic_speed.directional": "Includi direzione", - "create.display_source.kinetic_stress": "Stress della rete", - "create.display_source.kinetic_stress.display": "Informazione visualizzata", - "create.display_source.kinetic_stress.progress_bar": "Barra dei progressi", - "create.display_source.kinetic_stress.percent": "Percentuale", - "create.display_source.kinetic_stress.current": "Stress attuale", - "create.display_source.kinetic_stress.max": "Capacità massima", - "create.display_source.kinetic_stress.remaining": "Stress rimanente", - "create.display_source.redstone_power": "Livello di redstone", - "create.display_source.redstone_power.display": "Formato di visualizzazione", - "create.display_source.redstone_power.number": "Numero", - "create.display_source.redstone_power.progress_bar": "Barra dei progressi", - "create.display_source.boiler.not_enough_space": "Spazio insufficiente", - "create.display_source.boiler.for_boiler_status": "per lo Status della Caldaia", - - "create.display_target.line": "Riga %1$s", - "create.display_target.page": "Pagina %1$s", - "create.display_target.single_line": "Riga singola", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;ora;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "L'area selezionata è troppo grande", - "create.super_glue.cannot_reach": "I blocchi scelti devono essere collegati", - "create.super_glue.click_to_confirm": "Pemi di nuovo per confermare", - "create.super_glue.click_to_discard": "Premi da accovacciato per annullare", - "create.super_glue.first_pos": "Prima posizione selezionata", - "create.super_glue.abort": "Selezione annullata", - "create.super_glue.not_enough": "Non hai abbastanza colla nel tuo inventario", - "create.super_glue.success": "Incollaggio in corso...", - - "create.gui.config.overlay1": "Ciao :)", - "create.gui.config.overlay2": "Questo overlay è di esempio", - "create.gui.config.overlay3": "Cliccalo o trascinalo col mouse", - "create.gui.config.overlay4": "per muovere questa anteprima", - "create.gui.config.overlay5": "Premi Esc per uscire e", - "create.gui.config.overlay6": "salvare la nuova posizione", - "create.gui.config.overlay7": "Fai /create per resettare", - "create.gui.config.overlay8": "l'overlay alla posizione standard", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Il tick del server è attualmente rallentato di %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Il tick del server è ora rallentato di %s ms >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Il tick del server è tornato alla velocità normale :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: usa /killtps per riportare il tick del server alla velocità normale", - "create.command.killTPSCommand.status.usage.1": "[Create]: usa /killtps avvia per rallentare artificialmente il tick del server", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Questo Macchinario è troppo grande per essere raccolto", - "create.contraption.minecart_contraption_illegal_pickup": "Una forza misteriosa ti impedisce di raccogliere questo Macchinario", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Macchinario si ferma", - "create.subtitle.peculiar_bell_use": "Campana peculiare suona", - "create.subtitle.worldshaper_place": "Plasmatore del mondo spara", - "create.subtitle.whistle_train_manual": "Treno fischia", - "create.subtitle.steam": "Suoni di vapore", - "create.subtitle.saw_activate_stone": "Attivazione Sega meccanica", - "create.subtitle.schematicannon_finish": "Spara-progetti termina", - "create.subtitle.crafter_craft": "Fabbricatore fabbrica", - "create.subtitle.wrench_remove": "Componente si rompe", - "create.subtitle.train3": "Rumore attutito di ruote di carrello", - "create.subtitle.whistle": "Fischio", - "create.subtitle.cogs": "Rumore di ingranaggi", - "create.subtitle.slime_added": "Colla aggiunta", - "create.subtitle.whistle_train_low": "Treno fischia debolmente", - "create.subtitle.schematicannon_launch_block": "Spara-progetti spara", - "create.subtitle.controller_take": "Leggio svuotato", - "create.subtitle.crafter_click": "Fabbricatore lavora", - "create.subtitle.depot_plop": "Oggetto atterra", - "create.subtitle.confirm": "Suono affermativo", - "create.subtitle.mixing": "Suoni di mescolatura", - "create.subtitle.mechanical_press_activation_belt": "Pressa meccanica schiaccia", - "create.subtitle.fwoomp": "Lancia-patate spara", - "create.subtitle.sanding_long": "Rumori di levigatura", - "create.subtitle.crushing_1": "Suono di schiacciamento", - "create.subtitle.depot_slide": "Oggetto scivola", - "create.subtitle.blaze_munch": "Blaze mangia", - "create.subtitle.funnel_flap": "Lembi di imbuto agitati", - "create.subtitle.haunted_bell_use": "Campana infestata suona", - "create.subtitle.scroll_value": "Suono di input rotatorio", - "create.subtitle.controller_put": "Pulsantiera posata", - "create.subtitle.cranking": "Manovella gira", - "create.subtitle.sanding_short": "Levigatura veloce", - "create.subtitle.wrench_rotate": "Chiave a pappagallo usata", - "create.subtitle.potato_hit": "Vegetale colpisce", - "create.subtitle.saw_activate_wood": "Attivazione Sega meccanica", - "create.subtitle.whistle_high": "Fischio forte", - "create.subtitle.whistle_train_manual_low": "Treno fischia debolmente", - "create.subtitle.whistle_train": "Treno fischia", - "create.subtitle.haunted_bell_convert": "Risveglio di Campana infestata", - "create.subtitle.train": "Rumore di ruote di carrello", - "create.subtitle.deny": "Suono di rifiuto", - "create.subtitle.controller_click": "Click su pulsantiera", - "create.subtitle.whistle_low": "Fischio debole", - "create.subtitle.copper_armor_equip": "Equipaggiamento da immersione equipaggiato", - "create.subtitle.mechanical_press_activation": "Attivazione Pressa meccanica", - "create.subtitle.contraption_assemble": "Macchinario si muove", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "OGGETTO DI ESEMPIO (solo un indicatore che esiste nella descrizione)", - "item.create.example_item.tooltip.summary": "Una breve descrizione dell'oggetto. La _sottolineatura_ evidenzia un termine.", - "item.create.example_item.tooltip.condition1": "Quando questo", - "item.create.example_item.tooltip.behaviour1": "Allora questo oggetto fa questo. (i comportamenti mostrati con shift)", - "item.create.example_item.tooltip.condition2": "E quando questo", - "item.create.example_item.tooltip.behaviour2": "Puoi aggiungere tutti i comportamenti che desideri", - "item.create.example_item.tooltip.control1": "Quando premi Ctrl", - "item.create.example_item.tooltip.action1": "Questi controlli vengono visualizzati.", - - "block.create.wooden_bracket.tooltip": "SUPPORTO DI LEGNO", - "block.create.wooden_bracket.tooltip.summary": "_Decora_ le tue _assi_, _ruote dentate_ e _tubi_ rinforzandoli con del legno.", - - "block.create.metal_bracket.tooltip": "SUPPORTO DI METALLO", - "block.create.metal_bracket.tooltip.summary": "_Decora_ le tue _assi_, _ruote dentate_ e _tubi_ rinforzandoli con del ferro.", - - "block.create.seat.tooltip": "SEDILE", - "block.create.seat.tooltip.summary": "Siediti e goditi l'escursione! Ancora un giocatore a una macchina _in movimento_. Perfetto anche per l'arredamento! Dispone di una varietà di colori.", - "block.create.seat.tooltip.condition1": "Clicca con il pulsante destro sul sedile", - "block.create.seat.tooltip.behaviour1": "Fai sedere il giocatore sul _sedile_. Premi L-Shift per alzarti dal _sedile_.", - - "item.create.blaze_cake.tooltip": "TORTA PER BLAZE", - "item.create.blaze_cake.tooltip.summary": "Un delizioso trattamento per i tuoi _inceneritori a blaze_. Alimentali col fuoco!", - - "item.create.wand_of_symmetry.tooltip": "BASTONE DELLA SIMMETRIA", - "item.create.wand_of_symmetry.tooltip.summary": "Copia perfettamente il posizionamento dei blocchi, specchiandolo sui piani configurati.", - "item.create.wand_of_symmetry.tooltip.condition1": "Nella hotbar", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Rimane attivo", - "item.create.wand_of_symmetry.tooltip.control1": "Click destro sul terreno", - "item.create.wand_of_symmetry.tooltip.action1": "_Crea_ o _sposta_ lo specchio", - "item.create.wand_of_symmetry.tooltip.control2": "Click destro in aria", - "item.create.wand_of_symmetry.tooltip.action2": "_Rimuove_ lo specchio attivo", - "item.create.wand_of_symmetry.tooltip.control3": "Click destro da accovacciato", - "item.create.wand_of_symmetry.tooltip.action3": "Apre l'_interfaccia_ _di_ _configurazione_", - - "item.create.handheld_worldshaper.tooltip": "PLASMATORE DEL MONDO PORTATILE", - "item.create.handheld_worldshaper.tooltip.summary": "Strumento per la modifica di _paesaggi_ e _caratteristiche_ _del_ _terreno_.", - "item.create.handheld_worldshaper.tooltip.control1": "Click sinistro su un blocco", - "item.create.handheld_worldshaper.tooltip.action1": "Imposta i blocchi posizionati dallo strumento sul blocco selezionato.", - "item.create.handheld_worldshaper.tooltip.control2": "Click destro su un blocco", - "item.create.handheld_worldshaper.tooltip.action2": "Applica il _pennello_ e lo _strumento_ attualmente selezionati nella posizione colpita.", - "item.create.handheld_worldshaper.tooltip.control3": "Click destro da accovacciato", - "item.create.handheld_worldshaper.tooltip.action3": "Apre l'_interfaccia_ _di_ _configurazione_", - - "item.create.tree_fertilizer.tooltip": "FERTILIZZANTE PER ALBERI", - "item.create.tree_fertilizer.tooltip.summary": "Una potente combinazione di minerali adatta ad accelerare la crescita degli alberi più comuni.", - "item.create.tree_fertilizer.tooltip.condition1": "Se utilizzato su un arboscello", - "item.create.tree_fertilizer.tooltip.behaviour1": "Fa crescere gli alberi _indipendentemente_ dalle _condizioni_ _di_ _spazio_", - - "item.create.extendo_grip.tooltip": "BRACCIO ALLUNGABILE", - "item.create.extendo_grip.tooltip.summary": "Boioioing! _Incrementa notevolmente la distanza di interazione_ di chi lo brandisce.", - "item.create.extendo_grip.tooltip.condition1": "Quando in mano secondaria", - "item.create.extendo_grip.tooltip.behaviour1": "Incrementa la _distanza di interazione_ degli oggetti usati nella _mano primaria_.", - "item.create.extendo_grip.tooltip.condition2": "Indossando uno Zaino serbatoio", - "item.create.extendo_grip.tooltip.behaviour2": "Verrà consumata _Aria compressa_ invece della _Durata_ di questo oggetto.", - - "item.create.potato_cannon.tooltip": "CANNONE A PATATE", - "item.create.potato_cannon.tooltip.summary": "Fwoomp! Lancia i tuoi frutti o ortaggi ai tuoi nemici! Può essere alimentato con l'Aria Compressa in uno _Zaino serbatoio_", - "item.create.potato_cannon.tooltip.condition1": "Click destro", - "item.create.potato_cannon.tooltip.behaviour1": "_Spara_ un oggetto compatibile dal tuo _Inventario_.", - "item.create.potato_cannon.tooltip.condition2": "Indossando uno Zaino serbatoio", - "item.create.potato_cannon.tooltip.behaviour2": "Verrà consumata _Aria compressa_ invece della _Durata_ di questo oggetto.", - - "item.create.filter.tooltip": "FILTRO", - "item.create.filter.tooltip.summary": "_Controlla_ _gli_ _output_ e gli _input_ dei dispositivi logistici con maggiore _precisione_, confrontandoli con una _serie_ _di_ _oggetti_ o diversi _filtri_ _nidificati_.", - "item.create.filter.tooltip.condition1": "Quando si trova nello slot del filtro", - "item.create.filter.tooltip.behaviour1": "_Controlla_ il flusso degli oggetti in base alla sua _configurazione_.", - "item.create.filter.tooltip.condition2": "Click destro", - "item.create.filter.tooltip.behaviour2": "Apre l'_interfaccia_ _di_ _configurazione_.", - - "item.create.attribute_filter.tooltip": "FILTRO ATTRIBUTI", - "item.create.attribute_filter.tooltip.summary": "_Controlla_ _gli_ _output_ e gli _input_ dei dispositivi logistici con maggiore _precisione_, confrontandoli con una _serie_ _di_ _attributi_ e _categorie_ di oggetti.", - "item.create.attribute_filter.tooltip.condition1": "Quando si trova nello slot del filtro", - "item.create.attribute_filter.tooltip.behaviour1": "_Controlla_ il flusso degli oggetti in base alla sua _configurazione_.", - "item.create.attribute_filter.tooltip.condition2": "Click destro", - "item.create.attribute_filter.tooltip.behaviour2": "Apre l'_interfaccia_ _di_ _configurazione_.", - - "item.create.empty_schematic.tooltip": "PROGETTO VUOTO", - "item.create.empty_schematic.tooltip.summary": "Utilizzato come ingrediente per ricette e per la scrittura al _banco dei progetti_.", - - "item.create.schematic.tooltip": "PROGETTO", - "item.create.schematic.tooltip.summary": "Contiene una struttura da posizionare e collocare nel mondo. Posiziona l'ologramma come desideri e usa uno _Spara-progetti_ per costruirla.", - "item.create.schematic.tooltip.condition1": "In mano", - "item.create.schematic.tooltip.behaviour1": "Può essere posizionato utilizzando gli strumenti sullo schermo.", - "item.create.schematic.tooltip.control1": "Click destro da accovacciato", - "item.create.schematic.tooltip.action1": "Apre un'_interfaccia_ per l'immissione di _coordinate_ esatte.", - - "item.create.schematic_and_quill.tooltip": "PROGETTO E PENNA", - "item.create.schematic_and_quill.tooltip.summary": "Utilizzato per salvare una struttura nel tuo mondo in un file .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Passo 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Seleziona gli angoli usando il click destro.", - "item.create.schematic_and_quill.tooltip.condition2": "Passo 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "Premi _Ctrl_ e _scorri_ sulle facciate per regolare le dimensioni. Click destro di nuovo per salvare.", - "item.create.schematic_and_quill.tooltip.control1": "Click Destro", - "item.create.schematic_and_quill.tooltip.action1": "Seleziona un angolo / conferma il salvataggio.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl premuto", - "item.create.schematic_and_quill.tooltip.action2": "Seleziona i punti a _mezz'aria_. _Scorri_ per regolare la distanza.", - "item.create.schematic_and_quill.tooltip.control3": "Click destro da accovacciato", - "item.create.schematic_and_quill.tooltip.action3": "_Resetta_ e rimuove la selezione.", - - "block.create.schematicannon.tooltip": "SPARA-PROGETTI", - "block.create.schematicannon.tooltip.summary": "Spara blocchi per ricreare un _progetto_ posizionato nel mondo. Usa gli oggetti degli inventari adiacenti e della _polvere da sparo_ come combustibile.", - "block.create.schematicannon.tooltip.condition1": "Click destro", - "block.create.schematicannon.tooltip.behaviour1": "Apre l'_Interfaccia_", - - "block.create.schematic_table.tooltip": "BANCO DEI PROGETTI", - "block.create.schematic_table.tooltip.summary": "Importa un file .nbt su un _progetto_ _vuoto_.", - "block.create.schematic_table.tooltip.condition1": "Quando viene fornito un progetto vuoto", - "block.create.schematic_table.tooltip.behaviour1": "Carica un file selezionato dalla cartella Schematics.", - - "item.create.goggles.tooltip": "OCCHIALI DA INGEGNERE", - "item.create.goggles.tooltip.summary": "Un paio di occhiali per migliorare la tua vista con utili _informazioni_ _cinetiche_.", - "item.create.goggles.tooltip.condition1": "Quando indossati", - "item.create.goggles.tooltip.behaviour1": "Mostra gli _indicatori_ _colorati_ corrispondenti al _livello_ _di_ _velocità_ di un componente cinetico posizionato, nonché l'_impatto_ _sullo_ _stress_ e la capacità dei singoli componenti.", - "item.create.goggles.tooltip.condition2": "Quando si guarda un misuratore", - "item.create.goggles.tooltip.behaviour2": "Mostra informazioni dettagliate sulla _velocità_ o lo _stress_ della rete a cui è collegato il misuratore.", - "item.create.goggles.tooltip.condition3": "Quando si guarda un contenitore di fluidi", - "item.create.goggles.tooltip.behaviour3": "Mostra informazioni dettagliate sulla _Capacità_ del blocco e sui _Fluidi_ contenuti all'interno.", - - "item.create.wrench.tooltip": "CHIAVE A PAPPAGALLO", - "item.create.wrench.tooltip.summary": "Uno strumento utile per lavorare su congegni cinetici. Può essere usato per _ruotare_, _smontare_ e _configurare_ i componenti.", - "item.create.wrench.tooltip.control1": "Click destro su un blocco cinetico", - "item.create.wrench.tooltip.action1": "_Ruota_ _i_ _componenti_ verso o lontano dalla facciata con cui hai interagito.", - "item.create.wrench.tooltip.control2": "Click destro da accovacciato", - "item.create.wrench.tooltip.action2": "_Smonta_ _i_ _componenti_ _cinetici_ e li rimette nel _tuo_ _inventario_.", - - "block.create.nozzle.tooltip": "DISPERSORE", - "block.create.nozzle.tooltip.summary": "Collegalo di fronte a un _ventilatore_ per distribuire il suo effetto sulle entità in _tutte_ _le_ _direzioni_.", - - "block.create.cuckoo_clock.tooltip": "OROLOGIO A CUCÙ", - "block.create.cuckoo_clock.tooltip.summary": "Prodotto di artigianato raffinato usato per _decorare_ uno spazio e _tener_ _traccia_ _del_ _tempo_.", - "block.create.cuckoo_clock.tooltip.condition1": "Quando in rotazione", - "block.create.cuckoo_clock.tooltip.behaviour1": "Mostra l'_ora_ _corrente_ e suona una melodia due volte al giorno. Si _attiva_ una volta a mezzogiorno e una al crepuscolo, non appena i _giocatori_ _possono_ _dormire_.", - - "block.create.turntable.tooltip": "PIATTAFORMA GIREVOLE", - "block.create.turntable.tooltip.summary": "Assorbe la _forza_ _di_ _rotazione_, girando su se' stesso.", - - "block.create.toolbox.tooltip": "CASSETTA DEGLI ATTREZZI", - "block.create.toolbox.tooltip.summary": "Il compagno più fidato di ogni inventore. _Contiene_ una grande quantità di _8 diversi_ oggetti in maniera conveniente.", - "block.create.toolbox.tooltip.condition1": "Quando raccolto", - "block.create.toolbox.tooltip.behaviour1": "_Conserva_ il suo _contenuto_.", - "block.create.toolbox.tooltip.condition2": "Quando piazzato entro il raggio", - "block.create.toolbox.tooltip.behaviour2": "_Giocatori_ _vicini_ possono tenere premuto il _comando_ della _Cassetta degli attrezzi_ per accedere al suo contenuto _dalla distanza_.", - "block.create.toolbox.tooltip.condition3": "Click destro", - "block.create.toolbox.tooltip.behaviour3": "Apre l'_Interfaccia_.", - - "block.create.stockpile_switch.tooltip": "INTERRUTTORE A RIEMPIMENTO", - "block.create.stockpile_switch.tooltip.summary": "Attiva/disattiva un segnale redstone in base allo _spazio_ _di_ _stoccaggio_ nel contenitore collegato.", - "block.create.stockpile_switch.tooltip.condition1": "Quando la di sotto del limite inferiore", - "block.create.stockpile_switch.tooltip.behaviour1": "Smette di fornire il _segnale_ _redstone_", - - "block.create.content_observer.tooltip": "OSSERVATORE DI CONTENUTI", - "block.create.content_observer.tooltip.summary": "_Rileva oggetti_ dentro i _contenitori_ ed i _nastri_ corrispondenti ad un _filtro_. Quando l'_inventario_ del blocco, _nastro_ o _scivolo_ contiene un oggetto corrispondente, questo componente emetterà un _segnale redstone_. Quando un _imbuto_ osservato _trasferisce_ un oggetto corrispondente, questo componente emetterà un _segnale redstone_ temporaneo.", - "block.create.content_observer.tooltip.condition1": "Mentre osserva un contenitore", - "block.create.content_observer.tooltip.behaviour1": "Emette un _segnale redstone_ se il contenitore osservato contiene _oggetti corrispondenti_.", - "block.create.content_observer.tooltip.condition2": "Mentre osserva un imbuto", - "block.create.content_observer.tooltip.behaviour2": "Emette un _segnale redstone_ se l'imbuto osservato sta _trasferendo_ un _oggetto corrispondente_.", - - "block.create.creative_crate.tooltip": "CASSA (CREATIVA)", - "block.create.creative_crate.tooltip.summary": "Fornisce una scorta infinita di blocchi agli _Spara-progetti_ adiacenti.", - "block.create.creative_crate.tooltip.condition1": "Quando un oggetto è nel filtro", - "block.create.creative_crate.tooltip.behaviour1": "Qualsiasi _estrazione_ da questo contenitore fornisce _provviste infinite_ dell'oggetto in questione. Gli oggetti _inseriti_ in questo baule verranno _cancellati_.", - - "item.create.creative_blaze_cake.tooltip": "TORTA PER BLAZE (CREATIVA)", - "item.create.creative_blaze_cake.tooltip.summary": "Uno snack molto speciale per i tuoi _inceneritori a blaze_. Dopo aver mangiato questa torta, gli Inceneritori a Blaze _non finiranno mai il carburante_.", - "item.create.creative_blaze_cake.tooltip.condition1": "Quando usata su un inceneritore a blaze", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Modifica_ il livello di calore di un inceneritore a blaze.", - - "block.create.controller_rail.tooltip": "BINARIO DI CONTROLLO", - "block.create.controller_rail.tooltip.summary": "Un _binario alimentato unidirezionale_ capace di _controllare precisamente_ la _velocità di movimento_ di un carrello da miniera.", - "block.create.controller_rail.tooltip.condition1": "Quando alimentato da redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Accelera_ o _decelera_ i _carrelli da miniera_ che passano, a seconda della _potenza del segnale_. Propaga il segnale redstone ai binari di controllo adiacenti. Alimentare due binari di controllo con segnali differenti farà in modo che i binari tra di loro interpolino il segnale.", - - "item.create.sand_paper.tooltip": "CARTA VETRATA", - "item.create.sand_paper.tooltip.summary": "Una superficie di carta ruvida che può essere usata per _levigare_. Può essere applicata automaticamente usando l'installatore.", - "item.create.sand_paper.tooltip.condition1": "Quando utilizzata", - "item.create.sand_paper.tooltip.behaviour1": "Applica una levigatura agli oggetti tenuti in _mano secondaria_ o per _terra_ quando li si _guarda_.", - - "item.create.builders_tea.tooltip": "TÈ DEL COSTRUTTORE", - "item.create.builders_tea.tooltip.summary": "La bevanda perfetta per iniziare la giornata _motivato_ e _saturato._", - - "item.create.refined_radiance.tooltip": "SPLENDORE RAFFINATO", - "item.create.refined_radiance.tooltip.summary": "Un materiale cromatico forgiato dalla _luce_ _assorbita_.", - "item.create.refined_radiance.tooltip.condition1": "Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "Saranno implementati utilizzi per questo materiale in versioni future.", - - "item.create.shadow_steel.tooltip": "ACCIAIO OSCURO", - "item.create.shadow_steel.tooltip.summary": "Un materiale cromatico forgiato _nel_ _vuoto_.", - "item.create.shadow_steel.tooltip.condition1": "Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "Saranno implementati utilizzi per questo materiale in versioni future.", - - "item.create.linked_controller.tooltip": "PULSANTIERA DI COMANDO", - "item.create.linked_controller.tooltip.summary": "Consegna il potere di _controllare_ le frequenze di _Connettori_ _redstone_ sul _palmo_ della tua mano grazie ai suoi _sei_ _pulsanti_.", - "item.create.linked_controller.tooltip.condition1": "Click destro", - "item.create.linked_controller.tooltip.behaviour1": "_Attiva/disattiva_ la pulsantiera. I _comandi_ _di_ _movimento_ sono disattivi mentre lo usi.", - "item.create.linked_controller.tooltip.condition2": "Click destro da accovacciato", - "item.create.linked_controller.tooltip.behaviour2": "Apri l'_interfaccia di configurazione_ manuale.", - "item.create.linked_controller.tooltip.condition3": "Click destro su un Connettore redstone", - "item.create.linked_controller.tooltip.behaviour3": "Abilita la _Modalità Associa-tasti_. Premi uno dei _sei pulsanti_ per impostarlo alla _Frequenza del connettore_.", - "item.create.linked_controller.tooltip.condition4": "Click destro su un Leggio", - "item.create.linked_controller.tooltip.behaviour4": "Posa la pulsantiera sul Leggio per una più facile attivazione. (Click destro da accovacciato per recuperarlo)", - - "item.create.diving_helmet.tooltip": "ELMO DA IMMERSIONE", - "item.create.diving_helmet.tooltip.summary": "Se indossato con uno _Zaino Serbatoio_, permette al portatore di _respirare_ _sott'acqua_ per un periodo di tempo prolungato.", - "item.create.diving_helmet.tooltip.condition1": "Quando indossato", - "item.create.diving_helmet.tooltip.behaviour1": "Applica l'effetto di _Respirazione Subacquea_, consumando lentamente la _pressione dell'aria_ all'interno del serbatoio.", - - "item.create.copper_backtank.tooltip": "ZAINO SERBATOIO", - "item.create.copper_backtank.tooltip.summary": "Un _serbatoio_ _indossabile_ adatto per trasportare aria compressa.", - "item.create.copper_backtank.tooltip.condition1": "Quando indossato", - "item.create.copper_backtank.tooltip.behaviour1": "Fornisce aria_ _compressa_ a tutto ciò che lo richiede.", - "item.create.copper_backtank.tooltip.condition2": "Quando posizionato e collegato a un sistema cinetico", - "item.create.copper_backtank.tooltip.behaviour2": "_Assorbe_ _aria_ _compressa_ ad una velocità dipendente dalla velocità di rotazione.", - - "block.create.placard.tooltip": "CORNICE DI OTTONE", - "block.create.placard.tooltip.summary": "_Incornicia_ i tuoi _oggetti_ in ottone usando questo elegante pannello da muro. Sicuro per i macchinari!", - "block.create.placard.tooltip.condition1": "Click destro con un oggetto", - "block.create.placard.tooltip.behaviour1": "_Aggiunge_ l'_oggetto_ nella cornice. _Emette_ un segnale _redstone_ temporaneo se contiene già un oggetto corrispondente.", - "block.create.placard.tooltip.condition2": "Quando colpito", - "block.create.placard.tooltip.behaviour2": "_Rimuove_ l'_oggetto_ attualmente incorniciato.", - - "block.create.flywheel.tooltip": "VOLANO", - "block.create.flywheel.tooltip.summary": "_Decora_ i tuoi _macchinari_ con questa enorme ruota di ottone.", - "block.create.flywheel.tooltip.condition1": "Quando riceve forza centrifuga", - "block.create.flywheel.tooltip.behaviour1": "Gira.", - - "item.create.diving_boots.tooltip": "STIVALI DA IMMERSIONE", - "item.create.diving_boots.tooltip.summary": "Un paio di _stivali_ _pesanti_, che permettono di esplorare meglio il fondale oceanico.", - "item.create.diving_boots.tooltip.condition1": "Quando indossati", - "item.create.diving_boots.tooltip.behaviour1": "Il portatore _affonda_ _più velocemente_ e _non può_ _nuotare_. Permette di _camminare_ e _saltare_ sott'acqua. Il portatore è inoltre immune ai _Nastri_ _meccanici_.", - - "item.create.crafting_blueprint.tooltip": "PROGETTO DI FABBRICAZIONE", - "item.create.crafting_blueprint.tooltip.summary": "Se _appeso_ ad un muro, può essere usato per _specificare_ gli _ingredienti_ per fabbricare manualmente. Ogni slot rappresenta una ricetta.", - "item.create.crafting_blueprint.condition1": "Click destro su uno slot vuoto", - "item.create.crafting_blueprint.behaviour1": "Apri il _menù_ _di_ _fabbricazione_, permettendoti di _configurare_ una _ricetta_ e gli oggetti da mostrare.", - "item.create.crafting_blueprint.condition2": "Click destro si uno slot occupato", - "item.create.crafting_blueprint.behaviour2": "_Usa_ la _ricetta_ _selezionata_ con gli oggetti nel tuo _inventario_. _Accovacciati_ per fabbricare fino a uno _Stack_ di oggetti.", - - "item.create.minecart_coupling.tooltip": "AGGANCIO PER CARRELLI DA MINIERA", - "item.create.minecart_coupling.tooltip.summary": "_Concatena_ i _carrelli da miniera_ e le _macchine su carrello_ insieme per formare un treno maestoso.", - "item.create.minecart_coupling.tooltip.condition1": "Quando usato su un carrello da miniera", - "item.create.minecart_coupling.tooltip.behaviour1": "_Concatena_ due carrelli insieme, provando a tenerli uniti a una _distanza costante_ mentre si muovono.", - - "item.create.experience_nugget.tooltip": "PEPITA DI ESPERIENZA", - "item.create.experience_nugget.tooltip.summary": "_Ding!_ Una briciola di _ispirazione_ dalle tue fantastiche invenzioni.", - "item.create.experience_nugget.tooltip.condition1": "Quando usata", - "item.create.experience_nugget.tooltip.behaviour1": "_Guadagna_ i _punti_ _Esperienza_ contenuti all'interno.", - - "block.create.peculiar_bell.tooltip": "CAMPANA PECULIARE", - "block.create.peculiar_bell.tooltip.summary": "Una _Campana di Ottone_ decorativa. Posarla sopra del _Fuoco delle Anime_ potrebbe avere strani effetti...", - - "block.create.haunted_bell.tooltip": "CAMPANA INFESTATA", - "block.create.haunted_bell.tooltip.summary": "Una _Campana Maledetta_ infestata da anime perdute del Nether.", - "block.create.haunted_bell.tooltip.condition1": "Quando tenuta in mano o suonata", - "block.create.haunted_bell.tooltip.behaviour1": "Mostra i _punti bui_ nei quali possono apparire _creature ostili_.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "Questo comportamento può essere cambiato con una Chiave a pappagallo", - "create.ponder.shared.storage_on_contraption": "Inventari connessi al Macchinario raccoglieranno i drop automaticamente", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "Fonte: 16 RPM", - "create.ponder.shared.movement_anchors": "Puoi spostare strutture più grandi grazie alla Super colla.", - "create.ponder.tag.redstone": "Componenti Logici", - "create.ponder.tag.redstone.description": "Componenti che aiutano a costruire impianti redstone", - "create.ponder.tag.contraption_assembly": "Strumenti per Incollare", - "create.ponder.tag.contraption_assembly.description": "Attrezzi e componenti usati per assemblare strutture che devono far parte di un Macchinario", - "create.ponder.tag.fluids": "Manipolatori di Fluidi", - "create.ponder.tag.fluids.description": "Componenti che aiutano nel trasporto e utilizzo di fluidi", - "create.ponder.tag.decoration": "Estetica", - "create.ponder.tag.decoration.description": "Componenti principalmente usati per decorazione", - "create.ponder.tag.windmill_sails": "Vele per Mulini a vento", - "create.ponder.tag.windmill_sails.description": "Blocchi considerati valide vele e che aggiungono potenza ad un Mulino a vento quando assemblato. Ognuna di esse ha la stessa efficienza.", - "create.ponder.tag.arm_targets": "Bersagli per Braccia meccaniche", - "create.ponder.tag.arm_targets.description": "Componenti validi come input o output per un Braccio meccanico", - "create.ponder.tag.kinetic_appliances": "Ricevitori Cinetici", - "create.ponder.tag.kinetic_appliances.description": "Componenti che utilizzano la forza centrifuga per funzionare", - "create.ponder.tag.kinetic_sources": "Generatori Cinetici", - "create.ponder.tag.kinetic_sources.description": "Componenti che generano forza centrifuga", - "create.ponder.tag.movement_anchor": "Ancore di Movimento", - "create.ponder.tag.movement_anchor.description": "Componenti che permettono di costruire marchingegni semoventi, dando vita in vari modi ad una struttura ad essi collegata.", - "create.ponder.tag.kinetic_relays": "Blocchi Cinetici", - "create.ponder.tag.kinetic_relays.description": "Componenti che permettono di propagare la forza centrifuga e portarla altrove", - "create.ponder.tag.contraption_actor": "Componenti per Macchinari", - "create.ponder.tag.contraption_actor.description": "Componenti che si comportano in maniera speciale quando connessi a un Macchinario", - "create.ponder.tag.creative": "Modalità Creativa", - "create.ponder.tag.creative.description": "Componenti normalmente non ottenibili in Modalità Sopravvivenza", - "create.ponder.tag.display_sources": "Fonti di informazioni per il Lettore di dati", - "create.ponder.tag.display_sources.description": "Componenti o blocchi capaci di offrire informazioni leggibili da un Lettore di dati", - "create.ponder.tag.logistics": "Trasporto oggetti", - "create.ponder.tag.logistics.description": "Componenti capaci di spostare oggetti", - "create.ponder.tag.display_targets": "Visualizzatori per il Lettore di dati", - "create.ponder.tag.display_targets.description": "Componenti o blocchi che possono ricevere e visualizzare le informazioni lette da un Lettore di dati", - "create.ponder.tag.train_related": "Equipaggiamento per ferrovie", - "create.ponder.tag.train_related.description": "Componenti usati nella costruzione o gestione di Treni", - - "create.ponder.analog_lever.header": "Controllare segnali usando una Leva analogica", - "create.ponder.analog_lever.text_1": "Le Leve analogiche sono una compatta e precisa fonte di segnali redstone", - "create.ponder.analog_lever.text_2": "Fai click destro per aumentare la potenza del segnale di output", - "create.ponder.analog_lever.text_3": "Fai click destro da accovacciato per abbassare la potenza del segnale", - - "create.ponder.andesite_tunnel.header": "Usare Tunnel di andesite", - "create.ponder.andesite_tunnel.text_1": "I Tunnel di andesite possono essere usati per ricoprire i tuoi Nastri", - "create.ponder.andesite_tunnel.text_2": "Se un Tunnel ha connessioni laterali...", - "create.ponder.andesite_tunnel.text_3": "...estrarrà un singolo oggetto da qualsiasi stack che lo attraversa", - "create.ponder.andesite_tunnel.text_4": "Il resto proseguirà per la sua strada", - - "create.ponder.auto_schedule.header": "Stazioni e Tabelle di marcia", - "create.ponder.auto_schedule.text_1": "Le Tabelle di marcia possono dare una destinazione ai conducenti", - "create.ponder.auto_schedule.text_2": "I Comparatori riceveranno un segnale ogni volta che c'è un treno in attesa", - "create.ponder.auto_schedule.text_3": "Ricorda che le Stazioni possono essere raggiunte solo dalla direzione indicata", - "create.ponder.auto_schedule.text_4": "Le stazioni possono anche essere usate per assegnare nuove Tabelle di marcia automaticamente", - "create.ponder.auto_schedule.text_5": "Una Tabella di marcia posizionata su una stazione sarà automaticamente copiata sui treni presenti", - "create.ponder.auto_schedule.text_6": "Diversamente da come avviene in caso di assegnazione manuale, i conducenti non porteranno l'oggetto con se'", - - "create.ponder.basin.header": "Processare oggetti nella Vasca", - "create.ponder.basin.text_1": "Una Vasca può contenere oggetti e fluidi in attesa di essere lavorati", - "create.ponder.basin.text_2": "Al termine di un ciclo di lavorazione, le Vasche cercano di espellere il risultato lateralmente verso il basso", - "create.ponder.basin.text_3": "Se è presente un componente valido, la Vasca mostrerà un beccuccio di uscita", - "create.ponder.basin.text_4": "La lista di componenti validi è relativamente grande", - "create.ponder.basin.text_5": "Gli output saranno raccolti dall'inventario al di sotto del beccuccio", - "create.ponder.basin.text_6": "Senza un beccuccio d'uscita, le Vasche saranno costrette a trattenere gli oggetti creati al loro interno", - "create.ponder.basin.text_7": "Questo può tuttavia tornare utile se si intende usarli come ingredienti per un'ulteriore lavorazione", - "create.ponder.basin.text_8": "L'output desiderato dovrà poi comunque essere estratto dalla Vasca in qualche modo", - "create.ponder.basin.text_9": "Potrebbe essere necessario un filtro per evitare di estrarre oggetti ancora non lavorati", - - "create.ponder.bearing_modes.header": "Modalità di movimento del Supporto meccanico", - "create.ponder.bearing_modes.text_1": "Se fermato, il Supporto posizionerà la struttura all'angolo più vicino allineato alla griglia", - "create.ponder.bearing_modes.text_2": "Può essere configurato in modo che la struttura non torni mai ad essere blocchi solidi, o a farlo solo se vicina al suo angolo di partenza", - - "create.ponder.belt_casing.header": "Rivestire i Nastri", - "create.ponder.belt_casing.text_1": "Si possono usare Telai in andesite oppure ottone per decorare i Nastri meccanici", - "create.ponder.belt_casing.text_2": "Usa una Chiave a pappagallo per rimuovere il rivestimento", - - "create.ponder.belt_connector.header": "Usare i Nastri meccanici", - "create.ponder.belt_connector.text_1": "Fare click destro su due Assi con un Nastro le connetterà tra loro", - "create.ponder.belt_connector.text_2": "Puoi annullare selezioni accidentali facendo click sinistro da accovacciato", - "create.ponder.belt_connector.text_3": "Puoi inoltre inserire Assi addizionali all'interno del Nastro", - "create.ponder.belt_connector.text_4": "Tutte le Assi connesse da uno stesso Nastro gireranno alla stessa velocità e nella stessa direzione", - "create.ponder.belt_connector.text_5": "Le Assi addizionali possono essere rimosse con una Chiave a pappagallo", - "create.ponder.belt_connector.text_6": "Puoi colorare i Nastri meccanici per motivi estetici", - - "create.ponder.belt_directions.header": "Orientamenti validi per i Nastri meccanici", - "create.ponder.belt_directions.text_1": "I Nastri meccanici non possono essere connessi in maniera arbitraria", - "create.ponder.belt_directions.text_2": "1. Possono essere connessi orizzontalmente", - "create.ponder.belt_directions.text_3": "2. Possono essere connessi diagonalmente", - "create.ponder.belt_directions.text_4": "3. Possono essere connessi verticalmente", - "create.ponder.belt_directions.text_5": "4. E possono connettere Assi verticali orizzontalmente", - "create.ponder.belt_directions.text_6": "Queste sono tutte le direzioni disponibili. I Nastri possono coprire una qualsiasi lunghezza tra i 2 e i 20 blocchi", - - "create.ponder.belt_transport.header": "Usare Nastri meccanici per la logistica", - "create.ponder.belt_transport.text_1": "Un nastro in movimento può trasportare oggetti e altre entità", - "create.ponder.belt_transport.text_2": "Fai click destro con una mano libera per raccogliere un oggetto da un Nastro", - - "create.ponder.blaze_burner.header": "Alimentare Bruciatori a blaze", - "create.ponder.blaze_burner.text_1": "I Bruciatori a blaze possono riscaldare gli oggetti contenuti da una Vasca", - "create.ponder.blaze_burner.text_2": "Per fare ciò, il Bruciatore deve essere alimentato con oggetti infiammabili", - "create.ponder.blaze_burner.text_3": "Una Torta per blaze permette ai Bruciatori a blaze di raggiungere un livello di calore ancora più intenso", - "create.ponder.blaze_burner.text_4": "Il processo di alimentazione può essere automatizzato usando Installatori o Bracci meccanici", - - "create.ponder.brass_funnel.header": "L'Imbuto di ottone", - "create.ponder.brass_funnel.text_1": "Gli Imbuti di andesite possono estrarre solamente un oggetto alla volta.", - "create.ponder.brass_funnel.text_2": "Gli Imbuti di ottone possono estrarre fino ad un intero stack.", - "create.ponder.brass_funnel.text_3": "Scorrendo sullo slot di filtraggio dell'Imbuto permette di impostare la grandezza esatta dello stack da estrarre.", - "create.ponder.brass_funnel.text_4": "Usare un oggetto sullo slot di filtraggio costringerà l'Imbuto a trasferire solo oggetti ad esso corrispondenti.", - - "create.ponder.brass_tunnel.header": "Usare i Tunnel di ottone", - "create.ponder.brass_tunnel.text_1": "I Tunnel di ottone possono essere usati per ricoprire i tuoi Nastri", - "create.ponder.brass_tunnel.text_2": "I Tunnel di ottone hanno uno slot di filtraggio per ogni lato aperto", - "create.ponder.brass_tunnel.text_3": "I filtri in entrata impediranno a oggetti non corrispondenti di entrare", - "create.ponder.brass_tunnel.text_4": "I filtri in uscita possono essere usati per smistare gli oggetti per tipo", - "create.ponder.brass_tunnel.text_5": "Se un oggetto in entrata ha multiple uscite valide sarà la modalità di distribuzione impostata a decidere come procedere", - "create.ponder.brass_tunnel.text_6": "Dei Tunnel di ottone su Nastri paralleli formeranno un gruppo", - "create.ponder.brass_tunnel.text_7": "Gli oggetti in entrata saranno ora distribuiti tra tutte le uscite del gruppo", - "create.ponder.brass_tunnel.text_8": "È possibile anche inserire gli oggetti direttamente nel blocco di un Tunnel", - - "create.ponder.brass_tunnel_modes.header": "Modalità di distribuzione del Tunnel di ottone", - "create.ponder.brass_tunnel_modes.text_1": "È possibile, usando una Chiave a pappagallo, cambiare la modalità di distribuzione di un Tunnel di ottone", - "create.ponder.brass_tunnel_modes.text_10": "'Sincronizza input' è una impostazione unica del Tunnel di ottone", - "create.ponder.brass_tunnel_modes.text_11": "Gli oggetti saranno in grado di passare solo se ogni tunnel del gruppo ne ha uno in attesa", - "create.ponder.brass_tunnel_modes.text_12": "Questo assicura che tutti i Nastri di output abbiano lo stesso rateo di trasporto", - "create.ponder.brass_tunnel_modes.text_2": "'Dividi' cercherà di suddividere equamente gli stack in entrata tra tutte le uscite disponibili", - "create.ponder.brass_tunnel_modes.text_3": "Se un'uscita non ha spazio per i nuovi oggetti sarà ignorata", - "create.ponder.brass_tunnel_modes.text_4": "'Dividi forzatamente' non ignorerà le uscite bloccate, e aspetterà invece che si liberino", - "create.ponder.brass_tunnel_modes.text_5": "'Round Robin' lascia gli stack interi, e scorre tra le uscite iterativamente", - "create.ponder.brass_tunnel_modes.text_6": "Anche in questo caso, le uscite che non hanno abbastanza spazio saranno ignorate", - "create.ponder.brass_tunnel_modes.text_7": "'Round Robin forzato' non salta mai le uscite", - "create.ponder.brass_tunnel_modes.text_8": "'Dai precedenza al più vicino' darà priorità alle uscite più vicine al punto di entrata dell'oggetto", - "create.ponder.brass_tunnel_modes.text_9": "'Distribuisci casualmente' sceglierà un'uscita casuale per ogni stack in entrata", - - "create.ponder.cart_assembler.header": "Spostare strutture con l'Assemblatore di carrelli", - "create.ponder.cart_assembler.text_1": "Gli assemblatori di carrelli attivati con della redstone montano le strutture ad essi connesse ai Carrelli da miniera di passaggio", - "create.ponder.cart_assembler.text_2": "Se spenti, smonteranno invece i Macchinari con Carrello di passaggio, facendoli tornare blocchi", - "create.ponder.cart_assembler.text_3": "Puoi usare una Chiave a pappagallo sul Carrello da miniera per raccogliere il Macchinario e portarlo altrove", - - "create.ponder.cart_assembler_dual.header": "Assemblare Carrozze", - "create.ponder.cart_assembler_dual.text_1": "Ogni volta che due Assemblatori di carrelli condividono la struttura ad essi connessa...", - "create.ponder.cart_assembler_dual.text_2": "...attivare uno qualsiasi dei due li trasformerà in una Carrozza", - "create.ponder.cart_assembler_dual.text_3": "I carrelli si comporteranno come se fossero connessi da un Aggancio per carrelli da miniera", - - "create.ponder.cart_assembler_modes.header": "Impostazioni di rotazione per Macchinari con carrello", - "create.ponder.cart_assembler_modes.text_1": "I Macchinari con carrello tendono a ruotare sempre nella direzione di movimento del loro carrello", - "create.ponder.cart_assembler_modes.text_2": "Questa freccia indica quale lato della struttura sarà considerato 'avanti'", - "create.ponder.cart_assembler_modes.text_3": "Se l'Assemblatore è impostato su 'Blocca rotazione', il Macchinario non ruoterà mai", - - "create.ponder.cart_assembler_rails.header": "Altri tipi di carrelli da miniera e binari", - "create.ponder.cart_assembler_rails.text_1": "Gli Assemblatori non interferiranno con il movimento dei carrelli se posizionati su binari normali", - "create.ponder.cart_assembler_rails.text_2": "Se è invece su Binari Alimentati o di Controllo, i carrelli saranno fermati sul posto fino a che non riceve un segnale redstone", - "create.ponder.cart_assembler_rails.text_3": "Altri tipi di Carrelli da miniera possono essere usati come ancoraggio", - "create.ponder.cart_assembler_rails.text_4": "I carrelli con fornace si alimenteranno autonomamente, consumando il carbone all'interno di inventari connessi", - - "create.ponder.chain_drive.header": "Spostare la forza centrifuga con le Trasmissioni a catena", - "create.ponder.chain_drive.text_1": "Le Trasmissioni a catena propagano la rotazione in una linea", - "create.ponder.chain_drive.text_2": "Tutte le Assi connesse in questo modo ruoteranno nella stessa direzione", - "create.ponder.chain_drive.text_3": "Ogni parte della linea può essere ruotata di 90 gradi", - - "create.ponder.chain_gearshift.header": "Controllare la velocità di rotazione con dei Cambi a catena", - "create.ponder.chain_gearshift.text_1": "Normalmente, i Cambi a catena si comportano esattamente come le Trasmissioni a catena", - "create.ponder.chain_gearshift.text_2": "Con un segnale redstone, invece, essi raddoppieranno la velocità trasmessa agli altri Cambi nella linea", - "create.ponder.chain_gearshift.text_3": "Se il cambio attivato non è quello sorgente, la sua velocità sarà invece dimezzata", - "create.ponder.chain_gearshift.text_4": "In entrambi i casi, i Cambi a catena nella linea avranno sempre il doppio della velocità rispetto a quello che riceve il segnale", - "create.ponder.chain_gearshift.text_5": "I segnali analogici permettono di alterare più precisamente il rateo di accelerazione tra x1 e x2", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "Trasportare oggetti verso il basso con gli Scivoli", - "create.ponder.chute.text_1": "Gli Scivoli possono trasportare oggetti verticalmente, estraendoli o inserendoli in un inventario", - "create.ponder.chute.text_2": "Puoi aggiungere una finestra usando la Chiave a pappagallo", - "create.ponder.chute.text_3": "Piazzare uno scivolo su un lato di un altro lo renderà diagonale", - - "create.ponder.chute_upward.header": "Trasportare oggetti verso l'alto con gli Scivoli", - "create.ponder.chute_upward.text_1": "Piazzare un Ventilatore sopra o sotto ad uno Scivolo permette di spostare gli oggetti verso l'alto", - "create.ponder.chute_upward.text_2": "Ispezionare lo Scivolo con gli Occhiali da ingegnere mostra informazioni riguardanti la direzione del movimento", - "create.ponder.chute_upward.text_3": "Se vuoi inserire oggetti nell'estremità bloccata, dovrai farlo dai lati", - - "create.ponder.clockwork_bearing.header": "Dare vita a strutture con il Supporto per orologi", - "create.ponder.clockwork_bearing.text_1": "I Supporti per orologi si connettono ai blocchi di fronte ad essi", - "create.ponder.clockwork_bearing.text_2": "Una volta connessa ad un sistema rotante, la struttura verrà ruotata a seconda dell'orario attuale", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "Fai click destro sul supporto per assemblare o smontare la struttura", - "create.ponder.clockwork_bearing.text_6": "È possibile connettere una seconda struttura di fronte alla lancetta delle ore", - "create.ponder.clockwork_bearing.text_7": "Assicurati che le strutture non siano incollate l'una all'altra", - "create.ponder.clockwork_bearing.text_8": "La seconda struttura diventerà la lancetta dei minuti", - - "create.ponder.clutch.header": "Controllare la forza centrifuga con una Frizione", - "create.ponder.clutch.text_1": "Le Frizioni propagano la rotazione in una linea retta", - "create.ponder.clutch.text_2": "Taglieranno invece la connessione se ricevono un segnale redstone", - - "create.ponder.cog_speedup.header": "Cambiare marcia con gli Ingranaggi", - "create.ponder.cog_speedup.text_1": "Ingranaggi grandi e piccoli possono essere connessi diagonalmente", - "create.ponder.cog_speedup.text_2": "La velocità raddoppia passando da un ingranaggio grande a uno piccolo", - "create.ponder.cog_speedup.text_3": "La velocità dimezza se si muove invece nella direzione opposta", - - "create.ponder.cogwheel.header": "Trasportare la forza centrifuga con gli Ingranaggi", - "create.ponder.cogwheel.text_1": "Gli Ingranaggi propagano la loro rotazione tra gli Ingranaggi adiacenti", - "create.ponder.cogwheel.text_2": "Assi vicine connesse in questo modo ruoteranno in direzione opposta", - - "create.ponder.cogwheel_casing.header": "Rivestire gli Ingranaggi", - "create.ponder.cogwheel_casing.text_1": "Si possono usare Telai in andesite oppure ottone per decorare gli Ingranaggi", - "create.ponder.cogwheel_casing.text_2": "Eventuali componenti aggiunti in seguito non si collegheranno all'Asse di output", - "create.ponder.cogwheel_casing.text_3": "La Chiave a pappagallo può essere usata per attivare o disattivare tale connessione", - - "create.ponder.creative_fluid_tank.header": "Serbatio per fluidi (creativa)", - "create.ponder.creative_fluid_tank.text_1": "La versione in Modalità Creativa dei Serbatoi per fluidi può essere usata per creare una fonte infinita di fluidi", - "create.ponder.creative_fluid_tank.text_2": "Fai click destro con un oggetto che contiene fluidi per impostarlo", - "create.ponder.creative_fluid_tank.text_3": "Eventuali tubature possono ora estrarre dal Serbatoio una quantità infinita di quel fluido", - "create.ponder.creative_fluid_tank.text_4": "Qualsiasi fluido spinto all'interno di questo tipo di Serbatoio verrà cancellato", - - "create.ponder.creative_motor.header": "Generare forza centrifuga con un Motore (creativa)", - "create.ponder.creative_motor.text_1": "I Motori sono una fonte compatta e configurabile di forza centrifuga", - "create.ponder.creative_motor.text_2": "Scorere sul pannello posteriore cambia la RPM fornita in output", - - "create.ponder.creative_motor_mojang.header": "L'Enigma di Mojang", - - "create.ponder.crushing_wheels.header": "Processare oggetti con le Ruote frantumatrici", - "create.ponder.crushing_wheels.text_1": "Una coppia di Ruote frantumatrici sono un metodo molto efficiente per macinare oggetti", - "create.ponder.crushing_wheels.text_2": "La forza centrifuga in entrata deve farle girare l'una verso l'altra per farle funzionare", - "create.ponder.crushing_wheels.text_3": "Oggetti gettati o inseriti dall'alto verranno lavorati", - "create.ponder.crushing_wheels.text_4": "È possibile anche automatizzare l'inserimento e la raccolta di oggetti", - - "create.ponder.deployer.header": "Usare un Installatore", - "create.ponder.deployer.text_1": "Un installatore può imitare l'interazione di un giocatore sfruttando la forza centrifuga", - "create.ponder.deployer.text_10": "Fai click destro sul lato anteriore per dargli un oggetto da usare", - "create.ponder.deployer.text_11": "È anche possibile fornire oggetti automaticamente", - "create.ponder.deployer.text_12": "Gli installatori possiedono anche uno slot di filtraggio", - "create.ponder.deployer.text_13": "Se impostato, il filtro permetterà all'Installatore di attivarsi solo se contiene un oggetto corrispondente", - "create.ponder.deployer.text_14": "Si possono inserire solo oggetti che corrispondono al filtro...", - "create.ponder.deployer.text_15": "...e rimuovere solo quelli che non corrispondono", - "create.ponder.deployer.text_2": "Questo componente interagisce sempre e solo con la posizione 2 blocchi di fronte ad esso", - "create.ponder.deployer.text_3": "Avere la visuale ostruita non lo fermerà", - "create.ponder.deployer.text_4": "Gli installatori possono:", - "create.ponder.deployer.text_5": "piazzare blocchi,", - "create.ponder.deployer.text_6": "usare oggetti,", - "create.ponder.deployer.text_7": "attivare blocchi,", - "create.ponder.deployer.text_8": "raccogliere da blocchi", - "create.ponder.deployer.text_9": "e attaccare entità", - - "create.ponder.deployer_contraption.header": "Usare Installatori in un Macchinario", - "create.ponder.deployer_contraption.text_1": "Quando un Installatore viene mosso come parte di un Macchinario...", - "create.ponder.deployer_contraption.text_2": "...si attiverà a ogni punto visitato, usando oggetti da qualsiasi inventario a bordo del Macchinario", - "create.ponder.deployer_contraption.text_3": "Lo slot di filtraggio può essere usato per specificare quali oggetti usare", - - "create.ponder.deployer_modes.header": "Modalità degli Installatori", - "create.ponder.deployer_modes.text_1": "Normalmente, un Installatore imita un click destro", - "create.ponder.deployer_modes.text_2": "Puoi usare una Chiave a pappagallo per fare in modo che imiti invece un click sinistro", - - "create.ponder.deployer_processing.header": "Processare gli oggetti con un Installatore", - "create.ponder.deployer_processing.text_1": "Con un oggetto adatto in mano, gli Installatori possono processare gli oggetti sotto di loro", - "create.ponder.deployer_processing.text_2": "Gli oggetti di input possono essere o gettati a terra o messi su una Stazione per oggetti", - "create.ponder.deployer_processing.text_3": "Se essi sono, invece, trasportati da un Nastro...", - "create.ponder.deployer_processing.text_4": "L'Installatore li fermerà e lavorerà automaticamente", - - "create.ponder.deployer_redstone.header": "Controllare gli Installatori con la redstone", - "create.ponder.deployer_redstone.text_1": "Se ricevono un segnale redstone, gli Installatori smetteranno di funzionare", - "create.ponder.deployer_redstone.text_2": "Prima di fermarsi, però, completeranno qualsiasi lavoro abbiano già iniziato", - "create.ponder.deployer_redstone.text_3": "È possibile sfruttare questo comportamento con un impulso negativo per avviare un singolo ciclo di lavorazione", - - "create.ponder.depot.header": "Usare le Stazioni per oggetti", - "create.ponder.depot.text_1": "Le Stazioni per oggetti funzionano come una specie di 'Nastro stazionario'", - "create.ponder.depot.text_2": "Fai click destro per posare o raccogliere un oggetto manualmente", - "create.ponder.depot.text_3": "Così come i Nastri, una Stazione per oggetti può offrire il suo contenuto a componenti di lavorazione", - "create.ponder.depot.text_4": "...così come può permettere ad un Braccio meccanico di interagire", - - "create.ponder.display_board.header": "Usare i Tabelloni", - "create.ponder.display_board.text_1": "I Tabelloni sono una alternativa scalabile ai Cartelli", - "create.ponder.display_board.text_2": "Essi richiedono forza centrifuga per funzionare", - "create.ponder.display_board.text_3": "Il testo può essere impostato usando Targhette...", - "create.ponder.display_board.text_4": "...oppure modificato da un Lettore di dati", - "create.ponder.display_board.text_5": "È inoltre possibile colorare ogni riga del Tabellone individualmente", - "create.ponder.display_board.text_6": "Fai click destro su una riga con una mano vuota per cancellarne il contenuto", - - "create.ponder.display_link.header": "Impostare i Lettori di dati", - "create.ponder.display_link.text_1": "I Lettori di dati possono essere usati per mostrare informazioni in maniera dinamica", - "create.ponder.display_link.text_2": "Per prima cosa, fai click destro sul blocco visualizzatore che vuoi utilizzare...", - "create.ponder.display_link.text_3": "...poi connettilo al blocco da cui vuoi leggere informazioni", - "create.ponder.display_link.text_4": "Apri l'interfaccia per selezionare cosa verrà inviato", - "create.ponder.display_link.text_5": "Il visualizzatore riceverà ora le informazioni dal Connettore", - "create.ponder.display_link.text_6": "Non tutti i blocchi sono una fonte valida di informazioni...", - "create.ponder.display_link.text_7": "...e ogni blocco compatibile offre informazioni uniche", - "create.ponder.display_link.text_8": "I Lettori di dati possono funzionare con una piccola gamma di visualizzatori", - - "create.ponder.display_link_redstone.header": "Controllare i Connettori con la redstone", - "create.ponder.display_link_redstone.text_1": "Un Lettore di dati smette di inviare dati finché riceve un segnale restone", - "create.ponder.display_link_redstone.text_2": "Una volta spento il segnale, il timer è azzerato e le nuove informazioni saranno inviate immediatamente", - "create.ponder.display_link_redstone.text_3": "Eventauli segnali emessi dalla fonte di dati sono ignorati dal Connettore", - - "create.ponder.empty_blaze_burner.header": "Usare Bruciatori a blaze vuoti", - "create.ponder.empty_blaze_burner.text_1": "Fai click destro su un Blaze con un Bruciatore vuoto per catturarlo", - "create.ponder.empty_blaze_burner.text_2": "In alternativa puoi raccogliere un Blaze direttamente da un Generatore di mostri", - "create.ponder.empty_blaze_burner.text_3": "Hai ora una fonte di calore ideale per vari macchinari", - "create.ponder.empty_blaze_burner.text_4": "Si possono anche accendere con un Acciarino per motivi estetici", - "create.ponder.empty_blaze_burner.text_5": "Le fiamme possono poi essere cambiate usando un oggetto infuso di anime", - "create.ponder.empty_blaze_burner.text_6": "Queste fiamme non sono però abbastanza potenti per utilizzi industriali", - - "create.ponder.encased_fluid_pipe.header": "Rivestire Tubi per fluidi", - "create.ponder.encased_fluid_pipe.text_1": "Si possono usare Telai in rame per decorare i Tubi per fluidi", - "create.ponder.encased_fluid_pipe.text_2": "Oltre ad essere nascosti, i Tubi rivestiti saranno forzati a mantenere il loro stato di connessione", - "create.ponder.encased_fluid_pipe.text_3": "Non reagirà più all'aggiunta o rimozione di blocchi adiacenti", - - "create.ponder.fan_direction.header": "Flusso d'aria dei Vantilatori", - "create.ponder.fan_direction.text_1": "I Ventilatori usano la forza centrifuga per creare una corrente d'aria", - "create.ponder.fan_direction.text_2": "La potenza e la direzione della corrente dipendono dalla velocità di rotazione", - - "create.ponder.fan_processing.header": "Processare oggetti con i Ventilatri", - "create.ponder.fan_processing.text_1": "Quando un getto d'aria passa attraverso della lava, la corrente si scalda", - "create.ponder.fan_processing.text_2": "Oggetti investiti dall'area saranno fusi", - "create.ponder.fan_processing.text_3": "Cibo lanciato qui verrebbe incenerito", - "create.ponder.fan_processing.text_4": "Si può invece creare un sistema per affumicare usando fiamme o un Fuoco da campo", - "create.ponder.fan_processing.text_5": "Un getto d'aria che attraversa dell'acqua diventa un sistema di lavaggio", - "create.ponder.fan_processing.text_6": "Con questo sistema è possibile accedere a lavorazioni dal risultato interessante", - "create.ponder.fan_processing.text_7": "La velocità del Ventilatore non ha alcun effetto sulla velocità di lavorazione, ma solo sulla distanza", - "create.ponder.fan_processing.text_8": "La lavorazione con i ventilatori ha effetto anche se gli oggetti sono su Stazioni per oggetti o Nastri", - - "create.ponder.fluid_pipe_flow.header": "Spostare fuidi con i tubi di rame", - "create.ponder.fluid_pipe_flow.text_1": "I Tubi per fluidi possono connettere due o più sorgenti e destinazioni di fluidi", - "create.ponder.fluid_pipe_flow.text_2": "Puoi usare una Chiave a pappagallo per aggiungere una finestra ad un tubo senza curve", - "create.ponder.fluid_pipe_flow.text_3": "I Tubi con finestra non si connetteranno a nessun altro segmento adiacente", - "create.ponder.fluid_pipe_flow.text_4": "Se alimentati da Pompe meccaniche, i Tubi possono trasportare fluidi", - "create.ponder.fluid_pipe_flow.text_5": "All'inizio il fluido non viene estratto", - "create.ponder.fluid_pipe_flow.text_6": "Una volta che il flusso li connette, gli estremi iniziano a trasferire gradualmente il contenuto", - "create.ponder.fluid_pipe_flow.text_7": "In questo modo, i Tubi non contengono mai fisicamente nessun fluido", - - "create.ponder.fluid_pipe_interaction.header": "Svuotare e riempire contenitori di liquidi", - "create.ponder.fluid_pipe_interaction.text_1": "Gli estremi di un sistema di tubi possono interagire con una grande varietà di blocchi", - "create.ponder.fluid_pipe_interaction.text_2": "Qualsiasi blocco capace di contenere liquidi piò essere riempito o svuotato", - "create.ponder.fluid_pipe_interaction.text_3": "Blocchi sorgente di fronte ad un estremo aperto possono essere raccolti...", - "create.ponder.fluid_pipe_interaction.text_4": "...mentre punti di scarico liberi possono creare sorgenti di fluidi", - "create.ponder.fluid_pipe_interaction.text_5": "I Tubi possono anche estrarre fluidi da alcuni specifici blocchi direttamente", - - "create.ponder.fluid_tank_sizes.header": "Dimensioni dei Serbatoi per fluidi", - "create.ponder.fluid_tank_sizes.text_1": "I Serbatoi per fluidi possono essere uniti per sommare la loro capacità totale", - "create.ponder.fluid_tank_sizes.text_2": "Il quadrato della loro base può raggiungere i 3 blocchi di larghezza...", - "create.ponder.fluid_tank_sizes.text_3": "...e può crescere in altezza per oltre 30 strati", - "create.ponder.fluid_tank_sizes.text_4": "Puoi attivare o disattivare la finestra del Serbatoio con una Chiave a pappagallo", - - "create.ponder.fluid_tank_storage.header": "Immagazzinare fluidi in un Serbatoio per fluidi", - "create.ponder.fluid_tank_storage.text_1": "I Serbatoi per fluidi sono ottimi per immagazzinare grandi quantità di fluidi", - "create.ponder.fluid_tank_storage.text_2": "Un sistema di Tubi può aggiungere o rimuovere fluidi da qualsiasi lato", - "create.ponder.fluid_tank_storage.text_3": "Il riempimento può essere misurato da un Comparatore", - "create.ponder.fluid_tank_storage.text_4": "Tuttavia, in Sopravvivenza i fluidi non possono essere aggiunti ne' rimossi manualmente", - "create.ponder.fluid_tank_storage.text_5": "Puoi usare Vasche, Prosciugatori e Beccucci per svuotare o riempire oggetti che contengono fluidi", - - "create.ponder.funnel_compat.header": "Compatibilità degli Imbuti", - "create.ponder.funnel_compat.text_1": "Gli imbuti possono anche interagire facilmente con uno specifico insieme di componenti.", - "create.ponder.funnel_compat.text_2": "Seghe verticali", - "create.ponder.funnel_compat.text_3": "Stazioni per oggetti", - "create.ponder.funnel_compat.text_4": "Prosciugatori di oggetti", - - "create.ponder.funnel_direction.header": "Direzione di spostamento", - "create.ponder.funnel_direction.text_1": "Posizionato normalmente, esso estrarrà oggetti dall'inventario.", - "create.ponder.funnel_direction.text_2": "Posizionandolo da accovacciato inserirà invece gli oggetti nell'inventario.", - "create.ponder.funnel_direction.text_3": "Puoi usare una Chiave a pappagallo per ruotare l'imbuto dopo averlo posizionato.", - "create.ponder.funnel_direction.text_4": "Lo stesso vale nella maggior parte delle direzioni.", - "create.ponder.funnel_direction.text_5": "Gli imbuti sopra un Nastro estrarranno o inseriranno oggetti dipendentemente dalla direzione del Nastro.", - - "create.ponder.funnel_intro.header": "Usare gli Imbuti", - "create.ponder.funnel_intro.text_1": "Gli imbuti sono perfetti per trasferire oggetti da e in inventari.", - - "create.ponder.funnel_redstone.header": "Controllare gli Imbuti con la redstone", - "create.ponder.funnel_redstone.text_1": "Un segnale redstone impedirà agli Imbuti di funzionare", - - "create.ponder.funnel_transfer.header": "Trasferimento diretto", - "create.ponder.funnel_transfer.text_1": "Gli imbuti non possono trasferire gli oggetti direttamente tra inventari chiusi.", - "create.ponder.funnel_transfer.text_2": "Scivoli semplici o intelligenti potrebbero essere più adatti per tale scopo.", - "create.ponder.funnel_transfer.text_3": "Lo stesso vale per il movimento orizzontale. Un Nastro potrebbe tornare utile in questo caso.", - - "create.ponder.gantry_carriage.header": "Usare Carrelli da gru", - "create.ponder.gantry_carriage.text_1": "I Carrelli da gru possono essere montati e scorrere su un'Asse da gru.", - "create.ponder.gantry_carriage.text_2": "I sistemi a gru possono muovere blocchi ad essi connessi.", - - "create.ponder.gantry_cascaded.header": "Gru a cascata", - "create.ponder.gantry_cascaded.text_1": "Le Assi da gru si connettono a un Carrello senza aver bisogno di Super colla", - "create.ponder.gantry_cascaded.text_2": "Lo stesso vale per Carrelli connessi ad un'Asse in movimento", - "create.ponder.gantry_cascaded.text_3": "In questo modo è possibile creare un sistema a cascata capace di scorrere lungo multipli assi", - - "create.ponder.gantry_direction.header": "Direzione di movimento della gru", - "create.ponder.gantry_direction.text_1": "Le Assi da gru possono muoversi in diverse direzioni", - "create.ponder.gantry_direction.text_2": "La direzione in cui si muove il Carrello dipende dall'orientamento della sua Asse", - "create.ponder.gantry_direction.text_3": "...così come dal suo senso di rotazione", - "create.ponder.gantry_direction.text_4": "Lo stesso vale per la rotazione trasmessa", - - "create.ponder.gantry_redstone.header": "Propagazione dell'energia", - "create.ponder.gantry_redstone.text_1": "Dare energia redstone ad un'Asse da gru fermerà sul posto tutte le gru ad essa connesse", - "create.ponder.gantry_redstone.text_2": "La sua rotazione sarà, invece, trasferita alle Assi di output dei Carrelli", - - "create.ponder.gantry_shaft.header": "Usare Assi da gru", - "create.ponder.gantry_shaft.text_1": "Le Assi da gru sono i componenti di base per costruire sistemi a gru. Eventuali Carrelli ad esse collegati si muoveranno lungo di esse.", - "create.ponder.gantry_shaft.text_2": "I sistemi a gru possono muovere blocchi ad essi connessi.", - - "create.ponder.gearbox.header": "Trasferire forza centrifuga con gli Invertitori", - "create.ponder.gearbox.text_1": "Cambiare asse di rotazione può richiedere molto spazio", - "create.ponder.gearbox.text_2": "Un Invertitore è una versione più compatta di tale mostruosità", - "create.ponder.gearbox.text_3": "Assi connesse a lati adiacenti ruotano in direzioni specchiate", - "create.ponder.gearbox.text_4": "Connesioni in linea retta saranno invertite", - - "create.ponder.gearshift.header": "Controllare la forza centrifuga con un Cambio", - "create.ponder.gearshift.text_1": "I Cambi propagano la rotazione in una linea retta", - "create.ponder.gearshift.text_2": "Invertono inoltre la rotazione se ricevono un segnale redstone", - - "create.ponder.hand_crank.header": "Generare forza centrifuga usando Manovelle", - "create.ponder.hand_crank.text_1": "Le Manovelle possono essere usate dai giocatori per generare forza centrifuga manualmente", - "create.ponder.hand_crank.text_2": "Tieni premuto il pulsante destro per farla ruotare in senso antiorario", - "create.ponder.hand_crank.text_3": "La velocità di rotazione è relativamente alta", - "create.ponder.hand_crank.text_4": "Tieni premuto il pulsante destro da accovacciato per farla ruotare in senso orario", - - "create.ponder.hose_pulley.header": "Riempire e svuotare bacini con delle Carrucole per fluidi", - "create.ponder.hose_pulley.text_1": "Le Carrucole per fluidi sono perfette per riempire o drenare interi bacini di fluidi", - "create.ponder.hose_pulley.text_2": "L'altezza del beccuccio può essere regolata con un input di energia cinetica", - "create.ponder.hose_pulley.text_3": "Il tubo può essere ritratto invertendo la rotazione", - "create.ponder.hose_pulley.text_4": "Dal lato opposto è possibile connettere dei Tubi", - "create.ponder.hose_pulley.text_5": "Un sistema di Tubi connesso può fornire dei fluidi...", - "create.ponder.hose_pulley.text_6": "...oppure risucchiarli, svuotando gradualmente il bacino", - "create.ponder.hose_pulley.text_7": "La velocità di riempimento o svuotamento dipende interamente da sistema di Tubi", - - "create.ponder.hose_pulley_infinite.header": "Estrarre o gettare passivamente nei bacini con delle Carrucole per fluidi", - "create.ponder.hose_pulley_infinite.text_1": "Se il beccuccio della Carrucola per fluidi tocca un bacino abbastanza ampio...", - "create.ponder.hose_pulley_infinite.text_2": "...raccoglierà o getterà fluidi senza avere alcun effetto sul bacino stesso", - "create.ponder.hose_pulley_infinite.text_3": "Un sistema di Tubi può risucchiare o gettare fluidi infinitamente usando Carrucole di questo tipo", - - "create.ponder.hose_pulley_level.header": "Livelli di riempimento e svuotamento delle Carrucole per Fluidi", - "create.ponder.hose_pulley_level.text_1": "Quando completamente ritirata, la Carrucola per Fluidi non fa nulla", - "create.ponder.hose_pulley_level.text_2": "Lo svuotamento avviene dall'alto verso il basso", - "create.ponder.hose_pulley_level.text_3": "La nuova superficie si troverà appena sotto la posizione del beccuccio", - "create.ponder.hose_pulley_level.text_4": "Il riempimeno avviene dal basso verso l'alto", - "create.ponder.hose_pulley_level.text_5": "Il bacino crescerà fino a riempire lo strato di blocchi in cui si trova il beccuccio", - - "create.ponder.item_drain.header": "Svuotare contenitori di fluidi con i Prosciugatori di oggetti", - "create.ponder.item_drain.text_1": "I Prosciugatori di oggetti possono estrarre fluidi dagli oggetti posati sopra di essi", - "create.ponder.item_drain.text_2": "Fai click destro su di esso per versare fluidi direttamente dall'oggetto nella tua mano", - "create.ponder.item_drain.text_3": "Quando un oggetto viene inserito da un lato...", - "create.ponder.item_drain.text_4": "...esso rotolerà in avanti, svuotando i fluidi in esso contenuti", - "create.ponder.item_drain.text_5": "I sistemi di Tubi potranno ora estrarre i fluidi dal buffer interno del Prosciugatore", - - "create.ponder.item_vault_sizes.header": "Dimensioni di un Container", - "create.ponder.item_vault_sizes.text_1": "I Container possono essere combinati per sommare la loro capacità totale", - "create.ponder.item_vault_sizes.text_2": "Il loro quadrato di base può raggiungere un massimo di 3 blocchi di spessore...", - "create.ponder.item_vault_sizes.text_3": "...e la loro lunghezza crescere fino a 3 volte il loro diametro", - - "create.ponder.item_vault_storage.header": "Immagazzinare oggetti in un Container", - "create.ponder.item_vault_storage.text_1": "I Container possono essere usate per immagazzinare grandi quantità di oggetti", - "create.ponder.item_vault_storage.text_2": "Tuttavia, è impossibile mettere o togliere oggetti manualmente", - "create.ponder.item_vault_storage.text_3": "Qualsiasi componente per trasferire oggetti può sia inserire...", - "create.ponder.item_vault_storage.text_4": "...che rimuovere oggetti da questo contenitore", - - "create.ponder.large_cogwheel.header": "Trasportare la forza centrifuga con gli Ingranaggi grandi", - "create.ponder.large_cogwheel.text_1": "Gli Ingranaggi grandi propagano la loro rotazione connettendosi ad angoli di 90 gradi", - "create.ponder.large_cogwheel.text_2": "Questo pemette di cambiare l'asse in cui viene trasportata la forza centrifuga", - - "create.ponder.linear_chassis_attachment.header": "Collegare blocchi usando Telai lineari", - "create.ponder.linear_chassis_attachment.text_1": "Le facce aperte di un Telaio lineare possono essere rese appiccicose", - "create.ponder.linear_chassis_attachment.text_2": "Premi ancora per rendere appiccicoso anche il lato opposto", - "create.ponder.linear_chassis_attachment.text_3": "Fai click destro da accovacciato con una mano vuota per togliere la colla", - "create.ponder.linear_chassis_attachment.text_4": "I lati appiccicosi del Telaio lineare saranno in grado di connettersi ad una linea di blocchi davanti a sé", - "create.ponder.linear_chassis_attachment.text_5": "Puoi usare una Chiave a pappagallo per impostare la lunghezza di tale linea", - "create.ponder.linear_chassis_attachment.text_6": "Tenendo premuto CTRL mentre scorri cambierai la portata di tutti i Telai collegati", - "create.ponder.linear_chassis_attachment.text_7": "Collegare dei blocchi a qualsiasi altro lato richiede di utilizzare della Super colla", - "create.ponder.linear_chassis_attachment.text_8": "Grazie a queste meccaniche, strutture di qulsiasi forma possono essere trasformate in un Macchinario", - - "create.ponder.linear_chassis_group.header": "Spostare un gruppo di Telai lineari", - "create.ponder.linear_chassis_group.text_1": "I Telai lineari si connettono automaticamente ad altri Telai adiacenti dello stesso tipo", - "create.ponder.linear_chassis_group.text_2": "Se uno viene mosso come parte di un Macchinario, tutti gli altri saranno trascinati con esso", - "create.ponder.linear_chassis_group.text_3": "Telai di tipi diversi o ruotati in altre direzioni non si collegheranno", - - "create.ponder.mechanical_arm.header": "Impostare Braccia meccaniche", - "create.ponder.mechanical_arm.text_1": "Prima di essere posizionato, un Braccio meccanico avrà bisogno di essere assegnato ai suoi input e output", - "create.ponder.mechanical_arm.text_2": "Fai click destro su un inventario mentre hai in mano il Braccio per aggiungerlo come bersaglio", - "create.ponder.mechanical_arm.text_3": "Fai nuovamente click destro per scegliere tra input (blu) e output (arancione)", - "create.ponder.mechanical_arm.text_4": "Fai click sinistro per rimuovere il blocco dalla selezione", - "create.ponder.mechanical_arm.text_5": "Una volta posizionato, il Braccio meccanico bersaglierà i blocchi scelti", - "create.ponder.mechanical_arm.text_6": "Le Braccia meccaniche possono avere qualsiasi numero di input e output entro la loro portata", - "create.ponder.mechanical_arm.text_7": "Non tutti gli inventari, però, possono essere selezionati direttamente", - "create.ponder.mechanical_arm.text_8": "Usa Imbuti e Stazioni per oggetti per risolvere questo problema", - - "create.ponder.mechanical_arm_filtering.header": "Filtrare gli Output del Braccio meccanico", - "create.ponder.mechanical_arm_filtering.text_1": "Input", - "create.ponder.mechanical_arm_filtering.text_2": "Output", - "create.ponder.mechanical_arm_filtering.text_3": "A volte è preferibile applicare restrizioni ai bersagli del Braccio meccanico usando dei Filtri", - "create.ponder.mechanical_arm_filtering.text_4": "Le Braccia meccaniche non hanno alcuna impostazione di filtraggio incorporata", - "create.ponder.mechanical_arm_filtering.text_5": "Gli Imbuti di ottone sono però in grado di comunicare i loro filtri al Braccio", - "create.ponder.mechanical_arm_filtering.text_6": "Il Braccio è abbastanza intelligente da evitare perfino di raccogliere eventuali oggetti che non corrispondono con nessun filtro", - - "create.ponder.mechanical_arm_modes.header": "Modalità di distribuzione del Braccio meccanico", - "create.ponder.mechanical_arm_modes.text_1": "Input", - "create.ponder.mechanical_arm_modes.text_2": "Output", - "create.ponder.mechanical_arm_modes.text_3": "Ogni volta che un Braccio è costretto a scegliere tra multipli output validi...", - "create.ponder.mechanical_arm_modes.text_4": "...si comporterà in accordo con le sue impostazioni", - "create.ponder.mechanical_arm_modes.text_5": "Scorri con la Chiave a pappagallo per cambiare impostazione", - "create.ponder.mechanical_arm_modes.text_6": "Round Robin semplicemente scorrerà, uno alla volta, tra tutti gli output disponibili", - "create.ponder.mechanical_arm_modes.text_7": "Se un output non è in grado di accettare altri oggetti, sarà ignorato", - "create.ponder.mechanical_arm_modes.text_8": "Round Robin forzato non salterà mai gli output, attendendo invece che si liberino prima di procedere", - "create.ponder.mechanical_arm_modes.text_9": "Dai precedenza al primo darà maggiore priorità agli output impostati per primi mentre il Braccio veniva configurato", - - "create.ponder.mechanical_arm_redstone.header": "Controllare le Braccia meccaniche con la redstone", - "create.ponder.mechanical_arm_redstone.text_1": "Se ricevono un segnale redstone, le Braccia meccaniche smetteranno di funzionare", - "create.ponder.mechanical_arm_redstone.text_2": "Prima di fermarsi, però, completeranno qualsiasi spostamento abbiano già iniziato", - "create.ponder.mechanical_arm_redstone.text_3": "È possibile sfruttare questo comportamento con un impulso negativo per avviare un singolo ciclo di spostamento", - - "create.ponder.mechanical_bearing.header": "Spostare strutture usando un Supporto meccanico", - "create.ponder.mechanical_bearing.text_1": "I Supporti meccanici si collegano al blocco davanti a sé", - "create.ponder.mechanical_bearing.text_2": "Appena riceve della forza centrifuga, il Supporto trasformerà la struttura in un Marchingegno rotante", - - "create.ponder.mechanical_crafter.header": "Utilizzare i Fabbricatori meccanici", - "create.ponder.mechanical_crafter.text_1": "Si può costruire una matrice di Fabbricatori meccanici per automatizzare qualsiasi ricetta di Fabbricazione", - "create.ponder.mechanical_crafter.text_2": "Si possono alterare i percorsi dei Fabbricatori con una Chiave a pappagallo", - "create.ponder.mechanical_crafter.text_3": "Perché il sistema sia valido, tutti i percorsi devono convergere in una singola uscita su un lato qualsiasi della matrice", - "create.ponder.mechanical_crafter.text_4": "Gli output saranno posati in un inventario qualsiasi accanto all'uscita", - "create.ponder.mechanical_crafter.text_5": "I Fabbricatori richiedono forza centrifuga per funzionare", - "create.ponder.mechanical_crafter.text_6": "Fai click destro sul lato anteriore per inserire manualmente gli oggetti", - "create.ponder.mechanical_crafter.text_7": "Non appena tutti gli slot saranno occupati, la fabbricazione avrà inizio", - "create.ponder.mechanical_crafter.text_8": "Se ciò non è vero, si può costringere il processo a partire lo stesso con un segnale redstone", - - "create.ponder.mechanical_crafter_connect.header": "Connettere gli inventari di multipli Fabbricatori", - "create.ponder.mechanical_crafter_connect.text_1": "È possibile inserire gli oggetti nei Fabbricatori in maniera automatizzata", - "create.ponder.mechanical_crafter_connect.text_2": "Usare una Chiave a pappagallo permette di combinare gli input di Fabbricatori adiacenti", - "create.ponder.mechanical_crafter_connect.text_3": "D'ora in poi, tutti i Fabbricatori connessi condivideranno lo stesso input", - - "create.ponder.mechanical_crafter_covers.header": "Coprire lo slot di un Fabbricatore", - "create.ponder.mechanical_crafter_covers.text_1": "Alcune ricette non hanno ingredienti contigui, e richiedono slot vuoti tra un oggetto e l'altro", - "create.ponder.mechanical_crafter_covers.text_2": "In casi come questi, un Fabbricatore può essere riempito con una Copertura per slot, in modo che la matrice lo consideri uno slot vuoto", - "create.ponder.mechanical_crafter_covers.text_3": "Gli input condivisi creati con una Chiave a pappagallo possono superare questi Fabbricatori coperti", - - "create.ponder.mechanical_drill.header": "Rompere blocchi con la Trivella meccanica", - "create.ponder.mechanical_drill.text_1": "Quando alimentato dalla forza centrifuga, un Trapano meccanico romperà blocchi direttamente di fronte a sé", - "create.ponder.mechanical_drill.text_2": "La sua velocità di scavo dipende dalla velocità di rotazione", - - "create.ponder.mechanical_drill_contraption.header": "Usare trivelle meccaniche in un Macchinario", - "create.ponder.mechanical_drill_contraption.text_1": "Quando una Trivella viene mossa come parte di un Macchinario...", - "create.ponder.mechanical_drill_contraption.text_2": "...essi romperanno qualunque blocco che incontrano all'avanzare della struttura", - - "create.ponder.mechanical_harvester.header": "Usare Mietitrici meccaniche in un Macchinario", - "create.ponder.mechanical_harvester.text_1": "Quando una Mietitrice viene mossa come parte di un Macchinario...", - "create.ponder.mechanical_harvester.text_2": "...essa raccoglierà e ripianterà qualsiasi coltivazione che incontra", - - "create.ponder.mechanical_mixer.header": "Processare oggetti con il Frullatore meccanico", - "create.ponder.mechanical_mixer.text_1": "È possibile automatizzare un buon numero di ricette grazie a un Frullatore e una Vasca", - "create.ponder.mechanical_mixer.text_2": "Le ricette disponibili includono qualsiasi fabbricazione senza forma, più alcune ricette extra", - "create.ponder.mechanical_mixer.text_3": "Alcune di queste ricette potrebbero richiedere il calore di un Inceneritore a blaze", - "create.ponder.mechanical_mixer.text_4": "Lo slot di filtraggio permette di scegliere tra ricette in conflitto.", - - "create.ponder.mechanical_piston.header": "Spostare strutture usando un Pistone meccanico", - "create.ponder.mechanical_piston.text_1": "I Pistoni meccanici possono spingere i blocchi di fronte a sé", - "create.ponder.mechanical_piston.text_2": "La velocità e la direzione in cui si muovono dipende dalla rotazione in entrata", - "create.ponder.mechanical_piston.text_3": "I Pistoni appiccicosi possono anche trascinare i blocchi indietro", - - "create.ponder.mechanical_piston_modes.header": "Modalità di movimento del Pistone meccanico", - "create.ponder.mechanical_piston_modes.text_1": "Quando un Pistone si ferma, la struttura trasportata si riconverte in blocchi", - "create.ponder.mechanical_piston_modes.text_2": "Può essere configurato in modo che la struttura non torni mai ad essere blocchi solidi, o a farlo solo al suo punto di partenza", - - "create.ponder.mechanical_plough.header": "Usare Aratri meccanici in un Macchinario", - "create.ponder.mechanical_plough.text_1": "Quando un Aratro viene mosso come parte di un Macchinario...", - "create.ponder.mechanical_plough.text_2": "...esso romperà qualsiasi blocco che non ha una hitbox solida", - "create.ponder.mechanical_plough.text_3": "Inoltre, gli Aratri possono creare Terra zappata", - "create.ponder.mechanical_plough.text_4": "...e perfino lanciare entità senza ferirle", - - "create.ponder.mechanical_press.header": "Processare oggetti con la Pressa meccanica", - "create.ponder.mechanical_press.text_1": "Le Presse meccaniche possono processare gli oggetti sotto di loro", - "create.ponder.mechanical_press.text_2": "Gli oggetti di input possono essere o gettati a terra o messi su una Stazione per oggetti", - "create.ponder.mechanical_press.text_3": "Se essi sono, invece, trasportati da un Nastro...", - "create.ponder.mechanical_press.text_4": "La Pressa li fermerà e lavorerà automaticamente", - - "create.ponder.mechanical_press_compacting.header": "Compattare oggetti con una Pressa", - "create.ponder.mechanical_press_compacting.text_1": "È possibile compattare oggetti schiacciandoli in una Vasca", - "create.ponder.mechanical_press_compacting.text_2": "Compattare comprende qualsiasi ricetta di crafting 2x2 o 3x3 completamente piena di un solo oggetto, più alcune extra", - "create.ponder.mechanical_press_compacting.text_3": "Alcune di queste ricette potrebbero richiedere il calore di un Inceneritore a blaze", - "create.ponder.mechanical_press_compacting.text_4": "Lo slot di filtraggio permette di scegliere tra ricette in conflitto.", - - "create.ponder.mechanical_pump_flow.header": "Trasportare fluidi usando Pompe meccaniche", - "create.ponder.mechanical_pump_flow.text_1": "Le Pompe meccaniche governano il flusso di liquidi nei sistemi di Tubi a cui sono connesse", - "create.ponder.mechanical_pump_flow.text_2": "Quando attivate, la loro freccia indica la direzione del flusso", - "create.ponder.mechanical_pump_flow.text_3": "Il sistema dietro di essa sta ora inviando liquidi...", - "create.ponder.mechanical_pump_flow.text_4": "...mentre il sistema di fronte li distribuisce in avanti", - "create.ponder.mechanical_pump_flow.text_5": "Invertire la rotazione in input inverte la direzione del flusso", - "create.ponder.mechanical_pump_flow.text_6": "Usa la Chiave a pappagallo per invertire manualmente la direzione della Pompa", - - "create.ponder.mechanical_pump_speed.header": "Portata delle Pompe meccaniche", - "create.ponder.mechanical_pump_speed.text_1": "Indipendentemente dalla velocità, le Pompe meccaniche hanno una distanza massima di effetto di 16 blocchi", - "create.ponder.mechanical_pump_speed.text_2": "Aumentando la rotazione in input aumenta anche la velocità di propagazione dei fluidi...", - "create.ponder.mechanical_pump_speed.text_3": "...nonché la loro velocità di trasferimento", - "create.ponder.mechanical_pump_speed.text_4": "Le Pompe possono combinare la loro portata per cotrollare meglio un sistema di Tubi", - "create.ponder.mechanical_pump_speed.text_5": "Alternare la loro rotazione permette di allineare la direzione dei loro flussi", - - "create.ponder.mechanical_saw_breaker.header": "Tagliare alberi con la Sega meccanica", - "create.ponder.mechanical_saw_breaker.text_1": "Al ricevere forza centrifuga, una Sega meccanica inizierà a tagliare alberi davanti a sé", - "create.ponder.mechanical_saw_breaker.text_2": "Perché la Sega possa abbattere l'intero albero, essa dovrà rompere il blocco che lo connette al terreno", - - "create.ponder.mechanical_saw_contraption.header": "Usare Seghe meccaniche in un Macchinario", - "create.ponder.mechanical_saw_contraption.text_1": "Quando una Sega viene mossa come parte di un Macchinario...", - "create.ponder.mechanical_saw_contraption.text_2": "...essa taglierà qualsiasi albero con cui entra in contatto", - - "create.ponder.mechanical_saw_processing.header": "Processare oggetti con la Sega meccanica", - "create.ponder.mechanical_saw_processing.text_1": "Una Sega meccanica ruotata verso l'alto può tagliare una buona varietà di oggetti", - "create.ponder.mechanical_saw_processing.text_2": "Gli oggetti in lavorazione si muovono sempre nella direzione opposta alla rotazione della lama", - "create.ponder.mechanical_saw_processing.text_3": "Le Seghe funzionano anche come porzione centrale di un Nastro meccanico", - "create.ponder.mechanical_saw_processing.text_4": "Se un ingrediente ha multipli possibili risultati, si può scegliere quello desiderato con lo slot di filtraggio", - "create.ponder.mechanical_saw_processing.text_5": "Senza filtri, la Sega li fabbricherà tutti, uno alla volta", - - "create.ponder.millstone.header": "Processare oggetti in una Macina", - "create.ponder.millstone.text_1": "Le Macine lavorano gli oggetti triturandoli", - "create.ponder.millstone.text_2": "Possono essere alimentate con degli Ingranaggi", - "create.ponder.millstone.text_3": "Lancia o inserisci gli oggetti da sopra", - "create.ponder.millstone.text_4": "Dopo alcuni secondi, sarà possibile raccogliere gli oggetti con un click destro", - "create.ponder.millstone.text_5": "Gli output possono anche essere estratti in maniera automatizzata", - - "create.ponder.nixie_tube.header": "Usare i Tubi di Nixie", - "create.ponder.nixie_tube.text_1": "Quando attivati da redstone, i Tubi di Nixie mostreranno l'intensità del segnale in entrata", - "create.ponder.nixie_tube.text_2": "Si possono usare Targhette con nomi personalizzati per cambiare il testo da mostrare a piacimento", - "create.ponder.nixie_tube.text_3": "Fai click destro con un colorante per cambiare il colore", - - "create.ponder.piston_pole.header": "Usare i Pali di pistone", - "create.ponder.piston_pole.text_1": "Senza Pali ad esso connessi, un Pistone meccanico è inutile", - "create.ponder.piston_pole.text_2": "La lunghezza del Palo aggiunto sul suo retro definisce la sua distanza massima di estensione", - - "create.ponder.portable_fluid_interface.header": "Scambio di fluidi con un Macchinario", - "create.ponder.portable_fluid_interface.text_1": "I Serbatoi montati su di un Macchinario in movimento non possono connettersi ad un sistema di tubi senza essere smontate", - "create.ponder.portable_fluid_interface.text_2": "Questo componente, invece, permette di interagire con i Serbatoi di un Macchinario senza neppure doverlo fermare", - "create.ponder.portable_fluid_interface.text_3": "Piazzane un altro con uno spazio vuoto di 1 o 2 blocchi tra di essi", - "create.ponder.portable_fluid_interface.text_4": "Ogni volta che passano l'uno accanto all'altro, essi si connetteranno", - "create.ponder.portable_fluid_interface.text_5": "Mentre sono collegati, l'Interfaccia stazionaria rappresenterà TUTTI i Serbatoi nel Macchinario", - "create.ponder.portable_fluid_interface.text_6": "È ora possibile inserire i fluidi...", - "create.ponder.portable_fluid_interface.text_7": "...oppure estrarli dal Macchinario", - "create.ponder.portable_fluid_interface.text_8": "Se non avvengono scambi per troppo tempo, il Macchinario ripartirà", - - "create.ponder.portable_storage_interface.header": "Scambio di oggetti con un Macchinario", - "create.ponder.portable_storage_interface.text_1": "Gli inventari connessi ad un Macchinario in movimento non possono essere aperti da un giocatore ne' da altri componenti senza essere smontati", - "create.ponder.portable_storage_interface.text_2": "Questo componente, invece, permette di interagire con essi senza neppure dover fermare il Macchinario", - "create.ponder.portable_storage_interface.text_3": "Piazzane un altro con uno spazio vuoto di 1 o 2 blocchi tra di essi", - "create.ponder.portable_storage_interface.text_4": "Ogni volta che passano l'uno accanto all'altro, essi si connetteranno", - "create.ponder.portable_storage_interface.text_5": "Mentre sono collegati, l'Interfaccia stazionaria rappresenterà TUTTI gli inventari nel Macchinario", - "create.ponder.portable_storage_interface.text_6": "È ora possibile inserire gli oggetti...", - "create.ponder.portable_storage_interface.text_7": "...oppure estrarli dal Macchinario", - "create.ponder.portable_storage_interface.text_8": "Se non avvengono scambi per troppo tempo, il Macchinario ripartirà", - - "create.ponder.portable_storage_interface_redstone.header": "Controllare le Interfacce con la redstone", - "create.ponder.portable_storage_interface_redstone.text_1": "Se ricevono un segnale redstone, le Interfacce stazionarie smetteranno di funzionare", - - "create.ponder.powered_latch.header": "Controllare segnali con un Circuito bi-stato", - "create.ponder.powered_latch.text_1": "I Circuiti bi-stato sono leve attivabili con la redstone", - "create.ponder.powered_latch.text_2": "Un segnale sul retro lo accende", - "create.ponder.powered_latch.text_3": "Un segnale sul lato lo spegne", - "create.ponder.powered_latch.text_4": "I Circuiti bi-stato possono anche essere azionati manualmente", - - "create.ponder.powered_toggle_latch.header": "Controllare segnali con un Alternatore redstone", - "create.ponder.powered_toggle_latch.text_1": "Gli Alternatori redstone sono leve attivabili con la redstone", - "create.ponder.powered_toggle_latch.text_2": "Un segnale sul retro cambia il suo stato", - "create.ponder.powered_toggle_latch.text_3": "...on e poi off", - "create.ponder.powered_toggle_latch.text_4": "Gli Alternatori possono anche essere azionati manualmente", - - "create.ponder.pulse_extender.header": "Controllare segnali con un Estensore di impulsi", - "create.ponder.pulse_extender.text_1": "Gli Estensori di impulsi allungano la durata di un segnale di passaggio", - "create.ponder.pulse_extender.text_2": "Si attivano dopo un piccolo ritardo...", - "create.ponder.pulse_extender.text_3": "...e rimangono attivi per la durata impostata", - "create.ponder.pulse_extender.text_4": "Puoi impostare il timer con la rotellina del mouse", - "create.ponder.pulse_extender.text_5": "La durata massima per il timer è di 30 minuti", - - "create.ponder.pulse_repeater.header": "Controllare segnali con un Ripetitore di impulsi", - "create.ponder.pulse_repeater.text_1": "I ripetitori di impulsi emettono un piccolo segnale con un ritardo", - "create.ponder.pulse_repeater.text_2": "Puoi impostare questo ritardo con la rotellina del mouse", - "create.ponder.pulse_repeater.text_3": "La durata massima per il timer è di 30 minuti", - - "create.ponder.radial_chassis.header": "Collegare blocchi usando Telai radiali", - "create.ponder.radial_chassis.text_1": "I Telai radiali si connettono automaticamente ad altri telai adiacenti in una linea", - "create.ponder.radial_chassis.text_2": "Se uno viene mosso come parte di un Macchinario, tutti gli altri saranno trascinati con esso", - "create.ponder.radial_chassis.text_3": "I lati di un Telaio radiale possono essere resi appiccicosi", - "create.ponder.radial_chassis.text_4": "Premi ancora per rendere appiccicosi anche tutti gli altri", - "create.ponder.radial_chassis.text_5": "Fai click destro da accovacciato con una mano vuota per togliere la colla", - "create.ponder.radial_chassis.text_6": "Ogni volta che un blocco è adiacente a una faccia appiccicosa...", - "create.ponder.radial_chassis.text_7": "...essa si connetterà a tutti i blocchi raggiungibili entro un raggio su quello strato", - "create.ponder.radial_chassis.text_8": "Puoi usare una Chiave a pappagallo per impostare la lunghezza di tale raggio", - "create.ponder.radial_chassis.text_9": "I blocchi non raggiungibili da nessuna faccia appiccicosa non si connetteranno", - - "create.ponder.redstone_contact.header": "Contatti redstone", - "create.ponder.redstone_contact.text_1": "Due Contatti redstone ruotati l'uno verso l'altro emetteranno un seganle redstone", - "create.ponder.redstone_contact.text_2": "Questo rimane vero anche quando uno dei due si muove come parte di un Macchinario", - - "create.ponder.redstone_link.header": "Usare i Connettori redstone", - "create.ponder.redstone_link.text_1": "I Connettori redstone possono trasmettere segnali redstone in maniera wireless", - "create.ponder.redstone_link.text_2": "Fai click destro da accovacciato per metterli in modalità di ricezione o viceversa", - "create.ponder.redstone_link.text_3": "Un semplice click destro con una Chiave a pappagallo farà lo stesso", - "create.ponder.redstone_link.text_4": "I ricevitori riceveranno i segnali redstone di trasmettitori entro 128 blocchi", - "create.ponder.redstone_link.text_5": "Piazzare oggetti nei due slot specifica una frequenza", - "create.ponder.redstone_link.text_6": "Solo i connettori con frequenze identiche potranno comunicare tra loro", - - "create.ponder.rope_pulley.header": "Spostare strutture usando una Carrucola per corda", - "create.ponder.rope_pulley.text_1": "Le Carrucole per corda muovono i blocchi orizzontalmente quando ricevono forza centrifuga", - "create.ponder.rope_pulley.text_2": "La velocità e la direzione in cui si muovono dipende dalla rotazione in entrata", - - "create.ponder.rope_pulley_attachment.header": "Trasportare Carrucole come parte di un Macchinario", - "create.ponder.rope_pulley_attachment.text_1": "Se una Carrucola è essa stessa parte di un Macchinario...", - "create.ponder.rope_pulley_attachment.text_2": "...le strutture ad essa connesse saranno mosse con lei", - "create.ponder.rope_pulley_attachment.text_3": "Ricorda che le carrucole sono trasportabili solo se non attive", - - "create.ponder.rope_pulley_modes.header": "Modalità di movimento della Carrucola per corda", - "create.ponder.rope_pulley_modes.text_1": "Quando una Carrucola si ferma, la struttura trasportata si riconverte in blocchi", - "create.ponder.rope_pulley_modes.text_2": "Può essere configurata in modo che la struttura non torni mai ad essere blocchi solidi, o a farlo solo al suo punto di partenza", - - "create.ponder.rose_quartz_lamp.header": "Lampade di quarzo rosa", - "create.ponder.rose_quartz_lamp.text_1": "Le Lampade di quarzo rosa si attivano con un segnale redstone", - "create.ponder.rose_quartz_lamp.text_2": "Dopodiché, continueranno ad emettere loro stesse un segnale redstone", - "create.ponder.rose_quartz_lamp.text_3": "Quando multiple lampade sono unite in un gruppo...", - "create.ponder.rose_quartz_lamp.text_4": "...attivare una lampada concentrerà il segnale su di essa, disattivando le altre", - "create.ponder.rose_quartz_lamp.text_5": "I comparatori emetteranno un output dipendentemente dalla distanza dalla lampada accesa", - "create.ponder.rose_quartz_lamp.text_6": "Le lampade possono anche essere attivate o disattivate manualmente con una Chiave a pappagallo", - - "create.ponder.rotation_speed_controller.header": "Usare il Regolatore di velocità di rotazione", - "create.ponder.rotation_speed_controller.text_1": "Un Regolatore di velocità trasposrta la forza centrifuga tra il suo asse e l'Ingranaggio grande sopra di esso", - "create.ponder.rotation_speed_controller.text_2": "Usando la rotellina sul suo lato si può configuare la velocità in uscita", - - "create.ponder.sail.header": "Assemblare Mulini a vento con le Vele", - "create.ponder.sail.text_1": "Le Vele sono utili blocchi con cui costruire Mulini a vento", - "create.ponder.sail.text_2": "Si connettono tra di loro e con blocchi vicini senza alcun bisogno di Super colla o Telai", - "create.ponder.sail.text_3": "Fai click destro con un colorante per cambiarne il colore", - "create.ponder.sail.text_4": "Fai click destro con delle Cesoie per farle tornare Cornici", - - "create.ponder.sail_frame.header": "Assemblare Mulini a vento con le Cornici di vela", - "create.ponder.sail_frame.text_1": "Le Cornici di vela sono utili blocchi con cui costruire Mulini a vento", - "create.ponder.sail_frame.text_2": "Si connettono tra di loro e con blocchi vicini senza alcun bisogno di Super colla o Telai", - - "create.ponder.sequenced_gearshift.header": "Controllare la velocità di rotazione con un Cambio sequenziale", - "create.ponder.sequenced_gearshift.text_1": "I Cambi sequenziali trasportano la rotazione seguendo una lista di istruzioni", - "create.ponder.sequenced_gearshift.text_2": "Fai click destro per aprire la schermata di configurazione", - "create.ponder.sequenced_gearshift.text_3": "Al ricevere un segnale redstone, inizierà ad eseguire le istruzioni una alla volta", - "create.ponder.sequenced_gearshift.text_4": "Una volta finito, attenderà un nuovo segnale redstone per ricominciare", - "create.ponder.sequenced_gearshift.text_5": "Un comparatore redstone può essere usato per leggere il progresso attuale", - - "create.ponder.shaft.header": "Trasportare la forza centrifuga usando le Assi", - "create.ponder.shaft.text_1": "Le Assi propagano la rotazione in una linea retta.", - - "create.ponder.shaft_casing.header": "Rivestire le Assi", - "create.ponder.shaft_casing.text_1": "Si possono usare Telai di ottone o andesite per decorare le Assi", - - "create.ponder.smart_chute.header": "Filtrare oggetti usando gli Scivoli intelligenti", - "create.ponder.smart_chute.text_1": "Gli Scivoli intelligenti sono scivoli verticali con controllo addizionale", - "create.ponder.smart_chute.text_2": "Gli oggetti nello slot di filtraggio specificano cosa può essere estratto e trasferito", - "create.ponder.smart_chute.text_3": "Usa la rotellina del mouse per specificare la grandezza dello stack da estrarre", - "create.ponder.smart_chute.text_4": "Un segnale redstone impedirà agli Scivoli intelligenti di funzionare.", - - "create.ponder.smart_pipe.header": "Controllare i fluidi usando Tubi intelligenti", - "create.ponder.smart_pipe.text_1": "I Tubi intelligenti possono aiutare a controllare il flusso di qualsiasi tipo di fluido", - "create.ponder.smart_pipe.text_2": "Quando posizionati direttamente alla fonte, possono specificare quale fluido deve essere estratto", - "create.ponder.smart_pipe.text_3": "Fai semplicemente click destro sullo slot di filraggio con qualsiasi oggetto contenente il fluido che ti interessa", - "create.ponder.smart_pipe.text_4": "Quando posti più avanti in un sistema di Tubi, i Tubi intelligenti lasceranno passare solo il fluido impostato", - - "create.ponder.speedometer.header": "Monitorare informazioni cinetiche con un Tachimetro", - "create.ponder.speedometer.text_1": "Il tachimetro mostra la velocità attuale dei componenti a cui è connesso", - "create.ponder.speedometer.text_2": "Informazioni più dettagliate sono visibili ai giocatori che indossano Occhiali da ingegnere e che osservano la lancetta", - "create.ponder.speedometer.text_3": "Un Comparatore emette un segnale redstone la cui potenza dipende dalle misurazioni del Tachimetro", - - "create.ponder.spout_filling.header": "Riempire oggetti con uno Spruzzatore", - "create.ponder.spout_filling.text_1": "Lo Spruzzatore può riempire oggetti posati sotto di esso, purché siano in grado di accettare fluidi", - "create.ponder.spout_filling.text_2": "Il contenuto di uno Spruzzatore non può essere modificato manualmente", - "create.ponder.spout_filling.text_3": "Sarà necessario utilizzare dei Tubi per riempirlo di fluidi", - "create.ponder.spout_filling.text_4": "Gli oggetti in input possono essere posti su una Stazione per oggetti sotto lo Spruzzatore", - "create.ponder.spout_filling.text_5": "Se essi sono, invece, trasportati da un Nastro...", - "create.ponder.spout_filling.text_6": "Lo Spruzzatore li fermerà e lavorerà automaticamente", - - "create.ponder.stabilized_bearings.header": "Macchinari stabilizzati", - "create.ponder.stabilized_bearings.text_1": "Se un Supporto meccanico è esso stesso parte di un Macchinario..", - "create.ponder.stabilized_bearings.text_2": "...cercherà in ogni momento di restare dritto", - "create.ponder.stabilized_bearings.text_3": "Come sempre, il Supporto si connette al blocco di fronte a sé", - "create.ponder.stabilized_bearings.text_4": "Di conseguenza, l'intero sotto-macchinario rimarrà dritto", - - "create.ponder.steam_engine.header": "Installare Motori a vapore", - "create.ponder.steam_engine.text_1": "I Motori a vapore possono essere installati su un Serbatoio per fluidi", - "create.ponder.steam_engine.text_10": "Lvl 4", - "create.ponder.steam_engine.text_11": "4 Motori", - "create.ponder.steam_engine.text_12": "Lvl 8", - "create.ponder.steam_engine.text_13": "8 Motori", - "create.ponder.steam_engine.text_2": "Fai click sul Motore con un'Asse per crearne l'output cinetico", - "create.ponder.steam_engine.text_3": "Con abbastanza calore, acqua e spazio nel Serbatoio...", - "create.ponder.steam_engine.text_4": "...il motore inizierà a generare forza centrifuga", - "create.ponder.steam_engine.text_5": "Il sistema minimo richiede 4 Serbatoi", - "create.ponder.steam_engine.text_6": "Grazie a dei Bruciatori a blaze, l'output di energia può essere aumentato", - "create.ponder.steam_engine.text_7": "Livelli di potenza maggiori richiedono più acqua, spazio e calore", - "create.ponder.steam_engine.text_8": "Il livello di potenza della caldaia può essere osservato con gli Occhiali da Ingegnere", - "create.ponder.steam_engine.text_9": "Per ogni livello di potenza aggiunto si può far funzionare un Motore in più a pieno regime", - - "create.ponder.steam_whistle.header": "Installare Fischi a vapore", - "create.ponder.steam_whistle.text_1": "I Fischi a vapore possono essere connessi ai Serbatoi", - "create.ponder.steam_whistle.text_2": "Se il Serbatoio riceve abbastanza calore...", - "create.ponder.steam_whistle.text_3": "...il Fischio emetterà una nota quando attivato", - "create.ponder.steam_whistle.text_4": "Installa ulteriori Fischi su di esso per abbassarne l'intonazione", - "create.ponder.steam_whistle.text_5": "Scorri tra 3 diverse ottave usando una Chiave a pappagallo", - "create.ponder.steam_whistle.text_6": "Gli Occhiali da ingengere possono aiutare a scoprire l'intonazione attuale del Fischio", - - "create.ponder.sticker.header": "Incollare blocchi usando l'Incollatore", - "create.ponder.sticker.text_1": "Gli Incollatori sono l'ideale per alterare una struttura con la redstone", - "create.ponder.sticker.text_2": "Essi cambiano il loro stato una volta ricevuto un segnare redstone", - "create.ponder.sticker.text_3": "Una volta connesso questo Incollatore ad un Macchinario, il blocco si muoverà con esso", - "create.ponder.sticker.text_4": "Attivandolo nuovamente, il blocco non sarà più incollato", - - "create.ponder.stressometer.header": "Monitorare informazioni cinetiche con uno Stressometro", - "create.ponder.stressometer.text_1": "Lo Stressometro mostra la capacità di stress del sistema cinetico a cui è connesso", - "create.ponder.stressometer.text_2": "Informazioni più dettagliate sono visibili ai giocatori che indossano Occhiali da ingegnere che osservano la lancetta", - "create.ponder.stressometer.text_3": "Un Comparatore emette un segnale redstone la cui potenza dipende dalle misurazioni dello Stressometro", - - "create.ponder.super_glue.header": "Incollare blocchi con la Super colla", - "create.ponder.super_glue.text_1": "La Super colla raggruppa blocchi insieme per renderli un unico Macchinario", - "create.ponder.super_glue.text_2": "Fare click destro su due punti terminali crea una nuova area di colla", - "create.ponder.super_glue.text_3": "Per rimuovere un'area, picchiala con la colla in mano", - "create.ponder.super_glue.text_4": "Blocchi adiacenti che fanno parte della stessa area si tireranno l'un l'altro", - "create.ponder.super_glue.text_5": "Volumi di colla sovrapposti si muoveranno tutti insieme", - "create.ponder.super_glue.text_6": "Normalmente, i blocchi che si appoggiano su altri non richiedono colla", - - "create.ponder.track_chunks.header": "Attraversare chunk non caricati", - "create.ponder.track_chunks.text_1": "Le Rotaie funzionano anche al di fuori dei chunk caricati", - "create.ponder.track_chunks.text_2": "I treni attraverseranno parti inattive del mondo senza alcun problema", - "create.ponder.track_chunks.text_3": "Si fermeranno perfino alle stazioni o ai Semafori rossi", - "create.ponder.track_chunks.text_4": "Tuttavia, Trivelle e altri componenti a bordo non funzioneranno", - "create.ponder.track_chunks.text_5": "Una volta tornato vicino a un giocatore, il treno riapparirà", - - "create.ponder.track_observer.header": "Individuare Treni", - "create.ponder.track_observer.text_1": "Seleziona una Rotaia e poi posiziona l'Osservatore nelle vicinanze", - "create.ponder.track_observer.text_2": "L'Osservatore individuerà qualsiasi Treno di passaggio sopra il marcatore", - "create.ponder.track_observer.text_3": "Gli Osservatori possono essere filtrati per leggere il carico corrispondente", - - "create.ponder.track_placement.header": "Posizionare Rotaie", - "create.ponder.track_placement.text_1": "Le Rotaie sono un nuovo tipo di binari studiati per essere usati dai Treni", - "create.ponder.track_placement.text_2": "Per posizionare un insieme di Rotaie in un colpo solo, premi su una Rotaia già esistente", - "create.ponder.track_placement.text_3": "Poi seleziona oppure posiziona una seconda Rotaia", - "create.ponder.track_placement.text_4": "Le Rotaie possono anche formare curve o dislivelli", - "create.ponder.track_placement.text_5": "Mentre vengono connesse, le Rotaie cercano di fare sempre curve della stessa grandezza", - "create.ponder.track_placement.text_6": "Tuttavia, tenendo premuto il pulsante di corsa...", - "create.ponder.track_placement.text_7": "...le Rotaie creeranno la curva più larga possibile", - "create.ponder.track_placement.text_8": "I materiali nella mano secondaria saranno usati automaticamente come pavimentazione sotto le Rotaie", - - "create.ponder.track_portal.header": "Rotaie e Nether", - "create.ponder.track_portal.text_1": "Posizionando delle Rotaie accanto a un Portale del Nether...", - "create.ponder.track_portal.text_2": "...esse cercheranno di creare una Rotaia corrispondente dall'altro lato", - "create.ponder.track_portal.text_3": "I treni su questa ferrovia potranno ora viaggiare tra le dimensioni", - - "create.ponder.train_assembly.header": "Assemblare Treni", - "create.ponder.train_assembly.text_1": "Seleziona una Rotaia e posiziona la Stazione ferroviaria nelle vicinanze", - "create.ponder.train_assembly.text_10": "Ogni treno richiede dei Comandi a bordo", - "create.ponder.train_assembly.text_11": "Si può aggiungere un altro set di Comandi per potersi allontanare dalla Stazione in entrambe le direzioni", - "create.ponder.train_assembly.text_12": "Apri la schermata della Stazione e conferma la fine del processo di assemblaggio", - "create.ponder.train_assembly.text_13": "I treni possono essere smontati in blocchi solo alle stazioni", - "create.ponder.train_assembly.text_14": "Usando una mappa su una Stazione, sarà aggiunto su di essa un simbolo che la indica", - "create.ponder.train_assembly.text_15": "I Treni assemblati possono riposizionati su Rotaie vicine usando la Chiave a pappagallo", - "create.ponder.train_assembly.text_2": "Le stazioni sono i punti di destinazione della tua ferrovia", - "create.ponder.train_assembly.text_3": "Per creare un nuovo treno, apri la schermata della Stazione e passa in modalità di assemblaggio", - "create.ponder.train_assembly.text_4": "Nessun treno con una Tabella di marcia si avvicinerà alla stazione durante il processo di assemblaggio", - "create.ponder.train_assembly.text_5": "Usa un Rivestimento di treno sulle Rotaie per creare nuovi carrelli", - "create.ponder.train_assembly.text_6": "Premi di nuovo sulla Rotaia per cambiare il design del carrello", - "create.ponder.train_assembly.text_7": "Connetti i vari blocchi usando la Super colla", - "create.ponder.train_assembly.text_8": "I Treni si muovono più velocemente se trovano del combustibile in un inventario connesso", - "create.ponder.train_assembly.text_9": "Il combustibile all'interno dei Container non verrà consumato dal Treno", - - "create.ponder.train_controls.header": "Guidare i Treni", - "create.ponder.train_controls.text_1": "I Comandi del treno sono necessari per far funzionare i Treni", - "create.ponder.train_controls.text_2": "Una volta assemblato il treno, fai click destro sul blocco per iniziare a guidare", - "create.ponder.train_controls.text_3": "Puoi guidare il treno usando i pulsanti di movimento", - "create.ponder.train_controls.text_4": "Se lo desideri, puoi alterare la velocità massima con la rotellina del mouse", - "create.ponder.train_controls.text_5": "Tieni premuto spazio per avvicinarti e fermarti a una Stazione vicina", - "create.ponder.train_controls.text_6": "I Treni possono essere smontati solo alle Stazioni", - "create.ponder.train_controls.text_7": "I Fischi assemblati possono essere azionati con il pulsante di corsa", - "create.ponder.train_controls.text_8": "Accovacciati oppure premi di nuovo per fermare il Treno", - - "create.ponder.train_schedule.header": "Usare le Tabelle di marcia", - "create.ponder.train_schedule.text_1": "Le Tabelle di marcia permettono di assegnare dei conducenti ai Treni", - "create.ponder.train_schedule.text_2": "Fai click destro con l'oggetto in mano per aprire la sua interfaccia", - "create.ponder.train_schedule.text_3": "Una volta programmata, la Tabella di marcia può essere assegnata a un conducente", - "create.ponder.train_schedule.text_4": "Qualsiasi mob o Bruciatore a blaze presente di fronte ai Comandi di un treno è un conducente valido", - "create.ponder.train_schedule.text_5": "Una creatura catturata con un guinzaglio può essere messa a sedere più agevolmente", - "create.ponder.train_schedule.text_6": "Le Tabelle di marcia possono essere ritirate in qualsiasi momento", - - "create.ponder.train_signal_placement.header": "Posizionare i Semafori ferroviari", - "create.ponder.train_signal_placement.text_1": "Seleziona una Rotaia e posiziona il Semaforo ferroviario nelle vicinanze", - "create.ponder.train_signal_placement.text_2": "I Semafori controllano il traffico dei Treni non guidati da giocatori", - "create.ponder.train_signal_placement.text_3": "I Treni che seguono una Tabella di marcia non supereranno mai un Semaforo in direzione opposta a quella indicata", - "create.ponder.train_signal_placement.text_4": "...a meno che non ci sia un altro Semaforo ruotato nella suddetta direzione.", - "create.ponder.train_signal_placement.text_5": "I Tubi di Nixie connessi al Semaforo rendono le luci più facili da vedere", - - "create.ponder.train_signal_redstone.header": "Semafori e redstone", - "create.ponder.train_signal_redstone.text_1": "I Semafori possono essere resi forzatamente rossi con un segnale redstone", - "create.ponder.train_signal_redstone.text_2": "In contrasto, i Semafori rossi emettono un segnale redstone", - - "create.ponder.train_signal_signaling.header": "Prevenire le collisioni con i Semafori", - "create.ponder.train_signal_signaling.text_1": "I Semafori dividono la ferrovia in segmenti", - "create.ponder.train_signal_signaling.text_2": "Se un segmento è occupato, a nessun Treno sarà permesso di accedervi", - "create.ponder.train_signal_signaling.text_3": "Pertanto, un segmento conterrà un solo Treno alla volta", - "create.ponder.train_signal_signaling.text_4": "È possibile attivare una seconda modalità di segnalazione usando una Chiave a pappagallo", - "create.ponder.train_signal_signaling.text_5": "I segmenti di un segnalatore in ottone normalmente sono seguiti da Semafori normali", - "create.ponder.train_signal_signaling.text_6": "Questo speciale Semaforo può fermare i treni anche in un secondo caso", - "create.ponder.train_signal_signaling.text_7": "Fermerà qualsiasi Treno che, dopo essere entrato...", - "create.ponder.train_signal_signaling.text_8": "...non avrebbe modo di lasciare il segmento immediatamente", - "create.ponder.train_signal_signaling.text_9": "Questo permette di tenere i treni in coda al di fuori di un segmento trafficato o una intersezione", - - "create.ponder.valve_handle.header": "Generare Forza centrifuga usando Maniglie per valvola", - "create.ponder.valve_handle.text_1": "Le Maniglie per valvola possono essere usate dai giocatori per generare forza centrifuga manualmente", - "create.ponder.valve_handle.text_2": "Tieni premuto il pulsante destro per farla ruotare in senso antiorario", - "create.ponder.valve_handle.text_3": "La sua velocità di rotazione è lenta e precisa", - "create.ponder.valve_handle.text_4": "Tieni premuto il pulsante destro da accovacciato per farla ruotare in senso orario", - "create.ponder.valve_handle.text_5": "Le Maniglie per valvola possono essere colorate per motivi estetici", - - "create.ponder.valve_pipe.header": "Controllare i fluidi usando le Valvole", - "create.ponder.valve_pipe.text_1": "Le Valvole possono essere usate per controllare la propagazione dei fluidi in un sistema di Tubi", - "create.ponder.valve_pipe.text_2": "La loro asse di input definisce se il fluido può passare oppure no", - "create.ponder.valve_pipe.text_3": "Dando loro forza centrifuga nella direzione di apertura, le valvole si aprono", - "create.ponder.valve_pipe.text_4": "Si possono poi chiudere semplicemente invertendo la rotazione in entrata", - - "create.ponder.water_wheel.header": "Generare forza centrifuga con i Mulini ad acqua", - "create.ponder.water_wheel.text_1": "I Mulini ad acqua generano forza centrifuga grazie alle correnti d'acqua ad essi adiacenti", - "create.ponder.water_wheel.text_2": "Maggiori le facce a contatto con essi, più veloce sarà la rotazione del mulino", - "create.ponder.water_wheel.text_3": "Le lame del mulino dovrebbero sempre essere girate contro il flusso d'acqua", - "create.ponder.water_wheel.text_4": "Non saranno altrettanto efficienti se questa condizione non è rispettata", - - "create.ponder.weighted_ejector.header": "Usare gli Espulsori di Pesi", - "create.ponder.weighted_ejector.text_1": "Fai click destro da accovacciato con in mano un Espulsore per selezionarne la posizione bersaglio", - "create.ponder.weighted_ejector.text_10": "Il componente non si attiverà finché lo stack non raggiunge quel numero di oggetti", - "create.ponder.weighted_ejector.text_11": "Altre entità attiveranno sempre un Espulsore camminandoci sopra", - "create.ponder.weighted_ejector.text_2": "Una volta piazzato, l'Espulsore lancerà gli oggetti in quella posizione", - "create.ponder.weighted_ejector.text_3": "Un bersaglio valido può trovarsi a qualsiasi altezza o distanza entro un raggio", - "create.ponder.weighted_ejector.text_4": "Non può, tuttavia, essere posizionato lateralmente, neppure di un singolo blocco", - "create.ponder.weighted_ejector.text_5": "In assenza di un bersaglio valido, l'Espulsore bersaglierà semplicemente il blocco di fronte", - "create.ponder.weighted_ejector.text_6": "Fornisci forza centrifuga per caricarlo", - "create.ponder.weighted_ejector.text_7": "Piazzare oggetti su di esso lo farà attivare", - "create.ponder.weighted_ejector.text_8": "Se il bersaglio è un inventario, l'Espulsore aspetterà che ci sia spazio", - "create.ponder.weighted_ejector.text_9": "Scorri con una Chiave a pappagallo per specificare la grandezza dello stack da lanciare", - - "create.ponder.weighted_ejector_redstone.header": "Controllare gli Espulsori di pesi con la redstone", - "create.ponder.weighted_ejector_redstone.text_1": "Un segnale redstone impedirà agli Espulsori di funzionare", - "create.ponder.weighted_ejector_redstone.text_2": "Inoltre, gli Osservatori possono percepire l'attivazione di un Espulsore", - - "create.ponder.weighted_ejector_tunnel.header": "Dividere gli stack con gli Espulsori di pesi", - "create.ponder.weighted_ejector_tunnel.text_1": "Usando i Tunnel di ottone, gli Espulsori possono dividere gli stack in parti specifiche", - "create.ponder.weighted_ejector_tunnel.text_2": "Per prima cosa, configura il Tunnel su 'Dai precedenza al più vicino', così da dare priorità al suo output laterale", - "create.ponder.weighted_ejector_tunnel.text_3": "La grandezza dello stack dell'Espulsore determinerà il numero di oggetti da estrarre", - "create.ponder.weighted_ejector_tunnel.text_4": "All'arrivo di un nuovo stack, l'ammontare scelto uscirà dall'output laterale...", - "create.ponder.weighted_ejector_tunnel.text_5": "...mentre il resto proseguirà per la sua strada", - - "create.ponder.windmill_source.header": "Generare forza centrifuga con i Supporti per mulino a vento", - "create.ponder.windmill_source.text_1": "I Supporti per mulino a vento si connettono ai blocchi di fronte ad essi", - "create.ponder.windmill_source.text_2": "Crea una struttura con l'aiuto della Super colla", - "create.ponder.windmill_source.text_3": "Se hai incluso abbastanza vele valide, questa struttura conterà come mulino a vento", - "create.ponder.windmill_source.text_4": "Una volta attivato con un click destro, il Supporto per mulino a vento inizierà a generare forza centrifuga", - "create.ponder.windmill_source.text_5": "La sua velocità dipende dal numero di vele", - "create.ponder.windmill_source.text_6": "Usa una Chiave a pappagallo per cambiare la direzione di rotazione", - "create.ponder.windmill_source.text_7": "Fai click destro sul Supporto in qualsiasi momento per fermarlo e poter modificare di nuovo la struttura", - - "create.ponder.windmill_structure.header": "Macchinari per Mulini a vento", - "create.ponder.windmill_structure.text_1": "Qualsiasi struttura può essere un Mulino a vento valido, purché contenga almeno 8 blocchi che possano essere considerati vele.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json deleted file mode 100644 index 7703a8cc32..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 5", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "アカシアの窓", - "block.create.acacia_window_pane": "アカシアの板窓", - "block.create.adjustable_chain_gearshift": "可変チェーンギアシフト", - "block.create.analog_lever": "アナログレバー", - "block.create.andesite_belt_funnel": "安山岩ベルトファンネル", - "block.create.andesite_casing": "安山岩ケーシング", - "block.create.andesite_encased_cogwheel": "安山岩ケース入り歯車", - "block.create.andesite_encased_large_cogwheel": "安山岩ケース入り大きな歯車", - "block.create.andesite_encased_shaft": "安山岩ケース入りシャフト", - "block.create.andesite_funnel": "安山岩ファンネル", - "block.create.andesite_ladder": "安山岩のはしご", - "block.create.andesite_pillar": "安山岩の柱", - "block.create.andesite_tunnel": "安山岩トンネル", - "block.create.asurine": "瑠璃岩", - "block.create.asurine_pillar": "瑠璃岩の柱", - "block.create.basin": "鉢", - "block.create.belt": "メカニカルベルト", - "block.create.birch_window": "シラカバの窓", - "block.create.birch_window_pane": "シラカバの板窓", - "block.create.black_nixie_tube": "黒色のニキシー管", - "block.create.black_sail": "黒色の帆", - "block.create.black_seat": "黒色のシート", - "block.create.black_toolbox": "黒色の工具箱", - "block.create.black_valve_handle": "黒色のバルブハンドル", - "block.create.blaze_burner": "ブレイズバーナー", - "block.create.blue_nixie_tube": "青色のニキシー管", - "block.create.blue_sail": "青色の帆", - "block.create.blue_seat": "青色のシート", - "block.create.blue_toolbox": "青色の工具箱", - "block.create.blue_valve_handle": "青色のバルブハンドル", - "block.create.brass_belt_funnel": "真鍮ベルトファンネル", - "block.create.brass_block": "真鍮ブロック", - "block.create.brass_casing": "真鍮ケーシング", - "block.create.brass_encased_cogwheel": "真鍮ケース入り歯車", - "block.create.brass_encased_large_cogwheel": "真鍮ケース入り大きな歯車", - "block.create.brass_encased_shaft": "真鍮ケース入りシャフト", - "block.create.brass_funnel": "真鍮ファンネル", - "block.create.brass_ladder": "真鍮のはしご", - "block.create.brass_tunnel": "真鍮トンネル", - "block.create.brown_nixie_tube": "茶色のニキシー管", - "block.create.brown_sail": "茶色の帆", - "block.create.brown_seat": "茶色のシート", - "block.create.brown_toolbox": "茶色の工具箱", - "block.create.brown_valve_handle": "茶色のバルブハンドル", - "block.create.calcite_pillar": "方解石の柱", - "block.create.cart_assembler": "トロッコアセンブラ", - "block.create.chocolate": "チョコレート", - "block.create.chute": "シュート", - "block.create.clockwork_bearing": "時計仕掛けのベアリング", - "block.create.clutch": "クラッチ", - "block.create.cogwheel": "歯車", - "block.create.content_observer": "コンテンツオブザーバー", - "block.create.controller_rail": "コントローラーレール", - "block.create.controls": "列車運転台", - "block.create.copper_backtank": "銅のバックタンク", - "block.create.copper_casing": "銅ケーシング", - "block.create.copper_ladder": "銅のはしご", - "block.create.copper_shingle_slab": "銅の屋根板のハーフブロック", - "block.create.copper_shingle_stairs": "銅の屋根板の階段", - "block.create.copper_shingles": "銅の屋根板", - "block.create.copper_tile_slab": "銅タイルのハーフブロック", - "block.create.copper_tile_stairs": "銅タイルの階段", - "block.create.copper_tiles": "銅タイル", - "block.create.copper_valve_handle": "銅のバルブハンドル", - "block.create.creative_crate": "クリエティブクレート", - "block.create.creative_fluid_tank": "クリエイティブ液体タンク", - "block.create.creative_motor": "クリエイティブモーター", - "block.create.crimsite": "真紅岩", - "block.create.crimsite_pillar": "真紅岩の柱", - "block.create.crimson_window": "真紅の窓", - "block.create.crimson_window_pane": "真紅の板窓", - "block.create.crushing_wheel": "破砕ホイール", - "block.create.crushing_wheel_controller": "破砕ホイールコントローラー", - "block.create.cuckoo_clock": "鳩時計", - "block.create.cut_andesite": "安山岩の切石", - "block.create.cut_andesite_brick_slab": "安山岩の切石レンガのハーフブロック", - "block.create.cut_andesite_brick_stairs": "安山岩の切石レンガの階段", - "block.create.cut_andesite_brick_wall": "安山岩の切石レンガの塀", - "block.create.cut_andesite_bricks": "安山岩の切石レンガ", - "block.create.cut_andesite_slab": "安山岩の切石のハーフブロック", - "block.create.cut_andesite_stairs": "安山岩の切石の階段", - "block.create.cut_andesite_wall": "安山岩の切石の塀", - "block.create.cut_asurine": "瑠璃岩の切石", - "block.create.cut_asurine_brick_slab": "瑠璃岩の切石レンガのハーフブロック", - "block.create.cut_asurine_brick_stairs": "瑠璃岩の切石レンガの階段", - "block.create.cut_asurine_brick_wall": "瑠璃岩の切石レンガの塀", - "block.create.cut_asurine_bricks": "瑠璃岩の切石レンガ", - "block.create.cut_asurine_slab": "瑠璃岩の切石のハーフブロック", - "block.create.cut_asurine_stairs": "瑠璃岩の切石の階段", - "block.create.cut_asurine_wall": "瑠璃岩の切石の塀", - "block.create.cut_calcite": "方解石の切石", - "block.create.cut_calcite_brick_slab": "方解石の切石レンガのハーフブロック", - "block.create.cut_calcite_brick_stairs": "方解石の切石レンガの階段", - "block.create.cut_calcite_brick_wall": "方解石の切石レンガの塀", - "block.create.cut_calcite_bricks": "方解石の切石レンガ", - "block.create.cut_calcite_slab": "方解石の切石のハーフブロック", - "block.create.cut_calcite_stairs": "方解石の切石の階段", - "block.create.cut_calcite_wall": "方解石の切石の塀", - "block.create.cut_crimsite": "真紅岩の切石", - "block.create.cut_crimsite_brick_slab": "真紅岩の切石レンガのハーフブロック", - "block.create.cut_crimsite_brick_stairs": "真紅岩の切石レンガの階段", - "block.create.cut_crimsite_brick_wall": "真紅岩の切石レンガの塀", - "block.create.cut_crimsite_bricks": "真紅岩の切石レンガ", - "block.create.cut_crimsite_slab": "真紅岩の切石のハーフブロック", - "block.create.cut_crimsite_stairs": "真紅岩の切石の階段", - "block.create.cut_crimsite_wall": "真紅岩の切石の塀", - "block.create.cut_deepslate": "深層岩の切石", - "block.create.cut_deepslate_brick_slab": "深層岩の切石レンガのハーフブロック", - "block.create.cut_deepslate_brick_stairs": "深層岩の切石レンガの階段", - "block.create.cut_deepslate_brick_wall": "深層岩の切石レンガの塀", - "block.create.cut_deepslate_bricks": "深層岩の切石レンガ", - "block.create.cut_deepslate_slab": "深層岩の切石のハーフブロック", - "block.create.cut_deepslate_stairs": "深層岩の切石の階段", - "block.create.cut_deepslate_wall": "深層岩の切石の塀", - "block.create.cut_diorite": "閃緑岩の切石", - "block.create.cut_diorite_brick_slab": "閃緑岩の切石レンガのハーフブロック", - "block.create.cut_diorite_brick_stairs": "閃緑岩の切石レンガの階段", - "block.create.cut_diorite_brick_wall": "閃緑岩の切石レンガの塀", - "block.create.cut_diorite_bricks": "閃緑岩の切石レンガ", - "block.create.cut_diorite_slab": "閃緑岩の切石のハーフブロック", - "block.create.cut_diorite_stairs": "閃緑岩の切石の階段", - "block.create.cut_diorite_wall": "閃緑岩の切石の塀", - "block.create.cut_dripstone": "鍾乳石の切石", - "block.create.cut_dripstone_brick_slab": "鍾乳石の切石レンガのハーフブロック", - "block.create.cut_dripstone_brick_stairs": "鍾乳石の切石レンガの階段", - "block.create.cut_dripstone_brick_wall": "鍾乳石の切石レンガの塀", - "block.create.cut_dripstone_bricks": "鍾乳石の切石レンガ", - "block.create.cut_dripstone_slab": "鍾乳石の切石のハーフブロック", - "block.create.cut_dripstone_stairs": "鍾乳石の切石の階段", - "block.create.cut_dripstone_wall": "鍾乳石の切石の塀", - "block.create.cut_granite": "花崗岩の切石", - "block.create.cut_granite_brick_slab": "花崗岩の切石レンガのハーフブロック", - "block.create.cut_granite_brick_stairs": "花崗岩の切石レンガの階段", - "block.create.cut_granite_brick_wall": "花崗岩の切石レンガの塀", - "block.create.cut_granite_bricks": "花崗岩の切石レンガ", - "block.create.cut_granite_slab": "花崗岩の切石のハーフブロック", - "block.create.cut_granite_stairs": "花崗岩の切石の階段", - "block.create.cut_granite_wall": "花崗岩の切石の塀", - "block.create.cut_limestone": "石灰岩の切石", - "block.create.cut_limestone_brick_slab": "石灰岩の切石レンガのハーフブロック", - "block.create.cut_limestone_brick_stairs": "石灰岩の切石レンガの階段", - "block.create.cut_limestone_brick_wall": "石灰岩の切石レンガの塀", - "block.create.cut_limestone_bricks": "石灰岩の切石レンガ", - "block.create.cut_limestone_slab": "石灰岩の切石のハーフブロック", - "block.create.cut_limestone_stairs": "石灰岩の切石の階段", - "block.create.cut_limestone_wall": "石灰岩の切石の塀", - "block.create.cut_ochrum": "黄土岩の切石", - "block.create.cut_ochrum_brick_slab": "黄土岩の切石レンガのハーフブロック", - "block.create.cut_ochrum_brick_stairs": "黄土岩の切石レンガの階段", - "block.create.cut_ochrum_brick_wall": "黄土岩の切石レンガの塀", - "block.create.cut_ochrum_bricks": "黄土岩の切石レンガ", - "block.create.cut_ochrum_slab": "黄土岩の切石のハーフブロック", - "block.create.cut_ochrum_stairs": "黄土岩の切石の階段", - "block.create.cut_ochrum_wall": "黄土岩の切石の塀", - "block.create.cut_scorchia": "スコーチアの切石", - "block.create.cut_scorchia_brick_slab": "スコーチアの切石レンガのハーフブロック", - "block.create.cut_scorchia_brick_stairs": "スコーチアの切石レンガの階段", - "block.create.cut_scorchia_brick_wall": "スコーチアの切石レンガの塀", - "block.create.cut_scorchia_bricks": "スコーチアの切石レンガ", - "block.create.cut_scorchia_slab": "スコーチアの切石のハーフブロック", - "block.create.cut_scorchia_stairs": "スコーチアの切石の階段", - "block.create.cut_scorchia_wall": "スコーチアの切石の塀", - "block.create.cut_scoria": "スコリアの切石", - "block.create.cut_scoria_brick_slab": "スコリアの切石レンガのハーフブロック", - "block.create.cut_scoria_brick_stairs": "スコリアの切石レンガの階段", - "block.create.cut_scoria_brick_wall": "スコリアの切石レンガの塀", - "block.create.cut_scoria_bricks": "スコリアの切石レンガ", - "block.create.cut_scoria_slab": "スコリアの切石のハーフブロック", - "block.create.cut_scoria_stairs": "スコリアの切石の階段", - "block.create.cut_scoria_wall": "スコリアの切石の塀", - "block.create.cut_tuff": "凝灰岩の切石", - "block.create.cut_tuff_brick_slab": "凝灰岩の切石レンガのハーフブロック", - "block.create.cut_tuff_brick_stairs": "凝灰岩の切石レンガの階段", - "block.create.cut_tuff_brick_wall": "凝灰岩の切石レンガの塀", - "block.create.cut_tuff_bricks": "凝灰岩の切石レンガ", - "block.create.cut_tuff_slab": "凝灰岩の切石のハーフブロック", - "block.create.cut_tuff_stairs": "凝灰岩の切石の階段", - "block.create.cut_tuff_wall": "凝灰岩の切石の塀", - "block.create.cut_veridium": "翡翠岩の切石", - "block.create.cut_veridium_brick_slab": "翡翠岩の切石レンガのハーフブロック", - "block.create.cut_veridium_brick_stairs": "翡翠岩の切石レンガの階段", - "block.create.cut_veridium_brick_wall": "翡翠岩の切石レンガの塀", - "block.create.cut_veridium_bricks": "翡翠岩の切石レンガ", - "block.create.cut_veridium_slab": "翡翠岩の切石のハーフブロック", - "block.create.cut_veridium_stairs": "翡翠岩の切石の階段", - "block.create.cut_veridium_wall": "翡翠岩の切石の塀", - "block.create.cyan_nixie_tube": "水色のニキシー管", - "block.create.cyan_sail": "水色の帆", - "block.create.cyan_seat": "水色のシート", - "block.create.cyan_toolbox": "水色の工具箱", - "block.create.cyan_valve_handle": "水色のバルブハンドル", - "block.create.dark_oak_window": "ダークオークの窓", - "block.create.dark_oak_window_pane": "ダークオークの板窓", - "block.create.deepslate_pillar": "深層岩の柱", - "block.create.deepslate_zinc_ore": "深層亜鉛鉱石", - "block.create.deployer": "デプロイヤー", - "block.create.depot": "デポ", - "block.create.diorite_pillar": "閃緑岩の柱", - "block.create.display_board": "ディスプレイボード", - "block.create.display_link": "ディスプレイリンク", - "block.create.dripstone_pillar": "鍾乳石の柱", - "block.create.encased_chain_drive": "ケース入りチェーンドライブ", - "block.create.encased_fan": "ケース入りファン", - "block.create.encased_fluid_pipe": "ケース入り液体パイプ", - "block.create.exposed_copper_shingle_slab": "風化した銅の屋根板のハーフブロック", - "block.create.exposed_copper_shingle_stairs": "風化した銅の屋根板の階段", - "block.create.exposed_copper_shingles": "風化した銅の屋根板", - "block.create.exposed_copper_tile_slab": "風化した銅タイルのハーフブロック", - "block.create.exposed_copper_tile_stairs": "風化した銅タイルの階段", - "block.create.exposed_copper_tiles": "風化した銅タイル", - "block.create.fake_track": "地図用線路マーカー", - "block.create.fluid_pipe": "液体パイプ", - "block.create.fluid_tank": "液体タンク", - "block.create.fluid_valve": "液体バルブ", - "block.create.flywheel": "弾み車", - "block.create.framed_glass": "縁付きガラス", - "block.create.framed_glass_door": "縁付きガラスのドア", - "block.create.framed_glass_pane": "縁付きガラス板", - "block.create.framed_glass_trapdoor": "縁付きガラスのトラップドア", - "block.create.gantry_carriage": "ガントリーキャリッジ", - "block.create.gantry_shaft": "ガントリーシャフト", - "block.create.gearbox": "ギアボックス", - "block.create.gearshift": "ギアシフト", - "block.create.glass_fluid_pipe": "ガラスの液体パイプ", - "block.create.granite_pillar": "花崗岩の柱", - "block.create.gray_nixie_tube": "灰色のニキシー管", - "block.create.gray_sail": "灰色の帆", - "block.create.gray_seat": "灰色のシート", - "block.create.gray_toolbox": "灰色の工具箱", - "block.create.gray_valve_handle": "灰色のバルブハンドル", - "block.create.green_nixie_tube": "緑色のニキシー管", - "block.create.green_sail": "緑色の帆", - "block.create.green_seat": "緑色のシート", - "block.create.green_toolbox": "緑色の工具箱", - "block.create.green_valve_handle": "緑色のバルブハンドル", - "block.create.hand_crank": "ハンドクランク", - "block.create.haunted_bell": "憑りつかれた鐘", - "block.create.honey": "ハチミツ", - "block.create.horizontal_framed_glass": "横型ガラス窓", - "block.create.horizontal_framed_glass_pane": "横型ガラス板窓", - "block.create.hose_pulley": "ホースプーリー", - "block.create.item_drain": "アイテム排液口", - "block.create.item_vault": "アイテム保管庫", - "block.create.jungle_window": "ジャングルの窓", - "block.create.jungle_window_pane": "ジャングルの板窓", - "block.create.large_bogey": "大きな台車", - "block.create.large_cogwheel": "大きな歯車", - "block.create.layered_andesite": "安山岩の組石", - "block.create.layered_asurine": "瑠璃岩の組石", - "block.create.layered_calcite": "方解石の組石", - "block.create.layered_crimsite": "真紅岩の組石", - "block.create.layered_deepslate": "深層岩の組石", - "block.create.layered_diorite": "閃緑岩の組石", - "block.create.layered_dripstone": "鍾乳石の組石", - "block.create.layered_granite": "花崗岩の組石", - "block.create.layered_limestone": "石灰岩の組石", - "block.create.layered_ochrum": "黄土岩の組石", - "block.create.layered_scorchia": "スコーチアの組石", - "block.create.layered_scoria": "スコリアの組石", - "block.create.layered_tuff": "凝灰岩の組石", - "block.create.layered_veridium": "翡翠岩の組石", - "block.create.lectern_controller": "書見台コントローラー", - "block.create.light_blue_nixie_tube": "空色のニキシー菅", - "block.create.light_blue_sail": "空色の帆", - "block.create.light_blue_seat": "空色のシート", - "block.create.light_blue_toolbox": "空色の工具箱", - "block.create.light_blue_valve_handle": "空色のバルブハンドル", - "block.create.light_gray_nixie_tube": "薄灰色のニキシー管", - "block.create.light_gray_sail": "薄灰色の帆", - "block.create.light_gray_seat": "薄灰色のシート", - "block.create.light_gray_toolbox": "薄灰色の工具箱", - "block.create.light_gray_valve_handle": "薄灰色のバルブハンドル", - "block.create.lime_nixie_tube": "黄緑色のニキシー管", - "block.create.lime_sail": "黄緑色の帆", - "block.create.lime_seat": "黄緑色のシート", - "block.create.lime_toolbox": "黄緑色の工具箱", - "block.create.lime_valve_handle": "黄緑色のバルブハンドル", - "block.create.limestone": "石灰岩", - "block.create.limestone_pillar": "石灰岩の柱", - "block.create.linear_chassis": "リニアシャーシ", - "block.create.lit_blaze_burner": "燃焼中のブレイズバーナー", - "block.create.magenta_nixie_tube": "赤紫色のニキシー管", - "block.create.magenta_sail": "赤紫色の帆", - "block.create.magenta_seat": "赤紫色のシート", - "block.create.magenta_toolbox": "赤紫色の工具箱", - "block.create.magenta_valve_handle": "赤紫色のバルブハンドル", - "block.create.mechanical_arm": "メカニカルアーム", - "block.create.mechanical_bearing": "メカニカルベアリング", - "block.create.mechanical_crafter": "メカニカルクラフター", - "block.create.mechanical_drill": "メカニカルドリル", - "block.create.mechanical_harvester": "メカニカルハーベスター", - "block.create.mechanical_mixer": "メカニカルミキサー", - "block.create.mechanical_piston": "メカニカルピストン", - "block.create.mechanical_piston_head": "メカニカルピストンヘッド", - "block.create.mechanical_plough": "メカニカルプラウ", - "block.create.mechanical_press": "メカニカルプレス", - "block.create.mechanical_pump": "メカニカルポンプ", - "block.create.mechanical_saw": "メカニカルソー", - "block.create.metal_bracket": "金属ブラケット", - "block.create.metal_girder": "鉄骨", - "block.create.metal_girder_encased_shaft": "鉄骨入りシャフト", - "block.create.millstone": "石臼", - "block.create.minecart_anchor": "トロッコアンカー", - "block.create.mysterious_cuckoo_clock": "鳩時計", - "block.create.nixie_tube": "ニキシー管", - "block.create.nozzle": "ノズル", - "block.create.oak_window": "オークの窓", - "block.create.oak_window_pane": "オークの板窓", - "block.create.ochrum": "黄土岩", - "block.create.ochrum_pillar": "黄土岩の柱", - "block.create.orange_sail": "橙色の帆", - "block.create.orange_seat": "橙色のシート", - "block.create.orange_toolbox": "橙色の工具箱", - "block.create.orange_valve_handle": "橙色のバルブハンドル", - "block.create.ornate_iron_window": "鉄の装飾ガラス", - "block.create.ornate_iron_window_pane": "鉄の装飾ガラス板", - "block.create.oxidized_copper_shingle_slab": "酸化した銅の屋根板のハーフブロック", - "block.create.oxidized_copper_shingle_stairs": "酸化した銅の屋根板の階段", - "block.create.oxidized_copper_shingles": "酸化した銅の屋根板", - "block.create.oxidized_copper_tile_slab": "酸化した銅タイルのハーフブロック", - "block.create.oxidized_copper_tile_stairs": "酸化した銅タイルの階段", - "block.create.oxidized_copper_tiles": "酸化した銅タイル", - "block.create.peculiar_bell": "風変わりな鐘", - "block.create.pink_nixie_tube": "桃色のニキシー管", - "block.create.pink_sail": "桃色の帆", - "block.create.pink_seat": "桃色のシート", - "block.create.pink_toolbox": "桃色の工具箱", - "block.create.pink_valve_handle": "桃色のバルブハンドル", - "block.create.piston_extension_pole": "ピストン延長ポール", - "block.create.placard": "プラカード", - "block.create.polished_cut_andesite": "磨かれた安山岩の切石", - "block.create.polished_cut_andesite_slab": "磨かれた安山岩の切石のハーフブロック", - "block.create.polished_cut_andesite_stairs": "磨かれた安山岩の切石の階段", - "block.create.polished_cut_andesite_wall": "磨かれた安山岩の切石の塀", - "block.create.polished_cut_asurine": "磨かれた瑠璃岩の切石", - "block.create.polished_cut_asurine_slab": "磨かれた瑠璃岩の切石のハーフブロック", - "block.create.polished_cut_asurine_stairs": "磨かれた瑠璃岩の切石の階段", - "block.create.polished_cut_asurine_wall": "磨かれた瑠璃岩の切石の塀", - "block.create.polished_cut_calcite": "磨かれた方解石", - "block.create.polished_cut_calcite_slab": "磨かれた方解石のハーフブロック", - "block.create.polished_cut_calcite_stairs": "磨かれた方解石の階段", - "block.create.polished_cut_calcite_wall": "磨かれた方解石の塀", - "block.create.polished_cut_crimsite": "磨かれた真紅岩の切石", - "block.create.polished_cut_crimsite_slab": "磨かれた真紅岩の切石のハーフブロック", - "block.create.polished_cut_crimsite_stairs": "磨かれた真紅岩の切石の階段", - "block.create.polished_cut_crimsite_wall": "磨かれた真紅岩の切石の塀", - "block.create.polished_cut_deepslate": "磨かれた深層岩の切石", - "block.create.polished_cut_deepslate_slab": "磨かれた深層岩の切石のハーフブロック", - "block.create.polished_cut_deepslate_stairs": "磨かれた深層岩の切石の階段", - "block.create.polished_cut_deepslate_wall": "磨かれた深層岩の切石の塀", - "block.create.polished_cut_diorite": "磨かれた閃緑岩の切石", - "block.create.polished_cut_diorite_slab": "磨かれた閃緑岩の切石のハーフブロック", - "block.create.polished_cut_diorite_stairs": "磨かれた閃緑岩の切石の階段", - "block.create.polished_cut_diorite_wall": "磨かれた閃緑岩の切石の塀", - "block.create.polished_cut_dripstone": "磨かれた鍾乳石", - "block.create.polished_cut_dripstone_slab": "磨かれた鍾乳石のハーフブロック", - "block.create.polished_cut_dripstone_stairs": "磨かれた鍾乳石の階段", - "block.create.polished_cut_dripstone_wall": "磨かれた鍾乳石の塀", - "block.create.polished_cut_granite": "磨かれた花崗岩の切石", - "block.create.polished_cut_granite_slab": "磨かれた花崗岩の切石のハーフブロック", - "block.create.polished_cut_granite_stairs": "磨かれた花崗岩の切石の階段", - "block.create.polished_cut_granite_wall": "磨かれた花崗岩の切石の塀", - "block.create.polished_cut_limestone": "磨かれた石灰岩の切石", - "block.create.polished_cut_limestone_slab": "磨かれた石灰岩の切石のハーフブロック", - "block.create.polished_cut_limestone_stairs": "磨かれた石灰岩の切石の階段", - "block.create.polished_cut_limestone_wall": "磨かれた石灰岩の切石の塀", - "block.create.polished_cut_ochrum": "磨かれた黄土岩の切石", - "block.create.polished_cut_ochrum_slab": "磨かれた黄土岩の切石のハーフブロック", - "block.create.polished_cut_ochrum_stairs": "磨かれた黄土岩の切石の階段", - "block.create.polished_cut_ochrum_wall": "磨かれた黄土岩の切石の塀", - "block.create.polished_cut_scorchia": "磨かれたスコーチア", - "block.create.polished_cut_scorchia_slab": "磨かれたスコーチアのハーフブロック", - "block.create.polished_cut_scorchia_stairs": "磨かれたスコーチアの階段", - "block.create.polished_cut_scorchia_wall": "磨かれたスコーチアの塀", - "block.create.polished_cut_scoria": "磨かれたスコリア", - "block.create.polished_cut_scoria_slab": "磨かれたスコリアのハーフブロック", - "block.create.polished_cut_scoria_stairs": "磨かれたスコリアの階段", - "block.create.polished_cut_scoria_wall": "磨かれたスコリアの塀", - "block.create.polished_cut_tuff": "磨かれた凝灰岩の切石", - "block.create.polished_cut_tuff_slab": "磨かれた凝灰岩の切石のハーフブロック", - "block.create.polished_cut_tuff_stairs": "磨かれた凝灰岩の切石の階段", - "block.create.polished_cut_tuff_wall": "磨かれた凝灰岩の切石の塀", - "block.create.polished_cut_veridium": "磨かれた翡翠岩の切石", - "block.create.polished_cut_veridium_slab": "磨かれた翡翠岩の切石のハーフブロック", - "block.create.polished_cut_veridium_stairs": "磨かれた翡翠岩の切石の階段", - "block.create.polished_cut_veridium_wall": "磨かれた翡翠岩の切石の塀", - "block.create.portable_fluid_interface": "ポータブル液体インターフェース", - "block.create.portable_storage_interface": "ポータブルストーレジインターフェース", - "block.create.powered_latch": "パワードラッチ", - "block.create.powered_shaft": "パワードシャフト", - "block.create.powered_toggle_latch": "パワードトグルラッチ", - "block.create.pulley_magnet": "プーリーマグネット", - "block.create.pulse_extender": "パルスエクステンダー", - "block.create.pulse_repeater": "パルスリピーター", - "block.create.purple_nixie_tube": "紫色のニキシー管", - "block.create.purple_sail": "紫色の帆", - "block.create.purple_seat": "紫色のシート", - "block.create.purple_toolbox": "紫色の工具箱", - "block.create.purple_valve_handle": "紫色のバルブハンドル", - "block.create.radial_chassis": "ラジアルシャーシ", - "block.create.railway_casing": "鉄道用ケーシング", - "block.create.raw_zinc_block": "亜鉛の原石ブロック", - "block.create.red_nixie_tube": "赤色のニキシー管", - "block.create.red_sail": "赤色の帆", - "block.create.red_seat": "赤色のシート", - "block.create.red_toolbox": "赤色の工具箱", - "block.create.red_valve_handle": "赤色のバルブハンドル", - "block.create.redstone_contact": "レッドストーンコンタクト", - "block.create.redstone_link": "レッドストーンリンク", - "block.create.refined_radiance_casing": "光輝ケーシング", - "block.create.rope": "ロープ", - "block.create.rope_pulley": "ローププーリー", - "block.create.rose_quartz_block": "ローズクォーツブロック", - "block.create.rose_quartz_lamp": "ローズクォーツランプ", - "block.create.rose_quartz_tiles": "ローズクォーツタイル", - "block.create.rotation_speed_controller": "回転速度コントローラー", - "block.create.sail_frame": "帆フレーム", - "block.create.schematic_table": "概略図台", - "block.create.schematicannon": "概略図砲", - "block.create.scorchia": "スコーチア", - "block.create.scorchia_pillar": "スコーチアの柱", - "block.create.scoria": "スコリア", - "block.create.scoria_pillar": "スコリアの柱", - "block.create.secondary_linear_chassis": "セカンダリリニアシャーシ", - "block.create.sequenced_gearshift": "シーケンスギアシフト", - "block.create.shadow_steel_casing": "シャドウケーシング", - "block.create.shaft": "シャフト", - "block.create.small_andesite_brick_slab": "小さな安山岩レンガのハーフブロック", - "block.create.small_andesite_brick_stairs": "小さな安山岩レンガの階段", - "block.create.small_andesite_brick_wall": "小さな安山岩レンガの塀", - "block.create.small_andesite_bricks": "小さな安山岩レンガ", - "block.create.small_asurine_brick_slab": "小さな瑠璃岩レンガのハーフブロック", - "block.create.small_asurine_brick_stairs": "小さな瑠璃岩レンガの階段", - "block.create.small_asurine_brick_wall": "小さな瑠璃岩レンガの塀", - "block.create.small_asurine_bricks": "小さな瑠璃岩レンガ", - "block.create.small_bogey": "小さな台車", - "block.create.small_calcite_brick_slab": "小さな方解石レンガのハーフブロック", - "block.create.small_calcite_brick_stairs": "小さな方解石レンガの階段", - "block.create.small_calcite_brick_wall": "小さな方解石レンガの塀", - "block.create.small_calcite_bricks": "小さな方解石レンガ", - "block.create.small_crimsite_brick_slab": "小さな真紅岩レンガのハーフブロック", - "block.create.small_crimsite_brick_stairs": "小さな真紅岩レンガの階段", - "block.create.small_crimsite_brick_wall": "小さな真紅岩レンガの塀", - "block.create.small_crimsite_bricks": "小さな真紅岩レンガ", - "block.create.small_deepslate_brick_slab": "小さな深層岩レンガのハーフブロック", - "block.create.small_deepslate_brick_stairs": "小さな深層岩レンガの階段", - "block.create.small_deepslate_brick_wall": "小さな深層岩レンガの塀", - "block.create.small_deepslate_bricks": "小さな深層岩レンガ", - "block.create.small_diorite_brick_slab": "小さな閃緑岩レンガのハーフブロック", - "block.create.small_diorite_brick_stairs": "小さな閃緑岩レンガの階段", - "block.create.small_diorite_brick_wall": "小さな閃緑岩レンガの塀", - "block.create.small_diorite_bricks": "小さな閃緑岩レンガ", - "block.create.small_dripstone_brick_slab": "小さな鍾乳石レンガのハーフブロック", - "block.create.small_dripstone_brick_stairs": "小さな鍾乳石レンガの階段", - "block.create.small_dripstone_brick_wall": "小さな鍾乳石レンガの塀", - "block.create.small_dripstone_bricks": "小さな鍾乳石レンガ", - "block.create.small_granite_brick_slab": "小さな花崗岩レンガのハーフブロック", - "block.create.small_granite_brick_stairs": "小さな花崗岩レンガの階段", - "block.create.small_granite_brick_wall": "小さな花崗岩レンガの塀", - "block.create.small_granite_bricks": "小さな花崗岩レンガ", - "block.create.small_limestone_brick_slab": "小さな石灰岩レンガのハーフブロック", - "block.create.small_limestone_brick_stairs": "小さな石灰岩レンガの階段", - "block.create.small_limestone_brick_wall": "小さな石灰岩レンガの塀", - "block.create.small_limestone_bricks": "小さな石灰岩レンガ", - "block.create.small_ochrum_brick_slab": "小さな黄土岩レンガのハーフブロック", - "block.create.small_ochrum_brick_stairs": "小さな黄土岩レンガの階段", - "block.create.small_ochrum_brick_wall": "小さな黄土岩レンガの塀", - "block.create.small_ochrum_bricks": "小さな黄土岩レンガ", - "block.create.small_rose_quartz_tiles": "小さなローズクォーツタイル", - "block.create.small_scorchia_brick_slab": "小さなスコーチアレンガのハーフブロック", - "block.create.small_scorchia_brick_stairs": "小さなスコーチアレンガの階段", - "block.create.small_scorchia_brick_wall": "小さなスコーチアレンガの塀", - "block.create.small_scorchia_bricks": "小さなスコーチアレンガ", - "block.create.small_scoria_brick_slab": "小さなスコリアレンガのハーフブロック", - "block.create.small_scoria_brick_stairs": "小さなスコリアレンガの階段", - "block.create.small_scoria_brick_wall": "小さなスコリアレンガの塀", - "block.create.small_scoria_bricks": "小さなスコリアレンガ", - "block.create.small_tuff_brick_slab": "小さな凝灰岩レンガのハーフブロック", - "block.create.small_tuff_brick_stairs": "小さな凝灰岩レンガの階段", - "block.create.small_tuff_brick_wall": "小さな凝灰岩レンガの塀", - "block.create.small_tuff_bricks": "小さな凝灰岩レンガ", - "block.create.small_veridium_brick_slab": "小さな翡翠岩レンガのハーフブロック", - "block.create.small_veridium_brick_stairs": "小さな翡翠岩レンガの階段", - "block.create.small_veridium_brick_wall": "小さな翡翠岩レンガの塀", - "block.create.small_veridium_bricks": "小さな翡翠岩レンガ", - "block.create.smart_chute": "スマートシュート", - "block.create.smart_fluid_pipe": "スマート液体パイプ", - "block.create.speedometer": "速度メーター", - "block.create.spout": "アイテム注液口", - "block.create.spruce_window": "マツの窓", - "block.create.spruce_window_pane": "マツの板窓", - "block.create.steam_engine": "蒸気エンジン", - "block.create.steam_whistle": "汽笛", - "block.create.steam_whistle_extension": "延長汽笛", - "block.create.sticker": "スティッカー", - "block.create.sticky_mechanical_piston": "メカニカル粘着ピストン", - "block.create.stockpile_switch": "在庫スイッチ", - "block.create.stressometer": "応力メーター", - "block.create.tiled_glass": "タイルガラス", - "block.create.tiled_glass_pane": "タイルガラス板", - "block.create.track": "鉄道用線路", - "block.create.track_observer": "列車検知装置", - "block.create.track_signal": "鉄道信号機", - "block.create.track_station": "鉄道駅ブロック", - "block.create.train_door": "鉄道用ドア", - "block.create.train_trapdoor": "鉄道用トラップドア", - "block.create.tuff_pillar": "凝灰岩の柱", - "block.create.turntable": "ターンテーブル", - "block.create.veridium": "翡翠岩", - "block.create.veridium_pillar": "翡翠岩の柱", - "block.create.vertical_framed_glass": "縦型ガラス窓", - "block.create.vertical_framed_glass_pane": "縦型ガラス板窓", - "block.create.warped_window": "歪んだ窓", - "block.create.warped_window_pane": "歪んだ板窓", - "block.create.water_wheel": "水車", - "block.create.waxed_copper_shingle_slab": "錆止めされた銅の屋根板のハーフブロック", - "block.create.waxed_copper_shingle_stairs": "錆止めされた銅の屋根板の階段", - "block.create.waxed_copper_shingles": "錆止めされた銅の屋根板", - "block.create.waxed_copper_tile_slab": "錆止めされた銅タイルのハーフブロック", - "block.create.waxed_copper_tile_stairs": "錆止めされた銅タイルの階段", - "block.create.waxed_copper_tiles": "錆止めされた銅タイル", - "block.create.waxed_exposed_copper_shingle_slab": "錆止めされた風化した銅の屋根板のハーフブロック", - "block.create.waxed_exposed_copper_shingle_stairs": "錆止めされた風化した銅の屋根板の階段", - "block.create.waxed_exposed_copper_shingles": "錆止めされた風化した銅の屋根板", - "block.create.waxed_exposed_copper_tile_slab": "錆止めされた風化した銅タイルのハーフブロック", - "block.create.waxed_exposed_copper_tile_stairs": "錆止めされた風化した銅タイルの階段", - "block.create.waxed_exposed_copper_tiles": "錆止めされた風化した銅タイル", - "block.create.waxed_oxidized_copper_shingle_slab": "錆止めされた酸化した銅の屋根板のハーフブロック", - "block.create.waxed_oxidized_copper_shingle_stairs": "錆止めされた酸化した銅の屋根板の階段", - "block.create.waxed_oxidized_copper_shingles": "錆止めされた酸化した銅の屋根板", - "block.create.waxed_oxidized_copper_tile_slab": "錆止めされた酸化した銅タイルのハーフブロック", - "block.create.waxed_oxidized_copper_tile_stairs": "錆止めされた酸化した銅タイルの階段", - "block.create.waxed_oxidized_copper_tiles": "錆止めされた酸化した銅タイル", - "block.create.waxed_weathered_copper_shingle_slab": "錆止めされた錆びた銅の屋根板のハーフブロック", - "block.create.waxed_weathered_copper_shingle_stairs": "錆止めされた錆びた銅の屋根板の階段", - "block.create.waxed_weathered_copper_shingles": "錆止めされた錆びた銅の屋根板", - "block.create.waxed_weathered_copper_tile_slab": "錆止めされた錆びた銅タイルのハーフブロック", - "block.create.waxed_weathered_copper_tile_stairs": "錆止めされた錆びた銅タイルの階段", - "block.create.waxed_weathered_copper_tiles": "錆止めされた錆びた銅タイル", - "block.create.weathered_copper_shingle_slab": "錆びた銅の屋根板のハーフブロック", - "block.create.weathered_copper_shingle_stairs": "錆びた銅の屋根板の階段", - "block.create.weathered_copper_shingles": "錆びた銅の屋根板", - "block.create.weathered_copper_tile_slab": "錆びた銅タイルのハーフブロック", - "block.create.weathered_copper_tile_stairs": "錆びた銅タイルの階段", - "block.create.weathered_copper_tiles": "錆びた銅タイル", - "block.create.weighted_ejector": "重量射出機", - "block.create.white_nixie_tube": "白色のニキシー管", - "block.create.white_sail": "白色の帆", - "block.create.white_seat": "白色のシート", - "block.create.white_toolbox": "白色の工具箱", - "block.create.white_valve_handle": "白色のバルブハンドル", - "block.create.windmill_bearing": "風車ベアリング", - "block.create.wooden_bracket": "木製ブラケット", - "block.create.yellow_nixie_tube": "黄色のニキシー管", - "block.create.yellow_sail": "黄色の帆", - "block.create.yellow_seat": "黄色のシート", - "block.create.yellow_toolbox": "黄色の工具箱", - "block.create.yellow_valve_handle": "黄色のバルブハンドル", - "block.create.zinc_block": "亜鉛ブロック", - "block.create.zinc_ore": "亜鉛鉱石", - - "enchantment.create.capacity": "容量増加", - "enchantment.create.potato_recovery": "ポテト回収", - - "entity.create.carriage_contraption": "鉄道からくり", - "entity.create.contraption": "からくり", - "entity.create.crafting_blueprint": "クラフトブループリント", - "entity.create.gantry_contraption": "ガントリーからくり", - "entity.create.potato_projectile": "ポテト弾", - "entity.create.seat": "シート", - "entity.create.stationary_contraption": "付設からくり", - "entity.create.super_glue": "超粘着剤", - - "fluid.create.potion": "ポーション", - "fluid.create.tea": "建築家のお茶", - - "item.create.andesite_alloy": "安山岩合金", - "item.create.attribute_filter": "属性フィルター", - "item.create.bar_of_chocolate": "チョコレートバー", - "item.create.belt_connector": "メカニカルベルト", - "item.create.blaze_cake": "ブレイズケーキ", - "item.create.blaze_cake_base": "ブレイズケーキの型", - "item.create.brass_hand": "真鍮の手", - "item.create.brass_ingot": "真鍮インゴット", - "item.create.brass_nugget": "真鍮塊", - "item.create.brass_sheet": "真鍮シート", - "item.create.builders_tea": "建築家のお茶", - "item.create.chest_minecart_contraption": "チェスト付きからくりトロッコ", - "item.create.chocolate_bucket": "チョコレート入りバケツ", - "item.create.chocolate_glazed_berries": "チョコレートベリー", - "item.create.chromatic_compound": "色彩の化合物", - "item.create.cinder_flour": "ネザーラックの粉", - "item.create.copper_backtank": "銅のバックタンク", - "item.create.copper_backtank_placeable": "設置可能な銅のバックタンク", - "item.create.copper_nugget": "銅塊", - "item.create.copper_sheet": "銅板", - "item.create.crafter_slot_cover": "クラフタースロットカバー", - "item.create.crafting_blueprint": "クラフトブループリント", - "item.create.creative_blaze_cake": "クリエイティブブレイズケーキ", - "item.create.crushed_aluminum_ore": "砕いたアルミニウム鉱石", - "item.create.crushed_copper_ore": "砕いた銅鉱石", - "item.create.crushed_gold_ore": "砕いた金鉱石", - "item.create.crushed_iron_ore": "砕いた鉄鉱石", - "item.create.crushed_lead_ore": "砕いた鉛鉱石", - "item.create.crushed_nickel_ore": "砕いたニッケル鉱石", - "item.create.crushed_osmium_ore": "砕いたオスミウム鉱石", - "item.create.crushed_platinum_ore": "砕いたプラチナ鉱石", - "item.create.crushed_quicksilver_ore": "砕いた水銀鉱石", - "item.create.crushed_silver_ore": "砕いた銀鉱石", - "item.create.crushed_tin_ore": "砕いた錫鉱石", - "item.create.crushed_uranium_ore": "砕いたウラン鉱石", - "item.create.crushed_zinc_ore": "砕いた亜鉛鉱石", - "item.create.diving_boots": "潜水ブーツ", - "item.create.diving_helmet": "潜水ヘルメット", - "item.create.dough": "生地", - "item.create.electron_tube": "電子管", - "item.create.empty_blaze_burner": "空のブレイズバーナー", - "item.create.empty_schematic": "空の概略図", - "item.create.experience_nugget": "経験値の塊", - "item.create.extendo_grip": "マジックハンド", - "item.create.filter": "フィルター", - "item.create.furnace_minecart_contraption": "かまど付きからくりトロッコ", - "item.create.goggles": "エンジニアのゴーグル", - "item.create.golden_sheet": "金板", - "item.create.handheld_worldshaper": "携帯型ワールドシェーパー", - "item.create.honey_bucket": "ハチミツ入りバケツ", - "item.create.honeyed_apple": "リンゴのハチミツかけ", - "item.create.incomplete_precision_mechanism": "組み立て中の精密機構", - "item.create.incomplete_track": "組み立て中の鉄道用線路", - "item.create.iron_sheet": "鉄板", - "item.create.linked_controller": "リンクコントローラー", - "item.create.minecart_contraption": "からくりトロッコ", - "item.create.minecart_coupling": "トロッコ連結器", - "item.create.polished_rose_quartz": "磨かれたローズクォーツ", - "item.create.potato_cannon": "ポテトキャノン", - "item.create.powdered_obsidian": "黒曜石の粉", - "item.create.precision_mechanism": "精密機構", - "item.create.propeller": "プロペラ", - "item.create.raw_zinc": "亜鉛の原石", - "item.create.red_sand_paper": "赤い紙やすり", - "item.create.refined_radiance": "高貴な光輝", - "item.create.rose_quartz": "ローズクォーツ", - "item.create.sand_paper": "紙やすり", - "item.create.schedule": "鉄道時刻表", - "item.create.schematic": "概略図", - "item.create.schematic_and_quill": "概略図と羽根ペン", - "item.create.shadow_steel": "シャドウスチール", - "item.create.sturdy_sheet": "頑丈な板", - "item.create.super_glue": "超粘着剤", - "item.create.sweet_roll": "スイートロール", - "item.create.tree_fertilizer": "樹木の肥料", - "item.create.unprocessed_obsidian_sheet": "未処理の黒曜石板", - "item.create.vertical_gearbox": "垂直ギアボックス", - "item.create.wand_of_symmetry": "対称の杖", - "item.create.wheat_flour": "小麦粉", - "item.create.whisk": "泡立て器", - "item.create.wrench": "レンチ", - "item.create.zinc_ingot": "亜鉛インゴット", - "item.create.zinc_nugget": "亜鉛塊", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Createへようこそ", - "advancement.create.root.desc": "素晴らしいからくり仕掛け作りの時間だ!", - "advancement.create.andesite_alloy": "頑丈な岩", - "advancement.create.andesite_alloy.desc": "Createで最も重要な素材、安山岩合金を手に入れる。", - "advancement.create.andesite_casing": "安山岩の時代", - "advancement.create.andesite_casing.desc": "安山岩合金を木材に使って、基本の機械のケーシングを作る", - "advancement.create.mechanical_press": "ドン!", - "advancement.create.mechanical_press.desc": "メカニカルプレスで板を作る", - "advancement.create.encased_fan": "風のタクト", - "advancement.create.encased_fan.desc": "ケース入りファンを設置して稼働させる", - "advancement.create.fan_processing": "パーティクル加工", - "advancement.create.fan_processing.desc": "ケース入りファンを使って素材を加工する", - "advancement.create.saw_processing": "工房で最も恐ろしい", - "advancement.create.saw_processing.desc": "メカニカルソーを上向きに置いて素材を加工する", - "advancement.create.compacting": "小型化", - "advancement.create.compacting.desc": "プレスと鉢でより少ないアイテムからよりたくさんのアイテムを作る", - "advancement.create.belt": "ベルトコンブア", - "advancement.create.belt.desc": "2つのシャフトをメカニカルベルトで繋ぐ", - "advancement.create.funnel": "空港の美学", - "advancement.create.funnel.desc": "ファンネルで収納ブロックからアイテムを入出力する", - "advancement.create.chute": "垂直輸送", - "advancement.create.chute.desc": "メカニカルベルトの垂直バージョン、シュートを設置する", - "advancement.create.mechanical_mixer": "めちゃくちゃにしてやる", - "advancement.create.mechanical_mixer.desc": "材料をメカニカルミキサーで混ぜる", - "advancement.create.burner": "生きてる暖炉", - "advancement.create.burner.desc": "ブレイズバーナーを入手する", - "advancement.create.water_wheel": "水力を使おう", - "advancement.create.water_wheel.desc": "水車を置いて、回転させる", - "advancement.create.windmill": "そよ風", - "advancement.create.windmill.desc": "風車を組み立てて、回転させる", - "advancement.create.shifting_gears": "ギアシフト", - "advancement.create.shifting_gears.desc": "大きい歯車と小さい歯車を噛み合わせれば、回転速度を変えられる", - "advancement.create.millstone": "身を粉にして働く", - "advancement.create.millstone.desc": "石臼を置いて、素材をすり潰す", - "advancement.create.super_glue": "領域展開", - "advancement.create.super_glue.desc": "複数のブロックをまとめて接着する", - "advancement.create.contraption_actors": "動きの使い方", - "advancement.create.contraption_actors.desc": "ドリルか、ソー、ハーベスターのいずれかがついたからくりを作る", - "advancement.create.portable_storage_interface": "ドライブスルー", - "advancement.create.portable_storage_interface.desc": "ポータブルストレージインターフェースでからくりからアイテムを搬出入する", - "advancement.create.wrench_goggles": "装備支給", - "advancement.create.wrench_goggles.desc": "エンジニアのゴーグルとレンチを装備する", - "advancement.create.stressometer": "必要な応力は?", - "advancement.create.stressometer.desc": "動作中の応力メーターをゴーグルを通して見て、正確な値を読み取る", - "advancement.create.cuckoo_clock": "今何時?", - "advancement.create.cuckoo_clock.desc": "鳩時計が就寝の時間を告げるのを目撃する", - "advancement.create.windmill_maxed": "雄風", - "advancement.create.windmill_maxed.desc": "最強の風車を組み立てる", - "advancement.create.ejector_maxed": "飛び込みチャンピオン", - "advancement.create.ejector_maxed.desc": "重量射出機で30ブロック以上飛ぶ", - "advancement.create.pulley_maxed": "ロープは続くよどこまでも", - "advancement.create.pulley_maxed.desc": "ローププーリーを200ブロック以上伸ばす", - "advancement.create.cart_pickup": "力ずく", - "advancement.create.cart_pickup.desc": "200ブロック以上が取り付けられたからくりトロッコを回収する", - "advancement.create.anvil_plough": "鍛冶屋の大砲", - "advancement.create.anvil_plough.desc": "メカニカルプラウで金床を打ち上げる", - "advancement.create.lava_wheel_00000": "マグマ車", - "advancement.create.lava_wheel_00000.desc": "こんなの動くべきじゃない§7\n(隠し進捗)", - "advancement.create.hand_crank_000": "トレーニングの時間", - "advancement.create.hand_crank_000.desc": "疲れ果て、完全に空腹になるまでハンドクランクを回す§7\n(隠し進捗)", - "advancement.create.belt_funnel_kiss": "コウノトリの羽ばたき", - "advancement.create.belt_funnel_kiss.desc": "2つのベルトに載せたファンネルにキスをさせる", - "advancement.create.stressometer_maxed": "無駄のない動き", - "advancement.create.stressometer_maxed.desc": "応力メーターがちょうど100%を指すのを読み取る§7\n(隠し進捗)", - "advancement.create.copper": "もっと頑丈な岩", - "advancement.create.copper.desc": "液体を取り扱うために、銅を貯めておく", - "advancement.create.copper_casing": "銅の時代", - "advancement.create.copper_casing.desc": "銅のインゴットを木材に使って防水の機械のケーシングを作る", - "advancement.create.spout": "ぱしゃぱしゃ", - "advancement.create.spout.desc": "アイテム注液口が液体を充填している様子を見る", - "advancement.create.drain": "回転式排液機", - "advancement.create.drain.desc": "液体が入ったアイテムがアイテム排液口によって空になる様子を見る", - "advancement.create.steam_engine": "発電所", - "advancement.create.steam_engine.desc": "蒸気エンジンでトルクを生み出す", - "advancement.create.steam_whistle": "天使の歌声", - "advancement.create.steam_whistle.desc": "汽笛を稼働させる", - "advancement.create.backtank": "圧力、お持ち帰りで!", - "advancement.create.backtank.desc": "銅のバックタンクを作り、圧縮空気を溜める", - "advancement.create.diving_suit": "深海に潜る準備", - "advancement.create.diving_suit.desc": "銅のバックタンクと潜水ヘルメットを装備し、水に飛び込む", - "advancement.create.mechanical_pump_0": "圧をかける", - "advancement.create.mechanical_pump_0.desc": "メカニカルポンプを設置して、稼働させる", - "advancement.create.glass_pipe": "フロウ・スパイ", - "advancement.create.glass_pipe.desc": "液体が入ったパイプにレンチを使う", - "advancement.create.water_supply": "水たまり収集機", - "advancement.create.water_supply.desc": "パイプまたはポンプの端から、水を吸い込む", - "advancement.create.hose_pulley": "工業排水", - "advancement.create.hose_pulley.desc": "ホースプーリーを下げて、液体の放出や吸引を見る", - "advancement.create.chocolate_bucket": "空想世界", - "advancement.create.chocolate_bucket.desc": "溶けたチョコレート入りバケツを手に入れる", - "advancement.create.honey_drain": "自動養蜂", - "advancement.create.honey_drain.desc": "パイプで養蜂箱やハチの巣からハチミツを吸う", - "advancement.create.hose_pulley_lava": "地球の蛇口", - "advancement.create.hose_pulley_lava.desc": "無限と言えるほどに広い溶岩湖から溶岩を汲み上げる", - "advancement.create.steam_engine_maxed": "全速前進だ!", - "advancement.create.steam_engine_maxed.desc": "ボイラーを最大レベルで稼働させる", - "advancement.create.foods": "バランスのとれたおやつ", - "advancement.create.foods.desc": "チョコレートベリー、リンゴのハチミツかけ、スイートロールを全て同じ注液口で作る", - "advancement.create.diving_suit_lava": "ストライダーと泳ごう", - "advancement.create.diving_suit_lava.desc": "銅の潜水具と共にマグマダイブしてみる§7\n(隠し進捗)", - "advancement.create.chained_drain": "うまく回ってます", - "advancement.create.chained_drain.desc": "並んだアイテム排液口の上をアイテムが通るのを見る§7\n(隠し進捗)", - "advancement.create.cross_streams": "液体を交差させるな!", - "advancement.create.cross_streams.desc": "液体ネットワークの中で2種類の液体が出会う様子を見る§7\n(隠し進捗)", - "advancement.create.pipe_organ": "パイプオルガン", - "advancement.create.pipe_organ.desc": "音程の違う12個の汽笛を1つの液体タンクに設置する§7\n(隠し進捗)", - "advancement.create.brass": "本物の合金", - "advancement.create.brass.desc": "銅と亜鉛のインゴットをブレイズ付きミキサーを使って真鍮を作る", - "advancement.create.brass_casing": "真鍮の時代", - "advancement.create.brass_casing.desc": "真鍮のインゴットを木材に使って、高度な機械のケーシングを作る。", - "advancement.create.rose_quartz": "ピンク色のダイヤモンド", - "advancement.create.rose_quartz.desc": "ローズクォーツを磨く", - "advancement.create.deployer": "人工知能", - "advancement.create.deployer.desc": "自分の手と全く同じ動きをするデプロイヤーを設置して、稼働させる", - "advancement.create.precision_mechanism": "手間暇かけた骨董品", - "advancement.create.precision_mechanism.desc": "精密機構を組み立てる", - "advancement.create.speed_controller": "もう全部あいつ1人でいいんじゃないかな", - "advancement.create.speed_controller.desc": "回転速度コントローラーでからくりを微調整する", - "advancement.create.mechanical_arm": "手が離せない!", - "advancement.create.mechanical_arm.desc": "メカニカルアームがはじめてアイテムを運ぶ様子を見る", - "advancement.create.mechanical_crafter": "自動組み立て", - "advancement.create.mechanical_crafter.desc": "メカニカルクラフターをいくつか置き、動力を供給する", - "advancement.create.crushing_wheel": "巨大な一対", - "advancement.create.crushing_wheel.desc": "一組の破砕ホイールを設置して稼働させる", - "advancement.create.haunted_bell": "シャドーセンス", - "advancement.create.haunted_bell.desc": "憑りつかれた鐘を鳴らす", - "advancement.create.clockwork_bearing": "時計仕掛け", - "advancement.create.clockwork_bearing.desc": "時計仕掛けのベアリングでからくりを組み立てる", - "advancement.create.display_link": "ビッグデータ", - "advancement.create.display_link.desc": "ディスプレイリンクで情報を視覚化する", - "advancement.create.potato_cannon": "バキューン!", - "advancement.create.potato_cannon.desc": "ポテトキャノンで敵を倒す", - "advancement.create.extendo_grip": "ビヨヨーン!", - "advancement.create.extendo_grip.desc": "マジックハンドを手に入れる", - "advancement.create.linked_controller": "遠隔操作", - "advancement.create.linked_controller.desc": "リンクコントローラーから送信した信号をレッドストーンリンクに受信させる", - "advancement.create.arm_blaze_burner": "燃料補給マシーン", - "advancement.create.arm_blaze_burner.desc": "メカニカルアームにブレイズバーナーの燃料補給をさせる", - "advancement.create.crusher_maxed_0000": "破砕の勢い", - "advancement.create.crusher_maxed_0000.desc": "破砕ホイールを最高速度で稼働させる", - "advancement.create.arm_many_targets": "整理整頓マシーン", - "advancement.create.arm_many_targets.desc": "メカニカルアームに10ヶ所以上、搬出先を設定する", - "advancement.create.potato_cannon_collide": "野菜花火", - "advancement.create.potato_cannon_collide.desc": "違う種類のポテトキャノンの弾同士をぶつける", - "advancement.create.self_deploying": "自動運転トロッコ", - "advancement.create.self_deploying.desc": "自分の前に線路を置くからくりトロッコを作る", - "advancement.create.fist_bump": "グータッチだ、兄弟!", - "advancement.create.fist_bump.desc": "2つのデプロイヤーにグータッチさせる§7\n(隠し進捗)", - "advancement.create.crafter_lazy_000": "苦肉の策", - "advancement.create.crafter_lazy_000.desc": "メカニカルクラフターを極端に遅く稼働させ、インフラ整備を先延ばしにする§7\n(隠し進捗)", - "advancement.create.extendo_grip_dual": "脱法リーチ", - "advancement.create.extendo_grip_dual.desc": "二刀流のマジックハンドで超人的なリーチを手に入れる§7\n(隠し進捗)", - "advancement.create.musical_arm": "DJ メカニコ", - "advancement.create.musical_arm.desc": "メカニカルアームがジュークボックスを使う様子を見る§7\n(隠し進捗)", - "advancement.create.sturdy_sheet": "もっとも頑丈な岩", - "advancement.create.sturdy_sheet.desc": "黒曜石の粉を精製して頑丈な板を組み立てる", - "advancement.create.train_casing_00": "大交通時代", - "advancement.create.train_casing_00.desc": "頑丈な板をつかって鉄道用のケーシングを作る", - "advancement.create.train": "出発進行!", - "advancement.create.train.desc": "最初の列車を作る", - "advancement.create.conductor": "人材育成", - "advancement.create.conductor.desc": "時刻表で運転手に指示する", - "advancement.create.track_signal": "運行管理", - "advancement.create.track_signal.desc": "鉄道信号機を設置する", - "advancement.create.display_board_0": "ダイナミックな時刻表", - "advancement.create.display_board_0.desc": " ディスプレイリンクを使って、ディスプレイボードに列車の到着時間を表示させる", - "advancement.create.track_0": "新型ゲージ", - "advancement.create.track_0.desc": "鉄道用線路を手に入れる", - "advancement.create.train_whistle": "ポッポー!", - "advancement.create.train_whistle.desc": "汽笛を列車に組み込み、運転中に鳴らす", - "advancement.create.train_portal": "異次元通勤", - "advancement.create.train_portal.desc": "ネザーポータルを列車で通過する", - "advancement.create.track_crafting_factory": "線路工場", - "advancement.create.track_crafting_factory.desc": "同じメカニカルプレスで1000個以上の鉄道用線路を作る", - "advancement.create.long_bend": "超しなやか", - "advancement.create.long_bend.desc": "30ブロック以上の長さに曲がった線路を作る", - "advancement.create.long_train": "意欲的な取り組み", - "advancement.create.long_train.desc": "6両以上の編成で列車を作る", - "advancement.create.long_travel": "修学旅行", - "advancement.create.long_travel.desc": "列車で5000ブロック以上移動し、シートから降りる", - "advancement.create.train_roadkill": "轢き殺し", - "advancement.create.train_roadkill.desc": "列車で敵を轢く§7\n(隠し進捗)", - "advancement.create.red_signal": "運転の達人", - "advancement.create.red_signal.desc": "列車で赤信号を走る§7\n(隠し進捗)", - "advancement.create.train_crash": "ひどいおもてなし", - "advancement.create.train_crash.desc": "乗客として列車事故に遭遇する§7\n(隠し進捗)", - "advancement.create.train_crash_backwards": "盲点", - "advancement.create.train_crash_backwards.desc": "後ろ向きに走っている途中に他の列車と追突する§7\n(隠し進捗)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create's 建築ブロック", - - "death.attack.create.crush": "%1$sは破砕ホイールによって処理された", - "death.attack.create.crush.player": "%1$sは%2$sに破砕ホイールに投入された", - "death.attack.create.fan_fire": "%1$sはケース入りファンによって燻製にされた", - "death.attack.create.fan_fire.player": "%1$sは%2$sによって燻製にされた", - "death.attack.create.fan_lava": "%1$sはケース入りファンで精錬された", - "death.attack.create.fan_lava.player": "%1$sは%2$sによって熱風に投げ込まれた", - "death.attack.create.mechanical_drill": "%1$sはメカニカルドリルに突き抜かれた", - "death.attack.create.mechanical_drill.player": "%1$sは%2$sにドリルの目の前に投げ込まれた", - "death.attack.create.mechanical_saw": "%1$sはメカニカルソーで半分にカットされた", - "death.attack.create.mechanical_saw.player": "%1$sは%2$sによってメカニカルソーの回転する刃に投げ込まれた", - "death.attack.create.potato_cannon": "%1$sは%2$sのポテトキャノンに撃ち抜かれた", - "death.attack.create.potato_cannon.item": "%1$sは%2$sの%3$sに撃ち抜かれた", - "death.attack.create.cuckoo_clock_explosion": "%1$sは改造された鳩時計に爆破された", - "death.attack.create.cuckoo_clock_explosion.player": "%1$sは改造された鳩時計に爆破された", - "death.attack.create.run_over": "%1$sは%2$sに轢き殺された", - - "create.block.deployer.damage_source_name": "悪いデプロイヤー", - "create.block.cart_assembler.invalid": "トロッコアセンブラはレールの上にのみ設置できます", - - "create.menu.return": "メニューに戻る", - "create.menu.configure": "設定...", - "create.menu.ponder_index": "思案目次", - "create.menu.only_ingame": "一時停止メニューで利用可能", - "create.menu.report_bugs": "バグ報告", - "create.menu.support": "私たちを応援する", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "粉砕", - "create.recipe.milling": "製粉", - "create.recipe.fan_washing": "一括洗浄", - "create.recipe.fan_washing.fan": "水の奥のケース入りファン", - "create.recipe.fan_smoking": "一括燻製", - "create.recipe.fan_smoking.fan": "炎の奥のケース入りファン", - "create.recipe.fan_haunting": "一括憑霊", - "create.recipe.fan_haunting.fan": "魂の炎の奥のケース入りファン", - "create.recipe.fan_blasting": "一括精錬", - "create.recipe.fan_blasting.fan": "溶岩の奥のケース入りファン", - "create.recipe.pressing": "プレス", - "create.recipe.mixing": "混合", - "create.recipe.deploying": "使用", - "create.recipe.automatic_shapeless": "自動不定形クラフト", - "create.recipe.automatic_brewing": "自動醸造", - "create.recipe.packing": "圧縮", - "create.recipe.automatic_packing": "自動圧縮クラフト", - "create.recipe.sawing": "製材", - "create.recipe.mechanical_crafting": "メカニカルクラフト", - "create.recipe.automatic_shaped": "自動定形クラフト", - "create.recipe.block_cutting": "自動石切", - "create.recipe.wood_cutting": "自動製材", - "create.recipe.sandpaper_polishing": "紙やすりによる研磨", - "create.recipe.mystery_conversion": "不思議な変転", - "create.recipe.spout_filling": "アイテムへの注液", - "create.recipe.draining": "アイテムからの排液", - "create.recipe.item_application": "手動によるアイテム使用", - "create.recipe.item_application.any_axe": "任意の斧", - "create.recipe.sequenced_assembly": "組立ライン", - "create.recipe.assembly.next": "次の工程: %1$s", - "create.recipe.assembly.step": "手順: %1$s:", - "create.recipe.assembly.progress": "進捗: %1$s/%2$s", - "create.recipe.assembly.pressing": "プレスする", - "create.recipe.assembly.spout_filling_fluid": "%1$sを注液", - "create.recipe.assembly.deploying_item": "%1$sを組み込む", - "create.recipe.assembly.cutting": "ソーによる切断", - "create.recipe.assembly.repeat": "%1$s回繰り返す", - "create.recipe.assembly.junk": "ランダムな仕損品", - "create.recipe.processing.chance": "%1$s%%チャンス", - "create.recipe.deploying.not_consumed": "消費されない", - "create.recipe.heat_requirement.none": "加熱不要", - "create.recipe.heat_requirement.heated": "加熱が必要", - "create.recipe.heat_requirement.superheated": "極度の加熱が必要", - - "create.generic.range": "範囲", - "create.generic.radius": "半径", - "create.generic.width": "幅", - "create.generic.height": "高さ", - "create.generic.length": "長さ", - "create.generic.speed": "回転速度", - "create.generic.delay": "遅延", - "create.generic.duration": "時間", - "create.generic.timeUnit": "単位", - "create.generic.unit.ticks": "ティック", - "create.generic.unit.seconds": "秒", - "create.generic.unit.minutes": "分", - "create.generic.daytime.hour": "時間", - "create.generic.daytime.minute": "分", - "create.generic.daytime.second": "秒", - "create.generic.daytime.pm": "午後", - "create.generic.daytime.am": "午前", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "度", - "create.generic.unit.millibuckets": "mB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "時計回り", - "create.generic.counter_clockwise": "反時計回り", - "create.generic.in_quotes": "「%1$s」", - "create.generic.pitch": "音程: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "スクロール", - "create.action.confirm": "確認", - "create.action.abort": "中止", - "create.action.saveToFile": "保存", - "create.action.discard": "捨てる", - - "create.keyinfo.toolmenu": "ツールメニューをフォーカスする", - "create.keyinfo.toolbelt": "近くの工具箱にアクセス", - "create.keyinfo.scrollup": "マウスホイールアップをシミュレート(この世界で)", - "create.keyinfo.scrolldown": "マウスホイールダウンをシミュレーション(この世界で)", - - "create.gui.scrollInput.defaultTitle": "オプションを選択:", - "create.gui.scrollInput.scrollToModify": "スクロールして変更", - "create.gui.scrollInput.scrollToAdjustAmount": "スクロールして調整", - "create.gui.scrollInput.scrollToSelect": "スクロールして選択", - "create.gui.scrollInput.shiftScrollsFaster": "シフトを押してスクロールを加速", - "create.gui.toolmenu.focusKey": "[%1$s] 長押しでフォーカスする", - "create.gui.toolmenu.cycle": "[スクロール] で循環", - - "create.toolbox.unequip": "装備解除: %1$s", - "create.toolbox.outOfRange": "範囲内に工具箱がありません", - "create.toolbox.detach": "アイテムの追跡をやめて所持する", - "create.toolbox.depositAll": "近くの工具箱にアイテムを戻す", - "create.toolbox.depositBox": "工具箱にアイテムを戻す", - - "create.gui.symmetryWand.mirrorType": "ミラーの種類", - "create.gui.symmetryWand.orientation": "方向", - - "create.symmetry.mirror.plane": "線対称", - "create.symmetry.mirror.doublePlane": "長方形", - "create.symmetry.mirror.triplePlane": "八角形", - - "create.orientation.orthogonal": "直交", - "create.orientation.diagonal": "対角線", - "create.orientation.horizontal": "横型", - "create.orientation.alongZ": "Z軸に沿る", - "create.orientation.alongX": "X軸に沿る", - - "create.gui.terrainzapper.title": "携帯型ブロックザッパー", - "create.gui.terrainzapper.searchDiagonal": "対角線にフォロー", - "create.gui.terrainzapper.searchFuzzy": "素材の境界を無視", - "create.gui.terrainzapper.patternSection": "模様", - "create.gui.terrainzapper.pattern.solid": "敷き詰め", - "create.gui.terrainzapper.pattern.checkered": "市松模様", - "create.gui.terrainzapper.pattern.inversecheckered": "市松模様(反転)", - "create.gui.terrainzapper.pattern.chance25": "25%", - "create.gui.terrainzapper.pattern.chance50": "50%", - "create.gui.terrainzapper.pattern.chance75": "75%", - "create.gui.terrainzapper.placement": "配置", - "create.gui.terrainzapper.placement.merged": "合併", - "create.gui.terrainzapper.placement.attached": "添える", - "create.gui.terrainzapper.placement.inserted": "挿入", - "create.gui.terrainzapper.brush": "ブラシ", - "create.gui.terrainzapper.brush.cuboid": "直方体", - "create.gui.terrainzapper.brush.sphere": "球体", - "create.gui.terrainzapper.brush.cylinder": "円筒", - "create.gui.terrainzapper.brush.surface": "表面", - "create.gui.terrainzapper.brush.cluster": "鉱石", - "create.gui.terrainzapper.tool": "ツール", - "create.gui.terrainzapper.tool.fill": "埋立", - "create.gui.terrainzapper.tool.place": "設置", - "create.gui.terrainzapper.tool.replace": "置換", - "create.gui.terrainzapper.tool.clear": "削除", - "create.gui.terrainzapper.tool.overlay": "被せる", - "create.gui.terrainzapper.tool.flatten": "なだらかに", - - "create.terrainzapper.shiftRightClickToSet": "シフト-右クリックで形状を選択", - "create.terrainzapper.usingBlock": "使用中: %1$s", - "create.terrainzapper.leftClickToSet": "ブロックをスニークせず右クリックでブロックを選択", - - "create.minecart_coupling.two_couplings_max": "トロッコを2つ以上連結させることはできません", - "create.minecart_coupling.unloaded": "列車の一部があるチャンクがロードされていません", - "create.minecart_coupling.no_loops": "ループ状に連結させることはできません", - "create.minecart_coupling.removed": "トロッコの連結をすべて解除しました", - "create.minecart_coupling.too_far": "トロッコ同士が離れすぎています", - - "create.contraptions.movement_mode": "移動モード", - "create.contraptions.movement_mode.move_place": "停止時に常に設置", - "create.contraptions.movement_mode.move_place_returned": "開始位置のみに設置", - "create.contraptions.movement_mode.move_never_place": "アンカーが破壊されたときにのみ設置", - "create.contraptions.movement_mode.rotate_place": "停止時に常に設置", - "create.contraptions.movement_mode.rotate_place_returned": "初期角度付近のみ設置", - "create.contraptions.movement_mode.rotate_never_place": "アンカーが破壊されたときにのみ設置", - "create.contraptions.cart_movement_mode": "トロッコ移動モード", - "create.contraptions.cart_movement_mode.rotate": "常に動いている方向を向く", - "create.contraptions.cart_movement_mode.rotate_paused": "回転中に機械を一時停止する", - "create.contraptions.cart_movement_mode.rotation_locked": "常に向きを固定する", - "create.contraptions.windmill.rotation_direction": "回転方向", - "create.contraptions.clockwork.clock_hands": "時計の針", - "create.contraptions.clockwork.hour_first": "時針を最初に", - "create.contraptions.clockwork.minute_first": "分針を最初に", - "create.contraptions.clockwork.hour_first_24": "24時針を最初に", - - "create.logistics.filter": "フィルター", - "create.logistics.recipe_filter": "レシピフィルター", - "create.logistics.fluid_filter": "液体フィルター", - "create.logistics.firstFrequency": "一次周波数", - "create.logistics.secondFrequency": "二次周波数", - "create.logistics.filter.apply": "フィルターを%1$sに適用しました。", - "create.logistics.filter.apply_click_again": "フィルターを%1$sに適用しました。再度クリックすると数量をコピーします", - "create.logistics.filter.apply_count": "搬出入数をフィルターに適用しました。", - - "create.gui.goggles.generator_stats": "原動機の統計:", - "create.gui.goggles.kinetic_stats": "動力の統計:", - "create.gui.goggles.at_current_speed": "現在の回転速度で", - "create.gui.goggles.pole_length": "ポールの長さ:", - "create.gui.goggles.fluid_container": "液体コンテナの情報:", - "create.gui.goggles.fluid_container.capacity": "容量: ", - "create.gui.assembly.exception": "このからくりは組み立てることができません。:", - "create.gui.assembly.exception.unmovableBlock": "移動できないブロック(%4$s)、[%1$s %2$s %3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "[%1$s %2$s %3$s] のブロックがロードされているチャンクにありません。", - "create.gui.assembly.exception.structureTooLarge": "からくりに含まれるブロックが多すぎます。\n最大値: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "このピストンに取り付けられているピストン延長ポールが多すぎます。\n最大値: %1$s", - "create.gui.assembly.exception.noPistonPoles": "ピストンにピストン延長ポールがありません。", - "create.gui.assembly.exception.not_enough_sails": "このからくりは帆ブロックが足りていません。: %1$s\nが最低でも%2$s個必要です。", - "create.gui.gauge.info_header": "メーターの情報:", - "create.gui.speedometer.title": "回転速度", - "create.gui.stressometer.title": "ネットワークの応力", - "create.gui.stressometer.capacity": "残りの許容応力", - "create.gui.stressometer.overstressed": "応力超過", - "create.gui.stressometer.no_rotation": "回転なし", - "create.gui.contraptions.not_fast_enough": "この %1$s は_十分速く回転していない_ようです。", - "create.gui.contraptions.network_overstressed": "この機構は_応力超過_のようです。さらに原動機を追加するか、_応力_への影響が大きい機械の回転速度を_下げて_ください。", - "create.gui.adjustable_crate.title": "可変クレート", - "create.gui.adjustable_crate.storageSpace": "収納スペース", - "create.gui.stockpile_switch.title": "在庫スイッチ", - "create.gui.stockpile_switch.invert_signal": "信号を反転", - "create.gui.stockpile_switch.move_to_lower_at": "動作の下限は%1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "動作の上限は%1$s%%", - "create.gui.sequenced_gearshift.title": "シーケンスギアシフト", - "create.gui.sequenced_gearshift.instruction": "命令", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "回す角度", - "create.gui.sequenced_gearshift.instruction.turn_angle": "回転", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "角度分だけ回す", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "ピストン/プーリー/ガントリーを回す", - "create.gui.sequenced_gearshift.instruction.turn_distance": "ピストン", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "距離", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "一定時間待つ", - "create.gui.sequenced_gearshift.instruction.delay": "遅延", - "create.gui.sequenced_gearshift.instruction.delay.duration": "待機時間", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "終了", - "create.gui.sequenced_gearshift.instruction.end": "終了", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "レッドストーンパルスを待つ", - "create.gui.sequenced_gearshift.instruction.await": "待機", - "create.gui.sequenced_gearshift.speed": "回転速度, 方向", - "create.gui.sequenced_gearshift.speed.forward": "入力速度, 正転", - "create.gui.sequenced_gearshift.speed.forward_fast": "倍速, 正転", - "create.gui.sequenced_gearshift.speed.back": "入力速度, 反転", - "create.gui.sequenced_gearshift.speed.back_fast": "倍速, 反転", - - "create.schematicAndQuill.dimensions": "概略図サイズ: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "最初の位置セット", - "create.schematicAndQuill.secondPos": "2番目の位置セット", - "create.schematicAndQuill.noTarget": "[Ctrl] を押したままで空気ブロックを選択します", - "create.schematicAndQuill.abort": "選択を削除しました", - "create.schematicAndQuill.title": "概略図名:", - "create.schematicAndQuill.convert": "保存してすぐに適用", - "create.schematicAndQuill.fallbackName": "My Schematic", - "create.schematicAndQuill.saved": "%1$s として保存しました", - - "create.schematic.invalid": "[!] 無効なアイテム-代わりに概略図台を使ってください", - "create.schematic.position": "位置", - "create.schematic.rotation": "回転", - "create.schematic.rotation.none": "無し", - "create.schematic.rotation.cw90": "時計回りに90", - "create.schematic.rotation.cw180": "時計回りに180", - "create.schematic.rotation.cw270": "時計回りに270", - "create.schematic.mirror": "ミラー", - "create.schematic.mirror.none": "無し", - "create.schematic.mirror.frontBack": "正面-背面", - "create.schematic.mirror.leftRight": "左-右", - "create.schematic.tool.deploy": "配置する", - "create.schematic.tool.move": "XZを移動", - "create.schematic.tool.movey": "Yを移動", - "create.schematic.tool.rotate": "回転", - "create.schematic.tool.print": "印刷", - "create.schematic.tool.flip": "裏返し", - "create.schematic.tool.deploy.description.0": "概略図を特定の場所に移動します", - "create.schematic.tool.deploy.description.1": "地面を右クリックして配置します", - "create.schematic.tool.deploy.description.2": "[Ctrl] を押したまま、一定の距離で選択します", - "create.schematic.tool.deploy.description.3": "[Ctrl]-スクロールして距離を変更します", - "create.schematic.tool.move.description.0": "概略図を水平に動かします", - "create.schematic.tool.move.description.1": "概略図を向け、 [Ctrl]-スクロールして押し出します", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "概略図を垂直に動かします", - "create.schematic.tool.movey.description.1": "[Ctrl]-スクロールして上下に移動します", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "概略図を中心に回転させます", - "create.schematic.tool.rotate.description.1": "[Ctrl]-スクロールして90度回転します", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "構造物を即座にワールドに配置します", - "create.schematic.tool.print.description.1": "[右クリック] して、現在の場所への配置を確認します", - "create.schematic.tool.print.description.2": "このツールはクリエイティブモード専用です", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "選択した面に沿って概略図を反転します", - "create.schematic.tool.flip.description.1": "概略図をポイントし、 [Ctrl]-スクロールして反転します", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "同期しています...", - "create.schematics.uploadTooLarge": "概略図が大きすぎます", - "create.schematics.maxAllowedSize": "最大許容概略図ファイルサイズ: ", - - "create.gui.schematicTable.refresh": "ファイルを更新する", - "create.gui.schematicTable.open_folder": "フォルダを開く", - "create.gui.schematicTable.title": "概略図台", - "create.gui.schematicTable.availableSchematics": "利用可能な概略図", - "create.gui.schematicTable.noSchematics": "保存された概略図はありません", - "create.gui.schematicTable.uploading": "アップロードしています...", - "create.gui.schematicTable.finished": "アップロードが完了しました!", - "create.gui.schematicannon.title": "概略図砲", - "create.gui.schematicannon.listPrinter": "材料リスト印刷機", - "create.gui.schematicannon.gunpowderLevel": "火薬残量: %1$s%%", - "create.gui.schematicannon.shotsRemaining": "残りショット数: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "予備: %1$s", - "create.gui.schematicannon.optionEnabled": "現在 有効", - "create.gui.schematicannon.optionDisabled": "現在 無効", - "create.gui.schematicannon.showOptions": "プリンターの設定を表示する", - "create.gui.schematicannon.option.dontReplaceSolid": "固体ブロックを置き換えない", - "create.gui.schematicannon.option.replaceWithSolid": "固体ブロックを固体ブロックに置き換える", - "create.gui.schematicannon.option.replaceWithAny": "固体ブロックを任意のブロックに置き換える", - "create.gui.schematicannon.option.replaceWithEmpty": "固体ブロックを空気に置き換える", - "create.gui.schematicannon.option.skipMissing": "不足しているブロックをスキップ", - "create.gui.schematicannon.option.skipTileEntities": "タイルエンティティを保護する", - "create.gui.schematicannon.slot.gunpowder": "火薬を燃料として概略図砲に入れてください。", - "create.gui.schematicannon.slot.listPrinter": "本をここに入れると概略図の材料チェックリストを印刷します。", - "create.gui.schematicannon.slot.schematic": "概略図をここに入れてください。特定の場所に配置されていることを確認してください。", - "create.gui.schematicannon.option.skipMissing.description": "配置に必要なブロックを見つけられない場合、次の場所に進みます。", - "create.gui.schematicannon.option.skipTileEntities.description": "チェストなどのデータ保持ブロックの置き換えによる消滅を回避します。", - "create.gui.schematicannon.option.dontReplaceSolid.description": "その作業範囲の固体ブロックを置き換えることはなく、非固体ブロックと空気のみを置き換えます。", - "create.gui.schematicannon.option.replaceWithSolid.description": "固体ブロックを設置する場合にのみ、その位置の固体ブロックを置き換えます。", - "create.gui.schematicannon.option.replaceWithAny.description": "任意のブロックを設置する場合に、その位置の固体ブロックを置き換えます。", - "create.gui.schematicannon.option.replaceWithEmpty.description": "空気を含め、あらゆるブロックを設置する場合に作業範囲のあらゆるブロックを一掃します。", - - "create.schematicannon.status.idle": "停止中", - "create.schematicannon.status.ready": "準備完了", - "create.schematicannon.status.running": "稼働中", - "create.schematicannon.status.finished": "完了", - "create.schematicannon.status.paused": "一時停止中", - "create.schematicannon.status.stopped": "停止", - "create.schematicannon.status.noGunpowder": "火薬不足", - "create.schematicannon.status.targetNotLoaded": "ブロックが読み込まれていません", - "create.schematicannon.status.targetOutsideRange": "対象が遠すぎます", - "create.schematicannon.status.searching": "検索中", - "create.schematicannon.status.skipping": "スキップ", - "create.schematicannon.status.missingBlock": "不明なブロック:", - "create.schematicannon.status.placing": "配置中", - "create.schematicannon.status.clearing": "ブロックをクリア中", - "create.schematicannon.status.schematicInvalid": "概略図が無効です", - "create.schematicannon.status.schematicNotPlaced": "配置されていない概略図です", - "create.schematicannon.status.schematicExpired": "概略図ファイルが期限切れです", - - "create.materialChecklist": "素材チェックリスト", - "create.materialChecklist.blocksNotLoaded": "*免責事項*\n\n素材チェックリストは関連するチャンクがロードされていないため、不正確かもしれません。", - - "create.gui.filter.deny_list": "ブラックリスト", - "create.gui.filter.deny_list.description": "上記のいずれにも一致しない場合、アイテムは通り抜けます。空のブラックリストはすべてを受け入れます。", - "create.gui.filter.allow_list": "ホワイトリスト", - "create.gui.filter.allow_list.description": "上記のいずれかに一致した場合、アイテムは通り抜けます。空のホワイトリストはすべてを拒否します。", - "create.gui.filter.respect_data": "データを重視", - "create.gui.filter.respect_data.description": "アイテムは、耐久値、エンチャント、その他の属性も一致する場合にのみ一致します。", - "create.gui.filter.ignore_data": "データを無視", - "create.gui.filter.ignore_data.description": "アイテムは属性に関係なく一致します。", - - "create.item_attributes.placeable": "設置できるかか", - "create.item_attributes.placeable.inverted": "設置できないか", - "create.item_attributes.consumable": "食べられるか", - "create.item_attributes.consumable.inverted": "食べられないか", - "create.item_attributes.fluid_container": "液体を貯蔵できるか", - "create.item_attributes.fluid_container.inverted": "液体を貯蔵できないか", - "create.item_attributes.enchanted": "エンチャント済みか", - "create.item_attributes.enchanted.inverted": "エンチャントなしか", - "create.item_attributes.max_enchanted": "最大レベルのエンチャントがされているか", - "create.item_attributes.max_enchanted.inverted": "最大レベルのエンチャントがされていないか", - "create.item_attributes.renamed": "名前付きか", - "create.item_attributes.renamed.inverted": "名前付きでないか", - "create.item_attributes.damaged": "破損しているか", - "create.item_attributes.damaged.inverted": "破損していないか", - "create.item_attributes.badly_damaged": "ひどく損傷してるか", - "create.item_attributes.badly_damaged.inverted": "ひどく損傷していないか", - "create.item_attributes.not_stackable": "スタックできるかか", - "create.item_attributes.not_stackable.inverted": "スタックできないか", - "create.item_attributes.equipable": "装備できるかか", - "create.item_attributes.equipable.inverted": "装備できないか", - "create.item_attributes.furnace_fuel": "かまどの燃料か", - "create.item_attributes.furnace_fuel.inverted": "かまどの燃料でないか", - "create.item_attributes.washable": "洗浄できるかか", - "create.item_attributes.washable.inverted": "洗浄できないか", - "create.item_attributes.hauntable": "憑霊できるか", - "create.item_attributes.hauntable.inverted": "憑霊できないか", - "create.item_attributes.crushable": "粉砕できるかか", - "create.item_attributes.crushable.inverted": "粉砕できないか", - "create.item_attributes.smeltable": "精錬できるかか", - "create.item_attributes.smeltable.inverted": "精錬できないか", - "create.item_attributes.smokable": "燻製器で調理できるかか", - "create.item_attributes.smokable.inverted": "燻製器で調理できないか", - "create.item_attributes.blastable": "溶鉱炉で精錬できるかか", - "create.item_attributes.blastable.inverted": "溶鉱炉で精錬できないか", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "%1$sシュルカーか", - "create.item_attributes.shulker_level.inverted": "%1$sシュルカーでないか", - "create.item_attributes.shulker_level.full": "満杯の", - "create.item_attributes.shulker_level.empty": "空の", - "create.item_attributes.shulker_level.partial": "一部埋まっている", - "create.item_attributes.in_tag": "%1$sのタグが付けられてるか", - "create.item_attributes.in_tag.inverted": "%1$sのタグがついていないか", - "create.item_attributes.in_item_group": "%1$sに属してるか", - "create.item_attributes.in_item_group.inverted": "%1$sに属していないか", - "create.item_attributes.added_by": "%1$sによって追加されたか", - "create.item_attributes.added_by.inverted": "%1$sによって追加されていないか", - "create.item_attributes.has_enchant": "エンチャントされているか%1$s", - "create.item_attributes.has_enchant.inverted": "エンチャントがされていないか", - "create.item_attributes.color": "%1$sで染められているか", - "create.item_attributes.color.inverted": "%1$sで染められていないか", - "create.item_attributes.has_fluid": "%1$sを含んでいるか", - "create.item_attributes.has_fluid.inverted": "%1$sを含んでいないか", - "create.item_attributes.has_name": "%1$sの名前が付けられているか", - "create.item_attributes.has_name.inverted": "%1$sの名前が付けられているか", - "create.item_attributes.book_author": "%1$sが署名したか", - "create.item_attributes.book_author.inverted": "%1$sが署名していないか", - "create.item_attributes.book_copy_original": "オリジナルか", - "create.item_attributes.book_copy_original.inverted": "オリジナルでないか", - "create.item_attributes.book_copy_first": "コピーか", - "create.item_attributes.book_copy_first.inverted": "コピーでないか", - "create.item_attributes.book_copy_second": "コピーのコピーか", - "create.item_attributes.book_copy_second.inverted": "コピーのコピーでないか", - "create.item_attributes.book_copy_tattered": "ボロボロか", - "create.item_attributes.book_copy_tattered.inverted": "ボロボロでないか", - "create.item_attributes.astralsorcery_amulet": "%1$s 改善か", - "create.item_attributes.astralsorcery_amulet.inverted": "%1$s 改善されないか", - "create.item_attributes.astralsorcery_constellation": "%1$s に同調しているか", - "create.item_attributes.astralsorcery_constellation.inverted": "%1$s に同調していないか", - "create.item_attributes.astralsorcery_crystal": "%1$s クリスタル属性を持つか", - "create.item_attributes.astralsorcery_crystal.inverted": "%1$s クリスタル属性を持たないか", - "create.item_attributes.astralsorcery_perk_gem": "%1$s 特典属性があるか", - "create.item_attributes.astralsorcery_perk_gem.inverted": "%1$s 特典属性がないか", - - "create.gui.attribute_filter.no_selected_attributes": "属性が選択されていません", - "create.gui.attribute_filter.selected_attributes": "選択した属性:", - "create.gui.attribute_filter.add_attribute": "属性をリストに追加する", - "create.gui.attribute_filter.add_inverted_attribute": "反属性をリストに追加する", - "create.gui.attribute_filter.allow_list_disjunctive": "ホワイトリスト(いずれか)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "選択した属性のいずれかを持っている場合、アイテムは通り抜けます。", - "create.gui.attribute_filter.allow_list_conjunctive": "ホワイトリスト(全て)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "選択した属性をすべてを持っている場合、アイテムは通り抜けます。", - "create.gui.attribute_filter.deny_list": "ブラックリスト", - "create.gui.attribute_filter.deny_list.description": "選択した属性を持たない場合、アイテムは通り抜けます。", - "create.gui.attribute_filter.add_reference_item": "参照アイテムを追加", - - "create.tooltip.holdForDescription": "説明を表示するには [%1$s] を長押し", - "create.tooltip.holdForControls": "操作方法を確認するには [%1$s] を長押し", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "必要な回転速度: %1$s", - "create.tooltip.speedRequirement.none": "無し", - "create.tooltip.speedRequirement.slow": "低速", - "create.tooltip.speedRequirement.medium": "中速", - "create.tooltip.speedRequirement.fast": "高速", - "create.tooltip.stressImpact": "応力への影響: %1$s", - "create.tooltip.stressImpact.low": "低", - "create.tooltip.stressImpact.medium": "中", - "create.tooltip.stressImpact.high": "高", - "create.tooltip.stressImpact.overstressed": "応力超過", - "create.tooltip.up_to": "最大%1$s", - "create.tooltip.capacityProvided": "許容応力: %1$s", - "create.tooltip.capacityProvided.low": "小", - "create.tooltip.capacityProvided.medium": "中", - "create.tooltip.capacityProvided.high": "大", - "create.tooltip.generationSpeed": "%1$s %2$sを生成", - "create.tooltip.analogStrength": "アナログ強度: %1$s/15", - - "create.mechanical_arm.extract_from": "%1$sからアイテムを取得", - "create.mechanical_arm.deposit_to": "%1$sにアイテムを置く", - "create.mechanical_arm.summary": "メカニカルアームは%1$s個の搬入ブロックと%2$s個の搬出ブロックを持っています。", - "create.mechanical_arm.points_outside_range": "%1$s個の選択ブロックが射程限界のため、除外されました。", - - "create.weighted_ejector.target_set": "対象を選択", - "create.weighted_ejector.target_not_valid": "隣接ブロックへの射出(対象が無効)", - "create.weighted_ejector.no_target": "隣接ブロックへの射出(対象が選択されていない)", - "create.weighted_ejector.targeting": "[%1$s,%2$s,%3$s]へ射出", - "create.weighted_ejector.stack_size": "射出スタック量", - - "create.logistics.when_multiple_outputs_available": "複数の搬出先が利用できるとき:", - - "create.mechanical_arm.selection_mode.round_robin": "順繰り分配", - "create.mechanical_arm.selection_mode.forced_round_robin": "強制順繰り分配", - "create.mechanical_arm.selection_mode.prefer_first": "最初の対象を優先", - - "create.tunnel.selection_mode.split": "スタック分割", - "create.tunnel.selection_mode.forced_split": "強制スタック分割", - "create.tunnel.selection_mode.round_robin": "順繰り分配", - "create.tunnel.selection_mode.forced_round_robin": "強制順繰り分配", - "create.tunnel.selection_mode.prefer_nearest": "近い所を優先", - "create.tunnel.selection_mode.randomize": "ランダム", - "create.tunnel.selection_mode.synchronize": "同期", - - "create.tooltip.chute.header": "シュート情報", - "create.tooltip.chute.items_move_down": "アイテムを下方向に移動します", - "create.tooltip.chute.items_move_up": "アイテムを上方向に移動します", - "create.tooltip.chute.no_fans_attached": "ファンは接続されていません", - "create.tooltip.chute.fans_push_up": "下からファンが押しています", - "create.tooltip.chute.fans_push_down": "ファンが上から押しています", - "create.tooltip.chute.fans_pull_up": "ファンが上から吸い込んでいます", - "create.tooltip.chute.fans_pull_down": "ファンが下から吸い込んでいます", - "create.tooltip.chute.contains": "内容物: %1$s x%2$s", - "create.tooltip.deployer.header": "デプロイヤーの情報", - "create.tooltip.deployer.using": "モード: 使用", - "create.tooltip.deployer.punching": "モード: 攻撃", - "create.tooltip.deployer.contains": "アイテム: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "配布中:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "右クリックで取り出し", - - "create.linked_controller.bind_mode": "割り当てモード", - "create.linked_controller.press_keybind": "%1$s、%2$s、%3$s、%4$s、%5$sまたは%6$sを押すとこの周波数がそのキーに割り当てられます", - "create.linked_controller.key_bound": "周波数を割り当てました %1$s", - "create.linked_controller.frequency_slot_1": "キーバインド: %1$s、周波数 #1", - "create.linked_controller.frequency_slot_2": "キーバインド: %1$s、周波数 #2", - - "create.crafting_blueprint.crafting_slot": "材料スロット", - "create.crafting_blueprint.filter_items_viable": "フィルターが使えます", - "create.crafting_blueprint.display_slot": "表示スロット", - "create.crafting_blueprint.inferred": "レシピから推測", - "create.crafting_blueprint.manually_assigned": "手動割り当て", - "create.crafting_blueprint.secondary_display_slot": "第2表示スロット", - "create.crafting_blueprint.optional": "オプション", - - "create.potato_cannon.ammo.attack_damage": "攻撃力: %1$s", - "create.potato_cannon.ammo.reload_ticks": "リロード時間(tick): %1$s", - "create.potato_cannon.ammo.knockback": "ノックバック: %1$s", - - "create.hint.hose_pulley.title": "底なし汲み上げ可能", - "create.hint.hose_pulley": "対象となる液体は無限とみなされています。", - "create.hint.mechanical_arm_no_targets.title": "対象が見つかりません", - "create.hint.mechanical_arm_no_targets": "どうやらこの_メカニカルアーム_には_対象_が割り当てられていないようです。_メカニカルアーム_を_手_に持って_右クリック_して、ベルト、デポ、ファンネルなどのブロックを選択します。", - "create.hint.empty_bearing.title": "ベアリングの更新", - "create.hint.empty_bearing": "_素手_でベアリングを_右クリック_して、その前に先ほど作った構造物を_接続_します。", - "create.hint.full_deployer.title": "デプロイヤーのアイテムが溢れています", - "create.hint.full_deployer": "この_デプロイヤー_には、_搬出_する必要がある余分なアイテムが含まれています。_ ホッパー_や_漏斗_などを使って、あふれないようにしてください。", - - "create.backtank.low": "バックタンクの空気圧が低下しています", - "create.backtank.depleted": "バックタンクの空気圧が不足しています", - - "create.hint.derailed_train.title": "列車が脱線しています", - "create.hint.derailed_train": "この_列車_は繋がった線路の上に乗っていないようです。レンチで右クリックして近くの線路に移してください。", - - "create.boiler.status": "ボイラー状態: %1$s", - "create.boiler.status_short": "ボイラー: %1$s", - "create.boiler.passive": "レベル最小", - "create.boiler.idle": "停止中", - "create.boiler.lvl": "レベル%1$s", - "create.boiler.max_lvl": "レベル最大", - "create.boiler.size": "容量", - "create.boiler.size_dots": "... ", - "create.boiler.water": "水量", - "create.boiler.water_dots": "... ", - "create.boiler.heat": "熱量", - "create.boiler.heat_dots": "... ", - "create.boiler.via_one_engine": "1基のエンジン経由", - "create.boiler.via_engines": "%1$s基のエンジン経由", - - "create.gui.schedule.lmb_edit": "左クリックで編集", - "create.gui.schedule.rmb_remove": "右クリックで削除", - "create.gui.schedule.duplicate": "複製", - "create.gui.schedule.remove_entry": "動作を削除", - "create.gui.schedule.add_entry": "動作を追加", - "create.gui.schedule.move_up": "上に移動", - "create.gui.schedule.move_down": "下に移動", - "create.gui.schedule.add_condition": "条件を追加", - "create.gui.schedule.alternative_condition": "いずれか条件", - - "create.schedule.instruction_type": "次の動作:", - "create.schedule.instruction.editor": "命令エディタ", - "create.schedule.instruction.destination": "駅へ移動", - "create.schedule.instruction.destination.summary": "止まる駅:", - "create.schedule.instruction.filter_edit_box": "駅名", - "create.schedule.instruction.filter_edit_box_1": " * を使うと任意の文章を指定できます", - "create.schedule.instruction.filter_edit_box_2": "例: '私の駅, *乗線'", - "create.schedule.instruction.filter_edit_box_3": "列車は一致し開いている駅の中で最も近い駅を選びます", - "create.schedule.instruction.rename": "時刻表名の変更", - "create.schedule.instruction.rename.summary": "新しいタイトル", - "create.schedule.instruction.name_edit_box": "時刻表名", - "create.schedule.instruction.name_edit_box_1": "この文字はディスプレイの表示に影響します", - "create.schedule.instruction.name_edit_box_2": "デフォルトは次の行き先の名前です", - "create.schedule.instruction.throttle": "最大速度を制限する", - "create.schedule.instruction.throttle.summary": "最大速度を変更する%1$s", - "create.schedule.instruction.throttle_edit_box": "スロットル", - "create.schedule.instruction.throttle_edit_box_1": "列車の最大速度に影響します", - "create.schedule.condition_type": "もし~ならば/~後に再開:", - "create.schedule.condition.editor": "条件エディタ", - "create.schedule.condition.delay": "待機する", - "create.schedule.condition.delay_short": "待機: %1$s", - "create.schedule.condition.delay.status": "出発まで%1$s", - "create.schedule.condition.idle": "貨物のやりとりが停止しているなら", - "create.schedule.condition.idle_short": "貨物のやりとりが停止: %1$s", - "create.schedule.condition.idle.status": "%1$s貨物のやりとりが停止", - "create.schedule.condition.for_x_time": "%1$s間", - "create.schedule.condition.unloaded": "チャンクロードが解除されたら", - "create.schedule.condition.unloaded.status": "チャンクアンロードを待っています", - "create.schedule.condition.powered": "駅が赤石信号を受けたら", - "create.schedule.condition.powered.status": "レッドストーン信号を待っています", - "create.schedule.condition.time_of_day": "指定時刻", - "create.schedule.condition.time_of_day.scheduled": "予定時刻: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%4$s%1$s:%3$s", - "create.schedule.condition.time_of_day.rotation": "繰り返し", - "create.schedule.condition.time_of_day.rotation.every_24": "1日ごと", - "create.schedule.condition.time_of_day.rotation.every_12": "12時間ごと", - "create.schedule.condition.time_of_day.rotation.every_6": "6時間ごと", - "create.schedule.condition.time_of_day.rotation.every_4": "4時間ごと", - "create.schedule.condition.time_of_day.rotation.every_3": "3時間ごと", - "create.schedule.condition.time_of_day.rotation.every_2": "2時間ごと", - "create.schedule.condition.time_of_day.rotation.every_1": "1時間ごと", - "create.schedule.condition.time_of_day.rotation.every_0_45": "45分ごと", - "create.schedule.condition.time_of_day.rotation.every_0_30": "30分ごと", - "create.schedule.condition.time_of_day.rotation.every_0_15": "15分ごと", - "create.schedule.condition.time_of_day.status": "出発時刻: ", - "create.schedule.condition.threshold.train_holds": "鉄道が指定%1$s積んだら", - "create.schedule.condition.threshold.greater": "以上", - "create.schedule.condition.threshold.less": "以下", - "create.schedule.condition.threshold.equal": "ぴったり", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$sの%3$s", - "create.schedule.condition.threshold.matching_content": "一致する貨物", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "アイテム単位", - "create.schedule.condition.threshold.items": "個", - "create.schedule.condition.threshold.stacks": "スタック", - "create.schedule.condition.threshold.buckets": "バケツ", - "create.schedule.condition.threshold.status": "貨物: %1$s/%2$s%3$s", - "create.schedule.condition.threshold.place_item": "参照アイテム", - "create.schedule.condition.threshold.place_item_2": "フィルターも使えます", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "液体貨物の状態", - "create.schedule.condition.item_threshold": "アイテム貨物の状態", - "create.schedule.condition.redstone_link": "レッドストーンリンク", - "create.schedule.condition.redstone_link.status": "レッドストーンリンクを待つ", - "create.schedule.condition.redstone_link_on": "リンクがオンなら", - "create.schedule.condition.redstone_link_off": "リンクがオフなら", - "create.schedule.condition.redstone_link.powered": "オン", - "create.schedule.condition.redstone_link.unpowered": "オフ", - "create.schedule.condition.redstone_link.frequency_state": "周波数の状態: ", - "create.schedule.condition.redstone_link.frequency_powered": "周波数がオンなら:", - "create.schedule.condition.redstone_link.frequency_unpowered": "周波数がオフなら:", - "create.schedule.condition.player_count": "座っているプレイヤー数", - "create.schedule.condition.player_count.summary": "%1$s人のプレイヤー", - "create.schedule.condition.player_count.summary_plural": "%1$s人のプレイヤー", - "create.schedule.condition.player_count.seated": "%1$sが着席", - "create.schedule.condition.player_count.players": "人のプレイヤー", - "create.schedule.condition.player_count.condition": "条件", - "create.schedule.condition.player_count.exactly": "ちょうど", - "create.schedule.condition.player_count.or_above": "以上", - "create.schedule.condition.player_count.status": "乗客数: %1$s/%2$s", - "create.schedule.loop": "無限ループ", - "create.schedule.loop1": "予定を最初からやり直す", - "create.schedule.loop2": "完了したら", - "create.schedule.reset": "進行度をリセット", - "create.schedule.skip": "現在の動作をスキップ", - "create.schedule.applied_to_train": "今この列車は時刻表に従っています", - "create.schedule.non_controlling_seat": "車掌は運転台ブロックの正面に座っている必要があります", - "create.schedule.remove_with_empty_hand": "先に素手で時刻表を回収してください", - "create.schedule.auto_removed_from_train": "自動で適用された時刻表を削除しました", - "create.schedule.removed_from_train": "列車から時刻表を取り出しました", - "create.schedule.no_stops": "この時刻表には停車駅がありません", - "create.schedule.continued": "運行を再開しました", - - "create.track.selection_cleared": "選択を破棄しました", - "create.track.valid_connection": "接続可能 ✔", - "create.track.second_point": "線路を置くか、次の位置を指定してください", - "create.track.too_far": "遠すぎます", - "create.track.original_missing": "元のブロックが存在しません。スニーククリックでリセットできます", - "create.track.perpendicular": "垂直には接続できません", - "create.track.ascending_s_curve": "傾斜のあるS字カーブは作成できません", - "create.track.too_sharp": "カーブが急すぎます", - "create.track.too_steep": "傾斜が急すぎます", - "create.track.slope_turn": "ターンで傾斜から出たり入ったりすることはできません", - "create.track.opposing_slopes": "逆向きのカーブの傾斜は接続できません", - "create.track.leave_slope_ascending": "この登り傾斜から離脱することはできません", - "create.track.leave_slope_descending": "この下り傾斜から離脱することはできません", - "create.track.turn_90": "90度を超えるターンは設置できません", - "create.track.junction_start": "分岐から接続は始められません", - "create.track.turn_start": "ターンから接続は始められません", - "create.track.not_enough_tracks": "線路が足りません", - "create.track.not_enough_pavement": "道床ブロックが足りません", - - "create.portal_track.failed": "ポータル線路を設置できません:", - "create.portal_track.missing": "対象のポータルはまだ生成されていません", - "create.portal_track.blocked": "対象の位置は塞がっています(%1$s,%2$s,%3$s)", - - "create.station.idle": "駅は待機中です", - "create.station.assembly_title": "列車組み立て", - "create.station.close": "ウィンドウを閉じる", - "create.station.cancel": "組み立てをキャンセル", - "create.station.failed": "組み立てに失敗しました", - "create.station.icon_type": "アイコンの種類", - "create.station.create_train": "新しい列車の作成", - "create.station.assemble_train": "列車を組み立て", - "create.station.disassemble_train": "列車を分解", - "create.station.remove_schedule": "時刻表を取り出し", - "create.station.remove_auto_schedule": "自動で適用された時刻表を破棄", - "create.station.no_assembly_diagonal": "交差線路の上では", - "create.station.no_assembly_diagonal_1": "列車を組み立てられません", - "create.station.no_assembly_curve": "カーブしている線路の上では", - "create.station.no_assembly_curve_1": "列車を組み立てられません", - "create.station.train_not_aligned": "すべての車両が並んでいないため、", - "create.station.train_not_aligned_1": "列車を編集できません", - "create.station.carriage_number": "%1$s両目:", - "create.station.retry": "解決してやり直してください", - "create.station.no_bogeys": "台車がありません", - "create.station.one_bogey": "台車1台", - "create.station.more_bogeys": "台車%1$s台", - "create.station.how_to": "鉄道用ケーシングを強調表示された線路に使うと台車を作れます", - "create.station.how_to_1": "上の方のブロックを壊せば台車を壊せます", - "create.station.how_to_2": "車両を作るには1台か2台の台車を繋げてください", - - "create.train_assembly.too_many_bogeys": "台車が多すぎます: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "先頭の台車は駅マーカーの上にある必要があります", - "create.train_assembly.no_bogeys": "台車が見つかりません", - "create.train_assembly.not_connected_in_order": "台車は順番に接続されていません", - "create.train_assembly.bogeys_too_close": "台車%1$sと台車%2$sは近すぎます", - "create.train_assembly.single_bogey_carriage": "このタイプの台車は単体で列車にできません", - "create.train_assembly.nothing_attached": "台車%1$sには構造物が接続されていません", - "create.train_assembly.no_controls": "最低一つは前向きの運転台ブロックを列車に乗せる必要があります", - "create.train_assembly.sideways_controls": "乗っている運転台ブロックは横向きです", - "create.train_assembly.bogey_created": "台車を作りました。もう一度クリックすれば循環して種類を変えられます", - "create.train_assembly.requires_casing": "線路に台車を作るには鉄道用ケーシングを使ってください", - - "create.track_target.set": "対象となる線路を選択しました", - "create.track_target.success": "対象の線路との接続に成功しました", - "create.track_target.clear": "線路の選択を解除しました", - "create.track_target.missing": "まず対象となる線路を右クリックしてください", - "create.track_target.too_far": "対象となる線路はここから遠すぎます", - "create.track_target.no_junctions": "対象となる線路は交差できません", - "create.track_target.occupied": "対象となる線路はふさがっています", - "create.track_target.invalid": "この線路を選択することはできません", - - "create.train.unnamed": "無名の列車", - "create.train.cannot_relocate_moving": "動いている列車は移動できません", - "create.train.relocate": "%1$sを移動する線路をクリックしてください。スニーククリックでキャンセルできます。", - "create.train.relocate.abort": "列車の移動をキャンセルしました", - "create.train.relocate.success": "移動が成功しました", - "create.train.relocate.valid": "列車はここに移動可能です。クリックで適用", - "create.train.relocate.invalid": "列車をここに移動することはできません", - "create.train.relocate.too_far": "列車を移動させるには遠すぎます", - "create.train.departing_from": "%1$sから出発", - "create.train.arrived_at": "%1$sに到着", - "create.train.status": " 列車情報: %1$s", - "create.train.status.back_on_track": "列車は再び線路の上に戻りました", - "create.train.status.collision": "他の列車と衝突しました", - "create.train.status.end_of_track": "車両が線路の端に到達しました", - "create.train.status.double_portal": "ポータルから出て来ている間に別のポータルに車両が入ることはできません", - "create.train.status.coupling_stress": "連結器に大きな力がかかったため強制停止しました", - "create.train.status.track_missing": "列車が線路上にありません", - "create.train.status.paused_for_manual": "手動操縦のため、時刻表の運行を一時停止しました", - "create.train.status.opposite_driver": "この経路には逆向きの運転手が必要です", - "create.train.status.missing_driver": "運転手がいません", - "create.train.status.found_driver": "新しい運転手が見つかりました", - "create.train.status.navigation_success": "経路探索に成功しました", - "create.train.status.no_match": "線路ネットワークに'%1$s'と一致する駅が見つかりません", - "create.train.status.no_path": "次の行先への適切な経路が見つかりません", - - "create.track_signal.cannot_change_mode": "この信号のモードを切り替えることはできません", - "create.track_signal.mode_change.entry_signal": " -> 区間が空いているなら通過を許可", - "create.track_signal.mode_change.cross_signal": " -> 区間をよどみなく走行できるなら通過を許可", - - "create.contraption.controls.start_controlling": "運転中: %1$s", - "create.contraption.controls.stop_controlling": "運転終了", - "create.contraption.controls.approach_station": "%1$sキーを長押しで%2$sに停車", - - "create.display_link.set": "対象の位置を選択しました", - "create.display_link.success": "対象の位置と結び付けられました", - "create.display_link.clear": "選択した位置を破棄しました", - "create.display_link.too_far": "対象の位置はここから遠すぎます", - "create.display_link.invalid": "適切な対象ではありません、再設置してください", - "create.display_link.title": "ディスプレイリンク", - "create.display_link.no_source": "情報源がありません", - "create.display_link.no_target": "表示先がありません", - "create.display_link.reading_from": "受信元:", - "create.display_link.writing_to": "送信先:", - "create.display_link.attached_side": "接続面のブロック", - "create.display_link.targeted_location": "対象の位置のブロック", - "create.display_link.view_compatible": "クリックして互換性のあるすべてのものを表示", - "create.display_link.information_type": "情報の種類", - "create.display_link.display_on": "データの書き込み先:", - "create.display_link.display_on_multiline": "表示を始める行:", - - "create.display_source.label": "ラベル", - "create.display_source.combine_item_names": "アイテム名を結合", - "create.display_source.count_items": "一致するアイテムの量", - "create.display_source.list_items": "一致するアイテムの一覧", - "create.display_source.fluid_amount": "一致する液体の量", - "create.display_source.list_fluids": "一致する液体の一覧", - "create.display_source.nixie_tube": "ニキシー管の表示内容をコピー", - "create.display_source.fill_level": "収納ブロックの使用率", - "create.display_source.fill_level.display": "表示形式", - "create.display_source.fill_level.percent": "パーセント", - "create.display_source.fill_level.progress_bar": "プログレスバー", - "create.display_source.value_list.display": "数値の表示形式", - "create.display_source.value_list.shortened": "短縮", - "create.display_source.value_list.full_number": "完全な数値", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "プレイヤーの死亡回数", - "create.display_source.scoreboard": "スコアボード", - "create.display_source.scoreboard.objective": "Objective ID", - "create.display_source.scoreboard.objective_not_found": "'%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "プレイヤーの死亡回数", - "create.display_source.time_of_day": "現在時刻", - "create.display_source.stop_watch": "ストップウォッチ", - "create.display_source.time.format": "時刻の表示形式", - "create.display_source.time.12_hour": "12時間制", - "create.display_source.time.24_hour": "24時間制", - "create.display_source.accumulate_items": "蓄積アイテムカウンター", - "create.display_source.item_throughput": "アイテム処理量", - "create.display_source.item_throughput.interval": "間隔", - "create.display_source.item_throughput.interval.second": "毎秒", - "create.display_source.item_throughput.interval.minute": "毎分", - "create.display_source.item_throughput.interval.hour": "毎時", - "create.display_source.train_status": "鉄道運行の状態", - "create.display_source.station_summary": "鉄道駅の概要", - "create.display_source.station_summary.filter": "駅名フィルター", - "create.display_source.station_summary.train_name_column": "列車名の表示幅", - "create.display_source.station_summary.platform_column": "プラットフォームの表示幅", - "create.display_source.station_summary.now": "到着", - "create.display_source.station_summary.minutes": "分後", - "create.display_source.station_summary.seconds": "%1$s秒後", - "create.display_source.observed_train_name": "検知した列車名", - "create.display_source.max_enchant_level": "最大エンチャントコスト", - "create.display_source.boiler_status": "ボイラー状態", - "create.display_source.entity_name": "エンティティ名", - "create.display_source.kinetic_speed": "回転速度(RPM)", - "create.display_source.kinetic_speed.absolute": "回転方向を無視", - "create.display_source.kinetic_speed.directional": "回転方向を含める", - "create.display_source.kinetic_stress": "ネットワークの応力", - "create.display_source.kinetic_stress.display": "表示する情報", - "create.display_source.kinetic_stress.progress_bar": "プログレスバー", - "create.display_source.kinetic_stress.percent": "パーセント", - "create.display_source.kinetic_stress.current": "使用しているSU", - "create.display_source.kinetic_stress.max": "許容応力の合計", - "create.display_source.kinetic_stress.remaining": "残りのSU", - "create.display_source.redstone_power": "レッドストーン強度", - "create.display_source.redstone_power.display": "表示形式", - "create.display_source.redstone_power.number": "数値", - "create.display_source.redstone_power.progress_bar": "プログレスバー", - "create.display_source.boiler.not_enough_space": "ボイラーステータスの表示に", - "create.display_source.boiler.for_boiler_status": "十分なスペースがありません ", - - "create.display_target.line": "%1$s行目", - "create.display_target.page": "%1$sページ目", - "create.display_target.single_line": "単一行", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; 分;現在;15秒;30秒;45秒", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "選択した範囲が大きすぎます", - "create.super_glue.cannot_reach": "選択したブロックは繋がっているべきです", - "create.super_glue.click_to_confirm": "もう一度クリックで続行", - "create.super_glue.click_to_discard": "スニークしながらクリックで選択範囲を破棄", - "create.super_glue.first_pos": "始点を選択しました", - "create.super_glue.abort": "選択を破棄しました", - "create.super_glue.not_enough": "インベントリに十分な超粘着剤がありません。", - "create.super_glue.success": "超粘着剤を適用中...", - - "create.gui.config.overlay1": "やぁ(・∀・)", - "create.gui.config.overlay2": "これはオーバーレイのサンプルです", - "create.gui.config.overlay3": "マウスでクリックまたはドラッグしてください", - "create.gui.config.overlay4": "クリックしてこのプレビューを移動します", - "create.gui.config.overlay5": "ESCを押してこの画面を終了します", - "create.gui.config.overlay6": "それと新しい位置を保存します", - "create.gui.config.overlay7": "オーバーレイのリセットを実行 /作成", - "create.gui.config.overlay8": "クリックして、デフォルトの位置にリセットします。", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]:サーバーティックは現在 %s ms 遅くなっています :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: サーバーティックが %s ms 遅くなりました >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: サーバーティックが通常の速度に戻りました:D", - "create.command.killTPSCommand.status.usage.0": "[Create]: /killtps stopを使用してサーバーのティックを通常の速度に戻します", - "create.command.killTPSCommand.status.usage.1": "[Create]: /killtps start を使用して、サーバーのティックを意図的に遅くします", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "このからくりトロッコは大きすぎて拾えません", - "create.contraption.minecart_contraption_illegal_pickup": "超自然的な力が、からくりカートを世界に縛り付けています", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "からくりが止まる", - "create.subtitle.peculiar_bell_use": "風変わりな鐘が鳴る", - "create.subtitle.worldshaper_place": "ワールドシェーパーが設置する", - "create.subtitle.whistle_train_manual": "汽車の汽笛が鳴る", - "create.subtitle.steam": "蒸気の音", - "create.subtitle.saw_activate_stone": "メカニカルソーが動作する", - "create.subtitle.schematicannon_finish": "概略図砲が作業を終える", - "create.subtitle.crafter_craft": "メカニカルクラフターがクラフトする", - "create.subtitle.wrench_remove": "機械を壊す", - "create.subtitle.train3": "台車の車輪がゴロゴロと音を立てる", - "create.subtitle.whistle": "汽笛が鳴る", - "create.subtitle.cogs": "歯車がゴロゴロと鳴る", - "create.subtitle.slime_added": "スライムがぐしゃっとつぶれる", - "create.subtitle.whistle_train_low": "汽笛が低く鳴る", - "create.subtitle.schematicannon_launch_block": "概略図砲が発射する", - "create.subtitle.controller_take": "書見台が空になる", - "create.subtitle.crafter_click": "メカニカルクラフターのカチカチ音", - "create.subtitle.depot_plop": "デプロイヤーにアイテムが入れられる", - "create.subtitle.confirm": "成功音", - "create.subtitle.mixing": "混ぜる音", - "create.subtitle.mechanical_press_activation_belt": "メカニカルプレスがボンと鳴る", - "create.subtitle.fwoomp": "ポテトランチャーがバキューンと鳴る", - "create.subtitle.sanding_long": "研磨音", - "create.subtitle.crushing_1": "粉砕音", - "create.subtitle.depot_slide": "アイテムが滑る", - "create.subtitle.blaze_munch": "ブレイズが食べる音", - "create.subtitle.funnel_flap": "ファンネルがはためく", - "create.subtitle.haunted_bell_use": "憑りつかれた鐘が鳴る", - "create.subtitle.scroll_value": "スクロールのカチカチ音", - "create.subtitle.controller_put": "コントローラのトントン音", - "create.subtitle.cranking": "ハンドクランクが回る", - "create.subtitle.sanding_short": "研磨音", - "create.subtitle.wrench_rotate": "レンチが使われる", - "create.subtitle.potato_hit": "野菜が砕ける", - "create.subtitle.saw_activate_wood": "メカニカルソーが動作する", - "create.subtitle.whistle_high": "汽笛が高く鳴る", - "create.subtitle.whistle_train_manual_low": "汽車の汽笛が鳴る", - "create.subtitle.whistle_train": "汽車の汽笛が鳴る", - "create.subtitle.haunted_bell_convert": "憑りつかれた鐘が目覚める", - "create.subtitle.train": "台車の車輪が鳴る", - "create.subtitle.deny": "失敗音", - "create.subtitle.controller_click": "コントローラーのカチカチ音", - "create.subtitle.whistle_low": "汽笛が低く鳴る", - "create.subtitle.copper_armor_equip": "潜水服がチャリンと鳴る", - "create.subtitle.mechanical_press_activation": "メカニカルプレスがガーンと鳴る", - "create.subtitle.contraption_assemble": "からくりが動く", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "アイテムの例(ただ単にこのツールチップが存在することを示すマーカー)", - "item.create.example_item.tooltip.summary": "アイテムの簡単な説明。アンダーバーで用語を強調表示します。", - "item.create.example_item.tooltip.condition1": "これをしたとき", - "item.create.example_item.tooltip.behaviour1": "すると、このアイテムはこのようなことをします。(シフトを押したときに表示される)", - "item.create.example_item.tooltip.condition2": "そしてこれをしたとき", - "item.create.example_item.tooltip.behaviour2": "好きなだけ挙動を追加できます。", - "item.create.example_item.tooltip.control1": "Ctrlを押したとき", - "item.create.example_item.tooltip.action1": "これらのコントロールが表示されます。", - - "block.create.wooden_bracket.tooltip": "木製ブラケット", - "block.create.wooden_bracket.tooltip.summary": "この補強用の温かみのある腕木で_シャフト_、_歯車_、そして_パイプ_を_飾ろう_。", - - "block.create.metal_bracket.tooltip": "金属ブラケット", - "block.create.metal_bracket.tooltip.summary": "この補強用の工業的で頑丈な腕金で_シャフト_、_歯車_、そして_パイプ_を_飾ろう_。", - - "block.create.seat.tooltip": "シート", - "block.create.seat.tooltip.summary": "シートに座って乗り物を楽しもう!移動する_からくり_の上にプレイヤーを固定します。もちろん家具にも使えます。染色も。", - "block.create.seat.tooltip.condition1": "右クリックしたとき", - "block.create.seat.tooltip.behaviour1": "_シート_の上に座ります。左シフトを押すと_シート_から離れます。", - - "item.create.blaze_cake.tooltip": "ブレイズケーキ", - "item.create.blaze_cake.tooltip.summary": "働き者の_ブレイズバーナー_たちに美味しいごちそうを。彼らを燃え上がらせよう(物理)!", - - "item.create.wand_of_symmetry.tooltip": "対称の杖", - "item.create.wand_of_symmetry.tooltip.summary": "対象の鏡をまたいだ範囲内のブロック設置を完全に複製します。", - "item.create.wand_of_symmetry.tooltip.condition1": "ホットバーにあるとき", - "item.create.wand_of_symmetry.tooltip.behaviour1": "対象の鏡は有効のまま", - "item.create.wand_of_symmetry.tooltip.control1": "地面を右クリックしたとき", - "item.create.wand_of_symmetry.tooltip.action1": "対象の鏡を_作成_または_移動_する", - "item.create.wand_of_symmetry.tooltip.control2": "空中を右クリックしたとき", - "item.create.wand_of_symmetry.tooltip.action2": "有効な対象の鏡を_削除_", - "item.create.wand_of_symmetry.tooltip.control3": "スニークしながら右クリックしたとき", - "item.create.wand_of_symmetry.tooltip.action3": "_設定画面_を開きます。", - - "item.create.handheld_worldshaper.tooltip": "携帯型ワールドシェーパー", - "item.create.handheld_worldshaper.tooltip.summary": "特色ある_風景_や_地形_を作るのに便利な道具。", - "item.create.handheld_worldshaper.tooltip.control1": "ブロックを左クリックしたとき", - "item.create.handheld_worldshaper.tooltip.action1": "見ているブロックをこの道具に設定します。", - "item.create.handheld_worldshaper.tooltip.control2": "ブロックを右クリックしたとき", - "item.create.handheld_worldshaper.tooltip.action2": "選択されている_ブラシ_や_ツール_を目標の場所に適用します。", - "item.create.handheld_worldshaper.tooltip.control3": "スニークしながら右クリックしたとき", - "item.create.handheld_worldshaper.tooltip.action3": "_設定画面_を開きます。", - - "item.create.tree_fertilizer.tooltip": "樹木の肥料", - "item.create.tree_fertilizer.tooltip.summary": "一般的な種類の木の成長を早めるのに適したミネラルを配合した強力な肥料。", - "item.create.tree_fertilizer.tooltip.condition1": "苗木に使ったとき", - "item.create.tree_fertilizer.tooltip.behaviour1": "_間隔の条件_に_関係なく_苗木を成長させる", - - "item.create.extendo_grip.tooltip": "マジックハンド", - "item.create.extendo_grip.tooltip.summary": "ビヨヨーン!着用者の_射程_を大幅に_伸ばし_ます。", - "item.create.extendo_grip.tooltip.condition1": "オフハンドに装備したとき", - "item.create.extendo_grip.tooltip.behaviour1": "_メインハンド_で使うアイテムの_射程_を_伸ばし_ます。", - "item.create.extendo_grip.tooltip.condition2": "銅のバックタンクを装備したとき", - "item.create.extendo_grip.tooltip.behaviour2": "_耐久値_を消費しなくなります。代わりに_圧縮空気_をタンクから消費します。", - - "item.create.potato_cannon.tooltip": "ポテトキャノン", - "item.create.potato_cannon.tooltip.summary": "バキューン!自分が育てた野菜を敵に発射します。_銅のバックタンク_の圧縮空気でも動かせます。", - "item.create.potato_cannon.tooltip.condition1": "右クリックしたとき", - "item.create.potato_cannon.tooltip.behaviour1": "_インベントリ_の中から_適切_なアイテムを発射します。", - "item.create.potato_cannon.tooltip.condition2": "銅のバックタンクを装備した時", - "item.create.potato_cannon.tooltip.behaviour2": "_耐久値_を消費しなくなります。代わりに_圧縮空気_をタンクから消費します", - - "item.create.filter.tooltip": "フィルター", - "item.create.filter.tooltip.summary": "物流系の装置の_搬入_と_搬出_をより_正確_に_制御_し、_アイテムのセット_またはいくつかの_入れ子になったフィルター_と照合します。", - "item.create.filter.tooltip.condition1": "フィルタースロットにセットしたとき", - "item.create.filter.tooltip.behaviour1": "_設定_に応じてアイテムの流れを_制御_します。", - "item.create.filter.tooltip.condition2": "右クリックしたとき", - "item.create.filter.tooltip.behaviour2": "_設定画面_を開きます。", - - "item.create.attribute_filter.tooltip": "属性フィルター", - "item.create.attribute_filter.tooltip.summary": "物流系の装置の_搬入_と_搬出_をより_正確_に_制御_し、アイテムの_属性_と_カテゴリのセット_と照合します。", - "item.create.attribute_filter.tooltip.condition1": "フィルタースロットにセットしたとき", - "item.create.attribute_filter.tooltip.behaviour1": "_設定_に応じてアイテムの流れを_制御_します。", - "item.create.attribute_filter.tooltip.condition2": "右クリックしたとき", - "item.create.attribute_filter.tooltip.behaviour2": "_設定画面_を開きます。", - - "item.create.empty_schematic.tooltip": "空の概略図", - "item.create.empty_schematic.tooltip.summary": "レシピの材料、および_概略図台_からの書き込みに使われます。", - - "item.create.schematic.tooltip": "概略図", - "item.create.schematic.tooltip.summary": "ワールドに設置できる構造物を保存します。ホログラムを必要に応じて配置し、_概略図砲_を使って建築できます。", - "item.create.schematic.tooltip.condition1": "持ったとき", - "item.create.schematic.tooltip.behaviour1": "画面上のツールを使ってホログラムを配置します。", - "item.create.schematic.tooltip.control1": "スニークしながら右クリックしたとき", - "item.create.schematic.tooltip.action1": "正確な_座標_の入力_画面_を開きます", - - "item.create.schematic_and_quill.tooltip": "概略図と羽根ペン", - "item.create.schematic_and_quill.tooltip.summary": "ワールドの構造物を.nbtファイルに保存できます。", - "item.create.schematic_and_quill.tooltip.condition1": "ステップ1", - "item.create.schematic_and_quill.tooltip.behaviour1": "右クリックして2つのコーナーポイントを選択します。", - "item.create.schematic_and_quill.tooltip.condition2": "ステップ2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrlキーを押しながらスクロール_して、サイズを調整します。もう一度右クリックして保存します。", - "item.create.schematic_and_quill.tooltip.control1": "右クリックしたとき", - "item.create.schematic_and_quill.tooltip.action1": "コーナーポイントを選択/保存を確認します。", - "item.create.schematic_and_quill.tooltip.control2": "Ctrlを長押しているとき", - "item.create.schematic_and_quill.tooltip.action2": "_空中_でポイントを選択します。_スクロール_して距離を調整します。", - "item.create.schematic_and_quill.tooltip.control3": "スニークしながら右クリックしたとき", - "item.create.schematic_and_quill.tooltip.action3": "選択を_リセット_して削除します。", - - "block.create.schematicannon.tooltip": "概略図砲", - "block.create.schematicannon.tooltip.summary": "ブロックを撃って、_概略図_をもとにワールドに設置します。隣接する収納ブロックからのアイテムを自動搬入し、_火薬_を燃料とします。", - "block.create.schematicannon.tooltip.condition1": "右クリックしたとき", - "block.create.schematicannon.tooltip.behaviour1": "_UI_を開きます。", - - "block.create.schematic_table.tooltip": "概略図台", - "block.create.schematic_table.tooltip.summary": "保存された構造物を_空の概略図_に書き込みます。", - "block.create.schematic_table.tooltip.condition1": "空の概略図を入れたとき", - "block.create.schematic_table.tooltip.behaviour1": "Schematicsフォルダから選択したファイルをアップロードします。", - - "item.create.goggles.tooltip": "ゴーグル", - "item.create.goggles.tooltip.summary": "有用な_回転力_の_情報_を視界に映す眼鏡。", - "item.create.goggles.tooltip.condition1": "着用したとき", - "item.create.goggles.tooltip.behaviour1": "設置した機械の_回転速度_および、_機械_の_応力への影響_と_許容応力_を_色付きのインジケーター_で表示します。", - "item.create.goggles.tooltip.condition2": "計器を見たとき", - "item.create.goggles.tooltip.behaviour2": "計器が接続されている動力ネットワークの_回転速度_または_応力_に関する詳細情報を表示します。", - "item.create.goggles.tooltip.condition3": "液体コンテナを見たとき", - "item.create.goggles.tooltip.behaviour3": "ブロックの_容量_と、その中に貯蔵されている_液体_の詳細情報を表示します。", - - "item.create.wrench.tooltip": "レンチ", - "item.create.wrench.tooltip.summary": "機械いじりに便利な道具。機械の_回転_、_解体_、_設定_に使います。", - "item.create.wrench.tooltip.control1": "機械を右クリックしたとき", - "item.create.wrench.tooltip.action1": "操作した面に向かって、または面から離れるように_機械_を_回転_させます。", - "item.create.wrench.tooltip.control2": "スニークしながら右クリックしたとき", - "item.create.wrench.tooltip.action2": "_機械を分解_し、_インベントリ_に戻します。", - - "block.create.nozzle.tooltip": "ノズル", - "block.create.nozzle.tooltip.summary": "_ケース入りファン_の前面に取り付けて、エンティティへの影響を_全方向_に分散します。", - - "block.create.cuckoo_clock.tooltip": "鳩時計", - "block.create.cuckoo_clock.tooltip.summary": "空間を_彩り_、_時間を刻む_素晴らしい機械細工。", - "block.create.cuckoo_clock.tooltip.condition1": "動力を供給したとき", - "block.create.cuckoo_clock.tooltip.behaviour1": "_現在の時刻_を表示し、1日に2回曲を再生します。、_正午_と夕暮れに_プレイヤーが眠れる_時間になるとすぐに_再生_します。", - - "block.create.turntable.tooltip": "ターンテーブル", - "block.create.turntable.tooltip.summary": "_回転力_を洗練された乗り物酔いに変えよう。", - - "block.create.toolbox.tooltip": "工具箱", - "block.create.toolbox.tooltip.summary": "発明家の最愛の仲間。異なる8種類のアイテムを大量に_収納_できる便利グッズ。", - "block.create.toolbox.tooltip.condition1": "壊したとき", - "block.create.toolbox.tooltip.behaviour1": "インベントリの_内容_を_保持_します", - "block.create.toolbox.tooltip.condition2": "範囲内に置いたとき", - "block.create.toolbox.tooltip.behaviour2": "_近く_にいる_プレイヤー_が_工具箱_の_キーバインド_を押すと、工具箱に_触れずに_アクセスできます", - "block.create.toolbox.tooltip.condition3": "右クリックした時", - "block.create.toolbox.tooltip.behaviour3": "_収納UI_を開きます", - - "block.create.stockpile_switch.tooltip": "在庫スイッチ", - "block.create.stockpile_switch.tooltip.summary": "接続した収納ブロックの_空き容量_によってレッドストーン信号を切り替えます。便利なフィルターが付属しています。_コンパレータ―_とは違って、_在庫スイッチ_は、信号が反転する_しきい値_を設定できます。", - "block.create.stockpile_switch.tooltip.condition1": "右クリックしたとき", - "block.create.stockpile_switch.tooltip.behaviour1": "_設定画面_を開きます。", - - "block.create.content_observer.tooltip": "コンテンツオブザーバー", - "block.create.content_observer.tooltip.summary": "_収納ブロック_や_メカニカルベルト_内の設定した_フィルター_に一致する_アイテム_を_検出_します。", - "block.create.content_observer.tooltip.condition1": "収納ブロックを観察するとき", - "block.create.content_observer.tooltip.behaviour1": "観測する収納ブロックが_一致するコンテンツ_が入っている間、_レッドストーン信号_を発する。", - "block.create.content_observer.tooltip.condition2": "ファンネルを観察するとき", - "block.create.content_observer.tooltip.behaviour2": "_一致するアイテム_が_輸送_されると、_レッドストーンパルス_を発します。", - - "block.create.creative_crate.tooltip": "クリエイティブクレート", - "block.create.creative_crate.tooltip.summary": "あらゆるアイテムを無限に複製する_収納ブロック_。隣接する_概略図砲_へブロックを無限に供給します。", - "block.create.creative_crate.tooltip.condition1": "フィルタースロットにアイテムが入っているとき", - "block.create.creative_crate.tooltip.behaviour1": "このクレートから何かを_搬出_すると、指定したアイテムが_無限_に_搬出_されます。このクレートに_搬入_したアイテムは_消滅_します。", - - "item.create.creative_blaze_cake.tooltip": "クリエイティブブレイズケーキ", - "item.create.creative_blaze_cake.tooltip.summary": "ブレイズバーナーの火力をコントロールすることができる特別なケーキ。ブレイズバーナーたちがこれを食べれば絶対燃え尽きない(物理)。", - "item.create.creative_blaze_cake.tooltip.condition1": "ブレイズバーナーを使ったとき", - "item.create.creative_blaze_cake.tooltip.behaviour1": "ブレイズバーナーの火力を固定します。再度使用するとブレイズバーナーの火力を循環して切り替えます", - - "block.create.controller_rail.tooltip": "コントローラーレール", - "block.create.controller_rail.tooltip.summary": "トロッコの_移動速度_を_細かく制御_できる_一方通行_の_パワード_レール", - "block.create.controller_rail.tooltip.condition1": "レッドストーン信号を受けたとき", - "block.create.controller_rail.tooltip.behaviour1": "通過する_トロッコ_を_信号の強度_に対応した移動速度に_加速_または_減速_します。また、隣接するコントローラレールにレッドストーン信号を伝達します。2つのコントローラレールに強度の異なるレッドストーン信号を供給すると、それらの間のレールはその信号の変化を補間します。", - - "item.create.sand_paper.tooltip": "紙やすり", - "item.create.sand_paper.tooltip.summary": "_素材_を_磨く_のに使える荒い紙。デプロイヤーに自動で磨かせることもできます。", - "item.create.sand_paper.tooltip.condition1": "使ったとき", - "item.create.sand_paper.tooltip.behaviour1": "_オフハンド_で持っていたり、_視線先_の_ドロップ状態のアイテム_を磨きます。", - - "item.create.builders_tea.tooltip": "建築家のお茶", - "item.create.builders_tea.tooltip.summary": "_やる気_がみなぎる、一日の始まりに最適な飲み物。", - - "item.create.refined_radiance.tooltip": "高貴な光輝", - "item.create.refined_radiance.tooltip.summary": "_吸収した光輝_から鍛造した色彩素材。", - "item.create.refined_radiance.tooltip.condition1": "作業中", - "item.create.refined_radiance.tooltip.behaviour1": "この素材の使用方法は将来のリリースで実装予定です。", - - "item.create.shadow_steel.tooltip": "シャドウスチール", - "item.create.shadow_steel.tooltip.summary": "_奈落の虚無_から鍛造した色彩素材。", - "item.create.shadow_steel.tooltip.condition1": "作業中", - "item.create.shadow_steel.tooltip.behaviour1": "この素材の使用方法は将来のリリースで実装予定です。", - - "item.create.linked_controller.tooltip": "リンクコントローラー", - "item.create.linked_controller.tooltip.summary": "_6つのボタン_に割り当てられた周波数の_レッドストーンリンク_を_片手_で_制御_できます。", - "item.create.linked_controller.tooltip.condition1": "右クリック", - "item.create.linked_controller.tooltip.behaviour1": "コントローラーを_オンオフ_します。_制御_がオンのときは_移動_できません。", - "item.create.linked_controller.tooltip.condition2": "スニークしながら右クリック", - "item.create.linked_controller.tooltip.behaviour2": "手動_設定画面_を開きます", - "item.create.linked_controller.tooltip.condition3": "レッドストーンリンク受信機を右クリックしたとき", - "item.create.linked_controller.tooltip.behaviour3": "_割り当てモード_をオンにします。_6つのコントロール_のうち1つを押してリンクの周波数に_割り当て_ます。", - "item.create.linked_controller.tooltip.condition4": "書見台を右クリックしたとき", - "item.create.linked_controller.tooltip.behaviour4": "コントローラーを書見台に設置し、簡単に使えるようにします。(スニークしながら右クリックで取り出せます)", - - "item.create.diving_helmet.tooltip": "潜水ヘルメット", - "item.create.diving_helmet.tooltip.summary": "_銅のバックタンク_と一緒に使うと、長時間_水中_で_呼吸_できるようになるヘルメット。", - "item.create.diving_helmet.tooltip.condition1": "装備したとき", - "item.create.diving_helmet.tooltip.behaviour1": "バックタンクからゆっくりと_圧縮空気_を排出しながら、_水中呼吸_の効果を供給します。", - - "item.create.copper_backtank.tooltip": "銅のバックタンク", - "item.create.copper_backtank.tooltip.summary": "圧縮空気を運ぶため_携帯タンク_", - "item.create.copper_backtank.tooltip.condition1": "装備したとき", - "item.create.copper_backtank.tooltip.behaviour1": "必要な装備に_圧縮空気_を供給します。", - "item.create.copper_backtank.tooltip.condition2": "設置して動力を供給したとき", - "item.create.copper_backtank.tooltip.behaviour2": "_圧縮空気_を_集めます_。速度は回転速度によって決まります。", - - "block.create.placard.tooltip": "プラカード", - "block.create.placard.tooltip.summary": "このイカした真鍮の壁掛けパネルにアイテムを飾ろう。からくりにつけても大丈夫!", - "block.create.placard.tooltip.condition1": "右クリックしたとき", - "block.create.placard.tooltip.behaviour1": "持っている_アイテム_をプラカードに_入れます_。すでに一致するアイテムが入っていた場合、短い_レッドストーン_信号を_発します_。", - "block.create.placard.tooltip.condition2": "殴ったとき", - "block.create.placard.tooltip.behaviour2": "額縁から今入っているアイテムを_外します", - - "block.create.flywheel.tooltip": "弾み車", - "block.create.flywheel.tooltip.summary": "この立派な真鍮の車輪で_機械_を_飾ろう_", - "block.create.flywheel.tooltip.condition1": "動力を供給したとき", - "block.create.flywheel.tooltip.behaviour1": "回り始めます", - - "item.create.diving_boots.tooltip": "潜水ブーツ", - "item.create.diving_boots.tooltip.summary": "海底を歩けるようになる_重いブーツ_。", - "item.create.diving_boots.tooltip.condition1": "装備したとき", - "item.create.diving_boots.tooltip.behaviour1": "_沈むのが早くなり_、_泳げなく_なります。その代わり、水中で_歩いたり_、_ジャンプ_したりできます。また、メカニカルベルトの影響を受けなくなります。", - - "item.create.crafting_blueprint.tooltip": "クラフトブループリント", - "item.create.crafting_blueprint.tooltip.summary": "壁に_貼り_、_材料_の_配置_を_指定_することで手作業によるクラフトを簡単にできます。各スロットが1つのレシピを表しています。", - "item.create.crafting_blueprint.condition1": "空きスロットを右クリックしたとき", - "item.create.crafting_blueprint.behaviour1": "_レシピ_や表示するアイテムを_設定_できる_クラフトメニュー_を開きます。", - "item.create.crafting_blueprint.condition2": "設定済みスロットを右クリックしたとき", - "item.create.crafting_blueprint.behaviour2": "_インベントリ_にある一致する材料で_設定したレシピ_を_クラフト_します。_スニーク_すれば最大_スタック_分を一気にクラフトできます", - - "item.create.minecart_coupling.tooltip": "トロッコ連結器", - "item.create.minecart_coupling.tooltip.summary": "壮大な列車を作るために_トロッコ_や_からくり車両_を_連結_しよう。", - "item.create.minecart_coupling.tooltip.condition1": "トロッコに使ったとき", - "item.create.minecart_coupling.tooltip.behaviour1": "_2台_のトロッコを連結します。それらは移動中に_一定_の_距離_を保とうします。", - - "item.create.experience_nugget.tooltip": "経験値の塊", - "item.create.experience_nugget.tooltip.summary": "_チャリン!_素晴らしい発明から、_発想_の欠片を。", - "item.create.experience_nugget.tooltip.condition1": "使ったとき", - "item.create.experience_nugget.tooltip.behaviour1": "アイテムと引き換えに中の_経験値_を取り出します", - - "block.create.peculiar_bell.tooltip": "風変わりな鐘", - "block.create.peculiar_bell.tooltip.summary": "装飾用の_真鍮の鐘_。_魂の炎_の真上に置くと、別の使い道が見つかるかも...", - - "block.create.haunted_bell.tooltip": "憑りつかれた鐘", - "block.create.haunted_bell.tooltip.summary": "ネザーに彷徨う魂が宿る、呪われた鐘", - "block.create.haunted_bell.tooltip.condition1": "持ったとき、鳴らしたとき", - "block.create.haunted_bell.tooltip.behaviour1": "_敵モブ_がスポーンする近くの_光のない場所_を示します", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "この挙動はレンチを使って変更できます", - "create.ponder.shared.storage_on_contraption": "構造物中の収納ブロックは自動的にドロップを拾います", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "動力源: 16 RPM", - "create.ponder.shared.movement_anchors": "シャーシや超粘着剤を使えば大きな構造物も動かせます", - "create.ponder.tag.redstone": "制御機械", - "create.ponder.tag.redstone.description": "レッドストーン工学に役立つ機械", - "create.ponder.tag.contraption_assembly": "ブロック組み立て用品", - "create.ponder.tag.contraption_assembly.description": "アニメーションして動く構造物を組み立てるための道具や機械", - "create.ponder.tag.fluids": "液体制御機械", - "create.ponder.tag.fluids.description": "液体の輸送や利用に役立つ機械", - "create.ponder.tag.decoration": "装飾", - "create.ponder.tag.decoration.description": "主に装飾に使うブロック", - "create.ponder.tag.windmill_sails": "風車ベアリング用の帆", - "create.ponder.tag.windmill_sails.description": "風車につける構造物を組み立てたときに帆にカウントされるブロック。どのブロックを使っても効率は同じ", - "create.ponder.tag.arm_targets": "メカニカルアームの対象", - "create.ponder.tag.arm_targets.description": "メカニカルアームの搬入元または搬出先にできる機械/ブロック", - "create.ponder.tag.kinetic_appliances": "作業機械", - "create.ponder.tag.kinetic_appliances.description": "回転力を利用する機械", - "create.ponder.tag.kinetic_sources": "原動機", - "create.ponder.tag.kinetic_sources.description": "回転力を生み出す機械", - "create.ponder.tag.movement_anchor": "からくり機械", - "create.ponder.tag.movement_anchor.description": "取り付けたブロック構造物を様々な方法で動かすからくりを作る機械", - "create.ponder.tag.kinetic_relays": "伝達機械", - "create.ponder.tag.kinetic_relays.description": "回転力の伝達に役立つ機械", - "create.ponder.tag.contraption_actor": "からくり構造部品", - "create.ponder.tag.contraption_actor.description": "ブロックを動かす機械に取り付けたときに特別な動作をする機械", - "create.ponder.tag.creative": "クリエイティブ限定", - "create.ponder.tag.creative.description": "サバイバルモードでは通常入手できない機械", - "create.ponder.tag.display_sources": "ディスプレイリンクの情報源", - "create.ponder.tag.display_sources.description": "ディスプレイリンクでデータを読み取れる機械/ブロック", - "create.ponder.tag.logistics": "輸送機械", - "create.ponder.tag.logistics.description": "アイテムの運搬を補助する機械", - "create.ponder.tag.display_targets": "ディスプレイリンクの表示先", - "create.ponder.tag.display_targets.description": "ディスプレイリンクから受け取ったデータを処理・表示できる機械/ブロック", - "create.ponder.tag.train_related": "鉄道用品", - "create.ponder.tag.train_related.description": "からくり鉄道の建築、管理に使う機械", - - "create.ponder.analog_lever.header": "アナログレバーによる信号制御", - "create.ponder.analog_lever.text_1": "アナログレバーはコンパクトに正確なレッドストーン動力を出力できます。", - "create.ponder.analog_lever.text_2": "右クリックでレッドストーン強度を上げられます。", - "create.ponder.analog_lever.text_3": "スニークしながら右クリックでレッドストーン強度を下げられます。", - - "create.ponder.andesite_tunnel.header": "安山岩トンネルの使い方", - "create.ponder.andesite_tunnel.text_1": "安山岩トンネルは、ベルトを隠せます", - "create.ponder.andesite_tunnel.text_2": "安山岩トンネルが横につながっていると...", - "create.ponder.andesite_tunnel.text_3": "...通過するアイテムスタックから正確に1つのアイテムを分割します", - "create.ponder.andesite_tunnel.text_4": "残ったものは、そのルートを進み続けます", - - "create.ponder.auto_schedule.header": "鉄道駅 & 時刻表", - "create.ponder.auto_schedule.text_1": "時刻表は運転手に行先を伝えます", - "create.ponder.auto_schedule.text_2": "列車が停車するたびにコンパレーターはレッドストーン信号を発します", - "create.ponder.auto_schedule.text_3": "駅には表示された方向からしか近づけないことに注意してください", - "create.ponder.auto_schedule.text_4": "また、駅は新しい時刻表を自動で割り当てることもできます", - "create.ponder.auto_schedule.text_5": "時刻表を駅ブロックに置くと、自動でそれを停車している列車にコピーします", - "create.ponder.auto_schedule.text_6": "手動で渡す場合と異なり、運転手がアイテムを持ち運ぶことはありません", - - "create.ponder.basin.header": "鉢によるアイテム加工", - "create.ponder.basin.text_1": "鉢には素材となるアイテムや液体を入れられます", - "create.ponder.basin.text_2": "鉢は完成品アイテムを斜め下へ搬出しようとします", - "create.ponder.basin.text_3": "搬出できるブロックが存在する場合、鉢には搬出用の蛇口が表示されます", - "create.ponder.basin.text_4": "搬出先のブロックにはいくつかの選択肢があります", - "create.ponder.basin.text_5": "搬出したアイテムは下の収納ブロックに入ります", - "create.ponder.basin.text_6": "搬出先がない場合、鉢は完成品アイテムを保持します", - "create.ponder.basin.text_7": "これは、完成品アイテムを材料として再利用する必要がある場合に役立ちます", - "create.ponder.basin.text_8": "完成品アイテムは、鉢から搬出する必要があります", - "create.ponder.basin.text_9": "未処理のアイテムが搬出されないように、フィルターが必要になる場合があります", - - "create.ponder.bearing_modes.header": ":メカニカルベアリングの動作モード", - "create.ponder.bearing_modes.text_1": "止まったとき、ベアリングは格子に沿った近い角度に構造物を配置します", - "create.ponder.bearing_modes.text_2": "通常のブロックに戻らないように設定したり、開始時の角度のみブロックに戻るように設定したりできます", - - "create.ponder.belt_casing.header": "ケース入りベルト", - "create.ponder.belt_casing.text_1": "真鍮か安山岩ケーシングを使ってメカニカルベルトを飾れます", - "create.ponder.belt_casing.text_2": "ケーシングはレンチを使って外せます", - - "create.ponder.belt_connector.header": "メカニカルベルトの使い方", - "create.ponder.belt_connector.text_1": "メカニカルベルトを持って2つのシャフトを右クリックすると、シャフトにベルトコンベアを繋げて設置されます", - "create.ponder.belt_connector.text_2": "誤ったシャフトをクリックしてしまった場合、スニークしながら右クリックでキャンセルできます", - "create.ponder.belt_connector.text_3": "ベルト内のどこでも、シャフトを追加できます", - "create.ponder.belt_connector.text_4": "ベルトを介して接続したシャフトは、同じ速度・方向で回転します", - "create.ponder.belt_connector.text_5": "追加したシャフトは、レンチで取り除けます", - "create.ponder.belt_connector.text_6": "メカニカルベルトは染色して見栄えをよくできます", - - "create.ponder.belt_directions.header": "メカニカルベルトの有効な向きについて", - "create.ponder.belt_directions.text_1": "ベルトは自由な方向に接続できるわけではありません", - "create.ponder.belt_directions.text_2": "1.水平", - "create.ponder.belt_directions.text_3": "2.斜め", - "create.ponder.belt_directions.text_4": "3.垂直", - "create.ponder.belt_directions.text_5": "4.垂直方向のシャフトを水平に", - "create.ponder.belt_directions.text_6": "これらはすべて接続できる方向です。ベルトの長さは2~20ブロックの間で自由に接続できます", - - "create.ponder.belt_transport.header": "メカニカルベルトによる運搬", - "create.ponder.belt_transport.text_1": "ベルトを稼働させると、アイテムやエンティティを運べます", - "create.ponder.belt_transport.text_2": "素手で右クリックすると、ベルトからアイテムを取り出せます", - - "create.ponder.blaze_burner.header": "ブレイズバーナーへの餌やり", - "create.ponder.blaze_burner.text_1": "ブレイズバーナーは、鉢で加工するアイテムを加熱できます", - "create.ponder.blaze_burner.text_2": "その為には、ブレイズに燃料を与える必要があります", - "create.ponder.blaze_burner.text_3": "ブレイズケーキを与えると、バーナーはさらに火力を出せます", - "create.ponder.blaze_burner.text_4": "供給作業は、デプロイヤーやメカニカルアームで自動化できます", - - "create.ponder.brass_funnel.header": "真鍮ファンネル", - "create.ponder.brass_funnel.text_1": "安山岩ファンネルでは、1回につき1つのアイテムしか搬出できません", - "create.ponder.brass_funnel.text_2": "真鍮ファンネルは、最大で1スタックのアイテムを搬出できます", - "create.ponder.brass_funnel.text_3": "フィルタースロットを見ながらスクロールすると、取り出すアイテム数を正確に調整できます", - "create.ponder.brass_funnel.text_4": "フィルタースロットにアイテムを設定すると、ファンネルは一致するアイテムのみを運搬できます", - - "create.ponder.brass_tunnel.header": "真鍮トンネルの使い方", - "create.ponder.brass_tunnel.text_1": "真鍮トンネルは、ベルトを隠せます", - "create.ponder.brass_tunnel.text_2": "真鍮トンネルには、搬出入面それぞれにフィルタースロットがあります", - "create.ponder.brass_tunnel.text_3": "搬入側のフィルターは、単純に一致しないアイテムを搬入しないようにします", - "create.ponder.brass_tunnel.text_4": "搬出側のフィルターは、搬出するアイテムを種類別に分類できます", - "create.ponder.brass_tunnel.text_5": "通過するアイテムが複数の口から搬出できる場合は、モードによってどのように搬出されるかが決まります", - "create.ponder.brass_tunnel.text_6": "並べられた複数のベルト上の真鍮トンネルは接続されます", - "create.ponder.brass_tunnel.text_7": "搬入したアイテムは、接続されているすべての搬出口に分配されます", - "create.ponder.brass_tunnel.text_8": "アイテムをトンネルへ直接搬入することもできます", - - "create.ponder.brass_tunnel_modes.header": "真鍮トンネルの動作モード", - "create.ponder.brass_tunnel_modes.text_1": "真鍮トンネルはレンチを使って分配モードを変更できます", - "create.ponder.brass_tunnel_modes.text_10": "「同期」は、真鍮トンネルのデフォルト設定です", - "create.ponder.brass_tunnel_modes.text_11": "アイテムはグループ内の全てのトンネルがアイテムを搬入できる場合のみ通過を許可します", - "create.ponder.brass_tunnel_modes.text_12": "これにより、影響を受ける全てのベルトに同じ割合でアイテムを供給できます", - "create.ponder.brass_tunnel_modes.text_2": "「スタック分割」は、アイテムを通せる搬出口の間でアイテムスタックを均等に分配しようとします", - "create.ponder.brass_tunnel_modes.text_3": "搬出口がアイテムを通せない場合はスキップされます ", - "create.ponder.brass_tunnel_modes.text_4": "「強制スタック分割」は搬出をスキップせず、それができるようになるまで待機します", - "create.ponder.brass_tunnel_modes.text_5": "「順繰り分配」 はスタックを分割せず、それぞれの搬出口から順番に搬出します ", - "create.ponder.brass_tunnel_modes.text_6": "繰り返しになりますが、搬出口がアイテムを通せない場合はスキップされます", - "create.ponder.brass_tunnel_modes.text_7": "「強制順繰り分配」は、搬出をスキップしません", - "create.ponder.brass_tunnel_modes.text_8": "「近い所を優先」アイテムの搬入口に最も近い搬出口から優先して分配します ", - "create.ponder.brass_tunnel_modes.text_9": "「ランダム」は、スタック全体をランダムに選択した搬出口に分配します ", - - "create.ponder.cart_assembler.header": "トロッコアセンブラによる構造物の移動", - "create.ponder.cart_assembler.text_1": "レッドストーン信号を受けたアセンブラは通過するトロッコに、取り付けられた構造物を取り付けます", - "create.ponder.cart_assembler.text_2": "レッドストーン信号を受けていない場合、通過するトロッコの構造物を取り外し、ブロックへ戻します", - "create.ponder.cart_assembler.text_3": "トロッコにレンチを使うと、構造物を付けたまま別の場所へ運べます", - - "create.ponder.cart_assembler_dual.header": "列車を組み立てる", - "create.ponder.cart_assembler_dual.text_1": "2つのトロッコアセンブラが構造物を共有している場合...", - "create.ponder.cart_assembler_dual.text_2": "...どちらかにレッドストーン信号を与えると、列車が組み立てられます", - "create.ponder.cart_assembler_dual.text_3": "トロッコ連結器で接続したトロッコと同様の動作をします", - - "create.ponder.cart_assembler_modes.header": "からくり付きトロッコの方向設定", - "create.ponder.cart_assembler_modes.text_1": "トロッコの構造物は、トロッコの動きに合わせて回転します", - "create.ponder.cart_assembler_modes.text_2": "この矢印は、構造物のどちら側が前面かを示します", - "create.ponder.cart_assembler_modes.text_3": "アセンブラが「常に向きを固定する」に設定されている場合、からくりの向きは変わりません", - - "create.ponder.cart_assembler_rails.header": "その他のトロッコとレールの種類", - "create.ponder.cart_assembler_rails.text_1": "通常のレールに設置したトロッコアセンブラは、通過するカートの動きに影響を与えません", - "create.ponder.cart_assembler_rails.text_2": "パワードレールやコントローラーレールでは、レッドストーン信号を受けるまでトロッコは固定されます", - "create.ponder.cart_assembler_rails.text_3": "他のトロッコを使うこともできます", - "create.ponder.cart_assembler_rails.text_4": "かまど付きトロッコは、構造物の収納ブロックから燃料を確保します", - - "create.ponder.chain_drive.header": "ケース入りチェーンドライブによる回転力の伝達", - "create.ponder.chain_drive.text_1": "チェーンドライブは、一列に並べると回転を伝達します", - "create.ponder.chain_drive.text_2": "このように接続された全てのシャフトは、回転方向が同じです", - "create.ponder.chain_drive.text_3": "列の任意の部分を90度方向を変えて設置できます", - - "create.ponder.chain_gearshift.header": "チェーンギアシフトによる回転速度の制御", - "create.ponder.chain_gearshift.text_1": "信号を受けていないチェーンギアシフトは、チェーンドライブと同じように動作します", - "create.ponder.chain_gearshift.text_2": "信号を受けている時は、列内の他のチェーンドライブに伝達される速度が2倍になります", - "create.ponder.chain_gearshift.text_3": "信号を受けているチェーンギアシフトが動力源でない場合、速度が半分になります", - "create.ponder.chain_gearshift.text_4": "いずれの場合も、列内のチェーンドライブは常に「信号入りチェーンギアシフト」の2倍の速度で動作します", - "create.ponder.chain_gearshift.text_5": "レッドストーン信号の強度で、比率を1と2の間でより正確に調整できます", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "シュートによる下方向へ運搬", - "create.ponder.chute.text_1": "シュートは、収納ブロックから垂直方向にアイテムを運搬できます", - "create.ponder.chute.text_2": "レンチを使って、窓を付けられます", - "create.ponder.chute.text_3": "シュートを側面に配置すると、斜めに接続されます", - - "create.ponder.chute_upward.header": "シュートによる上方向へ運搬", - "create.ponder.chute_upward.text_1": "シュートの上部または下部にファンを配置すると、アイテムを上方向へ運搬できます", - "create.ponder.chute_upward.text_2": "エンジニアのゴーグルを付けてシュートを見ると、移動方向が表示されます", - "create.ponder.chute_upward.text_3": "ブロックで詰まっている端では、アイテムを側面から搬出入する必要があります", - - "create.ponder.clockwork_bearing.header": "時計仕掛けのベアリングを使った構造物のアニメーション", - "create.ponder.clockwork_bearing.text_1": "時計仕掛けのベアリングは、前面にブロックを取り付けられます", - "create.ponder.clockwork_bearing.text_2": "回転力を受けると、現在の時間に合わせて構造物が回転します", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "ベアリングを右クリックして、構造物のアニメーションを開始・停止します", - "create.ponder.clockwork_bearing.text_6": "時針の前に、2つ目の構造物を追加できます", - "create.ponder.clockwork_bearing.text_7": "2つの構造物が超粘着剤などで取り付けられていないか確認してください", - "create.ponder.clockwork_bearing.text_8": "2つ目の構造物は分針として回転します", - - "create.ponder.clutch.header": "クラッチによる回転力の制御", - "create.ponder.clutch.text_1": "クラッチはまっすぐ回転を伝達します", - "create.ponder.clutch.text_2": "レッドストーン信号を与えると、回転の伝達が止まります", - - "create.ponder.cog_speedup.header": "歯車による回転速度変化", - "create.ponder.cog_speedup.text_1": "大小の歯車は斜めに接続できます", - "create.ponder.cog_speedup.text_2": "大きな歯車から歯車に接続すると、伝達先の回転速度が2倍になります", - "create.ponder.cog_speedup.text_3": "逆に接続すると、伝達先の回転速度が半分になります", - - "create.ponder.cogwheel.header": "歯車による回転力の伝達", - "create.ponder.cogwheel.text_1": "歯車は隣接する歯車へ回転力を伝達します", - "create.ponder.cogwheel.text_2": "このように連結した隣り合うシャフトは、反対方向に回転します", - - "create.ponder.cogwheel_casing.header": "ケース入り歯車", - "create.ponder.cogwheel_casing.text_1": "真鍮や安山岩のケーシングは歯車を飾ることもできます", - "create.ponder.cogwheel_casing.text_2": "ケース入りにした歯車に、シャフトを繋ごうとしても繋がりません", - "create.ponder.cogwheel_casing.text_3": "レンチを使って繋がるかどうか切り替えることもできます", - - "create.ponder.creative_fluid_tank.header": "クリエイティブ液体タンク", - "create.ponder.creative_fluid_tank.text_1": "クリエイティブ液体タンクは、液体を無限に供給できます", - "create.ponder.creative_fluid_tank.text_2": "液体容器アイテムで右クリックで液体を指定できます", - "create.ponder.creative_fluid_tank.text_3": "液体ネットワークはタンクから指定した液体を無限に吸いだせます", - "create.ponder.creative_fluid_tank.text_4": "クリエイティブ液体タンクに押し入れた液体は消滅します", - - "create.ponder.creative_motor.header": "クリエイティブモーターによる回転力の生成", - "create.ponder.creative_motor.text_1": "クリエイティブモーターは、コンパクトで出力を調整できる原動機です", - "create.ponder.creative_motor.text_2": "背面パネルを見ながらスクロールすると、モーターの回転速度を変更できます", - - "create.ponder.creative_motor_mojang.header": "Mojangの謎", - - "create.ponder.crushing_wheels.header": "破砕ホイールによるアイテム加工", - "create.ponder.crushing_wheels.text_1": "一対の破砕ホイールは、非常に効果的にアイテムを粉砕できます", - "create.ponder.crushing_wheels.text_2": "動作には、互いに反対方向に回転させる必要があります", - "create.ponder.crushing_wheels.text_3": "上からアイテムを投げ入れたりして、搬入すると加工されます", - "create.ponder.crushing_wheels.text_4": "アイテムの搬出入を自動化することもできます", - - "create.ponder.deployer.header": "デプロイヤーの使い方", - "create.ponder.deployer.text_1": "回転力を供給したデプロイヤーは、プレイヤーの動作を模倣できます", - "create.ponder.deployer.text_10": "前面へアイテムを右クリックして、アイテムを搬出入できます", - "create.ponder.deployer.text_11": "自動でアイテムを搬出入することもできます", - "create.ponder.deployer.text_12": "デプロイヤーはフィルタースロットを持っています", - "create.ponder.deployer.text_13": "フィルターを設定すると、一致するアイテムを持っている時だけ稼働します", - "create.ponder.deployer.text_14": "また、フィルターに一致するアイテムのみが搬入されるようになり...", - "create.ponder.deployer.text_15": "...一致しないアイテムのみが搬出されます", - "create.ponder.deployer.text_2": "動作は、常に手前2ブロックの位置へ行われます", - "create.ponder.deployer.text_3": "真正面のブロックが邪魔になることはありません", - "create.ponder.deployer.text_4": "デプロイヤーは以下の動作に使えます", - "create.ponder.deployer.text_5": "ブロックの設置", - "create.ponder.deployer.text_6": "アイテムの使用", - "create.ponder.deployer.text_7": "ブロックの使用", - "create.ponder.deployer.text_8": "ブロックの収穫", - "create.ponder.deployer.text_9": "モブへの攻撃", - - "create.ponder.deployer_contraption.header": "からくりに組み込んでのデプロイヤーの使い方", - "create.ponder.deployer_contraption.text_1": "からくりの一部として、デプロイヤーを稼働させると...", - "create.ponder.deployer_contraption.text_2": "...稼働した場所ごとに稼働し、からくり内の収納ブロックのアイテムを使用します", - "create.ponder.deployer_contraption.text_3": "フィルタースロットを使って、どのアイテムを使用するか指定できます", - - "create.ponder.deployer_modes.header": "デプロイヤーの動作モード", - "create.ponder.deployer_modes.text_1": "デフォルトでは、デプロイヤーは右クリックの動作を模倣します", - "create.ponder.deployer_modes.text_2": "レンチを使えば、右クリックの動作を模倣するように設定できます", - - "create.ponder.deployer_processing.header": "デプロイヤーによるアイテムの処理", - "create.ponder.deployer_processing.text_1": "装着したアイテムで、デプロイヤーの先にあるアイテムを処理できます", - "create.ponder.deployer_processing.text_2": "加工したいアイテムはドロップしたり、デプロイヤーの下のデポに置いてください", - "create.ponder.deployer_processing.text_3": "ベルトでアイテムを供給すると", - "create.ponder.deployer_processing.text_4": "デプロイヤーが自動でアイテムを止め、加工します。", - - "create.ponder.deployer_redstone.header": "レッドストーン信号によるデプロイヤーの制御", - "create.ponder.deployer_redstone.text_1": "レッドストーン信号を受けている間、デプロイヤーは稼働しません", - "create.ponder.deployer_redstone.text_2": "デプロイヤーは停止する前に、開始したサイクルは終了させます", - "create.ponder.deployer_redstone.text_3": "その為、反転したパルス信号を使ってちょうど1サイクルだけ稼働させられます", - - "create.ponder.depot.header": "デポの使い方", - "create.ponder.depot.text_1": "デポは動かないメカニカルベルトのようなブロックです", - "create.ponder.depot.text_2": "右クリックして、手動でアイテムを搬出入できます", - "create.ponder.depot.text_3": "メカニカルベルトのように、載せたアイテムを加工できます", - "create.ponder.depot.text_4": "また、メカニカルアームにアイテムを供給することもできます", - - "create.ponder.display_board.header": "ディスプレイボードの使い方", - "create.ponder.display_board.text_1": "ディスプレイボードは看板に代わる、より拡張性の高いブロックです", - "create.ponder.display_board.text_2": "稼働には回転力が必要です", - "create.ponder.display_board.text_3": "文字の表示には名札を使うか...", - "create.ponder.display_board.text_4": "ディスプレイリンクを通して行えます", - "create.ponder.display_board.text_5": "ボードは、行ごとにそれぞれ染料で染色できます", - "create.ponder.display_board.text_6": "素手で右クリックすると、リセットできます", - - "create.ponder.display_link.header": "ディスプレイリンクの設置", - "create.ponder.display_link.text_1": "ディスプレイリンクは、変化する情報の視覚化に使えます", - "create.ponder.display_link.text_2": "はじめに、対象となるディスプレイを右クリックし...", - "create.ponder.display_link.text_3": "...それから情報を読み出すブロックに取り付けます", - "create.ponder.display_link.text_4": "選択・設定をするためにUIを開いてください", - "create.ponder.display_link.text_5": "これで、ディスプレイがリンクからの情報を受信するようになりました", - "create.ponder.display_link.text_6": "全てのブロックが情報源として使えるわけではありません", - "create.ponder.display_link.text_7": "互換性のあるブロックはそれぞれ固有の情報を提供します", - "create.ponder.display_link.text_8": "ディスプレイリンクは、複数の異なるディスプレイと連動できます", - - "create.ponder.display_link_redstone.header": "レッドストーンによる制御", - "create.ponder.display_link_redstone.text_1": "レッドストーン信号を受ける間、ディスプレイリンクは情報の更新を停止します", - "create.ponder.display_link_redstone.text_2": "信号が切れると、タイマーがリセットされ、新しい情報が即座に送信されます", - "create.ponder.display_link_redstone.text_3": "ただし、情報元から発せられるレッドストーン信号はリンクに影響を与えません", - - "create.ponder.empty_blaze_burner.header": "空のブレイズバーナーの使い方", - "create.ponder.empty_blaze_burner.text_1": "空のバーナーで右クリックするとブレイズを捕獲できます", - "create.ponder.empty_blaze_burner.text_2": "また、ブレイズはスポーンブロックから直接捕獲することもできます", - "create.ponder.empty_blaze_burner.text_3": "これで、様々な機械で利用できる理想的な熱源が得られます", - "create.ponder.empty_blaze_burner.text_4": "空のブレイズバーナーは火打石と打ち金を使って火を付ければ装飾にも使えます", - "create.ponder.empty_blaze_burner.text_5": "さらに、魂の宿ったアイテムを使うことで炎を変化させられます", - "create.ponder.empty_blaze_burner.text_6": "しかし、これは加工用の熱源には適していません", - - "create.ponder.encased_fluid_pipe.header": "ケース入り液体パイプ", - "create.ponder.encased_fluid_pipe.text_1": "銅ケーシングで液体パイプを飾れます", - "create.ponder.encased_fluid_pipe.text_2": "ただの飾りではなく、ケース入りパイプは接続がロックされます", - "create.ponder.encased_fluid_pipe.text_3": "隣接するブロックの設置や破壊などの更新に反応しなくなります", - - "create.ponder.fan_direction.header": "ケース入りファンの気流", - "create.ponder.fan_direction.text_1": "ケース入りファンは、回転力を利用して気流を生み出します", - "create.ponder.fan_direction.text_2": "気流の強さと方向は、供給される回転力によって決まります", - - "create.ponder.fan_processing.header": "ケース付きファンによるアイテム加工", - "create.ponder.fan_processing.text_1": "溶岩を通過した気流は、加熱されます", - "create.ponder.fan_processing.text_2": "この気流に当てられたアイテムは精錬されます", - "create.ponder.fan_processing.text_3": "ただし、食品は焼却されてしまいます", - "create.ponder.fan_processing.text_4": "食品加工には、代わりに火を使った燻製気流を使ってください", - "create.ponder.fan_processing.text_5": "水を通過する気流は、洗浄気流になります", - "create.ponder.fan_processing.text_6": "この気流を使えば、面白い加工ができます", - "create.ponder.fan_processing.text_7": "ファンの速度は処理速度とは関係がなく、範囲のみが変わります", - "create.ponder.fan_processing.text_8": "ファンによる加工は、デポやベルト上のアイテムにも行われます", - - "create.ponder.fluid_pipe_flow.header": "銅パイプを使った液体の移動", - "create.ponder.fluid_pipe_flow.text_1": "液体パイプは2つ以上の液体源と輸送先を繋げられます", - "create.ponder.fluid_pipe_flow.text_2": "レンチを使うと、まっすぐなパイプに窓を付けられます", - "create.ponder.fluid_pipe_flow.text_3": "窓付きパイプは側面と隣接するパイプとつながりません", - "create.ponder.fluid_pipe_flow.text_4": "メカニカルポンプを使えば液体を輸送できます", - "create.ponder.fluid_pipe_flow.text_5": "はじめは液体が輸送されません", - "create.ponder.fluid_pipe_flow.text_6": "流れが終点まで届くと徐々に輸送されていきます", - "create.ponder.fluid_pipe_flow.text_7": "つまり、パイプブロック自体に液体は入っていないということです", - - "create.ponder.fluid_pipe_interaction.header": "液体容器の排出と充填", - "create.ponder.fluid_pipe_interaction.text_1": "液体ネットワークは終点でさまざまなブロックとやりとりできます", - "create.ponder.fluid_pipe_interaction.text_2": "液体を溜めることができれば、どのようなブロックでも液体の搬入・搬出ができます", - "create.ponder.fluid_pipe_interaction.text_3": "開いているパイプの端の目の前の液体ブロックは吸い込めます", - "create.ponder.fluid_pipe_interaction.text_4": "また、開いたスペースに液体ブロックを設置できます", - "create.ponder.fluid_pipe_interaction.text_5": "パイプは、いくつかのブロックから直接液体を吸い込めます", - - "create.ponder.fluid_tank_sizes.header": "液体タンクの寸法", - "create.ponder.fluid_tank_sizes.text_1": "液体タンクは複数組み合わせて容量を増やせます。", - "create.ponder.fluid_tank_sizes.text_2": "横幅は最大3ブロック", - "create.ponder.fluid_tank_sizes.text_3": "高さは30ブロック以上重ねられます", - "create.ponder.fluid_tank_sizes.text_4": "レンチを使って、タンクの窓を付け外しできます", - - "create.ponder.fluid_tank_storage.header": "液体タンクへの液体の貯蔵", - "create.ponder.fluid_tank_storage.text_1": "液体タンクは大量の液体を貯蔵できます", - "create.ponder.fluid_tank_storage.text_2": "どの方向からでも液体を搬出入できます", - "create.ponder.fluid_tank_storage.text_3": "コンパレーターで液体量を測れます", - "create.ponder.fluid_tank_storage.text_4": "しかし、サバイバルモードでは手動で液体を搬出入できません。", - "create.ponder.fluid_tank_storage.text_5": "鉢、アイテム排液口、アイテム注液口などを使えばアイテムから液体を搬出入できます。", - - "create.ponder.funnel_compat.header": "ファンネルの互換性", - "create.ponder.funnel_compat.text_1": "ファンネルは、他のいくつかの機械とも相性がいいです", - "create.ponder.funnel_compat.text_2": "上向きのメカニカルソー", - "create.ponder.funnel_compat.text_3": "デポ", - "create.ponder.funnel_compat.text_4": "アイテム排液口など", - - "create.ponder.funnel_direction.header": "運搬の方向", - "create.ponder.funnel_direction.text_1": "通常の配置では、収納ブロックからアイテムを搬出します", - "create.ponder.funnel_direction.text_2": "スニークしながら設置すると、収納ブロックにアイテムを搬入します", - "create.ponder.funnel_direction.text_3": "レンチを使って、設置後にファンネルの動作モードを変えられます", - "create.ponder.funnel_direction.text_4": "ほとんどの方向で同じことができます", - "create.ponder.funnel_direction.text_5": "ベルト上のファンネルは、ベルトの移動方向に応じて搬入/搬出が決まります", - - "create.ponder.funnel_intro.header": "ファンネルの使い方", - "create.ponder.funnel_intro.text_1": "ファンネルは、収納ブロックのアイテムを運搬するのに使います", - - "create.ponder.funnel_redstone.header": "レッドストーンによる制御", - "create.ponder.funnel_redstone.text_1": "レッドストーン信号によって、ファンネルが動作を防げます", - - "create.ponder.funnel_transfer.header": "直接運搬", - "create.ponder.funnel_transfer.text_1": "ファンネルでは、閉じた収納ブロック間を直接運搬することはできません", - "create.ponder.funnel_transfer.text_2": "この様な場合は、シュートやスマートシュートの方が適しています", - "create.ponder.funnel_transfer.text_3": "また水平方向の運搬も同様で、この場合メカニカルベルトの方が適しています", - - "create.ponder.gantry_carriage.header": "ガントリーキャリッジの使い方", - "create.ponder.gantry_carriage.text_1": "ガントリーキャリッジは、ガントリーシャフトに取り付けてスライドできます", - "create.ponder.gantry_carriage.text_2": "ガントリーは、取り付けられたブロックを動かします", - - "create.ponder.gantry_cascaded.header": "立体ガントリー", - "create.ponder.gantry_cascaded.text_1": "ガントリーシャフトは、超粘着剤を使わずにキャリッジに取り付けられます", - "create.ponder.gantry_cascaded.text_2": "そのガントリーシャフトに取り付けたキャリッジも同様です", - "create.ponder.gantry_cascaded.text_3": "このように、ガントリーを立体的に接続すると、複数の移動軸をカバーできます", - - "create.ponder.gantry_direction.header": "ガントリーの移動方向", - "create.ponder.gantry_direction.text_1": "ガントリーシャフトは、向きを反対に設置できます", - "create.ponder.gantry_direction.text_2": "キャリッジの移動方向は、シャフトの向きによって決まります", - "create.ponder.gantry_direction.text_3": "また、シャフトの回転方向によっても決まります", - "create.ponder.gantry_direction.text_4": "キャリッジへ伝達する回転力も同じルールが適用されます", - - "create.ponder.gantry_redstone.header": "ガントリーによる回転力の伝達", - "create.ponder.gantry_redstone.text_1": "レッドストーン信号を受けたガントリーシャフトは、キャリッジの移動を停止します", - "create.ponder.gantry_redstone.text_2": "代わりに、その回転力をキャリッジの出力軸に伝達します", - - "create.ponder.gantry_shaft.header": "ガントリーシャフトの使い方", - "create.ponder.gantry_shaft.text_1": "ガントリーシャフトは、ガントリーからくりの基本となるものです。取り付けられたキャリッジはこのシャフトに沿って移動します", - "create.ponder.gantry_shaft.text_2": "ガントリーによるからくりは、取り付けたブロックを動かせます", - - "create.ponder.gearbox.header": "ギアボックスによる回転力の伝達", - "create.ponder.gearbox.text_1": "回転軸の向きを変えようとすると、すぐに機構がかさばってしまいます", - "create.ponder.gearbox.text_2": "これをコンパクトにしたものがギアボックスです", - "create.ponder.gearbox.text_3": "直角に曲げて伝達すると、鏡映しの方向に回転します", - "create.ponder.gearbox.text_4": "まっすぐ伝達すると、回転方向が逆になります", - - "create.ponder.gearshift.header": "ギアシフトによる回転力の制御", - "create.ponder.gearshift.text_1": "ギアシフトは、まっすぐ回転を伝達します", - "create.ponder.gearshift.text_2": "レッドストーン信号を受けると、回転方向を逆に伝達します", - - "create.ponder.hand_crank.header": "ハンドクランクによる回転力の生成", - "create.ponder.hand_crank.text_1": "ハンドクランクは手動で回転力を生み出す機械です", - "create.ponder.hand_crank.text_2": "右クリックし続けると、反時計回りに回転します", - "create.ponder.hand_crank.text_3": "回転速度は比較的速めです", - "create.ponder.hand_crank.text_4": "スニークしながら右クリックし続けると、時計回りに回転します", - - "create.ponder.hose_pulley.header": "ホースプーリーを使った液体の吸入・放出", - "create.ponder.hose_pulley.text_1": "ホースプーリーは、大規模な液体の吸入や放出に使います", - "create.ponder.hose_pulley.text_2": "回転力の出入口はプーリーのホースの高さを変えるのに使います", - "create.ponder.hose_pulley.text_3": "回転方向を逆にするとホースが収納されます", - "create.ponder.hose_pulley.text_4": "反対側にはパイプを接続できます", - "create.ponder.hose_pulley.text_5": "接続された液体ネットワークでプーリーに液体を供給すると、放出できます", - "create.ponder.hose_pulley.text_6": "また、プーリーから吸い出すことで、代わりに吸入できます", - "create.ponder.hose_pulley.text_7": "プーリーの吸入・放出速度は液体ネットワークの性能で決まります", - - "create.ponder.hose_pulley_infinite.header": "大規模な液体の無限の吸入・放出", - "create.ponder.hose_pulley_infinite.text_1": "ホースプーリーを十分に大きな海に設置すると", - "create.ponder.hose_pulley_infinite.text_2": "海に影響を与えずに液体を吸入・放出できます", - "create.ponder.hose_pulley_infinite.text_3": "つまり、液体ネットワークはこのプーリーから液体を無限に搬出入できます", - - "create.ponder.hose_pulley_level.header": "ホースプーリーの吸入・放出レベル", - "create.ponder.hose_pulley_level.text_1": "完全に収納された状態では、ホースプーリーは稼働しません", - "create.ponder.hose_pulley_level.text_2": "上から下に水を吸入します", - "create.ponder.hose_pulley_level.text_3": "表面の高さはホースのすぐ下になります", - "create.ponder.hose_pulley_level.text_4": "下から上に向かって放出します", - "create.ponder.hose_pulley_level.text_5": "ホースの端より上に放出されることはありません", - - "create.ponder.item_drain.header": "アイテム排液口で液体容器を空にする", - "create.ponder.item_drain.text_1": "アイテム排液口はアイテムから液体を取り出せます", - "create.ponder.item_drain.text_2": "右クリックすると、持っているアイテムの中の液体を注げます", - "create.ponder.item_drain.text_3": "横からアイテムを入れると...", - "create.ponder.item_drain.text_4": "...中に詰まった液体を出しながら横に転がっていきます", - "create.ponder.item_drain.text_5": "液体ネットワークで、排液口から液体を取り出せます", - - "create.ponder.item_vault_sizes.header": "アイテム保管庫の寸法", - "create.ponder.item_vault_sizes.text_1": "アイテム保管庫はいくつか繋げて容量を増やせます", - "create.ponder.item_vault_sizes.text_2": "そのベースとなる正方形の辺の長さは最大3ブロックまで...", - "create.ponder.item_vault_sizes.text_3": "...長さはその三倍まで伸ばせます", - - "create.ponder.item_vault_storage.header": "保管庫によるアイテムの保管", - "create.ponder.item_vault_storage.text_1": "アイテム保管庫は、大量のアイテムを保管できます", - "create.ponder.item_vault_storage.text_2": "ただし、アイテムを手動で搬出入することはできません", - "create.ponder.item_vault_storage.text_3": "アイテム運搬用の機械ならどれを使っても搬入と...", - "create.ponder.item_vault_storage.text_4": "搬出ができます", - - "create.ponder.large_cogwheel.header": "大きな歯車による回転力の伝達", - "create.ponder.large_cogwheel.text_1": "大きな歯車は、直角に接続できます", - "create.ponder.large_cogwheel.text_2": "回転力の回転軸を変えて伝達するのに役立ちます", - - "create.ponder.linear_chassis_attachment.header": "リニアシャーシによるブロックの取り付け", - "create.ponder.linear_chassis_attachment.text_1": "リニアシャーシの特定の面は特殊な粘着面にできます", - "create.ponder.linear_chassis_attachment.text_2": "もう一度クリックすると、反対側の面も粘着面になります", - "create.ponder.linear_chassis_attachment.text_3": "素手でスニークしながら右クリックすると粘着剤を剥がせます", - "create.ponder.linear_chassis_attachment.text_4": "リニアシャーシの特殊な粘着面は、ブロックの列をまとめて取り付けられます", - "create.ponder.linear_chassis_attachment.text_5": "レンチを使って、このシャーシの粘着範囲を正確に調整できます", - "create.ponder.linear_chassis_attachment.text_6": "CTRLを押しながらスクロールすると、接続している全てのシャーシブロックの範囲を一気に調整できます", - "create.ponder.linear_chassis_attachment.text_7": "他の面にブロックを接着するには、超粘着剤を使う必要があります", - "create.ponder.linear_chassis_attachment.text_8": "この仕組みを使えば、どんな形の構造物もからくりとして動かせます", - - "create.ponder.linear_chassis_group.header": "リニアシャーシをグループで動かす", - "create.ponder.linear_chassis_group.text_1": "リニアシャーシは、隣の同じ種類のシャーシと繋がります", - "create.ponder.linear_chassis_group.text_2": "からくり機械で1つを動かすと、他のリニアシャーシも一緒に動きます", - "create.ponder.linear_chassis_group.text_3": "異なる種類のシャーシや、別の方向を向いているシャーシは接続されません", - - "create.ponder.mechanical_arm.header": "メカニカルアームの設定", - "create.ponder.mechanical_arm.text_1": "メカニカルアームを設置する前に、搬入元と搬出先を設定しなければなりません", - "create.ponder.mechanical_arm.text_2": "特定のブロックを対象に設定するには、アームを持ったまま右クリックしてください", - "create.ponder.mechanical_arm.text_3": "搬入元(青)と搬出先(オレンジ)を切り替えるには、もう1度右クリックします", - "create.ponder.mechanical_arm.text_4": "アームを持ったまま右クリックすると選択が解除されます", - "create.ponder.mechanical_arm.text_5": "設置したメカニカルアームは、設定したブロックを対象にします", - "create.ponder.mechanical_arm.text_6": "範囲内であれば、複数の搬入元と搬出先を設定できます", - "create.ponder.mechanical_arm.text_7": "ただし、あらゆる機械やブロックを対象にできるわけではありません", - "create.ponder.mechanical_arm.text_8": "そんな時はファンネルやデポを経由させましょう", - - "create.ponder.mechanical_arm_filtering.header": "メカニカルアームの搬出フィルタリング", - "create.ponder.mechanical_arm_filtering.text_1": "搬入元", - "create.ponder.mechanical_arm_filtering.text_2": "搬出先", - "create.ponder.mechanical_arm_filtering.text_3": "フィルターを使ってアームが搬出入するアイテムを制限したいと思っても", - "create.ponder.mechanical_arm_filtering.text_4": "メカニカルアーム自体は、フィルターを設定できません", - "create.ponder.mechanical_arm_filtering.text_5": "そこで真鍮ファンネルなどを対象にした場合、アームにそのフィルターが反映されます", - "create.ponder.mechanical_arm_filtering.text_6": "アームは賢いので、搬出できないアイテムを拾うことはありません", - - "create.ponder.mechanical_arm_modes.header": "メカニカルアームの分配モード", - "create.ponder.mechanical_arm_modes.text_1": "搬入元", - "create.ponder.mechanical_arm_modes.text_2": "搬出先", - "create.ponder.mechanical_arm_modes.text_3": "アームは複数の有効な搬出先が設定されていると...", - "create.ponder.mechanical_arm_modes.text_4": "...設定に従ってアイテムを分配します", - "create.ponder.mechanical_arm_modes.text_5": "レンチを持ってスクロールすると設定を変えられます", - "create.ponder.mechanical_arm_modes.text_6": "「順繰り分配」は、有効な全ての搬出先へ順番に搬出します", - "create.ponder.mechanical_arm_modes.text_7": "搬出先がそれ以上のアイテムを受け取れない場合、そこへの搬出はスキップされます", - "create.ponder.mechanical_arm_modes.text_8": "「強制順繰り分配」は、搬出をスキップせず、空きがでるまで待機します", - "create.ponder.mechanical_arm_modes.text_9": "「最初の対象を優先」は、設定した順番が先の方の対象に優先して搬出します", - - "create.ponder.mechanical_arm_redstone.header": "メカニカルアームのレッドストーン制御", - "create.ponder.mechanical_arm_redstone.text_1": "レッドストーン信号を受けると、メカニカルアームは稼働しません", - "create.ponder.mechanical_arm_redstone.text_2": "ただし、停止する前に開始した搬出入が終わるまで稼働し続けます", - "create.ponder.mechanical_arm_redstone.text_3": "それを利用し、反転したパルス信号を使って1回だけ稼働させられます", - - "create.ponder.mechanical_bearing.header": "メカニカルベアリングによる構造物の移動", - "create.ponder.mechanical_bearing.text_1": "メカニカルベアリングは、手前にブロックを取り付けられます", - "create.ponder.mechanical_bearing.text_2": "回転力を供給すると、組み立てた構造物を回せます", - - "create.ponder.mechanical_crafter.header": "メカニカルクラフターの配置", - "create.ponder.mechanical_crafter.text_1": "メカニカルクラフターは、あらゆるクラフトレシピを自動化できます", - "create.ponder.mechanical_crafter.text_2": "レンチを使えばクラフターがアイテムを移動させるベルトの向きを変えられます", - "create.ponder.mechanical_crafter.text_3": "稼働にはすべてのベルトが、外にベルトが向いている1つのクラフターへ続いていなければなりません", - "create.ponder.mechanical_crafter.text_4": "完成品は外に向かうベルトが指す方向にある収納ブロックに搬出されます", - "create.ponder.mechanical_crafter.text_5": "メカニカルクラフターを稼働には回転力が必要です", - "create.ponder.mechanical_crafter.text_6": "前面を右クリックすると手動でアイテムを搬入できます", - "create.ponder.mechanical_crafter.text_7": "1つのクラフターに続くベルトの全スロットにアイテムが入ると、クラフトが開始されます", - "create.ponder.mechanical_crafter.text_8": "スロットが埋まっていなくても、レッドストーンパルスを使って強制的にクラフトを開始できます", - - "create.ponder.mechanical_crafter_connect.header": "メカニカルクラフターの搬入口の共有", - "create.ponder.mechanical_crafter_connect.text_1": "アイテムは自動でクラフターに搬入することもできます", - "create.ponder.mechanical_crafter_connect.text_2": "背面でレンチを使うと、メカニカルクラフターが接続されます", - "create.ponder.mechanical_crafter_connect.text_3": "接続した全てのクラフターは、同じ搬入口からアイテムを搬入できるようになります", - - "create.ponder.mechanical_crafter_covers.header": "メカニカルクラフターとスロットカバー", - "create.ponder.mechanical_crafter_covers.text_1": "一部のレシピでは、ベルトの流れの隙間を埋める為に追加のクラフターが必要になります", - "create.ponder.mechanical_crafter_covers.text_2": "スロットカバーを使って、クラフターを空のスロットとして動作するように設定できます", - "create.ponder.mechanical_crafter_covers.text_3": "背面にレンチを使って接続したクラフターは、カバーしたクラフターを無視して同じアイテムを搬入できます", - - "create.ponder.mechanical_drill.header": "メカニカルドリルでブロックを破壊する", - "create.ponder.mechanical_drill.text_1": "メカニカルドリルは回転力を供給すると、目の前のブロックを破壊します", - "create.ponder.mechanical_drill.text_2": "採掘速度は回転速度で決まります", - - "create.ponder.mechanical_drill_contraption.header": "からくりに組み込んでのメカニカルドリルの使い方", - "create.ponder.mechanical_drill_contraption.text_1": "メカニカルドリルを組み込んだからくりを動かすと...", - "create.ponder.mechanical_drill_contraption.text_2": "...ドリルは、移動先のブロックを破壊します", - - "create.ponder.mechanical_harvester.header": "からくりに組み込んでのメカニカルハーベスターの使い方", - "create.ponder.mechanical_harvester.text_1": "ハーベスター組み込んだからくりを動かすと...", - "create.ponder.mechanical_harvester.text_2": "...成熟した作物を収穫し、成長をリセットします", - - "create.ponder.mechanical_mixer.header": "メカニカルミキサーによるアイテム加工", - "create.ponder.mechanical_mixer.text_1": "ミキサーと鉢があれば、いくつかのクラフトレシピを自動化できます", - "create.ponder.mechanical_mixer.text_2": "自動化できるのは不定形レシピといくつかの追加レシピです", - "create.ponder.mechanical_mixer.text_3": "レシピの中には、ブレイズバーナーの熱を必要とするものもあります", - "create.ponder.mechanical_mixer.text_4": "フィルタースロットは、2つのレシピが競合するときに使えます", - - "create.ponder.mechanical_piston.header": "メカニカルピストンによる構造物の移動", - "create.ponder.mechanical_piston.text_1": "メカニカルピストンは、手前にあるブロックを動かせます", - "create.ponder.mechanical_piston.text_2": "移動の速度と方向は、供給する回転力で決まります", - "create.ponder.mechanical_piston.text_3": "メカニカル粘着ピストンは、取り付けられたブロックを引き戻せます", - - "create.ponder.mechanical_piston_modes.header": "メカニカルピストンの動作モード", - "create.ponder.mechanical_piston_modes.text_1": "ピストンの動作が止まると、移動した構造物はブロックへ戻ります", - "create.ponder.mechanical_piston_modes.text_2": "ブロックに戻らないように設定したり、動かし始めた場所でしかブロックに戻らないように設定したりできます", - - "create.ponder.mechanical_plough.header": "からくりに組み込んでのメカニカルプラウの使い方", - "create.ponder.mechanical_plough.text_1": "プラウを組み込んだからくりを動かすと...", - "create.ponder.mechanical_plough.text_2": "...当たり判定のないブロックが破壊します", - "create.ponder.mechanical_plough.text_3": "さらに、プラウは土を耕やします", - "create.ponder.mechanical_plough.text_4": "また、エンティティを傷つけずに飛ばすこともできます", - - "create.ponder.mechanical_press.header": "メカニカルプレスによるアイテム加工", - "create.ponder.mechanical_press.text_1": "メカニカルプレスは、その下に配置したアイテムを加工できます", - "create.ponder.mechanical_press.text_2": "加工するアイテムは下に落としたり、プレス機の下にあるデポに置いたりしてください", - "create.ponder.mechanical_press.text_3": "アイテムがベルトで供給されると...", - "create.ponder.mechanical_press.text_4": "...プレスが自動でアイテムを止め、加工します", - - "create.ponder.mechanical_press_compacting.header": "メカニカルプレスによる圧縮加工", - "create.ponder.mechanical_press_compacting.text_1": "鉢に入れられたアイテムをプレスし、圧縮加工できます", - "create.ponder.mechanical_press_compacting.text_2": "圧縮加工には、2x2、3x3のクラフトレシピに加え、いくつかの追加レシピがあります", - "create.ponder.mechanical_press_compacting.text_3": "これらのレシピの中には、ブレイズバーナーの熱を必要とするものがあります", - "create.ponder.mechanical_press_compacting.text_4": "フィルタースロットは、2つのレシピが競合するときに使えます", - - "create.ponder.mechanical_pump_flow.header": "メカニカルポンプによる液体輸送", - "create.ponder.mechanical_pump_flow.text_1": "メカニカルポンプは、接続したネットワークの液体の流れを制御します", - "create.ponder.mechanical_pump_flow.text_2": "稼働させると、矢印が液体の流れる方向を示します", - "create.ponder.mechanical_pump_flow.text_3": "後ろのネットワークが液体を吸い取っているのに対し...", - "create.ponder.mechanical_pump_flow.text_4": "...前のネットワークが液体を外側に送っています", - "create.ponder.mechanical_pump_flow.text_5": "回転方向を逆にすると、流れの方向が逆になります", - "create.ponder.mechanical_pump_flow.text_6": "レンチを使って手動でポンプの向きを変えることもできます", - - "create.ponder.mechanical_pump_speed.header": "メカニカルポンプの輸送速度", - "create.ponder.mechanical_pump_speed.text_1": "速度に関わらず、メカニカルポンプは16ブロック先までのパイプに影響を与えます", - "create.ponder.mechanical_pump_speed.text_2": "回転速度を速くすることで、流れの送られる速度と...", - "create.ponder.mechanical_pump_speed.text_3": "...液体の輸送速度が変わります", - "create.ponder.mechanical_pump_speed.text_4": "液体ネットワーク内のポンプはそれぞれ別の速度で動力を供給できます", - "create.ponder.mechanical_pump_speed.text_5": "向きを交互にすることで、流れの方向を揃えられます", - - "create.ponder.mechanical_saw_breaker.header": "メカニカルソーによる伐採", - "create.ponder.mechanical_saw_breaker.text_1": "メカニカルソーは回転力を供給すると、目の前の木を伐採できます", - "create.ponder.mechanical_saw_breaker.text_2": "木を完全に伐採するには、木と地面を繋ぐ最後の根本を伐採しなければなりません", - - "create.ponder.mechanical_saw_contraption.header": "からくりに組み込んでのメカニカルソーの使い方", - "create.ponder.mechanical_saw_contraption.text_1": "メカニカルソーを組み込んだからくりを動かすと...", - "create.ponder.mechanical_saw_contraption.text_2": "...メカニカルソーは木を伐採します", - - "create.ponder.mechanical_saw_processing.header": "メカニカルソーによるアイテム加工", - "create.ponder.mechanical_saw_processing.text_1": "上向きのメカニカルソーは、様々なアイテムを加工できます", - "create.ponder.mechanical_saw_processing.text_2": "加工したアイテムは、常にソーの回転方向とは逆に移動します", - "create.ponder.mechanical_saw_processing.text_3": "ソーはメカニカルベルトと繋げて加工できます", - "create.ponder.mechanical_saw_processing.text_4": "複数の完成品がある場合、フィルタースロットでどの完成品を作るかを指定できます", - "create.ponder.mechanical_saw_processing.text_5": "フィルターがない場合、ソーは全ての加工を順番に繰り返します", - - "create.ponder.millstone.header": "石臼によるアイテム加工", - "create.ponder.millstone.text_1": "石臼はアイテムを粉砕加工する機械です", - "create.ponder.millstone.text_2": "歯車を使って、側面から回転力を供給できます", - "create.ponder.millstone.text_3": "上からアイテムを投げ入れてアイテムを搬入できます", - "create.ponder.millstone.text_4": "しばらく待った後、右クリックで完成品を取り出せます", - "create.ponder.millstone.text_5": "加工品を搬出して自動化することもできます", - - "create.ponder.nixie_tube.header": "ニキシー管の使い方", - "create.ponder.nixie_tube.text_1": "ニキシー管は受けたレッドストーン信号の強度を表示します", - "create.ponder.nixie_tube.text_2": "金床で名付けた名札を使って、好きな文字を表示することもできます", - "create.ponder.nixie_tube.text_3": "染料で右クリックすることで表示の色を変えられます", - - "create.ponder.piston_pole.header": "ピストン延長ポール", - "create.ponder.piston_pole.text_1": "ポールが無いとメカニカルピストンは動きません", - "create.ponder.piston_pole.text_2": "後ろに付けたポールの長さによって、伸び縮みする長さが決まります", - - "create.ponder.portable_fluid_interface.header": "からくり液体交換", - "create.ponder.portable_fluid_interface.text_1": "移動しているからくりの液体タンクは、どんなパイプでも搬出入できません", - "create.ponder.portable_fluid_interface.text_2": "この機械は、からくりをブロックに戻すことなく液体を搬出入できます", - "create.ponder.portable_fluid_interface.text_3": "1~2ブロックの隙間を開けて2つ目のインターフェースを設置しましょう", - "create.ponder.portable_fluid_interface.text_4": "すれ違ったときに必ず接続されます", - "create.ponder.portable_fluid_interface.text_5": "接続中は、設置されている方のインターフェースはからくり内全てのタンクのように振る舞います", - "create.ponder.portable_fluid_interface.text_6": "液体の搬入と...", - "create.ponder.portable_fluid_interface.text_7": "...搬出ができます", - "create.ponder.portable_fluid_interface.text_8": "しばらく中身が搬出入されないと、このからくりはまた動き出します", - - "create.ponder.portable_storage_interface.header": "からくり内の収納ブロックとの搬出入", - "create.ponder.portable_storage_interface.text_1": "からくりに組み込まれた収納ブロックは、プレイヤーが開くことはできません", - "create.ponder.portable_storage_interface.text_2": "この装置は、からくりを停止することなく、収納ブロックと搬出入できます", - "create.ponder.portable_storage_interface.text_3": "1~2ブロックの間隔をあけて、2つ目のインターフェースを設置しましょう", - "create.ponder.portable_storage_interface.text_4": "両者がすれ違うたびに接続されます", - "create.ponder.portable_storage_interface.text_5": "接続中、設置されている方のインターフェースはからくり内全ての収納ブロックのように振る舞います", - "create.ponder.portable_storage_interface.text_6": "アイテムを搬入したり...", - "create.ponder.portable_storage_interface.text_7": "...アイテムを搬出したりできます", - "create.ponder.portable_storage_interface.text_8": "しばらくの間アイテムのやり取りがないと、からくりは稼働を再開します", - - "create.ponder.portable_storage_interface_redstone.header": "レッドストーンによる制御", - "create.ponder.portable_storage_interface_redstone.text_1": "レッドストーン信号を受けている間、設置されたインターフェースは接続を行いません", - - "create.ponder.powered_latch.header": "パワードラッチによる信号制御", - "create.ponder.powered_latch.text_1": "パワードラッチはレッドストーン信号で制御できるレバーです", - "create.ponder.powered_latch.text_2": "後ろからの信号でオンに", - "create.ponder.powered_latch.text_3": "側面からの信号でオフに戻ります", - "create.ponder.powered_latch.text_4": "パワードラッチは、手動でもオンオフできます", - - "create.ponder.powered_toggle_latch.header": "パワードトグルラッチによる信号制御", - "create.ponder.powered_toggle_latch.text_1": "パワードトグルラッチはレッドストーン信号で切り替えできるレバーです", - "create.ponder.powered_toggle_latch.text_2": "後ろからの信号で切り替えできます", - "create.ponder.powered_toggle_latch.text_3": "何度も信号を送るとオンとオフと繰り返します", - "create.ponder.powered_toggle_latch.text_4": "パワードトグルラッチは、手動でもオンオフもできます", - - "create.ponder.pulse_extender.header": "パルスエクステンダーによる信号制御", - "create.ponder.pulse_extender.text_1": "パルスエクステンダーは通過する信号を長くします", - "create.ponder.pulse_extender.text_2": "短時間の遅延の後...", - "create.ponder.pulse_extender.text_3": "...設定した時間だけ信号を出します", - "create.ponder.pulse_extender.text_4": "マウスホイールで、信号を出す時間を調整できます", - "create.ponder.pulse_extender.text_5": "最大で30分まで設定できます", - - "create.ponder.pulse_repeater.header": "パルスリピーターによる信号制御", - "create.ponder.pulse_repeater.text_1": "パルスリピーターは、レッドストーン信号を短縮して1tickのパルス信号にします", - "create.ponder.pulse_repeater.text_2": "マウスホイールで、遅延する時間を調整できます", - "create.ponder.pulse_repeater.text_3": "最大30分まで設定できます", - - "create.ponder.radial_chassis.header": "ラジアルシャーシによるブロックの取り付け", - "create.ponder.radial_chassis.text_1": "ラジアルシャーシは、同じ種類のシャーシと繋がります", - "create.ponder.radial_chassis.text_2": "からくり機械によって1つが動かされると、他も一緒に動きます", - "create.ponder.radial_chassis.text_3": "ラジアルシャーシの側面を粘着面にできます", - "create.ponder.radial_chassis.text_4": "もう一度クリックすると、他の全ての面も粘着面になります", - "create.ponder.radial_chassis.text_5": "素手でスニークしながら右クリックすると、粘着剤を剥がせます", - "create.ponder.radial_chassis.text_6": "ブロックが粘着面に設置されていると...", - "create.ponder.radial_chassis.text_7": "...その範囲内の繋がっている全てのブロックが取り付けられます", - "create.ponder.radial_chassis.text_8": "レンチを使って、シャーシの範囲の半径を正確に指定できます", - "create.ponder.radial_chassis.text_9": "どの粘着面とも繋がっていないブロックは取りつきません", - - "create.ponder.redstone_contact.header": "レッドストーンコンタクト", - "create.ponder.redstone_contact.text_1": "向かい合ったレッドストーンコンタクトは、レッドストーン信号を出力します", - "create.ponder.redstone_contact.text_2": "これは、片方のコンタクトがからくりの一部である場合でも同様です", - - "create.ponder.redstone_link.header": "レッドストーンリンクの使い方", - "create.ponder.redstone_link.text_1": "レッドストーンリンクは、レッドストーン信号を無線で送受信できます", - "create.ponder.redstone_link.text_2": "モードを切り替えるには、スニークしながら右クリックします", - "create.ponder.redstone_link.text_3": "レンチをもって右クリックでも、モードを切り替えられます", - "create.ponder.redstone_link.text_4": "受信機は、128ブロック以内の送信機のレッドストーン信号を受信します", - "create.ponder.redstone_link.text_5": "2つのスロットにアイテムを設定すると、周波数を設定できます", - "create.ponder.redstone_link.text_6": "周波数が一致するリンク同士のみが送受信を行います", - - "create.ponder.rope_pulley.header": "ローププーリーによる構造物の移動", - "create.ponder.rope_pulley.text_1": "ローププーリーは、回転力を供給するとブロックを垂直に動かせます", - "create.ponder.rope_pulley.text_2": "移動の方向と速度は、供給される回転力で決まります", - - "create.ponder.rope_pulley_attachment.header": "プーリーをからくりの一部として動かす", - "create.ponder.rope_pulley_attachment.text_1": "プーリーがからくりによって動かされると...", - "create.ponder.rope_pulley_attachment.text_2": "...プーリーと接続している構造物も一緒に動きます", - "create.ponder.rope_pulley_attachment.text_3": "プーリーが稼働している間は動かせないことに注意してください", - - "create.ponder.rope_pulley_modes.header": "ローププーリーの動作モード", - "create.ponder.rope_pulley_modes.text_1": "プーリーの動きが止まると、移動した構造物はブロックに戻ります", - "create.ponder.rope_pulley_modes.text_2": "ブロックに戻らないように設定したり、動かし始めた場所でしかブロックに戻らないように設定したりできます", - - "create.ponder.rose_quartz_lamp.header": "ローズクォーツランプ", - "create.ponder.rose_quartz_lamp.text_1": "ローズクォーツランプはレッドストーン信号を受けるとオンになります", - "create.ponder.rose_quartz_lamp.text_2": "するとその後もレッドストーン信号を発し続けます", - "create.ponder.rose_quartz_lamp.text_3": "複数のランプを並べて設置すると...", - "create.ponder.rose_quartz_lamp.text_4": "...ランプをオンにすると信号はそこに集中し、他のランプはオフになります", - "create.ponder.rose_quartz_lamp.text_5": "オンのランプの距離に応じてコンパレーターは信号を発します", - "create.ponder.rose_quartz_lamp.text_6": "レンチでランプを手動で切り替えることもできます", - - "create.ponder.rotation_speed_controller.header": "回転速度コントローラーの使い方", - "create.ponder.rotation_speed_controller.text_1": "コントローラーは、側面の軸から上の大きな歯車に回転を伝達します", - "create.ponder.rotation_speed_controller.text_2": "側面のパネルを見ながらスクロールすると、伝達する回転速度を調整できます", - - "create.ponder.sail.header": "帆による風車の組み立て", - "create.ponder.sail.text_1": "帆は、風車を作るのに便利なブロックです", - "create.ponder.sail.text_2": "超粘着剤やシャーシなしに、ブロックや帆フレームに取り付けられます", - "create.ponder.sail.text_3": "染料で右クリックして染色できます", - "create.ponder.sail.text_4": "ハサミで右クリックすると、フレームに戻せます", - - "create.ponder.sail_frame.header": "帆フレームによる風車の組み立て", - "create.ponder.sail_frame.text_1": "帆フレームは、風車を作るのに便利なブロックです", - "create.ponder.sail_frame.text_2": "超粘着剤やシャーシなしに、ブロックや帆フレームに取り付けられます", - - "create.ponder.sequenced_gearshift.header": "シーケンスギアシフトによる回転の制御", - "create.ponder.sequenced_gearshift.text_1": "シーケンスギアシフトは、設定されたプログラムに従って回転を伝達します", - "create.ponder.sequenced_gearshift.text_2": "右クリックで設定画面を開けます", - "create.ponder.sequenced_gearshift.text_3": "レッドストーン信号を受けると、設定されたプログラムを実行します", - "create.ponder.sequenced_gearshift.text_4": "終了すると止まり、また次のレッドストーン信号を受けると同じように動作します", - "create.ponder.sequenced_gearshift.text_5": "レッドストーンコンパレーターで、現在の進捗を読み取れます", - - "create.ponder.shaft.header": "シャフトによる回転力の伝達", - "create.ponder.shaft.text_1": "シャフトはまっすぐに回転を伝達します", - - "create.ponder.shaft_casing.header": "ケース入りシャフト", - "create.ponder.shaft_casing.text_1": "真鍮、安山岩ケーシングを使って、シャフトを装飾できます", - - "create.ponder.smart_chute.header": "スマートシュートによるアイテムのフィルタリング", - "create.ponder.smart_chute.text_1": "スマートシュートは、垂直方向のシュートにフィルター機能を追加したものです", - "create.ponder.smart_chute.text_2": "フィルタースロットを使って、何を搬出入するかを設定できます", - "create.ponder.smart_chute.text_3": "マウスホイールで搬出するスタック量を指定できます", - "create.ponder.smart_chute.text_4": "レッドストーン信号で、スマートシュートを停止させることもできます", - - "create.ponder.smart_pipe.header": "スマートパイプによる液体制御", - "create.ponder.smart_pipe.text_1": "スマートパイプは液体の種類によって流れを制御できます", - "create.ponder.smart_pipe.text_2": "搬入元に直接つなげることで、搬出する液体の種類を指定できます", - "create.ponder.smart_pipe.text_3": "フィルタースロットに液体の入ったアイテムを右クリックして指定できます", - "create.ponder.smart_pipe.text_4": "スマートパイプは、パイプネットワークの搬出先に設置すると、指定した液体のみを流します", - - "create.ponder.speedometer.header": "速度メーターによる動力情報の監視", - "create.ponder.speedometer.text_1": "速度メーターは、接続した機械の回転速度を表示します", - "create.ponder.speedometer.text_2": "エンジニアのゴーグルを装着していると、より詳細な情報を得られます", - "create.ponder.speedometer.text_3": "コンパレーターは、速度メーターの測定値に応じたレッドストーン信号を出力します", - - "create.ponder.spout_filling.header": "アイテム注液口によるアイテム充填", - "create.ponder.spout_filling.text_1": "注液口は、その下に用意したアイテムを液体で満たせます", - "create.ponder.spout_filling.text_2": "注液口の中身は手動で搬出入できません", - "create.ponder.spout_filling.text_3": "代わりに、パイプを使って液体を供給しましょう", - "create.ponder.spout_filling.text_4": "容器アイテムは、注液口の下のデポに置きましょう", - "create.ponder.spout_filling.text_5": "ベルトでアイテムを供給すると...", - "create.ponder.spout_filling.text_6": "...注液口が自動でアイテムを止め、加工します", - - "create.ponder.stabilized_bearings.header": "からくりの角度の固定", - "create.ponder.stabilized_bearings.text_1": "メカニカルベアリングが動いている構造物に組み込まれているなら...", - "create.ponder.stabilized_bearings.text_2": "...自身の角度を真っ直ぐに保とうとします", - "create.ponder.stabilized_bearings.text_3": "ベアリングにブロックを取り付けると", - "create.ponder.stabilized_bearings.text_4": "ベアリングに取り付けたサブのからくり全体が角度を真っ直ぐに保ったままになります", - - "create.ponder.steam_engine.header": "蒸気エンジンの設置", - "create.ponder.steam_engine.text_1": "蒸気エンジンは液体タンクに設置できます", - "create.ponder.steam_engine.text_10": "レベル4", - "create.ponder.steam_engine.text_11": "4基の蒸気エンジン", - "create.ponder.steam_engine.text_12": "レべル8", - "create.ponder.steam_engine.text_13": "8基の蒸気エンジン", - "create.ponder.steam_engine.text_2": "シャフトで蒸気エンジンをクリックして回転力の出力口を作れます", - "create.ponder.steam_engine.text_3": "十分な容量と水量、そして熱量があれば...", - "create.ponder.steam_engine.text_4": "...回転力を生成できます", - "create.ponder.steam_engine.text_5": "最低でも、4つの液体タンクが必要です", - "create.ponder.steam_engine.text_6": "ブレイズバーナーの助けを借りれば、出力を増やせます", - "create.ponder.steam_engine.text_7": "レベルを上げるには、より多くの容量、水量、熱量が必要です", - "create.ponder.steam_engine.text_8": "レベルは、エンジニアのゴーグルで確認できます", - "create.ponder.steam_engine.text_9": "レベルを上げるごとに、最大出力を出せるエンジンを増やせます", - - "create.ponder.steam_whistle.header": "汽笛の設置", - "create.ponder.steam_whistle.text_1": "汽笛は液体タンクに設置できます", - "create.ponder.steam_whistle.text_2": "タンクが十分な熱量を受けていれば...", - "create.ponder.steam_whistle.text_3": "...汽笛はレッドストーン信号を受けたとき、音を鳴らします", - "create.ponder.steam_whistle.text_4": "ブロックにアイテムの汽笛を使うことで、音程を下げられます", - "create.ponder.steam_whistle.text_5": "レンチを使って、3つのオクターブを循環して切り替えられます", - "create.ponder.steam_whistle.text_6": "エンジニアのゴーグルは、汽笛の音程を調べるのに役立ちます", - - "create.ponder.sticker.header": "スティッカーを使ったブロックの付け外し", - "create.ponder.sticker.text_1": "スティッカーは、ブロックの付け外しをレッドストーン信号で制御できます", - "create.ponder.sticker.text_2": "レッドストーン信号を受けると、状態が切り替わります", - "create.ponder.sticker.text_3": "付いているときは、からくりが動かされるとブロックも一緒に動きます", - "create.ponder.sticker.text_4": "もう一度信号を受けると、ブロックは外れます", - - "create.ponder.stressometer.header": "応力メーターによる動力情報の監視", - "create.ponder.stressometer.text_1": "応力メーターは、接続した動力ネットワークの許容応力を表示します", - "create.ponder.stressometer.text_2": "エンジニアのゴーグルを装着していると、より詳しい数値を見られます", - "create.ponder.stressometer.text_3": "コンパレーターは、応力メーターの測定値に応じたレッドストーン信号を出力します", - - "create.ponder.super_glue.header": "超粘着剤によるブロックの取り付け", - "create.ponder.super_glue.text_1": "超粘着剤はブロックをまとめて、動く構造物を作れます", - "create.ponder.super_glue.text_2": "2つの角をクリックすると、新しい「粘着」領域が作られます", - "create.ponder.super_glue.text_3": "領域を削除するには、超粘着剤を持って殴ってください", - "create.ponder.super_glue.text_4": "領域を共有する隣接するブロックは互いにくっつきます", - "create.ponder.super_glue.text_5": "重なった領域は一緒に移動します", - "create.ponder.super_glue.text_6": "他のブロックにぶら下げるブロックは、基本的に超粘着剤を必要としません", - - "create.ponder.track_chunks.header": "ロードされていないチャンクの旅", - "create.ponder.track_chunks.text_1": "線路はロードされたチャンクの外でも機能し続けます", - "create.ponder.track_chunks.text_2": "列車は世界の処理されていない場所でも問題なく走行します", - "create.ponder.track_chunks.text_3": "駅や赤信号で止まるのは変わりません", - "create.ponder.track_chunks.text_4": "ただし、ドリルなど、組み込んだ機械は動作しません", - "create.ponder.track_chunks.text_5": "プレイヤーが近づくと、列車は再び現れます", - - "create.ponder.track_observer.header": "列車の検知", - "create.ponder.track_observer.text_1": "鉄道用線路を選択し、その後列車検知装置を近くに置いてください", - "create.ponder.track_observer.text_2": "列車検知装置はそのマーカーに列車が通るとそれを検知します", - "create.ponder.track_observer.text_3": "列車検知装置はフィルターに一致する貨物があったときだけ動作するようにできます", - - "create.ponder.track_placement.header": "鉄道用線路の設置", - "create.ponder.track_placement.text_1": "からくり鉄道のために設計された新型レール", - "create.ponder.track_placement.text_2": "線路を一括して設置するには、まず既存の線路をクリックしてください", - "create.ponder.track_placement.text_3": "次に、2つ目の線路を設置または選択します", - "create.ponder.track_placement.text_4": "線路はターンや傾斜として設置することもできます", - "create.ponder.track_placement.text_5": "繋げたとき、線路はそれぞれのターンが均等な大きさになるよう配置されます", - "create.ponder.track_placement.text_6": "ダッシュキーを押しながら繋げると...", - "create.ponder.track_placement.text_7": "...代わりにできるだけ長くなめらかなターンを作ります", - "create.ponder.track_placement.text_8": "オフハンドに持った素材は線路の下に自動で敷き詰められます", - - "create.ponder.track_portal.header": "ネザーへの線路", - "create.ponder.track_portal.text_1": "鉄道用線路をネザーポータルに設置すると...", - "create.ponder.track_portal.text_2": "...向こう側に対となる線路の設置を試みます", - "create.ponder.track_portal.text_3": "この線路上の列車はディメンションを超えて進めます", - - "create.ponder.train_assembly.header": "列車の組み立て", - "create.ponder.train_assembly.text_1": "鉄道用線路を選択した後、駅を近くに置いてください", - "create.ponder.train_assembly.text_10": "列車には鉄道用運転台が必要です", - "create.ponder.train_assembly.text_11": "もうひとつ置くことで駅から両方向に発車発車をさせることもできます", - "create.ponder.train_assembly.text_12": "駅のUIを開いて、組み立て処理を実行してください", - "create.ponder.train_assembly.text_13": "列車は駅でしかブロックに戻すことは出きません", - "create.ponder.train_assembly.text_14": "地図を駅を使うと、その場所にラベル付きのマーカーが追加されます", - "create.ponder.train_assembly.text_15": "組み立てた列車はレンチで近くの線路に移動できます", - "create.ponder.train_assembly.text_2": "駅は線路網における道しるべとなります", - "create.ponder.train_assembly.text_3": "新しい列車を作るには、UIを開いて組み立てモードに切り替えてください", - "create.ponder.train_assembly.text_4": "組み立て中、定時運行している列車はこの駅に近づきません", - "create.ponder.train_assembly.text_5": "線路の上に鉄道ケーシングを使って新しい台車を作ってください。", - "create.ponder.train_assembly.text_6": "もう一度線路をクリックすると台車のデザインが循環して切り替わります", - "create.ponder.train_assembly.text_7": "超粘着剤を使ってブロックを取り付けてください", - "create.ponder.train_assembly.text_8": "組み立てた列車は組み込まれたチェストや樽から燃料を探し出せる場合、より速く走ります", - "create.ponder.train_assembly.text_9": "燃料をアイテム保管庫に入れておけば、列車によって消費されません", - - "create.ponder.train_controls.header": "列車の操縦", - "create.ponder.train_controls.text_1": "鉄道運転台はすべてのからくり鉄道に必要です", - "create.ponder.train_controls.text_2": "列車を組み立て、運転台を右クリックして操縦を始められます", - "create.ponder.train_controls.text_3": "列車の加速と進路決定は移動キーで行えます", - "create.ponder.train_controls.text_4": "必要に応じて、最高速度をマウスホイールで調整できます", - "create.ponder.train_controls.text_5": "スペースキーを長押しすることで、近くの駅に停車できます", - "create.ponder.train_controls.text_6": "列車は駅でしかブロックに戻せません", - "create.ponder.train_controls.text_7": "組み込んだ汽笛はダッシュキーで鳴らせます", - "create.ponder.train_controls.text_8": "スニークかもう一度クリックで列車の運転をやめられます", - - "create.ponder.train_schedule.header": "鉄道時刻表の使い方", - "create.ponder.train_schedule.text_1": "時刻表を使えば、列車を他の運転手に運転させられます", - "create.ponder.train_schedule.text_2": "アイテムを持って右クリックで設定画面を開けます", - "create.ponder.train_schedule.text_3": "一度時刻表を組めば、運転手に渡せます", - "create.ponder.train_schedule.text_4": "任意のモブか、ブレイズバーナーを運転台の真正面に座らせれば車掌にできます", - "create.ponder.train_schedule.text_5": "リードにモブを結べば、シートをクリックして簡単に座らせられます", - "create.ponder.train_schedule.text_6": "時刻表はいつでもモブから取りもどせます", - - "create.ponder.train_signal_placement.header": "鉄道信号機の設置", - "create.ponder.train_signal_placement.text_1": "鉄道用線路を選択して信号機を近くに置いてください", - "create.ponder.train_signal_placement.text_2": "信号機はプレイヤーが運転していない列車の運行を制御します", - "create.ponder.train_signal_placement.text_3": "定時運行している列車は決して信号機を逆向きに通過できません...", - "create.ponder.train_signal_placement.text_4": "...もう一つ、反対向きの信号機があれば話は別ですが", - "create.ponder.train_signal_placement.text_5": "ニキシー管を取り付けて、信号機の光をより見やすくできます", - - "create.ponder.train_signal_redstone.header": "信号機 & レッドストーン", - "create.ponder.train_signal_redstone.text_1": "レッドストーン信号で信号機の表示を強制できます", - "create.ponder.train_signal_redstone.text_2": "逆に、コンパレーターは赤信号の時にレッドストーン信号を発します", - - "create.ponder.train_signal_signaling.header": "信号機による衝突防止", - "create.ponder.train_signal_signaling.text_1": "鉄道信号機は鉄道用線路を区間に区切ります", - "create.ponder.train_signal_signaling.text_2": "区間に列車がある場合、他の列車は中への侵入が許可されません", - "create.ponder.train_signal_signaling.text_3": "従って、区間には一度に1つの列車しか存在できません", - "create.ponder.train_signal_signaling.text_4": "二つ目の信号機モードはレンチによって有効にできます", - "create.ponder.train_signal_signaling.text_5": "真鍮の信号機の区間は通常、普通の信号機とつながります", - "create.ponder.train_signal_signaling.text_6": "この特別な信号は、第二の条件下で列車を停止させられます", - "create.ponder.train_signal_signaling.text_7": "それは区間に入ろうとした列車を停止させます...", - "create.ponder.train_signal_signaling.text_8": "...すぐに区間を離れられない場合", - "create.ponder.train_signal_signaling.text_9": "これで、待っている列車を混雑する区間の中に入らないようにできます", - - "create.ponder.valve_handle.header": "バルブハンドルによる回転力の生成", - "create.ponder.valve_handle.text_1": "バルブハンドルは手動で回転力を生み出す原動機です", - "create.ponder.valve_handle.text_2": "右クリックし続けると、反時計回りに回転します", - "create.ponder.valve_handle.text_3": "回転速度はゆっくりですが、一定です", - "create.ponder.valve_handle.text_4": "スニーク状態で右クリックし続けると、時計回りに回転します", - "create.ponder.valve_handle.text_5": "バルブハンドルは、染色できます", - - "create.ponder.valve_pipe.header": "バルブによる液体制御", - "create.ponder.valve_pipe.text_1": "バルブは、液体ネットワークに流れる液体を制御するのに役立ちます", - "create.ponder.valve_pipe.text_2": "回転力で、液体が通過できるか制御できます", - "create.ponder.valve_pipe.text_3": "開放方向に回転力を与えるとバルブが開きます", - "create.ponder.valve_pipe.text_4": "回転方向を逆にすることでバルブを閉められます", - - "create.ponder.water_wheel.header": "水車による回転力の生成", - "create.ponder.water_wheel.text_1": "水車は隣接する水流から回転力を生み出します", - "create.ponder.water_wheel.text_2": "水流を受ける面が多ければ多いほど、水車の回転速度は速くなります", - "create.ponder.water_wheel.text_3": "水車の羽根は水流に逆らわないように設置してください", - "create.ponder.water_wheel.text_4": "逆向きに設置すると、回転速度が落ちてしまいます", - - "create.ponder.weighted_ejector.header": "重量射出機の使い方", - "create.ponder.weighted_ejector.text_1": "射出機を持ってスニークしながら右クリックすると、対象となる位置を設定できます", - "create.ponder.weighted_ejector.text_10": "スタック数を設定すると、保持しているスタックがその量に達したときのみ射出するようになります", - "create.ponder.weighted_ejector.text_11": "他のエンティティが射出機を踏むと、いつでも射出機が稼働します", - "create.ponder.weighted_ejector.text_2": "設置した射出機は、設定した場所に物体を発射します", - "create.ponder.weighted_ejector.text_3": "範囲内であれば高さや距離は問いません", - "create.ponder.weighted_ejector.text_4": "ただし、真正面以外へは射出できません", - "create.ponder.weighted_ejector.text_5": "有効な位置が設定されていない場合、真正面のブロックが対象になります", - "create.ponder.weighted_ejector.text_6": "巻き上げるには、回転力を供給する必要があります", - "create.ponder.weighted_ejector.text_7": "上にアイテムを置くと、射出機が稼働します", - "create.ponder.weighted_ejector.text_8": "対象が満杯の収納ブロックの場合、射出機はそのブロックに空きがでるまで待機します", - "create.ponder.weighted_ejector.text_9": "レンチを使って、スタック量を調整できます", - - "create.ponder.weighted_ejector_redstone.header": "レッドストーン信号による重量射出機の制御", - "create.ponder.weighted_ejector_redstone.text_1": "レッドストーン信号を受けている間、射出機は稼働しません", - "create.ponder.weighted_ejector_redstone.text_2": "また、オブザーバーは射出機の稼働を検知できます", - - "create.ponder.weighted_ejector_tunnel.header": "重量射出機によるアイテムスタックの分割", - "create.ponder.weighted_ejector_tunnel.text_1": "真鍮トンネルと組み合わせて、アイテムスタックの特定の量だけを分割できます", - "create.ponder.weighted_ejector_tunnel.text_2": "まず、側面の搬出口を優先させる為に、真鍮トンネルを「最寄りを優先」に設定します", - "create.ponder.weighted_ejector_tunnel.text_3": "次に、射出機に分割したいスタック量を設定します", - "create.ponder.weighted_ejector_tunnel.text_4": "設定した量のアイテムスタックは側面の搬出口から搬出され...", - "create.ponder.weighted_ejector_tunnel.text_5": "...残りのアイテムはそのまま搬出されます", - - "create.ponder.windmill_source.header": "風車ベアリングによる回転力の生成", - "create.ponder.windmill_source.text_1": "風車ベアリングは手前にブロックを取り付けられます", - "create.ponder.windmill_source.text_2": "超粘着剤を使って動く構造物を作ってください", - "create.ponder.windmill_source.text_3": "帆とみなされる十分な数のブロックが取り付けられていれば、風車として機能します", - "create.ponder.windmill_source.text_4": "右クリックして風車ベアリングを起動すると、回転力を供給し始めます", - "create.ponder.windmill_source.text_5": "回転速度は帆ブロックの数で決まります", - "create.ponder.windmill_source.text_6": "レンチを使って回転方向を変えられます", - "create.ponder.windmill_source.text_7": "ベアリングを右クリックすれば、いつでも回転を停止させて構造物を組み立て直せます", - - "create.ponder.windmill_structure.header": "からくり風車", - "create.ponder.windmill_structure.text_1": "帆とみなされるブロックが8個以上あれば、どのような構造物でも風車として動きます", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json deleted file mode 100644 index 894c8dd154..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 9", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "아카시아나무 유리창", - "block.create.acacia_window_pane": "아카시아나무 유리판 ", - "block.create.adjustable_chain_gearshift": "벨트 변속기", - "block.create.analog_lever": "아날로그 레버", - "block.create.andesite_belt_funnel": "안산암 퍼널", - "block.create.andesite_casing": "안산암 케이스", - "block.create.andesite_encased_cogwheel": "안산암 케이스를 씌운 톱니바퀴", - "block.create.andesite_encased_large_cogwheel": "안산암 케이스를 씌운 큰 톱니바퀴", - "block.create.andesite_encased_shaft": "안산암 케이스를 씌운 축", - "block.create.andesite_funnel": "안산암 퍼널", - "block.create.andesite_ladder": "안산암 사다리", - "block.create.andesite_pillar": "안산암 기둥", - "block.create.andesite_tunnel": "안산암 터널", - "block.create.asurine": "담청암", - "block.create.asurine_pillar": "담청암 기둥", - "block.create.basin": "대야", - "block.create.belt": "벨트", - "block.create.birch_window": "자작나무 유리창", - "block.create.birch_window_pane": "자작나무 유리판", - "block.create.black_nixie_tube": "검은색 닉시관", - "block.create.black_sail": "검은색 날개", - "block.create.black_seat": "검은색 좌석", - "block.create.black_toolbox": "검은색 공구상자", - "block.create.black_valve_handle": "검은색 밸브 손잡이", - "block.create.blaze_burner": "블레이즈 버너", - "block.create.blue_nixie_tube": "파란색 닉시관", - "block.create.blue_sail": "파란색 날개", - "block.create.blue_seat": "파란색 좌석", - "block.create.blue_toolbox": "파란색 공구상자", - "block.create.blue_valve_handle": "파란색 밸브 손잡이", - "block.create.brass_belt_funnel": "황동 퍼널", - "block.create.brass_block": "황동 블록", - "block.create.brass_casing": "황동 케이스", - "block.create.brass_encased_cogwheel": "황동 케이스를 씌운 톱니바퀴", - "block.create.brass_encased_large_cogwheel": "황동 케이스를 씌운 큰 톱니바퀴", - "block.create.brass_encased_shaft": "황동 케이스를 씌운 축", - "block.create.brass_funnel": "황동 퍼널", - "block.create.brass_ladder": "황동 사다리", - "block.create.brass_tunnel": "황동 터널", - "block.create.brown_nixie_tube": "갈색 닉시관", - "block.create.brown_sail": "갈색 날개", - "block.create.brown_seat": "갈색 좌석", - "block.create.brown_toolbox": "갈색 공구상자", - "block.create.brown_valve_handle": "갈색 밸브 손잡이", - "block.create.calcite_pillar": "방해석 기둥", - "block.create.cart_assembler": "수레 조립기", - "block.create.chocolate": "초콜릿", - "block.create.chute": "슈트", - "block.create.clockwork_bearing": "시계 베어링", - "block.create.clutch": "클러치", - "block.create.cogwheel": "톱니바퀴", - "block.create.content_observer": "정보 감지기", - "block.create.controller_rail": "방향 레일", - "block.create.controls": "기차 조종기", - "block.create.copper_backtank": "구리 산소통", - "block.create.copper_casing": "구리 케이스", - "block.create.copper_ladder": "구리 사다리", - "block.create.copper_shingle_slab": "구리 판자 반 블록", - "block.create.copper_shingle_stairs": "구리 판자 계단", - "block.create.copper_shingles": "구리 판자", - "block.create.copper_tile_slab": "구리 타일 반 블록", - "block.create.copper_tile_stairs": "구리 타일 계단", - "block.create.copper_tiles": "구리 타일", - "block.create.copper_valve_handle": "구리 밸브 손잡이", - "block.create.creative_crate": "크리에이티브 창고", - "block.create.creative_fluid_tank": "크리에이티브 탱크", - "block.create.creative_motor": "크리에이티브 모터", - "block.create.crimsite": "진홍암", - "block.create.crimsite_pillar": "진홍암 기둥", - "block.create.crimson_window": "진홍빛 유리창", - "block.create.crimson_window_pane": "진홍빛 유리판", - "block.create.crushing_wheel": "분쇄 휠", - "block.create.crushing_wheel_controller": "분쇄 휠 컨트롤러", - "block.create.cuckoo_clock": "뻐꾸기 시계", - "block.create.cut_andesite": "깎인 안산암", - "block.create.cut_andesite_brick_slab": "깎인 안산암 벽돌 반 블록", - "block.create.cut_andesite_brick_stairs": "깎인 안산암 벽돌 계단", - "block.create.cut_andesite_brick_wall": "깎인 안산암 벽돌 담장", - "block.create.cut_andesite_bricks": "깎인 안산암 벽돌", - "block.create.cut_andesite_slab": "깎인 안산암 반 블록", - "block.create.cut_andesite_stairs": "깎인 안산암 계단", - "block.create.cut_andesite_wall": "깎인 안산암 담장", - "block.create.cut_asurine": "깎인 담청암", - "block.create.cut_asurine_brick_slab": "깎인 담청암 벽돌 반 블록", - "block.create.cut_asurine_brick_stairs": "깎인 담청암 벽돌 계단", - "block.create.cut_asurine_brick_wall": "깎인 담청암 벽돌 담장", - "block.create.cut_asurine_bricks": "깎인 담청암 벽돌", - "block.create.cut_asurine_slab": "깎인 담청암 반 블록", - "block.create.cut_asurine_stairs": "깎인 담청암 계단", - "block.create.cut_asurine_wall": "깎인 담청암 담장", - "block.create.cut_calcite": "깎인 방해석", - "block.create.cut_calcite_brick_slab": "깎인 방해석 벽돌 반 블록", - "block.create.cut_calcite_brick_stairs": "깎인 방해석 벽돌 계단", - "block.create.cut_calcite_brick_wall": "깎인 방해석 벽돌 담장", - "block.create.cut_calcite_bricks": "깎인 방해석 벽돌", - "block.create.cut_calcite_slab": "깎인 방해석 반 블록", - "block.create.cut_calcite_stairs": "깎인 방해석 계단", - "block.create.cut_calcite_wall": "깎인 방해석 담장", - "block.create.cut_crimsite": "깎인 진홍암", - "block.create.cut_crimsite_brick_slab": "깎인 진홍암 벽돌 반 블록", - "block.create.cut_crimsite_brick_stairs": "깎인 진홍암 벽돌 계단", - "block.create.cut_crimsite_brick_wall": "깎인 진홍암 벽돌 담장", - "block.create.cut_crimsite_bricks": "깎인 진홍암 벽돌", - "block.create.cut_crimsite_slab": "깎인 진홍암 반 블록", - "block.create.cut_crimsite_stairs": "깎인 진홍암 계단", - "block.create.cut_crimsite_wall": "깎인 진홍암 담장", - "block.create.cut_deepslate": "깎인 심층암", - "block.create.cut_deepslate_brick_slab": "깎인 심층암 벽돌 반 블록", - "block.create.cut_deepslate_brick_stairs": "깎인 심층암 벽돌 계단", - "block.create.cut_deepslate_brick_wall": "깎인 심층암 벽돌 담장", - "block.create.cut_deepslate_bricks": "깎인 심층암 벽돌", - "block.create.cut_deepslate_slab": "깎인 심층암 반 블록", - "block.create.cut_deepslate_stairs": "깎인 심층암 계단", - "block.create.cut_deepslate_wall": "깎인 심층암 담장", - "block.create.cut_diorite": "깎인 섬록암", - "block.create.cut_diorite_brick_slab": "깎인 섬록암 벽돌 반 블록", - "block.create.cut_diorite_brick_stairs": "깎인 섬록암 벽돌 계단", - "block.create.cut_diorite_brick_wall": "깎인 섬록암 벽돌 담장", - "block.create.cut_diorite_bricks": "깎인 섬록암 벽돌", - "block.create.cut_diorite_slab": "깎인 섬록암 반 블록", - "block.create.cut_diorite_stairs": "깎인 섬록암 계단", - "block.create.cut_diorite_wall": "깎인 섬록암 담장", - "block.create.cut_dripstone": "깎인 점적석", - "block.create.cut_dripstone_brick_slab": "깎인 점적석 벽돌 반 블록", - "block.create.cut_dripstone_brick_stairs": "깎인 점적석 벽돌 계단", - "block.create.cut_dripstone_brick_wall": "깎인 점적석 벽돌 담장", - "block.create.cut_dripstone_bricks": "깎인 점적석 벽돌", - "block.create.cut_dripstone_slab": "깎인 점적석 반 블록", - "block.create.cut_dripstone_stairs": "깎인 점적석 계단", - "block.create.cut_dripstone_wall": "깎인 점적석 담장", - "block.create.cut_granite": "깎인 화강암", - "block.create.cut_granite_brick_slab": "깎인 화강암 벽돌 반 블록", - "block.create.cut_granite_brick_stairs": "깎인 화강암 벽돌 계단", - "block.create.cut_granite_brick_wall": "깎인 화강암 벽돌 담장", - "block.create.cut_granite_bricks": "깎인 화강암 벽돌", - "block.create.cut_granite_slab": "깎인 화강암 반 블록", - "block.create.cut_granite_stairs": "깎인 화강암 계단", - "block.create.cut_granite_wall": "깎인 화강암 담장", - "block.create.cut_limestone": "깎인 석회암", - "block.create.cut_limestone_brick_slab": "깎인 석회암 벽돌 반 블록", - "block.create.cut_limestone_brick_stairs": "깎인 석회암 벽돌 계단", - "block.create.cut_limestone_brick_wall": "깎인 석회암 벽돌 담장", - "block.create.cut_limestone_bricks": "깎인 석회암 벽돌", - "block.create.cut_limestone_slab": "깎인 석회암 반 블록", - "block.create.cut_limestone_stairs": "깎인 석회암 계단", - "block.create.cut_limestone_wall": "깎인 석회암 담장", - "block.create.cut_ochrum": "깎인 황토암", - "block.create.cut_ochrum_brick_slab": "깎인 황토암 벽돌 반 블록", - "block.create.cut_ochrum_brick_stairs": "깎인 황토암 벽돌 계단", - "block.create.cut_ochrum_brick_wall": "깎인 황토암 벽돌 담장", - "block.create.cut_ochrum_bricks": "깎인 황토암 벽돌", - "block.create.cut_ochrum_slab": "깎인 황토암 반 블록", - "block.create.cut_ochrum_stairs": "깎인 황토암 계단", - "block.create.cut_ochrum_wall": "깎인 황토암 담장", - "block.create.cut_scorchia": "깎인 짙은 스코리아", - "block.create.cut_scorchia_brick_slab": "깎인 짙은 스코리아 벽돌 반 블록", - "block.create.cut_scorchia_brick_stairs": "깎인 짙은 스코리아 벽돌 계단", - "block.create.cut_scorchia_brick_wall": "깎인 짙은 스코리아 벽돌 담장", - "block.create.cut_scorchia_bricks": "깎인 짙은 스코리아 벽돌", - "block.create.cut_scorchia_slab": "깎인 짙은 스코리아 반 블록", - "block.create.cut_scorchia_stairs": "깎인 짙은 스코리아 계단", - "block.create.cut_scorchia_wall": "깎인 짙은 스코리아 담장", - "block.create.cut_scoria": "깎인 스코리아", - "block.create.cut_scoria_brick_slab": "깎인 스코리아 벽돌 반 블록", - "block.create.cut_scoria_brick_stairs": "깎인 스코리아 벽돌 계단", - "block.create.cut_scoria_brick_wall": "깎인 스코리아 벽돌 담장", - "block.create.cut_scoria_bricks": "깎인 스코리아 벽돌", - "block.create.cut_scoria_slab": "깎인 스코리아 반 블록", - "block.create.cut_scoria_stairs": "깎인 스코리아 계단", - "block.create.cut_scoria_wall": "깎인 스코리아 담장", - "block.create.cut_tuff": "깎인 응회암", - "block.create.cut_tuff_brick_slab": "깎인 응회암 벽돌 반 블록", - "block.create.cut_tuff_brick_stairs": "깎인 응회암 벽돌 계단", - "block.create.cut_tuff_brick_wall": "깎인 응회암 벽돌 담장", - "block.create.cut_tuff_bricks": "깎인 응회암 벽돌", - "block.create.cut_tuff_slab": "깎인 응회암 반 블록", - "block.create.cut_tuff_stairs": "깎인 응회암 계단", - "block.create.cut_tuff_wall": "깎인 응회암 담장", - "block.create.cut_veridium": "깎인 심록암", - "block.create.cut_veridium_brick_slab": "깎인 심록암 벽돌 반 블록", - "block.create.cut_veridium_brick_stairs": "깎인 심록암 벽돌 계단", - "block.create.cut_veridium_brick_wall": "깎인 심록암 벽돌 담장", - "block.create.cut_veridium_bricks": "깎인 심록암 벽돌", - "block.create.cut_veridium_slab": "깎인 심록암 반 블록", - "block.create.cut_veridium_stairs": "깎인 심록암 계단", - "block.create.cut_veridium_wall": "깎인 심록암 담장", - "block.create.cyan_nixie_tube": "청록색 닉시관", - "block.create.cyan_sail": "청록색 날개", - "block.create.cyan_seat": "청록색 좌석", - "block.create.cyan_toolbox": "청록색 공구상자", - "block.create.cyan_valve_handle": "청록색 밸브 손잡이", - "block.create.dark_oak_window": "짙은 참나무 유리창", - "block.create.dark_oak_window_pane": "짙은 참나무 유리판", - "block.create.deepslate_pillar": "심층암 기둥", - "block.create.deepslate_zinc_ore": "심층암 아연 광석", - "block.create.deployer": "기계 손", - "block.create.depot": "아이템 거치대", - "block.create.diorite_pillar": "섬록암 기둥", - "block.create.display_board": "디스플레이 화면", - "block.create.display_link": "디스플레이 링크", - "block.create.dripstone_pillar": "점적석 기둥", - "block.create.encased_chain_drive": "체인 드라이브", - "block.create.encased_fan": "선풍기", - "block.create.encased_fluid_pipe": "구리 케이스를 씌운 파이프", - "block.create.exposed_copper_shingle_slab": "약간 녹슨 구리 판자 반 블록", - "block.create.exposed_copper_shingle_stairs": "약간 녹슨 구리 판자 계단", - "block.create.exposed_copper_shingles": "약간 녹슨 구리 판자", - "block.create.exposed_copper_tile_slab": "약간 녹슨 구리 타일 반 블록", - "block.create.exposed_copper_tile_stairs": "약간 녹슨 구리 타일 계단", - "block.create.exposed_copper_tiles": "약간 녹슨 구리 타일", - "block.create.fake_track": "지도용 선로 표시", - "block.create.fluid_pipe": "액체 파이프", - "block.create.fluid_tank": "액체 탱크", - "block.create.fluid_valve": "액체 밸브", - "block.create.flywheel": "플라이휠", - "block.create.framed_glass": "큰 유리", - "block.create.framed_glass_door": "유리 문", - "block.create.framed_glass_pane": "큰 유리판", - "block.create.framed_glass_trapdoor": "유리 다락문", - "block.create.gantry_carriage": "갠트리 운반대", - "block.create.gantry_shaft": "갠트리 축", - "block.create.gearbox": "기어박스", - "block.create.gearshift": "기어쉬프트", - "block.create.glass_fluid_pipe": "액체 파이프", - "block.create.granite_pillar": "화강암 기둥", - "block.create.gray_nixie_tube": "회색 닉시관", - "block.create.gray_sail": "회색 날개", - "block.create.gray_seat": "회색 좌석", - "block.create.gray_toolbox": "회색 공구상자", - "block.create.gray_valve_handle": "회색 밸브 손잡이", - "block.create.green_nixie_tube": "초록색 닉시관", - "block.create.green_sail": "초록색 날개", - "block.create.green_seat": "초록색 좌석", - "block.create.green_toolbox": "초록색 공구상자", - "block.create.green_valve_handle": "초록색 밸브 손잡이", - "block.create.hand_crank": "핸드 크랭크", - "block.create.haunted_bell": "귀신들린 종", - "block.create.honey": "꿀", - "block.create.horizontal_framed_glass": "수평 유리", - "block.create.horizontal_framed_glass_pane": "수평 유리판", - "block.create.hose_pulley": "호스 도르래", - "block.create.item_drain": "아이템 배수구", - "block.create.item_vault": "아이템 금고", - "block.create.jungle_window": "정글나무 유리창", - "block.create.jungle_window_pane": "정글나무 유리판", - "block.create.large_bogey": "큰 대차", - "block.create.large_cogwheel": "큰 톱니바퀴", - "block.create.layered_andesite": "단층 안산암", - "block.create.layered_asurine": "단층 담청암", - "block.create.layered_calcite": "단층 방해석", - "block.create.layered_crimsite": "단층 진홍암", - "block.create.layered_deepslate": "단층 심층암", - "block.create.layered_diorite": "단층 섬록암", - "block.create.layered_dripstone": "단층 점적석", - "block.create.layered_granite": "단층 화강암", - "block.create.layered_limestone": "단층 석회암", - "block.create.layered_ochrum": "단층 황토암", - "block.create.layered_scorchia": "단층 짙은 스코리아", - "block.create.layered_scoria": "단층 스코리아", - "block.create.layered_tuff": "단층 응회암", - "block.create.layered_veridium": "단층 심록암", - "block.create.lectern_controller": "독서대 조작기", - "block.create.light_blue_nixie_tube": "하늘색 닉시관", - "block.create.light_blue_sail": "하늘색 날개", - "block.create.light_blue_seat": "하늘색 좌석", - "block.create.light_blue_toolbox": "하늘색 공구상자", - "block.create.light_blue_valve_handle": "하늘색 밸브 손잡이", - "block.create.light_gray_nixie_tube": "회백색 닉시관", - "block.create.light_gray_sail": "회백색 날개", - "block.create.light_gray_seat": "회백색 좌석", - "block.create.light_gray_toolbox": "회백색 공구상자", - "block.create.light_gray_valve_handle": "회백색 밸브 손잡이", - "block.create.lime_nixie_tube": "연두색 닉시관", - "block.create.lime_sail": "연두색 날개", - "block.create.lime_seat": "연두색 좌석", - "block.create.lime_toolbox": "연두색 공구상자", - "block.create.lime_valve_handle": "연두색 밸브 손잡이", - "block.create.limestone": "석회암", - "block.create.limestone_pillar": "석회암 기둥", - "block.create.linear_chassis": "어두운 직선 섀시", - "block.create.lit_blaze_burner": "불타는 빈 블레이즈 버너", - "block.create.magenta_nixie_tube": "자홍색 닉시관", - "block.create.magenta_sail": "자홍색 날개", - "block.create.magenta_seat": "자홍색 좌석", - "block.create.magenta_toolbox": "자홍색 공구상자", - "block.create.magenta_valve_handle": "자홍색 밸브 손잡이", - "block.create.mechanical_arm": "기계 팔", - "block.create.mechanical_bearing": "베어링", - "block.create.mechanical_crafter": "조합기", - "block.create.mechanical_drill": "드릴", - "block.create.mechanical_harvester": "수확기", - "block.create.mechanical_mixer": "믹서", - "block.create.mechanical_piston": "기계식 피스톤", - "block.create.mechanical_piston_head": "기계식 피스톤 머리", - "block.create.mechanical_plough": "쟁기", - "block.create.mechanical_press": "압착기", - "block.create.mechanical_pump": "펌프", - "block.create.mechanical_saw": "톱", - "block.create.metal_bracket": "금속 지지대", - "block.create.metal_girder": "금속 거더", - "block.create.metal_girder_encased_shaft": "축을 끼운 금속 거더", - "block.create.millstone": "맷돌", - "block.create.minecart_anchor": "광산 수레 정박기", - "block.create.mysterious_cuckoo_clock": "뻐꾸기 시계", - "block.create.nixie_tube": "닉시관", - "block.create.nozzle": "노즐", - "block.create.oak_window": "참나무 유리창", - "block.create.oak_window_pane": "참나무 유리판", - "block.create.ochrum": "황토암", - "block.create.ochrum_pillar": "황토암 기둥", - "block.create.orange_sail": "주황색 날개", - "block.create.orange_seat": "주황색 좌석", - "block.create.orange_toolbox": "주황색 공구상자", - "block.create.orange_valve_handle": "주황색 밸브 손잡이", - "block.create.ornate_iron_window": "장식된 철 유리창", - "block.create.ornate_iron_window_pane": "장식된 철 유리판", - "block.create.oxidized_copper_shingle_slab": "산화된 구리 판자 반 블록", - "block.create.oxidized_copper_shingle_stairs": "산화된 구리 판자 계단", - "block.create.oxidized_copper_shingles": "산화된 구리 판자", - "block.create.oxidized_copper_tile_slab": "산화된 구리 타일 반 블록", - "block.create.oxidized_copper_tile_stairs": "산화된 구리 타일 계단", - "block.create.oxidized_copper_tiles": "산화된 구리 타일", - "block.create.peculiar_bell": "황동 종", - "block.create.pink_nixie_tube": "분홍색 닉시관", - "block.create.pink_sail": "분홍색 날개", - "block.create.pink_seat": "분홍색 좌석", - "block.create.pink_toolbox": "분홍색 공구상자", - "block.create.pink_valve_handle": "분홍색 밸브 손잡이", - "block.create.piston_extension_pole": "피스톤 연장 축", - "block.create.placard": "플래카드", - "block.create.polished_cut_andesite": "윤나는 깎인 안산암", - "block.create.polished_cut_andesite_slab": "윤나는 깎인 안산암 반 블록", - "block.create.polished_cut_andesite_stairs": "윤나는 깎인 안산암 계단", - "block.create.polished_cut_andesite_wall": "윤나는 깎인 안산암 담장", - "block.create.polished_cut_asurine": "윤나는 깎인 담청암", - "block.create.polished_cut_asurine_slab": "윤나는 깎인 담청암 반 블록", - "block.create.polished_cut_asurine_stairs": "윤나는 깎인 담청암 계단", - "block.create.polished_cut_asurine_wall": "윤나는 깎인 담청암 담장", - "block.create.polished_cut_calcite": "윤나는 깎인 방해석", - "block.create.polished_cut_calcite_slab": "윤나는 깎인 방해석 반 블록", - "block.create.polished_cut_calcite_stairs": "윤나는 깎인 방해석 계단", - "block.create.polished_cut_calcite_wall": "윤나는 깎인 방해석 담장", - "block.create.polished_cut_crimsite": "윤나는 깎인 진홍암", - "block.create.polished_cut_crimsite_slab": "윤나는 깎인 진홍암 반 블록", - "block.create.polished_cut_crimsite_stairs": "윤나는 깎인 진홍암 계단", - "block.create.polished_cut_crimsite_wall": "윤나는 깎인 진홍암 담장", - "block.create.polished_cut_deepslate": "윤나는 깎인 심층암", - "block.create.polished_cut_deepslate_slab": "윤나는 깎인 심층암 반 블록", - "block.create.polished_cut_deepslate_stairs": "윤나는 깎인 심층암 계단", - "block.create.polished_cut_deepslate_wall": "윤나는 깎인 심층암 담장", - "block.create.polished_cut_diorite": "윤나는 깎인 섬록암", - "block.create.polished_cut_diorite_slab": "윤나는 깎인 섬록암 반 블록", - "block.create.polished_cut_diorite_stairs": "윤나는 깎인 섬록암 계단", - "block.create.polished_cut_diorite_wall": "윤나는 깎인 섬록암 담장", - "block.create.polished_cut_dripstone": "윤나는 깎인 점적석", - "block.create.polished_cut_dripstone_slab": "윤나는 깎인 점적석 반 블록", - "block.create.polished_cut_dripstone_stairs": "윤나는 깎인 점적석 계단", - "block.create.polished_cut_dripstone_wall": "윤나는 깎인 점적석 담장", - "block.create.polished_cut_granite": "윤나는 깎인 화강암", - "block.create.polished_cut_granite_slab": "윤나는 깎인 화강암 반 블록", - "block.create.polished_cut_granite_stairs": "윤나는 깎인 화강암 계단", - "block.create.polished_cut_granite_wall": "윤나는 깎인 화강암 담장", - "block.create.polished_cut_limestone": "윤나는 깎인 석회암", - "block.create.polished_cut_limestone_slab": "윤나는 깎인 석회암 반 블록", - "block.create.polished_cut_limestone_stairs": "윤나는 깎인 석회암 계단", - "block.create.polished_cut_limestone_wall": "윤나는 깎인 석회암 담장", - "block.create.polished_cut_ochrum": "윤나는 깎인 황토암", - "block.create.polished_cut_ochrum_slab": "윤나는 깎인 황토암 반 블록", - "block.create.polished_cut_ochrum_stairs": "윤나는 깎인 황토암 계단", - "block.create.polished_cut_ochrum_wall": "윤나는 깎인 황토암 담장", - "block.create.polished_cut_scorchia": "윤나는 깎인 짙은 스코리아", - "block.create.polished_cut_scorchia_slab": "윤나는 깎인 짙은 스코리아 반 블록", - "block.create.polished_cut_scorchia_stairs": "윤나는 깎인 짙은 스코리아 계단", - "block.create.polished_cut_scorchia_wall": "윤나는 깎인 짙은 스코리아 담장", - "block.create.polished_cut_scoria": "윤나는 깎인 스코리아", - "block.create.polished_cut_scoria_slab": "윤나는 깎인 스코리아 반 블록", - "block.create.polished_cut_scoria_stairs": "윤나는 깎인 스코리아 계단", - "block.create.polished_cut_scoria_wall": "윤나는 깎인 스코리아 담장", - "block.create.polished_cut_tuff": "윤나는 깎인 응회암", - "block.create.polished_cut_tuff_slab": "윤나는 깎인 응회암 반 블록", - "block.create.polished_cut_tuff_stairs": "윤나는 깎인 응회암 계단", - "block.create.polished_cut_tuff_wall": "윤나는 깎인 응회암 담장", - "block.create.polished_cut_veridium": "윤나는 깎인 심록암", - "block.create.polished_cut_veridium_slab": "윤나는 깎인 심록암 반 블록", - "block.create.polished_cut_veridium_stairs": "윤나는 깎인 심록암 계단", - "block.create.polished_cut_veridium_wall": "윤나는 깎인 심록암 담장", - "block.create.portable_fluid_interface": "액체 인터페이스", - "block.create.portable_storage_interface": "아이템 인터페이스", - "block.create.powered_latch": "레드스톤 걸쇠", - "block.create.powered_shaft": "레드스톤 축", - "block.create.powered_toggle_latch": "레드스톤 토글 걸쇠", - "block.create.pulley_magnet": "도르래 자석", - "block.create.pulse_extender": "펄스 연장기", - "block.create.pulse_repeater": "펄스 중계기", - "block.create.purple_nixie_tube": "보라색 닉시관", - "block.create.purple_sail": "보라색 날개", - "block.create.purple_seat": "보라색 좌석", - "block.create.purple_toolbox": "보라색 공구상자", - "block.create.purple_valve_handle": "보라색 밸브 손잡이", - "block.create.radial_chassis": "원형 섀시", - "block.create.railway_casing": "기차 케이스", - "block.create.raw_zinc_block": "아연 원석 블록", - "block.create.red_nixie_tube": "빨간색 닉시관", - "block.create.red_sail": "빨간색 날개", - "block.create.red_seat": "빨간색 좌석", - "block.create.red_toolbox": "빨간색 공구상자", - "block.create.red_valve_handle": "빨간색 밸브 손잡이", - "block.create.redstone_contact": "동형 감지기", - "block.create.redstone_link": "레드스톤 링크", - "block.create.refined_radiance_casing": "빛나는 케이스", - "block.create.rope": "밧줄", - "block.create.rope_pulley": "밧줄 도르래", - "block.create.rose_quartz_block": "장밋빛 석영 블록", - "block.create.rose_quartz_lamp": "장밋빛 석영 조명", - "block.create.rose_quartz_tiles": "장밋빛 석영 타일", - "block.create.rotation_speed_controller": "회전 속도 컨트롤러", - "block.create.sail_frame": "풍차 날개 틀", - "block.create.schematic_table": "설계도 탁자", - "block.create.schematicannon": "설계도 대포", - "block.create.scorchia": "짙은 스코리아", - "block.create.scorchia_pillar": "짙은 스코리아 기둥", - "block.create.scoria": "스코리아", - "block.create.scoria_pillar": "스코리아 기둥", - "block.create.secondary_linear_chassis": "밝은 직선 섀시", - "block.create.sequenced_gearshift": "순서 기어쉬프트", - "block.create.shadow_steel_casing": "그림자 케이스", - "block.create.shaft": "축", - "block.create.small_andesite_brick_slab": "작은 안산암 벽돌 반 블록", - "block.create.small_andesite_brick_stairs": "작은 안산암 벽돌 계단", - "block.create.small_andesite_brick_wall": "작은 안산암 벽돌 담장", - "block.create.small_andesite_bricks": "작은 안산암 벽돌", - "block.create.small_asurine_brick_slab": "작은 담청암 벽돌 반 블록", - "block.create.small_asurine_brick_stairs": "작은 담청암 벽돌 계단", - "block.create.small_asurine_brick_wall": "작은 담청암 벽돌 담장", - "block.create.small_asurine_bricks": "작은 담청암 벽돌", - "block.create.small_bogey": "작은 대차", - "block.create.small_calcite_brick_slab": "작은 방해석 벽돌 반 블록", - "block.create.small_calcite_brick_stairs": "작은 방해석 벽돌 계단", - "block.create.small_calcite_brick_wall": "작은 방해석 벽돌 담장", - "block.create.small_calcite_bricks": "작은 방해석 벽돌", - "block.create.small_crimsite_brick_slab": "작은 진홍암 벽돌 반 블록", - "block.create.small_crimsite_brick_stairs": "작은 진홍암 벽돌 계단", - "block.create.small_crimsite_brick_wall": "작은 진홍암 벽돌 담장", - "block.create.small_crimsite_bricks": "작은 진홍암 벽돌", - "block.create.small_deepslate_brick_slab": "작은 심층암 벽돌 반 블록", - "block.create.small_deepslate_brick_stairs": "작은 심층암 벽돌 계단", - "block.create.small_deepslate_brick_wall": "작은 심층암 벽돌 담장", - "block.create.small_deepslate_bricks": "작은 심층암 벽돌", - "block.create.small_diorite_brick_slab": "작은 섬록암 벽돌 반 블록", - "block.create.small_diorite_brick_stairs": "작은 섬록암 벽돌 계단", - "block.create.small_diorite_brick_wall": "작은 섬록암 벽돌 담장", - "block.create.small_diorite_bricks": "작은 섬록암 벽돌", - "block.create.small_dripstone_brick_slab": "작은 점적석 벽돌 반 블록", - "block.create.small_dripstone_brick_stairs": "작은 점적석 벽돌 계단", - "block.create.small_dripstone_brick_wall": "작은 점적석 벽돌 담장", - "block.create.small_dripstone_bricks": "작은 점적석 벽돌", - "block.create.small_granite_brick_slab": "작은 화강암 벽돌 반 블록", - "block.create.small_granite_brick_stairs": "작은 화강암 벽돌 계단", - "block.create.small_granite_brick_wall": "작은 화강암 벽돌 담장", - "block.create.small_granite_bricks": "작은 화강암 벽돌", - "block.create.small_limestone_brick_slab": "작은 석회암 벽돌 반 블록", - "block.create.small_limestone_brick_stairs": "작은 석회암 벽돌 계단", - "block.create.small_limestone_brick_wall": "작은 석회암 벽돌 담장", - "block.create.small_limestone_bricks": "작은 석회암 벽돌", - "block.create.small_ochrum_brick_slab": "작은 황토암 벽돌 반 블록", - "block.create.small_ochrum_brick_stairs": "작은 황토암 벽돌 계단", - "block.create.small_ochrum_brick_wall": "작은 황토암 벽돌 담장", - "block.create.small_ochrum_bricks": "작은 황토암 벽돌", - "block.create.small_rose_quartz_tiles": "작은 장밋빛 석영 타일", - "block.create.small_scorchia_brick_slab": "작은 짙은 스코리아 벽돌 반 블록", - "block.create.small_scorchia_brick_stairs": "작은 짙은 스코리아 벽돌 계단", - "block.create.small_scorchia_brick_wall": "작은 짙은 스코리아 벽돌 담장", - "block.create.small_scorchia_bricks": "작은 짙은 스코리아 벽돌", - "block.create.small_scoria_brick_slab": "작은 스코리아 벽돌 반 블록", - "block.create.small_scoria_brick_stairs": "작은 스코리아 벽돌 계단", - "block.create.small_scoria_brick_wall": "작은 스코리아 벽돌 담장", - "block.create.small_scoria_bricks": "작은 스코리아 벽돌", - "block.create.small_tuff_brick_slab": "작은 응회암 벽돌 반 블록", - "block.create.small_tuff_brick_stairs": "작은 응회암 벽돌 계단", - "block.create.small_tuff_brick_wall": "작은 응회암 벽돌 담장", - "block.create.small_tuff_bricks": "작은 응회암 벽돌", - "block.create.small_veridium_brick_slab": "작은 심록암 벽돌 반 블록", - "block.create.small_veridium_brick_stairs": "작은 심록암 벽돌 계단", - "block.create.small_veridium_brick_wall": "작은 심록암 벽돌 담장", - "block.create.small_veridium_bricks": "작은 심록암 벽돌", - "block.create.smart_chute": "스마트 슈트", - "block.create.smart_fluid_pipe": "스마트 액체 파이프", - "block.create.speedometer": "속도 계측기", - "block.create.spout": "주입기", - "block.create.spruce_window": "가문비나무 유리창", - "block.create.spruce_window_pane": "가문비나무 유리판", - "block.create.steam_engine": "증기 엔진", - "block.create.steam_whistle": "기적 장치", - "block.create.steam_whistle_extension": "기적 연장 장치", - "block.create.sticker": "부착기", - "block.create.sticky_mechanical_piston": "기계식 끈끈이 피스톤", - "block.create.stockpile_switch": "수량 스위치", - "block.create.stressometer": "피로도 계측기", - "block.create.tiled_glass": "타일 유리", - "block.create.tiled_glass_pane": "타일 유리판", - "block.create.track": "기차 선로", - "block.create.track_observer": "기차 감지기", - "block.create.track_signal": "기차 신호기", - "block.create.track_station": "기차 정거장", - "block.create.train_door": "기차 문", - "block.create.train_trapdoor": "기차 다락문", - "block.create.tuff_pillar": "응회암 기둥", - "block.create.turntable": "돌림판", - "block.create.veridium": "심록암", - "block.create.veridium_pillar": "심록암 기둥", - "block.create.vertical_framed_glass": "수직 유리", - "block.create.vertical_framed_glass_pane": "수직 유리판", - "block.create.warped_window": "뒤틀린 유리창", - "block.create.warped_window_pane": "뒤틀린 유리판", - "block.create.water_wheel": "물레바퀴", - "block.create.waxed_copper_shingle_slab": "밀랍칠한 구리 판자 반 블록", - "block.create.waxed_copper_shingle_stairs": "밀랍칠한 구리 판자 계단", - "block.create.waxed_copper_shingles": "밀랍칠한 구리 판자", - "block.create.waxed_copper_tile_slab": "밀랍칠한 구리 타일 반 블록", - "block.create.waxed_copper_tile_stairs": "밀랍칠한 구리 타일 계단", - "block.create.waxed_copper_tiles": "밀랍칠한 구리 타일", - "block.create.waxed_exposed_copper_shingle_slab": "밀랍칠한 약간 녹슨 구리 판자 반 블록", - "block.create.waxed_exposed_copper_shingle_stairs": "밀랍칠한 약간 녹슨 구리 판자 계단", - "block.create.waxed_exposed_copper_shingles": "밀랍칠한 약간 녹슨 구리 판자", - "block.create.waxed_exposed_copper_tile_slab": "밀랍칠한 약간 녹슨 구리 타일 반 블록", - "block.create.waxed_exposed_copper_tile_stairs": "밀랍칠한 약간 녹슨 구리 타일 계단", - "block.create.waxed_exposed_copper_tiles": "밀랍칠한 약간 녹슨 구리 타일", - "block.create.waxed_oxidized_copper_shingle_slab": "밀랍칠한 산화된 구리 판자 반 블록", - "block.create.waxed_oxidized_copper_shingle_stairs": "밀랍칠한 산화된 구리 판자 계단", - "block.create.waxed_oxidized_copper_shingles": "밀랍칠한 산화된 구리 판자", - "block.create.waxed_oxidized_copper_tile_slab": "밀랍칠한 산화된 구리 타일 반 블록", - "block.create.waxed_oxidized_copper_tile_stairs": "밀랍칠한 산화된 구리 타일 계단", - "block.create.waxed_oxidized_copper_tiles": "밀랍칠한 산화된 구리 타일", - "block.create.waxed_weathered_copper_shingle_slab": "밀랍칠한 녹슨 구리 판자 반 블록", - "block.create.waxed_weathered_copper_shingle_stairs": "밀랍칠한 녹슨 구리 판자 계단", - "block.create.waxed_weathered_copper_shingles": "밀랍칠한 녹슨 구리 판자", - "block.create.waxed_weathered_copper_tile_slab": "밀랍칠한 녹슨 구리 타일 반 블록", - "block.create.waxed_weathered_copper_tile_stairs": "밀랍칠한 녹슨 구리 타일 계단", - "block.create.waxed_weathered_copper_tiles": "밀랍칠한 녹슨 구리 타일", - "block.create.weathered_copper_shingle_slab": "녹슨 구리 판자 반 블록", - "block.create.weathered_copper_shingle_stairs": "녹슨 구리 판자 계단", - "block.create.weathered_copper_shingles": "녹슨 구리 판자", - "block.create.weathered_copper_tile_slab": "녹슨 구리 타일 반 블록", - "block.create.weathered_copper_tile_stairs": "녹슨 구리 타일 계단", - "block.create.weathered_copper_tiles": "녹슨 구리 타일", - "block.create.weighted_ejector": "투척기", - "block.create.white_nixie_tube": "하얀색 닉시관", - "block.create.white_sail": "하얀색 날개", - "block.create.white_seat": "하얀색 좌석", - "block.create.white_toolbox": "하얀색 공구상자", - "block.create.white_valve_handle": "하얀색 밸브 손잡이", - "block.create.windmill_bearing": "풍차 베어링", - "block.create.wooden_bracket": "나무 지지대", - "block.create.yellow_nixie_tube": "노란색 닉시관", - "block.create.yellow_sail": "노란색 날개", - "block.create.yellow_seat": "노란색 좌석", - "block.create.yellow_toolbox": "노란색 공구상자", - "block.create.yellow_valve_handle": "노란색 밸브 손잡이", - "block.create.zinc_block": "아연 블록", - "block.create.zinc_ore": "아연 광석", - - "enchantment.create.capacity": "저장량", - "enchantment.create.potato_recovery": "대포알 회수", - - "entity.create.carriage_contraption": "기차 구조물", - "entity.create.contraption": "구조물", - "entity.create.crafting_blueprint": "조합 청사진", - "entity.create.gantry_contraption": "갠트리 구조물", - "entity.create.potato_projectile": "감자포 투사체", - "entity.create.seat": "좌석", - "entity.create.stationary_contraption": "고정된 구조물", - "entity.create.super_glue": "강력 접착제", - - "fluid.create.potion": "포션", - "fluid.create.tea": "건축가의 차", - - "item.create.andesite_alloy": "안산암 합금", - "item.create.attribute_filter": "속성 필터 틀", - "item.create.bar_of_chocolate": "초콜릿 바", - "item.create.belt_connector": "벨트", - "item.create.blaze_cake": "블레이즈 케이크", - "item.create.blaze_cake_base": "블레이즈 케이크 틀", - "item.create.brass_hand": "황동 손", - "item.create.brass_ingot": "황동 주괴", - "item.create.brass_nugget": "황동 조각", - "item.create.brass_sheet": "황동 판", - "item.create.builders_tea": "건축가의 차", - "item.create.chest_minecart_contraption": "상자가 실린 광산 수레 구조물", - "item.create.chocolate_bucket": "초콜릿 양동이", - "item.create.chocolate_glazed_berries": "초콜릿 바른 열매", - "item.create.chromatic_compound": "색채 혼합물", - "item.create.cinder_flour": "잿가루", - "item.create.copper_backtank": "구리 산소통", - "item.create.copper_backtank_placeable": "구리 산소통", - "item.create.copper_nugget": "구리 조각", - "item.create.copper_sheet": "구리 판", - "item.create.crafter_slot_cover": "조합기 슬롯 덮개", - "item.create.crafting_blueprint": "조합 청사진", - "item.create.creative_blaze_cake": "크리에이티브 블레이즈 케이크", - "item.create.crushed_aluminum_ore": "분쇄된 알루미늄 광석", - "item.create.crushed_copper_ore": "분쇄된 구리 광석", - "item.create.crushed_gold_ore": "분쇄된 금 광석", - "item.create.crushed_iron_ore": "분쇄된 철 광석", - "item.create.crushed_lead_ore": "분쇄된 납 광석", - "item.create.crushed_nickel_ore": "분쇄된 니켈 광석", - "item.create.crushed_osmium_ore": "분쇄된 오스뮴 광석", - "item.create.crushed_platinum_ore": "분쇄된 플래티넘 광석", - "item.create.crushed_quicksilver_ore": "분쇄된 수은 광석", - "item.create.crushed_silver_ore": "분쇄된 은 광석", - "item.create.crushed_tin_ore": "분쇄된 주석 광석", - "item.create.crushed_uranium_ore": "분쇄된 우라늄 광석", - "item.create.crushed_zinc_ore": "분쇄된 아연 광석", - "item.create.diving_boots": "다이빙 부츠", - "item.create.diving_helmet": "다이빙 헬멧", - "item.create.dough": "반죽", - "item.create.electron_tube": "전지 튜브", - "item.create.empty_blaze_burner": "빈 블레이즈 버너", - "item.create.empty_schematic": "빈 설계도", - "item.create.experience_nugget": "경험의 조각", - "item.create.extendo_grip": "외장형 연장 팔", - "item.create.filter": "필터 틀", - "item.create.furnace_minecart_contraption": "화로가 실린 광산 수레 구조물", - "item.create.goggles": "엔지니어의 고글", - "item.create.golden_sheet": "금 판", - "item.create.handheld_worldshaper": "크리에이티브 세계편집기", - "item.create.honey_bucket": "꿀 양동이", - "item.create.honeyed_apple": "꿀 바른 사과", - "item.create.incomplete_precision_mechanism": "미완성된 정밀 기계장치", - "item.create.incomplete_track": "미완성된 기차 선로", - "item.create.iron_sheet": "철 판", - "item.create.linked_controller": "레드스톤 링크 조작기", - "item.create.minecart_contraption": "광산 수레 구조물", - "item.create.minecart_coupling": "광산 수레 커플링", - "item.create.polished_rose_quartz": "윤나는 장밋빛 석영", - "item.create.potato_cannon": "감자포", - "item.create.powdered_obsidian": "흑요석 가루", - "item.create.precision_mechanism": "정밀 기계장치", - "item.create.propeller": "프로펠러", - "item.create.raw_zinc": "아연 원석", - "item.create.red_sand_paper": "붉은 사포", - "item.create.refined_radiance": "정제된 광채", - "item.create.rose_quartz": "장밋빛 석영", - "item.create.sand_paper": "사포", - "item.create.schedule": "기차 계획표", - "item.create.schematic": "설계도", - "item.create.schematic_and_quill": "설계도와 깃펜", - "item.create.shadow_steel": "그림자 강철", - "item.create.sturdy_sheet": "강판", - "item.create.super_glue": "강력 접착제", - "item.create.sweet_roll": "롤빵", - "item.create.tree_fertilizer": "나무 비료", - "item.create.unprocessed_obsidian_sheet": "미완성된 흑요석 판", - "item.create.vertical_gearbox": "수직 기어박스", - "item.create.wand_of_symmetry": "대칭의 지팡이", - "item.create.wheat_flour": "밀가루", - "item.create.whisk": "혼합기", - "item.create.wrench": "렌치", - "item.create.zinc_ingot": "아연 주괴", - "item.create.zinc_nugget": "아연 조각", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Create!", - "advancement.create.root.desc": "장치가 있으라!", - "advancement.create.andesite_alloy": "더 단단한 재료", - "advancement.create.andesite_alloy.desc": "안산안 합금을 얻으세요. Create모드의 가장 중요한 자원입니다", - "advancement.create.andesite_casing": "안산암 시대", - "advancement.create.andesite_casing.desc": "안산암 합금을 나무에 붙여 기본적인 케이스를 만드세요", - "advancement.create.mechanical_press": "'깡!'", - "advancement.create.mechanical_press.desc": "압착기에서 판을 만드세요", - "advancement.create.encased_fan": "바람 생성기", - "advancement.create.encased_fan.desc": "선풍기를 설치하고 작동시키세요", - "advancement.create.fan_processing": "입자로 가공하다", - "advancement.create.fan_processing.desc": "선풍기로 재료를 가공하세요", - "advancement.create.saw_processing": "작업소에서 가장 두려운 존재", - "advancement.create.saw_processing.desc": "위로 눕힌 톱으로 재료를 가공하세요", - "advancement.create.compacting": "압축", - "advancement.create.compacting.desc": "압착기와 대야로 많은 아이템을 압축하세요", - "advancement.create.belt": "켈프 벨트", - "advancement.create.belt.desc": "두 축에 벨트를 이으세요", - "advancement.create.funnel": "공항 체크인", - "advancement.create.funnel.desc": "퍼널을 이용해 보관함에서 아이템을 넣거나 빼내세요", - "advancement.create.chute": "수직 물류", - "advancement.create.chute.desc": "슈트로 아이템을 옮기세요", - "advancement.create.mechanical_mixer": "섞고 돌리고 섞고", - "advancement.create.mechanical_mixer.desc": "믹서로 재료들을 섞으세요", - "advancement.create.burner": "살아있는 난로", - "advancement.create.burner.desc": "블레이즈 버너를 얻으세요", - "advancement.create.water_wheel": "수력 동력화", - "advancement.create.water_wheel.desc": "물레바퀴를 설치하고 회전하게 만드세요", - "advancement.create.windmill": "산들 바람", - "advancement.create.windmill.desc": "풍차 베어링을 작동시키세요", - "advancement.create.shifting_gears": "기어 변속", - "advancement.create.shifting_gears.desc": "크기가 다른 톱니바퀴를 연결하여 장치의 속도를 바꿀 수 있습니다", - "advancement.create.millstone": "나만의 작은 분쇄기", - "advancement.create.millstone.desc": "멧돌을 설치하고 작동시키세요.", - "advancement.create.super_glue": "영역 접착", - "advancement.create.super_glue.desc": "여러 블록을 한 그룹으로 접착시키세요", - "advancement.create.contraption_actors": "목적있는 이동", - "advancement.create.contraption_actors.desc": "드릴이나 톱, 수확기를 장착한 구조물을 만드세요", - "advancement.create.portable_storage_interface": "드라이브스루 교환", - "advancement.create.portable_storage_interface.desc": "아이템 인터페이스를 통해 구조물에서 아이템을 넣거나 빼세요", - "advancement.create.wrench_goggles": "작업 준비 완료!", - "advancement.create.wrench_goggles.desc": "엔지니어의 고글과 렌치를 장착하세요", - "advancement.create.stressometer": "괴짜들을 위한 피로도", - "advancement.create.stressometer.desc": "피로도 계측기와 고글로 정확한 수치를 확인하세요", - "advancement.create.cuckoo_clock": "벌써 잘 시간이야?", - "advancement.create.cuckoo_clock.desc": "뻐꾸기 시계가 잘 시간을 알립니다. 잘 자...", - "advancement.create.windmill_maxed": "거센 바람", - "advancement.create.windmill_maxed.desc": "풍차 베어링을 최대 속력으로 작동시키세요", - "advancement.create.ejector_maxed": "스프링보드 챔피언", - "advancement.create.ejector_maxed.desc": "투척기로 30블록 이상 날아가세요", - "advancement.create.pulley_maxed": "어디로든밧줄", - "advancement.create.pulley_maxed.desc": "밧줄 도르래를 200블록 이상 늘리세요", - "advancement.create.cart_pickup": "강한 팔", - "advancement.create.cart_pickup.desc": "최소 200블록이 붙은 광산 수레 구조물을 들어올리세요", - "advancement.create.anvil_plough": "대장장이포", - "advancement.create.anvil_plough.desc": "쟁기로 모루를 날리세요!", - "advancement.create.lava_wheel_00000": "불레바퀴", - "advancement.create.lava_wheel_00000.desc": "용암으로 물레바퀴를 회전시키세요..?§7\n(숨겨진 발전과제)", - "advancement.create.hand_crank_000": "워크아웃 세션", - "advancement.create.hand_crank_000.desc": "힘이 빠질때까지 핸드 크랭크를 돌리세요§7\n(숨겨진 발전과제)", - "advancement.create.belt_funnel_kiss": "퍼널은 어떻게 태어나?", - "advancement.create.belt_funnel_kiss.desc": "두 벨트 퍼널을 만나게하세요. 쪽!", - "advancement.create.stressometer_maxed": "완벽한 과부하", - "advancement.create.stressometer_maxed.desc": "피로도 계측기에서 100% 수치를 확인하세요§7\n(숨겨진 발전과제)", - "advancement.create.copper": "더욱 더 단단한 재료", - "advancement.create.copper.desc": "액체를 다루기 위해 구리를 모아두세요", - "advancement.create.copper_casing": "구리 시대", - "advancement.create.copper_casing.desc": "구리 주괴를 나무에 붙여 방수 케이스를 만드세요", - "advancement.create.spout": "쪼르록", - "advancement.create.spout.desc": "주입기를 사용하여 아이템에 액체를 채우는 것을 보세요", - "advancement.create.drain": "데굴데굴 배수", - "advancement.create.drain.desc": "아이템 배수구가 액체를 비우는 것을 관찰하세요", - "advancement.create.steam_engine": "동력실 가동", - "advancement.create.steam_engine.desc": "증기 엔진을 사용해 동력을 생산하세요", - "advancement.create.steam_whistle": "천상의 목소리", - "advancement.create.steam_whistle.desc": "기적 장치를 작동시키세요", - "advancement.create.backtank": "기압과 함께", - "advancement.create.backtank.desc": "구리 산소통을 제작하고 기압을 축적하세요", - "advancement.create.diving_suit": "심해와 맞서다", - "advancement.create.diving_suit.desc": "다이빙 헬멧과 산소통을 장착하고 입수하세요", - "advancement.create.mechanical_pump_0": "펌프 가동", - "advancement.create.mechanical_pump_0.desc": "펌프를 설치하고 작동시키세요", - "advancement.create.glass_pipe": "액체 엿보기", - "advancement.create.glass_pipe.desc": "액체가 지나가는 파이프에 렌치를 사용하세요", - "advancement.create.water_supply": "웅덩이 수집가", - "advancement.create.water_supply.desc": "빨아들이는 파이프 끝이나 펌프를 이용해 물 블록을 흡수하세요", - "advancement.create.hose_pulley": "공업 유출", - "advancement.create.hose_pulley.desc": "호스 도르래를 사용하여 액체를 채우거나 빨아들이세요", - "advancement.create.chocolate_bucket": "상상의 세계", - "advancement.create.chocolate_bucket.desc": "초콜릿 양동이를 얻으세요", - "advancement.create.honey_drain": "자동 양봉장", - "advancement.create.honey_drain.desc": "파이프를 이용해 벌집이나 벌통에서 꿀을 빼내세요", - "advancement.create.hose_pulley_lava": "맨틀 두드리기", - "advancement.create.hose_pulley_lava.desc": "무한으로 인식되는 용암 웅덩이에서 용암을 끌어올리세요", - "advancement.create.steam_engine_maxed": "엔진 풀가동", - "advancement.create.steam_engine_maxed.desc": "보일러를 최고 레벨로 작동시키세요", - "advancement.create.foods": "달콤한 식단", - "advancement.create.foods.desc": "초콜릿 바른 열매, 꿀 바른 사과, 롤빵을 하나의 주입기에서 만드세요", - "advancement.create.diving_suit_lava": "스트라이더와 함께 수영을", - "advancement.create.diving_suit_lava.desc": "잠수복을 입고 용암에 입수하세요§7\n(숨겨진 발전과제)", - "advancement.create.chained_drain": "데구르르 굴러가", - "advancement.create.chained_drain.desc": "아이템이 여러 배수구 위를 굴러가는 것을 관찰하세요§7\n(숨겨진 발전과제)", - "advancement.create.cross_streams": "그 액체를 섞지 마오", - "advancement.create.cross_streams.desc": "액체관에서 두 가지 액체가 만나는 것을 관찰하세요§7\n(숨겨진 발전과제)", - "advancement.create.pipe_organ": "파이프 오르간", - "advancement.create.pipe_organ.desc": "하나의 액체 탱크에 각각 다른 음의 기적 장치를 12개 붙이세요§7\n(숨겨진 발전과제)", - "advancement.create.brass": "진짜 합금", - "advancement.create.brass.desc": "블레이즈의 힘으로 구리와 아연을 섞어 황동을 만드세요.", - "advancement.create.brass_casing": "황동 시대", - "advancement.create.brass_casing.desc": "황동을 나무에 붙여 정교한 케이스를 만드세요.", - "advancement.create.rose_quartz": "장밋빛 다이아몬드", - "advancement.create.rose_quartz.desc": "장밋빛 석영을 사포질하세요", - "advancement.create.deployer": "인공 지능", - "advancement.create.deployer.desc": "당신의 분신, 기계 손을 설치하고 작동시키세요.", - "advancement.create.precision_mechanism": "복잡한 호기심", - "advancement.create.precision_mechanism.desc": "정밀 기계장치를 조립하세요.", - "advancement.create.speed_controller": "엔지니어들이 이 장치를 싫어합니다!", - "advancement.create.speed_controller.desc": "회전 속도 컨트롤러로 정밀하게 속도를 조절하세요", - "advancement.create.mechanical_arm": "바쁘다 바빠!", - "advancement.create.mechanical_arm.desc": "기계 팔이 아이템을 옮기는 것을 관찰하세요", - "advancement.create.mechanical_crafter": "자동 조합", - "advancement.create.mechanical_crafter.desc": "조합기를 설치하고 작동시키세요", - "advancement.create.crushing_wheel": "한 쌍의 거인들", - "advancement.create.crushing_wheel.desc": "분쇄 휠을 제작하고 가동시키세요", - "advancement.create.haunted_bell": "영혼의 목소리", - "advancement.create.haunted_bell.desc": "귀신들린 종을 울리세요", - "advancement.create.clockwork_bearing": "시계기계", - "advancement.create.clockwork_bearing.desc": "시계 베어링에 구조물을 달고 작동시키세요", - "advancement.create.display_link": "빅 데이터", - "advancement.create.display_link.desc": "디스플레이 링크로 정보를 시각화하세요", - "advancement.create.potato_cannon": "'퐁!'", - "advancement.create.potato_cannon.desc": "감자포로 적을 처치하세요", - "advancement.create.extendo_grip": "띠요옹!", - "advancement.create.extendo_grip.desc": "외장형 연장 팔을 손에 쥐세요", - "advancement.create.linked_controller": "원격 조종", - "advancement.create.linked_controller.desc": "링크 조작기로 레드스톤 링크에 신호를 보내세요", - "advancement.create.arm_blaze_burner": "연료를 줄 수 있는 정도의 능력", - "advancement.create.arm_blaze_burner.desc": "기계 팔이 블레이즈 버너에 연료를 넣도록 하세요", - "advancement.create.crusher_maxed_0000": "갈갈갈갈", - "advancement.create.crusher_maxed_0000.desc": "한 쌍의 분쇄 휠을 최고 속도로 가동하세요", - "advancement.create.arm_many_targets": "정리를 할 수 있는 정도의 능력", - "advancement.create.arm_many_targets.desc": "기계 팔에 10개 이상의 출력부를 설정하세요", - "advancement.create.potato_cannon_collide": "비건 폭죽", - "advancement.create.potato_cannon_collide.desc": "서로 다른 감자포 투사체가 서로 부딪히게 하세요", - "advancement.create.self_deploying": "자율주행 수레", - "advancement.create.self_deploying.desc": "스스로 길을 이어가는 광산 수레 구조물을 제작하세요", - "advancement.create.fist_bump": "하이파이브!", - "advancement.create.fist_bump.desc": "두 기계 손을 서로 부딪치게 하세요§7\n(숨겨진 발전과제)", - "advancement.create.crafter_lazy_000": "임시방편", - "advancement.create.crafter_lazy_000.desc": "부족한 시설때문에 어쩔 수 없이 조합기의 속도를 크게 낮추세요§7\n(숨겨진 발전과제)", - "advancement.create.extendo_grip_dual": "띠요오오오오오오용!", - "advancement.create.extendo_grip_dual.desc": "양손에 외장형 연장 팔을 들어 초월적인 사거리를 가지세요§7\n(숨겨진 발전과제)", - "advancement.create.musical_arm": "볼륨 최대로!", - "advancement.create.musical_arm.desc": "기계 팔이 주크박스를 작동시키는 것을 보세요.", - "advancement.create.sturdy_sheet": "가장 단단한 재료", - "advancement.create.sturdy_sheet.desc": "분쇄된 흑요석을 제련하여 강판을 제작하세요", - "advancement.create.train_casing_00": "물류 시대", - "advancement.create.train_casing_00.desc": "강판을 이용하여 기차 부품에 쓰이는 케이스를 만드세요", - "advancement.create.train": "기차 나가신다!", - "advancement.create.train.desc": "첫 기차를 조립하세요", - "advancement.create.conductor": "기관사 교육", - "advancement.create.conductor.desc": "기차 계획표로 기관사를 가르치세요", - "advancement.create.track_signal": "교통 통제", - "advancement.create.track_signal.desc": "기차 신호기를 설치하세요", - "advancement.create.display_board_0": "유동적인 계획표", - "advancement.create.display_board_0.desc": "디스플레이 링크와 디스플레이 화면을 이용해 기차의 도착 시간을 예고하세요", - "advancement.create.track_0": "새로운 표준", - "advancement.create.track_0.desc": "기차 선로을 조립하세요", - "advancement.create.train_whistle": "칙칙폭폭!", - "advancement.create.train_whistle.desc": "기적 장치를 기차에 장착하고 운전 중에 작동시키세요", - "advancement.create.train_portal": "네더 익스프레스", - "advancement.create.train_portal.desc": "기차를 타고 네더 차원문을 넘어가세요", - "advancement.create.track_crafting_factory": "선로 공장", - "advancement.create.track_crafting_factory.desc": "하나의 압착기에서 1000개 이상의 기차 선로을 생산하세요", - "advancement.create.long_bend": "가장 긴 곡선", - "advancement.create.long_bend.desc": "30 블록 이상의 곡선 선로을 만드세요", - "advancement.create.long_train": "야심찬 조립가", - "advancement.create.long_train.desc": "최소 6개의 객실이 있는 기차를 조립하세요", - "advancement.create.long_travel": "현장체험 학습", - "advancement.create.long_travel.desc": "여행을 시작한 곳으로부터 5000블록 이상 떨어진 곳에서 좌석에서 내리세요", - "advancement.create.train_roadkill": "로드킬", - "advancement.create.train_roadkill.desc": "기차를 타고 적 위로 지나가세요§7\n(숨겨진 발전과제)", - "advancement.create.red_signal": "운전 장인", - "advancement.create.red_signal.desc": "기차를 타고 적신호를 지나치세요§7\n(숨겨진 발전과제)", - "advancement.create.train_crash": "끔찍한 사건", - "advancement.create.train_crash.desc": "탑승객인 상태에서 기차 충돌을 관찰하세요§7\n(숨겨진 발전과제)", - "advancement.create.train_crash_backwards": "사각지대", - "advancement.create.train_crash_backwards.desc": "후진하는 동안 다른 기차와 부딪히세요§7\n(숨겨진 발전과제)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create 건축 블록", - - "death.attack.create.crush": "%1$s이(가) 분쇄 휠로 가공되었습니다", - "death.attack.create.crush.player": "%1$s이(가) %2$s 때문에 분쇄 휠에서 가공되었습니다", - "death.attack.create.fan_fire": "%1$s이(가) 뜨거운 바람에 익어버렸습니다", - "death.attack.create.fan_fire.player": "%1$s이(가) %2$s 때문에 뜨거운 바람으로 익어버렸습니다", - "death.attack.create.fan_lava": "%1$s이(가) 용암 바람에 재가 되었습니다", - "death.attack.create.fan_lava.player": "%1$s이(가) %2$s 때문에 용암 바람으로 재가 되었습니다", - "death.attack.create.mechanical_drill": "%1$s이(가) 드릴에 관통당했습니다", - "death.attack.create.mechanical_drill.player": "%1$s이(가) %2$s 때문에 드릴에 관통당했습니다", - "death.attack.create.mechanical_saw": "%1$s이(가) 톱날에 반으로 갈라져 죽었습니다", - "death.attack.create.mechanical_saw.player": "%1$s이(가) %2$s 때문에 톱날에 반으로 갈라져 죽었습니다", - "death.attack.create.potato_cannon": "%1$s이(가) %2$s의 감자포에 맞고 죽었습니다.", - "death.attack.create.potato_cannon.item": "%1$s이(가) %3$s을(를) 사용한 %2$s에게 맞아 죽었습니다.", - "death.attack.create.cuckoo_clock_explosion": "%1$s이(가) 조작된 뻐꾸기 시계에 의해 폭파당했습니다", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s이(가) 조작된 뻐꾸기 시계에 의해 폭파당했습니다", - "death.attack.create.run_over": "%1$s이(가) %2$s 때문에 깔렸습니다", - - "create.block.deployer.damage_source_name": "기계 손", - "create.block.cart_assembler.invalid": "수레 조립기를 레일 위에 설치하세요", - - "create.menu.return": "메뉴로 돌아가기", - "create.menu.configure": "설정...", - "create.menu.ponder_index": "분석 메뉴", - "create.menu.only_ingame": "일시 정지 메뉴에서 가능합니다", - "create.menu.report_bugs": "버그 제보하기", - "create.menu.support": "후원하기", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "분쇄", - "create.recipe.milling": "제분", - "create.recipe.fan_washing": "세척", - "create.recipe.fan_washing.fan": "물과 선풍기", - "create.recipe.fan_smoking": "훈연", - "create.recipe.fan_smoking.fan": "불과 선풍기", - "create.recipe.fan_haunting": "심령", - "create.recipe.fan_haunting.fan": "영혼 불과 선풍기", - "create.recipe.fan_blasting": "제련", - "create.recipe.fan_blasting.fan": "용암과 선풍기", - "create.recipe.pressing": "압착", - "create.recipe.mixing": "혼합", - "create.recipe.deploying": "행동 모방", - "create.recipe.automatic_shapeless": "무형 자동 조합", - "create.recipe.automatic_brewing": "자동 양조", - "create.recipe.packing": "압축", - "create.recipe.automatic_packing": "자동 압축", - "create.recipe.sawing": "제재", - "create.recipe.mechanical_crafting": "기계 조합", - "create.recipe.automatic_shaped": "유형 자동 조합", - "create.recipe.block_cutting": "블록 절단", - "create.recipe.wood_cutting": "나무 절단", - "create.recipe.sandpaper_polishing": "사포질", - "create.recipe.mystery_conversion": "?", - "create.recipe.spout_filling": "채우기", - "create.recipe.draining": "배수", - "create.recipe.item_application": "수동 아이템 사용", - "create.recipe.item_application.any_axe": "모든 도끼", - "create.recipe.sequenced_assembly": "순서 조립", - "create.recipe.assembly.next": "다음 단계: %1$s", - "create.recipe.assembly.step": "단계 %1$s:", - "create.recipe.assembly.progress": "진행도: %1$s/%2$s", - "create.recipe.assembly.pressing": "압착하기", - "create.recipe.assembly.spout_filling_fluid": "%1$s 주입하기", - "create.recipe.assembly.deploying_item": "%1$s 사용하기", - "create.recipe.assembly.cutting": "톱으로 자르기", - "create.recipe.assembly.repeat": "%1$s번 반복하기", - "create.recipe.assembly.junk": "조립 실패한 조각들", - "create.recipe.processing.chance": "%1$s%% 확률", - "create.recipe.deploying.not_consumed": "소모되지 않음", - "create.recipe.heat_requirement.none": "열이 필요하지 않음", - "create.recipe.heat_requirement.heated": "가열됨", - "create.recipe.heat_requirement.superheated": "초고온 가열됨", - - "create.generic.range": "범위", - "create.generic.radius": "반지름", - "create.generic.width": "폭", - "create.generic.height": "높이", - "create.generic.length": "길이", - "create.generic.speed": "속도", - "create.generic.delay": "딜레이", - "create.generic.duration": "기간", - "create.generic.timeUnit": "시간 단위", - "create.generic.unit.ticks": "틱", - "create.generic.unit.seconds": "초", - "create.generic.unit.minutes": "분", - "create.generic.daytime.hour": "시간", - "create.generic.daytime.minute": "분", - "create.generic.daytime.second": "초", - "create.generic.daytime.pm": "pm", - "create.generic.daytime.am": "am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "시계 방향", - "create.generic.counter_clockwise": "시계 반대 방향", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "음계: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "스크롤하세요", - "create.action.confirm": "확인", - "create.action.abort": "중단", - "create.action.saveToFile": "저장", - "create.action.discard": "삭제", - - "create.keyinfo.toolmenu": "메뉴 세부정보 보기", - "create.keyinfo.toolbelt": "근처 공구상자 열기", - "create.keyinfo.scrollup": "마우스 휠을 위로 이동 (인게임에서)", - "create.keyinfo.scrolldown": "마우스 휠을 아래로 이동 (인게임에서)", - - "create.gui.scrollInput.defaultTitle": "옵션을 선택하세요:", - "create.gui.scrollInput.scrollToModify": "스크롤로 수정하기", - "create.gui.scrollInput.scrollToAdjustAmount": "스크롤로 수량 조절하기", - "create.gui.scrollInput.scrollToSelect": "스크롤로 선택", - "create.gui.scrollInput.shiftScrollsFaster": "쉬프트-스크롤로 빨리 수정하기", - "create.gui.toolmenu.focusKey": "[%1$s]를 눌러 세부정보 보기", - "create.gui.toolmenu.cycle": "스크롤로 순환", - - "create.toolbox.unequip": "되돌리기: %1$s", - "create.toolbox.outOfRange": "현재 아이템이 들어있는 공구상자와 너무 멀리 있습니다", - "create.toolbox.detach": "공구상자와 연결 끊기", - "create.toolbox.depositAll": "근처 공구상자로 모든 아이템 되돌리기", - "create.toolbox.depositBox": "공구상자로 아이템 되돌리기", - - "create.gui.symmetryWand.mirrorType": "거울의 형태", - "create.gui.symmetryWand.orientation": "거울의 방향", - - "create.symmetry.mirror.plane": "거울", - "create.symmetry.mirror.doublePlane": "사각형", - "create.symmetry.mirror.triplePlane": "팔각형", - - "create.orientation.orthogonal": "수직으로", - "create.orientation.diagonal": "대각선으로", - "create.orientation.horizontal": "수평으로", - "create.orientation.alongZ": "Z좌표를 따라", - "create.orientation.alongX": "X좌표를 따라", - - "create.gui.terrainzapper.title": "크리에이티브 세계편집기", - "create.gui.terrainzapper.searchDiagonal": "대각선 블록 포함", - "create.gui.terrainzapper.searchFuzzy": "물질 경계 무시", - "create.gui.terrainzapper.patternSection": "패턴", - "create.gui.terrainzapper.pattern.solid": "기본", - "create.gui.terrainzapper.pattern.checkered": "체스판", - "create.gui.terrainzapper.pattern.inversecheckered": "반전된 체스판", - "create.gui.terrainzapper.pattern.chance25": "랜덤하게 25% 채우기", - "create.gui.terrainzapper.pattern.chance50": "랜덤하게 50% 채우기", - "create.gui.terrainzapper.pattern.chance75": "랜덤하게 75% 채우기", - "create.gui.terrainzapper.placement": "설치 기준", - "create.gui.terrainzapper.placement.merged": "선택한 블록에", - "create.gui.terrainzapper.placement.attached": "선택한 블록 밖에", - "create.gui.terrainzapper.placement.inserted": "선택한 블록 안에", - "create.gui.terrainzapper.brush": "브러쉬", - "create.gui.terrainzapper.brush.cuboid": "정육면체", - "create.gui.terrainzapper.brush.sphere": "구", - "create.gui.terrainzapper.brush.cylinder": "원기둥", - "create.gui.terrainzapper.brush.surface": "면", - "create.gui.terrainzapper.brush.cluster": "원", - "create.gui.terrainzapper.tool": "설치 방식", - "create.gui.terrainzapper.tool.fill": "채우기", - "create.gui.terrainzapper.tool.place": "설치하기", - "create.gui.terrainzapper.tool.replace": "대체", - "create.gui.terrainzapper.tool.clear": "지우기", - "create.gui.terrainzapper.tool.overlay": "덮어씌우기", - "create.gui.terrainzapper.tool.flatten": "다듬기", - - "create.terrainzapper.shiftRightClickToSet": "쉬프트-우클릭으로 모양 설정하기", - "create.terrainzapper.usingBlock": "사용 중: %1$s", - "create.terrainzapper.leftClickToSet": "좌클릭으로 재료로 쓸 블록을 선택하세요", - - "create.minecart_coupling.two_couplings_max": "광산 수레는 최대 2개의 커플링만 가질 수 있습니다", - "create.minecart_coupling.unloaded": "열차 일부분이 로딩되지 않은 청크에 있는 것 같습니다", - "create.minecart_coupling.no_loops": "커플링은 반복할 수 없습니다", - "create.minecart_coupling.removed": "광산 수레에서 모든 커플링을 제거했습니다", - "create.minecart_coupling.too_far": "광산 수레들이 너무 멀리 떨어져 있습니다", - - "create.contraptions.movement_mode": "이동 설정", - "create.contraptions.movement_mode.move_place": "멈췄을 때 항상 구조물을 설치함", - "create.contraptions.movement_mode.move_place_returned": "멈췄을 때 시작 위치에서만 구조물을 설치함", - "create.contraptions.movement_mode.move_never_place": "멈춰도 구조물을 설치하지 않음", - "create.contraptions.movement_mode.rotate_place": "멈췄을 때 항상 구조물을 설치함", - "create.contraptions.movement_mode.rotate_place_returned": "멈췄을 때 시작 위치에서만 구조물을 설치함", - "create.contraptions.movement_mode.rotate_never_place": "멈춰도 구조물을 설치하지 않음", - "create.contraptions.cart_movement_mode": "수레 장치 이동 설정", - "create.contraptions.cart_movement_mode.rotate": "구조물이 항상 전방을 향함", - "create.contraptions.cart_movement_mode.rotate_paused": "수레가 회전할때 구조물이 행동을 멈춤", - "create.contraptions.cart_movement_mode.rotation_locked": "구조물이 회전하지 않음", - "create.contraptions.windmill.rotation_direction": "회전 방향", - "create.contraptions.clockwork.clock_hands": "시계침", - "create.contraptions.clockwork.hour_first": "시침 먼저", - "create.contraptions.clockwork.minute_first": "분침 먼저", - "create.contraptions.clockwork.hour_first_24": "시침 먼저 (24시간 단위)", - - "create.logistics.filter": "필터", - "create.logistics.recipe_filter": "조합법 필터", - "create.logistics.fluid_filter": "액체 필터", - "create.logistics.firstFrequency": "주파수 #1", - "create.logistics.secondFrequency": "주파수 #2", - "create.logistics.filter.apply": "%1$s에 필터를 적용했습니다", - "create.logistics.filter.apply_click_again": "%1$s에 필터를 적용했습니다. 다시 클릭하면 가지고 있는 아이템의 수량을 복사하여 필터에 적용합니다", - "create.logistics.filter.apply_count": "필터에 수량을 적용했습니다", - - "create.gui.goggles.generator_stats": "동력 상태:", - "create.gui.goggles.kinetic_stats": "작동 상태:", - "create.gui.goggles.at_current_speed": "현재 에너지량", - "create.gui.goggles.pole_length": "축 길이:", - "create.gui.goggles.fluid_container": "액체 저장 정보:", - "create.gui.goggles.fluid_container.capacity": "용량: ", - "create.gui.assembly.exception": "이 구조물은 움직일 수 없습니다:", - "create.gui.assembly.exception.unmovableBlock": "[%1$s,%2$s,%3$s]에 움직일 수 없는 [%4$s]이(가) 있습니다.", - "create.gui.assembly.exception.chunkNotLoaded": "[%1$s,%2$s,%3$s]에 있는 블록이 로드되지 않은 청크에 있습니다.", - "create.gui.assembly.exception.structureTooLarge": "이 구조물에 너무 많은 블록이 포함되어 있습니다.\n설정된 최댓값: %1$s개", - "create.gui.assembly.exception.tooManyPistonPoles": "이 피스톤에 너무 많은 연장 축이 부착되어 있습니다.\n설정된 최댓값: %1$s개", - "create.gui.assembly.exception.noPistonPoles": "이 피스톤은 연장 축이 없습니다.", - "create.gui.assembly.exception.not_enough_sails": "부착된 구조물에 날개 블록이 부족합니다. 현재: %1$s개 \n최소 %2$s개가 필요합니다.", - "create.gui.gauge.info_header": "계측기 정보:", - "create.gui.speedometer.title": "회전 속도", - "create.gui.stressometer.title": "네트워크 부하", - "create.gui.stressometer.capacity": "용량", - "create.gui.stressometer.overstressed": "과부하됨", - "create.gui.stressometer.no_rotation": "동력없음", - "create.gui.contraptions.not_fast_enough": "이 %1$s은(는) 작동하기에 _회전 속도_가 _부족합니다_", - "create.gui.contraptions.network_overstressed": "_과부하!_ _높은 피로도_ _용량_을 가진 발전기를 추가로 설치하거나 _장치 속도_를 _늦추세요_.", - "create.gui.adjustable_crate.title": "가변 창고", - "create.gui.adjustable_crate.storageSpace": "저장 공간", - "create.gui.stockpile_switch.title": "수량 스위치", - "create.gui.stockpile_switch.invert_signal": "신호 반전", - "create.gui.stockpile_switch.move_to_lower_at": "최소 신호 발동 비율:%1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "최소 신호 유지 비율:%1$s%%", - "create.gui.sequenced_gearshift.title": "순서 기어쉬프트", - "create.gui.sequenced_gearshift.instruction": "지시", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "축 회전", - "create.gui.sequenced_gearshift.instruction.turn_angle": "축 회전", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "각도", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "피스톤/도르래/겐트리 회전", - "create.gui.sequenced_gearshift.instruction.turn_distance": "장치 회전", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "거리", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "지연 시간", - "create.gui.sequenced_gearshift.instruction.delay": "지연", - "create.gui.sequenced_gearshift.instruction.delay.duration": "지연시간", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "종료", - "create.gui.sequenced_gearshift.instruction.end": "종료", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "새 레드스톤 신호 대기", - "create.gui.sequenced_gearshift.instruction.await": "대기", - "create.gui.sequenced_gearshift.speed": "속도, 방향", - "create.gui.sequenced_gearshift.speed.forward": "입력 속도, 그대로 회전", - "create.gui.sequenced_gearshift.speed.forward_fast": "입력 속도의 2배, 그대로 회전", - "create.gui.sequenced_gearshift.speed.back": "입력 속도, 반대로 회전", - "create.gui.sequenced_gearshift.speed.back_fast": "입력 속도의 2배, 반대로 회전", - - "create.schematicAndQuill.dimensions": "설계도 크기: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "첫 번째 위치를 설정했습니다", - "create.schematicAndQuill.secondPos": "두 번째 위치를 설정했습니다", - "create.schematicAndQuill.noTarget": "[Ctrl]을(를) 누르면 허공을 선택할 수 있습니다", - "create.schematicAndQuill.abort": "위치 설정을 제거했습니다", - "create.schematicAndQuill.title": "설계도 이름:", - "create.schematicAndQuill.convert": "저장하고 즉시 적용", - "create.schematicAndQuill.fallbackName": "내 설계도", - "create.schematicAndQuill.saved": "%1$s으(로) 저장했습니다", - - "create.schematic.invalid": "[!] 없는 아이템 - 설계도 테이블을 이용하세요", - "create.schematic.position": "위치", - "create.schematic.rotation": "회전", - "create.schematic.rotation.none": "없음", - "create.schematic.rotation.cw90": "90도 시계방향 회전", - "create.schematic.rotation.cw180": "180도 시계방향 회전", - "create.schematic.rotation.cw270": "270도 시계방향 회전", - "create.schematic.mirror": "거울", - "create.schematic.mirror.none": "없음", - "create.schematic.mirror.frontBack": "전-후", - "create.schematic.mirror.leftRight": "좌-우", - "create.schematic.tool.deploy": "전개", - "create.schematic.tool.move": "X/Z좌표 이동", - "create.schematic.tool.movey": "Y좌표 이동", - "create.schematic.tool.rotate": "회전", - "create.schematic.tool.print": "설치", - "create.schematic.tool.flip": "뒤집기", - "create.schematic.tool.deploy.description.0": "구조물의 위치를 설정합니다.", - "create.schematic.tool.deploy.description.1": "오른쪽 버튼을 누르면 땅에 배치합니다.", - "create.schematic.tool.deploy.description.2": "[Ctrl]을 누르면 일정 거리를 유지합니다.", - "create.schematic.tool.deploy.description.3": "[Ctrl]을 누르고 스크롤하면 거리를 변경합니다.", - "create.schematic.tool.move.description.0": "설계도를 수평 이동합니다.", - "create.schematic.tool.move.description.1": "설계도를 바라보며 [CTRL]을 누르고 스크롤하면 설계도를 밀어냅니다.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "설계도를 수직 이동시킵니다.", - "create.schematic.tool.movey.description.1": "설계도를 보고 [CTRL]-스크롤로 밉니다.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "설계도를 돌립니다.", - "create.schematic.tool.rotate.description.1": "[CTRL]-스크롤로 90도 돌립니다.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "구조물을 즉시 설치합니다.", - "create.schematic.tool.print.description.1": "[우클릭]으로 현재 지점에 설치합니다.", - "create.schematic.tool.print.description.2": "이 도구는 크리에이티브 모드 전용입니다.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "당신이 보는 면으로 설계도를 뒤집습니다.", - "create.schematic.tool.flip.description.1": "설계도를 보고 [CTRL]-스크롤로 뒤집습니다.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "동기화 중...", - "create.schematics.uploadTooLarge": "설계도가 너무 큽니다!.", - "create.schematics.maxAllowedSize": "최대 설계도 파일 크기:", - - "create.gui.schematicTable.refresh": "파일 새로고침", - "create.gui.schematicTable.open_folder": "폴더 열기", - "create.gui.schematicTable.title": "설계도 테이블", - "create.gui.schematicTable.availableSchematics": "사용가능한 설계도", - "create.gui.schematicTable.noSchematics": "저장된 설계도 없음", - "create.gui.schematicTable.uploading": "업로딩 중...", - "create.gui.schematicTable.finished": "업로드 완료!", - "create.gui.schematicannon.title": "설계도 대포", - "create.gui.schematicannon.listPrinter": "재료 목록 인쇄", - "create.gui.schematicannon.gunpowderLevel": "화약 용량 %1$s%%", - "create.gui.schematicannon.shotsRemaining": "남은 발포 수 : %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "화약 여분: %1$s", - "create.gui.schematicannon.optionEnabled": "현재 활성화 됨", - "create.gui.schematicannon.optionDisabled": "현재 비활성화 됨", - "create.gui.schematicannon.showOptions": "대포 설치 설정 열기", - "create.gui.schematicannon.option.dontReplaceSolid": "온전한 블록을 대체하지 않음", - "create.gui.schematicannon.option.replaceWithSolid": "온전한 블록을 재료로 대체함", - "create.gui.schematicannon.option.replaceWithAny": "온전한 블록을 아무 재료로 대체함", - "create.gui.schematicannon.option.replaceWithEmpty": "온전한 블록을 공기로 채움", - "create.gui.schematicannon.option.skipMissing": "부족한 블록을 무시하고 진행", - "create.gui.schematicannon.option.skipTileEntities": "블록 엔티티 보호", - "create.gui.schematicannon.slot.gunpowder": "화약을 넣어 대포 연료를 채우세요", - "create.gui.schematicannon.slot.listPrinter": "책을 넣어 건축 재료 체크리스트를 인쇄하세요", - "create.gui.schematicannon.slot.schematic": "여기에 설계도를 넣으세요. 건설 구역이 설정되어 있어야 합니다.", - "create.gui.schematicannon.option.skipMissing.description": "만약 대포가 설치에 필요한 블록을 찾지 못할 경우,건너뛰고 다음 블록 설치를 진행합니다.", - "create.gui.schematicannon.option.skipTileEntities.description": "대포가 상자, 화로같이 데이터가 담긴 블록을 설치하지 않습니다.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "대포가 작업구역의 온전한 블록을 대체하지 않습니다.", - "create.gui.schematicannon.option.replaceWithSolid.description": "대포가 작업구역의 온전한 블록을 대포가 가진 재료로 대체합니다.", - "create.gui.schematicannon.option.replaceWithAny.description": "대포가 작업구역의 온전한 블록을 대포가 가진 어떠한 재료로든 대체합니다.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "대포가 작업구역의 블록들을 제거합니다.", - - "create.schematicannon.status.idle": "휴식", - "create.schematicannon.status.ready": "준비됨", - "create.schematicannon.status.running": "작동 중", - "create.schematicannon.status.finished": "완료", - "create.schematicannon.status.paused": "일시 중지", - "create.schematicannon.status.stopped": "중단됨", - "create.schematicannon.status.noGunpowder": "화약이 부족함", - "create.schematicannon.status.targetNotLoaded": "목표가 없음", - "create.schematicannon.status.targetOutsideRange": "목표가 너무 멈", - "create.schematicannon.status.searching": "검색 중", - "create.schematicannon.status.skipping": "건너뛰는 중", - "create.schematicannon.status.missingBlock": "부족한 블록:", - "create.schematicannon.status.placing": "설치 중", - "create.schematicannon.status.clearing": "블록을 제거하는 중", - "create.schematicannon.status.schematicInvalid": "설계도 없음", - "create.schematicannon.status.schematicNotPlaced": "설계도가 전개되지 않음", - "create.schematicannon.status.schematicExpired": "설계도 파일이 제거됨", - - "create.materialChecklist": "재료 목록", - "create.materialChecklist.blocksNotLoaded": "* 경고 *\n\n관련된 청크가 불러올 수 없어 재료 목록이 부정확할 수 있습니다.", - - "create.gui.filter.deny_list": "블랙리스트", - "create.gui.filter.deny_list.description": "위에 등록된 아이템은 통과할 수 없습니다. 빈 블랙리스트는 모든 아이템을 통과시킵니다.", - "create.gui.filter.allow_list": "화이트리스트", - "create.gui.filter.allow_list.description": "위에 등록된 아이템만 통과할 수 있습니다. 빈 화이트리스트는 모든 아이템을 막습니다.", - "create.gui.filter.respect_data": "상세정보 일치", - "create.gui.filter.respect_data.description": "위 목록 아이템의 내구도, 마법부여, 그리고 다른 NBT와 일치할 때 통과시킵니다.", - "create.gui.filter.ignore_data": "상세정보 무시", - "create.gui.filter.ignore_data.description": "상세정보와 상관없이 아이템 종류만 일치한다면 통과시킵니다.", - - "create.item_attributes.placeable": "설치할 수 있음", - "create.item_attributes.placeable.inverted": "설치할 수 없음", - "create.item_attributes.consumable": "먹을 수 있음", - "create.item_attributes.consumable.inverted": "먹을 수 없음", - "create.item_attributes.fluid_container": "액체를 저장할 수 있음", - "create.item_attributes.fluid_container.inverted": "액체를 저장할 수 없음", - "create.item_attributes.enchanted": "마법부여됨", - "create.item_attributes.enchanted.inverted": "마법부여되지 않음", - "create.item_attributes.max_enchanted": "마법부여가 최고 레벨임", - "create.item_attributes.max_enchanted.inverted": "마법부여가 최고 레벨이 아님", - "create.item_attributes.renamed": "새로운 이름을 지어줌", - "create.item_attributes.renamed.inverted": "새로운 이름이 없음", - "create.item_attributes.damaged": "내구도가 닮", - "create.item_attributes.damaged.inverted": "내구도가 닳지 않음", - "create.item_attributes.badly_damaged": "심각하게 내구도가 닮", - "create.item_attributes.badly_damaged.inverted": "심각하게 내구도가 닳지 않음", - "create.item_attributes.not_stackable": "겹쳐질 수 없음", - "create.item_attributes.not_stackable.inverted": "겹쳐질 수 있음", - "create.item_attributes.equipable": "장착할 수 있음", - "create.item_attributes.equipable.inverted": "장착할 수 없음", - "create.item_attributes.furnace_fuel": "화로 연료로 쓸 수 있음", - "create.item_attributes.furnace_fuel.inverted": "화로 연료로 쓸 수 없음", - "create.item_attributes.washable": "세척될 수 있음", - "create.item_attributes.washable.inverted": "세척될 수 없음", - "create.item_attributes.hauntable": "귀신들릴 수 있음", - "create.item_attributes.hauntable.inverted": "귀신들릴 수 없음", - "create.item_attributes.crushable": "분쇄될 수 있음", - "create.item_attributes.crushable.inverted": "분쇄될 수 없음", - "create.item_attributes.smeltable": "구워질 수 있음", - "create.item_attributes.smeltable.inverted": "구워질 수 없음", - "create.item_attributes.smokable": "훈연될 수 있음", - "create.item_attributes.smokable.inverted": "훈연될 수 없음", - "create.item_attributes.blastable": "용광로에 녹일 수 있음", - "create.item_attributes.blastable.inverted": "용광로에 녹일 수 없음", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "셜커가 %1$s있음", - "create.item_attributes.shulker_level.inverted": "셜커가 %1$s있지 않음", - "create.item_attributes.shulker_level.full": "가득 차", - "create.item_attributes.shulker_level.empty": "비어", - "create.item_attributes.shulker_level.partial": "조금 차", - "create.item_attributes.in_tag": "%1$s로 등록됨", - "create.item_attributes.in_tag.inverted": "%1$s로 등록되지 않음", - "create.item_attributes.in_item_group": "%1$s탭에 속함", - "create.item_attributes.in_item_group.inverted": "%1$s탭에 속함", - "create.item_attributes.added_by": "%1$s모드가 추가함", - "create.item_attributes.added_by.inverted": "%1$s모드가 추가하지 않음", - "create.item_attributes.has_enchant": "%1$s 마법부여를 가지고 있음", - "create.item_attributes.has_enchant.inverted": "%1$s 마법부여를 가지고 있지 않음", - "create.item_attributes.color": "염색됨", - "create.item_attributes.color.inverted": "염색되지 않음", - "create.item_attributes.has_fluid": "%1$s을(를) 담고 있음", - "create.item_attributes.has_fluid.inverted": "%1$s을(를) 담고 있지 않음", - "create.item_attributes.has_name": "%1$s이라는 이름을 갖고 있음", - "create.item_attributes.has_name.inverted": "%1$s이라는 이름을 갖고 있지 않음", - "create.item_attributes.book_author": "%1$s이(가) 작성함", - "create.item_attributes.book_author.inverted": "%1$s이(가) 작성하지 않음", - "create.item_attributes.book_copy_original": "원본임", - "create.item_attributes.book_copy_original.inverted": "원본이 아님", - "create.item_attributes.book_copy_first": "원본의 복사본임", - "create.item_attributes.book_copy_first.inverted": "원본의 복사본이 아님", - "create.item_attributes.book_copy_second": "복사본의 복사본임", - "create.item_attributes.book_copy_second.inverted": "복사본의 복사본이 아님", - "create.item_attributes.book_copy_tattered": "낡고 헐었음", - "create.item_attributes.book_copy_tattered.inverted": "낡고 헐지 않음", - "create.item_attributes.astralsorcery_amulet": "%1$s이(가) 향상됨", - "create.item_attributes.astralsorcery_amulet.inverted": "%1$s이(가) 향상되지 않음", - "create.item_attributes.astralsorcery_constellation": "%1$s에 조율됨", - "create.item_attributes.astralsorcery_constellation.inverted": "%1$s에 조율되지 않음", - "create.item_attributes.astralsorcery_crystal": "%1$s 수정 속성을 가짐", - "create.item_attributes.astralsorcery_crystal.inverted": "%1$s 수정 속성을 가지고 있지 않음", - "create.item_attributes.astralsorcery_perk_gem": "%1$s 퍽 속성을 가짐", - "create.item_attributes.astralsorcery_perk_gem.inverted": "%1$s 퍽 속성을 가지고 있지 않음", - - "create.gui.attribute_filter.no_selected_attributes": "속성이 선택되지 않음", - "create.gui.attribute_filter.selected_attributes": "선택된 속성:", - "create.gui.attribute_filter.add_attribute": "리스트에 속성을 추가합니다", - "create.gui.attribute_filter.add_inverted_attribute": "리스트에 반대 속성을 추가합니다.", - "create.gui.attribute_filter.allow_list_disjunctive": "화이트리스트 (최소)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "아이템이 선택된 속성 중 하나라도 가지고 있다면 통과시킵니다.", - "create.gui.attribute_filter.allow_list_conjunctive": "화이트리스트 (모두)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "아이템이 선택된 속성 모두를 가지고 있어야 통과시킵니다.", - "create.gui.attribute_filter.deny_list": "블랙리스트", - "create.gui.attribute_filter.deny_list.description": "아이템이 선택된 속성이 없다면 통과시킵니다.", - "create.gui.attribute_filter.add_reference_item": "참고할 아이템을 추가하기", - - "create.tooltip.holdForDescription": "[%1$s]을 눌러 설명 보기", - "create.tooltip.holdForControls": "[%1$s]을 눌러 조작법 보기", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "요구 회전속도: %1$s", - "create.tooltip.speedRequirement.none": "없음", - "create.tooltip.speedRequirement.slow": "느림", - "create.tooltip.speedRequirement.medium": "보통", - "create.tooltip.speedRequirement.fast": "빠름", - "create.tooltip.stressImpact": "피로도 부하: %1$s", - "create.tooltip.stressImpact.low": "낮음", - "create.tooltip.stressImpact.medium": "보통", - "create.tooltip.stressImpact.high": "높음", - "create.tooltip.stressImpact.overstressed": "과부하", - "create.tooltip.up_to": "%1$s까지", - "create.tooltip.capacityProvided": "피로도 용량: %1$s", - "create.tooltip.capacityProvided.low": "적음", - "create.tooltip.capacityProvided.medium": "보통", - "create.tooltip.capacityProvided.high": "큼", - "create.tooltip.generationSpeed": "%1$s %2$s만큼 발전함", - "create.tooltip.analogStrength": "레드스톤 출력: %1$s/15", - - "create.mechanical_arm.extract_from": "%1$s을(를) 입력구로 설정했습니다", - "create.mechanical_arm.deposit_to": "%1$s을(를) 출력구로 설정했습니다", - "create.mechanical_arm.summary": "이 기계식 팔은 %1$s개의 입력구와 %2$s개의 출력구가 있습니다", - "create.mechanical_arm.points_outside_range": "범위 제한으로 인해 %1$s개의 선택된 지점이 해제되었습니다", - - "create.weighted_ejector.target_set": "투척 지점이 설정되었습니다", - "create.weighted_ejector.target_not_valid": "인접한 블록에다 발사합니다 (투척 지점이 올바르지 않습니다)", - "create.weighted_ejector.no_target": "인접한 블록에다 발사합니다 (투척 지점이 설정되지 않았습니다)", - "create.weighted_ejector.targeting": "[%1$s,%2$s,%3$s]에다 투척합니다", - "create.weighted_ejector.stack_size": "투척하는 아이템의 수량", - - "create.logistics.when_multiple_outputs_available": "여러 출력구가 있을 때", - - "create.mechanical_arm.selection_mode.round_robin": "돌아가며 처리", - "create.mechanical_arm.selection_mode.forced_round_robin": "돌아가며 처리(강제적)", - "create.mechanical_arm.selection_mode.prefer_first": "설정 순서 우선시", - - "create.tunnel.selection_mode.split": "분할", - "create.tunnel.selection_mode.forced_split": "분할(강제적)", - "create.tunnel.selection_mode.round_robin": "순서대로 처리", - "create.tunnel.selection_mode.forced_round_robin": "순서대로 처리(강제적)", - "create.tunnel.selection_mode.prefer_nearest": "가장 가까운 곳", - "create.tunnel.selection_mode.randomize": "무작위", - "create.tunnel.selection_mode.synchronize": "입력 동기화", - - "create.tooltip.chute.header": "슈트 정보", - "create.tooltip.chute.items_move_down": "아이템이 아래로 이동", - "create.tooltip.chute.items_move_up": "아이템이 위로 이동", - "create.tooltip.chute.no_fans_attached": "선풍기가 부착되지 않음", - "create.tooltip.chute.fans_push_up": "선풍기가 아래에서 밈", - "create.tooltip.chute.fans_push_down": "선풍기가 위에서 밈", - "create.tooltip.chute.fans_pull_up": "선풍기가 위에서 당김", - "create.tooltip.chute.fans_pull_down": "선풍기가 아래에서 당김", - "create.tooltip.chute.contains": "들어있는 아이템: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "분배 중인 아이템:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "우클릭하여 회수", - - "create.linked_controller.bind_mode": "연결 모드 활성화", - "create.linked_controller.press_keybind": "%1$s, %2$s, %3$s, %4$s, %5$s, %6$s 중 하나를 눌러 이 주파수를 해당 조작키에 연결하세요", - "create.linked_controller.key_bound": "%1$s에 주파수가 연결되었습니다", - "create.linked_controller.frequency_slot_1": "조작키: %1$s, 주파수 #1", - "create.linked_controller.frequency_slot_2": "조작키: %1$s, 주파수 #2", - - "create.crafting_blueprint.crafting_slot": "재료 슬롯", - "create.crafting_blueprint.filter_items_viable": "필터도 가능합니다", - "create.crafting_blueprint.display_slot": "전시 슬롯", - "create.crafting_blueprint.inferred": "실제 조합법과 같음", - "create.crafting_blueprint.manually_assigned": "직접 지정함", - "create.crafting_blueprint.secondary_display_slot": "두번째 전시 슬롯", - "create.crafting_blueprint.optional": "추가적", - - "create.potato_cannon.ammo.attack_damage": "%1$s 공격 피해", - "create.potato_cannon.ammo.reload_ticks": "%1$s 재장전 틱", - "create.potato_cannon.ammo.knockback": "%1$s 밀쳐내는 거리", - - "create.hint.hose_pulley.title": "무한 공급", - "create.hint.hose_pulley": "해당 액체는 _무한_합니다.", - "create.hint.mechanical_arm_no_targets.title": "목표 없음", - "create.hint.mechanical_arm_no_targets": "이 _기계 팔_은 _목표_가 설정되지 않았습니다. _기계 팔을 손에 들고_ 벨트, 아이템 거치대, 퍼널을 _우클릭_하여 목표로 지정하세요.", - "create.hint.empty_bearing.title": "베어링 업데이트", - "create.hint.empty_bearing": "_맨 손_으로 베어링을 _우클릭_하여 구조물을 _부착_하세요.", - "create.hint.full_deployer.title": "기계 손 아이템 과적", - "create.hint.full_deployer": "이 _기계 손_은 _배출_할 아이템을 가지고 있습니다. 호퍼 , 퍼널 등을 이용해 아이템을 빼내세요.", - - "create.backtank.low": "산소통 기압이 낮습니다", - "create.backtank.depleted": "산소통 기압이 모두 소진되었습니다", - - "create.hint.derailed_train.title": "선로을 벗어난 기차", - "create.hint.derailed_train": "이 _기차_아래에 선로이 없는 것 같습니다. _렌치_로 _우클릭_해서 근처 선로으로 옮기세요.", - - "create.boiler.status": "보일러 상태: %1$s", - "create.boiler.status_short": "보일러: %1$s", - "create.boiler.passive": "작동중", - "create.boiler.idle": "멈춤", - "create.boiler.lvl": "레벨 %1$s", - "create.boiler.max_lvl": "최고 레벨", - "create.boiler.size": "크기", - "create.boiler.size_dots": "... ", - "create.boiler.water": "물", - "create.boiler.water_dots": "....... ", - "create.boiler.heat": "열", - "create.boiler.heat_dots": "....... ", - "create.boiler.via_one_engine": "엔진 1개", - "create.boiler.via_engines": "엔진 %1$s개", - - "create.gui.schedule.lmb_edit": "좌클릭으로 수정", - "create.gui.schedule.rmb_remove": "우클릭으로 삭제", - "create.gui.schedule.duplicate": "복제", - "create.gui.schedule.remove_entry": "작업 삭제", - "create.gui.schedule.add_entry": "작업 추가", - "create.gui.schedule.move_up": "위로 이동", - "create.gui.schedule.move_down": "아래로 이동", - "create.gui.schedule.add_condition": "조건 추가", - "create.gui.schedule.alternative_condition": "대체 조건 추가", - - "create.schedule.instruction_type": "다음 행동:", - "create.schedule.instruction.editor": "설명 편집기", - "create.schedule.instruction.destination": "정거장으로 이동", - "create.schedule.instruction.destination.summary": "다음 역:", - "create.schedule.instruction.filter_edit_box": "정거장 이름", - "create.schedule.instruction.filter_edit_box_1": "* 로 문자 와일드카드를 사용할 수 있습니다", - "create.schedule.instruction.filter_edit_box_2": "예시: '내 정거장, 정거장 *'", - "create.schedule.instruction.filter_edit_box_3": "기차는 가장 가까운 빈 정거장을 선택합니다", - "create.schedule.instruction.rename": "행선지 제목 업데이트", - "create.schedule.instruction.rename.summary": "새로운 제목:", - "create.schedule.instruction.name_edit_box": "행선지 제목", - "create.schedule.instruction.name_edit_box_1": "디스플레이에 보일 문자입니다", - "create.schedule.instruction.name_edit_box_2": "기본값은 다음 정거장의 이름입니다", - "create.schedule.instruction.throttle": "최고 속도 변경", - "create.schedule.instruction.throttle.summary": "최고 속도를 %1$s로 변경", - "create.schedule.instruction.throttle_edit_box": "제한", - "create.schedule.instruction.throttle_edit_box_1": "기차의 최고 속도를 설정합니다", - "create.schedule.condition_type": "조건이 맞으면 계속:", - "create.schedule.condition.editor": "조건 편집기", - "create.schedule.condition.delay": "딜레이", - "create.schedule.condition.delay_short": "멈춤: %1$s", - "create.schedule.condition.delay.status": "%1$s후 출발", - "create.schedule.condition.idle": "저장소 휴식", - "create.schedule.condition.idle_short": "저장소 휴식: %1$s", - "create.schedule.condition.idle.status": "%1$s동안 저장소 멈춤", - "create.schedule.condition.for_x_time": "%1$s 동안", - "create.schedule.condition.unloaded": "청크 언로드", - "create.schedule.condition.unloaded.status": "청크 언로드되길 기다리는 중", - "create.schedule.condition.powered": "정거장 신호", - "create.schedule.condition.powered.status": "레드스톤 신호 기다리는 중", - "create.schedule.condition.time_of_day": "하루 시간", - "create.schedule.condition.time_of_day.scheduled": "계획 시간: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "시간차", - "create.schedule.condition.time_of_day.rotation.every_24": "하루마다", - "create.schedule.condition.time_of_day.rotation.every_12": "12시간마다", - "create.schedule.condition.time_of_day.rotation.every_6": "6시간마다", - "create.schedule.condition.time_of_day.rotation.every_4": "4시간마다", - "create.schedule.condition.time_of_day.rotation.every_3": "3시간마다", - "create.schedule.condition.time_of_day.rotation.every_2": "2시간마다", - "create.schedule.condition.time_of_day.rotation.every_1": "1시간마다", - "create.schedule.condition.time_of_day.rotation.every_0_45": "45분마다", - "create.schedule.condition.time_of_day.rotation.every_0_30": "30분마다", - "create.schedule.condition.time_of_day.rotation.every_0_15": "15분마다", - "create.schedule.condition.time_of_day.status": "출발 시간 ", - "create.schedule.condition.threshold.train_holds": "기차의 저장량이 %1$s", - "create.schedule.condition.threshold.greater": "다음보다 많으면", - "create.schedule.condition.threshold.less": "다음보다 적으면", - "create.schedule.condition.threshold.equal": "다음과 동일하면", - "create.schedule.condition.threshold.x_units_of_item": "%3$s %1$s %2$s", - "create.schedule.condition.threshold.matching_content": "내용물 일치", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "아이템 단위", - "create.schedule.condition.threshold.items": "개", - "create.schedule.condition.threshold.stacks": "스택", - "create.schedule.condition.threshold.buckets": "양동이", - "create.schedule.condition.threshold.status": "저장소: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "기준 아이템", - "create.schedule.condition.threshold.place_item_2": "필터를 사용할 수 있음", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "액체 저장소 조건", - "create.schedule.condition.item_threshold": "아이템 저장소 조건", - "create.schedule.condition.redstone_link": "레드스톤 링크", - "create.schedule.condition.redstone_link.status": "레드스톤 링크 신호 기다리는 중", - "create.schedule.condition.redstone_link_on": "링크 켜짐", - "create.schedule.condition.redstone_link_off": "링크 꺼짐", - "create.schedule.condition.redstone_link.powered": "신호 받을때", - "create.schedule.condition.redstone_link.unpowered": "신호 없을때", - "create.schedule.condition.redstone_link.frequency_state": "주파수 상태:", - "create.schedule.condition.redstone_link.frequency_powered": "주파수 신호 받음:", - "create.schedule.condition.redstone_link.frequency_unpowered": "주파수 신호 없음:", - "create.schedule.condition.player_count": "플레이어 착석", - "create.schedule.condition.player_count.summary": "플레이어 %1$s명", - "create.schedule.condition.player_count.summary_plural": "플레이어 %1$s명", - "create.schedule.condition.player_count.seated": "%1$s명 앉음", - "create.schedule.condition.player_count.players": "인원", - "create.schedule.condition.player_count.condition": "조건", - "create.schedule.condition.player_count.exactly": "동일", - "create.schedule.condition.player_count.or_above": "초과", - "create.schedule.condition.player_count.status": "승객 : %1$s/%2$s", - "create.schedule.loop": "영원히 반복", - "create.schedule.loop1": "계획표를 마무리하면", - "create.schedule.loop2": "처음으로 되돌아갑니다", - "create.schedule.reset": "진행도 초기화", - "create.schedule.skip": "현재 정거장 건너뛰기", - "create.schedule.applied_to_train": "기차는 이제 이 계획표대로 진행합니다", - "create.schedule.non_controlling_seat": "기관사는 조종기 앞에 앉아야 합니다", - "create.schedule.remove_with_empty_hand": "현재 적용된 계획표를 맨 손으로 제거하세요", - "create.schedule.auto_removed_from_train": "자동등록된 계획표 제거됨", - "create.schedule.removed_from_train": "기차에서 계획표를 회수했습니다", - "create.schedule.no_stops": "이 계획표는 정거장이 등록되지 않습니다", - "create.schedule.continued": "계획표를 진행합니다", - - "create.track.selection_cleared": "선택이 해제되었습니다", - "create.track.valid_connection": "연결할 수 있습니다 ✔", - "create.track.second_point": "선로를 설치하거나 두번째 지점을 선택하세요", - "create.track.too_far": "너무 멉니다", - "create.track.original_missing": "기준 블록이 제거되었습니다. 쉬프트 우클릭으로 초기화하세요", - "create.track.perpendicular": "수직으로 연결할 수 없습니다", - "create.track.ascending_s_curve": "기울어진 S자 곡선 선로을 생성할 수 없습니다", - "create.track.too_sharp": "곡선이 너무 날카롭습니다", - "create.track.too_steep": "경사면이 너무 급합니다", - "create.track.slope_turn": "곡선이 너무 불규칙합니다", - "create.track.opposing_slopes": "반대 경사면에 연결할 수 없습니다", - "create.track.leave_slope_ascending": "올라가는 동안 이 경사면을 벗어날 수 없습니다", - "create.track.leave_slope_descending": "내려가는 동안 이 경사면을 벗어날 수 없습니다", - "create.track.turn_90": "최대 90도까지 구부릴 수 있습니다", - "create.track.junction_start": "교차로에서 시작할 수 없습니다", - "create.track.turn_start": "곡선에서 시작할 수 없습니다", - "create.track.not_enough_tracks": "선로이 부족합니다", - "create.track.not_enough_pavement": "기반 블록이 부족합니다", - - "create.portal_track.failed": "차원간 선로을 설치할 수 없습니다:", - "create.portal_track.missing": "대상 차원문이 아직 생성되지 않았습니다", - "create.portal_track.blocked": "대상 좌표가 가로막혔습니다 (%1$s,%2$s,%3$s)", - - "create.station.idle": "정거장이 휴식중입니다", - "create.station.assembly_title": "기차 조립", - "create.station.close": "창 닫기", - "create.station.cancel": "조립 취소", - "create.station.failed": "조립 실패", - "create.station.icon_type": "아이콘 종류", - "create.station.create_train": "새로운 기차 조립", - "create.station.assemble_train": "기차 조립", - "create.station.disassemble_train": "기차 해체", - "create.station.remove_schedule": "계획표 회수", - "create.station.remove_auto_schedule": "자동 계획표 제거", - "create.station.no_assembly_diagonal": "대각선 선로에서", - "create.station.no_assembly_diagonal_1": "기차를 조립할 수 없습니다", - "create.station.no_assembly_curve": "곡선 선로에서", - "create.station.no_assembly_curve_1": "기차를 조립할 수 없습니다", - "create.station.train_not_aligned": "모든 객실이 일직선상에 없어", - "create.station.train_not_aligned_1": "해체할 수 없습니다", - "create.station.carriage_number": "%1$s번 객실:", - "create.station.retry": "이 문제를 해결하고 다시 시도해보세요", - "create.station.no_bogeys": "대차 없음", - "create.station.one_bogey": "대차 1개", - "create.station.more_bogeys": "대차 %1$s개", - "create.station.how_to": "하이라이트된 선로에 기차 케이스를 설치하여 대차를 생성하세요.", - "create.station.how_to_1": "대차를 제거하려면 윗 블록을 파괴하세요.", - "create.station.how_to_2": "객실은 1~2개의 대차를 이어 만들 수 있습니다.", - - "create.train_assembly.too_many_bogeys": "대차가 너무 많이 연결되었습니다: %1$s개", - "create.train_assembly.frontmost_bogey_at_station": "가장 앞의 대차는 정거장 발판에 있어야합니다", - "create.train_assembly.no_bogeys": "대차가 없습니다", - "create.train_assembly.not_connected_in_order": "대차가 순서대로 연결되지 않았습니다", - "create.train_assembly.bogeys_too_close": "%1$s번과 %2$s번 대차가 너무 가깝습니다", - "create.train_assembly.single_bogey_carriage": "이 대차는 스스로 객실을 지지할 수 없습니다", - "create.train_assembly.nothing_attached": "%1$s번 대차에 구조물이 없습니다", - "create.train_assembly.no_controls": "진행 방향을 향한 조종기가 최소 1개 필요합니다", - "create.train_assembly.sideways_controls": "조종기가 측면을 바라보고 있습니다", - "create.train_assembly.bogey_created": "대차가 생성되었습니다. 선로를 클릭하여 모양을 변경할 수 있습니다", - "create.train_assembly.requires_casing": "기차 케이스를 이용해 선로에 대차를 생성하세요", - - "create.track_target.set": "선로가 선택되었습니다", - "create.track_target.success": "성공적으로 선택된 선로와 연결되었습니다", - "create.track_target.clear": "선로 선택을 해제했습니다", - "create.track_target.missing": "먼저 선로를 선택하세요", - "create.track_target.too_far": "선택한 선로가 너무 멉니다", - "create.track_target.no_junctions": "교차로 선로는 선택할 수 없습니다", - "create.track_target.occupied": "해당 선로는 사용중입니다", - "create.track_target.invalid": "이 선로를 선택할 수 없습니다", - - "create.train.unnamed": "이름없는 기차", - "create.train.cannot_relocate_moving": "움직이는 기차를 옮길 수 없습니다", - "create.train.relocate": "%1$s를 놓을 선로를 클릭하세요. 쉬프트 우클릭으로 취소합니다", - "create.train.relocate.abort": "이동이 취소되었습니다", - "create.train.relocate.success": "성공적으로 옮겼습니다", - "create.train.relocate.valid": "여기에 옮길 수 있습니다. 클릭하여 놓습니다", - "create.train.relocate.invalid": "여기에 기차를 옮길 수 없습니다", - "create.train.relocate.too_far": "기차를 이렇게 멀리 옮길 수 없습니다", - "create.train.departing_from": "%1$s에서 출발합니다", - "create.train.arrived_at": "%1$s에 도착했습니다", - "create.train.status": " 기차에 대한 정보: %1$s", - "create.train.status.back_on_track": "기차가 다시 선로에 올랐습니다", - "create.train.status.collision": "다른 기차와 부딪혔습니다", - "create.train.status.end_of_track": "기차가 선로 끝에 도달했습니다", - "create.train.status.double_portal": "기차는 차원문에서 떠나는 동시에 들어갈 수 없습니다", - "create.train.status.coupling_stress": "커플링에 부하가 심해 멈췄습니다", - "create.train.status.track_missing": "기차 아래에 선로가 없습니다", - "create.train.status.paused_for_manual": "수동 조작으로 계획표가 정지되었습니다", - "create.train.status.opposite_driver": "선로가 반대 방향을 가리키고 있습니다", - "create.train.status.missing_driver": "기관사가 없어졌습니다", - "create.train.status.found_driver": "새 기관사가 들어왔습니다", - "create.train.status.navigation_success": "이동에 성공했습니다", - "create.train.status.no_match": "그래프에 '%1$s'와 일치하는 정거장이 없습니다", - "create.train.status.no_path": "다음 목적지로 가는 길을 찾을 수 없습니다", - - "create.track_signal.cannot_change_mode": "이 신호기의 모드를 변경할 수 없습니다", - "create.track_signal.mode_change.entry_signal": "-> 구역이 사용중이 아니면 통과 가능", - "create.track_signal.mode_change.cross_signal": "-> 구역을 온전히 횡단가능하면 통과 가능", - - "create.contraption.controls.start_controlling": "%1$s를 조종합니다", - "create.contraption.controls.stop_controlling": "구조물 조종을 멈췄습니다", - "create.contraption.controls.approach_station": "%1$s을(를) 눌러 %2$s에 접근합니다", - - "create.display_link.set": "표시할 대상을 선택했습니다", - "create.display_link.success": "성공적으로 대상과 연결되었습니다", - "create.display_link.clear": "대상 선택을 해제했습니다", - "create.display_link.too_far": "이곳은 대상과 너무 멉니다", - "create.display_link.invalid": "연결된 대상이 없습니다. 다시 시도해보세요", - "create.display_link.title": "디스플레이 링크", - "create.display_link.no_source": "디스플레이 정보 수집 대상이 아님", - "create.display_link.no_target": "디스플레이 정보 표시 대상이 아님", - "create.display_link.reading_from": "정보 수집 대상:", - "create.display_link.writing_to": "정보 표시 대상:", - "create.display_link.attached_side": "붙어있는 블록", - "create.display_link.targeted_location": "선택된 블록", - "create.display_link.view_compatible": "클릭하여 호환되는 블록 보기", - "create.display_link.information_type": "정보 종류", - "create.display_link.display_on": "정보 쓰기 위치", - "create.display_link.display_on_multiline": "다음 위치에서 쓰기 시작:", - - "create.display_source.label": "접두사", - "create.display_source.combine_item_names": "아이템 이름", - "create.display_source.count_items": "필터에 맞는 아이템 양", - "create.display_source.list_items": "필터에 맞는 아이템 목록", - "create.display_source.fluid_amount": "필터에 맞는 액체 양", - "create.display_source.list_fluids": "필터에 맞는 액체 목록", - "create.display_source.nixie_tube": "닉시관 복사", - "create.display_source.fill_level": "보관함 용량", - "create.display_source.fill_level.display": "디스플레이 형식", - "create.display_source.fill_level.percent": "백분율", - "create.display_source.fill_level.progress_bar": "진행도", - "create.display_source.value_list.display": "값 디스플레이", - "create.display_source.value_list.shortened": "축약", - "create.display_source.value_list.full_number": "전체 숫자", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "플레이어 죽은 횟수", - "create.display_source.scoreboard": "목표", - "create.display_source.scoreboard.objective": "목표 ID", - "create.display_source.scoreboard.objective_not_found": "'%1$s'을(를) 찾을 수 없음", - "create.display_source.scoreboard.objective.deaths": "플레이어 죽음", - "create.display_source.time_of_day": "현재 시간", - "create.display_source.stop_watch": "스톱워치", - "create.display_source.time.format": "시간 형식", - "create.display_source.time.12_hour": "12시간", - "create.display_source.time.24_hour": "24시간", - "create.display_source.accumulate_items": "아이템 수 축적", - "create.display_source.item_throughput": "통과한 아이템 수", - "create.display_source.item_throughput.interval": "간격", - "create.display_source.item_throughput.interval.second": "초당", - "create.display_source.item_throughput.interval.minute": "분당", - "create.display_source.item_throughput.interval.hour": "시간당", - "create.display_source.train_status": "기차 계획표 상태", - "create.display_source.station_summary": "기차 정거장 요약", - "create.display_source.station_summary.filter": "정거장 이름 필터", - "create.display_source.station_summary.train_name_column": "기차 표시 길이", - "create.display_source.station_summary.platform_column": "정거장 표시 길이", - "create.display_source.station_summary.now": "잠시후", - "create.display_source.station_summary.minutes": " 분", - "create.display_source.station_summary.seconds": "%1$s초", - "create.display_source.observed_train_name": "감지된 기차 이름", - "create.display_source.max_enchant_level": "최대 마법부여 수치", - "create.display_source.boiler_status": "보일러 상태", - "create.display_source.entity_name": "엔티티 이름", - "create.display_source.kinetic_speed": "회전 속도 (RPM)", - "create.display_source.kinetic_speed.absolute": "방향 무시", - "create.display_source.kinetic_speed.directional": "방향 포함", - "create.display_source.kinetic_stress": "네트워크 피로도", - "create.display_source.kinetic_stress.display": "디스플레이 형식", - "create.display_source.kinetic_stress.progress_bar": "진행도", - "create.display_source.kinetic_stress.percent": "백분율", - "create.display_source.kinetic_stress.current": "현재 피로도", - "create.display_source.kinetic_stress.max": "전체 피로도 용량", - "create.display_source.kinetic_stress.remaining": "남은 피로도", - "create.display_source.redstone_power": "레드스톤 세기", - "create.display_source.redstone_power.display": "디스플레이 형식", - "create.display_source.redstone_power.number": "숫자", - "create.display_source.redstone_power.progress_bar": "진행도", - "create.display_source.boiler.not_enough_space": "보일러 상태를 표시할", - "create.display_source.boiler.for_boiler_status": "공간이 부족함", - - "create.display_target.line": "%1$s번째 줄", - "create.display_target.page": "%1$s번째 쪽", - "create.display_target.single_line": "단일 줄", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; 분;잠시후;15초;30초;45초", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "선택된 영역이 너무 큽니다", - "create.super_glue.cannot_reach": "선택된 블록은 붙어있어야 합니다", - "create.super_glue.click_to_confirm": "다시 클릭하여 확인합니다", - "create.super_glue.click_to_discard": "쉬프트 우클릭하여 선택을 해제합니다", - "create.super_glue.first_pos": "첫번째 위치를 선택했습니다", - "create.super_glue.abort": "선택을 제거했습니다", - "create.super_glue.not_enough": "인벤토리에 접착제가 부족합니다", - "create.super_glue.success": "접착하는 중...", - - "create.gui.config.overlay1": "Hi :)", - "create.gui.config.overlay2": "This is a sample overlay", - "create.gui.config.overlay3": "Click or drag with your mouse", - "create.gui.config.overlay4": "to move this preview", - "create.gui.config.overlay5": "Press ESC to exit this screen", - "create.gui.config.overlay6": "and save the new position", - "create.gui.config.overlay7": "Run /create overlay reset", - "create.gui.config.overlay8": "to reset to the default position", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server tick is currently slowed by %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Server tick is slowed by %s ms now >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Server tick is back to regular speed :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: use /killtps stop to bring back server tick to regular speed", - "create.command.killTPSCommand.status.usage.1": "[Create]: use /killtps start to artificially slow down the server tick", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "이 수레 구조물은 들기에 너무 큽니다!", - "create.contraption.minecart_contraption_illegal_pickup": "신비로운 힘이 이 수레 구조물을 세계에 묶어두고 있습니다!", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "구조물이 멈춤", - "create.subtitle.peculiar_bell_use": "황동 종이 울림", - "create.subtitle.worldshaper_place": "세계편집기가 쏨", - "create.subtitle.whistle_train_manual": "기적 장치가 울림", - "create.subtitle.steam": "증기 소리", - "create.subtitle.saw_activate_stone": "톱이 작동함", - "create.subtitle.schematicannon_finish": "설계도 대포가 끝남", - "create.subtitle.crafter_craft": "조합기가 조합함", - "create.subtitle.wrench_remove": "장치가 부숴짐", - "create.subtitle.train3": "대차 바퀴가 덜덜 떨림", - "create.subtitle.whistle": "기적 소리", - "create.subtitle.cogs": "톱니바퀴가 돌아감", - "create.subtitle.slime_added": "슬라임이 철퍽거림", - "create.subtitle.whistle_train_low": "낮은 기적소리", - "create.subtitle.schematicannon_launch_block": "설계도 대포가 발사함", - "create.subtitle.controller_take": "독서대가 비워짐", - "create.subtitle.crafter_click": "조합기가 작동함", - "create.subtitle.depot_plop": "아이템이 놓임", - "create.subtitle.confirm": "확인음", - "create.subtitle.mixing": "섞는 소리", - "create.subtitle.mechanical_press_activation_belt": "압착기가 작동함", - "create.subtitle.fwoomp": "감자포를 쏨", - "create.subtitle.sanding_long": "사포를 사용함", - "create.subtitle.crushing_1": "분쇄되는 소리", - "create.subtitle.depot_slide": "아이템이 미끄러짐", - "create.subtitle.blaze_munch": "블레이즈 버너가 섭취함", - "create.subtitle.funnel_flap": "퍼널이 펄럭거림", - "create.subtitle.haunted_bell_use": "귀신들린 종이 울림", - "create.subtitle.scroll_value": "스크롤 소리", - "create.subtitle.controller_put": "조작기를 놓음", - "create.subtitle.cranking": "크랭크가 돌아감", - "create.subtitle.sanding_short": "사포를 사용함", - "create.subtitle.wrench_rotate": "렌치를 사용함", - "create.subtitle.potato_hit": "채소가 부딪힘", - "create.subtitle.saw_activate_wood": "톱이 작동함", - "create.subtitle.whistle_high": "높은 기적 소리", - "create.subtitle.whistle_train_manual_low": "기적 장치가 울림", - "create.subtitle.whistle_train": "기적 소리", - "create.subtitle.haunted_bell_convert": "종에 귀신이 들림", - "create.subtitle.train": "대차 바퀴가 덜컹거림", - "create.subtitle.deny": "취소음", - "create.subtitle.controller_click": "조작기를 누름", - "create.subtitle.whistle_low": "낮은 기적 소리", - "create.subtitle.copper_armor_equip": "잠수용 장비가 철커덕거림", - "create.subtitle.mechanical_press_activation": "압착기가 작동함", - "create.subtitle.contraption_assemble": "구조물이 움직임", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "나무 지지대", - "block.create.wooden_bracket.tooltip.summary": "나무를 이용해 _축, 톱니바퀴, 파이프_를 꾸며보세요.", - - "block.create.metal_bracket.tooltip": "금속 지지대", - "block.create.metal_bracket.tooltip.summary": "금속을 이용해 _축, 톱니바퀴, 파이프_를 꾸며보세요.", - - "block.create.seat.tooltip": "SEAT", - "block.create.seat.tooltip.summary": "앉아서 드라이브를 즐기세요! _움직이는 구조물_에 _플레이어_를 _고정_시킵니다. 가구용으로도 좋습니다! 다양한 색깔이 존재합니다.", - "block.create.seat.tooltip.condition1": "좌석에 우클릭", - "block.create.seat.tooltip.behaviour1": "플레이어가 좌석에 _앉습니다_. _왼쪽 쉬프트_를 눌러 좌석에서 _일어섭니다_.", - - "item.create.blaze_cake.tooltip": "블레이즈 케이크", - "item.create.blaze_cake.tooltip.summary": "열심히 일하는 _블레이즈_ _버너_의 식사입니다. 블레이즈를 더 뜨겁게 만드세요!", - - "item.create.wand_of_symmetry.tooltip": "SYMMETRY WAND", - "item.create.wand_of_symmetry.tooltip.summary": "설정된 반사 모드에 따라 블록 설치를 _똑같이_ _배치_합니다.", - "item.create.wand_of_symmetry.tooltip.condition1": "단축바에 있을 때", - "item.create.wand_of_symmetry.tooltip.behaviour1": "활성화 유지", - "item.create.wand_of_symmetry.tooltip.control1": "땅에다 우클릭", - "item.create.wand_of_symmetry.tooltip.action1": "거울을 _생성하거나_ _옮깁니다_.", - "item.create.wand_of_symmetry.tooltip.control2": "공중에 우클릭", - "item.create.wand_of_symmetry.tooltip.action2": "활성화된 거을을 _제거합니다_.", - "item.create.wand_of_symmetry.tooltip.control3": "웅크린 상태에서 우클릭", - "item.create.wand_of_symmetry.tooltip.action3": "_설정_ _창_을 엽니다.", - - "item.create.handheld_worldshaper.tooltip": "HANDHELD WORLDSHAPER", - "item.create.handheld_worldshaper.tooltip.summary": "_지형경관_을 만들 때 좋은 간편한 도구입니다.", - "item.create.handheld_worldshaper.tooltip.control1": "블록을 보고 좌클릭", - "item.create.handheld_worldshaper.tooltip.action1": "이 도구로 설치할 블록을 설정합니다.", - "item.create.handheld_worldshaper.tooltip.control2": "블록을 보고 우클릭", - "item.create.handheld_worldshaper.tooltip.action2": "해당 위치에 설정된 _브러쉬_ 와 _도구_를 적용합니다.", - "item.create.handheld_worldshaper.tooltip.control3": "웅크린 상태에서 우클릭", - "item.create.handheld_worldshaper.tooltip.action3": "_설정_ _창_을 엽니다.", - - "item.create.tree_fertilizer.tooltip": "TREE FERTILIZER", - "item.create.tree_fertilizer.tooltip.summary": "일반적인 나무 종류들의 성장을 촉진시킬 강력한 미네랄의 혼합물입니다.", - "item.create.tree_fertilizer.tooltip.condition1": "묘목에 사용했을 때", - "item.create.tree_fertilizer.tooltip.behaviour1": "묘목을 주위 공간과 _상관없이_ 성장시킵니다.", - - "item.create.extendo_grip.tooltip": "EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "띠요오옹! 사용자의 _사거리_를 늘려줍니다.", - "item.create.extendo_grip.tooltip.condition1": "다른 손에 있을 때", - "item.create.extendo_grip.tooltip.behaviour1": "_기존_ _손_에있는 아이템의 사거리를 늘립니다.", - "item.create.extendo_grip.tooltip.condition2": "구리 산소통을 착용했을 때", - "item.create.extendo_grip.tooltip.behaviour2": "_내구도_가 _소모되지_ _않고_, 탱크에서 _공기_가 _소모됩니다_.", - - "item.create.potato_cannon.tooltip": "POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "퐁! 집에서 키운 작물로 적을 처치하세요! _구리_ _산소통_의 산소로 움직일 수 있습니다.", - "item.create.potato_cannon.tooltip.condition1": "우클릭", - "item.create.potato_cannon.tooltip.behaviour1": "_인벤토리_에서 적당한 아이템을 _쏩니다_.", - "item.create.potato_cannon.tooltip.condition2": "구리 산소통을 착용했을 때", - "item.create.potato_cannon.tooltip.behaviour2": "_내구도_가 _소모되지_ _않고_, 탱크에서 _공기_가 _소모됩니다_.", - - "item.create.filter.tooltip": "FILTER", - "item.create.filter.tooltip.summary": "장치의 _입력_과 _출력_을 _필터_ 목록에 따라 _조정_합니다.", - "item.create.filter.tooltip.condition1": "필터 슬롯에 있을 때", - "item.create.filter.tooltip.behaviour1": "필터 _설정_에 따라 아이템 흐름을 _조정_합니다.", - "item.create.filter.tooltip.condition2": "우클릭", - "item.create.filter.tooltip.behaviour2": "_설정_ _창_을 엽니다.", - - "item.create.attribute_filter.tooltip": "ATTRIBUTE FILTER", - "item.create.attribute_filter.tooltip.summary": "장치의 _입력_과 _출력_을 필터 _속성_ 목록에 따라 _조정_합니다.", - "item.create.attribute_filter.tooltip.condition1": "필터 슬롯에 있을 때", - "item.create.attribute_filter.tooltip.behaviour1": "필터 _설정_에 따라 아이템 흐름을 _조정_합니다.", - "item.create.attribute_filter.tooltip.condition2": "우클릭", - "item.create.attribute_filter.tooltip.behaviour2": "_설정_ _창_을 엽니다.", - - "item.create.empty_schematic.tooltip": "EMPTY SCHEMATIC", - "item.create.empty_schematic.tooltip.summary": "조합 재료로 쓰이거나 설계도 테이블에서 설계도를 불러올 때 쓰입니다.", - - "item.create.schematic.tooltip": "SCHEMATIC", - "item.create.schematic.tooltip.summary": "세계에 구조물을 _홀로그램으로_ 불러와 지정하고 설치합니다. 지정된 홀로그램은 _설계도_ _대포_의 _작업_ _영역_이 됩니다.", - "item.create.schematic.tooltip.condition1": "들고 있을 때", - "item.create.schematic.tooltip.behaviour1": "UI의 도구로 _변경/설치_ 할 수 있습니다.", - "item.create.schematic.tooltip.control1": "웅크린 상태에서 우클릭", - "item.create.schematic.tooltip.action1": "정확한 _좌표_ 입력을 위한 창을 엽니다.", - - "item.create.schematic_and_quill.tooltip": "SCHEMATIC AND QUILL", - "item.create.schematic_and_quill.tooltip.summary": "세계에 있는 구조물을 _.nbt파일_로 저장할 때 쓰입니다.", - "item.create.schematic_and_quill.tooltip.condition1": "1단계", - "item.create.schematic_and_quill.tooltip.behaviour1": "_두_ _모서리_를 우클릭으로 선택하세요.", - "item.create.schematic_and_quill.tooltip.condition2": "2단계", - "item.create.schematic_and_quill.tooltip.behaviour2": "면을 바라보고 _Ctrl-스크롤_하여 크기를 조정하세요. 우클릭을 다시 하면 저장됩니다.", - "item.create.schematic_and_quill.tooltip.control1": "우클릭", - "item.create.schematic_and_quill.tooltip.action1": "모서리 선택 / 저장 확인", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl를 누르고 있을 때", - "item.create.schematic_and_quill.tooltip.action2": "_Scroll_를 이용하여 거리를 조정합니다.", - "item.create.schematic_and_quill.tooltip.control3": "웅크린 상태에서 우클릭", - "item.create.schematic_and_quill.tooltip.action3": "선택 영역을 리셋하고 _삭제_합니다.", - - "block.create.schematicannon.tooltip": "SCHEMATICANNON", - "block.create.schematicannon.tooltip.summary": "장착된 설계도를 바탕으로 블록들을 _발포_합니다. _화약_을 연료로 사용하고 주변 보관함에서 아이템을 사용합니다.", - "block.create.schematicannon.tooltip.condition1": "우클릭", - "block.create.schematicannon.tooltip.behaviour1": "설정 창을 엽니다.", - - "block.create.schematic_table.tooltip": "SCHEMATIC TABLE", - "block.create.schematic_table.tooltip.summary": "_빈_ _설계도_에 저장된 설계도를 불러옵니다.", - "block.create.schematic_table.tooltip.condition1": "빈 설계도를 넣을 때", - "block.create.schematic_table.tooltip.behaviour1": "Schematics 폴더에서 선택한 파일을 업로드합니다.", - - "item.create.goggles.tooltip": "GOGGLES", - "item.create.goggles.tooltip.summary": "_장치 정보_를 착용자의 시야에 띄어주는 안경입니다.", - "item.create.goggles.tooltip.condition1": "장착했을 때", - "item.create.goggles.tooltip.behaviour1": "해당 장치의 _속도_, _피로도_, _용량_을 레벨에 따라 에 따라 색상 UI를 보여줍니다.", - "item.create.goggles.tooltip.condition2": "계측기를 바라볼 때", - "item.create.goggles.tooltip.behaviour2": "계측기가 연결된 네트워크의 _속도_나 _스트레스_의 자세한 정보를 보여줍니다.", - "item.create.goggles.tooltip.condition3": "액체 용기를 바라볼 때", - "item.create.goggles.tooltip.behaviour3": "_용량_이 얼마나 되는지, _어떤 액체_가 들어있는 지 알려줍니다.", - - "item.create.wrench.tooltip": "렌치", - "item.create.wrench.tooltip.summary": "장치 구성에 유용한 도구입니다. 장치를 _회전_, _설정_, _해체_하는 데 쓰입니다.", - "item.create.wrench.tooltip.control1": "장치에 우클릭", - "item.create.wrench.tooltip.action1": "사용자가 바라보는 _면으로_ 혹은 _반대로_ 장치를 돌립니다.", - "item.create.wrench.tooltip.control2": "웅크린 상태에서 우클릭", - "item.create.wrench.tooltip.action2": "_장치_를 _해체_하고 _즉시_ _보관함_으로 넣습니다.", - - "block.create.nozzle.tooltip": "NOZZLE", - "block.create.nozzle.tooltip.summary": "선풍기 _앞_에 붙여 선풍기의 효과를 _전방향_으로 _확대_합니다.", - - "block.create.cuckoo_clock.tooltip": "CUCKOO CLOCK", - "block.create.cuckoo_clock.tooltip.summary": "_시간의_ _흐름_을 알고 공간을 _꾸미는_ 데 좋은 공예품입니다.", - "block.create.cuckoo_clock.tooltip.condition1": "회전할 때", - "block.create.cuckoo_clock.tooltip.behaviour1": "현재 시각을 보여주고 하루에 두 번 울립니다. 점심과 플레이어가 바로 잘 수 있는 저녁에 울립니다.", - - "block.create.turntable.tooltip": "TURNTABLE", - "block.create.turntable.tooltip.summary": "_동력_으로 _멀미_를 일으킵니다.", - - "block.create.toolbox.tooltip": "공구상자", - "block.create.toolbox.tooltip.summary": "모든 발명가의 가장 친한 동료입니다. _8가지 종류의_ 아이템을 편하게 _많이_ 저장할 수 있습니다.", - "block.create.toolbox.tooltip.condition1": "파괴했을 때", - "block.create.toolbox.tooltip.behaviour1": "아이템을 _떨어뜨리지 않습니다_.", - "block.create.toolbox.tooltip.condition2": "설치했을 때", - "block.create.toolbox.tooltip.behaviour2": "_근처 플레이어_가 _단축키_를 눌러 _원격으로_ 상자 속 아이템에 접근할 수 있습니다.", - "block.create.toolbox.tooltip.condition3": "우클릭 때", - "block.create.toolbox.tooltip.behaviour3": "창을 엽니다.", - - "block.create.stockpile_switch.tooltip": "stockpile_switch", - "block.create.stockpile_switch.tooltip.summary": "붙어있는 _보관함_에 들어있는 아이템을 기반으로 레드스톤 신호를 보냅니다. 필터도 제공됩니다. _비교기_와 반대로, 수량 스위치는 신호가 반전되는 _임계점_을 조절할 수 있습니다.", - "block.create.stockpile_switch.tooltip.condition1": "우클릭", - "block.create.stockpile_switch.tooltip.behaviour1": "설정 창을 엽니다.", - - "block.create.content_observer.tooltip": "CONTENT OBSERVER", - "block.create.content_observer.tooltip.summary": "보관함이나 벨트의 아이템을 등록된 _필터_를 이용해 _탐지_합니다. _보관함, 벨트, 슈트_ 안에 해당 아이템을 탐지하는 동안, 레드스톤 신호를 보냅니다. _퍼널_가 해당 아이템을 수송하면, _1틱_의 레드스톤 신호를 보냅니다.", - "block.create.content_observer.tooltip.condition1": "보관함를 탐지할 때", - "block.create.content_observer.tooltip.behaviour1": "해당 보관함에 _필터 아이템_이 있는 동안 _레드스톤 신호_를 방출합니다.", - "block.create.content_observer.tooltip.condition2": "퍼널을 탐지할 때", - "block.create.content_observer.tooltip.behaviour2": "_필터 아이템_이 이동하면 _레드스톤 펄스_를 방출합니다.", - - "block.create.creative_crate.tooltip": "THE ENDLESS CRATE", - "block.create.creative_crate.tooltip.summary": "이 상자는 아무 아이템을 _무한히_ 저장합니다. 설계도 대포 옆에 놓을 시 준비물을 _전부_ 공급합니다.", - "block.create.creative_crate.tooltip.condition1": "필터에 아이템을 설정할 시", - "block.create.creative_crate.tooltip.behaviour1": "선택된 아이템을 _무한정_으로 _빼낼_ 수 있습니다. 대신 _들어간_ 아이템은 _삭제_됩니다.", - - "item.create.creative_blaze_cake.tooltip": "CREATIVE CAKE", - "item.create.creative_blaze_cake.tooltip.summary": "_블레이즈 버너_의 열 _세기를 조절할 수 있는_ 매우 특별한 케이크입니다. 이 케이크를 섭취한 블레이즈 버너는 _절대 꺼지지_ 않습니다.", - "item.create.creative_blaze_cake.tooltip.condition1": "블레이즈 버너에 우클릭", - "item.create.creative_blaze_cake.tooltip.behaviour1": "블레이즈 버너의 열 세기를 _고정_시킵니다. 다시 사용하면 블레이즈 버너의 열 세기를 _순환_합니다.", - - "block.create.controller_rail.tooltip": "CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "_광산 수레_의 _이동속도_를 _세밀하게_ _조정_할 수 있는 _양방향_ _전동 레일_입니다.", - "block.create.controller_rail.tooltip.condition1": "레드스톤 신호를 받을 때", - "block.create.controller_rail.tooltip.behaviour1": "_신호 세기에 따라_ 지나가는 수레를 _가속, 감속_합니다. 레드스톤 신호는 다른 방향 레일에도 전달됩니다. 두 방향레일에 다른 세기를 전달하면 중간 레일들은 두 세기 사이의 신호를 받습니다.", - - "item.create.sand_paper.tooltip": "SAND PAPER", - "item.create.sand_paper.tooltip.summary": "재료들을 _윤내는 데_ 쓰이는 거친 종이입니다. 기계 손이 자동으로 쓸 수 있습니다.", - "item.create.sand_paper.tooltip.condition1": "사용할 때", - "item.create.sand_paper.tooltip.behaviour1": "_다른 손_에있는 아이템과 _바닥에 있는 아이템_을 윤냅니다.", - - "item.create.builders_tea.tooltip": "BUILDERS TEA", - "item.create.builders_tea.tooltip.summary": "하루를 시작하기에 좋은 음료입니다. _새로운 영감_을 줍니다.", - - "item.create.refined_radiance.tooltip": "REFINED RADIANCE", - "item.create.refined_radiance.tooltip.summary": "_흡수된_ _빛_으로 제련된 색채 혼합물입니다.", - "item.create.refined_radiance.tooltip.condition1": "현재 개발 중", - "item.create.refined_radiance.tooltip.behaviour1": "이 재료의 사용처는 이후 업데이트에 있을겁니다.", - - "item.create.shadow_steel.tooltip": "SHADOW STEEL", - "item.create.shadow_steel.tooltip.summary": "_공허_에서 제련된 색채 혼합물입니다.", - "item.create.shadow_steel.tooltip.condition1": "현재 개발 중", - "item.create.shadow_steel.tooltip.behaviour1": "이 재료의 사용처는 이후 업데이트에 있을겁니다.", - - "item.create.linked_controller.tooltip": "LINKED CONTROLLER", - "item.create.linked_controller.tooltip.summary": "_여섯_ _버튼_으로 _레드스톤_ _링크_와 연결되는 _휴대용_ _조작기_입니다.", - "item.create.linked_controller.tooltip.condition1": "우클릭", - "item.create.linked_controller.tooltip.behaviour1": "조작기를 킵니다. 조작하면서 _움직일_ _수_ _없습니다_.", - "item.create.linked_controller.tooltip.condition2": "웅크리면서 우클릭", - "item.create.linked_controller.tooltip.behaviour2": "_설정_ _창_을 엽니다.", - "item.create.linked_controller.tooltip.condition3": "레드스톤 링크 수신기에 우클릭", - "item.create.linked_controller.tooltip.behaviour3": "_연결_ _모드_를 활성화하고, _여섯_ _버튼_ 중 하나를 눌러 조작기를 주파수와 연결합니다.", - "item.create.linked_controller.tooltip.condition4": "독서대에 우클릭", - "item.create.linked_controller.tooltip.behaviour4": "조작기를 독서대에 올려놓아 쉽게 조작할 수 있습니다. (웅크리면서 우클릭으로 회수헙니다.)", - - "item.create.diving_helmet.tooltip": "DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "_구리_ _산소통_과 함께, 착용자가 물 속에서 _오랫동안_ _호흡_할 수 있게합니다.", - "item.create.diving_helmet.tooltip.condition1": "착용했을 때", - "item.create.diving_helmet.tooltip.behaviour1": "산소통에서 공기를 느리게 빨아들이며 _수중_ _호흡_ 효과를 제공합니다.", - - "item.create.copper_backtank.tooltip": "COPPER BACKTANK", - "item.create.copper_backtank.tooltip.summary": "공기를 옮길 수 있는 _착용가능한_ 탱크입니다.", - "item.create.copper_backtank.tooltip.condition1": "착용했을 때", - "item.create.copper_backtank.tooltip.behaviour1": "필요한 장비에 _공기_를 제공합니다.", - "item.create.copper_backtank.tooltip.condition2": "설치되고 동력으로 회전될 때", - "item.create.copper_backtank.tooltip.behaviour2": "동력 속도에 따라 _공기_를 _모읍니다_.", - - "block.create.placard.tooltip": "PLACARD", - "block.create.placard.tooltip.summary": "_아이템_을 황동안에 _장식_하세요. 구조물에도 사용할 수 있습니다!", - "block.create.placard.tooltip.condition1": "아이템을 들고 우클릭", - "block.create.placard.tooltip.behaviour1": "플래카드에 _아이템_을 추가합니다. _이미_ 같은 아이템이 장식되어 있다면 짧게 _레드스톤 신호_를 _방출_합니다.", - "block.create.placard.tooltip.condition2": "때렸을 때", - "block.create.placard.tooltip.behaviour2": "플래카드의 아이템을 _제거_합니다.", - - "block.create.flywheel.tooltip": "FLYWHEEL", - "block.create.flywheel.tooltip.summary": "황동 바퀴로 _장치_를 _장식_해보세요.", - "block.create.flywheel.tooltip.condition1": "동력을 공급받을 때", - "block.create.flywheel.tooltip.behaviour1": "회전합니다.", - - "item.create.diving_boots.tooltip": "DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "해저를 돌아다니기에 적합한 _무거운_ _부츠_ 한 켤레입니다.", - "item.create.diving_boots.tooltip.condition1": "착용했을 때", - "item.create.diving_boots.tooltip.behaviour1": "착용자는 빠르게 가라앉고 _수영_할 수 _없습니다_. 대신 물 속에서 _걷고_, _뛸_ 수 있습니다. 또한 _벨트_에 영향받지 않습니다.", - - "item.create.crafting_blueprint.tooltip": "CRAFTING BLUEPRINT", - "item.create.crafting_blueprint.tooltip.summary": "벽에 설치해 _특정_ _재료_로 더 _쉽게_ _조합_할 수 있습니다. 각 슬롯은 조합법을 나타냅니다.", - "item.create.crafting_blueprint.condition1": "빈 슬롯을 우클릭", - "item.create.crafting_blueprint.behaviour1": "_조합법_과 전시할 아이템을 설정하는 창을 엽니다.", - "item.create.crafting_blueprint.condition2": "설정된 슬롯에 우클릭", - "item.create.crafting_blueprint.behaviour2": "자신의 _인벤토리_에서 해당 슬롯의 _조합법_을 _실행_합니다. _웅크리면서_ 우클릭하면 한 번에 여러개를 조합합니다.", - - "item.create.minecart_coupling.tooltip": "MINECART COUPLING", - "item.create.minecart_coupling.tooltip.summary": "당신의 모든 _수레들을 이어 _멋진 _기차_를 만들어보세요.", - "item.create.minecart_coupling.tooltip.condition1": "광산 수레에 사용할 때", - "item.create.minecart_coupling.tooltip.behaviour1": "_두 수레를 묶어_ 이동할 때 고정된 _거리를 유지하게_ 합니다.", - - "item.create.experience_nugget.tooltip": "NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "_띵!_ 당신의 멋진 발명품에서 탄생한 _영감_의 알맹이입니다.", - "item.create.experience_nugget.tooltip.condition1": "사용했을 때", - "item.create.experience_nugget.tooltip.behaviour1": "담겨져 있던 _경험치_를 _배출_합니다.", - - "block.create.peculiar_bell.tooltip": "PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "장식을 위한 황동 종입니다. 영혼 불꽃 위에 설치하면 _기이한_ 일이 일어난다고 합니다...", - - "block.create.haunted_bell.tooltip": "HAUNTED BELL", - "block.create.haunted_bell.tooltip.summary": "지옥의 길잃은 영혼들이 씌인 _저주받은_ 종입니다.", - "block.create.haunted_bell.tooltip.condition1": "들고 있거나 종을 울릴 때", - "block.create.haunted_bell.tooltip.behaviour1": "_적대적_ _몹_이 생성되는 _빛이_ _없는_ 자리를 표시합니다.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "이 기능은 렌치를 이용해 변경할 수 있습니다.", - "create.ponder.shared.storage_on_contraption": "구조물에 부착된 보관함은 구조물이 떨어뜨린 아이템을 자동으로 줍습니다.", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "기본 속도: 16 RPM", - "create.ponder.shared.movement_anchors": "섀시나 강력 접착제를 이용해 큰 구조물도 옮길 수 있습니다.", - "create.ponder.tag.redstone": "레드스톤 부품", - "create.ponder.tag.redstone.description": "레드스톤 공학에 쓰이는 부품입니다.", - "create.ponder.tag.contraption_assembly": "블록 부착 도구", - "create.ponder.tag.contraption_assembly.description": "블록들을 이어 구조물로 만들게해주는 도구와 부품입니다.", - "create.ponder.tag.fluids": "액체 조정", - "create.ponder.tag.fluids.description": "액체를 나르고 사용하는 장치입니다.", - "create.ponder.tag.decoration": "장식", - "create.ponder.tag.decoration.description": "주로 장식 용도로 쓰이는 부품입니다.", - "create.ponder.tag.windmill_sails": "풍차 베어링의 날개", - "create.ponder.tag.windmill_sails.description": "조립되었을 때 풍차 구조물의 동력에 영향을 주는 블록들입니다. 이 블록들은 동일한 효율을 가집니다.", - "create.ponder.tag.arm_targets": "기계 팔의 목표 대상", - "create.ponder.tag.arm_targets.description": "기계 팔이 가져가거나 놓을 곳으로 선택할 수 있는 부품입니다.", - "create.ponder.tag.kinetic_appliances": "동력 장치", - "create.ponder.tag.kinetic_appliances.description": "동력을 사용하는 장치입니다.", - "create.ponder.tag.kinetic_sources": "동력 생산", - "create.ponder.tag.kinetic_sources.description": "동력을 생산하는 장치입니다.", - "create.ponder.tag.movement_anchor": "이동 고정장치", - "create.ponder.tag.movement_anchor.description": "부착된 구조물을 다양한 방법으로 움직이게하는 장치입니다.", - "create.ponder.tag.kinetic_relays": "동력 부품", - "create.ponder.tag.kinetic_relays.description": "동력을 다른 곳으로 연결할 때 도움을 주는 부품입니다.", - "create.ponder.tag.contraption_actor": "구조물 장치", - "create.ponder.tag.contraption_actor.description": "움직이는 구조물에 부착되어 특정 기능을 수행하는 장치입니다.", - "create.ponder.tag.creative": "크리에이티브 모드", - "create.ponder.tag.creative.description": "서바이벌 모드에서는 얻을 수 없는 부품입니다.", - "create.ponder.tag.display_sources": "디스플레이 링크의 정보 수집 대상", - "create.ponder.tag.display_sources.description": "디스플레이 링크가 읽을 수 있는 정보를 제공하는 부품과 블록입니다", - "create.ponder.tag.logistics": "아이템 수송", - "create.ponder.tag.logistics.description": "아이템을 옮기는데 도움을 줄 부품입니다.", - "create.ponder.tag.display_targets": "디스플레이 링크의 정보 표시 대상", - "create.ponder.tag.display_targets.description": "디스플레이 링크가 받은 정보를 표시할 수 있는 부품과 블록입니다", - "create.ponder.tag.train_related": "선로 장비", - "create.ponder.tag.train_related.description": "기차 구조물 조립이나 관리에 쓰이는 부품입니다", - - "create.ponder.analog_lever.header": "아날로그 레버를 이용해 신호 조절하기", - "create.ponder.analog_lever.text_1": "아날로그 레버는 정확하고 간편하게 레드스톤 신호의 세기를 조절합니다.", - "create.ponder.analog_lever.text_2": "우클릭으로 세기를 높입니다.", - "create.ponder.analog_lever.text_3": "웅크리면서 우클릭하면, 세기를 낮춥니다.", - - "create.ponder.andesite_tunnel.header": "안산암 터널 사용하기", - "create.ponder.andesite_tunnel.text_1": "안산암 터널은 벨트를 덮는데 사용할 수 있습니다.", - "create.ponder.andesite_tunnel.text_2": "인신임 터널의 옆면에 접촉점이 있다면...", - "create.ponder.andesite_tunnel.text_3": "...터널은 통과하는 아이템 스택에서 1개의 아이템을 분리시킵니다.", - "create.ponder.andesite_tunnel.text_4": "나머지는 가던 길을 갑니다.", - - "create.ponder.auto_schedule.header": "정거장 & 계획표", - "create.ponder.auto_schedule.text_1": "계획표로 기관사에게 도착점을 가르칠 수 있습니다.", - "create.ponder.auto_schedule.text_2": "비교기는 정거장에 기차가 도착하면 신호를 방출합니다.", - "create.ponder.auto_schedule.text_3": "정차할 때는 정거장에는 표시된 방향으로 접근해야합니다.", - "create.ponder.auto_schedule.text_4": "정거장에 새 계획표를 자동으로 지정할 수 있습니다.", - "create.ponder.auto_schedule.text_5": "정거장 위에 놓인 계획표는 도착한 기차 기관사에게 적용됩니다.", - "create.ponder.auto_schedule.text_6": "수동으로 계획표를 전달해줄 때와는 다르게, 계획표를 가져가지 않습니다.", - - "create.ponder.basin.header": "대야 안에서 아이템 처리하기", - "create.ponder.basin.text_1": "대야는 아이템과 액체를 담을 수 있습니다.", - "create.ponder.basin.text_2": "처리 이후, 대야는 옆면 아래로 결과물을 내보냅니다.", - "create.ponder.basin.text_3": "알맞는 부품이 있다면, 대야는 수송관을 나타냅니다.", - "create.ponder.basin.text_4": "다양한 부품들이 아이템을 받을 수 있습니다.", - "create.ponder.basin.text_5": "결과물은 아래 보관함에 떨어집니다.", - "create.ponder.basin.text_6": "수송관이 없다면, 대야는 처리된 아이템을 보관합니다.", - "create.ponder.basin.text_7": "결과물이 다시 사용될 때 유용합니다.", - "create.ponder.basin.text_8": "이 경우, 대야에서 특정 결과물을 빼내야 합니다.", - "create.ponder.basin.text_9": "처리되지 않은 아이템이 나오는 것을 방지하기 위해서는 필터가 필요합니다.", - - "create.ponder.bearing_modes.header": "베어링의 이동 설정", - "create.ponder.bearing_modes.text_1": "멈췄을 때, 베어링은 구조물을 가까운 수직 각도로 설치합니다.", - "create.ponder.bearing_modes.text_2": "이는 절대 설치하지 않거나, 시작한 지점에만 설치하도록 설정할 수 있습니다.", - - "create.ponder.belt_casing.header": "벨트 덮기", - "create.ponder.belt_casing.text_1": "황동, 안산암 케이스는 벨트를 꾸미는데 사용됩니다.", - "create.ponder.belt_casing.text_2": "렌치로 케이스를 없앨 수 있습니다.", - - "create.ponder.belt_connector.header": "벨트 사용하기", - "create.ponder.belt_connector.text_1": "두 축을 벨트로 우클릭하여 연결합니다.", - "create.ponder.belt_connector.text_2": "실수로 선택했다면, 웅크리면서 우클릭하여 취소합니다.", - "create.ponder.belt_connector.text_3": "벨트에 축을 추가로 넣을 수 있습니다.", - "create.ponder.belt_connector.text_4": "벨트로 연결된 축들은 같은 속도, 방향으로 회전합니다.", - "create.ponder.belt_connector.text_5": "추가된 축은 렌치로 없앨 수 있습니다.", - "create.ponder.belt_connector.text_6": "벨트를 염색하여 꾸밀 수 있습니다.", - - "create.ponder.belt_directions.header": "벨트 설치에 알맞는 방향", - "create.ponder.belt_directions.text_1": "벨트는 임의의 각도로 설치할 수 없습니다.", - "create.ponder.belt_directions.text_2": "1. 수평으로 연결할 수 있습니다.", - "create.ponder.belt_directions.text_3": "2. 대각선으로 연결할 수 있습니다.", - "create.ponder.belt_directions.text_4": "3. 수직으로 연결할 수 있습니다.", - "create.ponder.belt_directions.text_5": "4. 또한 수직 축을 평행하게 연결할 수 있습니다.", - "create.ponder.belt_directions.text_6": "이것들이 가능한 방향입니다. 벨트는 2 ~ 20 블록 길이를 연결합니다.", - - "create.ponder.belt_transport.header": "벨트를 이용한 수송", - "create.ponder.belt_transport.text_1": "움직이는 벨트는 아이템과 엔티티를 옮깁니다.", - "create.ponder.belt_transport.text_2": "빈손으로 우클릭하여 벨트 위의 아이템을 가져옵니다.", - - "create.ponder.blaze_burner.header": "블레이즈 버너 데우기", - "create.ponder.blaze_burner.text_1": "블레이즈 버너는 대야 안에서 처리되는 아이템에 열을 제공합니다.", - "create.ponder.blaze_burner.text_2": "이런 식으로, 블레이즈는 가연성 물질을 먹습니다.", - "create.ponder.blaze_burner.text_3": "블레이즈 케아크를 먹이면 버너는 더 뜨겁게 타오릅니다.", - "create.ponder.blaze_burner.text_4": "이 시스템은 기계 손이나 기계 팔을 이용해 자동화될 수 있습니다.", - - "create.ponder.brass_funnel.header": "황동 퍼널", - "create.ponder.brass_funnel.text_1": "안산암 퍼널는 아이템 한 개만 뽑아냅니다.", - "create.ponder.brass_funnel.text_2": "황동 퍼널는 한 스택까지 뽑을 수 있습니다.", - "create.ponder.brass_funnel.text_3": "핕터 슬롯을 스크롤하여 추출 갯수를 조절합니다.", - "create.ponder.brass_funnel.text_4": "필터 슬롯에 아이템을 사용하여 추출할 아이템 종류를 정합니다.", - - "create.ponder.brass_tunnel.header": "황동 터널 사용하기", - "create.ponder.brass_tunnel.text_1": "황동 터널은 벨트를 덮는데 사용할 수 있습니다.", - "create.ponder.brass_tunnel.text_2": "황동 터널은 열린 면마다 필터 슬롯이 있습니다.", - "create.ponder.brass_tunnel.text_3": "입구 필터는 맞지않는 아이템을 막습니다.", - "create.ponder.brass_tunnel.text_4": "출구 필터는 종류에 따라 아이템을 분류합니다.", - "create.ponder.brass_tunnel.text_5": "지나가는 아이템의 출구가 여러개일 때, 분배 모드가 어떻게 분배할지 정합니다.", - "create.ponder.brass_tunnel.text_6": "벨트 위, 평행한 황동 터널끼리는 연결됩니다.", - "create.ponder.brass_tunnel.text_7": "들어오는 아이템은 연결된 모든 출구로 분배됩니다.", - "create.ponder.brass_tunnel.text_8": "이런 식으로, 터널을 통해 직접 아이템을 넣을 수 있습니다.", - - "create.ponder.brass_tunnel_modes.header": "황동 터널의 분배 모드", - "create.ponder.brass_tunnel_modes.text_1": "렌치를 이용해, 황동 터널이 어떻게 분배할지 설정합니다.", - "create.ponder.brass_tunnel_modes.text_10": "[입력 동기화] 설정은 황동 터널만의 고유 설정입니다.", - "create.ponder.brass_tunnel_modes.text_11": "모든 입구에 아이템이 있어야만 통과할 수 있습니다.", - "create.ponder.brass_tunnel_modes.text_12": "이 설정은 연결된 모든 벨트에 아이템을 동시에 공급할 수 있습니다.", - "create.ponder.brass_tunnel_modes.text_2": "[분할] 설정은 가능한 출구에 아이템을 동등하게 분배하려 합니다.", - "create.ponder.brass_tunnel_modes.text_3": "한 출구가 아이템을 더 받을 수 없을 때, 그 출구는 제외됩니다.", - "create.ponder.brass_tunnel_modes.text_4": "[분리(강제적)] 설정은 출구를 제외하지 않습니다. 대신, 모두 아이템을 받을 수 있을 때까지 기다립니다.", - "create.ponder.brass_tunnel_modes.text_5": "[순서대로 처리] 설정은 아이템 수량을 유지한 채, 출구 차례대로 아이템을 분배합니다.", - "create.ponder.brass_tunnel_modes.text_6": "전 설정과 마찬가지로, 한 출구가 아이템을 더 받을 수 없다면, 그 출구는 제외됩니다.", - "create.ponder.brass_tunnel_modes.text_7": "[순서대로 처리(강제적)] 설정은 출구를 제외하지 않습니다.", - "create.ponder.brass_tunnel_modes.text_8": "[가장 가까운 곳] 설정은 입구와 가까운 출구 순서로 우선순위를 정합니다.", - "create.ponder.brass_tunnel_modes.text_9": "[무작위] 설정은 랜덤한 출구로 아이템을 분배합니다.", - - "create.ponder.cart_assembler.header": "수레 조립기로 구조물 움직이기", - "create.ponder.cart_assembler.text_1": "활성화된 수레 조립기는 지나가는 수레에 구조물을 부착합니다.", - "create.ponder.cart_assembler.text_2": "신호가 없다면, 구조물을 때어냅니다.", - "create.ponder.cart_assembler.text_3": "수레에 렌치로 우클릭하면 구조물을 들고 다닐 수 있습니다.", - - "create.ponder.cart_assembler_dual.header": "한 구조물에 여러 수레 결합하기", - "create.ponder.cart_assembler_dual.text_1": "두 조립기가 같은 구조물을 공유할 때...", - "create.ponder.cart_assembler_dual.text_2": "둘 중 하나를 작동시키면 기차 구조물이 됩니다.", - "create.ponder.cart_assembler_dual.text_3": "두 수레는 수레 커플링으로 연결된 것처럼 행동합니다.", - - "create.ponder.cart_assembler_modes.header": "수레 구조물 회전 설정", - "create.ponder.cart_assembler_modes.text_1": "구조물이 바라보는 방향은 수레의 방향과 동일합니다.", - "create.ponder.cart_assembler_modes.text_2": "이 화살표는 구조물이 바라보는 방향을 나타냅니다.", - "create.ponder.cart_assembler_modes.text_3": "조립기 설정에서 회전을 잠갔다면, 구조물은 회전하지 않습니다.", - - "create.ponder.cart_assembler_rails.header": "다른 종류의 수레와 레일", - "create.ponder.cart_assembler_rails.text_1": "일반 레일위의 조립기는 지나가는 수레에 아무 영향을 미치지 않습니다.", - "create.ponder.cart_assembler_rails.text_2": "전동 레일, 방향 레일 위에 있을 때, 신호를 받을 때까지 수레는 멈춥니다.", - "create.ponder.cart_assembler_rails.text_3": "다른 수레들도 쓸 수 있습니다.", - "create.ponder.cart_assembler_rails.text_4": "화로 수레는 부착된 보관함에서 연료를 가져와 스스로 움직입니다.", - - "create.ponder.chain_drive.header": "체인 드라이브로 회전 전달하기", - "create.ponder.chain_drive.text_1": "체인 드라이브는 한 줄로 회전을 전달합니다.", - "create.ponder.chain_drive.text_2": "이렇게 연결된 모든 축들은 같은 방향으로 회전합니다.", - "create.ponder.chain_drive.text_3": "한 줄의 아무 부분을 90도 돌릴 수 있습니다.", - - "create.ponder.chain_gearshift.header": "벨트 변속기를 통해 회전 속도 조절하기", - "create.ponder.chain_gearshift.text_1": "신호를 받지 않은 벨트 변속기는 체인 드라이브와 똑같이 작동합니다.", - "create.ponder.chain_gearshift.text_2": "신호를 받으면, 다른 체인 드라이브에 전달되는 속도는 2배가 됩니다.", - "create.ponder.chain_gearshift.text_3": "반대로 벨트 변속기가 직접 회전을 받지 않고 있다면, 변속기의 속도는 절반이 됩니다.", - "create.ponder.chain_gearshift.text_4": "두 가지 경우에도, 같은 줄의 체인 드라이브의 속도는 변속기 속도의 2배가 됩니다.", - "create.ponder.chain_gearshift.text_5": "아날로그 레버를 사용하면, 속도 비율을 1 ~ 2배 사이로 맞출 수 있습니다.", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "슈트를 이용해 아이템을 아래로 옮기기", - "create.ponder.chute.text_1": "슈트는 보관함에 있는 아이템을 수직으로 옮깁니다.", - "create.ponder.chute.text_2": "렌치를 이용해 창문을 만들 수 있습니다.", - "create.ponder.chute.text_3": "슈트 옆면에 다른 슈트를 설치하면 대각선으로 연결됩니다.", - - "create.ponder.chute_upward.header": "슈트를 이용해 아이템을 위로 옮기기", - "create.ponder.chute_upward.text_1": "선풍기를 위/아래에 설치하면, 슈트는 아이템을 위로 보냅니다.", - "create.ponder.chute_upward.text_2": "엔지니어의 고글로 슈트를 관찰하여 이동 방향을 확인하세요.", - "create.ponder.chute_upward.text_3": "막힌 끝 부분에서 아이템은 옆에서 넣거나 빼내야합니다.", - - "create.ponder.clockwork_bearing.header": "시계 베어링을 이용한 구조물 움직이기", - "create.ponder.clockwork_bearing.text_1": "시계 베어링은 앞에 있는 블록을 부착시킵니다.", - "create.ponder.clockwork_bearing.text_2": "동력을 받으면, 현재 시간에 맞춰 구조물이 돌아갑니다.", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "베어링을 우클릭하여 구조물을 멈추거나 움직이세요.", - "create.ponder.clockwork_bearing.text_6": "시침 구조물 앞에 분침 구조물을 추가할 수 있습니다.", - "create.ponder.clockwork_bearing.text_7": "접착제나 슬라임볼로 두 구조물을 연결하지 마세요.", - "create.ponder.clockwork_bearing.text_8": "두번째 구조물은 분침처럼 돌아갑니다.", - - "create.ponder.clutch.header": "클러치를 이용해 동력 조절하기", - "create.ponder.clutch.text_1": "클러치는 한 줄로 동력을 전달합니다.", - "create.ponder.clutch.text_2": "레드스톤 신호를 받으면, 동력 전달을 끊습니다.", - - "create.ponder.cog_speedup.header": "톱니바퀴로 기어변속하기", - "create.ponder.cog_speedup.text_1": "큰 톱니바퀴와 작은 톱니바퀴는 대각선으로 연결됩니다.", - "create.ponder.cog_speedup.text_2": "큰 쪽에서 작은 쪽으로 가는 속도는 2배가 됩니다.", - "create.ponder.cog_speedup.text_3": "반대의 경우에는 속도가 절반이 됩니다.", - - "create.ponder.cogwheel.header": "톱니바퀴를 이용해 동력 전달하기", - "create.ponder.cogwheel.text_1": "톱니바퀴는 인접한 톱니바퀴에 동력을 전달합니다.", - "create.ponder.cogwheel.text_2": "이렇게 연결된 톱니바퀴 축은 반대방향으로 돌아갑니다.", - - "create.ponder.cogwheel_casing.header": "톱니바쿼에 케이스 씌우기", - "create.ponder.cogwheel_casing.text_1": "황동, 안산암 케이스는 톱니바퀴를 꾸밀 때 사용할 수 있습니다.", - "create.ponder.cogwheel_casing.text_2": "기본적으로 케이스를 씌운 톱니바퀴는 축과 연결되지 않습니다.", - "create.ponder.cogwheel_casing.text_3": "렌치를 사용하여 축과 연결하거나 차단할 수 있습니다.", - - "create.ponder.creative_fluid_tank.header": "크리에이티브 탱크", - "create.ponder.creative_fluid_tank.text_1": "크리에이티브 탱크는 무한히 액체를 공급합니다.", - "create.ponder.creative_fluid_tank.text_2": "액체가 든 용기로 우클릭하여 액체를 채울 수 있습니다.", - "create.ponder.creative_fluid_tank.text_3": "파이프로 탱크에서 액체를 무한히 뽑아낼 수 있습니다.", - "create.ponder.creative_fluid_tank.text_4": "크리에이티브 탱크로 들어가는 모든 액체는 사라집니다.", - - "create.ponder.creative_motor.header": "크리에이티브 모터를 이용해 동력 생산하기", - "create.ponder.creative_motor.text_1": "크리에이티브 모터는 동력을 쉽게 생산, 조절합니다.", - "create.ponder.creative_motor.text_2": "모터 후면을 스크롤해서 모터의 RPM을 조절합니다.", - - "create.ponder.creative_motor_mojang.header": "Mojang의 수수께끼", - - "create.ponder.crushing_wheels.header": "분쇄 휠을 이용해 아이템 가공하기", - "create.ponder.crushing_wheels.text_1": "한 쌍의 분쇄 휠은 아이템을 매우 효과적으로 갈아버립니다.", - "create.ponder.crushing_wheels.text_2": "동력을 전달하여 서로 맞물리게 해야합니다.", - "create.ponder.crushing_wheels.text_3": "위에서 투입된 아이템은 가공되고, 아래로 떨어집니다.", - "create.ponder.crushing_wheels.text_4": "이 과정은 자동화 될 수 있습니다.", - - "create.ponder.deployer.header": "기계 손 이용하기", - "create.ponder.deployer.text_1": "동력을 받으면, 기계 손은 플레이어의 행동을 흉내냅니다.", - "create.ponder.deployer.text_10": "손에다 우클릭하여 기계 손이 쓸 아이템을 건네세요.", - "create.ponder.deployer.text_11": "아이템은 자동으로 투입될 수 있습니다.", - "create.ponder.deployer.text_12": "필터 슬롯도 있습니다.", - "create.ponder.deployer.text_13": "필터가 설정되면, 필터에 맞는 아이템을 들고있을 때 작동합니다.", - "create.ponder.deployer.text_14": "필터에 맞는 아이템만 들어가며...", - "create.ponder.deployer.text_15": "...그 외의 아이템은 배출됩니다.", - "create.ponder.deployer.text_2": "기계 손은 한 칸 떨어진 블록에 상호작용합니다.", - "create.ponder.deployer.text_3": "바로 앞에 블록이 있어도 상괸없습니다.", - "create.ponder.deployer.text_4": "기계 손이 할 수 있는 것:", - "create.ponder.deployer.text_5": "블록 설치하기", - "create.ponder.deployer.text_6": "아이템 사용하기", - "create.ponder.deployer.text_7": "블록 활성화하기", - "create.ponder.deployer.text_8": "블록 수확하기", - "create.ponder.deployer.text_9": "몹 공격하기", - - "create.ponder.deployer_contraption.header": "구조물에서의 기계 손", - "create.ponder.deployer_contraption.text_1": "기계 손이 움직이는 구조물의 일부면...", - "create.ponder.deployer_contraption.text_2": "...기계 손은 움직일 때마다 작동하며, 구조물에 붙어있는 아무 보관함의 아이템을 사용합니다.", - "create.ponder.deployer_contraption.text_3": "필터를 이용해 어떤 아이템을 사용할 지 정할 수 있습니다.", - - "create.ponder.deployer_modes.header": "기계 손의 작동 방식", - "create.ponder.deployer_modes.text_1": "기계 손은 기본적으로 우클릭을 흉내냅니다.", - "create.ponder.deployer_modes.text_2": "렌치를 이용해, 좌클릭을 흉내내도록 설정할 수 있습니다.", - - "create.ponder.deployer_processing.header": "기계 손으로 아이템 가공하기", - "create.ponder.deployer_processing.text_1": "기계 손이 적절한 아이템을 가지고 있으면, 아래 있는 아이템을 가공합니다.", - "create.ponder.deployer_processing.text_2": "가공할 아이템은 기계 손 아래에 떨구거나 아이템 거치대에 올려두어야 합니다.", - "create.ponder.deployer_processing.text_3": "아이템이 벨트에 있으면...", - "create.ponder.deployer_processing.text_4": "...기계 손이 알아서 아이템 이동을 멈추고 가공합니다.", - - "create.ponder.deployer_redstone.header": "레드스톤과 기계 손", - "create.ponder.deployer_redstone.text_1": "레드스톤 신호를 받으면, 기계 손은 작동하지 않습니다.", - "create.ponder.deployer_redstone.text_2": "작동을 멈추기 전에, 기계 손은 입력된 행동을 마무리합니다.", - "create.ponder.deployer_redstone.text_3": "따라서 부정 펄스는 한 번만 작동하게 합니다.", - - "create.ponder.depot.header": "아이템 거치대 사용하기", - "create.ponder.depot.text_1": "아이템 거치대는 고정된 벨트 역할입니다.", - "create.ponder.depot.text_2": "우클릭해서 아이템을 놓거나 가져갑니다.", - "create.ponder.depot.text_3": "벨트처럼, 놓여진 아이템은 가공될 수 있습니다.", - "create.ponder.depot.text_4": "그리고 기계 팔의 목표가 될 수 있습니다.", - - "create.ponder.display_board.header": "디스플레이 화면", - "create.ponder.display_board.text_1": "디스플레이 화면은 조절 가능한 표지판입니다.", - "create.ponder.display_board.text_2": "작동하려면 동력이 필요합니다.", - "create.ponder.display_board.text_3": "문자를 표시하는 방법은 이름표를 사용하거나...", - "create.ponder.display_board.text_4": "...디스플레이 링크를 이용하는 것입니다.", - "create.ponder.display_board.text_5": "염료를 각 줄마다 사용할 수 있습니다.", - "create.ponder.display_board.text_6": "맨 손으로 우클릭하여 줄을 초기화합니다.", - - "create.ponder.display_link.header": "디스플레이 링크 사용하기", - "create.ponder.display_link.text_1": "디스플레이 링크는 유동적인 정보를 표시하는데 사용됩니다.", - "create.ponder.display_link.text_2": "먼저 정보를 표시할 곳을 우클릭하고...", - "create.ponder.display_link.text_3": "...정보를 읽을 블록 옆에 설치합니다.", - "create.ponder.display_link.text_4": "창을 열어 어떤 정보를 어떻게 보낼지 설정합니다.", - "create.ponder.display_link.text_5": "이제 정보가 링크로부터 전송되어 표시됩니다.", - "create.ponder.display_link.text_6": "모든 블록이 정보를 제공하진 않습니다.", - "create.ponder.display_link.text_7": "호환되는 블록은 각각 다른 종류를 제공합니다.", - "create.ponder.display_link.text_8": "디스플레이 링크는 여러 블록에게 정보를 보낼 수 있습니다.", - - "create.ponder.display_link_redstone.header": "레드스톤 신호", - "create.ponder.display_link_redstone.text_1": "레드스톤 신호를 받으면, 디스플레이 링크는 정보를 전달하지 않습니다.", - "create.ponder.display_link_redstone.text_2": "신호가 끊기면, 딜레이가 초기화되어 새 정보가 바로 전달됩니다.", - "create.ponder.display_link_redstone.text_3": "정보를 제공하는 블록은 링크에게 영향을 미치지 않습니다.", - - "create.ponder.empty_blaze_burner.header": "빈 블레이즈 버너 사용하기", - "create.ponder.empty_blaze_burner.text_1": "블레이즈를 우클릭하여 버너에 가둡니다.", - "create.ponder.empty_blaze_burner.text_2": "또는 스포너에서도 블레이즈를 가둘 수 있습니다.", - "create.ponder.empty_blaze_burner.text_3": "이제 당신은 다양한 장치에 쓰일 이상적인 열원을 얻었습니다.", - "create.ponder.empty_blaze_burner.text_4": "장식적인 요소로는 라이터로 불을 붙일 수 있습니다.", - "create.ponder.empty_blaze_burner.text_5": "불꽃은 영혼불꽃으로 바꿀 수 있습니다.", - "create.ponder.empty_blaze_burner.text_6": "그러나 장치에 쓰일 열원으로는 적합하지 않습니다.", - - "create.ponder.encased_fluid_pipe.header": "파이프에 케이스 씌우기", - "create.ponder.encased_fluid_pipe.text_1": "구리 케이스로 파이프를 꾸밀 수 있습니다.", - "create.ponder.encased_fluid_pipe.text_2": "파이프를 가려주는 것 외에도, 파이프의 방향을 고정시키는 역할도 합니다.", - "create.ponder.encased_fluid_pipe.text_3": "이 파이프는 이제 나중에 추가된 블록에 영향받지 않습니다.", - - "create.ponder.fan_direction.header": "선풍기의 공기흐름", - "create.ponder.fan_direction.text_1": "선풍기는 동력을 이용해 바람을 만들어냅니다.", - "create.ponder.fan_direction.text_2": "바람의 세기와 방향, 거리는 동력에 따라 달라집니다.", - - "create.ponder.fan_processing.header": "선풍기로 아이템 가공하기", - "create.ponder.fan_processing.text_1": "바람이 용암을 통과하면, 공기가 뜨거워집니다.", - "create.ponder.fan_processing.text_2": "바람이 지나가는 자리의 아이템은 구워집니다.", - "create.ponder.fan_processing.text_3": "음식은 불타 없어집니다.", - "create.ponder.fan_processing.text_4": "대신, 불을 이용하면 음식을 굽습니다.", - "create.ponder.fan_processing.text_5": "물을 통과하는 바람을 통해 세척할 수 있습니다.", - "create.ponder.fan_processing.text_6": "이를 통해 새로운 가공을 할 수 있습니다.", - "create.ponder.fan_processing.text_7": "선풍기의 속도는 가공 속도와 관련이 없습니다!", - "create.ponder.fan_processing.text_8": "선풍기 가공은 벨트나 아이템 거치대의 아이템에도 적용됩니다.", - - "create.ponder.fluid_pipe_flow.header": "파이프로 액체 옮기기", - "create.ponder.fluid_pipe_flow.text_1": "파이프는 한 종류의 액체만 옮깁니다.", - "create.ponder.fluid_pipe_flow.text_2": "렌치를 이용하여 직선 파이프에 창문을 달 수 있습니다.", - "create.ponder.fluid_pipe_flow.text_3": "창문이 있는 파이프는 옆에 있는 파이프와 연결되지 않습니다.", - "create.ponder.fluid_pipe_flow.text_4": "펌프를 이용하면 파이프로 액체를 옮길 수 있습니다.", - "create.ponder.fluid_pipe_flow.text_5": "처음엔 액체가 빠지지 않습니다.", - "create.ponder.fluid_pipe_flow.text_6": "액체 흐름이 이어지면, 시작 탱크에서 끝 탱크로 액체가 본격적으로 이동합니다.", - "create.ponder.fluid_pipe_flow.text_7": "이렇기 때문에, 파이프는 실질적으로 아무런 액체도 담지 않습니다.", - - "create.ponder.fluid_pipe_interaction.header": "액체 용기를 비우고 채우기", - "create.ponder.fluid_pipe_interaction.text_1": "파이프의 끝은 다양한 블록과 상호작용할 수 있습니다.", - "create.ponder.fluid_pipe_interaction.text_2": "액체를 담을 수 있는 모든 블록은 비우거나 채울 수 있습니다.", - "create.ponder.fluid_pipe_interaction.text_3": "끝 부분에 있는 액체의 원천도 흡수할 수 있으며...", - "create.ponder.fluid_pipe_interaction.text_4": "...비어있는 곳에 액체를 배출할 수도 있습니다.", - "create.ponder.fluid_pipe_interaction.text_5": "다양한 다른 블록에서도 액체를 뽑아낼 수도 있습니다.", - - "create.ponder.fluid_tank_sizes.header": "액체 탱크의 크기", - "create.ponder.fluid_tank_sizes.text_1": "액체 탱크는 여러개 연결하여 용량을 늘릴 수 있습니다.", - "create.ponder.fluid_tank_sizes.text_2": "밑면 너비는 3블록까지 늘릴 수 있습니다.", - "create.ponder.fluid_tank_sizes.text_3": "높이는 32블록까지 가능합니다.", - "create.ponder.fluid_tank_sizes.text_4": "렌치를 이용해 탱크의 창문을 닫을 수 있습니다.", - - "create.ponder.fluid_tank_storage.header": "탱크에 액체 저장하기", - "create.ponder.fluid_tank_storage.text_1": "탱크는 많은 양의 액체를 저장합니다.", - "create.ponder.fluid_tank_storage.text_2": "어느 쪽에서나 파이프로 액체를 넣고 빼낼 수 있습니다.", - "create.ponder.fluid_tank_storage.text_3": "담긴 액체의 양은 비교기로 측정할 수 있습니다.", - "create.ponder.fluid_tank_storage.text_4": "그러나 서바이벌 모드에서는 액체를 직접 빼내고 넣을 순 없습니다.", - "create.ponder.fluid_tank_storage.text_5": "대야, 아이템 배수구, 주입기를 통해 액체를 빼내거나 채울 수 있습니다.", - - "create.ponder.funnel_compat.header": "퍼널 호환성", - "create.ponder.funnel_compat.text_1": "퍼널은 다른 장치들 위에 설치할 수 있습니다.", - "create.ponder.funnel_compat.text_2": "세로 톱", - "create.ponder.funnel_compat.text_3": "아이템 거치대", - "create.ponder.funnel_compat.text_4": "아이템 배수구", - - "create.ponder.funnel_direction.header": "수송 방향", - "create.ponder.funnel_direction.text_1": "설치하면, 보관함에서 아이템을 빼냅니다.", - "create.ponder.funnel_direction.text_2": "웅크리면서 설치하면, 아이템을 가져갑니다.", - "create.ponder.funnel_direction.text_3": "렌치를 이용해 설치 이후에도 설정을 변경할 수 있습니다.", - "create.ponder.funnel_direction.text_4": "다른 면에 설치해도 같은 규칙을 따릅니다.", - "create.ponder.funnel_direction.text_5": "벨트 위의 퍼널는 벨트의 움직임에 따라 아이템을 빼내거나 가져갑니다.", - - "create.ponder.funnel_intro.header": "퍼널 사용하기", - "create.ponder.funnel_intro.text_1": "퍼널는 보관함에서 아이템을 옮기거나 빼낼 때 유용합니다.", - - "create.ponder.funnel_redstone.header": "레드스톤 신호", - "create.ponder.funnel_redstone.text_1": "레드스톤 신호를 받으면 동작을 멈춥니다.", - - "create.ponder.funnel_transfer.header": "직접 수송", - "create.ponder.funnel_transfer.text_1": "퍼널는 아이템을 보관함에서 다른 보관함로 옮깁니다.", - "create.ponder.funnel_transfer.text_2": "슈트나 스마트 슈트가 이런 목적에 더 적합합니다.", - "create.ponder.funnel_transfer.text_3": "수평 방향으로는 벨트가 적합합니다.", - - "create.ponder.gantry_carriage.header": "갠트리 운반대 사용하기", - "create.ponder.gantry_carriage.text_1": "갠트리 운반대는 갠트리 축 위에서 움직입니다.", - "create.ponder.gantry_carriage.text_2": "갠트리 장치는 부착된 블록들을 움직입니다.", - - "create.ponder.gantry_cascaded.header": "계단식 갠트리", - "create.ponder.gantry_cascaded.text_1": "갠트리 운반대에 접착제 없이 갠트리 축을 붙일 수 있습니다.", - "create.ponder.gantry_cascaded.text_2": "움직이는 축 위의 운반대에도 적용됩니다.", - "create.ponder.gantry_cascaded.text_3": "아렇게 갠트리 시스템은 여러 축으로 이어나갈 수 있습니다.", - - "create.ponder.gantry_direction.header": "갠트리 동작 방향", - "create.ponder.gantry_direction.text_1": "갠트리 축은 서로 반대되게 설치할 수 있습니다.", - "create.ponder.gantry_direction.text_2": "운반대의 이동 방향은 축의 방향을 따릅니다.", - "create.ponder.gantry_direction.text_3": "축의 회전방향도 마찬가지입니다.", - "create.ponder.gantry_direction.text_4": "운반대 축의 회전에도 적용됩니다.", - - "create.ponder.gantry_redstone.header": "갠트리 동력 전달", - "create.ponder.gantry_redstone.text_1": "레드스톤 신호를 받은 갠트리 축은 운반대를 멈춤니다.", - "create.ponder.gantry_redstone.text_2": "대신, 동력은 운반대의 축에게 이어집니다.", - - "create.ponder.gantry_shaft.header": "갠트리 축 사용하기", - "create.ponder.gantry_shaft.text_1": "갠트리 축은 갠트리 장치에 필요합니다. 갠트리 운반대가 축을 따라 움직입니다.", - "create.ponder.gantry_shaft.text_2": "갠트리 장치는 부착된 블록들을 움직입니다.", - - "create.ponder.gearbox.header": "기어박스를 이용해 동력 전달하기", - "create.ponder.gearbox.text_1": "회전축을 변경하는 일은 쉽게 귀찮아집니다.", - "create.ponder.gearbox.text_2": "기어박스는 그런 문제를 쉽게 해결합니다.", - "create.ponder.gearbox.text_3": "모서리 축들은 서로 다른 방향으로 돌아갑니다.", - "create.ponder.gearbox.text_4": "반대편 축은 거꾸로 돌아갑니다.", - - "create.ponder.gearshift.header": "기어쉬프트를 이용해 동력 조절하기", - "create.ponder.gearshift.text_1": "기어쉬프트는 한 줄로 동력을 전달합니다.", - "create.ponder.gearshift.text_2": "레드스톤 신호를 받으면, 회전을 반전시킵니다.", - - "create.ponder.hand_crank.header": "핸드 크랭크로 동력 생산하기", - "create.ponder.hand_crank.text_1": "핸드 크랭크는 플레이어가 직접 동력을 생산하는 장치입니다.", - "create.ponder.hand_crank.text_2": "우클릭하면 시계 반대방향으로 회전합니다.", - "create.ponder.hand_crank.text_3": "동력 속도는 생각보다 빠릅니다.", - "create.ponder.hand_crank.text_4": "웅크리고 우클릭하면 시계 방향으로 회전합니다.", - - "create.ponder.hose_pulley.header": "호스 도르래로 액체 채우고 비우기", - "create.ponder.hose_pulley.text_1": "호스 도르래는 많은 양의 액체를 채우거나 비울 수 있습니다.", - "create.ponder.hose_pulley.text_2": "동력을 전달하여 호스의 높이를 정합니다.", - "create.ponder.hose_pulley.text_3": "동력 방향이 반전되면 호스는 올라갑니다.", - "create.ponder.hose_pulley.text_4": "반대쪽에는 파이프를 연결할 수 있습니다.", - "create.ponder.hose_pulley.text_5": "연결된 파이프에서 호스로 전달하여 액체를 채우거나...", - "create.ponder.hose_pulley.text_6": "...반대 방향으로 방향을 바꿔 액체를 비울 수 있습니다.", - "create.ponder.hose_pulley.text_7": "호스의 채우거나 비우는 속도는 펌프 속도에 기반합니다.", - - "create.ponder.hose_pulley_infinite.header": "매우 많은 양의 액체를 채우고 비우기", - "create.ponder.hose_pulley_infinite.text_1": "넓은 바다에서 호스 도르래를 작동시키면...", - "create.ponder.hose_pulley_infinite.text_2": "...물 블록을 없애거나 추가하지 않고 액체를 얻거나 버릴 수 있습니다.", - "create.ponder.hose_pulley_infinite.text_3": "파이프로 이런 도르래에서 무한한 액체를 얻을 수 있습니다.", - - "create.ponder.hose_pulley_level.header": "호스 도르래의 채우고 비우는 기준", - "create.ponder.hose_pulley_level.text_1": "호스가 완전히 올라가 있을 때, 도르래는 작동하지 않습니다.", - "create.ponder.hose_pulley_level.text_2": "맨 위부터 비웁니다.", - "create.ponder.hose_pulley_level.text_3": "호스 끝부분 아래의 액체는 그대로 남습니다.", - "create.ponder.hose_pulley_level.text_4": "맨 아래부터 채웁니다.", - "create.ponder.hose_pulley_level.text_5": "호스 끝부분 위는 채우지 않습니다.", - - "create.ponder.item_drain.header": "아이템 배수구로 액체 비우기", - "create.ponder.item_drain.text_1": "배수구는 아이템에서 액체를 비웁니다.", - "create.ponder.item_drain.text_2": "우클릭하여 손에 든 아이템에서 액체를 붓습니다.", - "create.ponder.item_drain.text_3": "아이템이 옆에서 들어온다면...", - "create.ponder.item_drain.text_4": "...아이템은 굴라가며 담긴 액체를 비웁니다.", - "create.ponder.item_drain.text_5": "배수구 탱크에 있는 액체는 파이프로 옮길 수 있습니다.", - - "create.ponder.item_vault_sizes.header": "아이템 금고의 크기", - "create.ponder.item_vault_sizes.text_1": "아이템 금고를 여러개 연결하여 총량을 늘릴 수 있습니다.", - "create.ponder.item_vault_sizes.text_2": "최대 너비는 3 블록이고...", - "create.ponder.item_vault_sizes.text_3": "...길이는 너비의 3배까지 늘릴 수 있습니다.", - - "create.ponder.item_vault_storage.header": "금고에 아이템 보관하기", - "create.ponder.item_vault_storage.text_1": "아이템 금고는 많은 아이템을 보관할 수 있습니다.", - "create.ponder.item_vault_storage.text_2": "하지만, 플레이어가 직접 꺼내거나 보관할 수는 없습니다.", - "create.ponder.item_vault_storage.text_3": "아이템을 수송할 수 있는 모든 부품은 아이템을 넣거나...", - "create.ponder.item_vault_storage.text_4": "...금고에서 아이템을 빼낼 수 있습니다", - - "create.ponder.large_cogwheel.header": "큰 톱니바퀴로 동력 전달하기", - "create.ponder.large_cogwheel.text_1": "큰 톱니바퀴는 수직으로 서로 맞물립니다.", - "create.ponder.large_cogwheel.text_2": "이는 다른 축으로 동력을 전달하는데 도움이 됩니다.", - - "create.ponder.linear_chassis_attachment.header": "직선 섀시를 이용해 블록 붙이기", - "create.ponder.linear_chassis_attachment.text_1": "직선 섀시의 열린 면은 접착할 수 있습니다.", - "create.ponder.linear_chassis_attachment.text_2": "다시 클릭하면 다른 면도 접착할 수 있게 만듭니다.", - "create.ponder.linear_chassis_attachment.text_3": "빈 손으로 웅크리고 우클릭하여 접착제를 없앨 수 있습니다.", - "create.ponder.linear_chassis_attachment.text_4": "직선 섀시의 접착면은 접착면 앞에 있는 블록들을 연결합니다.", - "create.ponder.linear_chassis_attachment.text_5": "렌치로 이용해 섀시의 접착 거리를 조절할 수 있습니다.", - "create.ponder.linear_chassis_attachment.text_6": "[CTRL]키를 누르고 스크롤하면 연결된 모든 섀시의 거리를 조절할 수 있습니다.", - "create.ponder.linear_chassis_attachment.text_7": "다른 면에 블록을 붙이려면 접착제가 필요합니다.", - "create.ponder.linear_chassis_attachment.text_8": "이런 원리를 통해 구조물이 장치로써 움직일 수 있게 됩니다.", - - "create.ponder.linear_chassis_group.header": "여러 직선 섀시 움직이기", - "create.ponder.linear_chassis_group.text_1": "직선 섀시는 다른 직선 섀시와 연결될 수 있습니다.", - "create.ponder.linear_chassis_group.text_2": "하나가 움직이면, 다른 섀시도 같이 움직입니다.", - "create.ponder.linear_chassis_group.text_3": "다른 종류의 섀시, 다른 면을 바라보는 섀시는 붙지 않습니다.", - - "create.ponder.mechanical_arm.header": "기계 팔 설치하기", - "create.ponder.mechanical_arm.text_1": "기계 팔은 설치되기 전, 입력부와 출력부를 지정해야 합니다.", - "create.ponder.mechanical_arm.text_2": "우클릭으로 보관함을 가진 블록을 대상으로 지정합니다.", - "create.ponder.mechanical_arm.text_3": "다시 우클릭하여 입력부(파랑) 출력부(주황)을 설정합니다.", - "create.ponder.mechanical_arm.text_4": "좌클릭하여 대상 선택을 해제합니다.", - "create.ponder.mechanical_arm.text_5": "설치된 기계 팔은 이전에 선택된 블록들을 대상으로 정합니다.", - "create.ponder.mechanical_arm.text_6": "거리안에 있다면 여러 블록을 지정할 수 있습니다.", - "create.ponder.mechanical_arm.text_7": "하지만 모든 보관함을 지닌 블록이 지정되지는 않습니다.", - "create.ponder.mechanical_arm.text_8": "퍼널와 아이템 거치대가 이런 문제를 해결할 수 있습니다.", - - "create.ponder.mechanical_arm_filtering.header": "기계 팔 필터링", - "create.ponder.mechanical_arm_filtering.text_1": "입력부", - "create.ponder.mechanical_arm_filtering.text_2": "출력부", - "create.ponder.mechanical_arm_filtering.text_3": "때때로 기계 팔이 필터에 맞추어 동작해야할 때가 있습니다.", - "create.ponder.mechanical_arm_filtering.text_4": "하지만 기계 팔자체에서 필터 기능을 지원하지는 않습니다.", - "create.ponder.mechanical_arm_filtering.text_5": "대신, 황동 퍼널의 필터는 기계 팔의 필터역할을 합니다.", - "create.ponder.mechanical_arm_filtering.text_6": "기계 팔은 필터에 맞게 적당한 양만 가져가는 똑똑한 친구입니다.", - - "create.ponder.mechanical_arm_modes.header": "기계 팔의 분배 설정", - "create.ponder.mechanical_arm_modes.text_1": "입력부", - "create.ponder.mechanical_arm_modes.text_2": "출력부", - "create.ponder.mechanical_arm_modes.text_3": "기계 팔이 여러 곳에 아이템을 전달해야 한다면...", - "create.ponder.mechanical_arm_modes.text_4": "...현재 분배 설정에 따라 행동합니다.", - "create.ponder.mechanical_arm_modes.text_5": "렌치로 스크롤하여 어떻게 분배할지 설정하세요.", - "create.ponder.mechanical_arm_modes.text_6": "'순서대로 옮김'은 가능한 곳을 순환하며 아이템을 분배합니다.", - "create.ponder.mechanical_arm_modes.text_7": "어느 한 곳이 더 전달받을 수 없다면, 그 곳은 넘어갑니다.", - "create.ponder.mechanical_arm_modes.text_8": "[돌아가며 처리(강제적)]은 전달할 곳을 절대 넘어가지 않고, 공간이 남을 때까지 기다립니다.", - "create.ponder.mechanical_arm_modes.text_9": "[설정 순서 우선시]은 기계 팔을 설치할 때 설정한 곳 순서대로 아이템을 전달합니다.", - - "create.ponder.mechanical_arm_redstone.header": "기계 팔과 레드스톤", - "create.ponder.mechanical_arm_redstone.text_1": "레드스톤 신호를 받으면, 기계 팔은 작동을 멈춥니다.", - "create.ponder.mechanical_arm_redstone.text_2": "작동을 멈추기 전에, 기계 팔은 입력된 행동을 마무리합니다.", - "create.ponder.mechanical_arm_redstone.text_3": "따라서 부정 펄스는 한 번만 작동하게 합니다.", - - "create.ponder.mechanical_bearing.header": "베어링으로 구조물 옮기기", - "create.ponder.mechanical_bearing.text_1": "베어링은 앞에 있는 블록을 부착시킵니다.", - "create.ponder.mechanical_bearing.text_2": "동력을 받으면, 블록들은 회전하는 구조물로 변합니다.", - - "create.ponder.mechanical_crafter.header": "조합기 설치하기", - "create.ponder.mechanical_crafter.text_1": "다수의 조합기로 모든 조합을 자동화할 수 있습니다.", - "create.ponder.mechanical_crafter.text_2": "렌치를 이용해, 조합기의 경로를 변경할 수 있습니다.", - "create.ponder.mechanical_crafter.text_3": "올바른 조합을 위해서는, 모든 조합기의 경로가 외부로 나가는 한 길로 이어져야합니다.", - "create.ponder.mechanical_crafter.text_4": "결과물은 경로 끝 보관함에 보내집니다.", - "create.ponder.mechanical_crafter.text_5": "조합기는 동력이 요구됩니다.", - "create.ponder.mechanical_crafter.text_6": "앞면을 우클릭해서 직접 아이템을 넣습니다.", - "create.ponder.mechanical_crafter.text_7": "모든 면이 아이템을 가지고 있다면, 조합이 시작됩니다.", - "create.ponder.mechanical_crafter.text_8": "모든 면이 아이템을 가지고 있지 않아도, 레드스톤 신호로 조합을 강제 시작할 수 있습니다.", - - "create.ponder.mechanical_crafter_connect.header": "조합기에 아이템 넣기", - "create.ponder.mechanical_crafter_connect.text_1": "조합기에 아이템을 자동으로 넣을 수 있습니다.", - "create.ponder.mechanical_crafter_connect.text_2": "후면에 렌치를 이용해 조합기 보관함을 연결할 수 있습니다.", - "create.ponder.mechanical_crafter_connect.text_3": "이제 모든 조합기가 한 곳에서 아이템을 받습니다.", - - "create.ponder.mechanical_crafter_covers.header": "조합기 슬롯 덮기", - "create.ponder.mechanical_crafter_covers.text_1": "몇몇 조합은 빈 공간을 채워줄 조합기가 필요합니다.", - "create.ponder.mechanical_crafter_covers.text_2": "슬롯 덮개를 이용해, 조합기에 빈 공간을 만들 수 있습니다.", - "create.ponder.mechanical_crafter_covers.text_3": "렌치를 이용해 보관함을 연결해도 덮개가 있는 조합기에는 아이템이 들어오지 않습니다.", - - "create.ponder.mechanical_drill.header": "드릴을 이용해 블록 부수기", - "create.ponder.mechanical_drill.text_1": "동력을 받으면, 드릴은 앞에 있는 블록을 파괴합니다.", - "create.ponder.mechanical_drill.text_2": "채굴 속도는 동력 속도에 비례합니다.", - - "create.ponder.mechanical_drill_contraption.header": "구조물에서의 드릴", - "create.ponder.mechanical_drill_contraption.text_1": "드릴이 움직이는 구조물의 일부면...", - "create.ponder.mechanical_drill_contraption.text_2": "...드릴이 부딪히는 블록을 파괴합니다.", - - "create.ponder.mechanical_harvester.header": "구조물에서의 수확기", - "create.ponder.mechanical_harvester.text_1": "수확기가 움직이는 구조물의 일부면...", - "create.ponder.mechanical_harvester.text_2": "...지나가는 길에 있는 작물을 수확하고, 성장 수치를 초기화합니다.", - - "create.ponder.mechanical_mixer.header": "믹서로 아이템 가공하기", - "create.ponder.mechanical_mixer.text_1": "믹서와 대야를 이용해 몇몇 조합을 자동화할 수 있습니다.", - "create.ponder.mechanical_mixer.text_2": "가능한 조합법은 어느 무형 조합법이나 가능하며, 모드에서 추가된 조합법도 있습니다.", - "create.ponder.mechanical_mixer.text_3": "몇몇 조합법은 블레이즈 버너의 열을 요구합니다.", - "create.ponder.mechanical_mixer.text_4": "필터 슬롯을 이용해 조합법이 겹치는 것을 방지합니다.", - - "create.ponder.mechanical_piston.header": "기계식 피스톤으로 구조물 옮기기", - "create.ponder.mechanical_piston.text_1": "기계식 피스톤은 블록들을 앞으로 움직입니다.", - "create.ponder.mechanical_piston.text_2": "속도와 방향은 들어오는 동력에 기반합니다.", - "create.ponder.mechanical_piston.text_3": "끈끈이 기계식 피스톤은 블록들을 다시 끌어옵니다.", - - "create.ponder.mechanical_piston_modes.header": "기계식 피스톤의 이동 설정", - "create.ponder.mechanical_piston_modes.text_1": "피스톤이 움직임을 멈추면, 움직인 구조물은 블록으로 바뀝니다.", - "create.ponder.mechanical_piston_modes.text_2": "블록으로 바뀌지 않게 하거나, 시작지점에서만 바뀌도록 설정할 수 있습니다.", - - "create.ponder.mechanical_plough.header": "구조물에서의 쟁기", - "create.ponder.mechanical_plough.text_1": "쟁기가 움직이는 구조물의 일부면...", - "create.ponder.mechanical_plough.text_2": "...히트박스가 없는 블록을 파괴합니다.", - "create.ponder.mechanical_plough.text_3": "또, 쟁기는 경작지를 만들 수 있습니다.", - "create.ponder.mechanical_plough.text_4": "...그리고 엔티티를 피해없이 날려보낼 수도 있습니다!", - - "create.ponder.mechanical_press.header": "압착기로 아이템 가공하기", - "create.ponder.mechanical_press.text_1": "압착기는 아래에 놓인 아이템을 가공할 수 있습니다.", - "create.ponder.mechanical_press.text_2": "가공할 아이템은 압착기 아래에 떨구거나 아이템 거치대에 올려두어야 합니다.", - "create.ponder.mechanical_press.text_3": "아이템이 벨트에 있으면...", - "create.ponder.mechanical_press.text_4": "...압착기가 알아서 아이템 이동을 멈추고 가공합니다.", - - "create.ponder.mechanical_press_compacting.header": "압착기로 아이템 압축하기", - "create.ponder.mechanical_press_compacting.text_1": "대야와 함께 사용해서 아이템을 압축할 수 있습니다.", - "create.ponder.mechanical_press_compacting.text_2": "가능한 조합법은 2x2 / 3x3 조합법을 포함하고, 모드에서 추가된 조합법도 있습니다.", - "create.ponder.mechanical_press_compacting.text_3": "몇몇 조합법은 블레이즈 버너의 열을 요구합니다.", - "create.ponder.mechanical_press_compacting.text_4": "필터 슬롯을 이용해 조합법이 겹치는 것을 방지합니다.", - - "create.ponder.mechanical_pump_flow.header": "펌프를 이용해 액체 옮기기", - "create.ponder.mechanical_pump_flow.text_1": "펌프는 연결된 파이프속 흐름을 관리합니다.", - "create.ponder.mechanical_pump_flow.text_2": "동력을 전달받으면 화살표가 흐름의 방향을 알려줍니다.", - "create.ponder.mechanical_pump_flow.text_3": "화살표 뒤의 파이프는 액체를 뽑아내고...", - "create.ponder.mechanical_pump_flow.text_4": "...화살표 앞의 파이프는 액체를 밀어냅니다.", - "create.ponder.mechanical_pump_flow.text_5": "동력 방향을 반전시키면 흐름의 방향도 반전됩니다.", - "create.ponder.mechanical_pump_flow.text_6": "렌치로 펌프 방향 자체를 돌릴 수도 있습니다.", - - "create.ponder.mechanical_pump_speed.header": "펌프의 처리율", - "create.ponder.mechanical_pump_speed.text_1": "동력 속도와는 상관없이 펌프는 16블록 길이의 파이프까지 영향을 미칩니다.", - "create.ponder.mechanical_pump_speed.text_2": "동력 속도를 높이면 액체가 흐르는 속도가 높아지고...", - "create.ponder.mechanical_pump_speed.text_3": "...옮기는 액체의 양도 증가합니다.", - "create.ponder.mechanical_pump_speed.text_4": "펌프는 병렬로 설치할 수 있습니다.", - "create.ponder.mechanical_pump_speed.text_5": "펌프 방향을 바꾸어 흐름의 뱡향을 통일할 수 있습니다.", - - "create.ponder.mechanical_saw_breaker.header": "톱으로 나무 베기", - "create.ponder.mechanical_saw_breaker.text_1": "동력을 받으면 앞에 있는 나무를 벱니다.", - "create.ponder.mechanical_saw_breaker.text_2": "두꺼운 나무를 벨려면, 땅에 붙어있는 마지막 나무 블록을 파괴해야합니다.", - - "create.ponder.mechanical_saw_contraption.header": "구조물에서의 톱", - "create.ponder.mechanical_saw_contraption.text_1": "톱이 움직이는 구조물의 일부면...", - "create.ponder.mechanical_saw_contraption.text_2": "...부딪히는 모든 나무를 벱니다.", - - "create.ponder.mechanical_saw_processing.header": "톱으로 아이템 가공하기", - "create.ponder.mechanical_saw_processing.text_1": "위를 바라보는 톱은 다양한 아이템을 가공합니다.", - "create.ponder.mechanical_saw_processing.text_2": "가공되는 아이템은 언제나 동력의 반대로 움직입니다.", - "create.ponder.mechanical_saw_processing.text_3": "톱은 벨트와 연동이 가능합니다.", - "create.ponder.mechanical_saw_processing.text_4": "재료가 여러 결과물로 가공될 수 있을 때, 필터로 제한할 수 있습니다.", - "create.ponder.mechanical_saw_processing.text_5": "필터가 없다면 톱은 모든 결과물을 순서대로 만듭니다.", - - "create.ponder.millstone.header": "맷돌로 아이템 갈기", - "create.ponder.millstone.text_1": "맷돌은 아이템을 갈아버립니다!", - "create.ponder.millstone.text_2": "톱니바퀴를 옆에 설치하여 돌릴 수 있습니다.", - "create.ponder.millstone.text_3": "윗면으로 아이템을 투입하세요.", - "create.ponder.millstone.text_4": "시간이 지난 후, 우클릭으로 결과물을 얻을 수 있습니다.", - "create.ponder.millstone.text_5": "결과물은 자동으로 빼낼 수 있습니다.", - - "create.ponder.nixie_tube.header": "닉시관 사용하기", - "create.ponder.nixie_tube.text_1": "레드스톤 신호를 받으면, 닉시관은 레드스톤 신호 세기를 나타냅니다.", - "create.ponder.nixie_tube.text_2": "이름표를 사용하여 원하는 글자를 나타낼 수도 있습니다.", - "create.ponder.nixie_tube.text_3": "염료를 들고 우클릭하여 색을 바꿀 수 있습니다.", - - "create.ponder.piston_pole.header": "피스톤 연장 축", - "create.ponder.piston_pole.text_1": "연장 축이 없으면, 기계식 피스톤은 움직일 수 없습니다.", - "create.ponder.piston_pole.text_2": "연장 축의 수가 곧 피스톤이 연장할 수 있는 거리입니다.", - - "create.ponder.portable_fluid_interface.header": "구조물 장치의 액체 교환", - "create.ponder.portable_fluid_interface.text_1": "움직이는 구조물의 액체 탱크는 파이프와 연결되지 않습니다.", - "create.ponder.portable_fluid_interface.text_2": "액체 인터페이스는 장치를 멈추지 않아도 탱크와 상호작용할 수 있습니다.", - "create.ponder.portable_fluid_interface.text_3": "두 번째 인터페이스를 1~2 블록 띄우고 설치하세요.", - "create.ponder.portable_fluid_interface.text_4": "서로를 마주칠 때마다, 접속을 시도합니다.", - "create.ponder.portable_fluid_interface.text_5": "접속한 상태에서, 블록 상태의 인터페이스는 장치의 모든 탱크와 동일합니다.", - "create.ponder.portable_fluid_interface.text_6": "액체를 넣을 수도 있고...", - "create.ponder.portable_fluid_interface.text_7": "...장치에서 액체를 뺄 수도 있습니다.", - "create.ponder.portable_fluid_interface.text_8": "일정 시간동안 액체가 교환되지 않으면, 장치는 움직입니다.", - - "create.ponder.portable_storage_interface.header": "구조물 장치의 아이템 교환", - "create.ponder.portable_storage_interface.text_1": "움직이는 장치의 보관함은 플레이어가 열 수 없습니다.", - "create.ponder.portable_storage_interface.text_2": "아이템 인터페이스는 장치를 멈추지 않아도 장치 보관함과 상호작용할 수 있습니다.", - "create.ponder.portable_storage_interface.text_3": "두 번째 인터페이스를 1~2 블록 띄우고 설치하세요.", - "create.ponder.portable_storage_interface.text_4": "서로를 마주칠 때마다, 접속을 시도합니다.", - "create.ponder.portable_storage_interface.text_5": "접속한 상태에서, 블록 상태의 인터페이스는 장치의 모든 보관함과 동일합니다.", - "create.ponder.portable_storage_interface.text_6": "아이템을 넣을 수도 있고...", - "create.ponder.portable_storage_interface.text_7": "...장치에서 아이템을 뺄 수도 있습니다.", - "create.ponder.portable_storage_interface.text_8": "일정 시간동안 아이템이 교환되지 않으면, 장치는 움직입니다.", - - "create.ponder.portable_storage_interface_redstone.header": "레드스톤 설정", - "create.ponder.portable_storage_interface_redstone.text_1": "레드스톤 신호를 받으면 인터페이스가 작동하지 않습니다.", - - "create.ponder.powered_latch.header": "레드스톤 걸쇠 사용하기", - "create.ponder.powered_latch.text_1": "레드스톤 걸쇠는 설정 가능한 레버입니다.", - "create.ponder.powered_latch.text_2": "뒤에서 오는 신호는 걸쇠 신호를 키고...", - "create.ponder.powered_latch.text_3": "...옆에서 오는 신호는 걸쇠 신호를 끕니다.", - "create.ponder.powered_latch.text_4": "레드스톤 걸쇠는 직접 끄고 킬 수도 있습니다.", - - "create.ponder.powered_toggle_latch.header": "레드스톤 토글 걸쇠 사용하기", - "create.ponder.powered_toggle_latch.text_1": "레드스톤 토글 걸쇠는 설정 가능한 레버입니다.", - "create.ponder.powered_toggle_latch.text_2": "뒤에서 오는 신호는 걸쇠의 신호를 킵니다.", - "create.ponder.powered_toggle_latch.text_3": "혹은 끕니다.", - "create.ponder.powered_toggle_latch.text_4": "레드스톤 토글 걸쇠는 직접 끄고 킬 수도 있습니다.", - - "create.ponder.pulse_extender.header": "펄스 연장기로 신호 조절하기", - "create.ponder.pulse_extender.text_1": "펄스 연장기는 지나가는 신호의 길이를 늘릴 수 있습니다.", - "create.ponder.pulse_extender.text_2": "연장기는 짧은 딜레이 후에 작동하고...", - "create.ponder.pulse_extender.text_3": "...설정된 시간 이후에 꺼집니다.", - "create.ponder.pulse_extender.text_4": "마우스 휠을 이용하여 연장 시간을 조절할 수 있습니다.", - "create.ponder.pulse_extender.text_5": "최대 신호 연장 시간은 30분입니다", - - "create.ponder.pulse_repeater.header": "펄스 중계기 사용하기", - "create.ponder.pulse_repeater.text_1": "펄스 중계기는 모든 레드스톤 신호를 1틱 신호로 바꿉니다.", - "create.ponder.pulse_repeater.text_2": "마우스 휠을 이용하여 딜레이 시간을 조절할 수 있습니다.", - "create.ponder.pulse_repeater.text_3": "최대 신호 딜레이 시간은 30분입니다", - - "create.ponder.radial_chassis.header": "원형 섀시를 이용해 블록 붙이기", - "create.ponder.radial_chassis.text_1": "원형 섀시는 다른 원형 섀시와 이어집니다.", - "create.ponder.radial_chassis.text_2": "하나가 움직이면, 다른 섀시도 같이 움직입니다.", - "create.ponder.radial_chassis.text_3": "원형 섀시의 옆면은 접착할 수 있습니다.", - "create.ponder.radial_chassis.text_4": "한번 더 클릭하여 모든 면을 접착면으로 만들 수 있습니다.", - "create.ponder.radial_chassis.text_5": "빈손으로 웅크리고 우클릭하여 접착제를 없앨 수 있습니다.", - "create.ponder.radial_chassis.text_6": "접착면에 블록이 있으면...", - "create.ponder.radial_chassis.text_7": "...해당 층 반지름 안에 있는 모든 블록을 연결합니다.", - "create.ponder.radial_chassis.text_8": "렌치룰 이용하여, 섀시의 부착 반지름을 조절할 수 있습니다.", - "create.ponder.radial_chassis.text_9": "접착면 반지름 밖의 블록은 붙지 않습니다.", - - "create.ponder.redstone_contact.header": "동형 감지기", - "create.ponder.redstone_contact.text_1": "서로 마주보는 동형 감지기는 레드스톤 신호를 발생시킵니다.", - "create.ponder.redstone_contact.text_2": "어느 한쪽이 움직이는 장치의 일부라도 동일하게 작동합니다.", - - "create.ponder.redstone_link.header": "레드스톤 링크 사용하기", - "create.ponder.redstone_link.text_1": "레드스톤 링크는 레드스톤 신호를 무선으로 전달합니다.", - "create.ponder.redstone_link.text_2": "웅크리면서 우클릭하여 신호를 수신하게 만듭니다.", - "create.ponder.redstone_link.text_3": "렌치로 우클릭도 같은 기능을 합니다.", - "create.ponder.redstone_link.text_4": "수신기는 128블록이내의 발신기 레드스톤 신호 세기를 전달합니다.", - "create.ponder.redstone_link.text_5": "두 슬롯에 아이템을 두어 주파수를 설정할 수 있습니다.", - "create.ponder.redstone_link.text_6": "맞는 주파수끼리만 레드스톤 링크가 작동합니다.", - - "create.ponder.rope_pulley.header": "밧줄 도르래로 구조물 옮기기", - "create.ponder.rope_pulley.text_1": "밧줄 도르래는 동력을 받으면 블록을 수직으로 옮깁니다.", - "create.ponder.rope_pulley.text_2": "방향과 속도는 들어오는 동력에 기반합니다.", - - "create.ponder.rope_pulley_attachment.header": "구조물로서의 밧줄 도르래", - "create.ponder.rope_pulley_attachment.text_1": "도르래가 장치에 의해 움직여지면...", - "create.ponder.rope_pulley_attachment.text_2": "...도르래에 딸린 구조물도 함께 움직입니다.", - "create.ponder.rope_pulley_attachment.text_3": "다만 도르래는 멈춰있을 때만 작동합니다.", - - "create.ponder.rope_pulley_modes.header": "밧줄 도르래의 이동 설정", - "create.ponder.rope_pulley_modes.text_1": "도르래가 움직임을 멈추면, 움직인 구조물은 블록으로 바뀝니다.", - "create.ponder.rope_pulley_modes.text_2": "블록으로 바뀌지 않게 하거나, 시작지점에서만 바뀌도록 설정할 수 있습니다.", - - "create.ponder.rose_quartz_lamp.header": "장밋빛 석영 조명", - "create.ponder.rose_quartz_lamp.text_1": "장밋빛 석영 조명은 레드스톤 신호를 받으면 켜집니다.", - "create.ponder.rose_quartz_lamp.text_2": "켜진 상태에서는 레드스톤 신호를 방출합니다.", - "create.ponder.rose_quartz_lamp.text_3": "여러 조명이 붙어있다면...", - "create.ponder.rose_quartz_lamp.text_4": "...신호를 받은 조명만 켜지고 나머지 조명은 꺼집니다.", - "create.ponder.rose_quartz_lamp.text_5": "비교기는 켜진 조명의 거리와 비례하여 신호를 방출합니다.", - "create.ponder.rose_quartz_lamp.text_6": "조명은 렌치로 끄고 켤 수도 있습니다.", - - "create.ponder.rotation_speed_controller.header": "회전 속도 컨트롤러 사용하기", - "create.ponder.rotation_speed_controller.text_1": "회전 속도 컨트롤러는 회전을 위 톱니바퀴로 회전을 전달합니다.", - "create.ponder.rotation_speed_controller.text_2": "스크롤하여 톱니바퀴에 전달되는 RPM을 조절합니다.", - - "create.ponder.sail.header": "날개를 이용해 풍차 조립하기", - "create.ponder.sail.text_1": "날개는 풍차를 만들기에 좋은 블록입니다.", - "create.ponder.sail.text_2": "강력 접착제나 섀시 없이 연결할 수 있습니다", - "create.ponder.sail.text_3": "염료로 우클릭하여 염색합니다.", - "create.ponder.sail.text_4": "가위로 우클릭하여 틀만 남길 수 있습니다.", - - "create.ponder.sail_frame.header": "날개 틀을 이용해 풍차 조립하기", - "create.ponder.sail_frame.text_1": "날개 틀은 풍차를 만들기에 좋은 블록입니다.", - "create.ponder.sail_frame.text_2": "강력 접착제나 섀시 없이 연결할 수 있습니다", - - "create.ponder.sequenced_gearshift.header": "순서화 전환기를 통한 회전 속도 제어", - "create.ponder.sequenced_gearshift.text_1": "순서화 전환기는 설정한 지시에 따라 회전됩니다.", - "create.ponder.sequenced_gearshift.text_2": "오른쪽 버튼을 누르면 설정 창이 열립니다.", - "create.ponder.sequenced_gearshift.text_3": "레드스톤 신호를 받으면 설정된 지시에 따라 회전하기 시작합니다.", - "create.ponder.sequenced_gearshift.text_4": "완료되면, 다음 레드스톤 신호를 기다립니다.", - "create.ponder.sequenced_gearshift.text_5": "레드스톤 비교기를 사용하면 현재 진행 상황을 알 수 있습니다.", - - "create.ponder.shaft.header": "축을 통한 동력 전달", - "create.ponder.shaft.text_1": "축은 일직선으로 회전을 전달합니다.", - - "create.ponder.shaft_casing.header": "축에 케이스 씌우기", - "create.ponder.shaft_casing.text_1": "황동 케이스나 안산암 케이스로 축을 장식할 수 있습니다.", - - "create.ponder.smart_chute.header": "스마트 슈트을 통한 아이템 필터", - "create.ponder.smart_chute.text_1": "스마트 슈트은 필터 기능이 있는 슈트입니다.", - "create.ponder.smart_chute.text_2": "필터 슬롯으로 아이템을 지정하여 원하는 아이템을 입출력할 수 있습니다.", - "create.ponder.smart_chute.text_3": "스크롤하여 한 번에 내보내는 아이템의 양을 조절합니다.", - "create.ponder.smart_chute.text_4": "레드스톤 신호를 받으면 작동을 멈춥니다.", - - "create.ponder.smart_pipe.header": "스마트 파이프를 통한 액체 필터", - "create.ponder.smart_pipe.text_1": "스마트 파이프는 필터 기능이 있는 파이프입니다.", - "create.ponder.smart_pipe.text_2": "비울 곳에다 설치하면, 어떤 액체를 뽑아낼지 설정할 수 있습니다.", - "create.ponder.smart_pipe.text_3": "필터 슬롯에 원하는 액체가 담긴 용기를 우클릭하면 됩니다.", - "create.ponder.smart_pipe.text_4": "다른 곳에 설치하면, 스마트 파이프는 맞는 액체만 통과시킵니다.", - - "create.ponder.speedometer.header": "속도 계측기를 통한 정보 확인", - "create.ponder.speedometer.text_1": "속도 계측기는 연결된 장치의 속도를 표시합니다.", - "create.ponder.speedometer.text_2": "고글을 장착하면, 세부 정보를 확인할 수 있습니다.", - "create.ponder.speedometer.text_3": "속도 계측기의 측정값에 따라 비교기가 레드스톤 신호를 내보냅니다.", - - "create.ponder.spout_filling.header": "주입기로 아이템에 액체 채우기", - "create.ponder.spout_filling.text_1": "주입기는 아래있는 아이템을 액체를 채웁니다.", - "create.ponder.spout_filling.text_2": "주입기 탱크는 직접 건드릴 수 없습니다.", - "create.ponder.spout_filling.text_3": "대신, 파이프로 액체를 공급할 수는 있습니다.", - "create.ponder.spout_filling.text_4": "주입기 아래 아이템 거치대에 아이템을 놓아, 액체를 채울 수 있습니다.", - "create.ponder.spout_filling.text_5": "아이템이 벨트에 있으면...", - "create.ponder.spout_filling.text_6": "...주입기가 알아서 아이템 이동을 멈추고 가공합니다.", - - "create.ponder.stabilized_bearings.header": "베어링 안정화", - "create.ponder.stabilized_bearings.text_1": "베어링이 움직이는 구조물의 일부분이어도...", - "create.ponder.stabilized_bearings.text_2": "...방향이 유지됩니다.", - "create.ponder.stabilized_bearings.text_3": "베어링에 블록이 부착되어도...", - "create.ponder.stabilized_bearings.text_4": "...부착된 구조물의 방향이 유지됩니다.", - - "create.ponder.steam_engine.header": "증기 엔진 가동하기", - "create.ponder.steam_engine.text_1": "증기 엔진은 액체 탱크에 설치할 수 있습니다.", - "create.ponder.steam_engine.text_10": "레벨 4", - "create.ponder.steam_engine.text_11": "4기통", - "create.ponder.steam_engine.text_12": "레벨 8", - "create.ponder.steam_engine.text_13": "8기통", - "create.ponder.steam_engine.text_2": "엔진에 축을 우클릭하면 연결됩니다.", - "create.ponder.steam_engine.text_3": "충분한 열과 물, 보일러 크기가 준비되면...", - "create.ponder.steam_engine.text_4": "...엔진은 동력을 생산합니다.", - "create.ponder.steam_engine.text_5": "최소 탱크 4개가 있어야 작동합니다.", - "create.ponder.steam_engine.text_6": "블레이즈 버너를 사용하면 엔진이 더 빠르게 회전합니다", - "create.ponder.steam_engine.text_7": "더 많은 열, 물, 크기를 제공하면 엔진이 더 강력해집니다.", - "create.ponder.steam_engine.text_8": "보일러의 레벨은 엔지니어의 고글로 확인할 수 있습니다.", - "create.ponder.steam_engine.text_9": "레벨이 오를때마다, 추가된 엔진이 최대로 가동할 수 있습니다", - - "create.ponder.steam_whistle.header": "기적 장치 사용하기", - "create.ponder.steam_whistle.text_1": "기적 장치는 액체 탱크에 설치할 수 있습니다.", - "create.ponder.steam_whistle.text_2": "탱크가 충분한 열은 가지고 있을 때...", - "create.ponder.steam_whistle.text_3": "...기적 장치가 신호를 받으면 소리를 냅니다", - "create.ponder.steam_whistle.text_4": "장치를 더 붙이면 음이 낮아집니다", - "create.ponder.steam_whistle.text_5": "렌치로 옥타브를 변경할 수 있습니다", - "create.ponder.steam_whistle.text_6": "엔지니어의 고글로 기적 장치의 음계를 확인할 수 있습니다", - - "create.ponder.sticker.header": "부착기를 통한 블록 부착", - "create.ponder.sticker.text_1": "부착기는 레드스톤으로 제어할 수 있습니다.", - "create.ponder.sticker.text_2": "신호를 받으면, 부착기가 블록을 부착합니다.", - "create.ponder.sticker.text_3": "장치가 이동하면 부착된 블록도 같이 이동합니다.", - "create.ponder.sticker.text_4": "다시 한번 신호를 받으면, 블록이 부착되지 않습니다.", - - "create.ponder.stressometer.header": "피로도 계측기를 통한 동적 정보 확인", - "create.ponder.stressometer.text_1": "피로도 계측기는 연결된 장치의 현재 부하를 표시합니다.", - "create.ponder.stressometer.text_2": "고글을 장착하면, 세부 정보를 확인할 수 있습니다.", - "create.ponder.stressometer.text_3": "피로도 계측기의 측정값에 따라 비교기가 레드스톤 신호를 내보냅니다.", - - "create.ponder.super_glue.header": "강력 접착제로 블록 붙이기", - "create.ponder.super_glue.text_1": "강력 접착제는 블록들을 하나의 움직일 수 있는 구조물로 접착할 수 있습니다", - "create.ponder.super_glue.text_2": "양 끝점을 클릭하면 새로운 '접착' 영역을 생성합니다", - "create.ponder.super_glue.text_3": "영역을 제거하려면 접착제를 손에 든채로 좌클릭하세요", - "create.ponder.super_glue.text_4": "영역안의 블록들은 다같이 움직입니다", - "create.ponder.super_glue.text_5": "영역을 공유하는 블록들도 다같이 움직입니다", - "create.ponder.super_glue.text_6": "블록에 매달린 블록들은 접착제를 필요로하지 않습니다", - - "create.ponder.track_chunks.header": "언로드된 청크에서의 이동", - "create.ponder.track_chunks.text_1": "언로드된 청크에서도 선로는 작동합니다.", - "create.ponder.track_chunks.text_2": "기차는 이런 청크에서도 문제없이 이동할 수 있습니다.", - "create.ponder.track_chunks.text_3": "이 기차도 정거장이나 적신호에 정지합니다.", - "create.ponder.track_chunks.text_4": "그러나 드릴이나 다른 장치는 작동하지 않습니다.", - "create.ponder.track_chunks.text_5": "플레이어 주변으로 오면, 기차는 다시 나타납니다.", - - "create.ponder.track_observer.header": "기차 감지하기", - "create.ponder.track_observer.text_1": "선로를 선택하고 근처에 감지기를 설치하세요.", - "create.ponder.track_observer.text_2": "감지기는 해당 선로를 지나가는 기차를 감지합니다.", - "create.ponder.track_observer.text_3": "감지기에 필터를 적용하여 저장소를 감지할 수 있습니다.", - - "create.ponder.track_placement.header": "기차 선로 설치하기", - "create.ponder.track_placement.text_1": "기차 구조물을 위한 새로운 레일입니다.", - "create.ponder.track_placement.text_2": "여러 레일을 설치하려면, 기존 레일에 우클릭하세요.", - "create.ponder.track_placement.text_3": "그런 다음, 다른 곳에 설치하거나 연결할 선로를 선택하세요.", - "create.ponder.track_placement.text_4": "선로는 구부리거나 경사지게 설치할 수도 있습니다", - "create.ponder.track_placement.text_5": "연결할 때, 같은 각도에서는 동일하게 구부러진 선로가 설치됩니다.", - "create.ponder.track_placement.text_6": "달리기 버튼을 누른채 연결하면...", - "create.ponder.track_placement.text_7": "...가장 길게 구부러진 선로를 설치합니다.", - "create.ponder.track_placement.text_8": "다른 손에 있는 재료는 선로 아래에 자동으로 깔립니다.", - - "create.ponder.track_portal.header": "선로와 네더", - "create.ponder.track_portal.text_1": "네더 차원문을 향해 설치된 선로는...", - "create.ponder.track_portal.text_2": "...차원문을 넘어 동일한 선로를 생성합니다.", - "create.ponder.track_portal.text_3": "기차는 이제 선로를 통해 차원을 넘어갈 수 있습니다.", - - "create.ponder.train_assembly.header": "기차 조립하기", - "create.ponder.train_assembly.text_1": "선로를 선택하고 근처에 기차 정거장을 설치하세요.", - "create.ponder.train_assembly.text_10": "모든 기차는 기차 조종기가 필요합니다.", - "create.ponder.train_assembly.text_11": "조종기를 더 추가해서 정거장에서 다른 방향으로 출발할 수 있습니다.", - "create.ponder.train_assembly.text_12": "정거장 창을 열고 조립을 완료합니다.", - "create.ponder.train_assembly.text_13": "기차는 정거장에 있을 때만 해체할 수 있습니다.", - "create.ponder.train_assembly.text_14": "지도를 정거장에 사용하면 해당 위치에 표시를 남길 수 있습니다.", - "create.ponder.train_assembly.text_15": "조립된 기차는 렌치로 옮길 수 있습니다.", - "create.ponder.train_assembly.text_2": "정거장은 기차 노선의 분기점입니다.", - "create.ponder.train_assembly.text_3": "새로운 기차를 조립하려면, 창을 열고 조립 모드로 전환하세요.", - "create.ponder.train_assembly.text_4": "조립할 때는 다른 기차가 이 정거장에 정차하지 않습니다.", - "create.ponder.train_assembly.text_5": "선로에 기차 케이스를 설치하여 새로운 대차를 만드세요.", - "create.ponder.train_assembly.text_6": "선로를 우클릭하여 다른 대차 디자인으로 변경할 수 있습니다.", - "create.ponder.train_assembly.text_7": "강력 접착제로 블록을 붙여보세요.", - "create.ponder.train_assembly.text_8": "기차는 조립될 때 창고나 통에 연료가 있다면 더 빨리 이동합니다.", - "create.ponder.train_assembly.text_9": "금고에 있는 연료는 기차가 사용하지 않습니다.", - - "create.ponder.train_controls.header": "기차 조종하기", - "create.ponder.train_controls.text_1": "기차 조종기는 모든 기차 구조물에 필요합니다.", - "create.ponder.train_controls.text_2": "조립되었으면, 우클릭해서 운전을 시작합니다.", - "create.ponder.train_controls.text_3": "이동 조작키로 기차를 운전하세요.", - "create.ponder.train_controls.text_4": "마우스 휠로 최고 속도를 조절할 수 있습니다.", - "create.ponder.train_controls.text_5": "스페이스를 눌러 근처 정거장에 정차합니다.", - "create.ponder.train_controls.text_6": "기차는 정거장에 있을 때만 블록 상태로 해체할 수 있습니다.", - "create.ponder.train_controls.text_7": "기적 장치는 달리기 키로 작동시킬 수 있습니다.", - "create.ponder.train_controls.text_8": "웅크리거나 다시 우클릭하여 기차 운전을 그만둡니다.", - - "create.ponder.train_schedule.header": "기차 계획표 사용하기", - "create.ponder.train_schedule.text_1": "계획표를 사용해 다른 기관사를 고용할 수 있습니다.", - "create.ponder.train_schedule.text_2": "아이템을 들고 우클릭하면 창을 엽니다.", - "create.ponder.train_schedule.text_3": "계획을 설정한 뒤, 기관사에게 넘깁니다.", - "create.ponder.train_schedule.text_4": "기차 조종기 앞에 앉은 다른 몹이나 블레이즈 버너는 적절한 기관사입니다.", - "create.ponder.train_schedule.text_5": "끈에 묶인 동물들은 좌석에 쉽게 앉힐 수 있습니다.", - "create.ponder.train_schedule.text_6": "언제든지 기관사에게서 계획표를 가져올 수 있습니다.", - - "create.ponder.train_signal_placement.header": "기차 신호기 설치하기", - "create.ponder.train_signal_placement.text_1": "선로를 선택하고 근처에 기차 신호기를 설치하세요.", - "create.ponder.train_signal_placement.text_2": "신호기는 플레이어가 아닌 기관사가 조종하는 기차의 흐름을 조절합니다.", - "create.ponder.train_signal_placement.text_3": "계획표에 따라 움직이는 기차는 다른 방향의 신호기를 건너지 않습니다.", - "create.ponder.train_signal_placement.text_4": "두번째 신호기를 설치하는 경우를 제외한다면요.", - "create.ponder.train_signal_placement.text_5": "닉시관을 설치해 기차 신호를 잘 보이게 할 수 있습니다.", - - "create.ponder.train_signal_redstone.header": "기차 신호와 레드스톤", - "create.ponder.train_signal_redstone.text_1": "레드스톤 신호를 받으면 적신호가 됩니다.", - "create.ponder.train_signal_redstone.text_2": "반대로 적신호라면 비교기에서 신호가 방출됩니다.", - - "create.ponder.train_signal_signaling.header": "기차 신호로 충돌 방지하기", - "create.ponder.train_signal_signaling.text_1": "기차 신호기를 이용해 노선에서 구역을 나눌 수 있습니다.", - "create.ponder.train_signal_signaling.text_2": "만약 해당 구역이 사용중이면, 다른 기차는 진입할 수 없습니다.", - "create.ponder.train_signal_signaling.text_3": "따라서 한 구역마다 한 기차만 사용할 수 있습니다.", - "create.ponder.train_signal_signaling.text_4": "렌치로 두번째 신호 모드를 사용할 수 있습니다.", - "create.ponder.train_signal_signaling.text_5": "노란색 구역의 신호는 일반적인 신호와 같습니다.", - "create.ponder.train_signal_signaling.text_6": "하지만 이 신호기는 또다른 상황에서 기차의 진입을 금지합니다.", - "create.ponder.train_signal_signaling.text_7": "해당 구역을 바로 지나갈 수 없을 때...", - "create.ponder.train_signal_signaling.text_8": "이 신호기는 기차를 정지시킵니다.", - "create.ponder.train_signal_signaling.text_9": "이 신호체계로 복잡한 구역의 기차들을 잘 관리할 수 있습니다.", - - "create.ponder.valve_handle.header": "밸브 손잡이로 동력 생산하기", - "create.ponder.valve_handle.text_1": "밸브 손잡이를 사용하면 수동으로 동력을 생성할 수 있습니다.", - "create.ponder.valve_handle.text_2": "우클릭하면 반시계 방향으로 회전합니다.", - "create.ponder.valve_handle.text_3": "전달되는 속도는 상대적으로 낮습니다.", - "create.ponder.valve_handle.text_4": "웅크리고 우클릭하면 시계 방향으로 회전합니다.", - "create.ponder.valve_handle.text_5": "염료로 염색할 수 있습니다.", - - "create.ponder.valve_pipe.header": "밸브로 흐름 조절하기", - "create.ponder.valve_pipe.text_1": "밸브는 파이프 속 액체 흐름을 조절합니다.", - "create.ponder.valve_pipe.text_2": "밸브의 축으로 액체가 통과할 수 있는지 조절합니다.", - "create.ponder.valve_pipe.text_3": "동력을 제공하면 밸브가 열립니다.", - "create.ponder.valve_pipe.text_4": "반대 방향으로 동력을 제공하면 밸브가 닫힙니다.", - - "create.ponder.water_wheel.header": "물레바퀴로 동력 생산하기", - "create.ponder.water_wheel.text_1": "물레바퀴는 물의 흐름으로부터 동력을 끌어옵니다.", - "create.ponder.water_wheel.text_2": "많은 면에 힘이 가해질수록 물레바퀴가 더 빠르게 회전합니다.", - "create.ponder.water_wheel.text_3": "바퀴의 날이 물이 흐르는 방향으로 향하게 된다면...", - "create.ponder.water_wheel.text_4": "...회전 속도가 감소하게 됩니다.", - - "create.ponder.weighted_ejector.header": "투척기 사용하기", - "create.ponder.weighted_ejector.text_1": "투척기를 들고 웅크리고 우클릭하면, 발사 지점을 정할 수 있습니다.", - "create.ponder.weighted_ejector.text_10": "투척기에 놓인 아이템의 양이 설정량에 도달한 경우에만 투척기가 작동합니다.", - "create.ponder.weighted_ejector.text_11": "다른 엔티티가 발사대를 밟으면, 항상 발사대가 작동합니다.", - "create.ponder.weighted_ejector.text_2": "투척기는 지정한 위치에다 물체를 투척합니다.", - "create.ponder.weighted_ejector.text_3": "이 범위의 아무 장소에 투척할 수 있습니다.", - "create.ponder.weighted_ejector.text_4": "옆으로 투척할 수는 없습니다.", - "create.ponder.weighted_ejector.text_5": "투척 지점이 선택되지 않거나 올바르지 않은 경우, 바로 앞에 물체를 투척합니다.", - "create.ponder.weighted_ejector.text_6": "투척하려면 회전력이 필요합니다.", - "create.ponder.weighted_ejector.text_7": "투척기에 아이템을 놓으면 투척기가 작동합니다.", - "create.ponder.weighted_ejector.text_8": "보관함이 투척 지점인 경우에는 보관함에 공간이 생길 때까지 기다립니다.", - "create.ponder.weighted_ejector.text_9": "렌치를 사용하여, 투척에 필요한 아이템의 양을 설정할 수 있습니다.", - - "create.ponder.weighted_ejector_redstone.header": "투척기와 레드스톤", - "create.ponder.weighted_ejector_redstone.text_1": "레드스톤 신호를 받으면, 투척기가 작동하지 않습니다.", - "create.ponder.weighted_ejector_redstone.text_2": "관측기는 투척기가 작동하는 것을 탐지할 수 있습니다.", - - "create.ponder.weighted_ejector_tunnel.header": "투척기로 아이템 분할하기", - "create.ponder.weighted_ejector_tunnel.text_1": "황동 터널과 같이 사용하면 특정 양만큼 아이템을 분할할 수 있습니다.", - "create.ponder.weighted_ejector_tunnel.text_2": "먼저, 황동 터널을 '가까운 곳 선호' 방식으로 변경하여 측면에 아이템을 먼저 출력하게 만드세요.", - "create.ponder.weighted_ejector_tunnel.text_3": "이제, 투척기에 설정량에 따라 아이템을 분할할 수 있습니다.", - "create.ponder.weighted_ejector_tunnel.text_4": "설정량만큼의 아이템이 출력되고...", - "create.ponder.weighted_ejector_tunnel.text_5": "...나머지 아이템은 계속 수송됩니다", - - "create.ponder.windmill_source.header": "풍차 베어링으로 동력 생산하기", - "create.ponder.windmill_source.text_1": "풍차 베어링은 앞에 있는 블록을 부착합니다.", - "create.ponder.windmill_source.text_2": "강력 접착제로 움직일 수 있는 구조물을 만들어보세요.", - "create.ponder.windmill_source.text_3": "충분한 날개 블록이 있어야 풍차 역할을 합니다.", - "create.ponder.windmill_source.text_4": "우클릭으로 가동하면, 풍차 베어링은 동력을 생산합니다.", - "create.ponder.windmill_source.text_5": "날개 블록의 개수가 동력 속도를 결정합니다.", - "create.ponder.windmill_source.text_6": "렌치로 회전 방향을 설정할 수 있습니다.", - "create.ponder.windmill_source.text_7": "베어링을 우클릭하여 언제든지 멈추고 구조물을 수정할 수 있습니다", - - "create.ponder.windmill_structure.header": "풍차 구조물", - "create.ponder.windmill_structure.text_1": "최소 8개 이상의 날개 블록이 있는 구조물만 풍차로 사용할 수 있습니다.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json deleted file mode 100644 index 3a41b255a2..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 2468", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "UNLOCALIZED: Acacia Window", - "block.create.acacia_window_pane": "UNLOCALIZED: Acacia Window Pane", - "block.create.adjustable_chain_gearshift": "UNLOCALIZED: Adjustable Chain Gearshift", - "block.create.analog_lever": "UNLOCALIZED: Analog Lever", - "block.create.andesite_belt_funnel": "UNLOCALIZED: Andesite Belt Funnel", - "block.create.andesite_casing": "UNLOCALIZED: Andesite Casing", - "block.create.andesite_encased_cogwheel": "UNLOCALIZED: Andesite Encased Cogwheel", - "block.create.andesite_encased_large_cogwheel": "UNLOCALIZED: Andesite Encased Large Cogwheel", - "block.create.andesite_encased_shaft": "UNLOCALIZED: Andesite Encased Shaft", - "block.create.andesite_funnel": "UNLOCALIZED: Andesite Funnel", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "UNLOCALIZED: Andesite Pillar", - "block.create.andesite_tunnel": "UNLOCALIZED: Andesite Tunnel", - "block.create.asurine": "UNLOCALIZED: Asurine", - "block.create.asurine_pillar": "UNLOCALIZED: Asurine Pillar", - "block.create.basin": "Bekken", - "block.create.belt": "Mechanische Transportband", - "block.create.birch_window": "UNLOCALIZED: Birch Window", - "block.create.birch_window_pane": "UNLOCALIZED: Birch Window Pane", - "block.create.black_nixie_tube": "UNLOCALIZED: Black Nixie Tube", - "block.create.black_sail": "UNLOCALIZED: Black Sail", - "block.create.black_seat": "UNLOCALIZED: Black Seat", - "block.create.black_toolbox": "UNLOCALIZED: Black Toolbox", - "block.create.black_valve_handle": "UNLOCALIZED: Black Valve Handle", - "block.create.blaze_burner": "UNLOCALIZED: Blaze Burner", - "block.create.blue_nixie_tube": "UNLOCALIZED: Blue Nixie Tube", - "block.create.blue_sail": "UNLOCALIZED: Blue Sail", - "block.create.blue_seat": "UNLOCALIZED: Blue Seat", - "block.create.blue_toolbox": "UNLOCALIZED: Blue Toolbox", - "block.create.blue_valve_handle": "UNLOCALIZED: Blue Valve Handle", - "block.create.brass_belt_funnel": "UNLOCALIZED: Brass Belt Funnel", - "block.create.brass_block": "UNLOCALIZED: Block of Brass", - "block.create.brass_casing": "UNLOCALIZED: Brass Casing", - "block.create.brass_encased_cogwheel": "UNLOCALIZED: Brass Encased Cogwheel", - "block.create.brass_encased_large_cogwheel": "UNLOCALIZED: Brass Encased Large Cogwheel", - "block.create.brass_encased_shaft": "UNLOCALIZED: Brass Encased Shaft", - "block.create.brass_funnel": "UNLOCALIZED: Brass Funnel", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "UNLOCALIZED: Brass Tunnel", - "block.create.brown_nixie_tube": "UNLOCALIZED: Brown Nixie Tube", - "block.create.brown_sail": "UNLOCALIZED: Brown Sail", - "block.create.brown_seat": "UNLOCALIZED: Brown Seat", - "block.create.brown_toolbox": "UNLOCALIZED: Brown Toolbox", - "block.create.brown_valve_handle": "UNLOCALIZED: Brown Valve Handle", - "block.create.calcite_pillar": "UNLOCALIZED: Calcite Pillar", - "block.create.cart_assembler": "Kar Assembler", - "block.create.chocolate": "UNLOCALIZED: Chocolate", - "block.create.chute": "UNLOCALIZED: Chute", - "block.create.clockwork_bearing": "UNLOCALIZED: Clockwork Bearing", - "block.create.clutch": "Koppeling", - "block.create.cogwheel": "Tandwiel", - "block.create.content_observer": "UNLOCALIZED: Content Observer", - "block.create.controller_rail": "UNLOCALIZED: Controller Rail", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "UNLOCALIZED: Copper Backtank", - "block.create.copper_casing": "UNLOCALIZED: Copper Casing", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "UNLOCALIZED: Copper Shingle Slab", - "block.create.copper_shingle_stairs": "UNLOCALIZED: Copper Shingle Stairs", - "block.create.copper_shingles": "UNLOCALIZED: Copper Shingles", - "block.create.copper_tile_slab": "UNLOCALIZED: Copper Tile Slab", - "block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs", - "block.create.copper_tiles": "UNLOCALIZED: Copper Tiles", - "block.create.copper_valve_handle": "UNLOCALIZED: Copper Valve Handle", - "block.create.creative_crate": "Bouwtekeningkannon Creatiefeerder", - "block.create.creative_fluid_tank": "UNLOCALIZED: Creative Fluid Tank", - "block.create.creative_motor": "UNLOCALIZED: Creative Motor", - "block.create.crimsite": "UNLOCALIZED: Crimsite", - "block.create.crimsite_pillar": "UNLOCALIZED: Crimsite Pillar", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", - "block.create.crushing_wheel": "Verpulveraar", - "block.create.crushing_wheel_controller": "UNLOCALIZED: Crushing Wheel Controller", - "block.create.cuckoo_clock": "UNLOCALIZED: Cuckoo Clock", - "block.create.cut_andesite": "UNLOCALIZED: Cut Andesite", - "block.create.cut_andesite_brick_slab": "UNLOCALIZED: Cut Andesite Brick Slab", - "block.create.cut_andesite_brick_stairs": "UNLOCALIZED: Cut Andesite Brick Stairs", - "block.create.cut_andesite_brick_wall": "UNLOCALIZED: Cut Andesite Brick Wall", - "block.create.cut_andesite_bricks": "UNLOCALIZED: Cut Andesite Bricks", - "block.create.cut_andesite_slab": "UNLOCALIZED: Cut Andesite Slab", - "block.create.cut_andesite_stairs": "UNLOCALIZED: Cut Andesite Stairs", - "block.create.cut_andesite_wall": "UNLOCALIZED: Cut Andesite Wall", - "block.create.cut_asurine": "UNLOCALIZED: Cut Asurine", - "block.create.cut_asurine_brick_slab": "UNLOCALIZED: Cut Asurine Brick Slab", - "block.create.cut_asurine_brick_stairs": "UNLOCALIZED: Cut Asurine Brick Stairs", - "block.create.cut_asurine_brick_wall": "UNLOCALIZED: Cut Asurine Brick Wall", - "block.create.cut_asurine_bricks": "UNLOCALIZED: Cut Asurine Bricks", - "block.create.cut_asurine_slab": "UNLOCALIZED: Cut Asurine Slab", - "block.create.cut_asurine_stairs": "UNLOCALIZED: Cut Asurine Stairs", - "block.create.cut_asurine_wall": "UNLOCALIZED: Cut Asurine Wall", - "block.create.cut_calcite": "UNLOCALIZED: Cut Calcite", - "block.create.cut_calcite_brick_slab": "UNLOCALIZED: Cut Calcite Brick Slab", - "block.create.cut_calcite_brick_stairs": "UNLOCALIZED: Cut Calcite Brick Stairs", - "block.create.cut_calcite_brick_wall": "UNLOCALIZED: Cut Calcite Brick Wall", - "block.create.cut_calcite_bricks": "UNLOCALIZED: Cut Calcite Bricks", - "block.create.cut_calcite_slab": "UNLOCALIZED: Cut Calcite Slab", - "block.create.cut_calcite_stairs": "UNLOCALIZED: Cut Calcite Stairs", - "block.create.cut_calcite_wall": "UNLOCALIZED: Cut Calcite Wall", - "block.create.cut_crimsite": "UNLOCALIZED: Cut Crimsite", - "block.create.cut_crimsite_brick_slab": "UNLOCALIZED: Cut Crimsite Brick Slab", - "block.create.cut_crimsite_brick_stairs": "UNLOCALIZED: Cut Crimsite Brick Stairs", - "block.create.cut_crimsite_brick_wall": "UNLOCALIZED: Cut Crimsite Brick Wall", - "block.create.cut_crimsite_bricks": "UNLOCALIZED: Cut Crimsite Bricks", - "block.create.cut_crimsite_slab": "UNLOCALIZED: Cut Crimsite Slab", - "block.create.cut_crimsite_stairs": "UNLOCALIZED: Cut Crimsite Stairs", - "block.create.cut_crimsite_wall": "UNLOCALIZED: Cut Crimsite Wall", - "block.create.cut_deepslate": "UNLOCALIZED: Cut Deepslate", - "block.create.cut_deepslate_brick_slab": "UNLOCALIZED: Cut Deepslate Brick Slab", - "block.create.cut_deepslate_brick_stairs": "UNLOCALIZED: Cut Deepslate Brick Stairs", - "block.create.cut_deepslate_brick_wall": "UNLOCALIZED: Cut Deepslate Brick Wall", - "block.create.cut_deepslate_bricks": "UNLOCALIZED: Cut Deepslate Bricks", - "block.create.cut_deepslate_slab": "UNLOCALIZED: Cut Deepslate Slab", - "block.create.cut_deepslate_stairs": "UNLOCALIZED: Cut Deepslate Stairs", - "block.create.cut_deepslate_wall": "UNLOCALIZED: Cut Deepslate Wall", - "block.create.cut_diorite": "UNLOCALIZED: Cut Diorite", - "block.create.cut_diorite_brick_slab": "UNLOCALIZED: Cut Diorite Brick Slab", - "block.create.cut_diorite_brick_stairs": "UNLOCALIZED: Cut Diorite Brick Stairs", - "block.create.cut_diorite_brick_wall": "UNLOCALIZED: Cut Diorite Brick Wall", - "block.create.cut_diorite_bricks": "UNLOCALIZED: Cut Diorite Bricks", - "block.create.cut_diorite_slab": "UNLOCALIZED: Cut Diorite Slab", - "block.create.cut_diorite_stairs": "UNLOCALIZED: Cut Diorite Stairs", - "block.create.cut_diorite_wall": "UNLOCALIZED: Cut Diorite Wall", - "block.create.cut_dripstone": "UNLOCALIZED: Cut Dripstone", - "block.create.cut_dripstone_brick_slab": "UNLOCALIZED: Cut Dripstone Brick Slab", - "block.create.cut_dripstone_brick_stairs": "UNLOCALIZED: Cut Dripstone Brick Stairs", - "block.create.cut_dripstone_brick_wall": "UNLOCALIZED: Cut Dripstone Brick Wall", - "block.create.cut_dripstone_bricks": "UNLOCALIZED: Cut Dripstone Bricks", - "block.create.cut_dripstone_slab": "UNLOCALIZED: Cut Dripstone Slab", - "block.create.cut_dripstone_stairs": "UNLOCALIZED: Cut Dripstone Stairs", - "block.create.cut_dripstone_wall": "UNLOCALIZED: Cut Dripstone Wall", - "block.create.cut_granite": "UNLOCALIZED: Cut Granite", - "block.create.cut_granite_brick_slab": "UNLOCALIZED: Cut Granite Brick Slab", - "block.create.cut_granite_brick_stairs": "UNLOCALIZED: Cut Granite Brick Stairs", - "block.create.cut_granite_brick_wall": "UNLOCALIZED: Cut Granite Brick Wall", - "block.create.cut_granite_bricks": "UNLOCALIZED: Cut Granite Bricks", - "block.create.cut_granite_slab": "UNLOCALIZED: Cut Granite Slab", - "block.create.cut_granite_stairs": "UNLOCALIZED: Cut Granite Stairs", - "block.create.cut_granite_wall": "UNLOCALIZED: Cut Granite Wall", - "block.create.cut_limestone": "UNLOCALIZED: Cut Limestone", - "block.create.cut_limestone_brick_slab": "UNLOCALIZED: Cut Limestone Brick Slab", - "block.create.cut_limestone_brick_stairs": "UNLOCALIZED: Cut Limestone Brick Stairs", - "block.create.cut_limestone_brick_wall": "UNLOCALIZED: Cut Limestone Brick Wall", - "block.create.cut_limestone_bricks": "UNLOCALIZED: Cut Limestone Bricks", - "block.create.cut_limestone_slab": "UNLOCALIZED: Cut Limestone Slab", - "block.create.cut_limestone_stairs": "UNLOCALIZED: Cut Limestone Stairs", - "block.create.cut_limestone_wall": "UNLOCALIZED: Cut Limestone Wall", - "block.create.cut_ochrum": "UNLOCALIZED: Cut Ochrum", - "block.create.cut_ochrum_brick_slab": "UNLOCALIZED: Cut Ochrum Brick Slab", - "block.create.cut_ochrum_brick_stairs": "UNLOCALIZED: Cut Ochrum Brick Stairs", - "block.create.cut_ochrum_brick_wall": "UNLOCALIZED: Cut Ochrum Brick Wall", - "block.create.cut_ochrum_bricks": "UNLOCALIZED: Cut Ochrum Bricks", - "block.create.cut_ochrum_slab": "UNLOCALIZED: Cut Ochrum Slab", - "block.create.cut_ochrum_stairs": "UNLOCALIZED: Cut Ochrum Stairs", - "block.create.cut_ochrum_wall": "UNLOCALIZED: Cut Ochrum Wall", - "block.create.cut_scorchia": "UNLOCALIZED: Cut Scorchia", - "block.create.cut_scorchia_brick_slab": "UNLOCALIZED: Cut Scorchia Brick Slab", - "block.create.cut_scorchia_brick_stairs": "UNLOCALIZED: Cut Scorchia Brick Stairs", - "block.create.cut_scorchia_brick_wall": "UNLOCALIZED: Cut Scorchia Brick Wall", - "block.create.cut_scorchia_bricks": "UNLOCALIZED: Cut Scorchia Bricks", - "block.create.cut_scorchia_slab": "UNLOCALIZED: Cut Scorchia Slab", - "block.create.cut_scorchia_stairs": "UNLOCALIZED: Cut Scorchia Stairs", - "block.create.cut_scorchia_wall": "UNLOCALIZED: Cut Scorchia Wall", - "block.create.cut_scoria": "UNLOCALIZED: Cut Scoria", - "block.create.cut_scoria_brick_slab": "UNLOCALIZED: Cut Scoria Brick Slab", - "block.create.cut_scoria_brick_stairs": "UNLOCALIZED: Cut Scoria Brick Stairs", - "block.create.cut_scoria_brick_wall": "UNLOCALIZED: Cut Scoria Brick Wall", - "block.create.cut_scoria_bricks": "UNLOCALIZED: Cut Scoria Bricks", - "block.create.cut_scoria_slab": "UNLOCALIZED: Cut Scoria Slab", - "block.create.cut_scoria_stairs": "UNLOCALIZED: Cut Scoria Stairs", - "block.create.cut_scoria_wall": "UNLOCALIZED: Cut Scoria Wall", - "block.create.cut_tuff": "UNLOCALIZED: Cut Tuff", - "block.create.cut_tuff_brick_slab": "UNLOCALIZED: Cut Tuff Brick Slab", - "block.create.cut_tuff_brick_stairs": "UNLOCALIZED: Cut Tuff Brick Stairs", - "block.create.cut_tuff_brick_wall": "UNLOCALIZED: Cut Tuff Brick Wall", - "block.create.cut_tuff_bricks": "UNLOCALIZED: Cut Tuff Bricks", - "block.create.cut_tuff_slab": "UNLOCALIZED: Cut Tuff Slab", - "block.create.cut_tuff_stairs": "UNLOCALIZED: Cut Tuff Stairs", - "block.create.cut_tuff_wall": "UNLOCALIZED: Cut Tuff Wall", - "block.create.cut_veridium": "UNLOCALIZED: Cut Veridium", - "block.create.cut_veridium_brick_slab": "UNLOCALIZED: Cut Veridium Brick Slab", - "block.create.cut_veridium_brick_stairs": "UNLOCALIZED: Cut Veridium Brick Stairs", - "block.create.cut_veridium_brick_wall": "UNLOCALIZED: Cut Veridium Brick Wall", - "block.create.cut_veridium_bricks": "UNLOCALIZED: Cut Veridium Bricks", - "block.create.cut_veridium_slab": "UNLOCALIZED: Cut Veridium Slab", - "block.create.cut_veridium_stairs": "UNLOCALIZED: Cut Veridium Stairs", - "block.create.cut_veridium_wall": "UNLOCALIZED: Cut Veridium Wall", - "block.create.cyan_nixie_tube": "UNLOCALIZED: Cyan Nixie Tube", - "block.create.cyan_sail": "UNLOCALIZED: Cyan Sail", - "block.create.cyan_seat": "UNLOCALIZED: Cyan Seat", - "block.create.cyan_toolbox": "UNLOCALIZED: Cyan Toolbox", - "block.create.cyan_valve_handle": "UNLOCALIZED: Cyan Valve Handle", - "block.create.dark_oak_window": "UNLOCALIZED: Dark Oak Window", - "block.create.dark_oak_window_pane": "UNLOCALIZED: Dark Oak Window Pane", - "block.create.deepslate_pillar": "UNLOCALIZED: Deepslate Pillar", - "block.create.deepslate_zinc_ore": "UNLOCALIZED: Deepslate Zinc Ore", - "block.create.deployer": "UNLOCALIZED: Deployer", - "block.create.depot": "UNLOCALIZED: Depot", - "block.create.diorite_pillar": "UNLOCALIZED: Diorite Pillar", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar", - "block.create.encased_chain_drive": "UNLOCALIZED: Encased Chain Drive", - "block.create.encased_fan": "Omhulsde Ventilator", - "block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe", - "block.create.exposed_copper_shingle_slab": "UNLOCALIZED: Exposed Copper Shingle Slab", - "block.create.exposed_copper_shingle_stairs": "UNLOCALIZED: Exposed Copper Shingle Stairs", - "block.create.exposed_copper_shingles": "UNLOCALIZED: Exposed Copper Shingles", - "block.create.exposed_copper_tile_slab": "UNLOCALIZED: Exposed Copper Tile Slab", - "block.create.exposed_copper_tile_stairs": "UNLOCALIZED: Exposed Copper Tile Stairs", - "block.create.exposed_copper_tiles": "UNLOCALIZED: Exposed Copper Tiles", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "UNLOCALIZED: Fluid Pipe", - "block.create.fluid_tank": "UNLOCALIZED: Fluid Tank", - "block.create.fluid_valve": "UNLOCALIZED: Fluid Valve", - "block.create.flywheel": "UNLOCALIZED: Flywheel", - "block.create.framed_glass": "Ingelijst Glas", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "UNLOCALIZED: Framed Glass Pane", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "UNLOCALIZED: Gantry Carriage", - "block.create.gantry_shaft": "UNLOCALIZED: Gantry Shaft", - "block.create.gearbox": "Versnellingsbak", - "block.create.gearshift": "Versnellingspook", - "block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe", - "block.create.granite_pillar": "UNLOCALIZED: Granite Pillar", - "block.create.gray_nixie_tube": "UNLOCALIZED: Gray Nixie Tube", - "block.create.gray_sail": "UNLOCALIZED: Gray Sail", - "block.create.gray_seat": "UNLOCALIZED: Gray Seat", - "block.create.gray_toolbox": "UNLOCALIZED: Gray Toolbox", - "block.create.gray_valve_handle": "UNLOCALIZED: Gray Valve Handle", - "block.create.green_nixie_tube": "UNLOCALIZED: Green Nixie Tube", - "block.create.green_sail": "UNLOCALIZED: Green Sail", - "block.create.green_seat": "UNLOCALIZED: Green Seat", - "block.create.green_toolbox": "UNLOCALIZED: Green Toolbox", - "block.create.green_valve_handle": "UNLOCALIZED: Green Valve Handle", - "block.create.hand_crank": "UNLOCALIZED: Hand Crank", - "block.create.haunted_bell": "UNLOCALIZED: Haunted Bell", - "block.create.honey": "UNLOCALIZED: Honey", - "block.create.horizontal_framed_glass": "UNLOCALIZED: Horizontal Framed Glass", - "block.create.horizontal_framed_glass_pane": "UNLOCALIZED: Horizontal Framed Glass Pane", - "block.create.hose_pulley": "UNLOCALIZED: Hose Pulley", - "block.create.item_drain": "UNLOCALIZED: Item Drain", - "block.create.item_vault": "UNLOCALIZED: Item Vault", - "block.create.jungle_window": "UNLOCALIZED: Jungle Window", - "block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "Groot Tandwiel", - "block.create.layered_andesite": "UNLOCALIZED: Layered Andesite", - "block.create.layered_asurine": "UNLOCALIZED: Layered Asurine", - "block.create.layered_calcite": "UNLOCALIZED: Layered Calcite", - "block.create.layered_crimsite": "UNLOCALIZED: Layered Crimsite", - "block.create.layered_deepslate": "UNLOCALIZED: Layered Deepslate", - "block.create.layered_diorite": "UNLOCALIZED: Layered Diorite", - "block.create.layered_dripstone": "UNLOCALIZED: Layered Dripstone", - "block.create.layered_granite": "UNLOCALIZED: Layered Granite", - "block.create.layered_limestone": "UNLOCALIZED: Layered Limestone", - "block.create.layered_ochrum": "UNLOCALIZED: Layered Ochrum", - "block.create.layered_scorchia": "UNLOCALIZED: Layered Scorchia", - "block.create.layered_scoria": "UNLOCALIZED: Layered Scoria", - "block.create.layered_tuff": "UNLOCALIZED: Layered Tuff", - "block.create.layered_veridium": "UNLOCALIZED: Layered Veridium", - "block.create.lectern_controller": "UNLOCALIZED: Lectern Controller", - "block.create.light_blue_nixie_tube": "UNLOCALIZED: Light Blue Nixie Tube", - "block.create.light_blue_sail": "UNLOCALIZED: Light Blue Sail", - "block.create.light_blue_seat": "UNLOCALIZED: Light Blue Seat", - "block.create.light_blue_toolbox": "UNLOCALIZED: Light Blue Toolbox", - "block.create.light_blue_valve_handle": "UNLOCALIZED: Light Blue Valve Handle", - "block.create.light_gray_nixie_tube": "UNLOCALIZED: Light Gray Nixie Tube", - "block.create.light_gray_sail": "UNLOCALIZED: Light Gray Sail", - "block.create.light_gray_seat": "UNLOCALIZED: Light Gray Seat", - "block.create.light_gray_toolbox": "UNLOCALIZED: Light Gray Toolbox", - "block.create.light_gray_valve_handle": "UNLOCALIZED: Light Gray Valve Handle", - "block.create.lime_nixie_tube": "UNLOCALIZED: Lime Nixie Tube", - "block.create.lime_sail": "UNLOCALIZED: Lime Sail", - "block.create.lime_seat": "UNLOCALIZED: Lime Seat", - "block.create.lime_toolbox": "UNLOCALIZED: Lime Toolbox", - "block.create.lime_valve_handle": "UNLOCALIZED: Lime Valve Handle", - "block.create.limestone": "Kalksteen", - "block.create.limestone_pillar": "Kalksteen Pillar", - "block.create.linear_chassis": "Lineaar Frame", - "block.create.lit_blaze_burner": "UNLOCALIZED: Lit Blaze Burner", - "block.create.magenta_nixie_tube": "UNLOCALIZED: Magenta Nixie Tube", - "block.create.magenta_sail": "UNLOCALIZED: Magenta Sail", - "block.create.magenta_seat": "UNLOCALIZED: Magenta Seat", - "block.create.magenta_toolbox": "UNLOCALIZED: Magenta Toolbox", - "block.create.magenta_valve_handle": "UNLOCALIZED: Magenta Valve Handle", - "block.create.mechanical_arm": "UNLOCALIZED: Mechanical Arm", - "block.create.mechanical_bearing": "Mechanische Lager", - "block.create.mechanical_crafter": "Mechanische Werkbank", - "block.create.mechanical_drill": "Mechanische Boor", - "block.create.mechanical_harvester": "Mechanische Oogster", - "block.create.mechanical_mixer": "Mechanische Menger", - "block.create.mechanical_piston": "Mechanische Kleefzuiger", - "block.create.mechanical_piston_head": "Mechanische Zuigerhoofd", - "block.create.mechanical_plough": "UNLOCALIZED: Mechanical Plough", - "block.create.mechanical_press": "Mechanische Pers", - "block.create.mechanical_pump": "UNLOCALIZED: Mechanical Pump", - "block.create.mechanical_saw": "Mechanische Zaag", - "block.create.metal_bracket": "UNLOCALIZED: Metal Bracket", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "UNLOCALIZED: Millstone", - "block.create.minecart_anchor": "UNLOCALIZED: Minecart Anchor", - "block.create.mysterious_cuckoo_clock": "UNLOCALIZED: Cuckoo Clock", - "block.create.nixie_tube": "UNLOCALIZED: Nixie Tube", - "block.create.nozzle": "UNLOCALIZED: Nozzle", - "block.create.oak_window": "UNLOCALIZED: Oak Window", - "block.create.oak_window_pane": "UNLOCALIZED: Oak Window Pane", - "block.create.ochrum": "UNLOCALIZED: Ochrum", - "block.create.ochrum_pillar": "UNLOCALIZED: Ochrum Pillar", - "block.create.orange_sail": "UNLOCALIZED: Orange Sail", - "block.create.orange_seat": "UNLOCALIZED: Orange Seat", - "block.create.orange_toolbox": "UNLOCALIZED: Orange Toolbox", - "block.create.orange_valve_handle": "UNLOCALIZED: Orange Valve Handle", - "block.create.ornate_iron_window": "UNLOCALIZED: Ornate Iron Window", - "block.create.ornate_iron_window_pane": "UNLOCALIZED: Ornate Iron Window Pane", - "block.create.oxidized_copper_shingle_slab": "UNLOCALIZED: Oxidized Copper Shingle Slab", - "block.create.oxidized_copper_shingle_stairs": "UNLOCALIZED: Oxidized Copper Shingle Stairs", - "block.create.oxidized_copper_shingles": "UNLOCALIZED: Oxidized Copper Shingles", - "block.create.oxidized_copper_tile_slab": "UNLOCALIZED: Oxidized Copper Tile Slab", - "block.create.oxidized_copper_tile_stairs": "UNLOCALIZED: Oxidized Copper Tile Stairs", - "block.create.oxidized_copper_tiles": "UNLOCALIZED: Oxidized Copper Tiles", - "block.create.peculiar_bell": "UNLOCALIZED: Peculiar Bell", - "block.create.pink_nixie_tube": "UNLOCALIZED: Pink Nixie Tube", - "block.create.pink_sail": "UNLOCALIZED: Pink Sail", - "block.create.pink_seat": "UNLOCALIZED: Pink Seat", - "block.create.pink_toolbox": "UNLOCALIZED: Pink Toolbox", - "block.create.pink_valve_handle": "UNLOCALIZED: Pink Valve Handle", - "block.create.piston_extension_pole": "Zuiger Verlengpaal", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "UNLOCALIZED: Polished Cut Andesite", - "block.create.polished_cut_andesite_slab": "UNLOCALIZED: Polished Cut Andesite Slab", - "block.create.polished_cut_andesite_stairs": "UNLOCALIZED: Polished Cut Andesite Stairs", - "block.create.polished_cut_andesite_wall": "UNLOCALIZED: Polished Cut Andesite Wall", - "block.create.polished_cut_asurine": "UNLOCALIZED: Polished Cut Asurine", - "block.create.polished_cut_asurine_slab": "UNLOCALIZED: Polished Cut Asurine Slab", - "block.create.polished_cut_asurine_stairs": "UNLOCALIZED: Polished Cut Asurine Stairs", - "block.create.polished_cut_asurine_wall": "UNLOCALIZED: Polished Cut Asurine Wall", - "block.create.polished_cut_calcite": "UNLOCALIZED: Polished Cut Calcite", - "block.create.polished_cut_calcite_slab": "UNLOCALIZED: Polished Cut Calcite Slab", - "block.create.polished_cut_calcite_stairs": "UNLOCALIZED: Polished Cut Calcite Stairs", - "block.create.polished_cut_calcite_wall": "UNLOCALIZED: Polished Cut Calcite Wall", - "block.create.polished_cut_crimsite": "UNLOCALIZED: Polished Cut Crimsite", - "block.create.polished_cut_crimsite_slab": "UNLOCALIZED: Polished Cut Crimsite Slab", - "block.create.polished_cut_crimsite_stairs": "UNLOCALIZED: Polished Cut Crimsite Stairs", - "block.create.polished_cut_crimsite_wall": "UNLOCALIZED: Polished Cut Crimsite Wall", - "block.create.polished_cut_deepslate": "UNLOCALIZED: Polished Cut Deepslate", - "block.create.polished_cut_deepslate_slab": "UNLOCALIZED: Polished Cut Deepslate Slab", - "block.create.polished_cut_deepslate_stairs": "UNLOCALIZED: Polished Cut Deepslate Stairs", - "block.create.polished_cut_deepslate_wall": "UNLOCALIZED: Polished Cut Deepslate Wall", - "block.create.polished_cut_diorite": "UNLOCALIZED: Polished Cut Diorite", - "block.create.polished_cut_diorite_slab": "UNLOCALIZED: Polished Cut Diorite Slab", - "block.create.polished_cut_diorite_stairs": "UNLOCALIZED: Polished Cut Diorite Stairs", - "block.create.polished_cut_diorite_wall": "UNLOCALIZED: Polished Cut Diorite Wall", - "block.create.polished_cut_dripstone": "UNLOCALIZED: Polished Cut Dripstone", - "block.create.polished_cut_dripstone_slab": "UNLOCALIZED: Polished Cut Dripstone Slab", - "block.create.polished_cut_dripstone_stairs": "UNLOCALIZED: Polished Cut Dripstone Stairs", - "block.create.polished_cut_dripstone_wall": "UNLOCALIZED: Polished Cut Dripstone Wall", - "block.create.polished_cut_granite": "UNLOCALIZED: Polished Cut Granite", - "block.create.polished_cut_granite_slab": "UNLOCALIZED: Polished Cut Granite Slab", - "block.create.polished_cut_granite_stairs": "UNLOCALIZED: Polished Cut Granite Stairs", - "block.create.polished_cut_granite_wall": "UNLOCALIZED: Polished Cut Granite Wall", - "block.create.polished_cut_limestone": "UNLOCALIZED: Polished Cut Limestone", - "block.create.polished_cut_limestone_slab": "UNLOCALIZED: Polished Cut Limestone Slab", - "block.create.polished_cut_limestone_stairs": "UNLOCALIZED: Polished Cut Limestone Stairs", - "block.create.polished_cut_limestone_wall": "UNLOCALIZED: Polished Cut Limestone Wall", - "block.create.polished_cut_ochrum": "UNLOCALIZED: Polished Cut Ochrum", - "block.create.polished_cut_ochrum_slab": "UNLOCALIZED: Polished Cut Ochrum Slab", - "block.create.polished_cut_ochrum_stairs": "UNLOCALIZED: Polished Cut Ochrum Stairs", - "block.create.polished_cut_ochrum_wall": "UNLOCALIZED: Polished Cut Ochrum Wall", - "block.create.polished_cut_scorchia": "UNLOCALIZED: Polished Cut Scorchia", - "block.create.polished_cut_scorchia_slab": "UNLOCALIZED: Polished Cut Scorchia Slab", - "block.create.polished_cut_scorchia_stairs": "UNLOCALIZED: Polished Cut Scorchia Stairs", - "block.create.polished_cut_scorchia_wall": "UNLOCALIZED: Polished Cut Scorchia Wall", - "block.create.polished_cut_scoria": "UNLOCALIZED: Polished Cut Scoria", - "block.create.polished_cut_scoria_slab": "UNLOCALIZED: Polished Cut Scoria Slab", - "block.create.polished_cut_scoria_stairs": "UNLOCALIZED: Polished Cut Scoria Stairs", - "block.create.polished_cut_scoria_wall": "UNLOCALIZED: Polished Cut Scoria Wall", - "block.create.polished_cut_tuff": "UNLOCALIZED: Polished Cut Tuff", - "block.create.polished_cut_tuff_slab": "UNLOCALIZED: Polished Cut Tuff Slab", - "block.create.polished_cut_tuff_stairs": "UNLOCALIZED: Polished Cut Tuff Stairs", - "block.create.polished_cut_tuff_wall": "UNLOCALIZED: Polished Cut Tuff Wall", - "block.create.polished_cut_veridium": "UNLOCALIZED: Polished Cut Veridium", - "block.create.polished_cut_veridium_slab": "UNLOCALIZED: Polished Cut Veridium Slab", - "block.create.polished_cut_veridium_stairs": "UNLOCALIZED: Polished Cut Veridium Stairs", - "block.create.polished_cut_veridium_wall": "UNLOCALIZED: Polished Cut Veridium Wall", - "block.create.portable_fluid_interface": "UNLOCALIZED: Portable Fluid Interface", - "block.create.portable_storage_interface": "UNLOCALIZED: Portable Storage Interface", - "block.create.powered_latch": "UNLOCALIZED: Powered Latch", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "UNLOCALIZED: Powered Toggle Latch", - "block.create.pulley_magnet": "UNLOCALIZED: Pulley Magnet", - "block.create.pulse_extender": "UNLOCALIZED: Pulse Extender", - "block.create.pulse_repeater": "Pulse Versterker", - "block.create.purple_nixie_tube": "UNLOCALIZED: Purple Nixie Tube", - "block.create.purple_sail": "UNLOCALIZED: Purple Sail", - "block.create.purple_seat": "UNLOCALIZED: Purple Seat", - "block.create.purple_toolbox": "UNLOCALIZED: Purple Toolbox", - "block.create.purple_valve_handle": "UNLOCALIZED: Purple Valve Handle", - "block.create.radial_chassis": "Rotation Frame", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "UNLOCALIZED: Block of Raw Zinc", - "block.create.red_nixie_tube": "UNLOCALIZED: Red Nixie Tube", - "block.create.red_sail": "UNLOCALIZED: Red Sail", - "block.create.red_seat": "UNLOCALIZED: Red Seat", - "block.create.red_toolbox": "UNLOCALIZED: Red Toolbox", - "block.create.red_valve_handle": "UNLOCALIZED: Red Valve Handle", - "block.create.redstone_contact": "Redstone redstone_contact", - "block.create.redstone_link": "Redstone Brug", - "block.create.refined_radiance_casing": "UNLOCALIZED: Radiant Casing", - "block.create.rope": "UNLOCALIZED: Rope", - "block.create.rope_pulley": "UNLOCALIZED: Rope Pulley", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "UNLOCALIZED: Rotation Speed Controller", - "block.create.sail_frame": "UNLOCALIZED: Sail Frame", - "block.create.schematic_table": "Bouwtekening Tafel", - "block.create.schematicannon": "Bouwtekeningkannon", - "block.create.scorchia": "UNLOCALIZED: Scorchia", - "block.create.scorchia_pillar": "UNLOCALIZED: Scorchia Pillar", - "block.create.scoria": "UNLOCALIZED: Scoria", - "block.create.scoria_pillar": "UNLOCALIZED: Scoria Pillar", - "block.create.secondary_linear_chassis": "UNLOCALIZED: Secondary Linear Chassis", - "block.create.sequenced_gearshift": "UNLOCALIZED: Sequenced Gearshift", - "block.create.shadow_steel_casing": "UNLOCALIZED: Shadow Casing", - "block.create.shaft": "Drijfas", - "block.create.small_andesite_brick_slab": "UNLOCALIZED: Small Andesite Brick Slab", - "block.create.small_andesite_brick_stairs": "UNLOCALIZED: Small Andesite Brick Stairs", - "block.create.small_andesite_brick_wall": "UNLOCALIZED: Small Andesite Brick Wall", - "block.create.small_andesite_bricks": "UNLOCALIZED: Small Andesite Bricks", - "block.create.small_asurine_brick_slab": "UNLOCALIZED: Small Asurine Brick Slab", - "block.create.small_asurine_brick_stairs": "UNLOCALIZED: Small Asurine Brick Stairs", - "block.create.small_asurine_brick_wall": "UNLOCALIZED: Small Asurine Brick Wall", - "block.create.small_asurine_bricks": "UNLOCALIZED: Small Asurine Bricks", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "UNLOCALIZED: Small Calcite Brick Slab", - "block.create.small_calcite_brick_stairs": "UNLOCALIZED: Small Calcite Brick Stairs", - "block.create.small_calcite_brick_wall": "UNLOCALIZED: Small Calcite Brick Wall", - "block.create.small_calcite_bricks": "UNLOCALIZED: Small Calcite Bricks", - "block.create.small_crimsite_brick_slab": "UNLOCALIZED: Small Crimsite Brick Slab", - "block.create.small_crimsite_brick_stairs": "UNLOCALIZED: Small Crimsite Brick Stairs", - "block.create.small_crimsite_brick_wall": "UNLOCALIZED: Small Crimsite Brick Wall", - "block.create.small_crimsite_bricks": "UNLOCALIZED: Small Crimsite Bricks", - "block.create.small_deepslate_brick_slab": "UNLOCALIZED: Small Deepslate Brick Slab", - "block.create.small_deepslate_brick_stairs": "UNLOCALIZED: Small Deepslate Brick Stairs", - "block.create.small_deepslate_brick_wall": "UNLOCALIZED: Small Deepslate Brick Wall", - "block.create.small_deepslate_bricks": "UNLOCALIZED: Small Deepslate Bricks", - "block.create.small_diorite_brick_slab": "UNLOCALIZED: Small Diorite Brick Slab", - "block.create.small_diorite_brick_stairs": "UNLOCALIZED: Small Diorite Brick Stairs", - "block.create.small_diorite_brick_wall": "UNLOCALIZED: Small Diorite Brick Wall", - "block.create.small_diorite_bricks": "UNLOCALIZED: Small Diorite Bricks", - "block.create.small_dripstone_brick_slab": "UNLOCALIZED: Small Dripstone Brick Slab", - "block.create.small_dripstone_brick_stairs": "UNLOCALIZED: Small Dripstone Brick Stairs", - "block.create.small_dripstone_brick_wall": "UNLOCALIZED: Small Dripstone Brick Wall", - "block.create.small_dripstone_bricks": "UNLOCALIZED: Small Dripstone Bricks", - "block.create.small_granite_brick_slab": "UNLOCALIZED: Small Granite Brick Slab", - "block.create.small_granite_brick_stairs": "UNLOCALIZED: Small Granite Brick Stairs", - "block.create.small_granite_brick_wall": "UNLOCALIZED: Small Granite Brick Wall", - "block.create.small_granite_bricks": "UNLOCALIZED: Small Granite Bricks", - "block.create.small_limestone_brick_slab": "UNLOCALIZED: Small Limestone Brick Slab", - "block.create.small_limestone_brick_stairs": "UNLOCALIZED: Small Limestone Brick Stairs", - "block.create.small_limestone_brick_wall": "UNLOCALIZED: Small Limestone Brick Wall", - "block.create.small_limestone_bricks": "UNLOCALIZED: Small Limestone Bricks", - "block.create.small_ochrum_brick_slab": "UNLOCALIZED: Small Ochrum Brick Slab", - "block.create.small_ochrum_brick_stairs": "UNLOCALIZED: Small Ochrum Brick Stairs", - "block.create.small_ochrum_brick_wall": "UNLOCALIZED: Small Ochrum Brick Wall", - "block.create.small_ochrum_bricks": "UNLOCALIZED: Small Ochrum Bricks", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "UNLOCALIZED: Small Scorchia Brick Slab", - "block.create.small_scorchia_brick_stairs": "UNLOCALIZED: Small Scorchia Brick Stairs", - "block.create.small_scorchia_brick_wall": "UNLOCALIZED: Small Scorchia Brick Wall", - "block.create.small_scorchia_bricks": "UNLOCALIZED: Small Scorchia Bricks", - "block.create.small_scoria_brick_slab": "UNLOCALIZED: Small Scoria Brick Slab", - "block.create.small_scoria_brick_stairs": "UNLOCALIZED: Small Scoria Brick Stairs", - "block.create.small_scoria_brick_wall": "UNLOCALIZED: Small Scoria Brick Wall", - "block.create.small_scoria_bricks": "UNLOCALIZED: Small Scoria Bricks", - "block.create.small_tuff_brick_slab": "UNLOCALIZED: Small Tuff Brick Slab", - "block.create.small_tuff_brick_stairs": "UNLOCALIZED: Small Tuff Brick Stairs", - "block.create.small_tuff_brick_wall": "UNLOCALIZED: Small Tuff Brick Wall", - "block.create.small_tuff_bricks": "UNLOCALIZED: Small Tuff Bricks", - "block.create.small_veridium_brick_slab": "UNLOCALIZED: Small Veridium Brick Slab", - "block.create.small_veridium_brick_stairs": "UNLOCALIZED: Small Veridium Brick Stairs", - "block.create.small_veridium_brick_wall": "UNLOCALIZED: Small Veridium Brick Wall", - "block.create.small_veridium_bricks": "UNLOCALIZED: Small Veridium Bricks", - "block.create.smart_chute": "UNLOCALIZED: Smart Chute", - "block.create.smart_fluid_pipe": "UNLOCALIZED: Smart Fluid Pipe", - "block.create.speedometer": "Snelheidsmeter", - "block.create.spout": "UNLOCALIZED: Spout", - "block.create.spruce_window": "UNLOCALIZED: Spruce Window", - "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "UNLOCALIZED: Sticker", - "block.create.sticky_mechanical_piston": "Mechanische Zuiger", - "block.create.stockpile_switch": "Voorraad Schakelaar", - "block.create.stressometer": "Stressmeter", - "block.create.tiled_glass": "Getegeld Glas", - "block.create.tiled_glass_pane": "Getegeld Glazen Paneel", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "UNLOCALIZED: Tuff Pillar", - "block.create.turntable": "Draaischijf", - "block.create.veridium": "UNLOCALIZED: Veridium", - "block.create.veridium_pillar": "UNLOCALIZED: Veridium Pillar", - "block.create.vertical_framed_glass": "UNLOCALIZED: Vertical Framed Glass", - "block.create.vertical_framed_glass_pane": "UNLOCALIZED: Vertical Framed Glass Pane", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", - "block.create.water_wheel": "Waterrad", - "block.create.waxed_copper_shingle_slab": "UNLOCALIZED: Waxed Copper Shingle Slab", - "block.create.waxed_copper_shingle_stairs": "UNLOCALIZED: Waxed Copper Shingle Stairs", - "block.create.waxed_copper_shingles": "UNLOCALIZED: Waxed Copper Shingles", - "block.create.waxed_copper_tile_slab": "UNLOCALIZED: Waxed Copper Tile Slab", - "block.create.waxed_copper_tile_stairs": "UNLOCALIZED: Waxed Copper Tile Stairs", - "block.create.waxed_copper_tiles": "UNLOCALIZED: Waxed Copper Tiles", - "block.create.waxed_exposed_copper_shingle_slab": "UNLOCALIZED: Waxed Exposed Copper Shingle Slab", - "block.create.waxed_exposed_copper_shingle_stairs": "UNLOCALIZED: Waxed Exposed Copper Shingle Stairs", - "block.create.waxed_exposed_copper_shingles": "UNLOCALIZED: Waxed Exposed Copper Shingles", - "block.create.waxed_exposed_copper_tile_slab": "UNLOCALIZED: Waxed Exposed Copper Tile Slab", - "block.create.waxed_exposed_copper_tile_stairs": "UNLOCALIZED: Waxed Exposed Copper Tile Stairs", - "block.create.waxed_exposed_copper_tiles": "UNLOCALIZED: Waxed Exposed Copper Tiles", - "block.create.waxed_oxidized_copper_shingle_slab": "UNLOCALIZED: Waxed Oxidized Copper Shingle Slab", - "block.create.waxed_oxidized_copper_shingle_stairs": "UNLOCALIZED: Waxed Oxidized Copper Shingle Stairs", - "block.create.waxed_oxidized_copper_shingles": "UNLOCALIZED: Waxed Oxidized Copper Shingles", - "block.create.waxed_oxidized_copper_tile_slab": "UNLOCALIZED: Waxed Oxidized Copper Tile Slab", - "block.create.waxed_oxidized_copper_tile_stairs": "UNLOCALIZED: Waxed Oxidized Copper Tile Stairs", - "block.create.waxed_oxidized_copper_tiles": "UNLOCALIZED: Waxed Oxidized Copper Tiles", - "block.create.waxed_weathered_copper_shingle_slab": "UNLOCALIZED: Waxed Weathered Copper Shingle Slab", - "block.create.waxed_weathered_copper_shingle_stairs": "UNLOCALIZED: Waxed Weathered Copper Shingle Stairs", - "block.create.waxed_weathered_copper_shingles": "UNLOCALIZED: Waxed Weathered Copper Shingles", - "block.create.waxed_weathered_copper_tile_slab": "UNLOCALIZED: Waxed Weathered Copper Tile Slab", - "block.create.waxed_weathered_copper_tile_stairs": "UNLOCALIZED: Waxed Weathered Copper Tile Stairs", - "block.create.waxed_weathered_copper_tiles": "UNLOCALIZED: Waxed Weathered Copper Tiles", - "block.create.weathered_copper_shingle_slab": "UNLOCALIZED: Weathered Copper Shingle Slab", - "block.create.weathered_copper_shingle_stairs": "UNLOCALIZED: Weathered Copper Shingle Stairs", - "block.create.weathered_copper_shingles": "UNLOCALIZED: Weathered Copper Shingles", - "block.create.weathered_copper_tile_slab": "UNLOCALIZED: Weathered Copper Tile Slab", - "block.create.weathered_copper_tile_stairs": "UNLOCALIZED: Weathered Copper Tile Stairs", - "block.create.weathered_copper_tiles": "UNLOCALIZED: Weathered Copper Tiles", - "block.create.weighted_ejector": "UNLOCALIZED: Weighted Ejector", - "block.create.white_nixie_tube": "UNLOCALIZED: White Nixie Tube", - "block.create.white_sail": "UNLOCALIZED: White Sail", - "block.create.white_seat": "UNLOCALIZED: White Seat", - "block.create.white_toolbox": "UNLOCALIZED: White Toolbox", - "block.create.white_valve_handle": "UNLOCALIZED: White Valve Handle", - "block.create.windmill_bearing": "UNLOCALIZED: Windmill Bearing", - "block.create.wooden_bracket": "UNLOCALIZED: Wooden Bracket", - "block.create.yellow_nixie_tube": "UNLOCALIZED: Yellow Nixie Tube", - "block.create.yellow_sail": "UNLOCALIZED: Yellow Sail", - "block.create.yellow_seat": "UNLOCALIZED: Yellow Seat", - "block.create.yellow_toolbox": "UNLOCALIZED: Yellow Toolbox", - "block.create.yellow_valve_handle": "UNLOCALIZED: Yellow Valve Handle", - "block.create.zinc_block": "UNLOCALIZED: Block of Zinc", - "block.create.zinc_ore": "UNLOCALIZED: Zinc Ore", - - "enchantment.create.capacity": "UNLOCALIZED: Capacity", - "enchantment.create.potato_recovery": "UNLOCALIZED: Potato Recovery", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "UNLOCALIZED: Contraption", - "entity.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", - "entity.create.gantry_contraption": "UNLOCALIZED: Gantry Contraption", - "entity.create.potato_projectile": "UNLOCALIZED: Potato Projectile", - "entity.create.seat": "UNLOCALIZED: Seat", - "entity.create.stationary_contraption": "UNLOCALIZED: Stationary Contraption", - "entity.create.super_glue": "UNLOCALIZED: Super Glue", - - "fluid.create.potion": "UNLOCALIZED: Potion", - "fluid.create.tea": "UNLOCALIZED: Builder's Tea", - - "item.create.andesite_alloy": "UNLOCALIZED: Andesite Alloy", - "item.create.attribute_filter": "UNLOCALIZED: Attribute Filter", - "item.create.bar_of_chocolate": "UNLOCALIZED: Bar of Chocolate", - "item.create.belt_connector": "Mechanische Transportband", - "item.create.blaze_cake": "UNLOCALIZED: Blaze Cake", - "item.create.blaze_cake_base": "UNLOCALIZED: Blaze Cake Base", - "item.create.brass_hand": "UNLOCALIZED: Brass Hand", - "item.create.brass_ingot": "UNLOCALIZED: Brass Ingot", - "item.create.brass_nugget": "Brons klompje", - "item.create.brass_sheet": "Brons Platen", - "item.create.builders_tea": "UNLOCALIZED: Builder's Tea", - "item.create.chest_minecart_contraption": "UNLOCALIZED: Chest Minecart Contraption", - "item.create.chocolate_bucket": "UNLOCALIZED: Chocolate Bucket", - "item.create.chocolate_glazed_berries": "UNLOCALIZED: Chocolate Glazed Berries", - "item.create.chromatic_compound": "UNLOCALIZED: Chromatic Compound", - "item.create.cinder_flour": "UNLOCALIZED: Cinder Flour", - "item.create.copper_backtank": "UNLOCALIZED: Copper Backtank", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Koper klompje", - "item.create.copper_sheet": "UNLOCALIZED: Copper Sheet", - "item.create.crafter_slot_cover": "UNLOCALIZED: Crafter Slot Cover", - "item.create.crafting_blueprint": "UNLOCALIZED: Crafting Blueprint", - "item.create.creative_blaze_cake": "UNLOCALIZED: Creative Blaze Cake", - "item.create.crushed_aluminum_ore": "UNLOCALIZED: Crushed Aluminum Ore", - "item.create.crushed_copper_ore": "UNLOCALIZED: Crushed Copper Ore", - "item.create.crushed_gold_ore": "UNLOCALIZED: Crushed Gold Ore", - "item.create.crushed_iron_ore": "UNLOCALIZED: Crushed Iron Ore", - "item.create.crushed_lead_ore": "UNLOCALIZED: Crushed Lead Ore", - "item.create.crushed_nickel_ore": "UNLOCALIZED: Crushed Nickel Ore", - "item.create.crushed_osmium_ore": "UNLOCALIZED: Crushed Osmium Ore", - "item.create.crushed_platinum_ore": "UNLOCALIZED: Crushed Platinum Ore", - "item.create.crushed_quicksilver_ore": "UNLOCALIZED: Crushed Quicksilver Ore", - "item.create.crushed_silver_ore": "UNLOCALIZED: Crushed Silver Ore", - "item.create.crushed_tin_ore": "UNLOCALIZED: Crushed Tin Ore", - "item.create.crushed_uranium_ore": "UNLOCALIZED: Crushed Uranium Ore", - "item.create.crushed_zinc_ore": "UNLOCALIZED: Crushed Zinc Ore", - "item.create.diving_boots": "UNLOCALIZED: Diving Boots", - "item.create.diving_helmet": "UNLOCALIZED: Diving Helmet", - "item.create.dough": "Deeg", - "item.create.electron_tube": "UNLOCALIZED: Electron Tube", - "item.create.empty_blaze_burner": "UNLOCALIZED: Empty Blaze Burner", - "item.create.empty_schematic": "Lege bouwtekening", - "item.create.experience_nugget": "UNLOCALIZED: Nugget of Experience", - "item.create.extendo_grip": "UNLOCALIZED: Extendo Grip", - "item.create.filter": "Filter", - "item.create.furnace_minecart_contraption": "UNLOCALIZED: Furnace Minecart Contraption", - "item.create.goggles": "Ingenieur's Bril", - "item.create.golden_sheet": "UNLOCALIZED: Golden Sheet", - "item.create.handheld_worldshaper": "UNLOCALIZED: Creative Worldshaper", - "item.create.honey_bucket": "UNLOCALIZED: Honey Bucket", - "item.create.honeyed_apple": "UNLOCALIZED: Honeyed Apple", - "item.create.incomplete_precision_mechanism": "UNLOCALIZED: Incomplete Precision Mechanism", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "IJzeren Platen", - "item.create.linked_controller": "UNLOCALIZED: Linked Controller", - "item.create.minecart_contraption": "UNLOCALIZED: Minecart Contraption", - "item.create.minecart_coupling": "UNLOCALIZED: Minecart Coupling", - "item.create.polished_rose_quartz": "UNLOCALIZED: Polished Rose Quartz", - "item.create.potato_cannon": "UNLOCALIZED: Potato Cannon", - "item.create.powdered_obsidian": "UNLOCALIZED: Powdered Obsidian", - "item.create.precision_mechanism": "UNLOCALIZED: Precision Mechanism", - "item.create.propeller": "Propeller", - "item.create.raw_zinc": "UNLOCALIZED: Raw Zinc", - "item.create.red_sand_paper": "UNLOCALIZED: Red Sand Paper", - "item.create.refined_radiance": "UNLOCALIZED: Refined Radiance", - "item.create.rose_quartz": "Roze Kwarts", - "item.create.sand_paper": "UNLOCALIZED: Sand Paper", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Bouwtekening", - "item.create.schematic_and_quill": "Bouwtekening en Veer", - "item.create.shadow_steel": "UNLOCALIZED: Shadow Steel", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "UNLOCALIZED: Super Glue", - "item.create.sweet_roll": "UNLOCALIZED: Sweet Roll", - "item.create.tree_fertilizer": "Boom mest", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "UNLOCALIZED: Vertical Gearbox", - "item.create.wand_of_symmetry": "Symmetrie Staf", - "item.create.wheat_flour": "UNLOCALIZED: Wheat Flour", - "item.create.whisk": "UNLOCALIZED: Whisk", - "item.create.wrench": "Moersleutel", - "item.create.zinc_ingot": "UNLOCALIZED: Zinc Ingot", - "item.create.zinc_nugget": "Zink Nugget", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "UNLOCALIZED: Welcome to Create", - "advancement.create.root.desc": "UNLOCALIZED: Here Be Contraptions", - "advancement.create.andesite_alloy": "UNLOCALIZED: Sturdier Rocks", - "advancement.create.andesite_alloy.desc": "UNLOCALIZED: Obtain some Andesite Alloy, Create's most important resource", - "advancement.create.andesite_casing": "UNLOCALIZED: The Andesite Age", - "advancement.create.andesite_casing.desc": "UNLOCALIZED: Apply Andesite Alloy to stripped wood, creating a basic casing for your machines", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "UNLOCALIZED: Kelp Drive", - "advancement.create.belt.desc": "UNLOCALIZED: Connect two Shafts with a Mechanical Belt", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "UNLOCALIZED: Vertical Logistics", - "advancement.create.chute.desc": "UNLOCALIZED: Transport some items by Chute", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "UNLOCALIZED: Harnessed Hydraulics", - "advancement.create.water_wheel.desc": "UNLOCALIZED: Place a Water Wheel and use it to generate torque", - "advancement.create.windmill": "UNLOCALIZED: A Mild Breeze", - "advancement.create.windmill.desc": "UNLOCALIZED: Assemble a windmill and use it to generate torque", - "advancement.create.shifting_gears": "UNLOCALIZED: Shifting Gears", - "advancement.create.shifting_gears.desc": "UNLOCALIZED: Connect a Large Cogwheel to a Small Cogwheel, allowing you to change the speed of your Contraption", - "advancement.create.millstone": "UNLOCALIZED: Embrace the Grind", - "advancement.create.millstone.desc": "UNLOCALIZED: Use a Millstone to pulverise materials", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "UNLOCALIZED: Stress for Nerds", - "advancement.create.stressometer.desc": "UNLOCALIZED: Get an exact readout with the help of Engineer's Goggles and a Stressometer", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "UNLOCALIZED: The Parrots and the Flaps", - "advancement.create.belt_funnel_kiss.desc": "UNLOCALIZED: Make two Belt-mounted Funnels kiss§7\n(Hidden Advancement)", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "UNLOCALIZED: The Copper Age", - "advancement.create.copper_casing.desc": "UNLOCALIZED: Apply Copper Ingots to stripped wood, creating a waterproof casing for your machines", - "advancement.create.spout": "UNLOCALIZED: Sploosh", - "advancement.create.spout.desc": "UNLOCALIZED: Watch a fluid-containing item be filled by a Spout", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "UNLOCALIZED: Flow Discovery", - "advancement.create.glass_pipe.desc": "UNLOCALIZED: Use your Wrench on a pipe that contains a fluid", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "UNLOCALIZED: Industrial Spillage", - "advancement.create.hose_pulley.desc": "UNLOCALIZED: Lower a Hose Pulley and watch it drain or fill a body of fluid", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "UNLOCALIZED: Real Alloys", - "advancement.create.brass.desc": "UNLOCALIZED: Create Brass Ingots by alloying Copper and Zinc Ingots in your Blaze-heated Mechanical Mixer", - "advancement.create.brass_casing": "UNLOCALIZED: The Brass Age", - "advancement.create.brass_casing.desc": "UNLOCALIZED: Apply Brass Ingots to stripped wood, creating a casing for more sophisticated machines", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "UNLOCALIZED: Artificial Intelligence", - "advancement.create.deployer.desc": "UNLOCALIZED: Place and power a Deployer, the perfect reflection of yourself", - "advancement.create.precision_mechanism": "UNLOCALIZED: Complex Curiosities", - "advancement.create.precision_mechanism.desc": "UNLOCALIZED: Assemble a Precision Mechanism", - "advancement.create.speed_controller": "UNLOCALIZED: Engineers Hate Him!", - "advancement.create.speed_controller.desc": "UNLOCALIZED: Fine-tune your Contraption with a Rotation Speed Controller", - "advancement.create.mechanical_arm": "UNLOCALIZED: Busy Hands", - "advancement.create.mechanical_arm.desc": "UNLOCALIZED: Watch your Mechanical Arm transport its first item", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "UNLOCALIZED: A Pair of Giants", - "advancement.create.crushing_wheel.desc": "UNLOCALIZED: Place and power a set of Crushing Wheels", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "UNLOCALIZED: Contraption O'Clock", - "advancement.create.clockwork_bearing.desc": "UNLOCALIZED: Assemble a structure mounted on a Clockwork Bearing", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "UNLOCALIZED: Fwoomp!", - "advancement.create.potato_cannon.desc": "UNLOCALIZED: Defeat an enemy with your Potato Cannon", - "advancement.create.extendo_grip": "UNLOCALIZED: Boioioing!", - "advancement.create.extendo_grip.desc": "UNLOCALIZED: Get hold of an Extendo Grip", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "UNLOCALIZED: Combust-o-Tron", - "advancement.create.arm_blaze_burner.desc": "UNLOCALIZED: Instruct a Mechanical Arm to feed your Blaze Burner", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "UNLOCALIZED: Organize-o-Tron", - "advancement.create.arm_many_targets.desc": "UNLOCALIZED: Program a Mechanical Arm with 10 or more output locations", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", - "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump§7\n(Hidden Advancement)", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "UNLOCALIZED: DJ Mechanico", - "advancement.create.musical_arm.desc": "UNLOCALIZED: Watch a Mechanical Arm operate your Jukebox§7\n(Hidden Advancement)", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "UNLOCALIZED: Create", - "itemGroup.create.palettes": "UNLOCALIZED: Create's Building Blocks", - - "death.attack.create.crush": "%1$s is verwerkd door verpulverende wielen", - "death.attack.create.crush.player": "UNLOCALIZED: %1$s was thrown into Crushing Wheels by %2$s", - "death.attack.create.fan_fire": "%1$s is verbrand door hete lucht", - "death.attack.create.fan_fire.player": "UNLOCALIZED: %1$s was thrown into a smoker by %2$s", - "death.attack.create.fan_lava": "%1$s is verbrand door een lava ventilator", - "death.attack.create.fan_lava.player": "UNLOCALIZED: %1$s was thrown into a smelter by %2$s", - "death.attack.create.mechanical_drill": "%1$s is gespietst door een mechanische boor", - "death.attack.create.mechanical_drill.player": "UNLOCALIZED: %1$s was thrown in front of a Drill by %2$s", - "death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by a Mechanical Saw", - "death.attack.create.mechanical_saw.player": "UNLOCALIZED: %1$s was thrown into a Saw by %2$s", - "death.attack.create.potato_cannon": "UNLOCALIZED: %1$s was shot by %2$s's Potato Cannon", - "death.attack.create.potato_cannon.item": "UNLOCALIZED: %1$s was shot by %2$s using %3$s", - "death.attack.create.cuckoo_clock_explosion": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock", - "death.attack.create.cuckoo_clock_explosion.player": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer", - "create.block.cart_assembler.invalid": "UNLOCALIZED: Place your Cart Assembler on a rail block", - - "create.menu.return": "UNLOCALIZED: Return to Menu", - "create.menu.configure": "UNLOCALIZED: Configure...", - "create.menu.ponder_index": "UNLOCALIZED: Ponder Index", - "create.menu.only_ingame": "UNLOCALIZED: Available in the Pause Menu", - "create.menu.report_bugs": "UNLOCALIZED: Report Issues", - "create.menu.support": "UNLOCALIZED: Support Us", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Verpulveren", - "create.recipe.milling": "UNLOCALIZED: Milling", - "create.recipe.fan_washing": "UNLOCALIZED: Bulk Washing", - "create.recipe.fan_washing.fan": "UNLOCALIZED: Fan behind Flowing Water", - "create.recipe.fan_smoking": "UNLOCALIZED: Bulk Smoking", - "create.recipe.fan_smoking.fan": "UNLOCALIZED: Fan behind Fire", - "create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", - "create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", - "create.recipe.fan_blasting": "UNLOCALIZED: Bulk Blasting", - "create.recipe.fan_blasting.fan": "UNLOCALIZED: Fan behind Lava", - "create.recipe.pressing": "Persen", - "create.recipe.mixing": "Mengen", - "create.recipe.deploying": "UNLOCALIZED: Deploying", - "create.recipe.automatic_shapeless": "UNLOCALIZED: Automated Shapeless Crafting", - "create.recipe.automatic_brewing": "UNLOCALIZED: Automated Brewing", - "create.recipe.packing": "Compressen", - "create.recipe.automatic_packing": "UNLOCALIZED: Automated Packing", - "create.recipe.sawing": "UNLOCALIZED: Sawing", - "create.recipe.mechanical_crafting": "UNLOCALIZED: Mechanical Crafting", - "create.recipe.automatic_shaped": "UNLOCALIZED: Automated Shaped Crafting", - "create.recipe.block_cutting": "Blok Zagen", - "create.recipe.wood_cutting": "UNLOCALIZED: Wood Cutting", - "create.recipe.sandpaper_polishing": "UNLOCALIZED: Sandpaper Polishing", - "create.recipe.mystery_conversion": "UNLOCALIZED: Mysterious Conversion", - "create.recipe.spout_filling": "UNLOCALIZED: Filling by Spout", - "create.recipe.draining": "UNLOCALIZED: Item Draining", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "UNLOCALIZED: Recipe Sequence", - "create.recipe.assembly.next": "UNLOCALIZED: Next: %1$s", - "create.recipe.assembly.step": "UNLOCALIZED: Step %1$s:", - "create.recipe.assembly.progress": "UNLOCALIZED: Progress: %1$s/%2$s", - "create.recipe.assembly.pressing": "UNLOCALIZED: Process in Press", - "create.recipe.assembly.spout_filling_fluid": "UNLOCALIZED: Spout %1$s", - "create.recipe.assembly.deploying_item": "UNLOCALIZED: Deploy %1$s", - "create.recipe.assembly.cutting": "UNLOCALIZED: Cut with Saw", - "create.recipe.assembly.repeat": "UNLOCALIZED: Repeat Sequence %1$s Times", - "create.recipe.assembly.junk": "UNLOCALIZED: Random salvage", - "create.recipe.processing.chance": "%1$s%% Kans", - "create.recipe.deploying.not_consumed": "UNLOCALIZED: Not Consumed", - "create.recipe.heat_requirement.none": "UNLOCALIZED: No Heating Required", - "create.recipe.heat_requirement.heated": "UNLOCALIZED: Heated", - "create.recipe.heat_requirement.superheated": "UNLOCALIZED: Super-Heated", - - "create.generic.range": "Omvang", - "create.generic.radius": "Radius", - "create.generic.width": "UNLOCALIZED: Width", - "create.generic.height": "UNLOCALIZED: Height", - "create.generic.length": "UNLOCALIZED: Length", - "create.generic.speed": "Snelheid", - "create.generic.delay": "Vertraging", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Seconden", - "create.generic.unit.minutes": "Minuten", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "UNLOCALIZED: RPM", - "create.generic.unit.stress": "UNLOCALIZED: su", - "create.generic.unit.degrees": "UNLOCALIZED: °", - "create.generic.unit.millibuckets": "UNLOCALIZED: mB", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "UNLOCALIZED: Clockwise", - "create.generic.counter_clockwise": "UNLOCALIZED: Counter-Clockwise", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Scroll", - "create.action.confirm": "Bevestigen", - "create.action.abort": "Afbreken", - "create.action.saveToFile": "Opslaan", - "create.action.discard": "Weggooien", - - "create.keyinfo.toolmenu": "Focus Gereedschap Menu", - "create.keyinfo.toolbelt": "UNLOCALIZED: Access Nearby Toolboxes", - "create.keyinfo.scrollup": "UNLOCALIZED: Simulate Mousewheel Up (inworld)", - "create.keyinfo.scrolldown": "UNLOCALIZED: Simulate Mousewheel Down (inworld)", - - "create.gui.scrollInput.defaultTitle": "Kies een optie:", - "create.gui.scrollInput.scrollToModify": "Scroll om aan te passen", - "create.gui.scrollInput.scrollToAdjustAmount": "UNLOCALIZED: Scroll to Adjust Amount", - "create.gui.scrollInput.scrollToSelect": "Scroll om te selecteren", - "create.gui.scrollInput.shiftScrollsFaster": "Shift om sneller te Scrollen", - "create.gui.toolmenu.focusKey": "Hou [%1$s] ingedrukt om te Focusen", - "create.gui.toolmenu.cycle": "[SCROLL] om te Cycleën", - - "create.toolbox.unequip": "UNLOCALIZED: Unequip: %1$s", - "create.toolbox.outOfRange": "UNLOCALIZED: Toolbox of held item not in Range", - "create.toolbox.detach": "UNLOCALIZED: Stop tracking and keep item", - "create.toolbox.depositAll": "UNLOCALIZED: Return items to nearby Toolboxes", - "create.toolbox.depositBox": "UNLOCALIZED: Return items to Toolbox", - - "create.gui.symmetryWand.mirrorType": "Spiegelen", - "create.gui.symmetryWand.orientation": "Orientatie", - - "create.symmetry.mirror.plane": "Spiegel één keer", - "create.symmetry.mirror.doublePlane": "Rechthoekig", - "create.symmetry.mirror.triplePlane": "Achthoekig", - - "create.orientation.orthogonal": "Orthogonaal", - "create.orientation.diagonal": "Diagonaal", - "create.orientation.horizontal": "Horizontaal", - "create.orientation.alongZ": "Langs Z-as", - "create.orientation.alongX": "Langs X-as", - - "create.gui.terrainzapper.title": "UNLOCALIZED: Handheld Blockzapper", - "create.gui.terrainzapper.searchDiagonal": "UNLOCALIZED: Follow Diagonals", - "create.gui.terrainzapper.searchFuzzy": "UNLOCALIZED: Ignore Material Borders", - "create.gui.terrainzapper.patternSection": "UNLOCALIZED: Pattern", - "create.gui.terrainzapper.pattern.solid": "UNLOCALIZED: Solid", - "create.gui.terrainzapper.pattern.checkered": "UNLOCALIZED: Checkerboard", - "create.gui.terrainzapper.pattern.inversecheckered": "UNLOCALIZED: Inverted Checkerboard", - "create.gui.terrainzapper.pattern.chance25": "UNLOCALIZED: 25% Roll", - "create.gui.terrainzapper.pattern.chance50": "UNLOCALIZED: 50% Roll", - "create.gui.terrainzapper.pattern.chance75": "UNLOCALIZED: 75% Roll", - "create.gui.terrainzapper.placement": "UNLOCALIZED: Placement", - "create.gui.terrainzapper.placement.merged": "UNLOCALIZED: Merged", - "create.gui.terrainzapper.placement.attached": "UNLOCALIZED: Attached", - "create.gui.terrainzapper.placement.inserted": "UNLOCALIZED: Inserted", - "create.gui.terrainzapper.brush": "UNLOCALIZED: Brush", - "create.gui.terrainzapper.brush.cuboid": "UNLOCALIZED: Cuboid", - "create.gui.terrainzapper.brush.sphere": "UNLOCALIZED: Sphere", - "create.gui.terrainzapper.brush.cylinder": "UNLOCALIZED: Cylinder", - "create.gui.terrainzapper.brush.surface": "UNLOCALIZED: Surface", - "create.gui.terrainzapper.brush.cluster": "UNLOCALIZED: Cluster", - "create.gui.terrainzapper.tool": "UNLOCALIZED: Tool", - "create.gui.terrainzapper.tool.fill": "UNLOCALIZED: Fill", - "create.gui.terrainzapper.tool.place": "UNLOCALIZED: Place", - "create.gui.terrainzapper.tool.replace": "UNLOCALIZED: Replace", - "create.gui.terrainzapper.tool.clear": "UNLOCALIZED: Clear", - "create.gui.terrainzapper.tool.overlay": "UNLOCALIZED: Overlay", - "create.gui.terrainzapper.tool.flatten": "UNLOCALIZED: Flatten", - - "create.terrainzapper.shiftRightClickToSet": "UNLOCALIZED: Shift-Right-Click to Select a Shape", - "create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s", - "create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material", - - "create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each", - "create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks", - "create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop", - "create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart", - "create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart", - - "create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode", - "create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped", - "create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position", - "create.contraptions.movement_mode.move_never_place": "UNLOCALIZED: Place only when Anchor Destroyed", - "create.contraptions.movement_mode.rotate_place": "UNLOCALIZED: Always Place when Stopped", - "create.contraptions.movement_mode.rotate_place_returned": "UNLOCALIZED: Only Place near Initial Angle", - "create.contraptions.movement_mode.rotate_never_place": "UNLOCALIZED: Only Place when Anchor Destroyed", - "create.contraptions.cart_movement_mode": "UNLOCALIZED: Cart Movement Mode", - "create.contraptions.cart_movement_mode.rotate": "UNLOCALIZED: Always face toward motion", - "create.contraptions.cart_movement_mode.rotate_paused": "UNLOCALIZED: Pause actors while rotating", - "create.contraptions.cart_movement_mode.rotation_locked": "UNLOCALIZED: Lock rotation", - "create.contraptions.windmill.rotation_direction": "UNLOCALIZED: Rotation Direction", - "create.contraptions.clockwork.clock_hands": "UNLOCALIZED: Clock Hands", - "create.contraptions.clockwork.hour_first": "UNLOCALIZED: Hour hand first", - "create.contraptions.clockwork.minute_first": "UNLOCALIZED: Minute hand first", - "create.contraptions.clockwork.hour_first_24": "UNLOCALIZED: 24-Hour hand first", - - "create.logistics.filter": "Filter", - "create.logistics.recipe_filter": "UNLOCALIZED: Recipe Filter", - "create.logistics.fluid_filter": "UNLOCALIZED: Fluid Filter", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "UNLOCALIZED: Applied filter to %1$s.", - "create.logistics.filter.apply_click_again": "UNLOCALIZED: Applied filter to %1$s, click again to copy the amount.", - "create.logistics.filter.apply_count": "UNLOCALIZED: Applied extraction count to filter.", - - "create.gui.goggles.generator_stats": "UNLOCALIZED: Generator Stats:", - "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", - "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", - "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", - "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", - "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", - "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", - "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", - "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", - "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", - "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", - "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", - "create.gui.stressometer.capacity": "UNLOCALIZED: Remaining Capacity", - "create.gui.stressometer.overstressed": "UNLOCALIZED: Overstressed", - "create.gui.stressometer.no_rotation": "UNLOCALIZED: No Rotation", - "create.gui.contraptions.not_fast_enough": "UNLOCALIZED: It appears that this %1$s is _not_ rotating with _enough_ _speed_.", - "create.gui.contraptions.network_overstressed": "UNLOCALIZED: It appears that this contraption is _overstressed_. Add more sources or _slow_ _down_ the components with a high _stress_ _impact_.", - "create.gui.adjustable_crate.title": "FlexKrat", - "create.gui.adjustable_crate.storageSpace": "Opslagruimte", - "create.gui.stockpile_switch.title": "Voorraad Schakelaar", - "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", - "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", - "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", - "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "UNLOCALIZED: Turn by angle", - "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "UNLOCALIZED: Angle", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "UNLOCALIZED: Turn to move Piston/Pulley/Gantry", - "create.gui.sequenced_gearshift.instruction.turn_distance": "UNLOCALIZED: Piston", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "UNLOCALIZED: Distance", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "UNLOCALIZED: Timed Delay", - "create.gui.sequenced_gearshift.instruction.delay": "UNLOCALIZED: Delay", - "create.gui.sequenced_gearshift.instruction.delay.duration": "UNLOCALIZED: Duration", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "UNLOCALIZED: End", - "create.gui.sequenced_gearshift.instruction.end": "UNLOCALIZED: End", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "UNLOCALIZED: Await new Redstone Pulse", - "create.gui.sequenced_gearshift.instruction.await": "UNLOCALIZED: Await", - "create.gui.sequenced_gearshift.speed": "UNLOCALIZED: Speed, Direction", - "create.gui.sequenced_gearshift.speed.forward": "UNLOCALIZED: Input speed, Forwards", - "create.gui.sequenced_gearshift.speed.forward_fast": "UNLOCALIZED: Double speed, Forwards", - "create.gui.sequenced_gearshift.speed.back": "UNLOCALIZED: Input speed, Reversed", - "create.gui.sequenced_gearshift.speed.back_fast": "UNLOCALIZED: Double speed, Reversed", - - "create.schematicAndQuill.dimensions": "Bouwtekening Groote: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Eerste positie ingesteld.", - "create.schematicAndQuill.secondPos": "Tweede positie ingesteld.", - "create.schematicAndQuill.noTarget": "Houd [Ctrl] ingedrukt om een Lucht block te kiezen.", - "create.schematicAndQuill.abort": "Keuze verwijderd.", - "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", - "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Upload Immediately", - "create.schematicAndQuill.fallbackName": "Mijn Bouwtekening", - "create.schematicAndQuill.saved": "Opgeslagen als %1$s", - - "create.schematic.invalid": "[!] Invalide object - Gebruik inplaats hiervan de Bouwtekening Tafel", - "create.schematic.position": "Positie", - "create.schematic.rotation": "Rotatie", - "create.schematic.rotation.none": "Geen", - "create.schematic.rotation.cw90": "Met de klok mee 90", - "create.schematic.rotation.cw180": "Met de klok mee 180", - "create.schematic.rotation.cw270": "Met de klok mee 270", - "create.schematic.mirror": "Spiegel", - "create.schematic.mirror.none": "Geen", - "create.schematic.mirror.frontBack": "Voor naar achter", - "create.schematic.mirror.leftRight": "Links naar rechts", - "create.schematic.tool.deploy": "Inzetten", - "create.schematic.tool.move": "Verplaats XZ", - "create.schematic.tool.movey": "Verplaats Y", - "create.schematic.tool.rotate": "Draai", - "create.schematic.tool.print": "Print", - "create.schematic.tool.flip": "Omdraaien", - "create.schematic.tool.deploy.description.0": "Verplaatst de structuur naar een locatie.", - "create.schematic.tool.deploy.description.1": "Klik met rechts op de grond om te plaatsen.", - "create.schematic.tool.deploy.description.2": "Houd [Ctrl] ingedrukt om op een afstand te selecteren.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Scroll om de afstand te veranderen.", - "create.schematic.tool.move.description.0": "Verschuift de Bouwtekening Horizontaal", - "create.schematic.tool.move.description.1": "Wijs naar de Bouwtekening and [CTRL]-Scroll om hem te duwen.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Verschuift de Bouwtekening Verticaal", - "create.schematic.tool.movey.description.1": "[CTRL]-Scroll om het omhoog/omlaag te bewegen", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Draait de Bouwtekening om zijn midden..", - "create.schematic.tool.rotate.description.1": "[CTRL]-Scroll om te draaien met 90 graden", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Plaats onmiddelijk de structuur in de wereld.", - "create.schematic.tool.print.description.1": "Klik met rechts om het plaatsen in de wereld te bevestigen.", - "create.schematic.tool.print.description.2": "Deze tool is alleen voor de creatieve modus.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Hiermee draait u de Bouwtekening langs het gezicht dat u selecteert.", - "create.schematic.tool.flip.description.1": "Wijs naar de Bouwtekening en [CTRL]-Scroll om hem om te draaien.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Synchroniseren...", - "create.schematics.uploadTooLarge": "Jouw Bouwtekening is te groot!", - "create.schematics.maxAllowedSize": "De maximum toegestane grote van een Bouwtekings bestand is:", - - "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", - "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", - "create.gui.schematicTable.title": "Bouwtekening Tafel", - "create.gui.schematicTable.availableSchematics": "Beschikbare Bouwtekeningen", - "create.gui.schematicTable.noSchematics": "Geen Bouwtekeningen opgeslagen", - "create.gui.schematicTable.uploading": "Uploaden...", - "create.gui.schematicTable.finished": "Upload Klaar!", - "create.gui.schematicannon.title": "Bouwtekeningkannon", - "create.gui.schematicannon.listPrinter": "Materiaal lijst Printer", - "create.gui.schematicannon.gunpowderLevel": "Buskruit op %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Schoten over: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Met backup: %1$s", - "create.gui.schematicannon.optionEnabled": "Momenteel Ingeschakeld", - "create.gui.schematicannon.optionDisabled": "Momenteel Uitgeschakeld", - "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", - "create.gui.schematicannon.option.dontReplaceSolid": "Niet vaste blokken vervangen", - "create.gui.schematicannon.option.replaceWithSolid": "Vervang vast met vast", - "create.gui.schematicannon.option.replaceWithAny": "Vervang vast met alles", - "create.gui.schematicannon.option.replaceWithEmpty": "Vervang vast met leeg", - "create.gui.schematicannon.option.skipMissing": "Sla missende blokken over", - "create.gui.schematicannon.option.skipTileEntities": "Bescherm Tile Entities", - "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", - "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", - "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", - "create.gui.schematicannon.option.skipMissing.description": "Als het Bouwtekeningkannon niet een geschikt blok kan vinden om te plaatsen gaat hij door bij de volgende locatie.", - "create.gui.schematicannon.option.skipTileEntities.description": "Het Bouwtekeningkannon probeert blokken met data zoals kisten te vermijden", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Het Bouwtekeningkannon zal nooit vaste blokken in zijn gebied vervangen, alleen niet-vaste blokken en lucht", - "create.gui.schematicannon.option.replaceWithSolid.description": "Het Bouwtekeningkannon zal alleen vaste blokken in zijn gebied veranderen, als de bouwtekening een vast blok bevat op zijn locatie.", - "create.gui.schematicannon.option.replaceWithAny.description": "Het Bouwtekeningkannon zal vaste blokken in zijn gebied vervangen als, de bouwtekening een blok op bevat op zijn locatie.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Het Bouwtekeningkannon zal alle blokken in zijn gebied vervangen, inclusief blokken vervangen door lucht.", - - "create.schematicannon.status.idle": "IJdel", - "create.schematicannon.status.ready": "Paraat", - "create.schematicannon.status.running": "Draaiend", - "create.schematicannon.status.finished": "Klaar", - "create.schematicannon.status.paused": "Gepauzeerd", - "create.schematicannon.status.stopped": "Gestopt", - "create.schematicannon.status.noGunpowder": "Buskruit op", - "create.schematicannon.status.targetNotLoaded": "Blok is niet geladen", - "create.schematicannon.status.targetOutsideRange": "Doel is te ver weg", - "create.schematicannon.status.searching": "Aan het zoeken", - "create.schematicannon.status.skipping": "Aan het overslaan", - "create.schematicannon.status.missingBlock": "Missende Blok:", - "create.schematicannon.status.placing": "Aan het plaatsen", - "create.schematicannon.status.clearing": "Blokken aan het verwijderen", - "create.schematicannon.status.schematicInvalid": "Bouwtekening niet valide", - "create.schematicannon.status.schematicNotPlaced": "Bouwtekening niet geplaatst", - "create.schematicannon.status.schematicExpired": "Bouwtekening verlopen", - - "create.materialChecklist": "UNLOCALIZED: Material Checklist", - "create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", - - "create.gui.filter.deny_list": "UNLOCALIZED: Deny-List", - "create.gui.filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT match any of the above. An empty Deny-List accepts everything.", - "create.gui.filter.allow_list": "UNLOCALIZED: Allow-List", - "create.gui.filter.allow_list.description": "UNLOCALIZED: Items pass if they match any of the above. An empty Allow-List rejects everything.", - "create.gui.filter.respect_data": "UNLOCALIZED: Respect Data", - "create.gui.filter.respect_data.description": "UNLOCALIZED: Items only match if their durability, enchantments, and other attributes match as well.", - "create.gui.filter.ignore_data": "UNLOCALIZED: Ignore Data", - "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", - - "create.item_attributes.placeable": "UNLOCALIZED: is placeable", - "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", - "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", - "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", - "create.item_attributes.fluid_container": "UNLOCALIZED: can store fluids", - "create.item_attributes.fluid_container.inverted": "UNLOCALIZED: cannot store fluids", - "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", - "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", - "create.item_attributes.max_enchanted": "UNLOCALIZED: is enchanted at max level", - "create.item_attributes.max_enchanted.inverted": "UNLOCALIZED: is not enchanted at max level", - "create.item_attributes.renamed": "UNLOCALIZED: has a custom name", - "create.item_attributes.renamed.inverted": "UNLOCALIZED: does not have a custom name", - "create.item_attributes.damaged": "UNLOCALIZED: is damaged", - "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", - "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", - "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", - "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", - "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", - "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", - "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", - "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", - "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", - "create.item_attributes.washable": "UNLOCALIZED: can be Washed", - "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", - "create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", - "create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", - "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", - "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", - "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", - "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", - "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", - "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", - "create.item_attributes.blastable": "UNLOCALIZED: can be Smelted in a Blast Furnace", - "create.item_attributes.blastable.inverted": "UNLOCALIZED: cannot be Smelted in a Blast Furnace", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "UNLOCALIZED: is shulker %1$s", - "create.item_attributes.shulker_level.inverted": "UNLOCALIZED: is shulker not %1$s", - "create.item_attributes.shulker_level.full": "UNLOCALIZED: full", - "create.item_attributes.shulker_level.empty": "UNLOCALIZED: empty", - "create.item_attributes.shulker_level.partial": "UNLOCALIZED: partially filled", - "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", - "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", - "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", - "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", - "create.item_attributes.has_enchant": "UNLOCALIZED: is enchanted with %1$s", - "create.item_attributes.has_enchant.inverted": "UNLOCALIZED: is not enchanted with %1$s", - "create.item_attributes.color": "UNLOCALIZED: is dyed %1$s", - "create.item_attributes.color.inverted": "UNLOCALIZED: is not dyed %1$s", - "create.item_attributes.has_fluid": "UNLOCALIZED: contains %1$s", - "create.item_attributes.has_fluid.inverted": "UNLOCALIZED: does not contain %1$s", - "create.item_attributes.has_name": "UNLOCALIZED: has the custom name %1$s", - "create.item_attributes.has_name.inverted": "UNLOCALIZED: does not have the custom name %1$s", - "create.item_attributes.book_author": "UNLOCALIZED: was authored by %1$s", - "create.item_attributes.book_author.inverted": "UNLOCALIZED: was not authored by %1$s", - "create.item_attributes.book_copy_original": "UNLOCALIZED: is an original", - "create.item_attributes.book_copy_original.inverted": "UNLOCALIZED: is not an original", - "create.item_attributes.book_copy_first": "UNLOCALIZED: is a first-generation copy", - "create.item_attributes.book_copy_first.inverted": "UNLOCALIZED: is not a first-generation copy", - "create.item_attributes.book_copy_second": "UNLOCALIZED: is a second-generation copy", - "create.item_attributes.book_copy_second.inverted": "UNLOCALIZED: is not a second-generation copy", - "create.item_attributes.book_copy_tattered": "UNLOCALIZED: is a tattered mess", - "create.item_attributes.book_copy_tattered.inverted": "UNLOCALIZED: is not a tattered mess", - "create.item_attributes.astralsorcery_amulet": "UNLOCALIZED: improves %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "UNLOCALIZED: does not improve %1$s", - "create.item_attributes.astralsorcery_constellation": "UNLOCALIZED: is attuned to %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "UNLOCALIZED: is not attuned to %1$s", - "create.item_attributes.astralsorcery_crystal": "UNLOCALIZED: has crystal attribute %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "UNLOCALIZED: does not have crystal attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem": "UNLOCALIZED: has perk attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "UNLOCALIZED: does not have perk attribute %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", - "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", - "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", - "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", - "create.gui.attribute_filter.allow_list_disjunctive": "UNLOCALIZED: Allow-List (Any)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", - "create.gui.attribute_filter.allow_list_conjunctive": "UNLOCALIZED: Allow-List (All)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "UNLOCALIZED: Items pass only if they have ALL of the selected attributes.", - "create.gui.attribute_filter.deny_list": "UNLOCALIZED: Deny-List", - "create.gui.attribute_filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT have any of the selected attributes.", - "create.gui.attribute_filter.add_reference_item": "UNLOCALIZED: Add Reference Item", - - "create.tooltip.holdForDescription": "UNLOCALIZED: Hold [%1$s] for Summary", - "create.tooltip.holdForControls": "UNLOCALIZED: Hold [%1$s] for Controls", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Snelheid eis: %1$s", - "create.tooltip.speedRequirement.none": "Geen", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "Gemiddeld", - "create.tooltip.speedRequirement.fast": "Snel", - "create.tooltip.stressImpact": "Stress Impact: %1$s", - "create.tooltip.stressImpact.low": "Laag", - "create.tooltip.stressImpact.medium": "Gemiddeld", - "create.tooltip.stressImpact.high": "Hoog", - "create.tooltip.stressImpact.overstressed": "UNLOCALIZED: Overstressed", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Stress Capacity: %1$s", - "create.tooltip.capacityProvided.low": "Klein", - "create.tooltip.capacityProvided.medium": "Gemiddeld", - "create.tooltip.capacityProvided.high": "Groot", - "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", - "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", - - "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", - "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", - "create.mechanical_arm.summary": "UNLOCALIZED: Mechanical Arm has %1$s input(s) and %2$s output(s).", - "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", - - "create.weighted_ejector.target_set": "UNLOCALIZED: Target Selected", - "create.weighted_ejector.target_not_valid": "UNLOCALIZED: Ejecting to Adjacent block (Target was not Valid)", - "create.weighted_ejector.no_target": "UNLOCALIZED: Ejecting to Adjacent block (No Target was Selected)", - "create.weighted_ejector.targeting": "UNLOCALIZED: Ejecting to [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "UNLOCALIZED: Ejected Stack Size", - - "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", - - "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.mechanical_arm.selection_mode.prefer_first": "UNLOCALIZED: Prefer First Target", - - "create.tunnel.selection_mode.split": "UNLOCALIZED: Split", - "create.tunnel.selection_mode.forced_split": "UNLOCALIZED: Forced Split", - "create.tunnel.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", - "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", - "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", - - "create.tooltip.chute.header": "UNLOCALIZED: Chute Information", - "create.tooltip.chute.items_move_down": "UNLOCALIZED: Items move Downward", - "create.tooltip.chute.items_move_up": "UNLOCALIZED: Items move Upward", - "create.tooltip.chute.no_fans_attached": "UNLOCALIZED: No attached fans", - "create.tooltip.chute.fans_push_up": "UNLOCALIZED: Fans push from Below", - "create.tooltip.chute.fans_push_down": "UNLOCALIZED: Fans push from Above", - "create.tooltip.chute.fans_pull_up": "UNLOCALIZED: Fans pull from Above", - "create.tooltip.chute.fans_pull_down": "UNLOCALIZED: Fans pull from Below", - "create.tooltip.chute.contains": "UNLOCALIZED: Contains: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "UNLOCALIZED: Currently distributing:", - "create.tooltip.brass_tunnel.contains_entry": "UNLOCALIZED: > %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "UNLOCALIZED: Right-Click to retrieve", - - "create.linked_controller.bind_mode": "UNLOCALIZED: Bind mode active", - "create.linked_controller.press_keybind": "UNLOCALIZED: Press %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, to bind this frequency to the respective key", - "create.linked_controller.key_bound": "UNLOCALIZED: Frequency bound to %1$s", - "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", - "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", - "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", - "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", - "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", - "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", - "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", - - "create.potato_cannon.ammo.attack_damage": "UNLOCALIZED: %1$s Attack Damage", - "create.potato_cannon.ammo.reload_ticks": "UNLOCALIZED: %1$s Reload Ticks", - "create.potato_cannon.ammo.knockback": "UNLOCALIZED: %1$s Knockback", - - "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", - "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", - "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", - "create.hint.mechanical_arm_no_targets": "UNLOCALIZED: It appears this _Mechanical_ _Arm_ has not been assigned any _targets._ Select belts, depots, funnels and other blocks by _right-clicking_ them while _holding_ the _Mechanical_ _Arm_ in your _hand_.", - "create.hint.empty_bearing.title": "UNLOCALIZED: Update Bearing", - "create.hint.empty_bearing": "UNLOCALIZED: _Right-click_ the bearing with an _empty_ _hand_ to _attach_ the structure you just built in front of it.", - "create.hint.full_deployer.title": "UNLOCALIZED: Deployer Item Overflow", - "create.hint.full_deployer": "UNLOCALIZED: It appears this _Deployer_ contains _excess_ _items_ that need to be _extracted._ Use a _hopper,_ _funnel_ or other means to free it from its overflow.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", - "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", - "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", - "create.gui.config.overlay4": "UNLOCALIZED: to move this preview", - "create.gui.config.overlay5": "UNLOCALIZED: Press ESC to exit this screen", - "create.gui.config.overlay6": "UNLOCALIZED: and save the new position", - "create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset", - "create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position", - - "create.command.killTPSCommand": "UNLOCALIZED: killtps", - "create.command.killTPSCommand.status.slowed_by.0": "UNLOCALIZED: [Create]: Server tick is currently slowed by %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "UNLOCALIZED: [Create]: Server tick is slowed by %s ms now >:)", - "create.command.killTPSCommand.status.slowed_by.2": "UNLOCALIZED: [Create]: Server tick is back to regular speed :D", - "create.command.killTPSCommand.status.usage.0": "UNLOCALIZED: [Create]: use /killtps stop to bring back server tick to regular speed", - "create.command.killTPSCommand.status.usage.1": "UNLOCALIZED: [Create]: use /killtps start to artificially slow down the server tick", - "create.command.killTPSCommand.argument.tickTime": "UNLOCALIZED: tickTime", - - "create.contraption.minecart_contraption_too_big": "UNLOCALIZED: This Cart Contraption seems too big to pick up", - "create.contraption.minecart_contraption_illegal_pickup": "UNLOCALIZED: A mystical force is binding this Cart Contraption to the world", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "UNLOCALIZED: Contraption stops", - "create.subtitle.peculiar_bell_use": "UNLOCALIZED: Peculiar Bell tolls", - "create.subtitle.worldshaper_place": "UNLOCALIZED: Worldshaper zaps", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.schematicannon_finish": "UNLOCALIZED: Schematicannon dings", - "create.subtitle.crafter_craft": "UNLOCALIZED: Crafter crafts", - "create.subtitle.wrench_remove": "UNLOCALIZED: Component breaks", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "UNLOCALIZED: Cogwheels rumble", - "create.subtitle.slime_added": "UNLOCALIZED: Slime squishes", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "UNLOCALIZED: Schematicannon fires", - "create.subtitle.controller_take": "UNLOCALIZED: Lectern empties", - "create.subtitle.crafter_click": "UNLOCALIZED: Crafter clicks", - "create.subtitle.depot_plop": "UNLOCALIZED: Item lands", - "create.subtitle.confirm": "UNLOCALIZED: Affirmative ding", - "create.subtitle.mixing": "UNLOCALIZED: Mixing noises", - "create.subtitle.mechanical_press_activation_belt": "UNLOCALIZED: Mechanical Press bonks", - "create.subtitle.fwoomp": "UNLOCALIZED: Potato Launcher fwoomps", - "create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", - "create.subtitle.crushing_1": "UNLOCALIZED: Crushing noises", - "create.subtitle.depot_slide": "UNLOCALIZED: Item slides", - "create.subtitle.blaze_munch": "UNLOCALIZED: Blaze Burner munches", - "create.subtitle.funnel_flap": "UNLOCALIZED: Funnel flaps", - "create.subtitle.haunted_bell_use": "UNLOCALIZED: Haunted Bell tolls", - "create.subtitle.scroll_value": "UNLOCALIZED: Scroll-input clicks", - "create.subtitle.controller_put": "UNLOCALIZED: Controller thumps", - "create.subtitle.cranking": "UNLOCALIZED: Hand Crank turns", - "create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", - "create.subtitle.wrench_rotate": "UNLOCALIZED: Wrench used", - "create.subtitle.potato_hit": "UNLOCALIZED: Vegetable impacts", - "create.subtitle.saw_activate_wood": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "UNLOCALIZED: Haunted Bell awakens", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "UNLOCALIZED: Declining boop", - "create.subtitle.controller_click": "UNLOCALIZED: Controller clicks", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "UNLOCALIZED: Diving equipment clinks", - "create.subtitle.mechanical_press_activation": "UNLOCALIZED: Mechanical Press clangs", - "create.subtitle.contraption_assemble": "UNLOCALIZED: Contraption moves", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "UNLOCALIZED: WOODEN BRACKET", - "block.create.wooden_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with a cozy and wooden bit of reinforcement.", - - "block.create.metal_bracket.tooltip": "UNLOCALIZED: METAL BRACKET", - "block.create.metal_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with an industrial and sturdy bit of reinforcement.", - - "block.create.seat.tooltip": "UNLOCALIZED: SEAT", - "block.create.seat.tooltip.summary": "UNLOCALIZED: Sit yourself down and enjoy the ride! Will anchor a player onto a moving _contraption_. Great for static furniture too! Comes in a variety of colours.", - "block.create.seat.tooltip.condition1": "UNLOCALIZED: Right click on Seat", - "block.create.seat.tooltip.behaviour1": "UNLOCALIZED: Sits the player on the _Seat_. Press L-shift to leave the _Seat_.", - - "item.create.blaze_cake.tooltip": "UNLOCALIZED: BLAZE CAKE", - "item.create.blaze_cake.tooltip.summary": "UNLOCALIZED: A Delicious treat for your hard-working _Blaze Burners_. Gets them all fired up!", - - "item.create.wand_of_symmetry.tooltip": "SYMMETRIE STAF", - "item.create.wand_of_symmetry.tooltip.summary": "Spiegelt uw blokplaatsing perfect over de geconfigureerde vlakken.", - "item.create.wand_of_symmetry.tooltip.condition1": "Waneer in de Actiebalk", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Blijft actief", - "item.create.wand_of_symmetry.tooltip.control1": "R-Klik op de Grond", - "item.create.wand_of_symmetry.tooltip.action1": "_Creëerd_ of _Beweegt_ de Spiegel", - "item.create.wand_of_symmetry.tooltip.control2": "R-Klik in de Lucht", - "item.create.wand_of_symmetry.tooltip.action2": "_Verwijderd_ de actieve Spiegel", - "item.create.wand_of_symmetry.tooltip.control3": "R-Klik terwijl je Sluipt", - "item.create.wand_of_symmetry.tooltip.action3": "Opent de _Configuratie_ _Interface_", - - "item.create.handheld_worldshaper.tooltip": "UNLOCALIZED: HANDHELD WORLDSHAPER", - "item.create.handheld_worldshaper.tooltip.summary": "UNLOCALIZED: Handy tool for creating _landscapes_ and _terrain features_.", - "item.create.handheld_worldshaper.tooltip.control1": "UNLOCALIZED: L-Click at Block", - "item.create.handheld_worldshaper.tooltip.action1": "UNLOCALIZED: Sets blocks placed by the tool to the targeted block.", - "item.create.handheld_worldshaper.tooltip.control2": "UNLOCALIZED: R-Click at Block", - "item.create.handheld_worldshaper.tooltip.action2": "UNLOCALIZED: Applies the currently selected _Brush_ and _Tool_ at the targeted location.", - "item.create.handheld_worldshaper.tooltip.control3": "UNLOCALIZED: R-Click while Sneaking", - "item.create.handheld_worldshaper.tooltip.action3": "UNLOCALIZED: Opens the _Configuration Interface_", - - "item.create.tree_fertilizer.tooltip": "BOOM MEST", - "item.create.tree_fertilizer.tooltip.summary": "Een krachtige combinatie van mineralen geschikt voor de meest voorkomende typen bomen.", - "item.create.tree_fertilizer.tooltip.condition1": "Wanneer gebruikt op Kiemplanten", - "item.create.tree_fertilizer.tooltip.behaviour1": "Groeit bomen onafhankelijk van beschikbare ruimte", - - "item.create.extendo_grip.tooltip": "UNLOCALIZED: EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "UNLOCALIZED: Boioioing! Greatly _increases reach distance_ of the wielder. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.extendo_grip.tooltip.condition1": "UNLOCALIZED: When in Off-Hand", - "item.create.extendo_grip.tooltip.behaviour1": "UNLOCALIZED: Increases _reach distance_ of items used in the _Main-Hand_.", - "item.create.extendo_grip.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.extendo_grip.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.potato_cannon.tooltip": "UNLOCALIZED: POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "UNLOCALIZED: Fwoomp! Launch your home-grown vegetables at your Enemies. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.potato_cannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "item.create.potato_cannon.tooltip.behaviour1": "UNLOCALIZED: _Shoots_ a suitable item from your _Inventory_.", - "item.create.potato_cannon.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.potato_cannon.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.filter.tooltip": "UNLOCALIZED: FILTER", - "item.create.filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of items_ or several _nested filters_.", - "item.create.filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.attribute_filter.tooltip": "UNLOCALIZED: ATTRIBUTE FILTER", - "item.create.attribute_filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of_ item _attributes_ and _categories_.", - "item.create.attribute_filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.attribute_filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.attribute_filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.attribute_filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.empty_schematic.tooltip": "LEGE BOUWTEKENING", - "item.create.empty_schematic.tooltip.summary": "Bruikbaar als ingredient in recepten en voor het schrijven aan de _BOUWTEKENING_ _TAFEL._", - - "item.create.schematic.tooltip": "BOUWTEKENING", - "item.create.schematic.tooltip.summary": "Bevat een structuur die gepositioneerd en geplaatst van worden in de wereld. Positineer het Hologram als gewilt en gebruik een _BOUWTEKENINGKANNON_ om het te bouwen.", - "item.create.schematic.tooltip.condition1": "Wanneer ingedrukt", - "item.create.schematic.tooltip.behaviour1": "Kan gepositioneerd worden met de knoppen op het scherm", - "item.create.schematic.tooltip.control1": "R-Klik terwijl je sluipt", - "item.create.schematic.tooltip.action1": "Opent een_Interface_ voor het invullen van preciese _coordinaten._", - - "item.create.schematic_and_quill.tooltip": "BOUWTEKENING EN VEER", - "item.create.schematic_and_quill.tooltip.summary": "Bruikbaar om een contructie in je wereld op te slaan naar een .nbt bestand.", - "item.create.schematic_and_quill.tooltip.condition1": "Stap 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selecteer twee hoekpunten met R-Klik", - "item.create.schematic_and_quill.tooltip.condition2": "Stap 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Scroll_ op de zijden om de groote aan te passen. R-Klik nogmaals om op te slaan.", - "item.create.schematic_and_quill.tooltip.control1": "R-Klik", - "item.create.schematic_and_quill.tooltip.action1": "Selecteer een hoekpunt / opslaan bevestigen", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Ingedrukt houden", - "item.create.schematic_and_quill.tooltip.action2": "Selecteer punten in _de lucht._ _Scroll_ om de afstand aan te passen.", - "item.create.schematic_and_quill.tooltip.control3": "R-Klik terwijl je sluipt", - "item.create.schematic_and_quill.tooltip.action3": "_Resets_ en verwijderd de selectie.", - - "block.create.schematicannon.tooltip": "BOUWTEKENINGKANNON", - "block.create.schematicannon.tooltip.summary": "Schiet blokken om een gepostioneerde _Bouwtekening_ in de Wereld te creëeren. Gebruikt blokken uit naastgelegen inventarissen en _Buskruit_ als brandstof.", - "block.create.schematicannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "block.create.schematicannon.tooltip.behaviour1": "UNLOCALIZED: Opens the _Interface_", - - "block.create.schematic_table.tooltip": "BOUWTEKENING TAFEL", - "block.create.schematic_table.tooltip.summary": "Schrijft opgeslagen bouwtekeningen op een _Lege_ _Bouwtekening_", - "block.create.schematic_table.tooltip.condition1": "Wanneer voorzien van een lege Bouwtekening", - "block.create.schematic_table.tooltip.behaviour1": "Uploadt een gekozen bestand uit uw bouwtekeningenmap", - - "item.create.goggles.tooltip": "BRIL", - "item.create.goggles.tooltip.summary": "Een bril om je visie te augmenteren met _kinetische_ _informatie._", - "item.create.goggles.tooltip.condition1": "Wanneer gedragen", - "item.create.goggles.tooltip.behaviour1": "Laat _gekleurde_ _indicaties_ zien die corresponderen met de _Snelheid_ van een geplaatst kinetisch onderdeel.", - "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", - "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", - "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", - "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", - - "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", - "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", - "item.create.wrench.tooltip.control1": "UNLOCALIZED: Right-Click a kinetic block", - "item.create.wrench.tooltip.action1": "UNLOCALIZED: _Rotates components_ toward or away from the face with which you interacted.", - "item.create.wrench.tooltip.control2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.wrench.tooltip.action2": "UNLOCALIZED: _Disassembles Kinetic components_ and places them back in _your inventory_.", - - "block.create.nozzle.tooltip": "UNLOCALIZED: NOZZLE", - "block.create.nozzle.tooltip.summary": "UNLOCALIZED: Attach to the front of an _Encased Fan_ to distribute its effect on Entities in _all directions_.", - - "block.create.cuckoo_clock.tooltip": "UNLOCALIZED: CUCKOO CLOCK", - "block.create.cuckoo_clock.tooltip.summary": "UNLOCALIZED: Fine craftsmanship for _decorating_ a space and _keeping track of time_.", - "block.create.cuckoo_clock.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.cuckoo_clock.tooltip.behaviour1": "UNLOCALIZED: Shows the _current time_ and plays a tune twice a day. _Activates_ once at _noon_ and at dusk, as soon as _players can sleep_.", - - "block.create.turntable.tooltip": "DRAAISCHIJF", - "block.create.turntable.tooltip.summary": "Verandert _Rotatiekracht_ in verfijnde bewegingsziekte.", - - "block.create.toolbox.tooltip": "UNLOCALIZED: TOOLBOX", - "block.create.toolbox.tooltip.summary": "UNLOCALIZED: Every Inventors' dearest Companion. Conveniently _holds_ a large amount of _8 Different_ item types.", - "block.create.toolbox.tooltip.condition1": "UNLOCALIZED: When Picked Up", - "block.create.toolbox.tooltip.behaviour1": "UNLOCALIZED: _Retains_ Inventory _Contents_.", - "block.create.toolbox.tooltip.condition2": "UNLOCALIZED: When placed in Range", - "block.create.toolbox.tooltip.behaviour2": "UNLOCALIZED: _Nearby_ _Players_ can hold the _Toolbox_ _Keybind_ to access its contents _Remotely_.", - "block.create.toolbox.tooltip.condition3": "UNLOCALIZED: When R-Clicked", - "block.create.toolbox.tooltip.behaviour3": "UNLOCALIZED: Opens the _Container Interface_.", - - "block.create.stockpile_switch.tooltip": "VOORRAAD SCHAKELAAR", - "block.create.stockpile_switch.tooltip.summary": "Schakelt een Redstone signaal op basis van de _Opslagruimte_ in de aangesloten Container.", - "block.create.stockpile_switch.tooltip.condition1": "Wanneer onder de laagste limiet", - "block.create.stockpile_switch.tooltip.behaviour1": "Stopt met het aanbieden van _Redstone_ _Kracht_", - - "block.create.content_observer.tooltip": "UNLOCALIZED: CONTENT OBSERVER", - "block.create.content_observer.tooltip.summary": "UNLOCALIZED: _Detects Items_ or _Fluids_ inside _containers_, _pipes_ or _conveyors_ matching a configured _filter_.", - "block.create.content_observer.tooltip.condition1": "UNLOCALIZED: When observing a Container", - "block.create.content_observer.tooltip.behaviour1": "UNLOCALIZED: Emits a _Redstone Signal_ while the observed container has _matching_ _content_.", - "block.create.content_observer.tooltip.condition2": "UNLOCALIZED: When observing a Funnel", - "block.create.content_observer.tooltip.behaviour2": "UNLOCALIZED: Emits a _Redstone Pulse_ when a _matching_ Item is _transferred_.", - - "block.create.creative_crate.tooltip": "CREATIEF KRAT", - "block.create.creative_crate.tooltip.summary": "Bied een eindloze vooraad blokken aan een aangeloten _Bouwtekeningkannon_", - "block.create.creative_crate.tooltip.condition1": "UNLOCALIZED: When Item in Filter Slot", - "block.create.creative_crate.tooltip.behaviour1": "UNLOCALIZED: Anything _extracting_ from this container will provide an _endless supply_ of the item specified. Items _inserted_ into this crate will be _voided._", - - "item.create.creative_blaze_cake.tooltip": "UNLOCALIZED: CREATIVE CAKE", - "item.create.creative_blaze_cake.tooltip.summary": "UNLOCALIZED: A very special treat for your _Blaze Burners_. After eating this cake, Blaze Burners will _never run out of fuel_.", - "item.create.creative_blaze_cake.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.creative_blaze_cake.tooltip.behaviour1": "UNLOCALIZED: _Cycles_ a Blaze Burner's heat level.", - - "block.create.controller_rail.tooltip": "UNLOCALIZED: CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "UNLOCALIZED: A _uni-directional powered rail_ capable of _fine control_ over a minecarts' _movement speed_.", - "block.create.controller_rail.tooltip.condition1": "UNLOCALIZED: When Powered by Redstone", - "block.create.controller_rail.tooltip.behaviour1": "UNLOCALIZED: _Accelerates_ or _Decelerates_ passing _minecarts_ corresponding to the _signal strength_. Propagates redstone power to adjacent controller rails. Powering two controller rails with different strengths will cause tracks between them to interpolate their signal.", - - "item.create.sand_paper.tooltip": "UNLOCALIZED: SAND PAPER", - "item.create.sand_paper.tooltip.summary": "UNLOCALIZED: A rough paper that can be used to _polish materials_. Can be automatically applied using the Deployer.", - "item.create.sand_paper.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.sand_paper.tooltip.behaviour1": "UNLOCALIZED: Applies polish to items held in the _offhand_ or lying on the _floor_ when _looking at them_", - - "item.create.builders_tea.tooltip": "UNLOCALIZED: BUILDERS TEA", - "item.create.builders_tea.tooltip.summary": "UNLOCALIZED: The perfect drink to get the day started- _Motivating_ and _Saturating._", - - "item.create.refined_radiance.tooltip": "UNLOCALIZED: REFINED RADIANCE", - "item.create.refined_radiance.tooltip.summary": "UNLOCALIZED: A Chromatic material forged from _absorbed light_.", - "item.create.refined_radiance.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.shadow_steel.tooltip": "UNLOCALIZED: SHADOW STEEL", - "item.create.shadow_steel.tooltip.summary": "UNLOCALIZED: A Chromatic material forged _in the void_.", - "item.create.shadow_steel.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.linked_controller.tooltip": "UNLOCALIZED: LINKED CONTROLLER", - "item.create.linked_controller.tooltip.summary": "UNLOCALIZED: Grants _handheld_ _control_ over _Redstone Link_ frequencies assigned to its _six_ _buttons_.", - "item.create.linked_controller.tooltip.condition1": "UNLOCALIZED: R-Click", - "item.create.linked_controller.tooltip.behaviour1": "UNLOCALIZED: _Toggles_ the controller. _Movement_ _controls_ are taken over while its active.", - "item.create.linked_controller.tooltip.condition2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.linked_controller.tooltip.behaviour2": "UNLOCALIZED: Opens the manual _Configuration Interface_.", - "item.create.linked_controller.tooltip.condition3": "UNLOCALIZED: R-Click on Redstone Link Receiver", - "item.create.linked_controller.tooltip.behaviour3": "UNLOCALIZED: Enables _Bind Mode_, press one of the _six controls_ to bind it to the _Links' Frequency_.", - "item.create.linked_controller.tooltip.condition4": "UNLOCALIZED: R-Click on Lectern", - "item.create.linked_controller.tooltip.behaviour4": "UNLOCALIZED: Places the Controller into the Lectern for easy activation. (R-Click while Sneaking to retrieve it)", - - "item.create.diving_helmet.tooltip": "UNLOCALIZED: DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "UNLOCALIZED: Together with a _Copper_ _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", - "item.create.diving_helmet.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_helmet.tooltip.behaviour1": "UNLOCALIZED: Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", - - "item.create.copper_backtank.tooltip": "UNLOCALIZED: COPPER BACKTANK", - "item.create.copper_backtank.tooltip.summary": "UNLOCALIZED: A _Wearable_ _Tank_ for carrying Pressurized Air.", - "item.create.copper_backtank.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.copper_backtank.tooltip.behaviour1": "UNLOCALIZED: Provides _Pressurized_ _Air_ to Equipment that requires it.", - "item.create.copper_backtank.tooltip.condition2": "UNLOCALIZED: When placed, Powered by Kinetics", - "item.create.copper_backtank.tooltip.behaviour2": "UNLOCALIZED: _Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "UNLOCALIZED: DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "UNLOCALIZED: A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", - "item.create.diving_boots.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_boots.tooltip.behaviour1": "UNLOCALIZED: Wielder _sinks_ _faster_ and _cannot_ _swim_. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", - - "item.create.crafting_blueprint.tooltip": "UNLOCALIZED: CRAFTING BLUEPRINT", - "item.create.crafting_blueprint.tooltip.summary": "UNLOCALIZED: _Placed_ on a wall, it can be used to _specify_ _ingredient_ _arrangements_ for easier manual crafting. Each slot represents a Recipe.", - "item.create.crafting_blueprint.condition1": "UNLOCALIZED: R-Click empty Slot", - "item.create.crafting_blueprint.behaviour1": "UNLOCALIZED: Opens a _Crafting_ _menu_ allowing you to _configure_ a _recipe_ and items to display.", - "item.create.crafting_blueprint.condition2": "UNLOCALIZED: R-Click configured Slot", - "item.create.crafting_blueprint.behaviour2": "UNLOCALIZED: _Applies_ the _configured_ _recipe_ with matching Ingredients found in your _Inventory_. _Sneak_ to craft up to a _Stack_ of items.", - - "item.create.minecart_coupling.tooltip": "UNLOCALIZED: MINECART COUPLING", - "item.create.minecart_coupling.tooltip.summary": "UNLOCALIZED: _Chains_ all your _Minecarts_ or _Carriage Contraptions_ together to form a majestic Train.", - "item.create.minecart_coupling.tooltip.condition1": "UNLOCALIZED: When Used on Minecart", - "item.create.minecart_coupling.tooltip.behaviour1": "UNLOCALIZED: _Couples_ two Minecarts together, attempting to keep them at a _constant distance_ while moving.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "UNLOCALIZED: PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "UNLOCALIZED: A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may cause side-effects...", - - "block.create.haunted_bell.tooltip": "UNLOCALIZED: HAUNTED BELL", - "block.create.haunted_bell.tooltip.summary": "UNLOCALIZED: A _Cursed Bell_ haunted by lost souls of the Nether.", - "block.create.haunted_bell.tooltip.condition1": "UNLOCALIZED: When Held or Rang", - "block.create.haunted_bell.tooltip.behaviour1": "UNLOCALIZED: Highlights nearby _Lightless Spots_ on which _Hostile Mobs_ can spawn.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", - "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", - "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", - "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", - "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", - "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Super Glue, larger structures can be moved.", - "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", - "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", - "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", - "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", - "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", - "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", - "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", - "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", - "create.ponder.tag.windmill_sails": "UNLOCALIZED: Sails for Windmill Bearings", - "create.ponder.tag.windmill_sails.description": "UNLOCALIZED: Blocks that count towards the strength of a Windmill Contraption when assembled. Each of these have equal efficiency in doing so.", - "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", - "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", - "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", - "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", - "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", - "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", - "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", - "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", - "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", - "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", - "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", - "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", - "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", - "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", - "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", - "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", - "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", - "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", - - "create.ponder.andesite_tunnel.header": "UNLOCALIZED: Using Andesite Tunnels", - "create.ponder.andesite_tunnel.text_1": "UNLOCALIZED: Andesite Tunnels can be used to cover up your belts", - "create.ponder.andesite_tunnel.text_2": "UNLOCALIZED: Whenever an Andesite Tunnel has connections to the sides...", - "create.ponder.andesite_tunnel.text_3": "UNLOCALIZED: ...they will split exactly one item off of any passing stacks", - "create.ponder.andesite_tunnel.text_4": "UNLOCALIZED: The remainder will continue on its path", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "UNLOCALIZED: Processing Items in the Basin", - "create.ponder.basin.text_1": "UNLOCALIZED: A Basin can hold Items and Fluids for Processing", - "create.ponder.basin.text_2": "UNLOCALIZED: After a processing step, basins try to output below to the side of them", - "create.ponder.basin.text_3": "UNLOCALIZED: When a valid component is present, the Basin will show an output faucet", - "create.ponder.basin.text_4": "UNLOCALIZED: A number of options are applicable here", - "create.ponder.basin.text_5": "UNLOCALIZED: Outputs will be caught by the inventory below", - "create.ponder.basin.text_6": "UNLOCALIZED: Without output faucet, the Basin will retain items created in its processing", - "create.ponder.basin.text_7": "UNLOCALIZED: This can be useful if outputs should be re-used as ingredients", - "create.ponder.basin.text_8": "UNLOCALIZED: Desired outputs will then have to be extracted from the basin", - "create.ponder.basin.text_9": "UNLOCALIZED: A Filter might be necessary to avoid pulling out un-processed items", - - "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", - "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", - "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", - - "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", - "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", - "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", - - "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", - "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", - "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", - "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", - "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", - "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", - "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", - - "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", - "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", - "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", - "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", - "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", - "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", - "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions. Belts can span any Length between 2 and 20 blocks", - - "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", - "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", - "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", - - "create.ponder.blaze_burner.header": "UNLOCALIZED: Feeding Blaze Burners", - "create.ponder.blaze_burner.text_1": "UNLOCALIZED: Blaze Burners can provide Heat to Items processed in a Basin", - "create.ponder.blaze_burner.text_2": "UNLOCALIZED: For this, the Blaze has to be fed with flammable items", - "create.ponder.blaze_burner.text_3": "UNLOCALIZED: With a Blaze Cake, the Burner can reach an even stronger level of heat", - "create.ponder.blaze_burner.text_4": "UNLOCALIZED: The feeding process can be automated using Deployers or Mechanical Arms", - - "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", - "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", - "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", - "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", - - "create.ponder.brass_tunnel.header": "UNLOCALIZED: Using Brass Tunnels", - "create.ponder.brass_tunnel.text_1": "UNLOCALIZED: Brass Tunnels can be used to cover up your belts", - "create.ponder.brass_tunnel.text_2": "UNLOCALIZED: Brass Tunnels have filter slots on each open side", - "create.ponder.brass_tunnel.text_3": "UNLOCALIZED: Filters on inbound connections simply block non-matching items", - "create.ponder.brass_tunnel.text_4": "UNLOCALIZED: Filters on outbound connections can be used to sort items by type", - "create.ponder.brass_tunnel.text_5": "UNLOCALIZED: Whenever a passing item has multiple valid exits, the distribution mode will decide how to handle it", - "create.ponder.brass_tunnel.text_6": "UNLOCALIZED: Brass Tunnels on parallel belts will form a group", - "create.ponder.brass_tunnel.text_7": "UNLOCALIZED: Incoming Items will now be distributed across all connected exits", - "create.ponder.brass_tunnel.text_8": "UNLOCALIZED: For this, items can also be inserted into the Tunnel block directly", - - "create.ponder.brass_tunnel_modes.header": "UNLOCALIZED: Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "UNLOCALIZED: Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", - "create.ponder.brass_tunnel_modes.text_10": "UNLOCALIZED: 'Synchronize Inputs' is a unique setting for Brass Tunnels", - "create.ponder.brass_tunnel_modes.text_11": "UNLOCALIZED: Items are only allowed past if every tunnel in the group has one waiting", - "create.ponder.brass_tunnel_modes.text_12": "UNLOCALIZED: This ensures that all affected belts supply items at the same rate", - "create.ponder.brass_tunnel_modes.text_2": "UNLOCALIZED: 'Split' will attempt to distribute the stack evenly between available outputs", - "create.ponder.brass_tunnel_modes.text_3": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_4": "UNLOCALIZED: 'Forced Split' will never skip outputs, and instead wait until they are free", - "create.ponder.brass_tunnel_modes.text_5": "UNLOCALIZED: 'Round Robin' keeps stacks whole, and cycles through outputs iteratively", - "create.ponder.brass_tunnel_modes.text_6": "UNLOCALIZED: Once Again, if an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_7": "UNLOCALIZED: 'Forced Round Robin' never skips outputs", - "create.ponder.brass_tunnel_modes.text_8": "UNLOCALIZED: 'Prefer Nearest' prioritizes the outputs closest to the items' input location", - "create.ponder.brass_tunnel_modes.text_9": "UNLOCALIZED: 'Randomize' will distribute whole stacks to randomly picked outputs", - - "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", - "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", - "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", - "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", - - "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", - "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", - "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", - "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", - - "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", - "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", - "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: This Arrow indicates which side of the Structure will be considered the front", - "create.ponder.cart_assembler_modes.text_3": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", - - "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", - "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", - "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", - "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", - "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", - - "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", - "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", - "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", - "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", - - "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", - "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exactly like Chain Drives", - "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", - "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", - "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", - "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", - "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", - - "create.ponder.chute.header": "UNLOCALIZED: Transporting Items downward via Chutes", - "create.ponder.chute.text_1": "UNLOCALIZED: Chutes can transport items vertically from and to inventories", - "create.ponder.chute.text_2": "UNLOCALIZED: Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "UNLOCALIZED: Placing chutes targeting the side faces of another will make it diagonal", - - "create.ponder.chute_upward.header": "UNLOCALIZED: Transporting Items upward via Chutes", - "create.ponder.chute_upward.text_1": "UNLOCALIZED: Using Encased Fans at the top or bottom, a Chute can move items upward", - "create.ponder.chute_upward.text_2": "UNLOCALIZED: Inspecting chutes with Engineers' Goggles reveals information about the movement direction", - "create.ponder.chute_upward.text_3": "UNLOCALIZED: On the 'blocked' end, items will have to be inserted/taken from the sides", - - "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", - "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", - "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", - "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", - "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", - "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", - "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", - "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure that the two Structures are not glued to each other", - "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", - - "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", - "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", - "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", - - "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", - "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", - "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", - "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", - - "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", - "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", - "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "UNLOCALIZED: Creative Fluid Tanks", - "create.ponder.creative_fluid_tank.text_1": "UNLOCALIZED: Creative Fluid Tanks can be used to provide a bottomless supply of fluid", - "create.ponder.creative_fluid_tank.text_2": "UNLOCALIZED: Right-Click with a fluid containing item to configure it", - "create.ponder.creative_fluid_tank.text_3": "UNLOCALIZED: Pipe Networks can now endlessly draw the assigned fluid from the tank", - "create.ponder.creative_fluid_tank.text_4": "UNLOCALIZED: Any Fluids pushed back into a Creative Fluid Tank will be voided", - - "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", - "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "UNLOCALIZED: Processing Items with Crushing Wheels", - "create.ponder.crushing_wheels.text_1": "UNLOCALIZED: A pair of Crushing Wheels can grind items very effectively", - "create.ponder.crushing_wheels.text_2": "UNLOCALIZED: Their Rotational Input has to make them spin into each other", - "create.ponder.crushing_wheels.text_3": "UNLOCALIZED: Items thrown or inserted into the top will get processed", - "create.ponder.crushing_wheels.text_4": "UNLOCALIZED: Items can be inserted and picked up through automated means as well", - - "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", - "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", - "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", - "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", - "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", - "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", - "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", - "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", - "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", - "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", - "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", - "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", - "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", - "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", - "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", - "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", - - "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", - "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", - "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", - "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", - - "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", - "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", - "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", - - "create.ponder.deployer_processing.header": "UNLOCALIZED: Processing Items using Deployers", - "create.ponder.deployer_processing.text_1": "UNLOCALIZED: With a fitting held item, Deployers can process items provided beneath them", - "create.ponder.deployer_processing.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Deployer", - "create.ponder.deployer_processing.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.deployer_processing.text_4": "UNLOCALIZED: The Deployer will hold and process them automatically", - - "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", - "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", - "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", - "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.depot.header": "UNLOCALIZED: Using Depots", - "create.ponder.depot.text_1": "UNLOCALIZED: Depots can serve as 'stationary' belt elements", - "create.ponder.depot.text_2": "UNLOCALIZED: Right-Click to manually place or remove Items from it", - "create.ponder.depot.text_3": "UNLOCALIZED: Just like Mechanical Belts, it can provide items to processing", - "create.ponder.depot.text_4": "UNLOCALIZED: ...as well as provide Items to Mechanical Arms", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "UNLOCALIZED: Using Empty Blaze Burners", - "create.ponder.empty_blaze_burner.text_1": "UNLOCALIZED: Right-click a Blaze with the empty burner to capture it", - "create.ponder.empty_blaze_burner.text_2": "UNLOCALIZED: Alternatively, Blazes can be collected from their Spawners directly", - "create.ponder.empty_blaze_burner.text_3": "UNLOCALIZED: You now have an ideal heat source for various machines", - "create.ponder.empty_blaze_burner.text_4": "UNLOCALIZED: For Aesthetic purposes, Empty Blaze Burners can also be lit using Flint and Steel", - "create.ponder.empty_blaze_burner.text_5": "UNLOCALIZED: The flame can be transformed using a soul-infused item", - "create.ponder.empty_blaze_burner.text_6": "UNLOCALIZED: However, without a blaze they are not suitable for industrial heating", - - "create.ponder.encased_fluid_pipe.header": "UNLOCALIZED: Encasing Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_1": "UNLOCALIZED: Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "UNLOCALIZED: Aside from being conceiled, Encased Pipes are locked into their connectivity state", - "create.ponder.encased_fluid_pipe.text_3": "UNLOCALIZED: It will no longer react to any neighbouring blocks being added or removed", - - "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", - "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", - - "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", - "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", - "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", - "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", - "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", - "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", - "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", - "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", - - "create.ponder.fluid_pipe_flow.header": "UNLOCALIZED: Moving Fluids using Copper Pipes", - "create.ponder.fluid_pipe_flow.text_1": "UNLOCALIZED: Fluid Pipes can connect two or more fluid sources and targets", - "create.ponder.fluid_pipe_flow.text_2": "UNLOCALIZED: Using a wrench, a straight pipe segment can be given a window", - "create.ponder.fluid_pipe_flow.text_3": "UNLOCALIZED: Windowed pipes will not connect to any other adjacent pipe segments", - "create.ponder.fluid_pipe_flow.text_4": "UNLOCALIZED: Powered by Mechanical Pumps, the Pipes can transport Fluids", - "create.ponder.fluid_pipe_flow.text_5": "UNLOCALIZED: No fluid is being extracted at first", - "create.ponder.fluid_pipe_flow.text_6": "UNLOCALIZED: Once the flow connects them, the endpoints gradually transfer their contents", - "create.ponder.fluid_pipe_flow.text_7": "UNLOCALIZED: Thus, the Pipe blocks themselves never 'physically' contain any fluid", - - "create.ponder.fluid_pipe_interaction.header": "UNLOCALIZED: Draining and Filling fluid containers", - "create.ponder.fluid_pipe_interaction.text_1": "UNLOCALIZED: Endpoints of a pipe network can interact with a variety of blocks", - "create.ponder.fluid_pipe_interaction.text_2": "UNLOCALIZED: Any block with fluid storage capabilities can be filled or drained", - "create.ponder.fluid_pipe_interaction.text_3": "UNLOCALIZED: Source blocks right in front of an open end can be picked up...", - "create.ponder.fluid_pipe_interaction.text_4": "UNLOCALIZED: ...while spilling into empty spaces can create fluid sources", - "create.ponder.fluid_pipe_interaction.text_5": "UNLOCALIZED: Pipes can also extract fluids from a handful of other blocks directly", - - "create.ponder.fluid_tank_sizes.header": "UNLOCALIZED: Dimensions of a Fluid tank", - "create.ponder.fluid_tank_sizes.text_1": "UNLOCALIZED: Fluid Tanks can be combined to increase the total capacity", - "create.ponder.fluid_tank_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.fluid_tank_sizes.text_3": "UNLOCALIZED: ...and grow in height by more than 30 additional layers", - "create.ponder.fluid_tank_sizes.text_4": "UNLOCALIZED: Using a Wrench, a tanks' window can be toggled", - - "create.ponder.fluid_tank_storage.header": "UNLOCALIZED: Storing Fluids in Fluid Tanks", - "create.ponder.fluid_tank_storage.text_1": "UNLOCALIZED: Fluid Tanks can be used to store large amounts of fluid", - "create.ponder.fluid_tank_storage.text_2": "UNLOCALIZED: Pipe networks can push and pull fluids from any side", - "create.ponder.fluid_tank_storage.text_3": "UNLOCALIZED: The contained fluid can be measured by a Comparator", - "create.ponder.fluid_tank_storage.text_4": "UNLOCALIZED: However, in Survival Mode Fluids cannot be added or taken manually", - "create.ponder.fluid_tank_storage.text_5": "UNLOCALIZED: You can use Basins, Item Drains and Spouts to drain or fill fluid containing items", - - "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", - "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", - "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", - "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", - "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", - - "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", - "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", - "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", - "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", - "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", - "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", - - "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", - "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", - - "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", - "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting", - - "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", - "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", - "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", - "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement. A mechanical belt should help here.", - - "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", - "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", - "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", - "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", - "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", - "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", - - "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", - "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", - "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", - "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", - "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", - - "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", - "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", - "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", - - "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", - "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", - "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", - "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", - "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", - "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", - "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", - - "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", - "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", - "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", - - "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", - "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", - "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - - "create.ponder.hose_pulley.header": "UNLOCALIZED: Source Filling and Draining using Hose Pulleys", - "create.ponder.hose_pulley.text_1": "UNLOCALIZED: Hose Pulleys can be used to fill or drain large bodies of Fluid", - "create.ponder.hose_pulley.text_2": "UNLOCALIZED: With the Kinetic Input, the height of the pulleys' hose can be controlled", - "create.ponder.hose_pulley.text_3": "UNLOCALIZED: The Pulley retracts while the input rotation is inverted", - "create.ponder.hose_pulley.text_4": "UNLOCALIZED: On the opposite side, pipes can be connected", - "create.ponder.hose_pulley.text_5": "UNLOCALIZED: Attached pipe networks can either provide fluid to the hose...", - "create.ponder.hose_pulley.text_6": "UNLOCALIZED: ...or pull from it, draining the pool instead", - "create.ponder.hose_pulley.text_7": "UNLOCALIZED: Fill and Drain speed of the pulley depends entirely on the fluid networks' throughput", - - "create.ponder.hose_pulley_infinite.header": "UNLOCALIZED: Passively Filling and Draining large bodies of Fluid", - "create.ponder.hose_pulley_infinite.text_1": "UNLOCALIZED: When deploying the Hose Pulley into a large enough ocean...", - "create.ponder.hose_pulley_infinite.text_2": "UNLOCALIZED: It will provide/dispose fluids without affecting the source", - "create.ponder.hose_pulley_infinite.text_3": "UNLOCALIZED: Pipe networks can limitlessly take fluids from/to such pulleys", - - "create.ponder.hose_pulley_level.header": "UNLOCALIZED: Fill and Drain level of Hose Pulleys", - "create.ponder.hose_pulley_level.text_1": "UNLOCALIZED: While fully retracted, the Hose Pulley cannot operate", - "create.ponder.hose_pulley_level.text_2": "UNLOCALIZED: Draining runs from top to bottom", - "create.ponder.hose_pulley_level.text_3": "UNLOCALIZED: The surface level will end up just below where the hose ends", - "create.ponder.hose_pulley_level.text_4": "UNLOCALIZED: Filling runs from bottom to top", - "create.ponder.hose_pulley_level.text_5": "UNLOCALIZED: The filled pool will not grow beyond the layer above the hose end", - - "create.ponder.item_drain.header": "UNLOCALIZED: Emptying Fluid Containers using Item Drains", - "create.ponder.item_drain.text_1": "UNLOCALIZED: Item Drains can extract fluids from items", - "create.ponder.item_drain.text_2": "UNLOCALIZED: Right-click it to pour fluids from your held item into it", - "create.ponder.item_drain.text_3": "UNLOCALIZED: When items are inserted from the side...", - "create.ponder.item_drain.text_4": "UNLOCALIZED: ...they roll across, emptying out their contained fluid", - "create.ponder.item_drain.text_5": "UNLOCALIZED: Pipe Networks can now pull the fluid from the drains' internal buffer", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", - "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", - "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", - - "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", - "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", - "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", - "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", - "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", - "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", - - "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "UNLOCALIZED: Setting up Mechanical Arms", - "create.ponder.mechanical_arm.text_1": "UNLOCALIZED: Mechanical Arms have to be assigned their in- and outputs before they are placed", - "create.ponder.mechanical_arm.text_2": "UNLOCALIZED: Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "UNLOCALIZED: Right-Click again to toggle between Input (Blue) and Output (Orange)", - "create.ponder.mechanical_arm.text_4": "UNLOCALIZED: Left-Click components to remove their Selection", - "create.ponder.mechanical_arm.text_5": "UNLOCALIZED: Once placed, the Mechanical Arm will target the blocks selected previously", - "create.ponder.mechanical_arm.text_6": "UNLOCALIZED: They can have any amount of in- and outputs within their range", - "create.ponder.mechanical_arm.text_7": "UNLOCALIZED: However, not every type of Inventory can be interacted with directly", - "create.ponder.mechanical_arm.text_8": "UNLOCALIZED: Funnels and Depots can help to Bridge that gap", - - "create.ponder.mechanical_arm_filtering.header": "UNLOCALIZED: Filtering Outputs of the Mechanical Arm", - "create.ponder.mechanical_arm_filtering.text_1": "UNLOCALIZED: Inputs", - "create.ponder.mechanical_arm_filtering.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_filtering.text_3": "UNLOCALIZED: Sometimes it is desirable to restrict targets of the Arm by matching a filter", - "create.ponder.mechanical_arm_filtering.text_4": "UNLOCALIZED: Mechanical Arms by themselves do not provide any options for filtering", - "create.ponder.mechanical_arm_filtering.text_5": "UNLOCALIZED: Brass Funnels as Targets do however communicate their own filter to the Arm", - "create.ponder.mechanical_arm_filtering.text_6": "UNLOCALIZED: The Arm is smart enough not to pick up items it couldn't distribute", - - "create.ponder.mechanical_arm_modes.header": "UNLOCALIZED: Distribution modes of the Mechanical Arm", - "create.ponder.mechanical_arm_modes.text_1": "UNLOCALIZED: Input", - "create.ponder.mechanical_arm_modes.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_modes.text_3": "UNLOCALIZED: Whenever an Arm has to choose between multiple valid outputs...", - "create.ponder.mechanical_arm_modes.text_4": "UNLOCALIZED: ...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "UNLOCALIZED: Scrolling with a Wrench will allow you to configure it", - "create.ponder.mechanical_arm_modes.text_6": "UNLOCALIZED: Round Robin mode simply cycles through all outputs that are available", - "create.ponder.mechanical_arm_modes.text_7": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.mechanical_arm_modes.text_8": "UNLOCALIZED: Forced Round Robin mode will never skip outputs, and instead wait until they are free", - "create.ponder.mechanical_arm_modes.text_9": "UNLOCALIZED: Prefer First prioritizes the outputs selected earliest when configuring this Arm", - - "create.ponder.mechanical_arm_redstone.header": "UNLOCALIZED: Controlling Mechanical Arms with Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Mechanical Arms will not activate", - "create.ponder.mechanical_arm_redstone.text_2": "UNLOCALIZED: Before stopping, it will finish any started cycles", - "create.ponder.mechanical_arm_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", - "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", - "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", - - "create.ponder.mechanical_crafter.header": "UNLOCALIZED: Setting up Mechanical Crafters", - "create.ponder.mechanical_crafter.text_1": "UNLOCALIZED: An array of Mechanical Crafters can be used to automate any Crafting Recipe", - "create.ponder.mechanical_crafter.text_2": "UNLOCALIZED: Using a Wrench, the Crafters' paths can be arranged", - "create.ponder.mechanical_crafter.text_3": "UNLOCALIZED: For a valid setup, all paths have to converge into one exit at any side", - "create.ponder.mechanical_crafter.text_4": "UNLOCALIZED: The outputs will be placed into the inventory at the exit", - "create.ponder.mechanical_crafter.text_5": "UNLOCALIZED: Mechanical Crafters require Rotational Force to operate", - "create.ponder.mechanical_crafter.text_6": "UNLOCALIZED: Right-Click the front to insert Items manually", - "create.ponder.mechanical_crafter.text_7": "UNLOCALIZED: Once every slot of a path contains an Item, the crafting process will begin", - "create.ponder.mechanical_crafter.text_8": "UNLOCALIZED: For recipes not fully occupying the crafter setup, the start can be forced using a Redstone Pulse", - - "create.ponder.mechanical_crafter_connect.header": "UNLOCALIZED: Connecting Inventories of Crafters", - "create.ponder.mechanical_crafter_connect.text_1": "UNLOCALIZED: Items can be inserted to Crafters automatically", - "create.ponder.mechanical_crafter_connect.text_2": "UNLOCALIZED: Using the Wrench at their backs, Mechanical Crafter inputs can be combined", - "create.ponder.mechanical_crafter_connect.text_3": "UNLOCALIZED: All connected Crafters can now be accessed by the same input location", - - "create.ponder.mechanical_crafter_covers.header": "UNLOCALIZED: Covering slots of Mechanical Crafters", - "create.ponder.mechanical_crafter_covers.text_1": "UNLOCALIZED: Some recipes will require additional Crafters to bridge gaps in the path", - "create.ponder.mechanical_crafter_covers.text_2": "UNLOCALIZED: Using Slot Covers, Crafters can be set to act as an Empty Slot in the arrangement", - "create.ponder.mechanical_crafter_covers.text_3": "UNLOCALIZED: Shared Inputs created with the Wrench at the back can also reach across covered Crafters", - - "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", - "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", - "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", - - "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", - "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", - "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", - - "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", - "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", - "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", - - "create.ponder.mechanical_mixer.header": "UNLOCALIZED: Processing Items with the Mechanical Mixer", - "create.ponder.mechanical_mixer.text_1": "UNLOCALIZED: With a Mixer and Basin, some Crafting Recipes can be automated", - "create.ponder.mechanical_mixer.text_2": "UNLOCALIZED: Available recipes include any Shapeless Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_mixer.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_mixer.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", - "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", - "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", - "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", - - "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", - "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", - "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", - "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", - "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", - "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", - "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", - - "create.ponder.mechanical_press.header": "UNLOCALIZED: Processing Items with the Mechanical Press", - "create.ponder.mechanical_press.text_1": "UNLOCALIZED: The Mechanical Press can process items provided beneath it", - "create.ponder.mechanical_press.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Press", - "create.ponder.mechanical_press.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.mechanical_press.text_4": "UNLOCALIZED: The Press will hold and process them automatically", - - "create.ponder.mechanical_press_compacting.header": "UNLOCALIZED: Compacting items with the Mechanical Press", - "create.ponder.mechanical_press_compacting.text_1": "UNLOCALIZED: Pressing items held in a Basin will cause them to be Compacted", - "create.ponder.mechanical_press_compacting.text_2": "UNLOCALIZED: Compacting includes any filled 2x2 or 3x3 Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_press_compacting.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_press_compacting.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_pump_flow.header": "UNLOCALIZED: Fluid Transportation using Mechanical Pumps", - "create.ponder.mechanical_pump_flow.text_1": "UNLOCALIZED: Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "UNLOCALIZED: When powered, their arrow indicates the direction of flow", - "create.ponder.mechanical_pump_flow.text_3": "UNLOCALIZED: The network behind is now pulling fluids...", - "create.ponder.mechanical_pump_flow.text_4": "UNLOCALIZED: ...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "UNLOCALIZED: Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "UNLOCALIZED: Use a Wrench to reverse the orientation of pumps manually", - - "create.ponder.mechanical_pump_speed.header": "UNLOCALIZED: Throughput of Mechanical Pumps", - "create.ponder.mechanical_pump_speed.text_1": "UNLOCALIZED: Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", - "create.ponder.mechanical_pump_speed.text_2": "UNLOCALIZED: Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "UNLOCALIZED: ...aswell as how quickly fluids are transferred", - "create.ponder.mechanical_pump_speed.text_4": "UNLOCALIZED: Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "UNLOCALIZED: Alternating their orientation can help align their flow directions", - - "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", - "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", - "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", - - "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", - "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", - "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", - - "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", - "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", - "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", - "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", - "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", - "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", - - "create.ponder.millstone.header": "UNLOCALIZED: Processing Items in the Millstone", - "create.ponder.millstone.text_1": "UNLOCALIZED: Millstones process items by grinding them", - "create.ponder.millstone.text_2": "UNLOCALIZED: They can be powered from the side using cogwheels", - "create.ponder.millstone.text_3": "UNLOCALIZED: Throw or Insert items at the top", - "create.ponder.millstone.text_4": "UNLOCALIZED: After some time, the result can be obtained via Right-click", - "create.ponder.millstone.text_5": "UNLOCALIZED: The outputs can also be extracted by automation", - - "create.ponder.nixie_tube.header": "UNLOCALIZED: Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "UNLOCALIZED: When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "UNLOCALIZED: Using name tags edited with an anvil, custom text can be displayed", - "create.ponder.nixie_tube.text_3": "UNLOCALIZED: Right-Click with Dye to change their display colour", - - "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", - "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", - "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", - - "create.ponder.portable_fluid_interface.header": "UNLOCALIZED: Contraption Fluid Exchange", - "create.ponder.portable_fluid_interface.text_1": "UNLOCALIZED: Fluid Tanks on moving contraptions cannot be accessed by any pipes", - "create.ponder.portable_fluid_interface.text_2": "UNLOCALIZED: This component can interact with fluid tanks without the need to stop the contraption", - "create.ponder.portable_fluid_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_fluid_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_fluid_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL Tanks on the contraption", - "create.ponder.portable_fluid_interface.text_6": "UNLOCALIZED: Fluid can now be inserted...", - "create.ponder.portable_fluid_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_fluid_interface.text_8": "UNLOCALIZED: After no contents have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", - "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", - "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", - "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", - - "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", - "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", - "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", - "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", - "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", - - "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", - "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", - "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", - "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", - "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", - "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", - "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", - "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", - "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", - "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", - "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", - "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", - - "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", - "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", - "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", - - "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", - "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", - "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", - "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", - "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", - "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", - "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", - - "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", - "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", - "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", - - "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", - "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", - "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", - "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", - - "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", - "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", - "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", - "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", - - "create.ponder.sail.header": "UNLOCALIZED: Assembling Windmills using Sails", - "create.ponder.sail.text_1": "UNLOCALIZED: Sails are handy blocks to create Windmills with", - "create.ponder.sail.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - "create.ponder.sail.text_3": "UNLOCALIZED: Right-Click with Dye to paint them", - "create.ponder.sail.text_4": "UNLOCALIZED: Right-Click with Shears to turn them back into frames", - - "create.ponder.sail_frame.header": "UNLOCALIZED: Assembling Windmills using Sail Frames", - "create.ponder.sail_frame.text_1": "UNLOCALIZED: Sail Frames are handy blocks to create Windmills with", - "create.ponder.sail_frame.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", - "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", - "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", - "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", - "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", - "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", - - "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", - "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", - - "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", - "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", - - "create.ponder.smart_chute.header": "UNLOCALIZED: Filtering Items using Smart Chutes", - "create.ponder.smart_chute.text_1": "UNLOCALIZED: Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "UNLOCALIZED: Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "UNLOCALIZED: Use the Mouse Wheel to specify the extracted stack size", - "create.ponder.smart_chute.text_4": "UNLOCALIZED: Redstone power will prevent Smart Chutes from acting.", - - "create.ponder.smart_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Smart Pipes", - "create.ponder.smart_pipe.text_1": "UNLOCALIZED: Smart pipes can help control flows by fluid type", - "create.ponder.smart_pipe.text_2": "UNLOCALIZED: When placed directly at the source, they can specify the type of fluid to extract", - "create.ponder.smart_pipe.text_3": "UNLOCALIZED: Simply Right-Click their filter slot with any item containing the desired fluid", - "create.ponder.smart_pipe.text_4": "UNLOCALIZED: When placed further down a pipe network, smart pipes will only let matching fluids continue", - - "create.ponder.speedometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "UNLOCALIZED: The Speedometer displays the current Speed of the attached components", - "create.ponder.speedometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.speedometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Speedometer's measurements", - - "create.ponder.spout_filling.header": "UNLOCALIZED: Filling Items using a Spout", - "create.ponder.spout_filling.text_1": "UNLOCALIZED: The Spout can fill fluid holding items provided beneath it", - "create.ponder.spout_filling.text_2": "UNLOCALIZED: The content of a Spout cannot be accessed manually", - "create.ponder.spout_filling.text_3": "UNLOCALIZED: Instead, Pipes can be used to supply it with fluids", - "create.ponder.spout_filling.text_4": "UNLOCALIZED: The Input items can be placed on a Depot under the Spout", - "create.ponder.spout_filling.text_5": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.spout_filling.text_6": "UNLOCALIZED: The Spout will hold and process them automatically", - - "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", - "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", - "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", - "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", - "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", - "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", - "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", - "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", - "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", - - "create.ponder.stressometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Stressometer", - "create.ponder.stressometer.text_1": "UNLOCALIZED: The Stressometer displays the current Stress Capacity of the attached kinetic network", - "create.ponder.stressometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.stressometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Stressometer's measurements", - - "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", - "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue groups blocks together into moving contraptions", - "create.ponder.super_glue.text_2": "UNLOCALIZED: Clicking two endpoints creates a new 'glued' area", - "create.ponder.super_glue.text_3": "UNLOCALIZED: To remove a box, punch it with the glue item in hand", - "create.ponder.super_glue.text_4": "UNLOCALIZED: Adjacent blocks sharing an area will pull each other along", - "create.ponder.super_glue.text_5": "UNLOCALIZED: Overlapping glue volumes will move together", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", - - "create.ponder.valve_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Valves", - "create.ponder.valve_pipe.text_1": "UNLOCALIZED: Valve pipes help control fluids propagating through pipe networks", - "create.ponder.valve_pipe.text_2": "UNLOCALIZED: Their shaft input controls whether fluid is currently allowed through", - "create.ponder.valve_pipe.text_3": "UNLOCALIZED: Given Rotational Force in the opening direction, the valve will open up", - "create.ponder.valve_pipe.text_4": "UNLOCALIZED: It can be closed again by reversing the input rotation", - - "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", - "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", - - "create.ponder.weighted_ejector.header": "UNLOCALIZED: Using Weighted Ejectors", - "create.ponder.weighted_ejector.text_1": "UNLOCALIZED: Sneak and Right-Click holding an Ejector to select its target location", - "create.ponder.weighted_ejector.text_10": "UNLOCALIZED: It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "UNLOCALIZED: Other Entities will always trigger an Ejector when stepping on it", - "create.ponder.weighted_ejector.text_2": "UNLOCALIZED: The placed ejector will now launch objects to the marked location", - "create.ponder.weighted_ejector.text_3": "UNLOCALIZED: A valid target can be at any height or distance within range", - "create.ponder.weighted_ejector.text_4": "UNLOCALIZED: They cannot however be off to a side", - "create.ponder.weighted_ejector.text_5": "UNLOCALIZED: If no valid Target was selected, it will simply target the block directly in front", - "create.ponder.weighted_ejector.text_6": "UNLOCALIZED: Supply Rotational Force in order to charge it up", - "create.ponder.weighted_ejector.text_7": "UNLOCALIZED: Items placed on the ejector cause it to trigger", - "create.ponder.weighted_ejector.text_8": "UNLOCALIZED: If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "UNLOCALIZED: Using the Wrench, a required Stack Size can be configured", - - "create.ponder.weighted_ejector_redstone.header": "UNLOCALIZED: Controlling Weighted Ejectors with Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "UNLOCALIZED: Furthermore, Observers can detect when Ejectors activate", - - "create.ponder.weighted_ejector_tunnel.header": "UNLOCALIZED: Splitting item stacks using Weighted Ejectors", - "create.ponder.weighted_ejector_tunnel.text_1": "UNLOCALIZED: Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", - "create.ponder.weighted_ejector_tunnel.text_2": "UNLOCALIZED: First, configure the Brass Tunnel to 'Prefer Nearest', in order to prioritize its side output", - "create.ponder.weighted_ejector_tunnel.text_3": "UNLOCALIZED: The Stack Size set on the Ejector now determines the amount to be split off", - "create.ponder.weighted_ejector_tunnel.text_4": "UNLOCALIZED: While a new stack of the configured size exits the side output...", - "create.ponder.weighted_ejector_tunnel.text_5": "UNLOCALIZED: ...the remainder will continue on its path", - - "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", - "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", - "create.ponder.windmill_source.text_2": "UNLOCALIZED: Create a movable structure with the help of Super Glue", - "create.ponder.windmill_source.text_3": "UNLOCALIZED: If enough Sail-like blocks are included, this can act as a Windmill", - "create.ponder.windmill_source.text_4": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", - "create.ponder.windmill_source.text_5": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "UNLOCALIZED: Use a Wrench to configure its rotation direction", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", - "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json deleted file mode 100644 index 6735df0aca..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 13", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Akacjowe okno", - "block.create.acacia_window_pane": "Akacjowa szyba okienna", - "block.create.adjustable_chain_gearshift": "Regulowany przekładnik łańcuchowy", - "block.create.analog_lever": "Dźwignia analogowa", - "block.create.andesite_belt_funnel": "Andezytowy lejek taśmowy", - "block.create.andesite_casing": "Andezytowa obudowa", - "block.create.andesite_encased_cogwheel": "Andezytowe izolowane koło zębate", - "block.create.andesite_encased_large_cogwheel": "Andezytowe izolowane dużo koło zębate", - "block.create.andesite_encased_shaft": "Andezytowy izolowany wał", - "block.create.andesite_funnel": "Andezytowy lejek", - "block.create.andesite_ladder": "Andezytowa Drabina", - "block.create.andesite_pillar": "Andezytowy filar", - "block.create.andesite_tunnel": "Andezytowy tunel", - "block.create.asurine": "Azuryn", - "block.create.asurine_pillar": "Azurynowy filar", - "block.create.basin": "Tygiel", - "block.create.belt": "Taśma", - "block.create.birch_window": "Brzozowe okno", - "block.create.birch_window_pane": "Brzozowa szyba okienna", - "block.create.black_nixie_tube": "Czarna lampa cyfrowa", - "block.create.black_sail": "Czarny żagiel", - "block.create.black_seat": "Czarne siedzenie", - "block.create.black_toolbox": "Czarna skrzynka na narzędzia", - "block.create.black_valve_handle": "Czarne pokrętło", - "block.create.blaze_burner": "Płomienny palnik", - "block.create.blue_nixie_tube": "Niebieska lampa cyfrowa", - "block.create.blue_sail": "Niebieski żagiel", - "block.create.blue_seat": "Niebieskie siedzenie", - "block.create.blue_toolbox": "Niebieska skrzynka na narzędzia", - "block.create.blue_valve_handle": "Niebieskie pokrętło", - "block.create.brass_belt_funnel": "Mosiężny lejek taśmowy", - "block.create.brass_block": "Blok mosiądzu", - "block.create.brass_casing": "Mosiężna obudowa", - "block.create.brass_encased_cogwheel": "Mosiężne izolowane koło zębate", - "block.create.brass_encased_large_cogwheel": "Mosiężne izolowane duże koło zębate", - "block.create.brass_encased_shaft": "Mosiężny izolowany wał", - "block.create.brass_funnel": "Mosiężny lejek", - "block.create.brass_ladder": "Mosiężna drabina", - "block.create.brass_tunnel": "Mosiężny tunel", - "block.create.brown_nixie_tube": "Brązowa lampa cyfrowa", - "block.create.brown_sail": "Brązowy żagiel", - "block.create.brown_seat": "Brązowe siedzenie", - "block.create.brown_toolbox": "Brązowa skrzynka na narzędzia", - "block.create.brown_valve_handle": "Brązowe pokrętło", - "block.create.calcite_pillar": "Kalcytowy filar", - "block.create.cart_assembler": "Monter wagoników", - "block.create.chocolate": "Czekolada", - "block.create.chute": "Zsyp", - "block.create.clockwork_bearing": "Mechanizm zegarowy", - "block.create.clutch": "Sprzęgło", - "block.create.cogwheel": "Koło zębate", - "block.create.content_observer": "Detektor zawartości", - "block.create.controller_rail": "Tory sterujące", - "block.create.controls": "Kontroler pociągów", - "block.create.copper_backtank": "Miedziany zbiornik w plecaku", - "block.create.copper_casing": "Miedziana obudowa", - "block.create.copper_ladder": "Miedziana drabina", - "block.create.copper_shingle_slab": "Płyta z miedzianych dachówek", - "block.create.copper_shingle_stairs": "Schody z miedzianych dachówek", - "block.create.copper_shingles": "Miedziane dachówki", - "block.create.copper_tile_slab": "Płyta z miedzianych kafelków", - "block.create.copper_tile_stairs": "Schody z miedziaych kafelków", - "block.create.copper_tiles": "Miedziane kafelki", - "block.create.copper_valve_handle": "Miedziane pokrętło", - "block.create.creative_crate": "Kreatywna skrzynka", - "block.create.creative_fluid_tank": "Kreatywny zbiornik", - "block.create.creative_motor": "Kreatywny silnik", - "block.create.crimsite": "Szkarlit", - "block.create.crimsite_pillar": "Szkarlitowy filar", - "block.create.crimson_window": "Szkarłatne okno", - "block.create.crimson_window_pane": "Szkarłatna szyba okienna", - "block.create.crushing_wheel": "Koło kruszące", - "block.create.crushing_wheel_controller": "Sterownik koła kruszącego", - "block.create.cuckoo_clock": "Zegar z kukułką", - "block.create.cut_andesite": "Przycięty andezyt", - "block.create.cut_andesite_brick_slab": "Przycięta andezytowa ceglana płyta", - "block.create.cut_andesite_brick_stairs": "Przycięte andezytowe ceglane schody", - "block.create.cut_andesite_brick_wall": "Przycięty andezytowy ceglany murek", - "block.create.cut_andesite_bricks": "Przycięte andezytowe cegły", - "block.create.cut_andesite_slab": "Przycięta andezytowa płyta", - "block.create.cut_andesite_stairs": "Przycięte andezytowe schody", - "block.create.cut_andesite_wall": "Przycięty andezytowy murek", - "block.create.cut_asurine": "Przycięty azuryn", - "block.create.cut_asurine_brick_slab": "Przycięta azurynowa ceglana płyta", - "block.create.cut_asurine_brick_stairs": "Przycięte azurynowe ceglane schody", - "block.create.cut_asurine_brick_wall": "Przycięty azurynowy ceglany murek", - "block.create.cut_asurine_bricks": "Przycięte azurynowe cegły", - "block.create.cut_asurine_slab": "Przycięta azurynowa płyta", - "block.create.cut_asurine_stairs": "Przycięte azurynowe schody", - "block.create.cut_asurine_wall": "Przycięty azurynowy murek", - "block.create.cut_calcite": "Przycięty kalcyt", - "block.create.cut_calcite_brick_slab": "Przycięta kalcytowa ceglana płyta", - "block.create.cut_calcite_brick_stairs": "Przycięte klacytowe ceglane schody", - "block.create.cut_calcite_brick_wall": "Przycięty kalcytowy ceglany murek", - "block.create.cut_calcite_bricks": "Przycięte kalcytowe cegły", - "block.create.cut_calcite_slab": "Przycięta kalcytowa płyta", - "block.create.cut_calcite_stairs": "Przycięte kalcytowe schody", - "block.create.cut_calcite_wall": "Przycięty kalcytowy murek", - "block.create.cut_crimsite": "Przycięty szkarlit", - "block.create.cut_crimsite_brick_slab": "Przycięta szkarlitowa ceglana płyta", - "block.create.cut_crimsite_brick_stairs": "Przycięte szkarlitowe ceglane schody", - "block.create.cut_crimsite_brick_wall": "Przycięty szkarlitowy ceglany murek", - "block.create.cut_crimsite_bricks": "Przycięte szkarlitowe cegły", - "block.create.cut_crimsite_slab": "Przycięta szkarlitowa płyta", - "block.create.cut_crimsite_stairs": "Przycięte szkarlitowe schody", - "block.create.cut_crimsite_wall": "Przycięty szkarlitowy murek", - "block.create.cut_deepslate": "Przycięty łupek", - "block.create.cut_deepslate_brick_slab": "Przycięta łupkowa ceglana płyta", - "block.create.cut_deepslate_brick_stairs": "Przycięte łupkowe ceglane schody", - "block.create.cut_deepslate_brick_wall": "Przycięty łupkowy ceglany murek", - "block.create.cut_deepslate_bricks": "Przycięte łupkowe cegły", - "block.create.cut_deepslate_slab": "Przycięta łupkowa płyta", - "block.create.cut_deepslate_stairs": "Przycięte łupkowe schody", - "block.create.cut_deepslate_wall": "Przycięty łupkowy murek", - "block.create.cut_diorite": "Przycięty dioryt", - "block.create.cut_diorite_brick_slab": "Przycięta diorytowa ceglana płyta", - "block.create.cut_diorite_brick_stairs": "Przycięte diorytowe ceglane schody", - "block.create.cut_diorite_brick_wall": "Przycięty diorytowy ceglany murek", - "block.create.cut_diorite_bricks": "Przycięte diorytowe cegły", - "block.create.cut_diorite_slab": "Przycięta diorytowa płyta", - "block.create.cut_diorite_stairs": "Przycięte diorytowe cegły", - "block.create.cut_diorite_wall": "Przycięty diorytowy murek", - "block.create.cut_dripstone": "Przycięty naciek", - "block.create.cut_dripstone_brick_slab": "Przycięta naciekowa ceglana płyta", - "block.create.cut_dripstone_brick_stairs": "Przycięte naciekowe ceglane schody", - "block.create.cut_dripstone_brick_wall": "Przycięty naciekowy ceglany murek", - "block.create.cut_dripstone_bricks": "Przycięte naciekowe cegły", - "block.create.cut_dripstone_slab": "Przycięta naciekowa płyta", - "block.create.cut_dripstone_stairs": "Przycięte naciekowe schody", - "block.create.cut_dripstone_wall": "Przycięty naciekowy murek", - "block.create.cut_granite": "Przycięty granit", - "block.create.cut_granite_brick_slab": "Przycięta granitowa ceglana płyta", - "block.create.cut_granite_brick_stairs": "Przycięte granitowe ceglane schody", - "block.create.cut_granite_brick_wall": "Przycięty granitowy ceglany murek", - "block.create.cut_granite_bricks": "Przycięte granitowe cegły", - "block.create.cut_granite_slab": "Przycięta granitowa płyta", - "block.create.cut_granite_stairs": "Przycięte granitowe schody", - "block.create.cut_granite_wall": "Przycięty granitowy murek", - "block.create.cut_limestone": "Przycięty wapień", - "block.create.cut_limestone_brick_slab": "Przycięta wapienna ceglana płyta", - "block.create.cut_limestone_brick_stairs": "Przycięte wapienne ceglane schody", - "block.create.cut_limestone_brick_wall": "Przycięty wapienny ceglane murek", - "block.create.cut_limestone_bricks": "Przycięte wapienne cegły", - "block.create.cut_limestone_slab": "Przycięta wapienna płyta", - "block.create.cut_limestone_stairs": "Przycięte wapienne schody", - "block.create.cut_limestone_wall": "Przycięty wapienny murek", - "block.create.cut_ochrum": "Przycięty ochran", - "block.create.cut_ochrum_brick_slab": "Przycięta ochranowa ceglana płyta", - "block.create.cut_ochrum_brick_stairs": "Przycięte ochranowe ceglane schody", - "block.create.cut_ochrum_brick_wall": "Przycięty ochranowy ceglany murek", - "block.create.cut_ochrum_bricks": "Przycięte ochranowe cegły", - "block.create.cut_ochrum_slab": "Przycięta ochranowa płyta", - "block.create.cut_ochrum_stairs": "Przycięte ochranowe schody", - "block.create.cut_ochrum_wall": "Przycięty ochranowy murek", - "block.create.cut_scorchia": "Palony przycięty żużel", - "block.create.cut_scorchia_brick_slab": "Wypalona przycięta żużlowa ceglana płyta", - "block.create.cut_scorchia_brick_stairs": "Wypalone przycięte żużlowe ceglane schody", - "block.create.cut_scorchia_brick_wall": "Wypalony przycięty żużlowy murek", - "block.create.cut_scorchia_bricks": "Wypalone przycięte żużlowe cegły", - "block.create.cut_scorchia_slab": "Wypalona przycięta żużlowa płyta", - "block.create.cut_scorchia_stairs": "Wypalone przycięte żużlowa schody", - "block.create.cut_scorchia_wall": "Wypalony przycięty żużlowy murek", - "block.create.cut_scoria": "Przycięty żużel", - "block.create.cut_scoria_brick_slab": "Przycięta żużlowa ceglana płyta", - "block.create.cut_scoria_brick_stairs": "Przycięte żużlowe ceglane schody", - "block.create.cut_scoria_brick_wall": "Przycięty żużlowy ceglany murek", - "block.create.cut_scoria_bricks": "Przycięte żużlowe cegły", - "block.create.cut_scoria_slab": "Przycięta żużlowa płyta", - "block.create.cut_scoria_stairs": "Przycięte żużlowe schody", - "block.create.cut_scoria_wall": "Przycięty żużlowy murek", - "block.create.cut_tuff": "Przycięty tuf", - "block.create.cut_tuff_brick_slab": "Przycięta tufowa ceglana płyta", - "block.create.cut_tuff_brick_stairs": "Przycięte tufowe ceglane schody", - "block.create.cut_tuff_brick_wall": "Przycięty tufowy ceglany murek", - "block.create.cut_tuff_bricks": "Przycięte tufowe cegły", - "block.create.cut_tuff_slab": "Przycięta tufowa płyta", - "block.create.cut_tuff_stairs": "Przycięte tufowe schody", - "block.create.cut_tuff_wall": "Przycięty tufowy murek", - "block.create.cut_veridium": "Przycięty weryd", - "block.create.cut_veridium_brick_slab": "Przycięta werydowa ceglana płyta", - "block.create.cut_veridium_brick_stairs": "Przycięte werydowe ceglane schody", - "block.create.cut_veridium_brick_wall": "Przycięty werydowy ceglany murek", - "block.create.cut_veridium_bricks": "Przycięte werydowe cegły", - "block.create.cut_veridium_slab": "Przycięta werydowa płyta", - "block.create.cut_veridium_stairs": "Przycięte werydowe schody", - "block.create.cut_veridium_wall": "Przycięty werydowy murek", - "block.create.cyan_nixie_tube": "Błękitna lampa cyfrowa", - "block.create.cyan_sail": "Błękitny żagiel", - "block.create.cyan_seat": "Błękitne siedzenie", - "block.create.cyan_toolbox": "Błękitna skrzynka na narzędzia", - "block.create.cyan_valve_handle": "Błękitne pokrętło", - "block.create.dark_oak_window": "Ciemnodębowe okno", - "block.create.dark_oak_window_pane": "Ciemnodębowa szyba okienna", - "block.create.deepslate_pillar": "Łupkowy filar", - "block.create.deepslate_zinc_ore": "Łupkowe złoże cynku", - "block.create.deployer": "Aplikator", - "block.create.depot": "Składnica", - "block.create.diorite_pillar": "Diorytowy filar", - "block.create.display_board": "Tablica wyświetlająca", - "block.create.display_link": "Nadajnik wyświetlacza", - "block.create.dripstone_pillar": "Naciekowy filar", - "block.create.encased_chain_drive": "Izolowany przekaźnik łańcuchowy", - "block.create.encased_fan": "Izolowany wiatrak", - "block.create.encased_fluid_pipe": "Izolowana rura", - "block.create.exposed_copper_shingle_slab": "Zwietrzała płyta z miedzianych dachówek", - "block.create.exposed_copper_shingle_stairs": "Zwietrzałe schody z miedzianych dachówek", - "block.create.exposed_copper_shingles": "Zwietrzałe miedziane dachówki", - "block.create.exposed_copper_tile_slab": "Zwietrzała płyta z miedzianych kafelków", - "block.create.exposed_copper_tile_stairs": "Zwietrzałe schody z miedzianych kafelków", - "block.create.exposed_copper_tiles": "Zwietrzałe miedziane kafelki", - "block.create.fake_track": "Znacznik torów dla map", - "block.create.fluid_pipe": "Rura", - "block.create.fluid_tank": "Zbiornik", - "block.create.fluid_valve": "Zawór", - "block.create.flywheel": "Koło zamachowe", - "block.create.framed_glass": "Oprawione okno", - "block.create.framed_glass_door": "Oprawione szklane drzwi", - "block.create.framed_glass_pane": "Oprawiona szyba", - "block.create.framed_glass_trapdoor": "Oprawiona szklana klapa", - "block.create.gantry_carriage": "Przenośnik suwnicowy", - "block.create.gantry_shaft": "Suwnica", - "block.create.gearbox": "Przekładnia", - "block.create.gearshift": "Przekładnik", - "block.create.glass_fluid_pipe": "Szklana rura", - "block.create.granite_pillar": "Granitowy filar", - "block.create.gray_nixie_tube": "Szara lampa cyfrowa", - "block.create.gray_sail": "Szary żagiel", - "block.create.gray_seat": "Szare siedzenie", - "block.create.gray_toolbox": "Szara skrzynka na narzędzia", - "block.create.gray_valve_handle": "Szare pokrętło", - "block.create.green_nixie_tube": "Zielona lampa cyfrowa", - "block.create.green_sail": "Zielony żagiel", - "block.create.green_seat": "Zielone siedzenie", - "block.create.green_toolbox": "Zielona skrzynka na narzędzia", - "block.create.green_valve_handle": "Zielone pokrętło", - "block.create.hand_crank": "Ręczna korba", - "block.create.haunted_bell": "Nawiedzony dzwon", - "block.create.honey": "Miód", - "block.create.horizontal_framed_glass": "Poziome oprawione szkło", - "block.create.horizontal_framed_glass_pane": "Pozioma oprawiona szyba", - "block.create.hose_pulley": "Krążek z wężem", - "block.create.item_drain": "Odpływ", - "block.create.item_vault": "Kontener na przedmioty", - "block.create.jungle_window": "Dżunglowe okno", - "block.create.jungle_window_pane": "Dżunglowa szyba okienna", - "block.create.large_bogey": "Duży wózek", - "block.create.large_cogwheel": "Duże koło zębate", - "block.create.layered_andesite": "Warstwowy andezyt", - "block.create.layered_asurine": "Warstwowy azuryn", - "block.create.layered_calcite": "Warstwowy kalcyt", - "block.create.layered_crimsite": "Warstwowy szkarlit", - "block.create.layered_deepslate": "Warstwowy łupek", - "block.create.layered_diorite": "Warstwowy dioryt", - "block.create.layered_dripstone": "Warstwowy naciek", - "block.create.layered_granite": "Warstwowy granit", - "block.create.layered_limestone": "Warstwowy wapień", - "block.create.layered_ochrum": "Warstwowy ochran", - "block.create.layered_scorchia": "Palony warstwowy żużel", - "block.create.layered_scoria": "Warstwowy żużel", - "block.create.layered_tuff": "Warstwowy tuf", - "block.create.layered_veridium": "Warstwowy weryd", - "block.create.lectern_controller": "Sterownik pulpitu", - "block.create.light_blue_nixie_tube": "Jasnoniebieska lampa cyfrowa", - "block.create.light_blue_sail": "Jasnoniebieski żagiel", - "block.create.light_blue_seat": "Jasnoniebieskie siedzenie", - "block.create.light_blue_toolbox": "Jasnoniebieska skrzynka na narzędzia", - "block.create.light_blue_valve_handle": "Jasnoniebieskie pokrętło", - "block.create.light_gray_nixie_tube": "Jasnoszara lampa cyfrowa", - "block.create.light_gray_sail": "Jasnoszary żagiel", - "block.create.light_gray_seat": "Jasnoszare siedzenie", - "block.create.light_gray_toolbox": "Jasnoszara skrzynka na narzędzia", - "block.create.light_gray_valve_handle": "Jasnoszare pokrętło", - "block.create.lime_nixie_tube": "Jasnozielona lampa cyfrowa", - "block.create.lime_sail": "Jasnozielony żagiel", - "block.create.lime_seat": "Jasnozielone siedzenie", - "block.create.lime_toolbox": "Jasnozielona skrzynka na narzędzia", - "block.create.lime_valve_handle": "Jasnozielone pokrętło", - "block.create.limestone": "Wapień", - "block.create.limestone_pillar": "Wapienny filar", - "block.create.linear_chassis": "Stelaż liniowy", - "block.create.lit_blaze_burner": "Zapalony płomienny palnik", - "block.create.magenta_nixie_tube": "Karmazynowa lampa cyfrowa", - "block.create.magenta_sail": "Karmazynowy żagiel", - "block.create.magenta_seat": "Karmazynowe siedzenie", - "block.create.magenta_toolbox": "Karmazynowa skrzynka na narzędzia", - "block.create.magenta_valve_handle": "Karmazynowe pokrętło", - "block.create.mechanical_arm": "Ramie mechaniczne", - "block.create.mechanical_bearing": "Mechaniczne łożysko", - "block.create.mechanical_crafter": "Mechaniczny stół rzemieślniczy", - "block.create.mechanical_drill": "Mechaniczne wiertło", - "block.create.mechanical_harvester": "Mechaniczna żniwiarka", - "block.create.mechanical_mixer": "Mechaniczny mikser", - "block.create.mechanical_piston": "Mechaniczny tłok", - "block.create.mechanical_piston_head": "Głowica mechanicznego tłoka", - "block.create.mechanical_plough": "Mechaniczny pług", - "block.create.mechanical_press": "Mechaniczna prasa", - "block.create.mechanical_pump": "Mechaniczna pompa", - "block.create.mechanical_saw": "Mechaniczna piła", - "block.create.metal_bracket": "Metalowy wspornik", - "block.create.metal_girder": "Metalowa belka", - "block.create.metal_girder_encased_shaft": "Metalowa belka z wałem", - "block.create.millstone": "Młynek", - "block.create.minecart_anchor": "Kotwica wagonikowa", - "block.create.mysterious_cuckoo_clock": "Zegar z kukułką", - "block.create.nixie_tube": "Lampa cyfrowa", - "block.create.nozzle": "Dysza", - "block.create.oak_window": "Dębowe okno", - "block.create.oak_window_pane": "Dębowa szyba okienna", - "block.create.ochrum": "Ochran", - "block.create.ochrum_pillar": "Ochranowy filar", - "block.create.orange_sail": "Pomarańczowy żagiel", - "block.create.orange_seat": "Pomarańczowe siedzenie", - "block.create.orange_toolbox": "Pomarańczowa skrznka na narzędzia", - "block.create.orange_valve_handle": "Pomarańczowe pokrętło", - "block.create.ornate_iron_window": "Ozdobne żelazne okno", - "block.create.ornate_iron_window_pane": "Ozdobna żelazne szyba okienna", - "block.create.oxidized_copper_shingle_slab": "Zaśniedziała płyta z miedzianych dachówek", - "block.create.oxidized_copper_shingle_stairs": "Zaśniedziałe schody z miedzianych dachówek", - "block.create.oxidized_copper_shingles": "Zaśniedziałe miedziane dachówki", - "block.create.oxidized_copper_tile_slab": "Zaśniedziała płyta z miedzianych kafelków", - "block.create.oxidized_copper_tile_stairs": "Zaśniedziałe schody z miedzianych kafelków", - "block.create.oxidized_copper_tiles": "Zaśniedziałe miedziane kafelki", - "block.create.peculiar_bell": "Dziwny dzwon", - "block.create.pink_nixie_tube": "Różowa lampa cyfrowa", - "block.create.pink_sail": "Różowy żagiel", - "block.create.pink_seat": "Różowe siedzenie", - "block.create.pink_toolbox": "Różowa skrzynka na narzędzia", - "block.create.pink_valve_handle": "Różowe pokrętło", - "block.create.piston_extension_pole": "Przedłużenie tłoka", - "block.create.placard": "Plakietka", - "block.create.polished_cut_andesite": "Wypolerowany przycięty andezyt", - "block.create.polished_cut_andesite_slab": "Wypolerowana przycięta andezytowa płyta", - "block.create.polished_cut_andesite_stairs": "Wypolerowane przycięte andezytowe schody", - "block.create.polished_cut_andesite_wall": "Wypolerowany przycięty andezytowy murek", - "block.create.polished_cut_asurine": "Wypolerowany przycięty azuryn", - "block.create.polished_cut_asurine_slab": "Wypolerowana przycięta azurynowa płyta", - "block.create.polished_cut_asurine_stairs": "Wypolerowane przycięte azurynowe schody", - "block.create.polished_cut_asurine_wall": "Wypolerowany przycięty azurynowy murek", - "block.create.polished_cut_calcite": "Wypolerowany przycięty kalcyt", - "block.create.polished_cut_calcite_slab": "Wypolerowana przycięta kalcytowa płyta", - "block.create.polished_cut_calcite_stairs": "Wypolerowane przycięte kalcytowe schody", - "block.create.polished_cut_calcite_wall": "Wypolerowany przycięty kalcytowy murek", - "block.create.polished_cut_crimsite": "Wypolerowany przycięty szkarlit", - "block.create.polished_cut_crimsite_slab": "Wypolerowana przycięta szkarlitowa płyta", - "block.create.polished_cut_crimsite_stairs": "Wypolerowane przycięte szkarlitowe schody", - "block.create.polished_cut_crimsite_wall": "Wypolerowany przycięty szkarlitowy murek", - "block.create.polished_cut_deepslate": "Wypolerowany przycięty łupek", - "block.create.polished_cut_deepslate_slab": "Wypolerowana przycięta łupkowa płyta", - "block.create.polished_cut_deepslate_stairs": "Wypolerowane przycięte łupkowe schody", - "block.create.polished_cut_deepslate_wall": "Wypolerowany przycięty łupkowy murek", - "block.create.polished_cut_diorite": "Wypolerowany przycięty dioryt", - "block.create.polished_cut_diorite_slab": "Wypolerowana przycięta driorytowa płyta", - "block.create.polished_cut_diorite_stairs": "Wypolerowane przycięte diorytowe schody", - "block.create.polished_cut_diorite_wall": "Wypolerowany przycięty diorytowy murek", - "block.create.polished_cut_dripstone": "Wypolerowany przycięty naciek", - "block.create.polished_cut_dripstone_slab": "Wypolerowana przycięta naciekowa płyta", - "block.create.polished_cut_dripstone_stairs": "Wypolerowane przycięte naciekowe schody", - "block.create.polished_cut_dripstone_wall": "Wypolerowany przycięty naciekowy murek", - "block.create.polished_cut_granite": "Wypolerowany przycięty granit", - "block.create.polished_cut_granite_slab": "Wypolerowana przycięta granitowa płyta", - "block.create.polished_cut_granite_stairs": "Wypolerowane przycięte granitowe schody", - "block.create.polished_cut_granite_wall": "Wypolerowany przycięty granitowy murek", - "block.create.polished_cut_limestone": "Wypolerowany przycięty wapień", - "block.create.polished_cut_limestone_slab": "Wypolerowana przycięta wapienna płyta", - "block.create.polished_cut_limestone_stairs": "Wypolerowane przycięte wapienne schody", - "block.create.polished_cut_limestone_wall": "Wypolerowany przycięty wapienny murek", - "block.create.polished_cut_ochrum": "Wypolerowany przycięty ochran", - "block.create.polished_cut_ochrum_slab": "Wypolerowana przycięta ochranowa płyta", - "block.create.polished_cut_ochrum_stairs": "Wypolerowane przycięte ochranowe schody", - "block.create.polished_cut_ochrum_wall": "Wypolerowany przycięty ochranowy murek", - "block.create.polished_cut_scorchia": "Palony wypolerowany przycięty żużel", - "block.create.polished_cut_scorchia_slab": "Palona wypolerowana przycięta żużlowa płyta", - "block.create.polished_cut_scorchia_stairs": "Palone wypolerowane przycięte żużlowe schody", - "block.create.polished_cut_scorchia_wall": "Palony wypolerowany przycięty żużlowy murek", - "block.create.polished_cut_scoria": "Wypolerowany przycięty żużel", - "block.create.polished_cut_scoria_slab": "Wypolerowana przycięta żużlowa płyta", - "block.create.polished_cut_scoria_stairs": "Wypolerowane przycięte żużlowe schody", - "block.create.polished_cut_scoria_wall": "Wypolerowany przycięty żużlowy murek", - "block.create.polished_cut_tuff": "Wypolerowany przycięty tuf", - "block.create.polished_cut_tuff_slab": "Wypolerowana przycięta tufowa płyta", - "block.create.polished_cut_tuff_stairs": "Wypolerowane przycięte tufowe schody", - "block.create.polished_cut_tuff_wall": "Wypolerowany przycięty tufowy murek", - "block.create.polished_cut_veridium": "Wypolerowany przycięty weryd", - "block.create.polished_cut_veridium_slab": "Wypolerowana przycięta werydowa płyta", - "block.create.polished_cut_veridium_stairs": "Wypolerowane przycięte werydowe schody", - "block.create.polished_cut_veridium_wall": "Wypolerowany przycięty werydowy murek", - "block.create.portable_fluid_interface": "Przenośny interfejs płynów", - "block.create.portable_storage_interface": "Przenośny interfejs magazynu", - "block.create.powered_latch": "Zaawansowany zasilany przełącznik", - "block.create.powered_shaft": "Zasilany wał", - "block.create.powered_toggle_latch": "Zasilany przełącznik", - "block.create.pulley_magnet": "Krążek z magnesem", - "block.create.pulse_extender": "Przedłużacz pulsu", - "block.create.pulse_repeater": "Przekaźnik pulsowy", - "block.create.purple_nixie_tube": "Fioletowa lampa cyfrowa", - "block.create.purple_sail": "Fioletowy żagiel", - "block.create.purple_seat": "Fioletowe siedzenie", - "block.create.purple_toolbox": "Fioletowa skrzynka na narzędzia", - "block.create.purple_valve_handle": "Fioletowe pokrętło", - "block.create.radial_chassis": "Stelaż promienisty", - "block.create.railway_casing": "Obudowa kolejowa", - "block.create.raw_zinc_block": "Blok rudy cynku", - "block.create.red_nixie_tube": "Czerwona lampa cyfrowa", - "block.create.red_sail": "Czerwony żagiel", - "block.create.red_seat": "Czerwone siedzenie", - "block.create.red_toolbox": "Czerwona skrzynka na narzędzia", - "block.create.red_valve_handle": "Czerwone pokrętło", - "block.create.redstone_contact": "Przełącznik kontaktowy", - "block.create.redstone_link": "Emiter sygnału", - "block.create.refined_radiance_casing": "Świetlista obudowa", - "block.create.rope": "Lina", - "block.create.rope_pulley": "Krążek z liną", - "block.create.rose_quartz_block": "Blok różowego kwarcu", - "block.create.rose_quartz_lamp": "Lampa z różowego kwarcu", - "block.create.rose_quartz_tiles": "Kafelki z różowego kwarcu", - "block.create.rotation_speed_controller": "Sterownik prędkości obrotu", - "block.create.sail_frame": "Rama żagla", - "block.create.schematic_table": "Stół do planowania", - "block.create.schematicannon": "Schematoarmata", - "block.create.scorchia": "Palony żużel", - "block.create.scorchia_pillar": "Palony żużlowy filar", - "block.create.scoria": "Żużel", - "block.create.scoria_pillar": "Żużlowy filar", - "block.create.secondary_linear_chassis": "Drugorzędny liniowy stelaż", - "block.create.sequenced_gearshift": "Przekładnik sekwencjonalny", - "block.create.shadow_steel_casing": "Mroczna obudowa", - "block.create.shaft": "Wał", - "block.create.small_andesite_brick_slab": "Płyta z małych andezytowych cegieł", - "block.create.small_andesite_brick_stairs": "Schody z małych andezytowych cegieł", - "block.create.small_andesite_brick_wall": "Murek z małych andezytowych cegieł", - "block.create.small_andesite_bricks": "Małe andezytowe cegły", - "block.create.small_asurine_brick_slab": "Płyta z małych azurynowych cegieł", - "block.create.small_asurine_brick_stairs": "Schody z małych azurynowuch cegieł", - "block.create.small_asurine_brick_wall": "Murek z małych azurynowych cegieł", - "block.create.small_asurine_bricks": "Małe azurynowe cegły", - "block.create.small_bogey": "Mały wózek", - "block.create.small_calcite_brick_slab": "Płyta z małych kalcytowych cegieł", - "block.create.small_calcite_brick_stairs": "Schody z małych kalcytowych cegieł", - "block.create.small_calcite_brick_wall": "Murek z młaych kalcytowych cegieł", - "block.create.small_calcite_bricks": "Małe kalcytowe cegły", - "block.create.small_crimsite_brick_slab": "Płyta z małych szkarlitowych cegieł", - "block.create.small_crimsite_brick_stairs": "Schody z malych szkarlitowych cegieł", - "block.create.small_crimsite_brick_wall": "Murek z małych szkarlitowych cegieł", - "block.create.small_crimsite_bricks": "Małe szkarlitowe cegły", - "block.create.small_deepslate_brick_slab": "Płyta z małych łupkowych cegieł", - "block.create.small_deepslate_brick_stairs": "Schody z małych łupkowych cegieł", - "block.create.small_deepslate_brick_wall": "Murek z małych łupkowych cegieł", - "block.create.small_deepslate_bricks": "Małe łupkowe cegły", - "block.create.small_diorite_brick_slab": "Płyta z małych diorytowych cegieł", - "block.create.small_diorite_brick_stairs": "Schody z małych diorytowych cegieł", - "block.create.small_diorite_brick_wall": "Murek z małych diorytowych cegieł", - "block.create.small_diorite_bricks": "Małe diorytowe cegły", - "block.create.small_dripstone_brick_slab": "Płyta z małych naciekowych cegieł", - "block.create.small_dripstone_brick_stairs": "Schody z małych naciekowych cegieł", - "block.create.small_dripstone_brick_wall": "Murek z małych naciekowych cegieł", - "block.create.small_dripstone_bricks": "Małe naciekowe cegły", - "block.create.small_granite_brick_slab": "Płyta z małych granitowych cegieł", - "block.create.small_granite_brick_stairs": "Schody z małych granitowych cegieł", - "block.create.small_granite_brick_wall": "Murek z małych granitowych cegieł", - "block.create.small_granite_bricks": "Małe granitowe cagły", - "block.create.small_limestone_brick_slab": "Płyta z małych wapiennych cegieł", - "block.create.small_limestone_brick_stairs": "Schody z małych wapiennych cegieł", - "block.create.small_limestone_brick_wall": "Murek z małych wapiennych cegieł", - "block.create.small_limestone_bricks": "Małe wapienne cegły", - "block.create.small_ochrum_brick_slab": "Płyta z małych ochranowych cegieł", - "block.create.small_ochrum_brick_stairs": "Schody z małych ochranowych cegieł", - "block.create.small_ochrum_brick_wall": "Murek z małych ochranowych cegieł", - "block.create.small_ochrum_bricks": "Małe ochranowe cegły", - "block.create.small_rose_quartz_tiles": "Małe kafelki z różowego kwarcu", - "block.create.small_scorchia_brick_slab": "Płyta z małych palonych żużlowych cegieł", - "block.create.small_scorchia_brick_stairs": "Schody z małych palonych żużlowych cegieł", - "block.create.small_scorchia_brick_wall": "Murek z małych palonych żużlowych cegieł", - "block.create.small_scorchia_bricks": "Małe palone żużlowe cegły", - "block.create.small_scoria_brick_slab": "Płyta z małych żużlowych cegieł", - "block.create.small_scoria_brick_stairs": "Schody z małych żużlowych cegieł", - "block.create.small_scoria_brick_wall": "Murek z małych żużlowych cegieł", - "block.create.small_scoria_bricks": "Małe żużlowe cegły", - "block.create.small_tuff_brick_slab": "Płyta z małych tufowych cegieł", - "block.create.small_tuff_brick_stairs": "Schody z małych tufowych cegieł", - "block.create.small_tuff_brick_wall": "Murek z małych tufowych cegieł", - "block.create.small_tuff_bricks": "Małe tufowe cegły", - "block.create.small_veridium_brick_slab": "Płyta z małych werydowych cegieł", - "block.create.small_veridium_brick_stairs": "Schody z małych werydowych cegieł", - "block.create.small_veridium_brick_wall": "Murek z małych werydowych cegieł", - "block.create.small_veridium_bricks": "Małe werydowe cegły", - "block.create.smart_chute": "Inteligentny Zsyp", - "block.create.smart_fluid_pipe": "Inteligentna rura", - "block.create.speedometer": "Prędkościomierz", - "block.create.spout": "Napełniacz", - "block.create.spruce_window": "Świerkowe okno", - "block.create.spruce_window_pane": "Świerkowa szyba okienna", - "block.create.steam_engine": "Silnik parowy", - "block.create.steam_whistle": "Gwizdek parowy", - "block.create.steam_whistle_extension": "Przedłużenie gwizdka parowego", - "block.create.sticker": "Przyklejacz", - "block.create.sticky_mechanical_piston": "Lepki mechaniczny tłok", - "block.create.stockpile_switch": "Przełącznik zawartościowy", - "block.create.stressometer": "Miernik obciążenia", - "block.create.tiled_glass": "Kafelkowane szkło", - "block.create.tiled_glass_pane": "Kafelkowana szyba", - "block.create.track": "Tor kolejowy", - "block.create.track_observer": "Detektor kolejowy", - "block.create.track_signal": "Sygnał kolejowy", - "block.create.track_station": "Stacja kolejowa", - "block.create.train_door": "Drzwi od pociągu", - "block.create.train_trapdoor": "Klapa od pociągu", - "block.create.tuff_pillar": "Tufowy filar", - "block.create.turntable": "Talerz obrotowy", - "block.create.veridium": "Weryd", - "block.create.veridium_pillar": "Werydowy filar", - "block.create.vertical_framed_glass": "Pionowe oprawione szkło", - "block.create.vertical_framed_glass_pane": "Pionowa oprawiona szyba", - "block.create.warped_window": "Spaczone okno", - "block.create.warped_window_pane": "Spaczona szyba okienna", - "block.create.water_wheel": "Koło wodne", - "block.create.waxed_copper_shingle_slab": "Woskowana płyta z miedzianych dachówek", - "block.create.waxed_copper_shingle_stairs": "Woskowane schody z miedzianych dachówek", - "block.create.waxed_copper_shingles": "Woskowane miedziane dachówki", - "block.create.waxed_copper_tile_slab": "Woskowana płyta z miedzianych kafelków", - "block.create.waxed_copper_tile_stairs": "Woskowane schody z miedzianych kafelków", - "block.create.waxed_copper_tiles": "Woskowane miedziane kafelki", - "block.create.waxed_exposed_copper_shingle_slab": "Woskowana zwietrzała płyta z miedzianych dachówek", - "block.create.waxed_exposed_copper_shingle_stairs": "Woskowane zwietrzałe schody z miedzianych dachówek", - "block.create.waxed_exposed_copper_shingles": "Woskowane zwietrzałe miedziane dachówki", - "block.create.waxed_exposed_copper_tile_slab": "Woskowana zwietrzała płyta z miedzianych kafelków", - "block.create.waxed_exposed_copper_tile_stairs": "Woskowane zwietrzałe schody z miedzianych kafelków", - "block.create.waxed_exposed_copper_tiles": "Woskowane zwietrzałe miedziane kafelki", - "block.create.waxed_oxidized_copper_shingle_slab": "Woskowana utleniona płyta z miedzianych dachówek", - "block.create.waxed_oxidized_copper_shingle_stairs": "Woskowane utlenione schody z miedzianych dachówek", - "block.create.waxed_oxidized_copper_shingles": "Woskowane utlenione miedziane dachówki", - "block.create.waxed_oxidized_copper_tile_slab": "Woskowana utleniona płyta z miedzianych kafelków", - "block.create.waxed_oxidized_copper_tile_stairs": "Woskowane utlenione schody z miedzianych kafelków", - "block.create.waxed_oxidized_copper_tiles": "Woskowane utlenione miedziane kafelki", - "block.create.waxed_weathered_copper_shingle_slab": "Woskowana zaśniedziała płyta z miedzianych dachówek", - "block.create.waxed_weathered_copper_shingle_stairs": "Woskowane zaśniedziałe schody z miedzianych dachówek", - "block.create.waxed_weathered_copper_shingles": "Woskowane zaśniedziałe miedziane dachówki", - "block.create.waxed_weathered_copper_tile_slab": "Woskowana zaśniedziała płyta z miedzianych kafelków", - "block.create.waxed_weathered_copper_tile_stairs": "Woskowane zaśniedziałe schody z miedzianych kafelków", - "block.create.waxed_weathered_copper_tiles": "Woskowane zaśniedziałe miedziane kafelki", - "block.create.weathered_copper_shingle_slab": "Zaśniedziała płyta z miedzianych dachówek", - "block.create.weathered_copper_shingle_stairs": "Zaśniedziałe schody z miedzianych dachówek", - "block.create.weathered_copper_shingles": "Zaśniedziałe miedziane dachówki", - "block.create.weathered_copper_tile_slab": "Zaśniedziała płyta z miedzianych kafelków", - "block.create.weathered_copper_tile_stairs": "Zaśniedziałe schody z miedzianych kafelków", - "block.create.weathered_copper_tiles": "Zaśniedziałe miedziane kafelki", - "block.create.weighted_ejector": "Wyrzutnia odważnikowa", - "block.create.white_nixie_tube": "Biała lampa cyfrowa", - "block.create.white_sail": "Biały żagiel", - "block.create.white_seat": "Białe siedzenie", - "block.create.white_toolbox": "Biała skrzynka na narzędzia", - "block.create.white_valve_handle": "Białe pokrętło", - "block.create.windmill_bearing": "Łożysko wiatraka", - "block.create.wooden_bracket": "Drewniany wspornik", - "block.create.yellow_nixie_tube": "Żółta lampa cyfrowa", - "block.create.yellow_sail": "Żółty żagiel", - "block.create.yellow_seat": "Żółte siedzenie", - "block.create.yellow_toolbox": "Żółta skrzynka na narzędzia", - "block.create.yellow_valve_handle": "Żółte pokrętło", - "block.create.zinc_block": "Blok cynku", - "block.create.zinc_ore": "Złoże cynku", - - "enchantment.create.capacity": "Pojemność", - "enchantment.create.potato_recovery": "Odzyskiwanie", - - "entity.create.carriage_contraption": "Maszyna wagonowa", - "entity.create.contraption": "Maszyna", - "entity.create.crafting_blueprint": "Szablon konstruowania", - "entity.create.gantry_contraption": "Maszyna suwnicowa", - "entity.create.potato_projectile": "Ziemniaczany pocisk", - "entity.create.seat": "Siedzenie", - "entity.create.stationary_contraption": "Maszyna stacjonarna", - "entity.create.super_glue": "Super Glue", - - "fluid.create.potion": "Mikstura", - "fluid.create.tea": "Herbatka Budowniczego", - - "item.create.andesite_alloy": "Stop andezytu", - "item.create.attribute_filter": "Filtr atrybutowy", - "item.create.bar_of_chocolate": "Tabliczka czekolady", - "item.create.belt_connector": "Taśma", - "item.create.blaze_cake": "Płomienne ciasto", - "item.create.blaze_cake_base": "Baza płomiennego ciasta", - "item.create.brass_hand": "Mosiężna dłoń", - "item.create.brass_ingot": "Sztabka mosiądzu", - "item.create.brass_nugget": "Bryłka mosiądzu", - "item.create.brass_sheet": "Arkusz mosiądzu", - "item.create.builders_tea": "Herbatka Budowniczego", - "item.create.chest_minecart_contraption": "Maszyna w wagoniku ze skrzynią", - "item.create.chocolate_bucket": "Wiadro czekolady", - "item.create.chocolate_glazed_berries": "Jagody w czekoladzie", - "item.create.chromatic_compound": "Związek chromatyczny", - "item.create.cinder_flour": "Rozżarzona mąka", - "item.create.copper_backtank": "Miedziany zbiornik w plecaku", - "item.create.copper_backtank_placeable": "Stacjonarny miedziany zbiornik w plecaku", - "item.create.copper_nugget": "Bryłka miedzi", - "item.create.copper_sheet": "Arkusz miedzi", - "item.create.crafter_slot_cover": "Przykrywka na slot stołu rzemieślniczego", - "item.create.crafting_blueprint": "Szablon konstruowania", - "item.create.creative_blaze_cake": "Kreatywne płomienne ciasto", - "item.create.crushed_aluminum_ore": "Rozkruszona ruda żelaza", - "item.create.crushed_copper_ore": "Rozkruszona ruda miedzi", - "item.create.crushed_gold_ore": "Rozkruszona ruda złota", - "item.create.crushed_iron_ore": "Rozkruszona ruda żelaza", - "item.create.crushed_lead_ore": "Rozkruszona ruda ołowiu", - "item.create.crushed_nickel_ore": "Rozkruszona ruda niklu", - "item.create.crushed_osmium_ore": "Rozkruszona ruda osmu", - "item.create.crushed_platinum_ore": "Rozkruszona ruda platyny", - "item.create.crushed_quicksilver_ore": "Rozkruszona ruda rtęci", - "item.create.crushed_silver_ore": "Rozkruszona ruda srebra", - "item.create.crushed_tin_ore": "Rozkruszona ruda cyny", - "item.create.crushed_uranium_ore": "Rozkruszona ruda uranu", - "item.create.crushed_zinc_ore": "Rozkruszona ruda cynku", - "item.create.diving_boots": "Buty do nurkowania", - "item.create.diving_helmet": "Hełm do nurkowania", - "item.create.dough": "Ciasto", - "item.create.electron_tube": "Lampa elektronowa", - "item.create.empty_blaze_burner": "Pusty płomienny palnik", - "item.create.empty_schematic": "Pusty schemat", - "item.create.experience_nugget": "Bryłka doświadczenia", - "item.create.extendo_grip": "Wydłużony Chwytak", - "item.create.filter": "Filtr", - "item.create.furnace_minecart_contraption": "Maszyna w wagoniku z piecem", - "item.create.goggles": "Gogle inżyniera", - "item.create.golden_sheet": "Arkusz złota", - "item.create.handheld_worldshaper": "Ręczny kształter", - "item.create.honey_bucket": "Wiadro miodu", - "item.create.honeyed_apple": "Jabłko w miodzie", - "item.create.incomplete_precision_mechanism": "Niedokończony precyzyjny mechanizm", - "item.create.incomplete_track": "Niedokończone tory kolejowe", - "item.create.iron_sheet": "Arkusz żelaza", - "item.create.linked_controller": "Zdalny sterownik", - "item.create.minecart_contraption": "Maszyna w wagoniku", - "item.create.minecart_coupling": "Łącznik wagoników", - "item.create.polished_rose_quartz": "Wypolerowany różowy kwarc", - "item.create.potato_cannon": "Armata na ziemniaki", - "item.create.powdered_obsidian": "Sproszkowany obsydian", - "item.create.precision_mechanism": "Precyzyjny mechanizm", - "item.create.propeller": "Śmigło", - "item.create.raw_zinc": "Ruda cynku", - "item.create.red_sand_paper": "Czerwony papier ścierny", - "item.create.refined_radiance": "Świetlisty materiał", - "item.create.rose_quartz": "Różowy kwarc", - "item.create.sand_paper": "Papier ścierny", - "item.create.schedule": "Harmonogram kolejowy", - "item.create.schematic": "Schemat", - "item.create.schematic_and_quill": "Schemat z piórem", - "item.create.shadow_steel": "Mroczna stal", - "item.create.sturdy_sheet": "Zbity arkusz", - "item.create.super_glue": "Super Glue", - "item.create.sweet_roll": "Słodka bułka", - "item.create.tree_fertilizer": "Nawóz do drzew", - "item.create.unprocessed_obsidian_sheet": "Nieprzerobiony arkusz obsydianowy", - "item.create.vertical_gearbox": "Pionowa przekładnia", - "item.create.wand_of_symmetry": "Różdżka symetrii", - "item.create.wheat_flour": "Mąka pszenna", - "item.create.whisk": "Trzepaczka", - "item.create.wrench": "Klucz", - "item.create.zinc_ingot": "Sztabka cynku", - "item.create.zinc_nugget": "Bryłka cynku", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Witaj w Create", - "advancement.create.root.desc": "Czas, aby zacząć tworzyć wspaniałe Maszyny!", - "advancement.create.andesite_alloy": "Słynne stopy", - "advancement.create.andesite_alloy.desc": "Materiały z Create mają czasami dziwne nazwy, stop andezytu jest jednym z nich.", - "advancement.create.andesite_casing": "Epoka andezytu łupanego", - "advancement.create.andesite_casing.desc": "Użyj stopu andezytu, aby wytworzyć podstawową obudowę.", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "Wytłocz kilka arkuszy w mechanicznej prasie.", - "advancement.create.encased_fan": "Dzisiaj w nocy silny wiatr", - "advancement.create.encased_fan.desc": "Postaw i zasil izolowany wiatrak.", - "advancement.create.fan_processing": "Receptury molekularne", - "advancement.create.fan_processing.desc": "Użyj izolowanego wiatraka do obróbki przedmiotów.", - "advancement.create.saw_processing": "Najostrzejsze narzędzie w szopie", - "advancement.create.saw_processing.desc": "Użyj piły mechanicznej do obróbki przedmiotów.", - "advancement.create.compacting": "Kompaktoinator", - "advancement.create.compacting.desc": "Użyj prasy i tygla, aby przerobić więcej na mniej.", - "advancement.create.belt": "Taśma produkcyjna", - "advancement.create.belt.desc": "Połącz dwa wały tworząc taśmociąg.", - "advancement.create.funnel": "Estetyka lotniskowa", - "advancement.create.funnel.desc": "Włóż lub wyjmij przedmioty z pojemnika za pomocą lejka.", - "advancement.create.chute": "Czarna dziura", - "advancement.create.chute.desc": "Postaw zsyp - pionową część taśmociągu.", - "advancement.create.mechanical_mixer": "Pomieszanie z poplątaniem", - "advancement.create.mechanical_mixer.desc": "Połącz składniki w mechanicznym mikserze", - "advancement.create.burner": "Żywe ognisko", - "advancement.create.burner.desc": "Zdobądź płomeinny palnik.", - "advancement.create.water_wheel": "Energia odnawialna", - "advancement.create.water_wheel.desc": "Postaw koło wodne i spraw, aby zaczęło się kręcić!", - "advancement.create.windmill": "Łagodna bryza", - "advancement.create.windmill.desc": "Skonstruuj działający wiatrak.", - "advancement.create.shifting_gears": "Przekładnia", - "advancement.create.shifting_gears.desc": "Połącz duże koło zębate i małe koło zębate, co pozwoli zmienić prędkość obrotu Twojej maszyny.", - "advancement.create.millstone": "Kieszonkowy rozgniatacz", - "advancement.create.millstone.desc": "Postaw i wpraw w ruch młynek.", - "advancement.create.super_glue": "Co Kropelka sklei, sklei...", - "advancement.create.super_glue.desc": "Sklej ze sobą bloki za pomocą Super Glue.", - "advancement.create.contraption_actors": "Ruch celowy", - "advancement.create.contraption_actors.desc": "Zbuduj maszynę z wiertłami, piłami lub żniwiarkami na pokładzie.", - "advancement.create.portable_storage_interface": "Wymiana przejazdowa", - "advancement.create.portable_storage_interface.desc": "Użyj przenośnego interfejsu magazynu by włożyć lub wyjąć przedmioty do maszyny.", - "advancement.create.wrench_goggles": "Wyposażony", - "advancement.create.wrench_goggles.desc": "Posiądź gogle inżyniera i klucz.", - "advancement.create.stressometer": "Ale że jakie obciążenie?", - "advancement.create.stressometer.desc": "Połóż i wpraw w ruch miernik obciążenia. Popatrz na niego przez Twoje gogle, aby poznać dokładną wartość.", - "advancement.create.cuckoo_clock": "Czy to już czas?", - "advancement.create.cuckoo_clock.desc": "Zauważ jak twój zegar z kukułką ogłasza porę snu.", - "advancement.create.windmill_maxed": "Silna bryza", - "advancement.create.windmill_maxed.desc": "Skonstruuj wiatrak o maksymalnej mocy.", - "advancement.create.ejector_maxed": "Czempion trampolinowy", - "advancement.create.ejector_maxed.desc": "Zostań wystrzelony dalej niż 30 bloków przez wyrzutnie odważnikową.", - "advancement.create.pulley_maxed": "Lina do nikąd", - "advancement.create.pulley_maxed.desc": "Wydłuż krążek z liną na ponad 200 bloków.", - "advancement.create.cart_pickup": "Silne łapy", - "advancement.create.cart_pickup.desc": "Podnieś maszynę wagonikową z ponad 200 blokami.", - "advancement.create.anvil_plough": "Kowadlana artyleria", - "advancement.create.anvil_plough.desc": "Wstrzel kowadło za pomocą mechanicznych pługów.", - "advancement.create.lava_wheel_00000": "Energia geotermalna", - "advancement.create.lava_wheel_00000.desc": "To nie powinno zadziałać.§7\n(Ukryty postęp)", - "advancement.create.hand_crank_000": "Sesja wyciskania", - "advancement.create.hand_crank_000.desc": "Użyj ręcznej korby aż do wykończenia.§7\n(Ukryty postęp)", - "advancement.create.belt_funnel_kiss": "Zakochana para", - "advancement.create.belt_funnel_kiss.desc": "Spraw, aby dwa lejki na taśmociągu się pocałowały", - "advancement.create.stressometer_maxed": "Idealne obciążenie", - "advancement.create.stressometer_maxed.desc": "Dostań 100% odczyt miernika obicążenia.§7\n(Ukryty postęp)", - "advancement.create.copper": "Twardsze skały", - "advancement.create.copper.desc": "Zdobądź trochę miedzi na swoje przyszłe wynalazki dotyczące cieczy.", - "advancement.create.copper_casing": "Epoka miedzi", - "advancement.create.copper_casing.desc": "Użyj arkuszy miedzi i odrobiny drewna, aby wytworzyć miedzianą obudowę.", - "advancement.create.spout": "Plum", - "advancement.create.spout.desc": "Patrz jak przedmiot napełnia się płynem przy użyciu napełniacza.", - "advancement.create.drain": "Suszenie bębnowe", - "advancement.create.drain.desc": "Zobacz jak przedmiot zawierający ciecz zostaje opróżniony przez odpływ.", - "advancement.create.steam_engine": "Rewolucja przemysłowa", - "advancement.create.steam_engine.desc": "Użyj silnika parowego do generowania mocy.", - "advancement.create.steam_whistle": "Anielski głos", - "advancement.create.steam_whistle.desc": "Uruchom gwizdek parowy.", - "advancement.create.backtank": "Pneumatyczne zaopatrzenie", - "advancement.create.backtank.desc": "Stwórz miedziany zbiornik w plecaku i napełnij go sprężonym powietrzem.", - "advancement.create.diving_suit": "Gotowy na głębiny", - "advancement.create.diving_suit.desc": "Załóż hełm do nurkowania razem z miedzianym zbiornikiem w plecaku i wskocz do wody.", - "advancement.create.mechanical_pump_0": "Pod ciśnieniem", - "advancement.create.mechanical_pump_0.desc": "Postaw i zasil mechaniczną pompę.", - "advancement.create.glass_pipe": "Płynny podglądacz", - "advancement.create.glass_pipe.desc": "Patrz jak ciecz płynie przez rurę z okienkiem. Użyj klucza na prostej rurze, aby dodać do niej okno.", - "advancement.create.water_supply": "Wysysacz kałuż", - "advancement.create.water_supply.desc": "Użyj ssącą końcówkę rury lub pompy aby wessać blok wody.", - "advancement.create.hose_pulley": "Wyciek przemysłowy", - "advancement.create.hose_pulley.desc": "Obniż krążek z wężem, aby osuszyć lub wypełnić płynem jakiś obszar.", - "advancement.create.chocolate_bucket": "Świat wyobraźni", - "advancement.create.chocolate_bucket.desc": "Zdobądź wiadro płynnej czekolady.", - "advancement.create.honey_drain": "Autonomiczne pszczelarstwo", - "advancement.create.honey_drain.desc": "Użyj rur, aby pompować miód z gniazda lub ula.", - "advancement.create.hose_pulley_lava": "Pompa płaszczowa", - "advancement.create.hose_pulley_lava.desc": "Wypompuj lawę ze zbiornika tak dużego, aby był uznawany za nieskończony.", - "advancement.create.steam_engine_maxed": "Pełną parą", - "advancement.create.steam_engine_maxed.desc": "Uruchom boiler na najwyższym stopniu mocy.", - "advancement.create.foods": "Zbalansowana dieta", - "advancement.create.foods.desc": "Użyj tego samego napełniacza, aby stworzyć jagody w czekoladzie, jabłko w miodzie i słodką bułkę.", - "advancement.create.diving_suit_lava": "W magmie z magmołazami.", - "advancement.create.diving_suit_lava.desc": "Spróbuj pływać lawie w swoim miedzianym stroju nurka.§7\n(Ukryty postęp)", - "advancement.create.chained_drain": "Toczymy się", - "advancement.create.chained_drain.desc": "Patrz na przedmiot toczący się po kilku odpływach.§7\n(Ukryty postęp)", - "advancement.create.cross_streams": "Nie krzyżuj strumieni!", - "advancement.create.cross_streams.desc": "Patrz jak dwa płyny stykają się w Toim systemie rur.§7\n(Ukryty postęp)", - "advancement.create.pipe_organ": "Organy mechaniczne", - "advancement.create.pipe_organ.desc": "Dołącz 12 gwizdków parowych o różnej wysokości do jednego zbiornika.§7\n(Ukryty postęp)", - "advancement.create.brass": "Prawdziwe stopy", - "advancement.create.brass.desc": "Zmieszaj miedź i cynk, tworząc mosiądz.", - "advancement.create.brass_casing": "Epoka brązu", - "advancement.create.brass_casing.desc": "Użyj nowo poznany mosiądz i odrobiny drewna, aby wytworzyć ulepszoną obudowę.", - "advancement.create.rose_quartz": "Różowe diamenty", - "advancement.create.rose_quartz.desc": "Wypoleruj trochę różowego kwarcu.", - "advancement.create.deployer": "Dźgnij, postaw i zniszcz", - "advancement.create.deployer.desc": "Postaw i wpraw w ruch aplikator, Twoje idealne odbicie.", - "advancement.create.precision_mechanism": "Skomplikowana ciekawostka", - "advancement.create.precision_mechanism.desc": "Wytwórz precyzyjny mechanizm.", - "advancement.create.speed_controller": "Inżynierowie go nienawidzą!", - "advancement.create.speed_controller.desc": "Postaw sterownik prędkości obrotu, najlepsze narzędzie do zmiany przekładni.", - "advancement.create.mechanical_arm": "Ręce pełne roboty", - "advancement.create.mechanical_arm.desc": "Wytwórz ramię mechaniczne, wybierz miejsca wejścia i wyjścia, postaw je i wpraw w ruch. Patrz jak robi wszystko za Ciebie.", - "advancement.create.mechanical_crafter": "Automatyczna konstrukcja", - "advancement.create.mechanical_crafter.desc": "Postaw i zasil kilka mechanicznych stołów rzemieślniczych.", - "advancement.create.crushing_wheel": "Nierozłączna para", - "advancement.create.crushing_wheel.desc": "Wytwórz parę kół kruszących, aby kruszyły więcej materiałów w krótszym czasie.", - "advancement.create.haunted_bell": "Zmysł ciemności", - "advancement.create.haunted_bell.desc": "Zadzwoń nawiedzonym dzwonem.", - "advancement.create.clockwork_bearing": "Jaką mamy godzinę?", - "advancement.create.clockwork_bearing.desc": "Skonstruuj strukturę obracającą się na mechanizmie zegarowym.", - "advancement.create.display_link": "Ważne dane", - "advancement.create.display_link.desc": "Użyj nadajnika wyświetlającego aby wyświetlać informacje.", - "advancement.create.potato_cannon": "W sam środek!", - "advancement.create.potato_cannon.desc": "Pokanaj przeciwnika przy użyciu armaty na ziemniaki.", - "advancement.create.extendo_grip": "Dalej dalej ręce Gadżeta!", - "advancement.create.extendo_grip.desc": "Złap w ręce Wydłużony Chwytak.", - "advancement.create.linked_controller": "Zdalne sterowanie", - "advancement.create.linked_controller.desc": "Aktywuj emiter sygnału za pomocą zdalnego sterownika.", - "advancement.create.arm_blaze_burner": "Automatyczny wlot paliwowy", - "advancement.create.arm_blaze_burner.desc": "Poinstruuj ramię mechaniczne, jak napełniać płomienny palnik.", - "advancement.create.crusher_maxed_0000": "Miażdżąca prędkość", - "advancement.create.crusher_maxed_0000.desc": "Wpraw w ruch parę kół kruszących z maksymalną prędkością.", - "advancement.create.arm_many_targets": "Organizer", - "advancement.create.arm_many_targets.desc": "Zaprogramuj ramię mechaniczne z przynajmniej dziesięcioma miejscami wyjścia.", - "advancement.create.potato_cannon_collide": "Organiczne fajerwerki", - "advancement.create.potato_cannon_collide.desc": "Spraw, aby różne warzywa wystrzelone z armaty na ziemniaki zderzyły się ze sobą.", - "advancement.create.self_deploying": "Witajcie w erze samoobsługi!", - "advancement.create.self_deploying.desc": "Stwórz maszynę wagonikową która kładzie przed sobą tory.", - "advancement.create.fist_bump": "Żółwik!", - "advancement.create.fist_bump.desc": "Spraw, aby dwa aplikatory stuknęły się pięścią.", - "advancement.create.crafter_lazy_000": "Desperacka inżynieria", - "advancement.create.crafter_lazy_000.desc": "Drastycznie zwolnij mechaniczny stół rzemieślniczy, aby odwlec budowę poprawnej infrastruktury.§7\n(Ukryty postęp)", - "advancement.create.extendo_grip_dual": "Najdłuższy chwytak", - "advancement.create.extendo_grip_dual.desc": "Trzymaj wydłużone chwytaki oburącz, aby posiąść nadludzki zasięg.§7\n(Ukryty postęp)", - "advancement.create.musical_arm": "Zagraj coś dla mnie!", - "advancement.create.musical_arm.desc": "Patrz jak mechaniczne ramię obsługuje szafę grającą.", - "advancement.create.sturdy_sheet": "Najtwardsze skały", - "advancement.create.sturdy_sheet.desc": "Stwórz zbity arkusz poprzez rafinację sproszkowanego obsydianu.", - "advancement.create.train_casing_00": "Epoka logistyki", - "advancement.create.train_casing_00.desc": "Użyj zbitych arkuszy, aby stworzyć obudowę dla elementów kolejowych.", - "advancement.create.train": "Wszyscy na pokład!", - "advancement.create.train.desc": "Skonstruuj swój pierwszy pociąg.", - "advancement.create.conductor": "Instruktor konduktor", - "advancement.create.conductor.desc": "Pokieruj maszynistę harmonogramem kolejowym.", - "advancement.create.track_signal": "Kontrola ruchu", - "advancement.create.track_signal.desc": "Postaw sygnał kolejowy.", - "advancement.create.display_board_0": "Dynamiczny rozkład jazdy", - "advancement.create.display_board_0.desc": "Przewidź przyjazd pociągu na swojej tablicy wyświetlającej z pomocą nadajnika wyświetlającego.", - "advancement.create.track_0": "Nowy rozstaw", - "advancement.create.track_0.desc": "Zdobądź tory kolejowe.", - "advancement.create.train_whistle": "Ciuch ciuch!", - "advancement.create.train_whistle.desc": "Skonstruuj parowy gwizdek na swoim pociągu i uruchom go podczas jazdy.", - "advancement.create.train_portal": "Międzywymiarowy konduktor", - "advancement.create.train_portal.desc": "Przejedź pociągiem przez portal do Netheru.", - "advancement.create.track_crafting_factory": "Fabryka torów", - "advancement.create.track_crafting_factory.desc": "Wyprodukuj ponad 1000 torów kolejowych za pomocą tej samej mechanicznej prasy.", - "advancement.create.long_bend": "Najdłuższy zakręt", - "advancement.create.long_bend.desc": "Zbuduj zakrzywioną sekcję torów dłuższą niż 30 bloków.", - "advancement.create.long_train": "Wielkie ambicje", - "advancement.create.long_train.desc": "Stwórz pociąg z przynajmniej sześcioma wagonami.", - "advancement.create.long_travel": "Wielka podróż", - "advancement.create.long_travel.desc": "Wysiądź z siedzenia pociągu ponad 5000 bloków od miejsca początku podróży.", - "advancement.create.train_roadkill": "Zabójstwo na torach", - "advancement.create.train_roadkill.desc": "Przejedź przeciwnika swoim pociągiem.§7\n(Ukryty postęp)", - "advancement.create.red_signal": "Kierowca bombowca", - "advancement.create.red_signal.desc": "Przejedź na czerwonym świetle pociągiem.§7\n(Ukryty postęp)", - "advancement.create.train_crash": "Okropne usługi", - "advancement.create.train_crash.desc": "Doświadcz zderzenia pociągów jako pasażer.§7\n(Ukryty postęp)", - "advancement.create.train_crash_backwards": "Ślepa plamka", - "advancement.create.train_crash_backwards.desc": "Zderz się z innym pociągiem podczas jazdy do tyłu.§7\n(Ukryty postęp)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Bloki budowlane Create", - - "death.attack.create.crush": "Gracz %1$s został zgnieciony przez koło kruszące", - "death.attack.create.crush.player": "Gracz %1$s został wrzucony w koła kruszące przez %2$s", - "death.attack.create.fan_fire": "Gracz %1$s poparzył się gorącym powietrzem", - "death.attack.create.fan_fire.player": "Gracz %1$s został wepchnięty w strumień gorącego powietrza przez %2$s", - "death.attack.create.fan_lava": "Gracz %1$s poparzył się kroplami lawy", - "death.attack.create.fan_lava.player": "Gracz %1$s został wepchnięty w strumień kropel lawy przez %2$s", - "death.attack.create.mechanical_drill": "Gracz %1$s nabił się na mechaniczne wiertło", - "death.attack.create.mechanical_drill.player": "Gracz %1$s został wepchnięty na mechaniczne wiertło przez %2$s", - "death.attack.create.mechanical_saw": "Gracz %1$s został przecięty na pół przez mechaniczną piłę", - "death.attack.create.mechanical_saw.player": "Gracz %1$s został wepchnięty na mechaniczną piłę przez %2$s", - "death.attack.create.potato_cannon": "Gracz %1$s został zestrzelowny przez armate na ziemniaki należącą do %2$s", - "death.attack.create.potato_cannon.item": "Gracz %1$s został zestrzelowny przez %2$s z użyciem %3$s", - "death.attack.create.cuckoo_clock_explosion": "Gracz %1$s został wysadzony w powietrze przez uszkodzony zegar z kukułką", - "death.attack.create.cuckoo_clock_explosion.player": "Gracz %1$s został wysadzony w powietrze przez uszkodzony zegar z kukułką", - "death.attack.create.run_over": "Gracz %1$s został przejechany przez %2$s", - - "create.block.deployer.damage_source_name": "zbuntowany aplikator", - "create.block.cart_assembler.invalid": "Postaw monter wagoników na torze", - - "create.menu.return": "Powrót do menu", - "create.menu.configure": "Konfiguracja...", - "create.menu.ponder_index": "Katalog analiz", - "create.menu.only_ingame": "Dostępne w menu gry", - "create.menu.report_bugs": "Zgłoś błąd", - "create.menu.support": "Wesprzyj nas", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Kruszenie", - "create.recipe.milling": "Mielenie", - "create.recipe.fan_washing": "Hurtowe płukanie", - "create.recipe.fan_washing.fan": "Wiatrak za płynącą wodą", - "create.recipe.fan_smoking": "Hurtowe wędzenie", - "create.recipe.fan_smoking.fan": "Wiatrak za ogniem", - "create.recipe.fan_haunting": "Hurtowe nawiedzanie", - "create.recipe.fan_haunting.fan": "Wiatrak za ogniem dusz", - "create.recipe.fan_blasting": "Hurtowe topienie", - "create.recipe.fan_blasting.fan": "Wiatrak za lawą", - "create.recipe.pressing": "Tłoczenie", - "create.recipe.mixing": "Mieszanie", - "create.recipe.deploying": "Aplikowanie", - "create.recipe.automatic_shapeless": "Zautomatyzowanie bezkształtne konstruowanie", - "create.recipe.automatic_brewing": "Zautomatyzowane warzenie", - "create.recipe.packing": "Prasowanie", - "create.recipe.automatic_packing": "Zautomatyzowane pakowanie", - "create.recipe.sawing": "Cięcie", - "create.recipe.mechanical_crafting": "Mechaniczne konstruowanie", - "create.recipe.automatic_shaped": "Zautomatyzowane określone konstruowanie", - "create.recipe.block_cutting": "Cięcie bloków", - "create.recipe.wood_cutting": "Cięcie drewna", - "create.recipe.sandpaper_polishing": "Polerowanie papierem ściernym", - "create.recipe.mystery_conversion": "Tajemnicza przemiana", - "create.recipe.spout_filling": "Napełnianie", - "create.recipe.draining": "Osuszanie", - "create.recipe.item_application": "Manualne aplikowanie przedmiotów", - "create.recipe.item_application.any_axe": "Dowolna siekiera", - "create.recipe.sequenced_assembly": "Składanie", - "create.recipe.assembly.next": "Następnie: %1$s", - "create.recipe.assembly.step": "Krok %1$s:", - "create.recipe.assembly.progress": "Postęp: %1$s/%2$s", - "create.recipe.assembly.pressing": "Sprasuj", - "create.recipe.assembly.spout_filling_fluid": "Napełnij: %1$s", - "create.recipe.assembly.deploying_item": "Przyłącz: %1$s", - "create.recipe.assembly.cutting": "Przetnij piłą", - "create.recipe.assembly.repeat": "Powtórz %1$s razy", - "create.recipe.assembly.junk": "Losowy komponent", - "create.recipe.processing.chance": "%1$s%% szans", - "create.recipe.deploying.not_consumed": "Nie zużyte", - "create.recipe.heat_requirement.none": "Nie wymaga podgrzewania", - "create.recipe.heat_requirement.heated": "Podgrzewane", - "create.recipe.heat_requirement.superheated": "Silnie podgrzewane", - - "create.generic.range": "Zasięg", - "create.generic.radius": "Promień", - "create.generic.width": "Szerokość", - "create.generic.height": "Wysokość", - "create.generic.length": "Długość", - "create.generic.speed": "Prędkość", - "create.generic.delay": "Opóźnienie", - "create.generic.duration": "Czas trwania", - "create.generic.timeUnit": "Jednostka czasu", - "create.generic.unit.ticks": "Tiki", - "create.generic.unit.seconds": "Sekundy", - "create.generic.unit.minutes": "Minuty", - "create.generic.daytime.hour": "Godzina", - "create.generic.daytime.minute": "Minuta", - "create.generic.daytime.second": "Sekunda", - "create.generic.daytime.pm": "pm", - "create.generic.daytime.am": "am", - "create.generic.unit.rpm": "Ob/min", - "create.generic.unit.stress": "JO", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smW", - "create.generic.unit.buckets": "W", - "create.generic.clockwise": "Zgodnie ze wskazówkami zegara", - "create.generic.counter_clockwise": "Przeciwnie do wskazówek zegara", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "Wysokość: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Przewiń", - "create.action.confirm": "Potwierdź", - "create.action.abort": "Przerwij", - "create.action.saveToFile": "Zapisz", - "create.action.discard": "Odrzuć", - - "create.keyinfo.toolmenu": "Menu narzędzi", - "create.keyinfo.toolbelt": "Uzyskaj dostęp do pobliskich skrzynek na narzędzia", - "create.keyinfo.scrollup": "Symuluj przewijanie w górę (w świecie)", - "create.keyinfo.scrolldown": "Symuluj przewijanie w dół (w świecie)", - - "create.gui.scrollInput.defaultTitle": "Wybierz opcję:", - "create.gui.scrollInput.scrollToModify": "Przewiń, aby zmodyfikować", - "create.gui.scrollInput.scrollToAdjustAmount": "Przewiń, aby dostosować ilość", - "create.gui.scrollInput.scrollToSelect": "Przewiń, aby wybrać", - "create.gui.scrollInput.shiftScrollsFaster": "Naciśnij Shift, aby przewijać szybciej", - "create.gui.toolmenu.focusKey": "Przytrzymaj [%1$s], aby skupić", - "create.gui.toolmenu.cycle": "[SCROLL] przewijać", - - "create.toolbox.unequip": "Pozbądź się: %1$s", - "create.toolbox.outOfRange": "Skrzynka na narzędzia z trzymanym przedmiotem nie jest w zasięgu", - "create.toolbox.detach": "Przestań śledzić i zatrzymaj przedmiot", - "create.toolbox.depositAll": "Przywróć przedmioty do pobliskich skrzynek na narzędzia", - "create.toolbox.depositBox": "Przywróć przedmioty do skrzynki na narzędzia", - - "create.gui.symmetryWand.mirrorType": "Odbicie lustrzane", - "create.gui.symmetryWand.orientation": "Orientacja", - - "create.symmetry.mirror.plane": "Odbij lustrzanie raz", - "create.symmetry.mirror.doublePlane": "Prostokątnie", - "create.symmetry.mirror.triplePlane": "Ośmiokątnie", - - "create.orientation.orthogonal": "ortogonalnie", - "create.orientation.diagonal": "ukośnie", - "create.orientation.horizontal": "poziomo", - "create.orientation.alongZ": "Wzdłuż Z", - "create.orientation.alongX": "Wzdłuż X", - - "create.gui.terrainzapper.title": "Ręczny kształter", - "create.gui.terrainzapper.searchDiagonal": "Wzdłuż linii ukośnych", - "create.gui.terrainzapper.searchFuzzy": "Ignoruj krawędzie materiałów", - "create.gui.terrainzapper.patternSection": "Wzór", - "create.gui.terrainzapper.pattern.solid": "Ciągły", - "create.gui.terrainzapper.pattern.checkered": "Szachownica", - "create.gui.terrainzapper.pattern.inversecheckered": "Odrócona szachownica", - "create.gui.terrainzapper.pattern.chance25": "Obrót o 25%", - "create.gui.terrainzapper.pattern.chance50": "Obrót o 50%", - "create.gui.terrainzapper.pattern.chance75": "Obrót o 75%", - "create.gui.terrainzapper.placement": "Położenie", - "create.gui.terrainzapper.placement.merged": "Połączony", - "create.gui.terrainzapper.placement.attached": "Przyłączony", - "create.gui.terrainzapper.placement.inserted": "Wstawiony", - "create.gui.terrainzapper.brush": "Pędzel", - "create.gui.terrainzapper.brush.cuboid": "Prostopadłościan", - "create.gui.terrainzapper.brush.sphere": "Kula", - "create.gui.terrainzapper.brush.cylinder": "Walec", - "create.gui.terrainzapper.brush.surface": "Powierzchnia", - "create.gui.terrainzapper.brush.cluster": "Grupa", - "create.gui.terrainzapper.tool": "Narzędzie", - "create.gui.terrainzapper.tool.fill": "Wypełnianie", - "create.gui.terrainzapper.tool.place": "Stawianie", - "create.gui.terrainzapper.tool.replace": "Zamiana", - "create.gui.terrainzapper.tool.clear": "Czyszczenie", - "create.gui.terrainzapper.tool.overlay": "Pokrywanie", - "create.gui.terrainzapper.tool.flatten": "Wypłaszczanie", - - "create.terrainzapper.shiftRightClickToSet": "Shift+Prawe kliknięcie, aby wybrać kształt", - "create.terrainzapper.usingBlock": "Używając: %1$s", - "create.terrainzapper.leftClickToSet": "Kliknij LPM na blok aby ustawić materiał", - - "create.minecart_coupling.two_couplings_max": "Wagoniki nie mogą mieć więcej niż dwa łączniki każdy", - "create.minecart_coupling.unloaded": "Część twojego pociągu wydaje się być w niezaładowanych Chunkach.", - "create.minecart_coupling.no_loops": "Łączniki nie mogą tworzyć pętli", - "create.minecart_coupling.removed": "Usunięto z wagonika wszystkie łączniki", - "create.minecart_coupling.too_far": "Wagoniki są zbyt daleko od siebie", - - "create.contraptions.movement_mode": "Tryb poruszania", - "create.contraptions.movement_mode.move_place": "Zawsze stawiaj przy zatrzymaniu", - "create.contraptions.movement_mode.move_place_returned": "Stawiaj jedynie w pozycji startu", - "create.contraptions.movement_mode.move_never_place": "Stawiaj jedynie, gdy kotwica jest zniszczona", - "create.contraptions.movement_mode.rotate_place": "Zawsze stawiaj przy zatrzymaniu", - "create.contraptions.movement_mode.rotate_place_returned": "Stawiaj jedynie blisko kąta początkowego", - "create.contraptions.movement_mode.rotate_never_place": "Stawiaj jedynie, gdy kotwica jest zniszczona\n", - "create.contraptions.cart_movement_mode": "Tryb poruszania wagonika", - "create.contraptions.cart_movement_mode.rotate": "Zawsze kieruj w stronę ruchu", - "create.contraptions.cart_movement_mode.rotate_paused": "Zatrzymaj komponenty podczas obrotu", - "create.contraptions.cart_movement_mode.rotation_locked": "Zablokuj obrót", - "create.contraptions.windmill.rotation_direction": "Kierunek obrotu", - "create.contraptions.clockwork.clock_hands": "Wskazówki zegara", - "create.contraptions.clockwork.hour_first": "Najpierw wskazówka godzinowa", - "create.contraptions.clockwork.minute_first": "Najpierw wskazówka minutowa", - "create.contraptions.clockwork.hour_first_24": "Najpierw wskazówka 24-godzinna", - - "create.logistics.filter": "Filtr", - "create.logistics.recipe_filter": "Filtr receptur", - "create.logistics.fluid_filter": "Filtr płynów", - "create.logistics.firstFrequency": "Częst. #1", - "create.logistics.secondFrequency": "Częst. #2", - "create.logistics.filter.apply": "Zastosowano filtr na %1$s.", - "create.logistics.filter.apply_click_again": "Zastosowano filtr na %1$s; kliknij ponownie, aby skopiować ilość.", - "create.logistics.filter.apply_count": "Zastosowano limit wyciągania do filtra.", - - "create.gui.goggles.generator_stats": "Właściwości generatora:", - "create.gui.goggles.kinetic_stats": "Właściwości kinetyczne:", - "create.gui.goggles.at_current_speed": "przy obecnej prędkości", - "create.gui.goggles.pole_length": "Długość przedłużenia:", - "create.gui.goggles.fluid_container": "Informacje o zbiorniku:", - "create.gui.goggles.fluid_container.capacity": "Pojemność:", - "create.gui.assembly.exception": "Nie udało się zmontować maszyny:", - "create.gui.assembly.exception.unmovableBlock": "Nieprzesuwalny bloki (%4$s) na [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Blok na [%1$s,%2$s,%3$s] nie był w załadowanym Chunku", - "create.gui.assembly.exception.structureTooLarge": "Zbyt dużo bloków w maszynie. Ustawione maksimum to: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Zbyt dużo przedłużeń tłoka. Ustawione maksimum to: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Brakuje kilku przedłużeń tłoka", - "create.gui.assembly.exception.not_enough_sails": "Przyczepiona struktura nie zawiera wystarczająco żaglo-podobnych bloków: %1$s Wymagane minimum to %2$s", - "create.gui.gauge.info_header": "Informacje miernika:", - "create.gui.speedometer.title": "Prędkość obrotu", - "create.gui.stressometer.title": "Obciążenie systemu", - "create.gui.stressometer.capacity": "Pozostała pojemność", - "create.gui.stressometer.overstressed": "Przeciążenie", - "create.gui.stressometer.no_rotation": "Brak obrotu", - "create.gui.contraptions.not_fast_enough": "Wygląda na to, że %1$s_nie_ obraca się z _wystarczającą_ _prędkością_.", - "create.gui.contraptions.network_overstressed": "Wygląda na to, że ta maszyna jest _przeciążona_. Dodaj więcej źródeł lub _spowolnij_ komponenty z wysoką _wartością_ _obciążenia_.", - "create.gui.adjustable_crate.title": "Regulowana skrzynka", - "create.gui.adjustable_crate.storageSpace": "Pojemność", - "create.gui.stockpile_switch.title": "Przełącznik zawartościowy", - "create.gui.stockpile_switch.invert_signal": "Odwróć sygnał", - "create.gui.stockpile_switch.move_to_lower_at": "Zmień na niższą wartość przy %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Zmień na wyższą wartość przy %1$s%%", - "create.gui.sequenced_gearshift.title": "Przekładnik sekwencjonalny", - "create.gui.sequenced_gearshift.instruction": "Instrukcja", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Obróć o kąt", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Obróć", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Kąt", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Obróć, aby przesunąć tłok/krążek/przenośnik suwnicowy", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Tłok", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Dystans", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Opóźnienie czasowe", - "create.gui.sequenced_gearshift.instruction.delay": "Opóźn.", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Czas trwania", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Koniec", - "create.gui.sequenced_gearshift.instruction.end": "Koniec", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Czekaj na kolejny puls", - "create.gui.sequenced_gearshift.instruction.await": "Czekaj", - "create.gui.sequenced_gearshift.speed": "Prędkość, kierunek", - "create.gui.sequenced_gearshift.speed.forward": "Prędkość wejściowa, do przodu", - "create.gui.sequenced_gearshift.speed.forward_fast": "Podwójna prędkość, do przodu", - "create.gui.sequenced_gearshift.speed.back": "Prędkość wejściowa, odwrotnie", - "create.gui.sequenced_gearshift.speed.back_fast": "Podwójna prędkość, odwrotnie", - - "create.schematicAndQuill.dimensions": "Wielkość schematu: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Ustawiono pierwszą pozycję.", - "create.schematicAndQuill.secondPos": "Ustawiono drugą pozycję.", - "create.schematicAndQuill.noTarget": "Trzymaj [Ctrl], aby zaznaczyć bloki powietrza.", - "create.schematicAndQuill.abort": "Usunięto zaznaczenie.", - "create.schematicAndQuill.title": "Nazwa schematu:", - "create.schematicAndQuill.convert": "Zapisz i wyślij natychmiastowo", - "create.schematicAndQuill.fallbackName": "Nowy schemat", - "create.schematicAndQuill.saved": "Zapisano jako %1$s", - - "create.schematic.invalid": "[!] Nieprawidłowy przedmiot - użyj stołu do planowania", - "create.schematic.position": "Pozycja", - "create.schematic.rotation": "Obrót", - "create.schematic.rotation.none": "Brak", - "create.schematic.rotation.cw90": "Zgodnie z zegarem 90", - "create.schematic.rotation.cw180": "Zgodnie z zegarem 180", - "create.schematic.rotation.cw270": "Zgodnie z zegarem 270", - "create.schematic.mirror": "Odbij", - "create.schematic.mirror.none": "Brak", - "create.schematic.mirror.frontBack": "Przód-tył", - "create.schematic.mirror.leftRight": "Prawo-lewo", - "create.schematic.tool.deploy": "Pozycja", - "create.schematic.tool.move": "Przesuń XZ", - "create.schematic.tool.movey": "Przesuń Y", - "create.schematic.tool.rotate": "Obróć", - "create.schematic.tool.print": "Drukuj", - "create.schematic.tool.flip": "Odbij", - "create.schematic.tool.deploy.description.0": "Przesuwa strukturę na pozycję.", - "create.schematic.tool.deploy.description.1": "Kliknij PPM na ziemię, aby postawić.", - "create.schematic.tool.deploy.description.2": "Trzymaj [Ctrl], aby zaznaczyć w określonej odległości.", - "create.schematic.tool.deploy.description.3": "[Ctrl]+Przewijanie, aby zmienić dystans", - "create.schematic.tool.move.description.0": "Przesuwa schemat poziomo.", - "create.schematic.tool.move.description.1": "Wskaż na schemat i [Ctrl]+Przewijaj, aby popchnąć.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Przesuwa schemat pionowo.", - "create.schematic.tool.movey.description.1": "[Ctrl]+Przewijanie, aby przesunąć w górę/dół.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Obraca schemat wokół jego środka.", - "create.schematic.tool.rotate.description.1": "[Ctrl]+Przewijanie, aby obrócić o 90 stopni.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Natychmiastowo stawia strukturę w świecie.", - "create.schematic.tool.print.description.1": "Kliknij PPM, aby potwierdzić ustawienie w obecnej pozycji.", - "create.schematic.tool.print.description.2": "Ta funkcja jest tylko dla trybu kreatywnego.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Odbija schemat w stronę, w jakiej wskazałeś.", - "create.schematic.tool.flip.description.1": "Wskaż na schemat [Ctrl]+Przewijaj, aby odbić", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Synchronizacja...", - "create.schematics.uploadTooLarge": "Twój schemat przekracza limity ustanowione przez serwer.", - "create.schematics.maxAllowedSize": "Maksymalna wielkość schematu to:", - - "create.gui.schematicTable.refresh": "Odśwież pliki", - "create.gui.schematicTable.open_folder": "Otwórz folder", - "create.gui.schematicTable.title": "Stół do planowania", - "create.gui.schematicTable.availableSchematics": "Dostępne schematy", - "create.gui.schematicTable.noSchematics": "Brak zapisanych schematów", - "create.gui.schematicTable.uploading": "Wysyłanie...", - "create.gui.schematicTable.finished": "Wysyłanie zakończone!", - "create.gui.schematicannon.title": "Schematoarmata", - "create.gui.schematicannon.listPrinter": "Drukowanie listy", - "create.gui.schematicannon.gunpowderLevel": "Ilość prochu: %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Pozostałe wystrzały: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Wliczając zapas: %1$s", - "create.gui.schematicannon.optionEnabled": "Obecnie włączone", - "create.gui.schematicannon.optionDisabled": "Obecnie wyłączone\n", - "create.gui.schematicannon.showOptions": "Pokaż ustawienia drukowania", - "create.gui.schematicannon.option.dontReplaceSolid": "Nie zastępuj stałych bloków", - "create.gui.schematicannon.option.replaceWithSolid": "Zastępuj stałe stałymi", - "create.gui.schematicannon.option.replaceWithAny": "Zastępuj stałe dowolnymi", - "create.gui.schematicannon.option.replaceWithEmpty": "Zastępuj stałe pustymi", - "create.gui.schematicannon.option.skipMissing": "Pomijaj brakujące bloki", - "create.gui.schematicannon.option.skipTileEntities": "Chroń byty bloków", - "create.gui.schematicannon.slot.gunpowder": "Dodaj prochu, aby załadować armatę", - "create.gui.schematicannon.slot.listPrinter": "Daj tu książki, aby wydrukować listę", - "create.gui.schematicannon.slot.schematic": "Daj tu swój schemat. Upewnij się, że jest postawiony w odpowiednim miejscu.", - "create.gui.schematicannon.option.skipMissing.description": "Jeśli armata nie znajdzie wymaganego bloku, przejdzie w następne miejsce", - "create.gui.schematicannon.option.skipTileEntities.description": "Armata będzie unikać zastępowania bloków przechowujących dane, takich jak skrzynie.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Armata nigdy nie będzie zastępować jakichkolwiek stałych bloków, jedynie nie-stałe i powietrze.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Armata będzie zastępować stałe bloki jedynie, jeśli schemat zawiera stały blok w tym miejscu.", - "create.gui.schematicannon.option.replaceWithAny.description": "Armata będzie zastępować stałe bloki jedynie, jeśli schemat zawiera dowolny blok w tym miejscu.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Armata usunie wszystkie bloki, wliczając te zastępowane przez powietrze.", - - "create.schematicannon.status.idle": "Niepracująca", - "create.schematicannon.status.ready": "Gotowa", - "create.schematicannon.status.running": "Działająca", - "create.schematicannon.status.finished": "Ukończone", - "create.schematicannon.status.paused": "Wstrzymana", - "create.schematicannon.status.stopped": "Zatrzymana", - "create.schematicannon.status.noGunpowder": "Koniec prochu", - "create.schematicannon.status.targetNotLoaded": "Cel nie jest załadowany", - "create.schematicannon.status.targetOutsideRange": "Cel jest za daleko", - "create.schematicannon.status.searching": "Szukanie", - "create.schematicannon.status.skipping": "Pomijanie", - "create.schematicannon.status.missingBlock": "Brakujący przedmiot:", - "create.schematicannon.status.placing": "Stawianie", - "create.schematicannon.status.clearing": "Usuwanie bloków", - "create.schematicannon.status.schematicInvalid": "Nieprawidłowy schemat", - "create.schematicannon.status.schematicNotPlaced": "Schemat nieustawiony", - "create.schematicannon.status.schematicExpired": "Schemat wygasł", - - "create.materialChecklist": "Lista materiałów", - "create.materialChecklist.blocksNotLoaded": "* Zastrzeżenie *\\n\\n Lista materiałów może być niedokładna, bo znaczące Chunki nie są załadowane.", - - "create.gui.filter.deny_list": "Lista zabroniona", - "create.gui.filter.deny_list.description": "Przedmioty są przepuszczane, jeśli NIE pasują do żadnego z powyższych. Pusta lista przepuszcza wszystko.", - "create.gui.filter.allow_list": "Lista dozwolona", - "create.gui.filter.allow_list.description": "Przedmioty są przepuszczane, jeśli pasują do któregoś z powyższych. Pusta lista odrzuca wszystko", - "create.gui.filter.respect_data": "Bierz dane pod uwagę", - "create.gui.filter.respect_data.description": "Przedmioty pasują jedynie, jeśli ich wytrzymałość, zaklęcia i inne właściwości również pasują.", - "create.gui.filter.ignore_data": "Ignoruj dane", - "create.gui.filter.ignore_data.description": "Przedmioty pasują pomimo ich właściwości.", - - "create.item_attributes.placeable": "jest stawialny", - "create.item_attributes.placeable.inverted": "nie jest stawialny", - "create.item_attributes.consumable": "jadalny", - "create.item_attributes.consumable.inverted": "niejadalny", - "create.item_attributes.fluid_container": "może przechowywać płyny", - "create.item_attributes.fluid_container.inverted": "nie może przechowywać płynów", - "create.item_attributes.enchanted": "jest zaklęty", - "create.item_attributes.enchanted.inverted": "nie jest zaklęty", - "create.item_attributes.max_enchanted": "jest zaklęte na maksymalny poziom", - "create.item_attributes.max_enchanted.inverted": "nie jest zaklęte na maksymalny poziom", - "create.item_attributes.renamed": "posiada niestandardową nazwę", - "create.item_attributes.renamed.inverted": "nie posiada niestandardowej nazwy", - "create.item_attributes.damaged": "jest uszkodzony", - "create.item_attributes.damaged.inverted": "nie jest uszkodzony", - "create.item_attributes.badly_damaged": "jest silnie uszkodzony", - "create.item_attributes.badly_damaged.inverted": "nie jest silnie uszkodzony", - "create.item_attributes.not_stackable": "nie może być grupowany", - "create.item_attributes.not_stackable.inverted": "może być grupowany", - "create.item_attributes.equipable": "może zostać założony", - "create.item_attributes.equipable.inverted": "nie może zostać założony", - "create.item_attributes.furnace_fuel": "jest paliwem dla pieca", - "create.item_attributes.furnace_fuel.inverted": "nie jest paliwem dla pieca", - "create.item_attributes.washable": "może zostać opłukany", - "create.item_attributes.washable.inverted": "nie może zostać opłukany", - "create.item_attributes.hauntable": "może zostać nawiedzony", - "create.item_attributes.hauntable.inverted": "nie może zostać nawiedzony", - "create.item_attributes.crushable": "może być rozkruszony", - "create.item_attributes.crushable.inverted": "nie może być rozkruszony", - "create.item_attributes.smeltable": "może zostać przepalony", - "create.item_attributes.smeltable.inverted": "nie może zostać przepalony", - "create.item_attributes.smokable": "może być wędzony", - "create.item_attributes.smokable.inverted": "nie może być wędzony", - "create.item_attributes.blastable": "może być stopiony w piecu hutniczym", - "create.item_attributes.blastable.inverted": "nie może być stopiony w piecu hutniczym", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "jest %1$s", - "create.item_attributes.shulker_level.inverted": "nie jest %1$s", - "create.item_attributes.shulker_level.full": "pełna", - "create.item_attributes.shulker_level.empty": "pusta", - "create.item_attributes.shulker_level.partial": "częściowo wypełniona", - "create.item_attributes.in_tag": "posiada znacznik %1$s", - "create.item_attributes.in_tag.inverted": "nie posiada znacznika %1$s", - "create.item_attributes.in_item_group": "jest w grupie \"%1$s\"", - "create.item_attributes.in_item_group.inverted": "nie jest w grupie \"%1$s\"", - "create.item_attributes.added_by": "dodany przez %1$s", - "create.item_attributes.added_by.inverted": "niedodany przez %1$s", - "create.item_attributes.has_enchant": "posiada zaklęcie %1$s", - "create.item_attributes.has_enchant.inverted": "nie posiada zaklęcia %1$s", - "create.item_attributes.color": "jest zafarbowane, kolor %1$s", - "create.item_attributes.color.inverted": "nie jest zafarbowane, kolor %1$s", - "create.item_attributes.has_fluid": "zawiera %1$s", - "create.item_attributes.has_fluid.inverted": "nie zawiera %1$s", - "create.item_attributes.has_name": "posiada nazwę %1$s", - "create.item_attributes.has_name.inverted": "nie posiada nazwy %1$s", - "create.item_attributes.book_author": "autorem jest %1$s", - "create.item_attributes.book_author.inverted": "autorem nie jest %1$s", - "create.item_attributes.book_copy_original": "jest oryginałem", - "create.item_attributes.book_copy_original.inverted": "nie jest oryginałem", - "create.item_attributes.book_copy_first": "jest kopią oryginału", - "create.item_attributes.book_copy_first.inverted": "nie jest kopią oryginału", - "create.item_attributes.book_copy_second": "jest kopią kopii", - "create.item_attributes.book_copy_second.inverted": "nie jest kopią kopii", - "create.item_attributes.book_copy_tattered": "jest postrzępiona", - "create.item_attributes.book_copy_tattered.inverted": "nie jest postrzępiona", - "create.item_attributes.astralsorcery_amulet": "ulepsza %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "nie ulepsza %1$s", - "create.item_attributes.astralsorcery_constellation": "jest dopasowany do %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "nie jest dopasowany do %1$s", - "create.item_attributes.astralsorcery_crystal": "posiada właściwości kryształu %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "nie posiada właściwości kryształu %1$s", - "create.item_attributes.astralsorcery_perk_gem": "posiada dodatkową właściwość %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "nie posiada dodatkowej właściwości %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Brak wybranych właściwości", - "create.gui.attribute_filter.selected_attributes": "Wybrane właściwości:", - "create.gui.attribute_filter.add_attribute": "Dodaj właściwość do listy ", - "create.gui.attribute_filter.add_inverted_attribute": "Dodaj przeciwną właściwość do listy", - "create.gui.attribute_filter.allow_list_disjunctive": "Lista dozwolona (dowolny)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Przedmioty są przepuszczane jedynie, jeśli posiada dowolny z wybranych właściwości.", - "create.gui.attribute_filter.allow_list_conjunctive": "Lista dozwolona (wszystkie)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Przedmioty są przepuszczane jedynie, jeśli posiada WSZYSTKIE z wybranych właściwości.", - "create.gui.attribute_filter.deny_list": "Lista zabroniona", - "create.gui.attribute_filter.deny_list.description": "Przedmioty są przepuszczane jedynie, jeśli nie posiadają ŻADNEGO z wybranych właściwości.", - "create.gui.attribute_filter.add_reference_item": "Dodaj przedmiot źródłowy", - - "create.tooltip.holdForDescription": "Przytrzymaj [%1$s], aby zobaczyć podsumowanie", - "create.tooltip.holdForControls": "Przytrzymaj [%1$s], aby zobaczyć sterowanie", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Wymagana prędkość: %1$s", - "create.tooltip.speedRequirement.none": "Brak", - "create.tooltip.speedRequirement.slow": "Wolna", - "create.tooltip.speedRequirement.medium": "Umiarkowana", - "create.tooltip.speedRequirement.fast": "Wysoka", - "create.tooltip.stressImpact": "Wpływ na obciążenie: %1$s", - "create.tooltip.stressImpact.low": "Niski", - "create.tooltip.stressImpact.medium": "Umiarkowany", - "create.tooltip.stressImpact.high": "Wysoki", - "create.tooltip.stressImpact.overstressed": "Przeciążenie", - "create.tooltip.up_to": "Maksymalnie: %1$s", - "create.tooltip.capacityProvided": "Odporność na obciążenie: %1$s", - "create.tooltip.capacityProvided.low": "Niska", - "create.tooltip.capacityProvided.medium": "Średnia", - "create.tooltip.capacityProvided.high": "Wysoka", - "create.tooltip.generationSpeed": "Wytwarza %1$s %2$s", - "create.tooltip.analogStrength": "Siła analogowa: %1$s/15", - - "create.mechanical_arm.extract_from": "Wyciągaj przedmioty z %1$s", - "create.mechanical_arm.deposit_to": "Wkładaj przedmioty do %1$s", - "create.mechanical_arm.summary": "Mechaniczne ramię ma %1$s wejść i %2$s wyjść.", - "create.mechanical_arm.points_outside_range": "Usunięto %1$s wybranych punktów interakcji z powodu limitów zasięgu", - - "create.weighted_ejector.target_set": "Wybrano cel", - "create.weighted_ejector.target_not_valid": "Wyrzuca do przylegających bloków (cel był nieprawidłowy)", - "create.weighted_ejector.no_target": "Wyrzuca do przylegających bloków (nie wybrano celu)", - "create.weighted_ejector.targeting": "Wyrzuca do [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Wielkość wyrzucanego stosu", - - "create.logistics.when_multiple_outputs_available": "Kiedy wybrano wiele wyjść", - - "create.mechanical_arm.selection_mode.round_robin": "Dookoła", - "create.mechanical_arm.selection_mode.forced_round_robin": "Dookoła (wymuszone)", - "create.mechanical_arm.selection_mode.prefer_first": "Preferuj pierwszy cel", - - "create.tunnel.selection_mode.split": "Podziel", - "create.tunnel.selection_mode.forced_split": "Wymuś podział", - "create.tunnel.selection_mode.round_robin": "Dookoła", - "create.tunnel.selection_mode.forced_round_robin": "Dookoła (wymuszone)", - "create.tunnel.selection_mode.prefer_nearest": "Preferuj najbliższe", - "create.tunnel.selection_mode.randomize": "Losowo", - "create.tunnel.selection_mode.synchronize": "Synchronizuj wejścia", - - "create.tooltip.chute.header": "Informacja o zsypie", - "create.tooltip.chute.items_move_down": "Przedmioty w dół", - "create.tooltip.chute.items_move_up": "Przedmioty w górę", - "create.tooltip.chute.no_fans_attached": "Brak przyłączonych wiatraków", - "create.tooltip.chute.fans_push_up": "Wiatraki pchają od dołu", - "create.tooltip.chute.fans_push_down": "Wiatraki pchają od góry", - "create.tooltip.chute.fans_pull_up": "Wiatraki ciągną od góry", - "create.tooltip.chute.fans_pull_down": "Wiatraki ciągną od dołu", - "create.tooltip.chute.contains": "Zawiera: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Aktualnie przenosi:", - "create.tooltip.brass_tunnel.contains_entry": "> %2$sx %1$s", - "create.tooltip.brass_tunnel.retrieve": "Kliknij prawym przyciskiem, aby zabrać", - - "create.linked_controller.bind_mode": "Tryb przypisywania aktywny", - "create.linked_controller.press_keybind": "Naciśnij %1$s, %2$s, %3$s, %4$s, %5$s lub %6$s, aby przypisać częstotliwość do odpowiadającego przycisku", - "create.linked_controller.key_bound": "Przypisano częstotliwość do przycisku %1$s", - "create.linked_controller.frequency_slot_1": "Przycisk: %1$s, częst. #1", - "create.linked_controller.frequency_slot_2": "Przycisk: %1$s, częst. #2", - - "create.crafting_blueprint.crafting_slot": "Slot na składnik", - "create.crafting_blueprint.filter_items_viable": "Zaawansowane filtry są dopuszczalne", - "create.crafting_blueprint.display_slot": "Slot demonstracyjny", - "create.crafting_blueprint.inferred": "Pobierany z receptury", - "create.crafting_blueprint.manually_assigned": "Przypisany ręcznie", - "create.crafting_blueprint.secondary_display_slot": "Dodatkowy slot demonstracyjny", - "create.crafting_blueprint.optional": "Opcjonalny", - - "create.potato_cannon.ammo.attack_damage": "%1$s do obrażeń", - "create.potato_cannon.ammo.reload_ticks": "%1$s na przeładowanie", - "create.potato_cannon.ammo.knockback": "%1$s do odrzutu", - - "create.hint.hose_pulley.title": "Niewyczerpany zapas", - "create.hint.hose_pulley": "Wybrane zbiornik cieczy jest uznany za nieskończony", - "create.hint.mechanical_arm_no_targets.title": "Brak celi", - "create.hint.mechanical_arm_no_targets": "Wygląda na to, że żadne _cele_ nie zostały przypisane do tego _mechanicznego_ _ramienia_. Wybierz taśmociągi, składnice, lejki i inne bloki _klikając_ na nie _PPM_, trzymając w _ręce_ _mechaniczne_ _ramię_", - "create.hint.empty_bearing.title": "Aktualizuj łożysko", - "create.hint.empty_bearing": "_Kliknij_ na łożysko _PPM_ pustą ręką, aby _przyczepić_ do niego strukturę zbudowaną z przodu.", - "create.hint.full_deployer.title": "Nadmiar przedmiotów w aplikatorze", - "create.hint.full_deployer": "Wygląda na to, że ten _aplikator_ zawiera _nadmiar_ _przedmiotów_, które muszą zostać _wyciągnięte_. Użyj _leji_, _lejków_ lub innych sposobów, aby uwolnić od przepełnienia.", - - "create.backtank.low": "Niskie ciśnienie zbiornika", - "create.backtank.depleted": "Ciśnienie zbiornika wyczerpane", - - "create.hint.derailed_train.title": "Wykolejony pociąg", - "create.hint.derailed_train": "Ten _pociąg_ nie jest umiejscowiony na połączonej sekcji torów. _Kliknij PPM_ za pomocą _klucza_, aby umiejscowić go na innym torze.", - - "create.boiler.status": "Stan boilera: %1$s", - "create.boiler.status_short": "Boiler: %1$s", - "create.boiler.passive": "Bierny", - "create.boiler.idle": "W spoczynku", - "create.boiler.lvl": "Stopień mocy: %1$s", - "create.boiler.max_lvl": "Maks.", - "create.boiler.size": "Wielkość", - "create.boiler.size_dots": "....... ", - "create.boiler.water": "Woda", - "create.boiler.water_dots": "... ", - "create.boiler.heat": "Ciepło", - "create.boiler.heat_dots": "...... ", - "create.boiler.via_one_engine": "poprzez 1 silnik", - "create.boiler.via_engines": "poprzez %1$s silniki(ów)", - - "create.gui.schedule.lmb_edit": "Kliknij LPM, aby edytować", - "create.gui.schedule.rmb_remove": "Kliknij PPM, aby usunąć", - "create.gui.schedule.duplicate": "Duplikuj", - "create.gui.schedule.remove_entry": "Usuń czynność", - "create.gui.schedule.add_entry": "Dodaj czynność", - "create.gui.schedule.move_up": "Przenieś w górę", - "create.gui.schedule.move_down": "Przenieś w dół", - "create.gui.schedule.add_condition": "Dodaj warunek", - "create.gui.schedule.alternative_condition": "Alternatywny warunek", - - "create.schedule.instruction_type": "Następna czynność:", - "create.schedule.instruction.editor": "Edytor instrukcji", - "create.schedule.instruction.destination": "Jedź do stacji", - "create.schedule.instruction.destination.summary": "Następny przystanek:", - "create.schedule.instruction.filter_edit_box": "Nazwa stacji", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "Aktualizuj tytuł harmonogramu", - "create.schedule.instruction.rename.summary": "Nowy tytuł:", - "create.schedule.instruction.name_edit_box": "Tytuł harmonogramu", - "create.schedule.instruction.name_edit_box_1": "Wpływa na tekst pokazany na wyświetlaczach", - "create.schedule.instruction.name_edit_box_2": "Domyślnie - nazwa następnego celu", - "create.schedule.instruction.throttle": "Zmień prędkość", - "create.schedule.instruction.throttle.summary": "Zmień prędkość na %1$s", - "create.schedule.instruction.throttle_edit_box": "Prędkość", - "create.schedule.instruction.throttle_edit_box_1": "Wpływa na maksymalną prędkość pociągu", - "create.schedule.condition_type": "Kontynuuj jeżeli/po", - "create.schedule.condition.editor": "Edytor warunków", - "create.schedule.condition.delay": "Zaplanowane opóźnienie", - "create.schedule.condition.delay_short": "Czekaj: %1$s", - "create.schedule.condition.delay.status": "Odjeżdża za %1$s", - "create.schedule.condition.idle": "Brak aktywności ładunku", - "create.schedule.condition.idle_short": "Ładunek nieaktywny: %1$s", - "create.schedule.condition.idle.status": "Ładunek nieaktywny przez %1$s", - "create.schedule.condition.for_x_time": "przez %1$s", - "create.schedule.condition.unloaded": "Chunk niezaładowany", - "create.schedule.condition.unloaded.status": "Czekanie na wyładowanie chunku", - "create.schedule.condition.powered": "Stacja zasilona", - "create.schedule.condition.powered.status": "Czekanie na sygnał redstone", - "create.schedule.condition.time_of_day": "Godzina", - "create.schedule.condition.time_of_day.scheduled": "Zaplanowany czas: %1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "Obieg", - "create.schedule.condition.time_of_day.rotation.every_24": "Codziennie", - "create.schedule.condition.time_of_day.rotation.every_12": "Co 12 godzin", - "create.schedule.condition.time_of_day.rotation.every_6": "Co 6 godzin", - "create.schedule.condition.time_of_day.rotation.every_4": "Co 4 godziny", - "create.schedule.condition.time_of_day.rotation.every_3": "Co 3 godziny", - "create.schedule.condition.time_of_day.rotation.every_2": "Co 2 godziny", - "create.schedule.condition.time_of_day.rotation.every_1": "Co godzinę", - "create.schedule.condition.time_of_day.rotation.every_0_45": "Co 45 minut", - "create.schedule.condition.time_of_day.rotation.every_0_30": "Co 30 minut", - "create.schedule.condition.time_of_day.rotation.every_0_15": "Co 15 minut", - "create.schedule.condition.time_of_day.status": "Odjeżdża o ", - "create.schedule.condition.threshold.train_holds": "Pociąg zawiera %1$s", - "create.schedule.condition.threshold.greater": "więcej niż", - "create.schedule.condition.threshold.less": "mniej niż", - "create.schedule.condition.threshold.equal": "dokładnie", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$s: %3$s", - "create.schedule.condition.threshold.matching_content": "Pasująca zawartość", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "Jednostka przedmiotów", - "create.schedule.condition.threshold.items": "Przemioty", - "create.schedule.condition.threshold.stacks": "Stosy", - "create.schedule.condition.threshold.buckets": "Wiadra", - "create.schedule.condition.threshold.status": "Ładunek: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "Przedmiot odniesienia", - "create.schedule.condition.threshold.place_item_2": "Filtry mogą zostać użyte", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "Warunek ładunku płynów", - "create.schedule.condition.item_threshold": "Warunek ładunku przedmiotów", - "create.schedule.condition.redstone_link": "Emiter sygnału", - "create.schedule.condition.redstone_link.status": "Czekanie na emiter sygnału", - "create.schedule.condition.redstone_link_on": "Emiter włączony", - "create.schedule.condition.redstone_link_off": "Emiter wyłączony", - "create.schedule.condition.redstone_link.powered": "Zasilony", - "create.schedule.condition.redstone_link.unpowered": "Nie zasilony", - "create.schedule.condition.redstone_link.frequency_state": "Stan częstotliwości:", - "create.schedule.condition.redstone_link.frequency_powered": "Częstotliwość aktywna:", - "create.schedule.condition.redstone_link.frequency_unpowered": "Częstotliwość nieaktywna:", - "create.schedule.condition.player_count": "Siedzący gracze", - "create.schedule.condition.player_count.summary": "%1$s Gracz", - "create.schedule.condition.player_count.summary_plural": "%1$s Graczy", - "create.schedule.condition.player_count.seated": "%1$s siedzących", - "create.schedule.condition.player_count.players": "Graczey", - "create.schedule.condition.player_count.condition": "Warunek", - "create.schedule.condition.player_count.exactly": "Dokładnie", - "create.schedule.condition.player_count.or_above": "Lub więcej", - "create.schedule.condition.player_count.status": "Pasażerowie: %1$s/%2$s", - "create.schedule.loop": "Zapętlaj", - "create.schedule.loop1": "Harmonogram rozpoczyna się od nowa", - "create.schedule.loop2": "kiedy instrukcje zostały zakończone", - "create.schedule.reset": "Resetuj postęp harmonogramu", - "create.schedule.skip": "Pomiń aktualny przystanek", - "create.schedule.applied_to_train": "Pociąg teraz przestrzega ten harmonogram", - "create.schedule.non_controlling_seat": "Konduktor musi siedzieć przed blokiem kontroli", - "create.schedule.remove_with_empty_hand": "Zabierz aktualny harmonogram pustą ręką", - "create.schedule.auto_removed_from_train": "Automatyczny harmonogram odrzucony", - "create.schedule.removed_from_train": "Harmonogram odebrany z pociągu", - "create.schedule.no_stops": "Ten harmonogram nie ma żadnych przystanków", - "create.schedule.continued": "Harmonogram wznowiony", - - "create.track.selection_cleared": "Zaznaczenie wyczysczone", - "create.track.valid_connection": "Można połączyć ✔", - "create.track.second_point": "Postaw tory lub zaznacz kolejny punkt", - "create.track.too_far": "Zbyt daleko", - "create.track.original_missing": "Oryginalny blok usunięty, kliknij skradając się, aby zresetować", - "create.track.perpendicular": "Nie można połączyć prostopadle", - "create.track.ascending_s_curve": "Nie można zbudować nachylonych zakrętów-S", - "create.track.too_sharp": "Zbyt ostry zakręt", - "create.track.too_steep": "Zbyt strome nachylenie", - "create.track.slope_turn": "Nie można wjechać lub wyjechać z nachylenia na zakręcie", - "create.track.opposing_slopes": "Nie można połączyć przeciwległych nachyleń", - "create.track.leave_slope_ascending": "Nie można opuścić tego nachylenia podczas podjeżdżania", - "create.track.leave_slope_descending": "Nie można opuścić tego nachylenia podczas zjeżdżania", - "create.track.turn_90": "Można zakręcić maksymalnie o 90 stopni", - "create.track.junction_start": "Nie można rozpocząć połączenia ze skrzyżowania", - "create.track.turn_start": "Nie można rozpocząć połączenia z zakrętu", - "create.track.not_enough_tracks": "Za mało torów w ręce", - "create.track.not_enough_pavement": "Za mało bloków podpory w ręce", - - "create.portal_track.failed": "Nie można postawić torów do portalu:", - "create.portal_track.missing": "Docelowy portal nie wygenerowany", - "create.portal_track.blocked": "Docelowa lokacja zablokowana (%1$s,%2$s,%3$s)", - - "create.station.idle": "Stacja w spoczynku", - "create.station.assembly_title": "Montaż pociągów", - "create.station.close": "Zamknij okno", - "create.station.cancel": "Anuluj montaż", - "create.station.failed": "Nie udało się zmontować", - "create.station.icon_type": "Typ ikony", - "create.station.create_train": "Stwórz nowy pociąg", - "create.station.assemble_train": "Zmontuj pociąg", - "create.station.disassemble_train": "Rozmontuj pociąg", - "create.station.remove_schedule": "Odbierz harmonogram", - "create.station.remove_auto_schedule": "Odrzuć automatyczny harmonogram", - "create.station.no_assembly_diagonal": "Nie można budować pociągów", - "create.station.no_assembly_diagonal_1": "na skośnych torach", - "create.station.no_assembly_curve": "Nie można budować pociągów", - "create.station.no_assembly_curve_1": "na zakrętach", - "create.station.train_not_aligned": "Nie można rozmontować,", - "create.station.train_not_aligned_1": "nie wszystkie wagony wyrównane", - "create.station.carriage_number": "Wagon %1$s:", - "create.station.retry": "Napraw to i spróbuj ponownie", - "create.station.no_bogeys": "Brak wózków", - "create.station.one_bogey": "1 wózek", - "create.station.more_bogeys": "%1$s wózek", - "create.station.how_to": "Użyj obudowy kolejowej na podświetlonych torach, aby zbudować wózki.", - "create.station.how_to_1": "Usuwaj wózki poprzez niszczenie bloku powyżej.", - "create.station.how_to_2": "Buduj wagony przyczepione do jednego lub dwóch wózków.", - - "create.train_assembly.too_many_bogeys": "Zbyt wiele wózków przyczepionych: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "Pierwszy wózek musi znajdować się na oznaczeniu stacji", - "create.train_assembly.no_bogeys": "Brak znalezionych wózków", - "create.train_assembly.not_connected_in_order": "Wózki nie są połączone w kolejności", - "create.train_assembly.bogeys_too_close": "Wózki %1$s i %2$s są zbyt blisko siebie", - "create.train_assembly.single_bogey_carriage": "Ten typ wózka nie może sam podrzymać wagonu", - "create.train_assembly.nothing_attached": "Brak konstrukcji przyczepionej do wózka %1$s", - "create.train_assembly.no_controls": "Przynajmniej jeden blok kontrolny przyczepiony przodem do kierunku jazdy musi znajdować się na pociągu", - "create.train_assembly.sideways_controls": "Blok kontrolny jest przyczepiony bokiem", - "create.train_assembly.bogey_created": "Wagon zbudowany. Kliknij ponownie, aby zmienić typ", - "create.train_assembly.requires_casing": "Używaj obudów kolejowych, aby budować wózki na torach", - - "create.track_target.set": "Docelowy tor zaznaczony", - "create.track_target.success": "Pomyślnie przypisano do docelowego toru", - "create.track_target.clear": "Zaznaczenie toru wyczyszczone", - "create.track_target.missing": "Najpierw kliknij PPM na docelowy tor", - "create.track_target.too_far": "Docelowy tor jest zbyt daleko stąd", - "create.track_target.no_junctions": "Docelowy tor nie może być skrzyżowaniem", - "create.track_target.occupied": "Zaznaczony tor jest zajęty", - "create.track_target.invalid": "Nie można zaznaczyć tego toru", - - "create.train.unnamed": "Pociąg bez nazwy", - "create.train.cannot_relocate_moving": "Nie można przenieść pociągu w ruchu", - "create.train.relocate": "Kliknij tor, aby przenieść %1$s. Kliknij kucając, aby anulować", - "create.train.relocate.abort": "Przenoszenie anulowane", - "create.train.relocate.success": "Przenoszenie zakończone pomyślnie", - "create.train.relocate.valid": "Można tu przenieść, kliknij, aby potwierdzić", - "create.train.relocate.invalid": "Nie można przenieść tutaj pociągu", - "create.train.relocate.too_far": "Nie można przenieść pociągu tak daleko", - "create.train.departing_from": "Odjeżdża z %1$s", - "create.train.arrived_at": "Przybyto do %1$s", - "create.train.status": " Informacja o pociągu: %1$s", - "create.train.status.back_on_track": "Pociąg jest ponownie na torach", - "create.train.status.collision": "Kolizja z innym pociągiem", - "create.train.status.end_of_track": "Pociąg dotarł do końca swojego toru", - "create.train.status.double_portal": "Wagon nie może wejść do portalu podczas wychodzenia z innego", - "create.train.status.coupling_stress": "Przymusowy przystanek z powodu obciążenia na łącznikach", - "create.train.status.track_missing": "Brak torów pod pociągiem", - "create.train.status.paused_for_manual": "Harmonogram zatrzymany dla kontroli manualnej", - "create.train.status.opposite_driver": "Droga wymaga kierowcy w przeciwnym kierunku", - "create.train.status.missing_driver": "Kierowca zaginął", - "create.train.status.found_driver": "Nowy kierowca został znaleziony", - "create.train.status.navigation_success": "Nawigacja powiodła się", - "create.train.status.no_match": "Brak stacji pasującej do '%1$s'", - "create.train.status.no_path": "Nie można znaleźć pasującej ścieżki do kolejnego przystanku", - - "create.track_signal.cannot_change_mode": "Nie można zmienić trybu tego sygnału", - "create.track_signal.mode_change.entry_signal": "-> Zezwól na przejazd jeżeli droga nie jest zajęta", - "create.track_signal.mode_change.cross_signal": "-> Zezwól na przejazd jeżeli droga w pełni przejezdna", - - "create.contraption.controls.start_controlling": "Teraz kontrolowane: %1$s", - "create.contraption.controls.stop_controlling": "Przestano kontrolować maszynę", - "create.contraption.controls.approach_station": "Przytrzymaj %1$s aby podjechać do %2$s", - - "create.display_link.set": "Pozycja docelowa zaznaczona", - "create.display_link.success": "Pomyślnie przypisano do pozycji docelowej", - "create.display_link.clear": "Zaznaczenie pozycji wyczyszczone", - "create.display_link.too_far": "Pozycja docelowa jest zbyt daleko stąd", - "create.display_link.invalid": "Nadajnik nie ma poprawnego celu, spróbuj postawić go znowu", - "create.display_link.title": "Nadajnik wyświetlacza", - "create.display_link.no_source": "Nie jest źródłem wyświetlacza", - "create.display_link.no_target": "Nie jest celem wyświetlającym", - "create.display_link.reading_from": "Odczytuj z:", - "create.display_link.writing_to": "Wysyłaj do:", - "create.display_link.attached_side": "Blok na przyczepionej stronie", - "create.display_link.targeted_location": "Blok w lokacji docelowej", - "create.display_link.view_compatible": "Kliknij, aby zobaczyć wszystkie kompatybilne", - "create.display_link.information_type": "Typ informacji", - "create.display_link.display_on": "Wysyłaj dane do:", - "create.display_link.display_on_multiline": "Zacznij pisać na:", - - "create.display_source.label": "Doczepiony podpis:", - "create.display_source.combine_item_names": "Połącz nazwy przedmiotów", - "create.display_source.count_items": "Liczba pasujących przedmiotów", - "create.display_source.list_items": "Lista pasujących przedmiotów", - "create.display_source.fluid_amount": "Liczba pasujących płynów", - "create.display_source.list_fluids": "Lista pasujących płynów", - "create.display_source.nixie_tube": "Kopiuj lampy cyfrowe", - "create.display_source.fill_level": "Poziom napełnienia kontenerów", - "create.display_source.fill_level.display": "Format wyświetlania", - "create.display_source.fill_level.percent": "Procent", - "create.display_source.fill_level.progress_bar": "Pasek postępu", - "create.display_source.value_list.display": "Wartość wyświetlana", - "create.display_source.value_list.shortened": "Skrócona", - "create.display_source.value_list.full_number": "Pełna liczba", - "create.display_source.value_list.thousand": "tys.", - "create.display_source.value_list.million": "mil.", - "create.display_source.player_deaths": "Śmierci graczy", - "create.display_source.scoreboard": "Cel", - "create.display_source.scoreboard.objective": "ID celu", - "create.display_source.scoreboard.objective_not_found": "Nie znaleziono '%1$s'", - "create.display_source.scoreboard.objective.deaths": "Śmierci graczy", - "create.display_source.time_of_day": "Godzina", - "create.display_source.stop_watch": "Minutnik", - "create.display_source.time.format": "Format czasowy", - "create.display_source.time.12_hour": "12-godzinny", - "create.display_source.time.24_hour": "24-godzinny", - "create.display_source.accumulate_items": "Kumuluj liczbę przedmiotów", - "create.display_source.item_throughput": "Prędkość przedmiotów", - "create.display_source.item_throughput.interval": "Interwał", - "create.display_source.item_throughput.interval.second": "na sekundę", - "create.display_source.item_throughput.interval.minute": "na minutę", - "create.display_source.item_throughput.interval.hour": "na godzinę", - "create.display_source.train_status": "Status harmonogramu kolejowego", - "create.display_source.station_summary": "Podsumowanie stacji kolejowej", - "create.display_source.station_summary.filter": "Filtr nazwy stacji", - "create.display_source.station_summary.train_name_column": "Rozmiar kolumny pociągu", - "create.display_source.station_summary.platform_column": "Rozmiar kolumny platformy", - "create.display_source.station_summary.now": "teraz", - "create.display_source.station_summary.minutes": "min", - "create.display_source.station_summary.seconds": "%1$ss", - "create.display_source.observed_train_name": "Nazwa wykrytego pociągu", - "create.display_source.max_enchant_level": "Maksymalny koszt zaklinania", - "create.display_source.boiler_status": "Stan boilera", - "create.display_source.entity_name": "Nazwa bytu", - "create.display_source.kinetic_speed": "Prędkość obrotu (Ob/min)", - "create.display_source.kinetic_speed.absolute": "Ignoruj kierunek", - "create.display_source.kinetic_speed.directional": "Pokaż kierunek", - "create.display_source.kinetic_stress": "Obciążenie systemu", - "create.display_source.kinetic_stress.display": "Wyświetlone informacje", - "create.display_source.kinetic_stress.progress_bar": "Pasek postępu", - "create.display_source.kinetic_stress.percent": "Procenty", - "create.display_source.kinetic_stress.current": "Obciążenie w JO", - "create.display_source.kinetic_stress.max": "Całkowita pojemność", - "create.display_source.kinetic_stress.remaining": "Pozostałe JO", - "create.display_source.redstone_power": "Siła sygnału redstone", - "create.display_source.redstone_power.display": "Format wyświetlania", - "create.display_source.redstone_power.number": "Liczba", - "create.display_source.redstone_power.progress_bar": "Pasek postępu", - "create.display_source.boiler.not_enough_space": "Nie wystarczająco miejsca, ", - "create.display_source.boiler.for_boiler_status": "by wyświetlić stan boilera", - - "create.display_target.line": "Linijka %1$s", - "create.display_target.page": "Strona %1$s", - "create.display_target.single_line": "Pojedyncza linia", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;teraz;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;T;M", - "create.flap_display.cycles.fluid_units": "mW;W ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "Zaznaczony obszar jest zbyt duży", - "create.super_glue.cannot_reach": "Zaznaczone bloki muszą być połączone", - "create.super_glue.click_to_confirm": "Kliknij ponownie, aby potwierdzyć", - "create.super_glue.click_to_discard": "Kliknij kucając, aby odrzucić zaznaczenie", - "create.super_glue.first_pos": "Pierwsza pozycja zaznaczona", - "create.super_glue.abort": "Zaznaczenie odrzucone", - "create.super_glue.not_enough": "Nie wystarczająco kleju w ekwipunku", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "Cześć :)", - "create.gui.config.overlay2": "To jest przykładowa nakładka", - "create.gui.config.overlay3": "Kliknij lub przeciągnij myszką", - "create.gui.config.overlay4": "aby przesunąć ten podgląd", - "create.gui.config.overlay5": "Naciśnij ESC, aby opuścić ten ekran", - "create.gui.config.overlay6": "i zapisać nową pozycję", - "create.gui.config.overlay7": "Uruchom \"/create overlay reset\"", - "create.gui.config.overlay8": "aby zresetować pozycję", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Obecne opóźnienie serwera to %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Serwer jest teraz opóźniony o %s >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Serwer wrócił do standardowej prędkości :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: Użyj \"/killtps stop\", aby przywrócić serwer do standardowej prędkości", - "create.command.killTPSCommand.status.usage.1": "[Create]: Użyj \"/killtps start\", aby sztucznie spowolnić serwer", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Ta maszyna w wagoniku jest zbyt duża, aby ją podnieść", - "create.contraption.minecart_contraption_illegal_pickup": "Mistyczna siła jednoczy tą maszynę w wagoniku ze światem", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Maszyna staje", - "create.subtitle.peculiar_bell_use": "Dziwny dzwon dzwoni", - "create.subtitle.worldshaper_place": "Kształter strzela", - "create.subtitle.whistle_train_manual": "Pociąg trąbi", - "create.subtitle.steam": "Dźwięki pary", - "create.subtitle.saw_activate_stone": "Mechaniczna piła aktywuje się", - "create.subtitle.schematicannon_finish": "Schematoarmata skończyła", - "create.subtitle.crafter_craft": "Mechaniczny stół rzemieślniczy konstruuje", - "create.subtitle.wrench_remove": "Komponent niszczy się", - "create.subtitle.train3": "Koła wózka dudnią stłumione", - "create.subtitle.whistle": "Gwizdanie", - "create.subtitle.cogs": "Koła zębate terkoczą", - "create.subtitle.slime_added": "Szlam plaska", - "create.subtitle.whistle_train_low": "Niskie gwizdanie", - "create.subtitle.schematicannon_launch_block": "Schematoarmata strzela", - "create.subtitle.controller_take": "Pulpit opróżnia się", - "create.subtitle.crafter_click": "Mechaniczny stół rzemieślniczy stuka", - "create.subtitle.depot_plop": "Przedmiot ląduje", - "create.subtitle.confirm": "Dźwięk potwierdzenia", - "create.subtitle.mixing": "Dźwięki mieszania", - "create.subtitle.mechanical_press_activation_belt": "Mechaniczna prasa stuka", - "create.subtitle.fwoomp": "Armata na ziemniaki strzela", - "create.subtitle.sanding_long": "Dźwięki ścierania", - "create.subtitle.crushing_1": "Dźwięki kruszenia", - "create.subtitle.depot_slide": "Przedmiot ślizga się", - "create.subtitle.blaze_munch": "Płomyk szczęśliwie przeżuwa", - "create.subtitle.funnel_flap": "Lejek trzepocze", - "create.subtitle.haunted_bell_use": "Nawiedzony dzwoń dzwoni", - "create.subtitle.scroll_value": "Kliknięcie", - "create.subtitle.controller_put": "Sterownik klika", - "create.subtitle.cranking": "Ręczna korba obraca się", - "create.subtitle.sanding_short": "Dźwięki ścierania", - "create.subtitle.wrench_rotate": "Klucz skrzypi", - "create.subtitle.potato_hit": "Warzywo ląduje", - "create.subtitle.saw_activate_wood": "Mechaniczna piła aktywuje się", - "create.subtitle.whistle_high": "Wysokie gwizdanie", - "create.subtitle.whistle_train_manual_low": "Pociąg trąbi", - "create.subtitle.whistle_train": "Gwizdanie", - "create.subtitle.haunted_bell_convert": "Nawiedzony dzwon budzi się", - "create.subtitle.train": "Koła wózka dudnią", - "create.subtitle.deny": "Dźwięk odmowy", - "create.subtitle.controller_click": "Sterownik klika", - "create.subtitle.whistle_low": "Niskie gwizdanie", - "create.subtitle.copper_armor_equip": "Sprzęt do nurkowania pobrzękuje", - "create.subtitle.mechanical_press_activation": "Mechaniczna prasa się uruchamia", - "create.subtitle.contraption_assemble": "Maszyna przesuwa się", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "PRZYKŁADOWY PRZEDMIOT (jedynie znacznik, że ten dymek istnieje)", - "item.create.example_item.tooltip.summary": "Krótki opis przedmiotu. _Podkreślenia_, ha, podkreślają termin.", - "item.create.example_item.tooltip.condition1": "Kiedy to", - "item.create.example_item.tooltip.behaviour1": "Wtedy ten przedmiot coś robi (zachowania pokazują się przy Shifcie)", - "item.create.example_item.tooltip.condition2": "A kiedy to", - "item.create.example_item.tooltip.behaviour2": "Możesz dodać tak wiele zachowań jak chcesz", - "item.create.example_item.tooltip.control1": "Kiedy przyciśnięto Ctrl", - "item.create.example_item.tooltip.action1": "Wyświetla się sterowanie.", - - "block.create.wooden_bracket.tooltip": "DREWNIANY WSPORNIK", - "block.create.wooden_bracket.tooltip.summary": "_Udekoruj_ swoje _wały_, _koła zębate_ i _rury_ drewnianą i przytulną podporą.", - - "block.create.metal_bracket.tooltip": "METALOWY WSPORNIK", - "block.create.metal_bracket.tooltip.summary": "_Udekoruj_ swoje _wały_, _koła zębate_ i _rury_ wytrzymałą, przemysłową podporą.", - - "block.create.seat.tooltip": "SIEDZENIE", - "block.create.seat.tooltip.summary": "Usiądź i ciesz się jazdą! Przyczepi gracza do _ruchomej maszyny_. Również świetne do tworzenia stojących mebli! Dostępne w wielu kolorach.", - "block.create.seat.tooltip.condition1": "Kliknięcie PPM na siedzenie", - "block.create.seat.tooltip.behaviour1": "Sadza gracza na _siedzeniu_. Naciśnij lewy Shift, aby opuścić _siedzenie_.", - - "item.create.blaze_cake.tooltip": "PŁOMIENNE CIASTO", - "item.create.blaze_cake.tooltip.summary": "Pyszna przekąska dla Twoich cięzko pracujących _płomiennych palników_. Rozpala je wszystkie!", - - "item.create.wand_of_symmetry.tooltip": "RÓŻDŻKA SYMETRII", - "item.create.wand_of_symmetry.tooltip.summary": "Idealnie odbija lustrzanie bloki wzdłuż wybranych płaszczyzn.", - "item.create.wand_of_symmetry.tooltip.condition1": "Kiedy w pasku szybkiego wyboru", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Pozostaje aktywna", - "item.create.wand_of_symmetry.tooltip.control1": "Kliknięcie PPM na ziemię", - "item.create.wand_of_symmetry.tooltip.action1": "_Tworzy_ lub _przenosi_ lustro", - "item.create.wand_of_symmetry.tooltip.control2": "Kliknięcie PPM w powietrzu", - "item.create.wand_of_symmetry.tooltip.action2": "_Usuwa_ aktywne lustro", - "item.create.wand_of_symmetry.tooltip.control3": "Kliknięcie PPM w czasie skradania", - "item.create.wand_of_symmetry.tooltip.action3": "Otwiera _ustawienia_.", - - "item.create.handheld_worldshaper.tooltip": "RĘCZNY KSZTAŁTOWACZ", - "item.create.handheld_worldshaper.tooltip.summary": "Poręczne narzędzie do tworzenia _krajobrazów_ i _cech terenu_.", - "item.create.handheld_worldshaper.tooltip.control1": "Kliknięcie LPM na blok", - "item.create.handheld_worldshaper.tooltip.action1": "Przypisuje do narzędzia wybrany blok.", - "item.create.handheld_worldshaper.tooltip.control2": "Kliknięcie PPM na blok", - "item.create.handheld_worldshaper.tooltip.action2": "Stosuje obecnie wybrany _pędzel_ i _narzędzie_ w docelowej lokalizacji.", - "item.create.handheld_worldshaper.tooltip.control3": "Kliknięcie PPM w czasie skradania", - "item.create.handheld_worldshaper.tooltip.action3": "Otwiera _ustawienia_.", - - "item.create.tree_fertilizer.tooltip": "NAWÓZ DO DRZEW", - "item.create.tree_fertilizer.tooltip.summary": "Silna kombinacja minerałów odpowiednich do nawożenia pospolitych gatunków drzew", - "item.create.tree_fertilizer.tooltip.condition1": "Kiedy użyto na sadzonce", - "item.create.tree_fertilizer.tooltip.behaviour1": "Przyspiesza wzrost drzew, _pomimo dostępnej przestrzeni_.", - - "item.create.extendo_grip.tooltip": "WYDŁUŻONY CHWYTAK", - "item.create.extendo_grip.tooltip.summary": "Mocno _wydłuża zasięg_ rąk posiadacza.", - "item.create.extendo_grip.tooltip.condition1": "Kiedy w drugiej ręce", - "item.create.extendo_grip.tooltip.behaviour1": "_Wydłuża zasięg_ głównej ręki.", - "item.create.extendo_grip.tooltip.condition2": "Nosząc miedziany zbiornik w plecaku", - "item.create.extendo_grip.tooltip.behaviour2": "_Wytrzymałość_ nie będzie spadać. Zamiast tego, _sprężone powietrze_ będzie pobierane ze zbiornika.", - - "item.create.potato_cannon.tooltip": "ARMATA NA ZIEMNIAKI", - "item.create.potato_cannon.tooltip.summary": "Strzelaj swoimi domowymi warzywami w przeciwników. Może być zasilone sprężonym powietrzem z _miedzanego zbiornika w placaku_", - "item.create.potato_cannon.tooltip.condition1": "Kliknięcie PPM", - "item.create.potato_cannon.tooltip.behaviour1": "_Strzela_ pasującym przedmiotem z Twojego _ekwipunku_.", - "item.create.potato_cannon.tooltip.condition2": "Nosząc miedziany zbiornik w plecaku", - "item.create.potato_cannon.tooltip.behaviour2": "_Wytrzymałość_ nie będzie spadać. Zamiast tego, _sprężone powietrze_ będzie pobierane ze zbiornika.", - - "item.create.filter.tooltip": "FILTR", - "item.create.filter.tooltip.summary": "_Kontroluje_ wejścia i wyjścia urządzeń logistycznych z _większą precyzją_, przypasowując przedmioty do listy przedmiotów zawartej w filtrze lub wielu filtrach schowanych jeden w drugi.", - "item.create.filter.tooltip.condition1": "Kiedy w slocie na filtr", - "item.create.filter.tooltip.behaviour1": "_Kontroluje_ przepływ przedmiotów według jego _konfiguracji_.", - "item.create.filter.tooltip.condition2": "Kliknięcie PPM", - "item.create.filter.tooltip.behaviour2": "Otwiera _ustawienia_.", - - "item.create.attribute_filter.tooltip": "FILTR ATRYBUTOWY", - "item.create.attribute_filter.tooltip.summary": "_Kontroluje_ wejścia i wyjścia urządzeń logistycznych z _większą precyzją_, przypasowując przedmioty do listy właściwości przedmiotów zawartej w filtrze.", - "item.create.attribute_filter.tooltip.condition1": "Kiedy w slocie na filtr", - "item.create.attribute_filter.tooltip.behaviour1": "_Kontroluje_ przepływ przedmiotów według jego _konfiguracji_.", - "item.create.attribute_filter.tooltip.condition2": "Kliknięcie PPM", - "item.create.attribute_filter.tooltip.behaviour2": "Otwiera _ustawienia_.", - - "item.create.empty_schematic.tooltip": "PUSTY SCHEMAT", - "item.create.empty_schematic.tooltip.summary": "Używany, jako składnik do receptur i do pisania w _stole do planowania_.", - - "item.create.schematic.tooltip": "SCHEMAT", - "item.create.schematic.tooltip.summary": "Przechowuje strukturę do postawienia w świecie. Ustaw hologram według uznania i użyj _Schematoarmaty_, aby ją zbudować.", - "item.create.schematic.tooltip.condition1": "Kiedy w ręce", - "item.create.schematic.tooltip.behaviour1": "Może zostać _ustawiona_ z użyciem narzędzi wyświetlonych na ekranie.", - "item.create.schematic.tooltip.control1": "Kliknięcie PPM w czasie skradania", - "item.create.schematic.tooltip.action1": "Otwiera _ustawienia_.", - - "item.create.schematic_and_quill.tooltip": "SCHEMAT Z PIÓREM", - "item.create.schematic_and_quill.tooltip.summary": "Używany do zapisania struktury z Twojego świata do pliku .nbt", - "item.create.schematic_and_quill.tooltip.condition1": "Krok 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Zaznacz dwa rogi prawym przyciskiem myszy.", - "item.create.schematic_and_quill.tooltip.condition2": "Krok 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_[Ctrl]+Przewijaj_ patrząc się na ściany, aby dostosować rozmiar. Kliknij znowu PPM, aby zapisać.", - "item.create.schematic_and_quill.tooltip.control1": "Kliknięcie PPM", - "item.create.schematic_and_quill.tooltip.action1": "Wybierz róg/potwierdź zapisanie.", - "item.create.schematic_and_quill.tooltip.control2": "Trzymane w ręce + Ctrl", - "item.create.schematic_and_quill.tooltip.action2": "Zaznacz rogi _w powietrzu_. _Przewijaj_, aby dostosować dystans.", - "item.create.schematic_and_quill.tooltip.control3": "Kliknięcie PPM w czasie skradania", - "item.create.schematic_and_quill.tooltip.action3": "_Resetuje_ i usuwa zaznaczenie.", - - "block.create.schematicannon.tooltip": "SCHEMATOARMATA", - "block.create.schematicannon.tooltip.summary": "Strzela blokami, aby odtworzyć wybrany schemat w świecie. Zużywa przedmioty z sąsiadujących bloków, potrzebuje _prochu_ jako paliwo.", - "block.create.schematicannon.tooltip.condition1": "Kliknięcie PPM", - "block.create.schematicannon.tooltip.behaviour1": "Otwiera _interfejs_.", - - "block.create.schematic_table.tooltip": "STÓŁ DO PLANOWANIA", - "block.create.schematic_table.tooltip.summary": "Przypisuje zapisane schematy do _pustego schematu_.", - "block.create.schematic_table.tooltip.condition1": "Kiedy włożono pusty schemat", - "block.create.schematic_table.tooltip.behaviour1": "Pobiera wybrany plik z Twojego folderu ze schematami", - - "item.create.goggles.tooltip": "GOGLE", - "item.create.goggles.tooltip.summary": "Para okularów służąca do rozszerzania Twojej wizji o _przydatne informacje_.", - "item.create.goggles.tooltip.condition1": "Kiedy założone", - "item.create.goggles.tooltip.behaviour1": "Pokazuje _kolorowe wskazówki_ odpowiadające _prędkości obrotu_ komponentu, jak i również ich _wpływ_ oraz _odporność na obciążenie_.", - "item.create.goggles.tooltip.condition2": "Patrząc na miernik", - "item.create.goggles.tooltip.behaviour2": "Pokazuje szczegółowe informacje na temat _prędkości_ lub _obciążenia_ systemu, do którego miernik jest podłączony.", - "item.create.goggles.tooltip.condition3": "Patrząc na zbiorniki", - "item.create.goggles.tooltip.behaviour3": "Pokazuje szczegółowe informacje na temat _pojemności_ zbiornika i wszelkich _płynów_ przechowywanych wewnątrz.", - - "item.create.wrench.tooltip": "KLUCZ", - "item.create.wrench.tooltip.summary": "Przydatne narzędzie do pracy z maszynami. Może być użyty do _obracania_, _rozbiórki_ i _konfiguracji_ komponentów.", - "item.create.wrench.tooltip.control1": "Kliknięcie PPM na ruchomy blok", - "item.create.wrench.tooltip.action1": "_Obraca_ komponenty do- lub od- strony, na którą kliknięto.", - "item.create.wrench.tooltip.control2": "Kliknięcie PPM w czasie skradania", - "item.create.wrench.tooltip.action2": "_Rozmontowuje_ komponenty i wkłada je z powrotem do _Twojego ekwipunku_.", - - "block.create.nozzle.tooltip": "DYSZA", - "block.create.nozzle.tooltip.summary": "Przyczep do przedniej części _izolowanego wiatraka_, aby rozprowadzić jego efekt na _wszystkie strony_.", - - "block.create.cuckoo_clock.tooltip": "ZEGAR Z KUKUŁKĄ", - "block.create.cuckoo_clock.tooltip.summary": "Kunsztowny wytwór do _dekoracji_ przestrzeni mieszkalnej i _mierzenia czasu_.", - "block.create.cuckoo_clock.tooltip.condition1": "Kiedy zasilony siłą obrotową", - "block.create.cuckoo_clock.tooltip.behaviour1": "Pokazuje _obecny czas_ i gra melodyjkę dwa razy dziennie. Aktywuje się raz w _południe_ i raz o zmierzchu, jak tylko _możliwy jest sen_.", - - "block.create.turntable.tooltip": "TALERZ OBROTOWY", - "block.create.turntable.tooltip.summary": "Zamienia _siłę obrotu_ na _chorobę lokomocyjną_.", - - "block.create.toolbox.tooltip": "SKRZYNKA NA NARZĘDZIA", - "block.create.toolbox.tooltip.summary": "Najlepszy przyjaciel każdego wynalazcy. Wygodnie _przechowuje_ dużą liczbę _8 różnych_ typów przedmiotów.", - "block.create.toolbox.tooltip.condition1": "Kiedy podniesiony", - "block.create.toolbox.tooltip.behaviour1": "_Zatrzymuje_ swoją _zawartość_.", - "block.create.toolbox.tooltip.condition2": "Kiedy postawiony w zasięgu", - "block.create.toolbox.tooltip.behaviour2": "_Pobliscy_ _Gracze_ mogą przytrzymać _Klawisz_ _skrzynki na narzędzia_ aby _zdalnie_ uzyskać dostęp do jej zawartości.", - "block.create.toolbox.tooltip.condition3": "Kliknięcie PPM", - "block.create.toolbox.tooltip.behaviour3": "Otwiera _interfejs kontenera_.", - - "block.create.stockpile_switch.tooltip": "PRZEŁĄCZNIK ZAWARTOŚCIOWY", - "block.create.stockpile_switch.tooltip.summary": "Przełącza sygnał Redstone bazując na _ilości przedmiotów_ przechowywanych w sąsiadującym bloku. Może posiadać filtr. W odróżnieniu od _komparatora_, przełącznik zawartościowy pozwala na konfigurację _progów_, przy których sygnały są odwrotne.", - "block.create.stockpile_switch.tooltip.condition1": "Kliknięcie PPM", - "block.create.stockpile_switch.tooltip.behaviour1": "Otwiera _ustawienia_.", - - "block.create.content_observer.tooltip": "DETEKTOR ZAWARTOŚCI", - "block.create.content_observer.tooltip.summary": "_Wykrywa przedmioty_ zawarte w sąsiadującym _bloku_ lub _taśmociągu_, które pasują do ustalonego filtra. Kiedy obserwowany blok _zawiera_ ten przedmiot, detektor wyśle _sygnał Redstone_.", - "block.create.content_observer.tooltip.condition1": "Kiedy obserwuje kontener", - "block.create.content_observer.tooltip.behaviour1": "Wysyła _sygnał redstone_ kiedy obserwowany kontener posiada _pasującą_ _zawartość_.", - "block.create.content_observer.tooltip.condition2": "Kiedy obserwuje lejek", - "block.create.content_observer.tooltip.behaviour2": "Wysyła _puls_ _redstone_ kiedy _pasujący_ przedmiot jest _transferowany_.", - - "block.create.creative_crate.tooltip": "SKRZYNKA BEZ DNA", - "block.create.creative_crate.tooltip.summary": "Ta skrzynia pozwala na _nieskończone powielanie_ dowolnego przedmiotu. Postaw obok _Schematoarmaty_, aby usunąć wszelkie wymagania dotyczące materiałów.", - "block.create.creative_crate.tooltip.condition1": "Kiedy przedmiot jest w slocie na filtr", - "block.create.creative_crate.tooltip.behaviour1": "Bloki _wyciągające_ przedmioty z tego bloku będą miały _nieskończony zapas_ wybranego przedmiotu. Przedmioty włożone do tej skrzynki będą _usuwane_.", - - "item.create.creative_blaze_cake.tooltip": "KREATYWNE PŁOMIENNE CIASTO", - "item.create.creative_blaze_cake.tooltip.summary": "Wykwintny przysmak _płomiennych palników_. Pozwala na _kontrolowanie poziomu ciepła_ wydzielanego przez palnik. Po zjedzeniu palnik nigdy nie przestanie się palić.", - "item.create.creative_blaze_cake.tooltip.condition1": "Kliknięcie PPM na płomienny palnik", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Blokuje_ poziom ciepła płomiennego palnika. Po ponownym użyciu zmienia poziom ciepła na wyższy.", - - "block.create.controller_rail.tooltip": "TORY STERUJĄCE", - "block.create.controller_rail.tooltip.summary": "_Wielokierunkowy_ zasilany tor pozwalający na _dokładną kontrolę_ nad _prędkością wagonika_.", - "block.create.controller_rail.tooltip.condition1": "Kiedy zasilone przez Redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Przyspiesza_ lub _spowalnia_ przejeżdżające _wagoniki_, bazując na sile sygnału. Przekazuje sygnał do sąsiadujących torów. Zasilenie dwóch połączonych torów innymi siłami sygnału spowoduje, że tory pomiędzy nimi będą miały stopniowo zmieniającą się siłę sygnału.", - - "item.create.sand_paper.tooltip": "PAPIER ŚCIERNY", - "item.create.sand_paper.tooltip.summary": "Szorstki papier używany do _polerowania_ materiałów. Może być automatycznie wykorzystywany z użyciem _aplikatora_.", - "item.create.sand_paper.tooltip.condition1": "Kiedy użyto", - "item.create.sand_paper.tooltip.behaviour1": "_Poleruje_ przedmioty trzymane w _drugiej ręce_ lub _leżące na ziemi_ w linii wzroku.", - - "item.create.builders_tea.tooltip": "HERBATKA BUDOWNICZEGO", - "item.create.builders_tea.tooltip.summary": "Idealny napój na początek dnia - _sycący_ i _motywujący_", - - "item.create.refined_radiance.tooltip": "ŚWIETLISTY MATERIAŁ", - "item.create.refined_radiance.tooltip.summary": "Chromatyczny materiał powstały z _absorbcji światła_.", - "item.create.refined_radiance.tooltip.condition1": "Prace w toku", - "item.create.refined_radiance.tooltip.behaviour1": "Zastosowania dla tego materiału pojawią się w przyszłości.", - - "item.create.shadow_steel.tooltip": "MROCZNA STAL", - "item.create.shadow_steel.tooltip.summary": "Chromatyczny materiał powstały w _otchłani_.", - "item.create.shadow_steel.tooltip.condition1": "Prace w toku", - "item.create.shadow_steel.tooltip.behaviour1": "Zastosowania dla tego materiału pojawią się w przyszłości.", - - "item.create.linked_controller.tooltip": "ZDALNY STEROWNIK", - "item.create.linked_controller.tooltip.summary": "Daje _zdalną_ _kontrolę_ nad _częstotliwościami_ _emiterów_ _sygnału_ przypisanymi do jego _sześciu_ _guzików_.", - "item.create.linked_controller.tooltip.condition1": "Kliknięcie PPM", - "item.create.linked_controller.tooltip.behaviour1": "Aktywuje sterownik. _Przyciski_ służace _do_ _poruszania_ _się_ od teraz pełnią rolę _przycisków_ _sterownika_.", - "item.create.linked_controller.tooltip.condition2": "Kliknięcie PPM skradając się", - "item.create.linked_controller.tooltip.behaviour2": "Otwiera _interfejs_ _częstotliwości_ sterownika.", - "item.create.linked_controller.tooltip.condition3": "Kliknięcie PPM na emiter sygnału", - "item.create.linked_controller.tooltip.behaviour3": "Włącza _tryb_ _przypisywania_. Wciśnij jeden z sześciu guzików aby przypisać go do częstotliwości emitera.", - "item.create.linked_controller.tooltip.condition4": "Kliknięcie PPM na pulpit", - "item.create.linked_controller.tooltip.behaviour4": "_Kładzie_ sterownik na pulpicie, dla _wygody_ _użycia_. Kliknij PPM skradając się, aby go _zabrać_ _z_ _powrotem_.", - - "item.create.diving_helmet.tooltip": "HEŁM DO NURKOWANIA", - "item.create.diving_helmet.tooltip.summary": "Wraz z _miedzianym_ _zbiornikiem_ _w_ _plecaku_ pozwala na dłuższe oddychanie pod wodą.", - "item.create.diving_helmet.tooltip.condition1": "Kiedy na głowie", - "item.create.diving_helmet.tooltip.behaviour1": "Daje efekt _oddychania_ _pod_ _wodą_, powoli pobierając powietrze ze zbiornika.", - - "item.create.copper_backtank.tooltip": "MIEDZIANY ZBIORNIK W PLECAKU", - "item.create.copper_backtank.tooltip.summary": "Zbiornik służący do przechowywania _sprężonego_ _powietrza_. Można go ubrać na tors.", - "item.create.copper_backtank.tooltip.condition1": "Kiedy na torsie", - "item.create.copper_backtank.tooltip.behaviour1": "Dostarcza _sprężonego_ _powietrza_ przedmiotom, które go potrzebują.", - "item.create.copper_backtank.tooltip.condition2": "Po postawieniu i zasileniu siłą obrotową", - "item.create.copper_backtank.tooltip.behaviour2": "_Zbiera_ _sprężone_ _powietrze_, w tempie zależnym od prędkości obrotu.", - - "block.create.placard.tooltip": "Plakietka", - "block.create.placard.tooltip.summary": "_Opraw_ swoje przedmioty w mosiądzu używając tego eleganckiego panelu ściennego. Dozwolone na maszynach!", - "block.create.placard.tooltip.condition1": "Kliknięcie PPM przedmiotem", - "block.create.placard.tooltip.behaviour1": "_Dodaje_ trzymany _przedmiot_ do plakietki. _Wysyła_ krótki sygnał _redstone_ jeżeli trzymany przedmiot był już na plakietce.", - "block.create.placard.tooltip.condition2": "Kiedy uderzony", - "block.create.placard.tooltip.behaviour2": "_Usuwa_ bieżący _przedmiot_ z plakietki.", - - "block.create.flywheel.tooltip": "KOŁO ZAMACHOWE", - "block.create.flywheel.tooltip.summary": "_Odzób_ swoją _maszynerię_ tym imponującym mosiężnym kołem.", - "block.create.flywheel.tooltip.condition1": "Kiedy zasilony siłą obrotową", - "block.create.flywheel.tooltip.behaviour1": "Zaczyna się kręcić.", - - "item.create.diving_boots.tooltip": "BUTY DO NURKOWANIA", - "item.create.diving_boots.tooltip.summary": "Para _ciężkich_ _butów_, pozwalająca na efektywniejsze _przemierzanie_ _dna_ _oceanu_.", - "item.create.diving_boots.tooltip.condition1": "Kiedy na stopach", - "item.create.diving_boots.tooltip.behaviour1": "Noszący _szybciej_ _opada_ _na_ _dno_ i _nie_ _może_ _pływać_. Daje możliwość _chodzenia_ i _skakania_ pod wodą. Taśmociągi nie przesuwają graczy noszących te buty.", - - "item.create.crafting_blueprint.tooltip": "SZABLON KONSTRUOWANIA", - "item.create.crafting_blueprint.tooltip.summary": "Po _postawieniu_ _na_ _ścianie_ może być użyty do _łatwiejszego_ ręcznego _konstruowania_. Każdy kwadrat reprezentuje jedną recepturę.", - "item.create.crafting_blueprint.condition1": "Kliknięcie PPM na pusty kwadrat", - "item.create.crafting_blueprint.behaviour1": "Wyświetla menu konstruowania i pozwala na _konfigurację_ _receptury_ i przedmiotów do wyświetlenia.", - "item.create.crafting_blueprint.condition2": "Kliknięcie PPM na skonfigurowany kwadrat", - "item.create.crafting_blueprint.behaviour2": "_Konstruuje_ skonfigurowany _przedmiot_, używając przedmiotów zawartych w ekwipunku gracza. Kliknij _skradając_ _się_, aby uzyskać _cały_ _stos_ przedmiotów.", - - "item.create.minecart_coupling.tooltip": "ŁĄCZNIK WAGONIKÓW", - "item.create.minecart_coupling.tooltip.summary": "_Łączy_ wszystkie Twoje _wagoniki_ lub _maszyny torowe_, tworząc majestatyczny pociąg.", - "item.create.minecart_coupling.tooltip.condition1": "Kiedy użyto na wagoniku", - "item.create.minecart_coupling.tooltip.behaviour1": "_Łączy_ dwa wagoniki, próbując utrzymać je w stałej odległości od siebie.", - - "item.create.experience_nugget.tooltip": "BRYŁKA DOŚWIADCZENIA", - "item.create.experience_nugget.tooltip.summary": "_Dzyń!_ Kawałeczek _inspiracji_ z twoich fantastycznych wynalazków.", - "item.create.experience_nugget.tooltip.condition1": "Kiedy użyto", - "item.create.experience_nugget.tooltip.behaviour1": "_Wypuszcza_ punkty _doświadczenia_ zawarte wewnątrz.", - - "block.create.peculiar_bell.tooltip": "DZIWNY DZWON", - "block.create.peculiar_bell.tooltip.summary": "_Dekoracyjny_ _dzwon_ z mosiądzu. Postawienie nad _eterycznym_ _ogniem_ może wywołać efekty uboczne...", - - "block.create.haunted_bell.tooltip": "NAWIEDZONY DZWON", - "block.create.haunted_bell.tooltip.summary": "_Przeklęty_ _dzwon_ nawiedzony przez dusze z Netheru.", - "block.create.haunted_bell.tooltip.condition1": "Kiedy trzymany w ręce lub po zadzwonieniu", - "block.create.haunted_bell.tooltip.behaviour1": "Oznacza _pobliskie_ _bloki_, na których mogą pojawiać się _agresywne_ _moby_.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 Ob/min", - "create.ponder.shared.behaviour_modify_wrench": "To zachowanie może być zmodyfikowane przy pomocy klucza", - "create.ponder.shared.storage_on_contraption": "Pojemniki przyłączone do maszyny będą podnosiły przedmioty automatycznie", - "create.ponder.shared.rpm8": "8 Ob/min", - "create.ponder.shared.rpm32": "32 Ob/min", - "create.ponder.shared.rpm16_source": "Źródło: 16 Ob/min", - "create.ponder.shared.movement_anchors": "Z pomocą stelaży lub Super Glue, większe struktury mogą być przesuwane.", - "create.ponder.tag.redstone": "Komponenty logiczne", - "create.ponder.tag.redstone.description": "Komponenty przydatne w Redstonie", - "create.ponder.tag.contraption_assembly": "Bloki do tworzenia maszyn", - "create.ponder.tag.contraption_assembly.description": "Narzędzia i komponenty używane do konstrukcji ruchomych maszyn", - "create.ponder.tag.fluids": "Manipulator płynów", - "create.ponder.tag.fluids.description": "Komponenty przydatne przy pracy z płynami", - "create.ponder.tag.decoration": "Dekoracje", - "create.ponder.tag.decoration.description": "Komponenty używane głównie do celów estetycznych", - "create.ponder.tag.windmill_sails": "Bloki żaglo-podobne", - "create.ponder.tag.windmill_sails.description": "Bloki, które dokładają się do siły, z jaką obracają się łopaty maszyny wiatrakowej.", - "create.ponder.tag.arm_targets": "Cele dla mechanicznego ramienia", - "create.ponder.tag.arm_targets.description": "Komponenty, które mogą być wybrane, jako wejście lub wyjście dla mechanicznego ramienia", - "create.ponder.tag.kinetic_appliances": "Urządzenia obrotowe", - "create.ponder.tag.kinetic_appliances.description": "Komponenty używające siły obrotowej", - "create.ponder.tag.kinetic_sources": "Źródła siły obrotowej", - "create.ponder.tag.kinetic_sources.description": "Komponenty, które generują siłę obrotu", - "create.ponder.tag.movement_anchor": "Komponenty ruchome", - "create.ponder.tag.movement_anchor.description": "Komponenty, które pozwalają na tworzenie ruchomych maszyn, poruszając ją na wiele różnych sposobów.", - "create.ponder.tag.kinetic_relays": "Bloki obrotowe", - "create.ponder.tag.kinetic_relays.description": "Komponenty, które pomagają w przekazywaniu siły obrotowej w inne miejsca", - "create.ponder.tag.contraption_actor": "Komponenty aktywne maszyn", - "create.ponder.tag.contraption_actor.description": "Komponenty, które posiadają specjalne zachowanie będąc podłączonymi do maszyny", - "create.ponder.tag.creative": "Tryb kreatywny", - "create.ponder.tag.creative.description": "Komponenty niedostępne na trybie przetrwania", - "create.ponder.tag.display_sources": "Źródła dla nadajników wyświetlacza", - "create.ponder.tag.display_sources.description": "Komponenty lub bloki, które oferują dane, które mogą zostać odczytane przez nadajniki wyświetlacza.", - "create.ponder.tag.logistics": "Transport przedmiotów", - "create.ponder.tag.logistics.description": "Komponenty, które pomagają w transporcie przedmiotów", - "create.ponder.tag.display_targets": "Cele dla nadajników wyświetlacza", - "create.ponder.tag.display_targets.description": "Komponenty lub bloki, które mogą przetwarzać dane otrzymane od nadajników wyświetlacza.", - "create.ponder.tag.train_related": "Zaopatrzenie kolejowe", - "create.ponder.tag.train_related.description": "Komponenty używane przy konstrukcji lub zarządzaniu maszynami kolejowymi", - - "create.ponder.analog_lever.header": "Kontrola sygnałów z wykorzystaniem dźwigni analogowej", - "create.ponder.analog_lever.text_1": "Dźwignie analogowe są kompaktowymi i dokładnymi źródłami sygnału Redstone", - "create.ponder.analog_lever.text_2": "Kliknij PPM, aby zwiększyć wysyłaną przez nie siłę sygnału ", - "create.ponder.analog_lever.text_3": "Kliknij PPM skradając się, aby zmniejszyć wysyłaną przez nie siłę sygnału ", - - "create.ponder.andesite_tunnel.header": "Używanie andezytowych tuneli", - "create.ponder.andesite_tunnel.text_1": "Andezytowe tunele mogą być użyte do przykrycia Twoich taśmociągów", - "create.ponder.andesite_tunnel.text_2": "Kiedy andezytowy tunel ma połączenie z jego boku...", - "create.ponder.andesite_tunnel.text_3": "...będzie oddzielał dokładnie jeden przedmiot na każde wyjście", - "create.ponder.andesite_tunnel.text_4": "Reszta przedmiotów będzie kontynuowało swoją podróż", - - "create.ponder.auto_schedule.header": "Stacje i tworzenie harmonogramów", - "create.ponder.auto_schedule.text_1": "Harmonogramy mogą zostać użyte, aby nadać kierowcom cel jazdy", - "create.ponder.auto_schedule.text_2": "Komparatory otrzymają sygnał kiedy na stacji obecny jest pociąg", - "create.ponder.auto_schedule.text_3": "Stacje mogą być nadjechane tylko w zaznaczonym kierunku", - "create.ponder.auto_schedule.text_4": "Stacje mogą być również użyte, aby automatycznie przypisać nowe harmonogramy.", - "create.ponder.auto_schedule.text_5": "Harmonogram położony na stacji automatycznie skopiuje się na obecne pociągi", - "create.ponder.auto_schedule.text_6": "Przeciwnie do manualnego ustawiania harmonogramów, kierowcy nie wezmą ze sobą przedmiotu ze stacji", - - "create.ponder.basin.header": "Przetwarzanie przedmiotów w tyglu", - "create.ponder.basin.text_1": "Tygiel może przechowywać przedmioty i płyny do późniejszej obróbki", - "create.ponder.basin.text_2": "Po obróbce, tygle spróbują wyrzucić gotowy przedmiot z boku, jeden blok pod spodem", - "create.ponder.basin.text_3": "Jeśli stoi tam odpowiedni komponent, z boku tygla pojawi się wylot", - "create.ponder.basin.text_4": "Jest tu wiele opcji", - "create.ponder.basin.text_5": "Produkty będą pobrane przez poniższy pojemnik", - "create.ponder.basin.text_6": "Bez wylotu, tygiel zachowa produkty przez niego wytworzone", - "create.ponder.basin.text_7": "Może to być przydatne, jeśli przedmioty te muszą być ponownie użyte jako składniki", - "create.ponder.basin.text_8": "Gotowe przedmioty muszą być wyciągnięte z tygla", - "create.ponder.basin.text_9": "Filtr może być przydatny, aby zapobiec wyciąganiu nieprzerobionych przedmiotów", - - "create.ponder.bearing_modes.header": "Tryby ruchu dla mechanicznego łożyska", - "create.ponder.bearing_modes.text_1": "Kiedy zatrzymane, mechaniczne łożysko umieści strukturę w najbliższej możliwej przestrzeni", - "create.ponder.bearing_modes.text_2": "Może zostać ustawiony, aby nigdy nie powracał do stałych bloków, lub tylko blisko kąta, z jakiego zaczął", - - "create.ponder.belt_casing.header": "Przykrywanie taśmociągów", - "create.ponder.belt_casing.text_1": "Mosiężne lub andezytowe obudowy mogą być użyte do dekoracji taśmociągów", - "create.ponder.belt_casing.text_2": "Klucz może zostać użyty do usunięcia obudowy", - - "create.ponder.belt_connector.header": "Używanie taśmociągów", - "create.ponder.belt_connector.text_1": "Kliknięcie PPM na dwa wały połączy je taśmociągiem", - "create.ponder.belt_connector.text_2": "Przypadkowe wybory mogą być anulowane klikając na nie PPM skradając się", - "create.ponder.belt_connector.text_3": "Dodatkowe wały mogą zostać dodane w środku taśmociągu", - "create.ponder.belt_connector.text_4": "Wały połączone taśmociągiem będą się obracały z taką samą prędkością i kierunkiem", - "create.ponder.belt_connector.text_5": "Dodatkowe wały mogą zostać usunięte przy pomocy klucza", - "create.ponder.belt_connector.text_6": "Taśmociągi mogą zostać zabarwione w celach estetycznych", - - "create.ponder.belt_directions.header": "Prawidłowe orientacje taśmociągów", - "create.ponder.belt_directions.text_1": "Taśmociągi nie mogą się łączyć w losowych kierunkach", - "create.ponder.belt_directions.text_2": "1. Mogą się łączyć poziomo", - "create.ponder.belt_directions.text_3": "2. Mogą się łączyć ukośnie", - "create.ponder.belt_directions.text_4": "3. Mogą się łączyć pionowo", - "create.ponder.belt_directions.text_5": "4. I mogą łączyć pionowe wały poziomo", - "create.ponder.belt_directions.text_6": "To są wszystkie możliwe kierunki połączeń. Taśmociągi mogą mieć dowolną długość od 2 do 20 bloków", - - "create.ponder.belt_transport.header": "Używanie taśmociągów w celach logistycznych", - "create.ponder.belt_transport.text_1": "Ruchome taśmociągi będą przesuwały przedmioty lub inne byty", - "create.ponder.belt_transport.text_2": "Kliknij PPM pustą ręką, aby zabrać przedmiot z taśmociągu", - - "create.ponder.blaze_burner.header": "Napełnianie płomiennych palników", - "create.ponder.blaze_burner.text_1": "Płomienne palniki dają ciepło potrzebne do obróbki niektórych przedmiotów w tyglu", - "create.ponder.blaze_burner.text_2": "Aby uzyskać ciepło, płomyk uwięziony wewnątrz musi dostać jakieś łatwopalne przedmioty", - "create.ponder.blaze_burner.text_3": "Z użyciem płomiennego ciasta, palnik może uzyskać szczególnie wysoką temperaturę", - "create.ponder.blaze_burner.text_4": "Dostarczanie płomykowi przedmiotów może zostać zautomatyzowane z użyciem aplikatorów lub mechanicznych ramion", - - "create.ponder.brass_funnel.header": "Mosiężny lej", - "create.ponder.brass_funnel.text_1": "Andezytowe leje mogą pobierać jedynie pojedyncze przedmioty", - "create.ponder.brass_funnel.text_2": "Mosiężne leje mogą pobierać nawet pełne stosy", - "create.ponder.brass_funnel.text_3": "Przewijanie na slocie filtrującym pozwala na precyzyjną kontrolę nad maksymalną wielkością stosu", - "create.ponder.brass_funnel.text_4": "Użycie przedmiotu patrząc na slot filtrujący spowoduje, że lej będzie przesyłał tylko pasujące przedmioty", - - "create.ponder.brass_tunnel.header": "Używanie mosiężnych tuneli", - "create.ponder.brass_tunnel.text_1": "Mosiężne tunele mogą być użyte do przykrycia Twoich taśmociągów", - "create.ponder.brass_tunnel.text_2": "Mosiężne tunele posiadają slot filtrujący na każdej otwartej stronie", - "create.ponder.brass_tunnel.text_3": "Filtry przy wejściach zwyczajnie nie przepuszczają niepasujących przedmiotów", - "create.ponder.brass_tunnel.text_4": "Filtry przy wyjściach mogą być użyte do sortowania przedmiotów", - "create.ponder.brass_tunnel.text_5": "Jeśli przedmiot ma wiele możliwych wyjść, tryb dystrybucji zdecyduje jak mają się zachować", - "create.ponder.brass_tunnel.text_6": "Tunele na przylegających taśmociągach stworzą połączenie", - "create.ponder.brass_tunnel.text_7": "Przybyłe przedmioty będą dystrybuowane na wszystkie połączone wyjścia", - "create.ponder.brass_tunnel.text_8": "Przedmioty mogą być również wrzucone prosto do tunelu", - - "create.ponder.brass_tunnel_modes.header": "Tryby dystrybucji mosiężnego tunelu", - "create.ponder.brass_tunnel_modes.text_1": "Tryb dystrybucji mosiężnego tunelu może zostać wybrany z użyciem klucza", - "create.ponder.brass_tunnel_modes.text_10": "'Synchronizuj wejścia' jest trybem unikalnym dla mosiężnych tuneli", - "create.ponder.brass_tunnel_modes.text_11": "Przedmioty są przepuszczane jedynie, kiedy przed każdym połączonym tunelem czeka przedmiot", - "create.ponder.brass_tunnel_modes.text_12": "Dzięki temu mamy pewność, że każdy taśmociąg przesyła przedmioty z taką samą szybkością", - "create.ponder.brass_tunnel_modes.text_2": "Tryb 'Podziel' będzie starał się rozdzielić przedmioty do każdego wyjścia po równo", - "create.ponder.brass_tunnel_modes.text_3": "Jeśli wyjście nie może już przyjąć więcej przedmiotów, zostanie pominięte", - "create.ponder.brass_tunnel_modes.text_4": "Tryb 'Wymuś podział' nigdy nie pominie żadnego wyjścia, a zamiast tego będzie czekał, aż wszystkie będą wolne", - "create.ponder.brass_tunnel_modes.text_5": "Tryb 'Dookoła' zachowuje wielkość stosu, i rozprowadza je do każdego wyjścia po kolei", - "create.ponder.brass_tunnel_modes.text_6": "Znowu: jeśli wyjście nie może już przyjąć więcej przedmiotów, zostanie pominięte", - "create.ponder.brass_tunnel_modes.text_7": "Tryb 'Dookoła (wymuszony)' nigdy nie pominie żadnego wyjścia", - "create.ponder.brass_tunnel_modes.text_8": "Tryb 'Preferuj najbliższe' priorytetyzuje najbliższe wyjście od wejścia, z którego przybył przedmiot", - "create.ponder.brass_tunnel_modes.text_9": "Tryb 'Losowo' rozdystrybuuje całe stosy do losowych wyjść", - - "create.ponder.cart_assembler.header": "Przesuwanie maszyn z użyciem montera wagoników", - "create.ponder.cart_assembler.text_1": "Zasilony monter wagoników przyczepia dołączone struktury do przejeżdżających wagoników", - "create.ponder.cart_assembler.text_2": "Niezasilony, odczepia struktury od przejeżdżających wagoników", - "create.ponder.cart_assembler.text_3": "Klucz pomoże Ci przenieść gotowy wagonik w inne miejsce", - - "create.ponder.cart_assembler_dual.header": "Konstruowanie wielowagonikowych struktur", - "create.ponder.cart_assembler_dual.text_1": "Jeśli dwa montery wagoników dzielą ze sobą jedną strukturę...", - "create.ponder.cart_assembler_dual.text_2": "...zasilenie dowolnego z nich przyczepi konstrukcję do obu wagoników", - "create.ponder.cart_assembler_dual.text_3": "Wagoniki będą się zachowywać jak te połączone łącznikiem", - - "create.ponder.cart_assembler_modes.header": "Dostosowywanie orientacji maszyn w wagoniku", - "create.ponder.cart_assembler_modes.text_1": "Maszyny w wagoniku obracają się wraz z wagonikiem", - "create.ponder.cart_assembler_modes.text_2": "Ta strzałka pokazuje, która strona maszyny jest jej przodem", - "create.ponder.cart_assembler_modes.text_3": "Jeśli monter jest ustawiony na tryb 'Zablokuj obrót', maszyna nigdy nie zmieni swojej orientacji", - - "create.ponder.cart_assembler_rails.header": "Inne typy wagoników i torów", - "create.ponder.cart_assembler_rails.text_1": "Montery wagoników stojące na zwykłych torach nie zmienią prędkości przejeżdżającego wagonika", - "create.ponder.cart_assembler_rails.text_2": "Jeśli stoi na zasilanych lub sterujących torach, wagonik będzie stał w miejscu tak długo, aż nie zostaną tory zasilone", - "create.ponder.cart_assembler_rails.text_3": "Inne typy wagoników mogą być użyte jako baza dla maszyny", - "create.ponder.cart_assembler_rails.text_4": "Wagoniki z piecem będą ciągle zasilane, pobierając paliwo z doczepionych pojemników", - - "create.ponder.chain_drive.header": "Przekazywanie siły obrotowej z użyciem przekaźników łańcuchowych", - "create.ponder.chain_drive.text_1": "Przekaźniki łańcuchowe przekazują obroty do wszystkich połączonych przekaźników", - "create.ponder.chain_drive.text_2": "Wszystkie wały połączone w ten sposób będą obracać się w tą samą stronę", - "create.ponder.chain_drive.text_3": "Dowolna część w rzędzie może być obrócona o 90 stopni", - - "create.ponder.chain_gearshift.header": "Kontrolowanie prędkości obrotu z użyciem przekładników łańcuchowych", - "create.ponder.chain_gearshift.text_1": "Niezasilone przekładniki łańcuchowe zachowują się dokładnie tak samo jak przekaźniki łańcuchowe", - "create.ponder.chain_gearshift.text_2": "Kiedy zasilone, prędkość przekazywana do pozostałych przekładników jest podwojona", - "create.ponder.chain_gearshift.text_3": "Jeśli zasilony przekładnik nie jest źródłem obrotów, jego prędkość będzie zmniejszona dwukrotnie", - "create.ponder.chain_gearshift.text_4": "W oby przypadkach, pozostałe przekładniki będą pracować z dwukrotnie większą prędkością niż ten, który jest zasilony", - "create.ponder.chain_gearshift.text_5": "Z użyciem sygnałów analogowych, ta różnica może być dostosowana z większą dokładnością - pomiędzy 1 a 2x", - "create.ponder.chain_gearshift.text_6": "12 Ob/min", - - "create.ponder.chute.header": "Transport przedmiotów w dół z użyciem zsypów", - "create.ponder.chute.text_1": "Zsypy mogą transportować przedmioty pionowo z- i do pojemników", - "create.ponder.chute.text_2": "Używając klucza można stworzyć okno", - "create.ponder.chute.text_3": "Stawiając zsyp na bocznej stronie innego zsypu, będzie on skośny", - - "create.ponder.chute_upward.header": "Transport przedmiotów w górę przez zsypy", - "create.ponder.chute_upward.text_1": "Używając izolowanych wiatraków pod zsypem możliwy jest transport przedmiotów w górę zsypu", - "create.ponder.chute_upward.text_2": "Patrzenie na zsyp przez Gogle Inżyniera pokazuje informacje o kierunku funkcjonowania zsypu", - "create.ponder.chute_upward.text_3": "Od 'zablokowanej' strony przedmioty muszą być wkładane/wyciągane od boku", - - "create.ponder.clockwork_bearing.header": "Używanie mechanizmu zegarowego", - "create.ponder.clockwork_bearing.text_1": "Mechanizmy zegarowe przyczepiają do siebie bloki, które mają z przodu", - "create.ponder.clockwork_bearing.text_2": "Po dostarczeniu siły obrotowej, struktura obróci się, pokazując obecną godzinę", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "Kliknij PPM na mechanizm, aby zatrzymać lub rozpocząć obrót struktury", - "create.ponder.clockwork_bearing.text_6": "Przed wskazówką godzinową, można dodać kolejną strukturę", - "create.ponder.clockwork_bearing.text_7": "Upewnij się, że obie struktury nie są ze sobą połączone", - "create.ponder.clockwork_bearing.text_8": "Druga struktura będzie działać jak wskazówka minutowa", - - "create.ponder.clutch.header": "Kontrolowanie obrotu z użyciem sprzęgła", - "create.ponder.clutch.text_1": "Sprzęgło przekazuje obrót w linii prostej", - "create.ponder.clutch.text_2": "Zasilony, przerywa połączenie", - - "create.ponder.cog_speedup.header": "Przekładnia z kół zębatych", - "create.ponder.cog_speedup.text_1": "Duże i małe koła zębate mogą być połączone po ukosie", - "create.ponder.cog_speedup.text_2": "Przekazując z dużego koła na małe, prędkość wzrośnie dwukrotnie", - "create.ponder.cog_speedup.text_3": "Przekazując na odwrót, prędkość spadnie dwukrotnie", - - "create.ponder.cogwheel.header": "Przekazywanie obrotu z użyciem kół zębatych", - "create.ponder.cogwheel.text_1": "Koła zębate przekazują obrót do sąsiadujących kół", - "create.ponder.cogwheel.text_2": "Koła połączone w ten sposób będą obracać się w przeciwnych kierunkach", - - "create.ponder.cogwheel_casing.header": "Izolowanie kół zębatych", - "create.ponder.cogwheel_casing.text_1": "Mosiężne lub andezytowe obudowy mogą zostać użyte aby udekorować koła zębate", - "create.ponder.cogwheel_casing.text_2": "Komponenty dodane po izolowaniu nie zostaną połączone z wyjściami wałów", - "create.ponder.cogwheel_casing.text_3": "Klucz może zostać użyty, aby przełączać połączenia", - - "create.ponder.creative_fluid_tank.header": "Kreatywne zbiorniki", - "create.ponder.creative_fluid_tank.text_1": "Kretywne zbiorniki mogą być użyte do zapewnienia nieskończonej ilości dowolnej cieczy", - "create.ponder.creative_fluid_tank.text_2": "Kliknij PPM przedmiotem zawierającym jakąś ciecz, aby napełnić nią zbiornik", - "create.ponder.creative_fluid_tank.text_3": "Systemu rur mogą od teraz pobierać przypisaną ciecz w nieskończoność", - "create.ponder.creative_fluid_tank.text_4": "Jakiekolwiek płyny wtłaczane do kreatywnego zbiornika będą usuwane", - - "create.ponder.creative_motor.header": "Generowanie siły obrotowej z użyciem kreatywnego silnika", - "create.ponder.creative_motor.text_1": "Kreatywny silnik to kompaktowe i regulowane źródło siły obrotowej", - "create.ponder.creative_motor.text_2": "Przewijanie patrząc na tylny panel zmienia prędkość obrotu", - - "create.ponder.creative_motor_mojang.header": "Enigma Mojangu", - - "create.ponder.crushing_wheels.header": "Kruszenie przedmiotów", - "create.ponder.crushing_wheels.text_1": "Para kół kruszących kruszy przedmioty niezwykle efektywnie", - "create.ponder.crushing_wheels.text_2": "Powinny się one kręcić w przeciwnych kierunkach", - "create.ponder.crushing_wheels.text_3": "Przedmioty wrzucone od góry będą kruszone", - "create.ponder.crushing_wheels.text_4": "Przedmioty mogą zostać wrzucone i odebrane automatycznie", - - "create.ponder.deployer.header": "Używanie aplikatora", - "create.ponder.deployer.text_1": "Aplikator może imitować niektóre zachowania gracza, z użyciem siły obrotowej", - "create.ponder.deployer.text_10": "Kliknij PPM jego przód, aby dać mu przedmiot", - "create.ponder.deployer.text_11": "Przedmioty mogą też zostać dostarczone automatycznie", - "create.ponder.deployer.text_12": "Aplikatory posiadają slot filtrujący", - "create.ponder.deployer.text_13": "Kiedy filtr jest skonfigurowany, aplikator użyje tylko pasujących przedmiotów", - "create.ponder.deployer.text_14": "Od teraz jedynie pasujące przedmioty mogą być włożone...", - "create.ponder.deployer.text_15": "...i jedynie niepasujące przedmioty mogą być wyciągnięte", - "create.ponder.deployer.text_2": "Aplikator może używać przedmiotów jedynie 2 bloki przed nim", - "create.ponder.deployer.text_3": "Bloki bezpośrednio przed nim nie ograniczają go", - "create.ponder.deployer.text_4": "Aplikatory mogą:", - "create.ponder.deployer.text_5": "Stawiać bloki,", - "create.ponder.deployer.text_6": "Używać przedmiotów,", - "create.ponder.deployer.text_7": "Aktywować bloki,", - "create.ponder.deployer.text_8": "Kopać bloki", - "create.ponder.deployer.text_9": "i atakować moby", - - "create.ponder.deployer_contraption.header": "Używanie aplikatorów w maszynach", - "create.ponder.deployer_contraption.text_1": "Kiedy aplikatory są przesuwane, jako część ruchomej maszyny...", - "create.ponder.deployer_contraption.text_2": "...aktywują się przy każdym odwiedzonym bloku, pobierając przedmioty z pojemników przyczepionych do maszyny", - "create.ponder.deployer_contraption.text_3": "Slot filtrujący może być użyty do sprecyzowania, jakich przedmiotów używać", - - "create.ponder.deployer_modes.header": "Tryby aplikatora", - "create.ponder.deployer_modes.text_1": "Domyślnie, aplikator imituje prawe kliknięcie", - "create.ponder.deployer_modes.text_2": "Może być przestawiony na lewe kliknięcie używając klucza", - - "create.ponder.deployer_processing.header": "Przetwarzanie przedmiotów z użyciem aplikatorów", - "create.ponder.deployer_processing.text_1": "Posiadając odpowiedni przedmiot aplikatory mogą przyłączać je do przedmiotów leżących poniżej", - "create.ponder.deployer_processing.text_2": "Przedmioty mogą być rzucone lub położone na składnicy poniżej aplikatora", - "create.ponder.deployer_processing.text_3": "Jeśli przedmioty znajdują się na taśmociągu...", - "create.ponder.deployer_processing.text_4": "...aplikator zatrzyma je i przetworzy - wszystko automatycznie", - - "create.ponder.deployer_redstone.header": "Kontrolowanie aplikatorów z użyciem Redstone'a", - "create.ponder.deployer_redstone.text_1": "Zasilone przez Redstone, aplikatory nie aktywują się", - "create.ponder.deployer_redstone.text_2": "Przed zatrzymaniem, aplikatory dokończą już zaczętą czynność", - "create.ponder.deployer_redstone.text_3": "Chwilowe wyłączenie sygnału aktywuje więc aplikator dokładnie raz", - - "create.ponder.depot.header": "Używanie składnic", - "create.ponder.depot.text_1": "Składnice działają jak nieruchome elementy taśmociągu", - "create.ponder.depot.text_2": "Kliknij PPM, aby ręcznie położyć lub podnieść z niej przedmiot", - "create.ponder.depot.text_3": "Podobnie jak taśmociągi, składnica może dostarczać przedmioty do obróbki...", - "create.ponder.depot.text_4": "…jak i również dla mechanicznych ramion", - - "create.ponder.display_board.header": "Używanie tablic wyświetlających", - "create.ponder.display_board.text_1": "Tablice wyświetlające to skalowana alternatywa tabliczek", - "create.ponder.display_board.text_2": "Wymagają one siły obrotowej, aby działać", - "create.ponder.display_board.text_3": "Tekst może być wyświetlany za pomocą znaczników...", - "create.ponder.display_board.text_4": "...lub za pomocą nadajników wyświetlacza", - "create.ponder.display_board.text_5": "Barwniki mogą zostać zaaplikowane na pojedyncze linijki tablicy", - "create.ponder.display_board.text_6": "Linijki mogą zostać zresetowane przez kliknięcie pustą ręką", - - "create.ponder.display_link.header": "Konfigurowanie nadajników wyświetlacza", - "create.ponder.display_link.text_1": "Nadajniki wyświetlacza mogą zostać użyte do wizualizacji dynamicznych informacji", - "create.ponder.display_link.text_2": "Na początek, kliknij PPM na docelowy wyświetlacz...", - "create.ponder.display_link.text_3": "...potem przyczep nadajnik do bloku źródła wyświetlacza", - "create.ponder.display_link.text_4": "Otwórz interfejs, aby wybrać i skonfigurować wysyłane informacje", - "create.ponder.display_link.text_5": "Wyświetlacz będzie teraz otrzymywał informacje z nadajnika", - "create.ponder.display_link.text_6": "Nie każdy blok może działać jako źródło", - "create.ponder.display_link.text_7": "Każdy kompatybilny blok nadaje unikalne informacje", - "create.ponder.display_link.text_8": "Nadajnik wyświetlacza może działać z kilkoma różnymi wyświetlaczami", - - "create.ponder.display_link_redstone.header": "Kontrola redstone", - "create.ponder.display_link_redstone.text_1": "Nadajniki wyświetlacza zasilone sygnałem redstone przestaną wysyłać aktualizacje", - "create.ponder.display_link_redstone.text_2": "Kiedy zasilanie zostanie odcięte, zegarek zostanie zresetowany i nowe informacje zostaną natychmiastowo wysłane", - "create.ponder.display_link_redstone.text_3": "Sygnały wysłane ze źródła nie wpływają na nadajnik", - - "create.ponder.empty_blaze_burner.header": "Używanie pustych płomiennych palników", - "create.ponder.empty_blaze_burner.text_1": "Kliknij PPM na Płomyka trzymają w ręce pusty palnik, aby uwięzić go w środku", - "create.ponder.empty_blaze_burner.text_2": "Ewentualnie, Płomyk może być zabrany prosto z jego Spawnera", - "create.ponder.empty_blaze_burner.text_3": "Masz teraz idealne źródło ciepła dla przeróżnych maszyn", - "create.ponder.empty_blaze_burner.text_4": "Dla celów dekoracyjnych, puste palniki można też zapalić krzesiwem", - "create.ponder.empty_blaze_burner.text_5": "Płomień palnika można zmienić w płomień dusz z użyciem piasku lub gleby dusz.", - "create.ponder.empty_blaze_burner.text_6": "Palniki bez Płomyka nie będą dawały jednak ciepła", - - "create.ponder.encased_fluid_pipe.header": "Przykrywanie rur", - "create.ponder.encased_fluid_pipe.text_1": "Miedziana obudowa może być użyta do udekorowania rur", - "create.ponder.encased_fluid_pipe.text_2": "Poza byciem ukrytym, rury są zablokowane w ich oryginalnym położeniu", - "create.ponder.encased_fluid_pipe.text_3": "Nie będzie oddziaływała już z sąsiadującymi blokami", - - "create.ponder.fan_direction.header": "Przepływ powietrza przez izolowane wiatraki", - "create.ponder.fan_direction.text_1": "Izolowane wiatraki używają siły obrotowej, aby wytworzyć przepływ powietrza", - "create.ponder.fan_direction.text_2": "Siła i kierunek przepływu zależy od właściwości siły obrotu", - - "create.ponder.fan_processing.header": "Obróbka przedmiotów z użyciem izolowanych wiatraków", - "create.ponder.fan_processing.text_1": "Przepływając przez lawę, powietrze staje się gorące", - "create.ponder.fan_processing.text_2": "Przedmioty, które wpadną na jego drogę będą wytopione", - "create.ponder.fan_processing.text_3": "Wrzucone jedzenie będzie spalone na popiół", - "create.ponder.fan_processing.text_4": "Zamiast lawy można użyć ognia, aby wędzić surowe jedzenie", - "create.ponder.fan_processing.text_5": "Powietrze przepływające przez wodę będzie płukało przedmioty", - "create.ponder.fan_processing.text_6": "W ten sposób z niepozornych przedmiotów można otrzymać przedmioty znacznie bardziej interesujące...", - "create.ponder.fan_processing.text_7": "Prędkość wiatraka nie wpływa na szybkość obróbki, a jedynie na jego zasięg!", - "create.ponder.fan_processing.text_8": "Przepływ powietrza działa również na przedmioty na taśmociągach lub składnicach", - - "create.ponder.fluid_pipe_flow.header": "Transport cieczy z użyciem rur", - "create.ponder.fluid_pipe_flow.text_1": "Rury mogą połączyć dwa lub więcej bloków przechowujących ciecze", - "create.ponder.fluid_pipe_flow.text_2": "Używając klucza, prosta rura może mieć w sobie okienko", - "create.ponder.fluid_pipe_flow.text_3": "Rury z oknami nie będą się łączyć z żadnymi rurami po jej boku", - "create.ponder.fluid_pipe_flow.text_4": "Rury mogą transportować ciecze dzięki mechanicznym pompom", - "create.ponder.fluid_pipe_flow.text_5": "Ciecz nie jest z początku transportowana...", - "create.ponder.fluid_pipe_flow.text_6": "Kiedy przepływ dotrze do celu, połączone ze sobą bloki będą stopniowo przesyłać zawarte ciecze", - "create.ponder.fluid_pipe_flow.text_7": "W ten sposób, postawione rury nigdy tak naprawde nie zawierają w sobie żadnej cieczy", - - "create.ponder.fluid_pipe_interaction.header": "Opróżnianie i napełnianie bloków przechowujących ciecze", - "create.ponder.fluid_pipe_interaction.text_1": "Punkty końcowe systemu rur mogą współpracować z rozmaitością różnych bloków", - "create.ponder.fluid_pipe_interaction.text_2": "Dowolny blok mogący przechowywać ciecze może być opróżniony lub napełniony", - "create.ponder.fluid_pipe_interaction.text_3": "Źródła cieczy bezpośrednio przed otwartym zakończeniem rury mogą być zebrane...", - "create.ponder.fluid_pipe_interaction.text_4": "...a wycieki w puste przestrzenie mogą tworzyć nowe źródła", - "create.ponder.fluid_pipe_interaction.text_5": "Rury mogą również opróżniać niektóre bloki bezpośrednio", - - "create.ponder.fluid_tank_sizes.header": "Rozmiary zbiornika", - "create.ponder.fluid_tank_sizes.text_1": "Zbiorniki mogą być połączone aby zwiększyć ich łączną pojemność", - "create.ponder.fluid_tank_sizes.text_2": "Ich podstawa może mieć aż do 3 bloków...", - "create.ponder.fluid_tank_sizes.text_3": "...i rozciągać się na nawet 30 dodatkowych warstw w górę", - "create.ponder.fluid_tank_sizes.text_4": "Używając klucza, zbiornik może otrzymać okienko", - - "create.ponder.fluid_tank_storage.header": "Przechowywanie cieczy w zbiornikach", - "create.ponder.fluid_tank_storage.text_1": "Zbiorniki mogą być używane do przechowywania dużych ilości cieczy", - "create.ponder.fluid_tank_storage.text_2": "Rury mogą zostać podłączone od dowolnej strony", - "create.ponder.fluid_tank_storage.text_3": "Poziom cieczy może być zmierzony z użyciem komparatora", - "create.ponder.fluid_tank_storage.text_4": "W trybie przetrwania ciecze nie mogą być dodane lub zabrane manualnie", - "create.ponder.fluid_tank_storage.text_5": "Można użyć tygli, odpływów lub napełniaczy aby opróżnić lub napełnić przedmioty mogące przechowywać ciecze", - - "create.ponder.funnel_compat.header": "Kompatybilność lejków", - "create.ponder.funnel_compat.text_1": "Lejki działają też z wieloma innymi komponentami", - "create.ponder.funnel_compat.text_2": "Pionowe piły", - "create.ponder.funnel_compat.text_3": "Składnice", - "create.ponder.funnel_compat.text_4": "Odpływy", - - "create.ponder.funnel_direction.header": "Kierunek transportu", - "create.ponder.funnel_direction.text_1": "Postawiony normalnie, wyciąga przedmioty z pojemnika", - "create.ponder.funnel_direction.text_2": "Postawiony w czasie skradania, wkłada przedmioty do pojemnika", - "create.ponder.funnel_direction.text_3": "Używając klucza, lejek może być odwrócony już po postawieniu", - "create.ponder.funnel_direction.text_4": "Takie same zasady stosują się do większości orientacji", - "create.ponder.funnel_direction.text_5": "Lejki na taśmociągach będą wyciągały/wkładały, bazując na ich kierunku poruszania się", - - "create.ponder.funnel_intro.header": "Używanie lejków", - "create.ponder.funnel_intro.text_1": "Lejki są idealne to transportu przedmiotów z- i do pojemników", - - "create.ponder.funnel_redstone.header": "Kontrola Redstonem", - "create.ponder.funnel_redstone.text_1": "Zasilenie spowoduje, że lejek przestanie działać", - - "create.ponder.funnel_transfer.header": "Bezpośredni transport", - "create.ponder.funnel_transfer.text_1": "Lejki nie mogą bezpośrednio transportować pomiędzy zamkniętymi pojemnikami", - "create.ponder.funnel_transfer.text_2": "Zsypy lub inteligentne zsypy mogą bardziej się do tego nadawać", - "create.ponder.funnel_transfer.text_3": "To samo tyczy się transportu poziomego. Taśmociąg może tutaj pomóc", - - "create.ponder.gantry_carriage.header": "Używanie przenośników suwnicowych", - "create.ponder.gantry_carriage.text_1": "Przenośnik suwnicowy może być zamontowany i przesuwany po suwnicy", - "create.ponder.gantry_carriage.text_2": "Może on przenosić dołączone bloki", - - "create.ponder.gantry_cascaded.header": "Kaskadowe suwnice", - "create.ponder.gantry_cascaded.text_1": "Suwnice można dołączyć do przenośnika suwnicowego bez użycia Super Glue", - "create.ponder.gantry_cascaded.text_2": "To samo tyczy się przenośników zamontowanych na przesuwanej suwnicy", - "create.ponder.gantry_cascaded.text_3": "Dlatego więc system suwnic może posiadać wiele osi ruchu", - - "create.ponder.gantry_direction.header": "Kierunek ruchu przenośnika", - "create.ponder.gantry_direction.text_1": "Suwnice mogą mieć odwrotne orientacje", - "create.ponder.gantry_direction.text_2": "Kierunek ruchu przenośnika zależy od orientacji jego suwnicy", - "create.ponder.gantry_direction.text_3": "…jak i kierunku obrotu suwnicy", - "create.ponder.gantry_direction.text_4": "Te same zasady stosują się do obrotu dołączonych elementów", - - "create.ponder.gantry_redstone.header": "Przenoszenie obrotu przez przenośniki", - "create.ponder.gantry_redstone.text_1": "Zasilone suwnice zatrzymują swoje przenośniki", - "create.ponder.gantry_redstone.text_2": "Zamiast tego, jej obrót przekazywany jest do wyjściowego wała przenośnika", - - "create.ponder.gantry_shaft.header": "Używanie suwnic", - "create.ponder.gantry_shaft.text_1": "Suwnice są podstawą całego mechanizmu suwnicowego. Dołączone przenośniki będą poruszać się wzdłuż suwnic", - "create.ponder.gantry_shaft.text_2": "Mechanizmy suwnicowe mogą przesuwać dołączone bloki", - - "create.ponder.gearbox.header": "Przenoszenie siły obrotowej z użyciem przekładni", - "create.ponder.gearbox.text_1": "Zmiany osi obrotu mogą bardzo szybko stać się bardzo duże", - "create.ponder.gearbox.text_2": "Przekładnia jest bardziej kompaktową wersją tego mechanizmu", - "create.ponder.gearbox.text_3": "Wały dookoła rogów obracają się w lustrzanych kierunkach", - "create.ponder.gearbox.text_4": "Proste połączenie będzie odwrócone", - - "create.ponder.gearshift.header": "Przenoszenie siły obrotowej z użyciem przekładnika", - "create.ponder.gearshift.text_1": "Przekładniki przenoszą obrót w linii prostej", - "create.ponder.gearshift.text_2": "Kiedy zasilone, kierunek obrotu odwraca się", - - "create.ponder.hand_crank.header": "Generowanie siły obrotowej z użyciem ręcznej korby", - "create.ponder.hand_crank.text_1": "Korby mogą być użyte przez gracza, aby ręcznie wprawić komponent w ruch", - "create.ponder.hand_crank.text_2": "Trzymaj PPM, aby obrócić ją odwrotnie niż wskazówki zegara", - "create.ponder.hand_crank.text_3": "Wytwarzana prędkość jest dosyć duża!", - "create.ponder.hand_crank.text_4": "Trzymaj PPM skradając się, aby obrócić ją zgodnie ze wskazówkami zegara", - - "create.ponder.hose_pulley.header": "Osuszanie i napełnianie źródeł z użyciem krązków z wężem", - "create.ponder.hose_pulley.text_1": "Krążki z wężem mogą być użyte do napełniania lub opróżniania dużych akwenów cieczy", - "create.ponder.hose_pulley.text_2": "Z użyciem siły obrotowej, wysokość węża może być kontrolowana", - "create.ponder.hose_pulley.text_3": "Wąż jest wciągany z powrotem, gdy siły obrotowa jest odwrócona", - "create.ponder.hose_pulley.text_4": "Z drugiej strony mogą być przyłączone rury", - "create.ponder.hose_pulley.text_5": "Przyłączone systemy rur mogą wylewać ciecz przez wąż...", - "create.ponder.hose_pulley.text_6": "...lub zasysać ją, tym samym osuszając akwen", - "create.ponder.hose_pulley.text_7": "Prędkość transportu cieczy zależy w całości od przepływu cieczy w całym systemie rur", - - "create.ponder.hose_pulley_infinite.header": "Pasywne osuszanie i napełnianie dużych akwenów cieczy", - "create.ponder.hose_pulley_infinite.text_1": "Opuszczając wąż do odpowiednio wielkiego akwenu...", - "create.ponder.hose_pulley_infinite.text_2": "Będzie transportować ciecz w dowolną stronę, bez wpływu na źródło, do którego został opuszczony", - "create.ponder.hose_pulley_infinite.text_3": "System rur może wtedy pobierać lub wylewać ciecze przez takie węże bez limitu", - - "create.ponder.hose_pulley_level.header": "Poziomy cieczy przy krążkach z wężem", - "create.ponder.hose_pulley_level.text_1": "Będąc w pełni zwinięty, krążek z wężem nie może pracować", - "create.ponder.hose_pulley_level.text_2": "Osuszanie odbywa się od góry do dołu", - "create.ponder.hose_pulley_level.text_3": "Poziom cieczy będzie tuż za końcem węża", - "create.ponder.hose_pulley_level.text_4": "Napełnianie odbywa się z dołu do góry", - "create.ponder.hose_pulley_level.text_5": "Poziom cieczy nie podniesie się powyżej blok, w którym znajduje się koniec węża", - - "create.ponder.item_drain.header": "Opróżnianie przedmiotów z użyciem odpływów", - "create.ponder.item_drain.text_1": "Odpływy mogą opróżniać przedmioty zawierające ciecz", - "create.ponder.item_drain.text_2": "Kliknij PPM na odpływ, aby opróżnić trzymany przedmiot", - "create.ponder.item_drain.text_3": "Kiedy przedmioty są dostarczane od boku...", - "create.ponder.item_drain.text_4": "...są opróżniane i przesuwane na drugą stronę", - "create.ponder.item_drain.text_5": "Systemy rur mogą wyciągać zawartą w odpływie ciecz", - - "create.ponder.item_vault_sizes.header": "Rozmiary kontenerów na przedmioty", - "create.ponder.item_vault_sizes.text_1": "Kontenery na przedmioty mogą zostać połączone aby zwiększyć ich pojemność", - "create.ponder.item_vault_sizes.text_2": "Ich kwadratowa podstawa może być szeroka na maksymalnie 3 bloki...", - "create.ponder.item_vault_sizes.text_3": "...a ich długość 3 razy większa niż średnica", - - "create.ponder.item_vault_storage.header": "Przechowywanie przedmiotów w kontenerach", - "create.ponder.item_vault_storage.text_1": "Kontenery na przedmioty mogą zostać użyte do przechowywania dużych ilości przedmiotów", - "create.ponder.item_vault_storage.text_2": "Jednakże, zawartość nie może być wkładana ani wyjmowana manualnie", - "create.ponder.item_vault_storage.text_3": "Jakiekolwiek komponenty do transportu przedmiotów mogą wkładać...", - "create.ponder.item_vault_storage.text_4": "...lub wyjmować zawartość z tego kontenera", - - "create.ponder.large_cogwheel.header": "Przekazywanie siły obrotowej z użyciem dużych kół zębatych", - "create.ponder.large_cogwheel.text_1": "Duże koła zębate mogą się łączyć ze sobą pod kątem prostym", - "create.ponder.large_cogwheel.text_2": "Pomogą one w przekazywaniu siły obrotowej na inne osie obrotu", - - "create.ponder.linear_chassis_attachment.header": "Dołączanie bloków do stelaża liniowego", - "create.ponder.linear_chassis_attachment.text_1": "Odkryte strony stelaża mogą być oblepione szlamem", - "create.ponder.linear_chassis_attachment.text_2": "Kliknij ponownie, aby oblepić również drugą stronę", - "create.ponder.linear_chassis_attachment.text_3": "Kliknij PPM skradając się, aby usunąć szlam", - "create.ponder.linear_chassis_attachment.text_4": "Lepkie strony zabiorą ze sobą linie bloków przed sobą", - "create.ponder.linear_chassis_attachment.text_5": "Użyj klucza, aby ustawić maksymalny zasięg działania stelaża", - "create.ponder.linear_chassis_attachment.text_6": "Trzymając CTRL i przewijając dostosujesz maksymalny zasięg wszystkich połączonych stelaży", - "create.ponder.linear_chassis_attachment.text_7": "Przyłączanie bloków do innej strony wymaga użycia Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "Z wykorzystaniem tych mechanik, struktury w każdym kształcie mogą tworzyć maszyną", - - "create.ponder.linear_chassis_group.header": "Przesuwanie liniowych stelaży w grupach", - "create.ponder.linear_chassis_group.text_1": "Liniowe stelaże łączą się z identycznymi stelażami obok nich", - "create.ponder.linear_chassis_group.text_2": "Kiedy jeden z nich jest przesunięty, wszystkie inne są ciągnięte za nim", - "create.ponder.linear_chassis_group.text_3": "Stelaże innego typu lub postawione w innym kierunku nie zostaną połączone", - - "create.ponder.mechanical_arm.header": "Ustawianie mechanicznych ramion", - "create.ponder.mechanical_arm.text_1": "Wejścia i wyjścia muszą zostać przypisane do ramienia, zanim będzie można je postawić", - "create.ponder.mechanical_arm.text_2": "Kliknij PPM na blok trzymając ramię, aby przypisać do niego cel", - "create.ponder.mechanical_arm.text_3": "Kliknij ponownie, aby przełączyć pomiędzy wejściem (niebieski) i wyjściem (pomarańczowy)", - "create.ponder.mechanical_arm.text_4": "Kliknij LPM, aby usunąć zaznaczenie", - "create.ponder.mechanical_arm.text_5": "Po postawieniu, mechaniczne ramię będzie operować pomiędzy wybranymi blokami", - "create.ponder.mechanical_arm.text_6": "Mogą one mieć dowolną ilość wejść i wyjść w ich zasięgu", - "create.ponder.mechanical_arm.text_7": "Nie z każdym blokiem zawierającym przedmioty może ono jednak bezpośrednio pracować", - "create.ponder.mechanical_arm.text_8": "Lejki i składnice mogą zapełnić tą lukę", - - "create.ponder.mechanical_arm_filtering.header": "Filtrowanie wyjść z mechanicznego ramienia", - "create.ponder.mechanical_arm_filtering.text_1": "Wejścia", - "create.ponder.mechanical_arm_filtering.text_2": "Wyjścia", - "create.ponder.mechanical_arm_filtering.text_3": "Czasami potrzebne jest ograniczenie celów ramienia przy pomocy filtra", - "create.ponder.mechanical_arm_filtering.text_4": "Mechaniczne ramiona nie posiadają żadnych opcji filtrowanie same w sobie", - "create.ponder.mechanical_arm_filtering.text_5": "Mosiężne lejki ustawione jako cele komunikują ramieniu informacje o swoim filtrze", - "create.ponder.mechanical_arm_filtering.text_6": "Ramię jest wystarczająco mądre, aby nie podnosić przedmiotów, których nie mogłoby odstawić", - - "create.ponder.mechanical_arm_modes.header": "Tryby dystrybucji mechanicznego ramienia", - "create.ponder.mechanical_arm_modes.text_1": "Wejście", - "create.ponder.mechanical_arm_modes.text_2": "Wyjście", - "create.ponder.mechanical_arm_modes.text_3": "Kiedykolwiek ramię musi wybrać pomiędzy wieloma możliwymi wyjściami...", - "create.ponder.mechanical_arm_modes.text_4": "…będzie działać zgodnie z jego ustawieniami", - "create.ponder.mechanical_arm_modes.text_5": "Przewijanie trzymając klucz pozwoli ci na konfigurację", - "create.ponder.mechanical_arm_modes.text_6": "Tryb 'Dookoła' zwyczajnie pozwala na cykl pomiędzy wszystkimi dostępnymi wyjściami", - "create.ponder.mechanical_arm_modes.text_7": "Jeśli wyjście nie może przyjąć więcej przedmiotów, będzie ono pominięte", - "create.ponder.mechanical_arm_modes.text_8": "Tryb 'Dookoła (wymuszony)' nigdy nie pominie żadnego wyjścia i poczeka, aż będzie ono wolne", - "create.ponder.mechanical_arm_modes.text_9": "Tryb 'Preferuj pierwszy cel' priorytetyzuje cele ustawione przed postawieniem jako pierwsze", - - "create.ponder.mechanical_arm_redstone.header": "Kontrolowanie mechanicznych ramion z użyciem Redstone'a", - "create.ponder.mechanical_arm_redstone.text_1": "Kiedy zasilone, mechaniczne ramię przestanie działać", - "create.ponder.mechanical_arm_redstone.text_2": "Przed zatrzymaniem, ramiona dokończą zaczętą już czynność", - "create.ponder.mechanical_arm_redstone.text_3": "Chwilowe wyłączenie sygnału aktywuje więc ramię dokładnie raz", - - "create.ponder.mechanical_bearing.header": "Przesuwanie struktur z użyciem mechanicznego łożyska", - "create.ponder.mechanical_bearing.text_1": "Mechaniczne łożysko przyczepia do siebie blok, który jest przed nim", - "create.ponder.mechanical_bearing.text_2": "W momencie otrzymania siły obrotowej, stworzy on obracającą się maszynę", - - "create.ponder.mechanical_crafter.header": "Ustawianie mechanicznych stołów rzemieślniczych", - "create.ponder.mechanical_crafter.text_1": "Grupa mechanicznych stołów rzemieślniczych może być użyta, aby zautomatyzować każdą recepturę", - "create.ponder.mechanical_crafter.text_2": "Używając klucza, ścieżki stołów mogą zostać ułożone", - "create.ponder.mechanical_crafter.text_3": "Aby układ był poprawny, wszystkie ścieżki muszą prowadzić do jednego wyjścia po dowolnej stronie", - "create.ponder.mechanical_crafter.text_4": "Produkty będą umieszczone w bloku przy wyjściu", - "create.ponder.mechanical_crafter.text_5": "Mechaniczne stoły rzemieślnicze wymagają siły obrotowej, aby pracować", - "create.ponder.mechanical_crafter.text_6": "Kliknij PPM na ich przody, aby ręcznie włożyć tam przedmioty", - "create.ponder.mechanical_crafter.text_7": "Kiedy każdy slot zawiera przedmiot, rozpocznie się proces konstruowania", - "create.ponder.mechanical_crafter.text_8": "Dla receptur, które nie zajmują wszystkich slotów, start konstruowania można rozpocząć zasilając dowolny z nich", - - "create.ponder.mechanical_crafter_connect.header": "Łączenie ekwipunków mechanicznych stołów rzemieślniczych", - "create.ponder.mechanical_crafter_connect.text_1": "Przedmioty mogą być włożone do stołów automatycznie", - "create.ponder.mechanical_crafter_connect.text_2": "Klikając na ich tył kluczem, mechaniczne stoły rzemieślnicze może połączyć ze sobą", - "create.ponder.mechanical_crafter_connect.text_3": "Wszystkie połączone stoły mogą przyjmować teraz przedmioty z jednego miejsca", - - "create.ponder.mechanical_crafter_covers.header": "Przykrywanie slotów mechanicznych stołów rzemieślniczych", - "create.ponder.mechanical_crafter_covers.text_1": "Niektóre receptury wymagają zapełnienia dziury pomiędzy poszczególnymi stołami", - "create.ponder.mechanical_crafter_covers.text_2": "Używając przykrywek na slot, można wyłączyć jeden stół z użytku. Nie będzie on przyjmował przedmiotów, ale będzie łączył sąsiadujące sloty w jedną całość", - "create.ponder.mechanical_crafter_covers.text_3": "Połączone stoły również działają w przypadku przykrycia jednego ze slotów", - - "create.ponder.mechanical_drill.header": "Niszczenie bloków mechanicznym wiertłem", - "create.ponder.mechanical_drill.text_1": "Po otrzymaniu siły obrotowej, mechaniczne wiertło będzie niszczyć bloki bezpośrednio przed nim", - "create.ponder.mechanical_drill.text_2": "Jego prędkość niszczenia zależy od prędkości siły obrotowej", - - "create.ponder.mechanical_drill_contraption.header": "Używanie mechanicznych wierteł w maszynach", - "create.ponder.mechanical_drill_contraption.text_1": "Kiedy wiertła są przesuwane razem z maszyną...", - "create.ponder.mechanical_drill_contraption.text_2": "…zniszczą one bloki na ich drodze", - - "create.ponder.mechanical_harvester.header": "Używanie mechanicznych żniwiarek w maszynach", - "create.ponder.mechanical_harvester.text_1": "Kiedy żniwiarki są przesuwane razem z maszyną...", - "create.ponder.mechanical_harvester.text_2": "…zbiorą one dojrzałe plony na ich drodze", - - "create.ponder.mechanical_mixer.header": "Obróbka przedmiotów z użyciem mechanicznego miksera", - "create.ponder.mechanical_mixer.text_1": "Używając miksera i tygla, niektóre receptury mogą być zautomatyzowane", - "create.ponder.mechanical_mixer.text_2": "Dostępne są wszystkie receptury nieokreślone, plus kilka innych", - "create.ponder.mechanical_mixer.text_3": "Niektóre z nich mogą wymagać użycia płomiennego palnika", - "create.ponder.mechanical_mixer.text_4": "Slot filtrujący może być użyty w przypadku dwóch konfliktujących receptur", - - "create.ponder.mechanical_piston.header": "Przesuwanie struktur z użyciem mechanicznego tłoka", - "create.ponder.mechanical_piston.text_1": "Mechaniczny tłok może przesuwać znajdujące się przed nim bloki", - "create.ponder.mechanical_piston.text_2": "Prędkość i kierunek ruchu zależy od dostarczonej siły obrotowej", - "create.ponder.mechanical_piston.text_3": "Lepkie mechaniczne tłoki mogą przyciągać doczepione bloki", - - "create.ponder.mechanical_piston_modes.header": "Tryby ruchu mechanicznych tłoków", - "create.ponder.mechanical_piston_modes.text_1": "Kiedy tłok zatrzyma się, przesuwana struktura znów stanie się zwyczajnymi blokami", - "create.ponder.mechanical_piston_modes.text_2": "Można go skonfigurować, aby bloki nigdy nie stawały się stałymi, lub tylko w pozycji początkowej", - - "create.ponder.mechanical_plough.header": "Używanie mechanicznych pługów w maszynach", - "create.ponder.mechanical_plough.text_1": "Kiedy pługi są przesuwane razem z maszyną...", - "create.ponder.mechanical_plough.text_2": "…zniszczą one niesolidne bloki na ich drodze", - "create.ponder.mechanical_plough.text_3": "Dodatkowo, pługi mogą orać pola", - "create.ponder.mechanical_plough.text_4": "…mogą też odrzucać moby bez ranienia ich", - - "create.ponder.mechanical_press.header": "Obróbka przedmiotów z użyciem mechanicznej prasy", - "create.ponder.mechanical_press.text_1": "Mechaniczna prasa może przetwarzać przedmioty znajdujące się pod nią", - "create.ponder.mechanical_press.text_2": "Przedmioty wejściowe mogą być rzucone pod prasę lub położone na składnicy", - "create.ponder.mechanical_press.text_3": "Kiedy przedmioty znajdują się na taśmociągu...", - "create.ponder.mechanical_press.text_4": "…prasa zatrzyma je i przetworzy - wszystko automatycznie", - - "create.ponder.mechanical_press_compacting.header": "Zbijanie przedmiotów z użyciem mechanicznej prasy", - "create.ponder.mechanical_press_compacting.text_1": "Prasowanie przedmiotów znajdujących się w tyglu sprawi, że staną się zbite", - "create.ponder.mechanical_press_compacting.text_2": "Można w ten sposób przetworzyć każdą recepturę, która wypełnia jednym przedmiotem kwadrat 2x2 lub 3x3", - "create.ponder.mechanical_press_compacting.text_3": "Niektóre z nich mogą wymagać użycia płomiennego palnika", - "create.ponder.mechanical_press_compacting.text_4": "Slot filtrujący może być użyty w przypadku dwóch konfliktujących receptur", - - "create.ponder.mechanical_pump_flow.header": "Transport płynów z użyciem mechanicznych pomp", - "create.ponder.mechanical_pump_flow.text_1": "Mechaniczne pompy zarządzają przepływem przez system rur, którego są częścią", - "create.ponder.mechanical_pump_flow.text_2": "Po wprawieniu w ruch, ich strzałka wskazuje kierunek przepływu", - "create.ponder.mechanical_pump_flow.text_3": "Rury z tyłu pobierają teraz ciecz...", - "create.ponder.mechanical_pump_flow.text_4": "...a te z przodu oddają zawartą ciecz", - "create.ponder.mechanical_pump_flow.text_5": "Odwrócenie kierunku obracania odwraca też kierunek przepływu", - "create.ponder.mechanical_pump_flow.text_6": "Użyj klucza, aby ręcznie odwrócić kierunek przepływu przez pompę", - - "create.ponder.mechanical_pump_speed.header": "Przepustowość mechanicznych pomp", - "create.ponder.mechanical_pump_speed.text_1": "Niezależnie od prędkości, mechaniczne pompy działają na odległość maksymalnie 16 bloków", - "create.ponder.mechanical_pump_speed.text_2": "Zwiększenie prędkości powoduje zwiększenie prędkości przepływu cieczy...", - "create.ponder.mechanical_pump_speed.text_3": "...jak i maksymalną przepustowość pompy", - "create.ponder.mechanical_pump_speed.text_4": "Pompy łączą swoją przepustowość w tym samemy systemie rur", - "create.ponder.mechanical_pump_speed.text_5": "Zmiana orientacji pompy pomoże w dostosowaniu kierunku przepływu", - - "create.ponder.mechanical_saw_breaker.header": "Ścinanie drzew z użyciem mechanicznej piły", - "create.ponder.mechanical_saw_breaker.text_1": "Po otrzymaniu siły obrotowej, mechaniczna piła zetnie każde znajdujące się przed nią drzewo", - "create.ponder.mechanical_saw_breaker.text_2": "Aby całkowicie ściąć drzewo, piła musi zniszczyć każdy blok łączący je z ziemią", - - "create.ponder.mechanical_saw_contraption.header": "Używanie mechanicznych pił w maszynach", - "create.ponder.mechanical_saw_contraption.text_1": "Kiedy piły są przesuwane razem z maszyną...", - "create.ponder.mechanical_saw_contraption.text_2": "…zetną one drzewa na ich drodze", - - "create.ponder.mechanical_saw_processing.header": "Obróbka przedmiotów z użyciem mechanicznej piły", - "create.ponder.mechanical_saw_processing.text_1": "Skierowana w górę mechaniczna piła może przetwarzać wiele różnych przedmiotów", - "create.ponder.mechanical_saw_processing.text_2": "Przerabiany przedmiot zawsze przesuwa się przeciwnie do kierunku obrotu piły", - "create.ponder.mechanical_saw_processing.text_3": "Piły mogą współpracować z taśmociągami", - "create.ponder.mechanical_saw_processing.text_4": "Slot filtrujący może być użyty w przypadku dwóch konfliktujących receptur", - "create.ponder.mechanical_saw_processing.text_5": "Bez ustawionego filtra, piła przejdzie przez wszystkie receptury po kolei", - - "create.ponder.millstone.header": "Obróbka przedmiotów w młynku", - "create.ponder.millstone.text_1": "Młynek przetwarza przedmioty mieląc je", - "create.ponder.millstone.text_2": "Może być wprawiony w ruch od boku z użyciem kół zębatych", - "create.ponder.millstone.text_3": "Wrzuć lub włóż przedmiot od góry", - "create.ponder.millstone.text_4": "Po jakimś czasie, produkty mogą być zabrane prawym kliknięciem", - "create.ponder.millstone.text_5": "…lub w zautomatyzowany sposób", - - "create.ponder.nixie_tube.header": "Używanie lamp cyfrowych", - "create.ponder.nixie_tube.text_1": "Kiedy zasilone, lampy cyfrowe wyświetlą siłę sygnału Redstone, jaki otrzymują", - "create.ponder.nixie_tube.text_2": "Używając znaczników i kowadła można wyświetlić własny tekst", - "create.ponder.nixie_tube.text_3": "Użyj barwników, aby zmienić kolor lampy", - - "create.ponder.piston_pole.header": "Przedłużenia tłoka", - "create.ponder.piston_pole.text_1": "Bez przyłączonych przedłużeń, mechaniczny tłok nie może się wysunąć", - "create.ponder.piston_pole.text_2": "Długość przedłużenia z tyłu ustala maksymalny zasięg tłoka", - - "create.ponder.portable_fluid_interface.header": "Przekazywanie cieczy z ruchomych maszyn do stojących bloków", - "create.ponder.portable_fluid_interface.text_1": "Zwyczajne rury nie mają dostępu do zbiorników z ruchomych maszyn", - "create.ponder.portable_fluid_interface.text_2": "Ten blok pozwala na transport cieczy bez potrzeby zatrzymywania maszyny", - "create.ponder.portable_fluid_interface.text_3": "Postaw drugi interfejs oddalony o 1 lub 2 bloki", - "create.ponder.portable_fluid_interface.text_4": "Kiedy będą blisko siebie, połączą się", - "create.ponder.portable_fluid_interface.text_5": "Po połączeniu, stacjonarny interfejs będzie reprezentował WSZYSTKIE zbiorniki w ruchomej maszynie", - "create.ponder.portable_fluid_interface.text_6": "Ciecz może od teraz być wpompowana...", - "create.ponder.portable_fluid_interface.text_7": "...lub wypompowania z maszyny", - "create.ponder.portable_fluid_interface.text_8": "W momencie, kiedy przed dłuższy czas żadne ciecze nie będą wymieniane, maszyna zostanie odłączona i będzie kontynuowała swoją pracę", - - "create.ponder.portable_storage_interface.header": "Używanie przenośnych interfejsów magazynu", - "create.ponder.portable_storage_interface.text_1": "Pojemniki na ruchomych maszynach nie mogą być otwarte przez gracza", - "create.ponder.portable_storage_interface.text_2": "Ten komponent może współpracować z zawartością maszyny bez potrzeby jej zatrzymywania", - "create.ponder.portable_storage_interface.text_3": "Postaw drugi w odstępie od 1 do 2 bloków", - "create.ponder.portable_storage_interface.text_4": "Kiedy będą blisko siebie połączą się", - "create.ponder.portable_storage_interface.text_5": "Kiedy są połączone, stojący interfejs będzie reprezentował wszystkie pojemniki znajdujące się na maszynie", - "create.ponder.portable_storage_interface.text_6": "Przedmioty mogą być wsadzone...", - "create.ponder.portable_storage_interface.text_7": "…lub wyciągnięte z maszyny", - "create.ponder.portable_storage_interface.text_8": "W momencie, kiedy przed dłuższy czas żadne przedmioty nie będą wymieniane, maszyna zostanie odłączona i będzie kontynuowała swoją pracę", - - "create.ponder.portable_storage_interface_redstone.header": "Kontrola Redstonem", - "create.ponder.portable_storage_interface_redstone.text_1": "Zasilenie Redstonem zapobiegnie połączeniu się interfejsów", - - "create.ponder.powered_latch.header": "Kontrola sygnału z użyciem zaawansowanego zasilanego przełącznika", - "create.ponder.powered_latch.text_1": "Zaawansowane zasilane przełączniki to dźwignie, które można kontrolować przez Redstone", - "create.ponder.powered_latch.text_2": "Sygnały otrzymane z tyłu włączają je...", - "create.ponder.powered_latch.text_3": "...a sygnały od boku wyłączają", - "create.ponder.powered_latch.text_4": "Zaawansowane zasilane przełączniki mogą też być przełączone ręcznie", - - "create.ponder.powered_toggle_latch.header": "Kontrola sygnału z użyciem zasilanego przełącznika", - "create.ponder.powered_toggle_latch.text_1": "Zasilane przełączniki to dźwignie, które można kontrolować przez Redstone", - "create.ponder.powered_toggle_latch.text_2": "Sygnały otrzymane z tyłu przełączają je", - "create.ponder.powered_toggle_latch.text_3": "włączone... wyłączone...", - "create.ponder.powered_toggle_latch.text_4": "Zasilane przełączniki mogą też być przełączone ręcznie", - - "create.ponder.pulse_extender.header": "Kontrolowanie sygnałów za pomocą przedłużaczy pulsów", - "create.ponder.pulse_extender.text_1": "Wydłużacze pulsów mogą przedłużyć sygnał który przez nie przechodzi", - "create.ponder.pulse_extender.text_2": "Aktywują się one z krótkim opóźnieniem...", - "create.ponder.pulse_extender.text_3": "...i schładzają się przez skonfigurowany czas", - "create.ponder.pulse_extender.text_4": "Czas rozładowania może być skonfigurowany używając kółka od myszy", - "create.ponder.pulse_extender.text_5": "Skonfigurowany czas może wynosić nawet 30 minut", - - "create.ponder.pulse_repeater.header": "Kontrola sygnału z użyciem przekaźników pulsowych", - "create.ponder.pulse_repeater.text_1": "Przekaźniki pulsowe skrócą dowolny sygnał do pojedynczego pulsu", - "create.ponder.pulse_repeater.text_2": "Czas ładowania może być skonfigurowany używając kółka od myszy", - "create.ponder.pulse_repeater.text_3": "Skonfigurowany czas może wynosić nawet 30 minut", - - "create.ponder.radial_chassis.header": "Przyłączanie bloków z użyciem stelaża promienistego", - "create.ponder.radial_chassis.text_1": "Stelaże promieniste łączą się z identycznymi stelażami w jednym rzędzie", - "create.ponder.radial_chassis.text_2": "Kiedy jeden z nich jest przesunięty, wszystkie inne również się przesuwają", - "create.ponder.radial_chassis.text_3": "Boczne ściany stelaży promienistych mogą zostać oblepione szlamem", - "create.ponder.radial_chassis.text_4": "Kliknij ponownie, aby oblepić wszystkie strony", - "create.ponder.radial_chassis.text_5": "Kliknij PPM skradając się, aby usunąć szlam", - "create.ponder.radial_chassis.text_6": "Lepkie strony zabiorą ze sobą przyczepione bloki...", - "create.ponder.radial_chassis.text_7": "...w określonym zasięgu", - "create.ponder.radial_chassis.text_8": "Użyj klucza, aby ustawić maksymalny zasięg działania stelaża", - "create.ponder.radial_chassis.text_9": "Bloki, które nie są w żaden sposób połączone z lepką stroną stelaża nie będą przesuwane", - - "create.ponder.redstone_contact.header": "Przełącznik kontaktowy", - "create.ponder.redstone_contact.text_1": "Przełączniki kontaktowe skierowane w swoją stronę będą emitować sygnał Redstone", - "create.ponder.redstone_contact.text_2": "Działa to też w momencie, kiedy jeden z nich jest częścią ruchomej maszyny", - - "create.ponder.redstone_link.header": "Używanie emiterów sygnału", - "create.ponder.redstone_link.text_1": "Emitery sygnału mogą przesyłać sygnał Redstone bezprzewodowo", - "create.ponder.redstone_link.text_2": "Kliknij PPM skradając się, aby przełączyć na tryb odbierania", - "create.ponder.redstone_link.text_3": "Prawe kliknięcie kluczek robi dokładnie to samo", - "create.ponder.redstone_link.text_4": "Odbiorniki emitują sygnał Redstone nadajników w zasięgu 128 bloków", - "create.ponder.redstone_link.text_5": "Wkładając przedmioty do dwóch slotów można sprecyzować częstotliwość", - "create.ponder.redstone_link.text_6": "Jedynie emitery z pasującymi częstotliwościami będą się ze sobą komunikować", - - "create.ponder.rope_pulley.header": "Przesuwanie struktur z użyciem krążków z liną", - "create.ponder.rope_pulley.text_1": "Krążki z liną mogę przesuwać pionowo bloki z wykorzystaniem siły obrotowej", - "create.ponder.rope_pulley.text_2": "Prędkość i kierunek ruchu zależą od dostarczonej siły obrotowej", - - "create.ponder.rope_pulley_attachment.header": "Przesuwanie krążków jako część maszyny", - "create.ponder.rope_pulley_attachment.text_1": "Kiedy krążek jest częścią ruchomej maszyny...", - "create.ponder.rope_pulley_attachment.text_2": "...przyczepiona do niego struktura również się przesunie", - "create.ponder.rope_pulley_attachment.text_3": "Pamiętaj, że krążki mogą pracować jedynie, jeśli same się nie poruszają", - - "create.ponder.rope_pulley_modes.header": "Tryby ruchu krążków z liną", - "create.ponder.rope_pulley_modes.text_1": "Kiedy krążek przestaje się obracać, przyczepiona do niego struktura staje się z powrotem blokami", - "create.ponder.rope_pulley_modes.text_2": "Można go skonfigurować, aby bloki nigdy nie stawały się stałymi, lub tylko w pozycji początkowej", - - "create.ponder.rose_quartz_lamp.header": "Lampy z różowego kwarcu", - "create.ponder.rose_quartz_lamp.text_1": "Lampy z różowego kwarcu aktywują się przy otrzymaniu sygnału redstone", - "create.ponder.rose_quartz_lamp.text_2": "Po czym będą one dalej wydzielać sygnał", - "create.ponder.rose_quartz_lamp.text_3": "Kiedy kilka lamp jest ustawionych w grupie...", - "create.ponder.rose_quartz_lamp.text_4": "...aktywowanie lampy skupi na niej sygnał, wyłączając wszystkie inne", - "create.ponder.rose_quartz_lamp.text_5": "Komparatory wydzielają sygnał na podstawie odległości do włączonej lampy", - "create.ponder.rose_quartz_lamp.text_6": "Lampy mogą być przełączone manualnie przy użyciu klucza", - - "create.ponder.rotation_speed_controller.header": "Używanie sterownika prędkości obrotu", - "create.ponder.rotation_speed_controller.text_1": "Sterownik prędkości obrotu może przekazywać siłę obrotową z jego osi do dużego koła zębatego ponad nim", - "create.ponder.rotation_speed_controller.text_2": "Patrząc się na jego bok i przewijając można dostosować wyjściową prędkość", - - "create.ponder.sail.header": "Konstruowanie wiatraków z użyciem żagli", - "create.ponder.sail.text_1": "Żagle to bloki przydatne do konstrukcji wiatraków", - "create.ponder.sail.text_2": "Przyłączą się one do innych bloków i żagli, bez potrzeby użycia Super Glue lub stelaży", - "create.ponder.sail.text_3": "Kliknij PPM trzymając barwnik, aby je pomalować", - "create.ponder.sail.text_4": "Kliknij PPM trzymając nożyce, aby usunąć żagiel i zostawić samą ramę", - - "create.ponder.sail_frame.header": "Konstrukcja wiatraków z użyciem ram żagla", - "create.ponder.sail_frame.text_1": "Ramy żagla to bloki przydatne do konstrukcji wiatraków", - "create.ponder.sail_frame.text_2": "Przyłączą się one do innych bloków i ram, bez potrzeby użycia Super Glue lub stelaży", - - "create.ponder.sequenced_gearshift.header": "Kontrolowanie prędkości obrotu z użyciem przekładników sekwencjonalnych", - "create.ponder.sequenced_gearshift.text_1": "Przekładniki sekwencjonalne przekazują obrót poprzez wyznaczoną listę instrukcji", - "create.ponder.sequenced_gearshift.text_2": "Kliknij PPM, aby otworzyć interfejs", - "create.ponder.sequenced_gearshift.text_3": "Kiedy zostanie zasilony Redstonem, rozpocznie wykonywać swoją ustaloną sekwencję", - "create.ponder.sequenced_gearshift.text_4": "Po zakończeniu, czeka na następny sygnał i zaczyna od nowa", - "create.ponder.sequenced_gearshift.text_5": "Komparator może być użyty do odczytania obecnego postępu", - - "create.ponder.shaft.header": "Przekazywanie siły obrotowej z użyciem wałów", - "create.ponder.shaft.text_1": "Wały przekazują siłę obrotową w linii prostej", - - "create.ponder.shaft_casing.header": "Izolowanie wałów", - "create.ponder.shaft_casing.text_1": "Mosiężna lub andezytowa obudowa może być użyta do udekorowania wałów", - - "create.ponder.smart_chute.header": "Sortowanie przedmiotów z użyciem inteligentnych zsypów", - "create.ponder.smart_chute.text_1": "Inteligentny zsyp to pionowy zsyp z dodatkową kontrolą", - "create.ponder.smart_chute.text_2": "Poprzez slot filtrujący można zdecydować, które przedmioty mogą być transportowane", - "create.ponder.smart_chute.text_3": "Użyj rolki w myszce, aby sprecyzować maksymalną wielkość stosu", - "create.ponder.smart_chute.text_4": "Sygnał Redstone zatrzyma działanie inteligentnych zsypów", - - "create.ponder.smart_pipe.header": "Kontrolowanie przepływu cieczy z użyciem inteligentnych rur", - "create.ponder.smart_pipe.text_1": "Inteligentne rury mogą pomóc kontrolować rodzaj przepływającej cieczy", - "create.ponder.smart_pipe.text_2": "Po postawieniu bezpośrednio przy źródle, można ustawić rodzaj cieczy, jaka będzie mogła być pobierana", - "create.ponder.smart_pipe.text_3": "Po prostu kliknij na filtr dowolnym przedmiotem zawierającym upragnioną ciecz", - "create.ponder.smart_pipe.text_4": "Kiedy postawiono dalej w systemie rur, inteligentne rury przepuszczą jedynie wybraną ciecz", - - "create.ponder.speedometer.header": "Monitorowanie prędkości obrotu z użyciem prędkościomierza", - "create.ponder.speedometer.text_1": "Prędkościomierz wyświetla obecną prędkość przyłączonych komponentów", - "create.ponder.speedometer.text_2": "Mając na sobie gogle inżyniera, gracz może pozyskać dodatkowe informacje z miernika", - "create.ponder.speedometer.text_3": "Komparatory mogą emitować sygnał Redstone bazując na pomiarach prędkościomierza", - - "create.ponder.spout_filling.header": "Napełnianie przedmiotów z użyciem napełniacza", - "create.ponder.spout_filling.text_1": "Napełniacz może napełnić niektóre przedmioty dostarczone poniżej", - "create.ponder.spout_filling.text_2": "Nie da się manualnie zabrać lub dostarczyć cieczy do napełniacza", - "create.ponder.spout_filling.text_3": "Zamiast tego, rury mogą zostać użyte, aby dostarczyć ciecze do napełniacza", - "create.ponder.spout_filling.text_4": "Przedmioty do napełnienia mogą zostać położone na składnicy pod napełniaczem", - "create.ponder.spout_filling.text_5": "Jeśli przedmioty znajdują się na taśmociągu...", - "create.ponder.spout_filling.text_6": "...napełniacz zatrzyma je i przetworzy - wszystko automatycznie", - - "create.ponder.stabilized_bearings.header": "Stabilizowanie maszyn", - "create.ponder.stabilized_bearings.text_1": "Kiedy łożyska mechaniczne są częścią ruchomej maszyny...", - "create.ponder.stabilized_bearings.text_2": "...będą utrzymywać swoją obrotową część w pozycji wyjściowej", - "create.ponder.stabilized_bearings.text_3": "Znowu, łożysko przyłączy do siebie bloki znajdujące się przed nim", - "create.ponder.stabilized_bearings.text_4": "Rezultatem tego będzie to, że pod-maszyna będzie utrzymywała się w tej samej pozycji", - - "create.ponder.steam_engine.header": "Konfigurowanie silników parowych", - "create.ponder.steam_engine.text_1": "Silniki parowe mogą zostać postawione na zbiornikach", - "create.ponder.steam_engine.text_10": "Stopień mocy: 4", - "create.ponder.steam_engine.text_11": "4 silniki", - "create.ponder.steam_engine.text_12": "Stopień mocy: 8", - "create.ponder.steam_engine.text_13": "8 silników", - "create.ponder.steam_engine.text_2": "Kliknięcie silnika wałem stworzy wyjście siły obrotowej", - "create.ponder.steam_engine.text_3": "Z wystarczającym ciepłem, wodą i miejscem w boilerze...", - "create.ponder.steam_engine.text_4": "...będą one generować siłe obrotową", - "create.ponder.steam_engine.text_5": "Minimalna konfiguracja potrzebuje 4 zbiorniki", - "create.ponder.steam_engine.text_6": "Z pomocą płomiennych palników, wyjście mocy może być zwiększone", - "create.ponder.steam_engine.text_7": "Wyższe stopnie mocy wymagają więcej wody, wielkości i ciepła", - "create.ponder.steam_engine.text_8": "Bieżący stopień mocy boilera może zostać sprawdzony przy pomocy gogli inżeyniera", - "create.ponder.steam_engine.text_9": "Z każdym dodanym stopniem mocy, dodatkowy silnik może działać z pełną mocą", - - "create.ponder.steam_whistle.header": "Konfigurowanie gwizdków parowych", - "create.ponder.steam_whistle.text_1": "Gwizdki parowe mogą zostać postawione na zbiornikach", - "create.ponder.steam_whistle.text_2": "Jeżeli zbiornik otrzyma wystarczająco ciepła...", - "create.ponder.steam_whistle.text_3": "...gwizdek zacznie wydobywać dźwięk podczas aktywacji", - "create.ponder.steam_whistle.text_4": "Użyj gwizdka jako przedmiot na bloku, aby obniżyć wysokość dźwięku", - "create.ponder.steam_whistle.text_5": "zmieniaj między trzema różnymi oktawami przy pomocy klucza", - "create.ponder.steam_whistle.text_6": "Gogle inżyniera pomogą przy sprawdzaniu bieżącej wysokości gwizdka", - - "create.ponder.sticker.header": "Przyczepianie bloków z użyciem przyklejacza", - "create.ponder.sticker.text_1": "Przyklejacze są idealne do kontrolowanego przez Redstone przyczepiania bloków", - "create.ponder.sticker.text_2": "Po otrzymaniu sygnału, zmieni on swoje ułożenie", - "create.ponder.sticker.text_3": "Jeśli jest przesunięty razem z maszyną, przyklejony blok również się przesunie", - "create.ponder.sticker.text_4": "Po ponownym zasileniu blok zostanie odczepiony", - - "create.ponder.stressometer.header": "Monitorowanie obciążenia z użyciem miernika obciążenia", - "create.ponder.stressometer.text_1": "Miernik obciążenia wyświetla odporność na obciążenie systemu, do którego jest podłączony", - "create.ponder.stressometer.text_2": "Mając na sobie gogle inżyniera, gracz może pozyskać dodatkowe informacje z miernika", - "create.ponder.stressometer.text_3": "Komparatory mogą emitować sygnał Redstone bazując na pomiarach miernika", - - "create.ponder.super_glue.header": "Przyklejanie bloków z użycie Super Glue", - "create.ponder.super_glue.text_1": "Super Glue może zostać użyty pomiędzy dwoma blokami", - "create.ponder.super_glue.text_2": "Przyklejone bloki będą przesuwane razem ze strukturą, do której są przyklejone", - "create.ponder.super_glue.text_3": "Kiedy Super Glue jest trzymany w drugiej ręce...", - "create.ponder.super_glue.text_4": "...stawiane bloki będą automatycznie przyklejane", - "create.ponder.super_glue.text_5": "Super Glue może zostać usunięty lewym kliknięciem", - "create.ponder.super_glue.text_6": "Bloki wiszące na innych generalnie nie potrzebują kleju", - - "create.ponder.track_chunks.header": "Przemierzanie niezaładowanych chunków", - "create.ponder.track_chunks.text_1": "Tory pozostaną funkcjonalne poza załadowanymi chunkami", - "create.ponder.track_chunks.text_2": "Pociągi będą podróżować przez nieaktywne sekcje świata bez problemu", - "create.ponder.track_chunks.text_3": "Będą się zatrzymywać na stacjach lub czerwonych sygnałach", - "create.ponder.track_chunks.text_4": "Jednak, wierła i inne maszyny na pokładzie nie będą działać", - "create.ponder.track_chunks.text_5": "Kiedy pociąg znajdzie się wystarczająco blisko gracza, pojawi się on spowrotem", - - "create.ponder.track_observer.header": "Wykrywanie pociągów", - "create.ponder.track_observer.text_1": "Zaznacz tor i postaw obok detektor kolejowy", - "create.ponder.track_observer.text_2": "Detektor będzie wykrywał pociągi przejeżdżające na torach", - "create.ponder.track_observer.text_3": "Detektory mogą zostać skonfigurowane, żeby aktywowały się jedynie przy pasującym ładunku", - - "create.ponder.track_placement.header": "Stawianie torów kolejowych", - "create.ponder.track_placement.text_1": "Nowy typ torów zaprojektowany dla maszyn kolejowych", - "create.ponder.track_placement.text_2": "Aby postawić rząd torów hurtowo, kliknij na istniejący tor", - "create.ponder.track_placement.text_3": "I postaw lub zaznacz kolejny tor", - "create.ponder.track_placement.text_4": "Tory mogą być również postawione jako zakręty lub nachylenia", - "create.ponder.track_placement.text_5": "Podczas łączenia, tory będą starały się zbudować każdy zakręt z równą wielkoścą", - "create.ponder.track_placement.text_6": "Trzymanie klawisza biegu podczas łączenia...", - "create.ponder.track_placement.text_7": "...zbuduje zamiast tego najdłuższy pasujący zakręt", - "create.ponder.track_placement.text_8": "Materiały w drugiej ręce będą automatycznie zbudowane pod torami jako podpory", - - "create.ponder.track_portal.header": "Tory i Nether", - "create.ponder.track_portal.text_1": "Tory postawione obok portalu do Netheru...", - "create.ponder.track_portal.text_2": "...spróbują zbudować odpowiadające im tory po drugiej stronie", - "create.ponder.track_portal.text_3": "Pociągi na tych torach mogą teraz podróżować między wymiarami", - - "create.ponder.train_assembly.header": "Montowanie pociągów", - "create.ponder.train_assembly.text_1": "Zaznacz tor kolejowy i postaw obok stację", - "create.ponder.train_assembly.text_10": "Każdy pociąg potrzebuje kontroler pociągów na pokładzie", - "create.ponder.train_assembly.text_11": "Opcjonalny drugi kontroler pozwala odjeżdżanie ze stacji w obu kierunkach", - "create.ponder.train_assembly.text_12": "Otwórz interfejs stacji i potwierdź proces montowania", - "create.ponder.train_assembly.text_13": "Pociągi mogą być rozmontowane spowrotem na bloki tylko na stacjach", - "create.ponder.train_assembly.text_14": "Kiedy użyte na stacji, mapy dodadzą podpisany znacznik w jej miejscu", - "create.ponder.train_assembly.text_15": "Zmontowane pociągi mogą być przeniesione na pobliskie tory za pomocą klucza", - "create.ponder.train_assembly.text_2": "Stacje są punktami orientacyjnymi Twojej sieci torów", - "create.ponder.train_assembly.text_3": "Aby stworzyć nowy pociąg, otówrz interfejs i przełącz na tryb montażu", - "create.ponder.train_assembly.text_4": "Podczas montażu, zaplanowane pociągi nie będą podjeżdżać do tej stacji", - "create.ponder.train_assembly.text_5": "Buduj nowe wózki używając obudów na torach", - "create.ponder.train_assembly.text_6": "Kliknij na tor ponownie, aby zmieniać styl wózków", - "create.ponder.train_assembly.text_7": "Przyczepiaj bloki przy pomocy Super Glue", - "create.ponder.train_assembly.text_8": "Zmontowane pociągi będą poruszać się szybciej jeżeli mogą znaleźć paliwo w przyczepionych skrzyniach lub beczkach", - "create.ponder.train_assembly.text_9": "Paliwo znajdujące się w kontenerach na przedmioty nie będzie używane przez pociągi", - - "create.ponder.train_controls.header": "Kontrolowanie pociągów", - "create.ponder.train_controls.text_1": "Kontroler pociągów jest wymagany na każdej maszynie kolejowej", - "create.ponder.train_controls.text_2": "Kiedy pociąg został zmontowany, kliknij PPM na kontroler aby zacząć kierować", - "create.ponder.train_controls.text_3": "Przyśpieszaj i kieruj pociągiem używając klawiszy ruchu", - "create.ponder.train_controls.text_4": "W razie potrzeby, maksymalna prędkość pociągu może zostać dostosowana przy pomocy kółka od myszy", - "create.ponder.train_controls.text_5": "Przytrzymaj Spację, aby podjechać do pobliskiej stacji", - "create.ponder.train_controls.text_6": "Pociągi mogą być rozmontowane spowrotem na bloki tylko na stacjach", - "create.ponder.train_controls.text_7": "Zmontowane gwizdki mogą być aktywowane przy pomocy klawisza biegu", - "create.ponder.train_controls.text_8": "Wciśnij klawisz skradania się lub kliknij drugi raz, aby przestać kontrolować pociąg", - - "create.ponder.train_schedule.header": "Używanie harmonogramów kolejowych", - "create.ponder.train_schedule.text_1": "Harmonogramy pozwalają na kontrolowanie pocągów przez innych kierowców", - "create.ponder.train_schedule.text_2": "Kliknij PPM z harmonogramem w ręce, aby otworzyć jego interfejs", - "create.ponder.train_schedule.text_3": "Kiedy zaprogramowany, harmonogram może być przekazany kierowcy pociągu", - "create.ponder.train_schedule.text_4": "Dowolny mob lub płomienny palnik siedzący przed kontrolerem pociągów nadaje się na konduktora", - "create.ponder.train_schedule.text_5": "Stworzenia na smyczach mogą być posadzone na siedzeniach w wygodniejszy sposób", - "create.ponder.train_schedule.text_6": "Harmonogramy mogą zostać odebrane od kierowców w dowolnej chwili", - - "create.ponder.train_signal_placement.header": "Stawianie sygnałów kolejowych", - "create.ponder.train_signal_placement.text_1": "Zaznacz tor kolejowy i postaw sygnał w pobliżu", - "create.ponder.train_signal_placement.text_2": "Sygnały kontrolują przebieg pociągów kierowanych automatycznie", - "create.ponder.train_signal_placement.text_3": "Zaplanowane pociągi nigdy nie przejadą przez sygnały w przeciwnym kierunku", - "create.ponder.train_signal_placement.text_4": "...chyba że postawiony jest drugi sygnał w przeciwnym kierunku", - "create.ponder.train_signal_placement.text_5": "Lampy cyfrowe mogą zostać przyczepione, aby światło sygnału stało się lepiej widoczne", - - "create.ponder.train_signal_redstone.header": "Sygnały i redstone", - "create.ponder.train_signal_redstone.text_1": "Czerwone światło może być wymuszone poprzez zasilenie sygnału", - "create.ponder.train_signal_redstone.text_2": "Odwrotnie, czerwone światło emituje wyjście komparatora", - - "create.ponder.train_signal_signaling.header": "Zapobieganie kolizji za pomocą sygnałów", - "create.ponder.train_signal_signaling.text_1": "Sygnały kolejowe dzielą tory na segmenty", - "create.ponder.train_signal_signaling.text_2": "Jeżeli segment jest zajęty, żaden inny pociąg nie będzie mógł na niego wjechać", - "create.ponder.train_signal_signaling.text_3": "Zatem, każdy segment będzie miał na sobie tylko jeden pociąg", - "create.ponder.train_signal_signaling.text_4": "Drugi tryb sygnału jest dostępny przy użyciu klucza", - "create.ponder.train_signal_signaling.text_5": "Segmenty mosiężnego sygnału zwykle prowadzą do zwyczajnego sygnału", - "create.ponder.train_signal_signaling.text_6": "Ten specjalny sygnał może zatrzymywać pociągi pod drugim warunkiem", - "create.ponder.train_signal_signaling.text_7": "Zatrzyma pociągi, które przy wjechaniu...", - "create.ponder.train_signal_signaling.text_8": "...nie mogłyby natychmiastowo opuścić segmentu", - "create.ponder.train_signal_signaling.text_9": "Pomaga to w powstrzymaniu pociągów w kolejce od wjeżdżania na zajęty segment", - - "create.ponder.valve_handle.header": "Generowanie siły obrotowej z użyciem pokręteł", - "create.ponder.valve_handle.text_1": "Pokrętła mogą być użyte, aby ręcznie wytworzyć siłę obrotową bezpośrednio w miejscu postawienia", - "create.ponder.valve_handle.text_2": "Trzymaj PPM, aby obrócić ją odwrotnie niż wskazówki zegara", - "create.ponder.valve_handle.text_3": "Wytwarzana prędkość jest niewielka, ale pozwala na dokładny obrót", - "create.ponder.valve_handle.text_4": "Trzymaj PPM skradając się, aby obrócić ją zgodnie ze wskazówkami zegara", - "create.ponder.valve_handle.text_5": "Pokrętła mogą być zabarwione dla celów dekoracyjnych", - - "create.ponder.valve_pipe.header": "Kontrolowanie przepływu cieczy z użyciem zaworów", - "create.ponder.valve_pipe.text_1": "Zawory mogą pomóc w kontroli przepływu cieczy przez system rur", - "create.ponder.valve_pipe.text_2": "Ich wał, przy obrocie, zmienia, czy ciecz może przepływać, czy nie", - "create.ponder.valve_pipe.text_3": "Obracając wał w kierunku, w którym płynie ciecz, otworzy zawór", - "create.ponder.valve_pipe.text_4": "Może być spowrotem zamknięty odwracając kierunek obrotu", - - "create.ponder.water_wheel.header": "Generowanie siły obrotowej z użyciem kół wodnych", - "create.ponder.water_wheel.text_1": "Koła wodne pobierają energię z prądów wodnych", - "create.ponder.water_wheel.text_2": "Im więcej stron ma dostęp do wody, tym szybciej koło się będzie obracać", - "create.ponder.water_wheel.text_3": "Łopaty koła wodnego powinny być zorientowane przeciwnie do prądu", - "create.ponder.water_wheel.text_4": "Będąc zorientowane z prądem nie będą zbyt efektywne", - - "create.ponder.weighted_ejector.header": "Używanie wyrzutni odważnikowych", - "create.ponder.weighted_ejector.text_1": "Kliknij PPM skradając się i mając w ręce wyrzutnię, aby wybrać jego cel", - "create.ponder.weighted_ejector.text_10": "Od teraz aktywuje się tylko w momencie, jeśli wystarczająca ilość przedmiotów znajdzie się na jego wierzchu", - "create.ponder.weighted_ejector.text_11": "Inne moby zawsze zostaną wyrzucone", - "create.ponder.weighted_ejector.text_2": "Postawiona wyrzutnia będzie strzelała przedmiotami w wybrane miejsce", - "create.ponder.weighted_ejector.text_3": "Cel może być na dowolnej wysokości i odległości w zasięgu wyrzutni", - "create.ponder.weighted_ejector.text_4": "Nie mogą być jednak przesunięte w bok", - "create.ponder.weighted_ejector.text_5": "Jeśli nie wybrano żadnego celu, wyrzuci ona przedmioty na blok bezpośrednio przed sobą", - "create.ponder.weighted_ejector.text_6": "Dostarcz siłę obrotową, aby ją załadować", - "create.ponder.weighted_ejector.text_7": "Przedmioty znajdujące się na jej wierzchu aktywują ją", - "create.ponder.weighted_ejector.text_8": "Jeśli celem jest blok mogący przechowywać przedmioty, wyrzutnia poczeka aż będzie tam miejsce", - "create.ponder.weighted_ejector.text_9": "Używając klucza można wybrać wielkość stosu, jaki ma być wyrzucony", - - "create.ponder.weighted_ejector_redstone.header": "Kontrolowanie wyrzutni odważnikowych z użyciem Redstone'a", - "create.ponder.weighted_ejector_redstone.text_1": "Zasilona Redstonem, wyrzutnia nie aktywuje się", - "create.ponder.weighted_ejector_redstone.text_2": "Ponad to, detektory mogą wykrywać, kiedy wyrzutnia się aktywuje", - - "create.ponder.weighted_ejector_tunnel.header": "Rozdzielanie stosów z użyciem wyrzutni odważnikowych", - "create.ponder.weighted_ejector_tunnel.text_1": "W połączeniu z mosiężnymi tunelami, wyrzutnie mogą", - "create.ponder.weighted_ejector_tunnel.text_2": "Po pierwsze, ustaw tunel na tryb 'Preferuj najbliższy', aby zpriorytetyzować boczne wyjście", - "create.ponder.weighted_ejector_tunnel.text_3": "Wielkość stosu ustawiona na wyrzutni ustala ilość, jaka ma być oddzielona", - "create.ponder.weighted_ejector_tunnel.text_4": "W momencie, kiedy stos o określonym rozmiarze opuści tunel...", - "create.ponder.weighted_ejector_tunnel.text_5": "...pozostała część będzie kontynuować swoją podróż", - - "create.ponder.windmill_source.header": "Generowanie siły obrotowej z użyciem łożysk wiatraka", - "create.ponder.windmill_source.text_1": "Łożysko wiatraka przyczepia do siebie bloki, które znajdują się przed nimi", - "create.ponder.windmill_source.text_2": "Jeśli wystarczająco żaglo-podobnych bloków jest przyłączonych do niego, może działać jak wiatrak", - "create.ponder.windmill_source.text_3": "Po aktywacji prawym kliknięciem, łożysko wiatraka zacznie generować siłę obrotową", - "create.ponder.windmill_source.text_4": "Ilość żagli ustala prędkość obrotu", - "create.ponder.windmill_source.text_5": "Użyj klucza, aby dostosować kierunek obrotu", - "create.ponder.windmill_source.text_6": "Kliknij PPM na łożysko, aby zatrzymać obrót i zmodyfikować dołączoną strukturę", - "create.ponder.windmill_source.text_7": "Możesz kliknąć na łożysko w każdej chwili, aby je zatrzymać i zedytować przyczepioną budowlę", - - "create.ponder.windmill_structure.header": "Wiatraki", - "create.ponder.windmill_structure.text_1": "Każda struktura jest uznawana za wiatrak w momencie, kiedy ma w sobie co najmniej 8 żaglo-podobnych bloków", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json deleted file mode 100644 index 74fc79f704..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 1312", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Janela de Acácia", - "block.create.acacia_window_pane": "Vidraça de Acácia", - "block.create.adjustable_chain_gearshift": "Correia Ajustável", - "block.create.analog_lever": "Alavanca Analógica", - "block.create.andesite_belt_funnel": "Funil de Esteira de Andesito", - "block.create.andesite_casing": "Revestimento de Andesito", - "block.create.andesite_encased_cogwheel": "Roda dentada revestida com andesito", - "block.create.andesite_encased_large_cogwheel": "Roda dentada grande revestida com andesito", - "block.create.andesite_encased_shaft": "Eixo revestido com latão", - "block.create.andesite_funnel": "Funil de Andesito", - "block.create.andesite_ladder": "Escada de mão de andesito", - "block.create.andesite_pillar": "Pilar de andesito", - "block.create.andesite_tunnel": "Tunel de Andesito", - "block.create.asurine": "Asurino", - "block.create.asurine_pillar": "Pilar de Asurino", - "block.create.basin": "Bacia", - "block.create.belt": "Esteira Mecânica", - "block.create.birch_window": "Janela de Bétula", - "block.create.birch_window_pane": "Vidraça de Bétula", - "block.create.black_nixie_tube": "Tubo nixie preto", - "block.create.black_sail": "Vela preta", - "block.create.black_seat": "Assento preto", - "block.create.black_toolbox": "Caixa de ferramentas preta", - "block.create.black_valve_handle": "Válvula preta", - "block.create.blaze_burner": "Queimador de blaze", - "block.create.blue_nixie_tube": "Tubo nixie azul", - "block.create.blue_sail": "Vela azul", - "block.create.blue_seat": "Assento azul", - "block.create.blue_toolbox": "Caixa de ferramentas azul", - "block.create.blue_valve_handle": "Válvula azul", - "block.create.brass_belt_funnel": "Funil de Esteira de Latão", - "block.create.brass_block": "Bloco de Latão", - "block.create.brass_casing": "Revestimento de Latão", - "block.create.brass_encased_cogwheel": "Roda dentada revestida com latão", - "block.create.brass_encased_large_cogwheel": "Roda dentada grande revestida com latão", - "block.create.brass_encased_shaft": "Eixo Revestido com Latão", - "block.create.brass_funnel": "Funil de Latão", - "block.create.brass_ladder": "Escada de mão de latão", - "block.create.brass_tunnel": "Tunel de Latão", - "block.create.brown_nixie_tube": "Tubo de nixie marrom", - "block.create.brown_sail": "Vela marrom", - "block.create.brown_seat": "Assento marrom", - "block.create.brown_toolbox": "Caixa de ferramentas marrom", - "block.create.brown_valve_handle": "Válvula marrom", - "block.create.calcite_pillar": "Pilar de Calcita", - "block.create.cart_assembler": "Montador de Carrinho de Mina", - "block.create.chocolate": "Chocolate", - "block.create.chute": "Calha", - "block.create.clockwork_bearing": "Rolamento de relôgio", - "block.create.clutch": "Embreagem", - "block.create.cogwheel": "Roda Dentada", - "block.create.content_observer": "Observador de Conteúdo", - "block.create.controller_rail": "Trilho Controlador", - "block.create.controls": "Controles do trem", - "block.create.copper_backtank": "Tanque Traseiro de Cobre", - "block.create.copper_casing": "Revestimento de Cobre", - "block.create.copper_ladder": "Escada de mão de cobre", - "block.create.copper_shingle_slab": "Laje de telha de cobre", - "block.create.copper_shingle_stairs": "Escada de telha de cobre", - "block.create.copper_shingles": "Telha de cobre", - "block.create.copper_tile_slab": "Laje de ladrilho de cobre", - "block.create.copper_tile_stairs": "Escada de ladrilho de cobre", - "block.create.copper_tiles": "Ladrilho de cobre", - "block.create.copper_valve_handle": "Válvula de Cobre", - "block.create.creative_crate": "Caixa Criativa", - "block.create.creative_fluid_tank": "Tanque de Fluidos Criativo", - "block.create.creative_motor": "Motor Criativo", - "block.create.crimsite": "Carmesito", - "block.create.crimsite_pillar": "Pilar de Camesito", - "block.create.crimson_window": "Janela carmesim", - "block.create.crimson_window_pane": "Vidraça carmesim", - "block.create.crushing_wheel": "Roda de Moer", - "block.create.crushing_wheel_controller": "Controlador da roda de moer", - "block.create.cuckoo_clock": "Relógio Cuckoo", - "block.create.cut_andesite": "Andesito lapidado", - "block.create.cut_andesite_brick_slab": "Laje de tijolos lapidados de andesito", - "block.create.cut_andesite_brick_stairs": "Escada de tijolos lapidados de andesito", - "block.create.cut_andesite_brick_wall": "Muro de tijolos lapidados de andesito", - "block.create.cut_andesite_bricks": "Tijolos lapidados de andesito", - "block.create.cut_andesite_slab": "Laje de andesito lapidado", - "block.create.cut_andesite_stairs": "Escada de andesito lapidado", - "block.create.cut_andesite_wall": "Muro de andesito lapidado", - "block.create.cut_asurine": "Asurino lapidado", - "block.create.cut_asurine_brick_slab": "Laje de tijolos lapidados de Asurino", - "block.create.cut_asurine_brick_stairs": "Escada de tijolos lapidados de Asurino", - "block.create.cut_asurine_brick_wall": "Muro de tijolos lapidados de Asurino", - "block.create.cut_asurine_bricks": "Tijolos lapidados de Asurino", - "block.create.cut_asurine_slab": "Laje de Asurino lapidado", - "block.create.cut_asurine_stairs": "Escada de Asurino lapidado", - "block.create.cut_asurine_wall": "Muro de Asurino lapidado", - "block.create.cut_calcite": "Calcita lapidada", - "block.create.cut_calcite_brick_slab": "Laje de tijolos lapidados de Calcita", - "block.create.cut_calcite_brick_stairs": "Escada de tijolos lapidados de Calcita", - "block.create.cut_calcite_brick_wall": "Muro de tijolos lapidados de Calcita", - "block.create.cut_calcite_bricks": "Tijolos lapidados de Calcita", - "block.create.cut_calcite_slab": "Laje de Calcita lapidada", - "block.create.cut_calcite_stairs": "Escada de Calcita lapidada", - "block.create.cut_calcite_wall": "Muro de Calcita lapidada", - "block.create.cut_crimsite": "Carmesito lapidado", - "block.create.cut_crimsite_brick_slab": "Laje de tijolos lapidados de Carmesito", - "block.create.cut_crimsite_brick_stairs": "Escada de tijolos lapidados de Carmesito", - "block.create.cut_crimsite_brick_wall": "Muro de tijolos lapidados de Carmesito", - "block.create.cut_crimsite_bricks": "Tijolos lapidados de Carmesito", - "block.create.cut_crimsite_slab": "Laje de Carmesito lapidado", - "block.create.cut_crimsite_stairs": "Escada de Carmesito lapidado", - "block.create.cut_crimsite_wall": "Muro de Carmesito lapidado", - "block.create.cut_deepslate": "Ardósia lapidada", - "block.create.cut_deepslate_brick_slab": "Laje de tijolos lapidados de ardósia", - "block.create.cut_deepslate_brick_stairs": "Escada de tijolos lapidados de ardósia", - "block.create.cut_deepslate_brick_wall": "Muro de tijolos lapidados de ardósia", - "block.create.cut_deepslate_bricks": "Tijolos lapidados de ardósia", - "block.create.cut_deepslate_slab": "Laje de ardósia lapidada", - "block.create.cut_deepslate_stairs": "Escada de ardósia lapidada", - "block.create.cut_deepslate_wall": "Muro de ardósia lapidada", - "block.create.cut_diorite": "Diorito lapidado", - "block.create.cut_diorite_brick_slab": "Laje de tijolos lapidados de diorito", - "block.create.cut_diorite_brick_stairs": "Escada de tijolos lapidados de diorito", - "block.create.cut_diorite_brick_wall": "Muro de tijolos lapidados de diorito", - "block.create.cut_diorite_bricks": "Tijolos lapidados de diorito", - "block.create.cut_diorite_slab": "Laje de diorito lapidado", - "block.create.cut_diorite_stairs": "Escada de diorito lapidado", - "block.create.cut_diorite_wall": "Muro de diorito lapidado", - "block.create.cut_dripstone": "Espeleotema lapidado", - "block.create.cut_dripstone_brick_slab": "Laje de tijolos lapidados de espeleotema", - "block.create.cut_dripstone_brick_stairs": "Escada de tijolos lapidados de espeleotema", - "block.create.cut_dripstone_brick_wall": "Muro de tijolos lapidados de espeleotema", - "block.create.cut_dripstone_bricks": "Tijolos lapidados de espeleotema", - "block.create.cut_dripstone_slab": "Laje de espeleotema lapidado", - "block.create.cut_dripstone_stairs": "Escada de espeleotema lapidado", - "block.create.cut_dripstone_wall": "Muro de espeleotema lapidado", - "block.create.cut_granite": "Granito lapidado", - "block.create.cut_granite_brick_slab": "Laje de tijolos lapidados de granito", - "block.create.cut_granite_brick_stairs": "Escada de tijolos lapidados de granito", - "block.create.cut_granite_brick_wall": "Muro de tijolos lapidados de granito", - "block.create.cut_granite_bricks": "Tijolos lapidados de granito", - "block.create.cut_granite_slab": "Laje de granito lapidado", - "block.create.cut_granite_stairs": "Escada de granito lapidado", - "block.create.cut_granite_wall": "Muro de granito lapidado", - "block.create.cut_limestone": "Calcário lapidado", - "block.create.cut_limestone_brick_slab": "Laje de tijolos lapidados de calcário", - "block.create.cut_limestone_brick_stairs": "Escada de tijolos lapidados de calcário", - "block.create.cut_limestone_brick_wall": "Muro de tijolos lapidados de calcário", - "block.create.cut_limestone_bricks": "Tijolos lapidados de calcário", - "block.create.cut_limestone_slab": "Laje de calcário lapidado", - "block.create.cut_limestone_stairs": "Escada de calcário lapidado", - "block.create.cut_limestone_wall": "Muro de calcário lapidado", - "block.create.cut_ochrum": "Ocrom", - "block.create.cut_ochrum_brick_slab": "Laje de tijolos lapidados de Ocrom", - "block.create.cut_ochrum_brick_stairs": "Escada de tijolos lapidados de Ocrom", - "block.create.cut_ochrum_brick_wall": "Muro de tijolos lapidados de Ocrom", - "block.create.cut_ochrum_bricks": "Tijolos lapidados de Ocrom", - "block.create.cut_ochrum_slab": "Laje de Ocrom lapidado", - "block.create.cut_ochrum_stairs": "Escada de Ocrom lapidado", - "block.create.cut_ochrum_wall": "Muro de Ocrom lapidado", - "block.create.cut_scorchia": "Escória negra lapidada", - "block.create.cut_scorchia_brick_slab": "Laje de tijolos lapidados de escória negra", - "block.create.cut_scorchia_brick_stairs": "Escada de tijolos lapidados de escória negra", - "block.create.cut_scorchia_brick_wall": "Muro de tijolos lapidados de escória negra", - "block.create.cut_scorchia_bricks": "Tijolos lapidados de escória negra", - "block.create.cut_scorchia_slab": "Laje de escória negra lapidada", - "block.create.cut_scorchia_stairs": "Escada de escória negra lapidada", - "block.create.cut_scorchia_wall": "Muro de escória negra lapidada", - "block.create.cut_scoria": "Escória lapidada", - "block.create.cut_scoria_brick_slab": "Laje de tijolos lapidados de escória", - "block.create.cut_scoria_brick_stairs": "Escada de tijolos lapidados de escória", - "block.create.cut_scoria_brick_wall": "Muro de tijolos lapidados de escória", - "block.create.cut_scoria_bricks": "Tijolos lapidados de escória", - "block.create.cut_scoria_slab": "Laje de escória lapidada", - "block.create.cut_scoria_stairs": "Escada de escória lapidada", - "block.create.cut_scoria_wall": "Muro de escória lapidada", - "block.create.cut_tuff": "Tufo lapidado", - "block.create.cut_tuff_brick_slab": "Laje de tijolos lapidados de tufo", - "block.create.cut_tuff_brick_stairs": "Escada de tijolos lapidados de tufo", - "block.create.cut_tuff_brick_wall": "Muro de tijolos lapidados de tufo", - "block.create.cut_tuff_bricks": "Tijolos lapidados de tufo", - "block.create.cut_tuff_slab": "Laje de tufo lapidado", - "block.create.cut_tuff_stairs": "Escada de tufo lapidado", - "block.create.cut_tuff_wall": "Muro de tufo lapidado", - "block.create.cut_veridium": "Veridiano lapidado", - "block.create.cut_veridium_brick_slab": "Laje de tijolos lapidados de Veridiano", - "block.create.cut_veridium_brick_stairs": "Escada de tijolos lapidados de Veridiano", - "block.create.cut_veridium_brick_wall": "Muro de tijolos lapidados de Veridiano", - "block.create.cut_veridium_bricks": "Tijolos lapidados de Veridiano", - "block.create.cut_veridium_slab": "Laje de Veridiano lapidado", - "block.create.cut_veridium_stairs": "Escada de Veridiano lapidado", - "block.create.cut_veridium_wall": "Muro de Veridiano lapidado", - "block.create.cyan_nixie_tube": "Tubo nixie ciano", - "block.create.cyan_sail": "Vela ciano", - "block.create.cyan_seat": "Assento ciano", - "block.create.cyan_toolbox": "caixa de ferramentas ciano", - "block.create.cyan_valve_handle": "Válvula ciano", - "block.create.dark_oak_window": "Janela de carvalho escuro", - "block.create.dark_oak_window_pane": "Vidraça de carvalho escuro", - "block.create.deepslate_pillar": "Pilar de ardósia", - "block.create.deepslate_zinc_ore": "Minério de zinco de ardósia", - "block.create.deployer": "Implantador", - "block.create.depot": "Depósito", - "block.create.diorite_pillar": "Pilar de diorito", - "block.create.display_board": "Placa de exibição", - "block.create.display_link": "Conexão de placa de exibição", - "block.create.dripstone_pillar": "Pilar de espeleotema", - "block.create.encased_chain_drive": "Correia Revestida", - "block.create.encased_fan": "Ventilador Revestida", - "block.create.encased_fluid_pipe": "Cano de Fluidos Revestido", - "block.create.exposed_copper_shingle_slab": "Laje de telha de cobre exposta", - "block.create.exposed_copper_shingle_stairs": "Escada de telha de cobre exposta", - "block.create.exposed_copper_shingles": "Telha de cobre exposta", - "block.create.exposed_copper_tile_slab": "Laje de ladrilho de cobre exposta", - "block.create.exposed_copper_tile_stairs": "Escada de ladrilho de cobre exposta", - "block.create.exposed_copper_tiles": "Ladrilho de cobre exposto", - "block.create.fake_track": "Marcador de trilhos para mapa", - "block.create.fluid_pipe": "Cano de Fluido", - "block.create.fluid_tank": "Tanque de fluido", - "block.create.fluid_valve": "Válvula", - "block.create.flywheel": "Volante de inércia", - "block.create.framed_glass": "Vidro emoldurado", - "block.create.framed_glass_door": "Porta de vidro emoldurado", - "block.create.framed_glass_pane": "Vidraça emoldurada", - "block.create.framed_glass_trapdoor": "Alçapão de vidro emoldurado", - "block.create.gantry_carriage": "Carruagem de Pórtico", - "block.create.gantry_shaft": "Eixo de Pórtico", - "block.create.gearbox": "Caixa de Transmissão", - "block.create.gearshift": "Câmbio", - "block.create.glass_fluid_pipe": "Cano de Fluido de Vidro", - "block.create.granite_pillar": "Pilar de granito", - "block.create.gray_nixie_tube": "Tubo nixie cinza", - "block.create.gray_sail": "Vela cinza", - "block.create.gray_seat": "Assento cinza", - "block.create.gray_toolbox": "Caixa de ferramentas cinza", - "block.create.gray_valve_handle": "Válvula cinza", - "block.create.green_nixie_tube": "Tubo nixie verde", - "block.create.green_sail": "Vela verde", - "block.create.green_seat": "Assento verde", - "block.create.green_toolbox": "Caixa de ferramentas verde", - "block.create.green_valve_handle": "Válvula verde", - "block.create.hand_crank": "Manivela", - "block.create.haunted_bell": "Sino assombrado", - "block.create.honey": "Mel", - "block.create.horizontal_framed_glass": "Vidro emoldurado horizontal", - "block.create.horizontal_framed_glass_pane": "Vidraça emoldurada horizontal", - "block.create.hose_pulley": "Polia de Mangueira", - "block.create.item_drain": "Dreno de Item", - "block.create.item_vault": "Cofre de itens", - "block.create.jungle_window": "Janela da selva", - "block.create.jungle_window_pane": "Vidraça da selva", - "block.create.large_bogey": "Roda grande do trem", - "block.create.large_cogwheel": "Roda dentada grande", - "block.create.layered_andesite": "Andesito estratificado", - "block.create.layered_asurine": "Asurino estratificado", - "block.create.layered_calcite": "Calcita estratificada", - "block.create.layered_crimsite": "Carmesito estratificado", - "block.create.layered_deepslate": "Ardósia estratificado", - "block.create.layered_diorite": "Diorito estratificado", - "block.create.layered_dripstone": "Espeleotema estratificado", - "block.create.layered_granite": "Granito estratificado", - "block.create.layered_limestone": "Calcário estratificado", - "block.create.layered_ochrum": "Ocrom estratificado", - "block.create.layered_scorchia": "Escória negra estratificada", - "block.create.layered_scoria": "Escória estratificada", - "block.create.layered_tuff": "Tufo estratificado", - "block.create.layered_veridium": "Veridiano estratificado", - "block.create.lectern_controller": "Controle de Atril", - "block.create.light_blue_nixie_tube": "tubo nixie azul claro", - "block.create.light_blue_sail": "Vela azul claro", - "block.create.light_blue_seat": "Assento azul claro", - "block.create.light_blue_toolbox": "Caixa de ferramentas azul claro", - "block.create.light_blue_valve_handle": "válvula azul claro", - "block.create.light_gray_nixie_tube": "Tubo nixie azul claro", - "block.create.light_gray_sail": "Vela cinza claro", - "block.create.light_gray_seat": "Assento cinza claro", - "block.create.light_gray_toolbox": "Caixa de ferramentas cinza claro", - "block.create.light_gray_valve_handle": "Válvula cinza claro", - "block.create.lime_nixie_tube": "Tubo nixie cinza claro", - "block.create.lime_sail": "Vela lima", - "block.create.lime_seat": "Assento lima", - "block.create.lime_toolbox": "Caixa de ferramentas lima", - "block.create.lime_valve_handle": "Válvula lima", - "block.create.limestone": "Calcário", - "block.create.limestone_pillar": "Pilar de Calcário", - "block.create.linear_chassis": "Chassis Linear", - "block.create.lit_blaze_burner": "Queimador de Blaze Acesso", - "block.create.magenta_nixie_tube": "Tubo nixie magenta", - "block.create.magenta_sail": "Vela magenta", - "block.create.magenta_seat": "Assento magenta", - "block.create.magenta_toolbox": "Caixa de ferramentas magenta", - "block.create.magenta_valve_handle": "Válvula magenta", - "block.create.mechanical_arm": "Braço mecânico", - "block.create.mechanical_bearing": "Rolamento mecânico", - "block.create.mechanical_crafter": "Fabricador mecânico", - "block.create.mechanical_drill": "Broca Mecânica", - "block.create.mechanical_harvester": "Coletor Mecânico", - "block.create.mechanical_mixer": "Batedeira mecânica", - "block.create.mechanical_piston": "Pistão Mecânico", - "block.create.mechanical_piston_head": "Cabeça do Pistão Mecânico", - "block.create.mechanical_plough": "Arador Mecânico", - "block.create.mechanical_press": "Prensa Mecânica", - "block.create.mechanical_pump": "Bomba Mecânica", - "block.create.mechanical_saw": "Serra Mecânica", - "block.create.metal_bracket": "Suporte de metal", - "block.create.metal_girder": "Viga de metal", - "block.create.metal_girder_encased_shaft": "Eixo revestido com viga de metal", - "block.create.millstone": "Pedra de Moer", - "block.create.minecart_anchor": "Ancóra de carrinho de Mina", - "block.create.mysterious_cuckoo_clock": "Relógio cuckoo", - "block.create.nixie_tube": "Tubo Nixie", - "block.create.nozzle": "Bocal", - "block.create.oak_window": "janela de carvalho", - "block.create.oak_window_pane": "Vidraça de carvalho", - "block.create.ochrum": "Ocrom", - "block.create.ochrum_pillar": "Pilar de Ocrom", - "block.create.orange_sail": "Vela laranja", - "block.create.orange_seat": "Assento laranja", - "block.create.orange_toolbox": "Caixa de ferramentas laranja", - "block.create.orange_valve_handle": "Válvula laranja", - "block.create.ornate_iron_window": "Janela ornamentada com ferro", - "block.create.ornate_iron_window_pane": "Vidraça ornamentada com ferro", - "block.create.oxidized_copper_shingle_slab": "Laje de telha de cobre oxidada", - "block.create.oxidized_copper_shingle_stairs": "Escada de telha de cobre oxidada", - "block.create.oxidized_copper_shingles": "Telha de cobre oxidada", - "block.create.oxidized_copper_tile_slab": "Laje de ladrilho de cobre oxidado", - "block.create.oxidized_copper_tile_stairs": "Escada de ladrilho de cobre oxidado", - "block.create.oxidized_copper_tiles": "Ladrilho de cobre oxidado", - "block.create.peculiar_bell": "Sino peculiar", - "block.create.pink_nixie_tube": "Tubo nixie rosa", - "block.create.pink_sail": "Vela rosa", - "block.create.pink_seat": "Assento rosa", - "block.create.pink_toolbox": "Caixa de ferramentas rosa", - "block.create.pink_valve_handle": "Válvula rosa", - "block.create.piston_extension_pole": "Vara de Extensão do Pistão", - "block.create.placard": "Cartaz", - "block.create.polished_cut_andesite": "Andesito lapidado polido", - "block.create.polished_cut_andesite_slab": "Laje de andesito lapidado polido", - "block.create.polished_cut_andesite_stairs": "Escada de andesito lapidado polido", - "block.create.polished_cut_andesite_wall": "Muro de andesito lapidado polido", - "block.create.polished_cut_asurine": "Asurino lapidado polido", - "block.create.polished_cut_asurine_slab": "Laje de Asurino lapidado polido", - "block.create.polished_cut_asurine_stairs": "Escada de Asurino lapidado polido", - "block.create.polished_cut_asurine_wall": "Muro de Asurino lapidado polido", - "block.create.polished_cut_calcite": "Calcita lapidada polida", - "block.create.polished_cut_calcite_slab": "Laje de calcita lapidada polida", - "block.create.polished_cut_calcite_stairs": "Escada de calcita lapidada polida", - "block.create.polished_cut_calcite_wall": "Muro de calcita lapidada polida", - "block.create.polished_cut_crimsite": "Carmesito lapidado polido", - "block.create.polished_cut_crimsite_slab": "Laje de Carmesito lapidado polido", - "block.create.polished_cut_crimsite_stairs": "Escada de Carmesito lapidado polido", - "block.create.polished_cut_crimsite_wall": "Muro de Carmesito lapidado polido", - "block.create.polished_cut_deepslate": "Ardósia lapidado polido", - "block.create.polished_cut_deepslate_slab": "Laje de ardósia lapidado polido", - "block.create.polished_cut_deepslate_stairs": "Escada de ardósia lapidado polido", - "block.create.polished_cut_deepslate_wall": "Muro de ardósia lapidado polido", - "block.create.polished_cut_diorite": "Diorito lapidado polido", - "block.create.polished_cut_diorite_slab": "Laje de diorito lapidado polido", - "block.create.polished_cut_diorite_stairs": "Escada de diorito lapidado polido", - "block.create.polished_cut_diorite_wall": "Muro de diorito lapidado polido", - "block.create.polished_cut_dripstone": "Espeleotema lapidado polido", - "block.create.polished_cut_dripstone_slab": "Laje de espeleotema lapidado polido", - "block.create.polished_cut_dripstone_stairs": "Escada de espeleotema lapidado polido", - "block.create.polished_cut_dripstone_wall": "Muro de espeleotema lapidado polido", - "block.create.polished_cut_granite": "Granito lapidado polido", - "block.create.polished_cut_granite_slab": "Laje de granito lapidado polido", - "block.create.polished_cut_granite_stairs": "Escada de granito lapidado polido", - "block.create.polished_cut_granite_wall": "Muro de granito lapidado polido", - "block.create.polished_cut_limestone": "Calcário lapidado polido", - "block.create.polished_cut_limestone_slab": "Laje de calcário lapidado polido", - "block.create.polished_cut_limestone_stairs": "Escada de calcário lapidado polido", - "block.create.polished_cut_limestone_wall": "Muro de calcário lapidado polido", - "block.create.polished_cut_ochrum": "Ocrom lapidado polido", - "block.create.polished_cut_ochrum_slab": "Laje de Ocrom lapidado polido", - "block.create.polished_cut_ochrum_stairs": "Escada de Ocrom lapidado polido", - "block.create.polished_cut_ochrum_wall": "Muro de Ocrom lapidado polido", - "block.create.polished_cut_scorchia": "Escória negra lapidada polida", - "block.create.polished_cut_scorchia_slab": "Laje de escória negra lapidada polida", - "block.create.polished_cut_scorchia_stairs": "Escada de escória negra lapidada polida", - "block.create.polished_cut_scorchia_wall": "Muro de escória negra lapidada polida", - "block.create.polished_cut_scoria": "Escória lapidada polida", - "block.create.polished_cut_scoria_slab": "Laje de escória lapidada polida", - "block.create.polished_cut_scoria_stairs": "Escada de escória lapidada polida", - "block.create.polished_cut_scoria_wall": "Muro de escória lapidada polida", - "block.create.polished_cut_tuff": "Tufo lapidado polido", - "block.create.polished_cut_tuff_slab": "Laje de tufo lapidado polido", - "block.create.polished_cut_tuff_stairs": "Escada de tufo lapidado polido", - "block.create.polished_cut_tuff_wall": "Muro de tufo lapidado polido", - "block.create.polished_cut_veridium": "Veridiano lapidado polido", - "block.create.polished_cut_veridium_slab": "Laje de Veridiano lapidado polido", - "block.create.polished_cut_veridium_stairs": "Escada de Veridiano lapidado polido", - "block.create.polished_cut_veridium_wall": "muro de Veridiano lapidado polido", - "block.create.portable_fluid_interface": "Interface de fluidos portátil", - "block.create.portable_storage_interface": "Interface de armazenamento portátil", - "block.create.powered_latch": "Trava de redstone", - "block.create.powered_shaft": "Eixo energizado", - "block.create.powered_toggle_latch": "Trava de alternância de redstone", - "block.create.pulley_magnet": "Ímã da Polia", - "block.create.pulse_extender": "Extensor de pulso", - "block.create.pulse_repeater": "Repetidor de Pulso", - "block.create.purple_nixie_tube": "Tubo nixie roxo", - "block.create.purple_sail": "Vela roxo", - "block.create.purple_seat": "Assento roxo", - "block.create.purple_toolbox": "Caixa de ferramentas roxa", - "block.create.purple_valve_handle": "válvula roxa", - "block.create.radial_chassis": "Chassis Radial", - "block.create.railway_casing": "Revestimento de trem", - "block.create.raw_zinc_block": "Bloco de zinco bruto", - "block.create.red_nixie_tube": "Tubo nixie vermelho", - "block.create.red_sail": "Vela vermelha", - "block.create.red_seat": "Assento vermelho", - "block.create.red_toolbox": "Caixa de ferramentas vermelha", - "block.create.red_valve_handle": "Válvula vermelha", - "block.create.redstone_contact": "Contato de Redstone", - "block.create.redstone_link": "Conexão de Redstone", - "block.create.refined_radiance_casing": "Revestimento Brilhante", - "block.create.rope": "Corda", - "block.create.rope_pulley": "Polia", - "block.create.rose_quartz_block": "Bloco de quartzo rosa", - "block.create.rose_quartz_lamp": "Lâmpada de quartzo rosa", - "block.create.rose_quartz_tiles": "Telha de quartzo rosa", - "block.create.rotation_speed_controller": "Controlador de velocidade rotacional", - "block.create.sail_frame": "Moldura de vela", - "block.create.schematic_table": "Mesa de Esquema", - "block.create.schematicannon": "Canhão de Esquema", - "block.create.scorchia": "Escória negra", - "block.create.scorchia_pillar": "Pilar de escória negra", - "block.create.scoria": "Escória", - "block.create.scoria_pillar": "Pilar de escória", - "block.create.secondary_linear_chassis": "Chassis linear secundário", - "block.create.sequenced_gearshift": "Câmbio sequencial", - "block.create.shadow_steel_casing": "Revestimento das Sombras", - "block.create.shaft": "Eixo", - "block.create.small_andesite_brick_slab": "Laje de tijolos pequenos de andesito", - "block.create.small_andesite_brick_stairs": "Escada de tijolos pequenos de andesito", - "block.create.small_andesite_brick_wall": "Muro de tijolos pequenos de andesito", - "block.create.small_andesite_bricks": "Tijolos pequenos de andesito", - "block.create.small_asurine_brick_slab": "Laje de tijolos pequenos de Asurino", - "block.create.small_asurine_brick_stairs": "Escada de tijolos pequenos de Asurino", - "block.create.small_asurine_brick_wall": "Muro de tijolos pequenos de Asurino", - "block.create.small_asurine_bricks": "Tijolos pequenos de Asurino", - "block.create.small_bogey": "Roda do trem pequena", - "block.create.small_calcite_brick_slab": "Laje de tijolos pequenos de calcita", - "block.create.small_calcite_brick_stairs": "Escada de tijolos pequenos de calcita", - "block.create.small_calcite_brick_wall": "Muro de tijolos pequenos de calcita", - "block.create.small_calcite_bricks": "Tijolos pequenos de calcita", - "block.create.small_crimsite_brick_slab": "Laje de tijolos pequenos de Carmesito", - "block.create.small_crimsite_brick_stairs": "Escada de tijolos pequenos de Carmesito", - "block.create.small_crimsite_brick_wall": "Muro de tijolos pequenos de Carmesito", - "block.create.small_crimsite_bricks": "Tijolos pequenos de Carmesito", - "block.create.small_deepslate_brick_slab": "Laje de tijolos pequenos de ardósia", - "block.create.small_deepslate_brick_stairs": "Escada de tijolos pequenos de ardósia", - "block.create.small_deepslate_brick_wall": "Muro de tijolos pequenos de ardósia", - "block.create.small_deepslate_bricks": "Tijolos pequenos de ardósia", - "block.create.small_diorite_brick_slab": "Laje de tijolos pequenos de diorito", - "block.create.small_diorite_brick_stairs": "Escada de tijolos pequenos de diorito", - "block.create.small_diorite_brick_wall": "Muro de tijolos pequenos de diorito", - "block.create.small_diorite_bricks": "Tijolos pequenos de diorito", - "block.create.small_dripstone_brick_slab": "Laje de tijolos pequenos de espeleotema", - "block.create.small_dripstone_brick_stairs": "Escada de tijolos pequenos de espeleotema", - "block.create.small_dripstone_brick_wall": "Muro de tijolos pequenos de espeleotema", - "block.create.small_dripstone_bricks": "Tijolos pequenos de espeleotema", - "block.create.small_granite_brick_slab": "Laje de tijolos pequenos de granito", - "block.create.small_granite_brick_stairs": "Escada de tijolos pequenos de granito", - "block.create.small_granite_brick_wall": "Muro de tijolos pequenos de granito", - "block.create.small_granite_bricks": "Tijolos pequenos de granito", - "block.create.small_limestone_brick_slab": "Laje de tijolos pequenos de calcário", - "block.create.small_limestone_brick_stairs": "Escada de tijolos pequenos de calcário", - "block.create.small_limestone_brick_wall": "Muro de tijolos pequenos de calcário", - "block.create.small_limestone_bricks": "Tijolos pequenos de calcário", - "block.create.small_ochrum_brick_slab": "Laje de tijolos pequenos de Ocrom", - "block.create.small_ochrum_brick_stairs": "Escada de tijolos pequenos de Ocrom", - "block.create.small_ochrum_brick_wall": "Muro de tijolos pequenos de Ocrom", - "block.create.small_ochrum_bricks": "Tijolos pequenos de Ocrom", - "block.create.small_rose_quartz_tiles": "Telha de quartzo rosa pequena", - "block.create.small_scorchia_brick_slab": "Laje de tijolos pequenos de escória negra", - "block.create.small_scorchia_brick_stairs": "Escada de tijolos pequenos de escória negra", - "block.create.small_scorchia_brick_wall": "Muro de tijolos pequenos de escória negra", - "block.create.small_scorchia_bricks": "Tijolos pequenos de escória negra", - "block.create.small_scoria_brick_slab": "Laje de tijolos pequenos de escória", - "block.create.small_scoria_brick_stairs": "Escada de tijolos pequenos de escória", - "block.create.small_scoria_brick_wall": "Muro de tijolos pequenos de escória", - "block.create.small_scoria_bricks": "Tijolos pequenos de escória", - "block.create.small_tuff_brick_slab": "Laje de tijolos pequenos de tufo", - "block.create.small_tuff_brick_stairs": "Escada de tijolos pequenos de tufo", - "block.create.small_tuff_brick_wall": "Muro de tijolos pequenos de tufo", - "block.create.small_tuff_bricks": "Tijolos pequenos de tufo", - "block.create.small_veridium_brick_slab": "Laje de tijolos pequenos de Veridiano", - "block.create.small_veridium_brick_stairs": "Escada de tijolos pequenos de Veridiano", - "block.create.small_veridium_brick_wall": "Muro de tijolos pequenos de Veridiano", - "block.create.small_veridium_bricks": "Tijolos pequenos de Veridiano", - "block.create.smart_chute": "Calha Inteligente", - "block.create.smart_fluid_pipe": "Cano de Fluidos Inteligente", - "block.create.speedometer": "Velocímetro", - "block.create.spout": "Bica", - "block.create.spruce_window": "Janela de pinheiro", - "block.create.spruce_window_pane": "Vidraça de pinheiro", - "block.create.steam_engine": "Motor a vapor", - "block.create.steam_whistle": "Apito a vapor", - "block.create.steam_whistle_extension": "Extensão do apito a vapor", - "block.create.sticker": "Adesivo", - "block.create.sticky_mechanical_piston": "Pistão Mecânico Grudento", - "block.create.stockpile_switch": "Disjuntor de Armazenamento", - "block.create.stressometer": "Estressómetro", - "block.create.tiled_glass": "Vidro Entalhado", - "block.create.tiled_glass_pane": "Vidraça Entalhada", - "block.create.track": "Trilho do trem", - "block.create.track_observer": "Observador de trem", - "block.create.track_signal": "Sinal de trem", - "block.create.track_station": "Estação de trem", - "block.create.train_door": "Porta de trem", - "block.create.train_trapdoor": "Alçapão de trem", - "block.create.tuff_pillar": "Pilar de tufo", - "block.create.turntable": "Mesa giratória", - "block.create.veridium": "Veridiano", - "block.create.veridium_pillar": "Pilar de Verdiano", - "block.create.vertical_framed_glass": "Vidro emoldurado vertical", - "block.create.vertical_framed_glass_pane": "Vidraça emoldurada vertical", - "block.create.warped_window": "Janela distorcida", - "block.create.warped_window_pane": "Vidraça distorcida", - "block.create.water_wheel": "Roda de Água", - "block.create.waxed_copper_shingle_slab": "Laje de telha de cobre encerada", - "block.create.waxed_copper_shingle_stairs": "Escada de telha de cobre encerada", - "block.create.waxed_copper_shingles": "Telha de cobre encerada", - "block.create.waxed_copper_tile_slab": "Laje de ladrilho de cobre encerada", - "block.create.waxed_copper_tile_stairs": "Escada de ladrilho de cobre encerada", - "block.create.waxed_copper_tiles": "Ladrilho de cobre encerado", - "block.create.waxed_exposed_copper_shingle_slab": "Laje de telha de cobre exposta encerada", - "block.create.waxed_exposed_copper_shingle_stairs": "Escada de telha de cobre exposta encerada", - "block.create.waxed_exposed_copper_shingles": "Telha de cobre exposta encerada", - "block.create.waxed_exposed_copper_tile_slab": "Laje de ladrilho de cobre exposta encerada", - "block.create.waxed_exposed_copper_tile_stairs": "Escada de ladrilho de cobre exposta encerada", - "block.create.waxed_exposed_copper_tiles": "Ladrilhos de cobre exposto encerado", - "block.create.waxed_oxidized_copper_shingle_slab": "Laje de telha de cobre oxidada encerada", - "block.create.waxed_oxidized_copper_shingle_stairs": "Escada de telha de cobre oxidada encerada", - "block.create.waxed_oxidized_copper_shingles": "Telha de cobre oxidado encerada", - "block.create.waxed_oxidized_copper_tile_slab": "Laje de ladrilhos de cobre oxidada encerada", - "block.create.waxed_oxidized_copper_tile_stairs": "Escada de ladrilhos de cobre oxidada encerada", - "block.create.waxed_oxidized_copper_tiles": "Ladrilhos de cobre oxidado encerado", - "block.create.waxed_weathered_copper_shingle_slab": "Laje de telha de cobre desgastada encerada", - "block.create.waxed_weathered_copper_shingle_stairs": "Escada de telha de cobre desgastada encerada", - "block.create.waxed_weathered_copper_shingles": "Telha de cobre desgastada encereda", - "block.create.waxed_weathered_copper_tile_slab": "Laje de ladrilho de cobre desgastado encerado", - "block.create.waxed_weathered_copper_tile_stairs": "Escada de ladrilho de cobre desgastado encerado", - "block.create.waxed_weathered_copper_tiles": "Ladrilho de cobre desgastado encerado", - "block.create.weathered_copper_shingle_slab": "Laje de telha de cobre desgastada encerada", - "block.create.weathered_copper_shingle_stairs": "Escada de telha de cobre desgastada encerada", - "block.create.weathered_copper_shingles": "Telha de cobre desgastada encerada", - "block.create.weathered_copper_tile_slab": "Laje de ladrilhos de cobre desgastada encerada", - "block.create.weathered_copper_tile_stairs": "Escada de ladrilhos de cobre desgastada encerada", - "block.create.weathered_copper_tiles": "Ladrilhos de cobre desgastado encerado", - "block.create.weighted_ejector": "Ejetor ponderado", - "block.create.white_nixie_tube": "Tubo nixie branco", - "block.create.white_sail": "Vela branca", - "block.create.white_seat": "Assento branco", - "block.create.white_toolbox": "Caixa de ferramentas branca", - "block.create.white_valve_handle": "Válvula branca", - "block.create.windmill_bearing": "Rolamento de moinho", - "block.create.wooden_bracket": "Suporte de madeira", - "block.create.yellow_nixie_tube": "Tubo nixie amarelo", - "block.create.yellow_sail": "Vela amarela", - "block.create.yellow_seat": "Assento amarelo", - "block.create.yellow_toolbox": "Caixa de amarela", - "block.create.yellow_valve_handle": "Válvula amarela", - "block.create.zinc_block": "Bloco de Zinco", - "block.create.zinc_ore": "Minério de Zinco", - - "enchantment.create.capacity": "Capacidade", - "enchantment.create.potato_recovery": "Recuperação de Batata", - - "entity.create.carriage_contraption": "Engenhoca de carruagem", - "entity.create.contraption": "Engenhoca", - "entity.create.crafting_blueprint": "Esquema de Fabricação", - "entity.create.gantry_contraption": "Engenhoca de Pórtico", - "entity.create.potato_projectile": "Projétil de batata", - "entity.create.seat": "Assento", - "entity.create.stationary_contraption": "Engenhoca estacionária", - "entity.create.super_glue": "Super Cola", - - "fluid.create.potion": "Poção", - "fluid.create.tea": "Chá do Construtor", - - "item.create.andesite_alloy": "Liga de Andesito", - "item.create.attribute_filter": "Filtro de Atributo", - "item.create.bar_of_chocolate": "Barra de Chocolate", - "item.create.belt_connector": "Esteira Mecânica", - "item.create.blaze_cake": "Bolo de Blaze", - "item.create.blaze_cake_base": "Base do Bolo de Blaze", - "item.create.brass_hand": "Mão de Latão", - "item.create.brass_ingot": "Barra de Latão", - "item.create.brass_nugget": "Pepita de Latão", - "item.create.brass_sheet": "Chapa de Latão", - "item.create.builders_tea": "Chá do Construtor", - "item.create.chest_minecart_contraption": "Engenhoca de carrinho de mina com baú", - "item.create.chocolate_bucket": "Balde de Chocolate", - "item.create.chocolate_glazed_berries": "Baga com Cobertura de Chocolate", - "item.create.chromatic_compound": "Composto Cromático", - "item.create.cinder_flour": "Farinha de Netherrack", - "item.create.copper_backtank": "Tanque Traseiro de cobre", - "item.create.copper_backtank_placeable": "Tanque de cobre traseiro colocável", - "item.create.copper_nugget": "Pepita de Cobre", - "item.create.copper_sheet": "Chapa de Cobre", - "item.create.crafter_slot_cover": "Cobertura do slot de fabricador", - "item.create.crafting_blueprint": "Esquema de Fabricação", - "item.create.creative_blaze_cake": "Bolo de Blaze Criativo", - "item.create.crushed_aluminum_ore": "Minério de Alumínio Esmagado", - "item.create.crushed_copper_ore": "Minério de Cobre Esmagado", - "item.create.crushed_gold_ore": "Minério de Ouro Esmagado", - "item.create.crushed_iron_ore": "Minério de Ferro Esmagado", - "item.create.crushed_lead_ore": "Minério de Chumbo Esmagado", - "item.create.crushed_nickel_ore": "Minério de Níquel Esmagado", - "item.create.crushed_osmium_ore": "Minério de Ósmio Esmagado", - "item.create.crushed_platinum_ore": "Minério de Platina Esmagado", - "item.create.crushed_quicksilver_ore": "Minério de Mercúrio Esmagado", - "item.create.crushed_silver_ore": "Minério de Prata Esmagado", - "item.create.crushed_tin_ore": "Minério de Estanho Esmagado", - "item.create.crushed_uranium_ore": "Urânio Esmagado", - "item.create.crushed_zinc_ore": "Minério de Zinco Esmagado", - "item.create.diving_boots": "Botas de Mergulhador", - "item.create.diving_helmet": "Capacete de Mergulhador", - "item.create.dough": "Massa de pão", - "item.create.electron_tube": "Tubo de Elétron", - "item.create.empty_blaze_burner": "Queimador de Blaze Vazio", - "item.create.empty_schematic": "Esquema vazio", - "item.create.experience_nugget": "Pepita de experiência", - "item.create.extendo_grip": "Extensão de Pegador", - "item.create.filter": "Filtro", - "item.create.furnace_minecart_contraption": "Engenhoca de Carrinho de Mina com Fornalha", - "item.create.goggles": "Óculos de Engenheiro", - "item.create.golden_sheet": "Chapa de Ouro", - "item.create.handheld_worldshaper": "Terraformador de Mundo Criativo", - "item.create.honey_bucket": "Balde de Mel", - "item.create.honeyed_apple": "Maçã com Cobertura de Mel", - "item.create.incomplete_precision_mechanism": "Mecanismo de Precisão", - "item.create.incomplete_track": "trilho incompleto", - "item.create.iron_sheet": "Chapa de Ferro", - "item.create.linked_controller": "Controle conectado", - "item.create.minecart_contraption": "Engenhoca de Carrinho de Mina", - "item.create.minecart_coupling": "Acoplamento de Carrinho de Mina", - "item.create.polished_rose_quartz": "Quartzo Rosa Polido", - "item.create.potato_cannon": "Canhão de Batata", - "item.create.powdered_obsidian": "Pó de Obsidiana", - "item.create.precision_mechanism": "Mecanismo de Precisão", - "item.create.propeller": "Hélice", - "item.create.raw_zinc": "Zinco bruto", - "item.create.red_sand_paper": "Lixa Vermelha", - "item.create.refined_radiance": "Luz Refinada", - "item.create.rose_quartz": "Quartzo Rosa", - "item.create.sand_paper": "Lixa", - "item.create.schedule": "Programação do trem", - "item.create.schematic": "Esquema", - "item.create.schematic_and_quill": "Esquema e pena", - "item.create.shadow_steel": "Aço sombrio", - "item.create.sturdy_sheet": "Chapa resistente", - "item.create.super_glue": "Super Cola", - "item.create.sweet_roll": "Rolinho Doce", - "item.create.tree_fertilizer": "Fertilizante de Árvore", - "item.create.unprocessed_obsidian_sheet": "Chapa de obsidiana não processada", - "item.create.vertical_gearbox": "Caixa de Transmissão Vertical", - "item.create.wand_of_symmetry": "Varinha de Simetria", - "item.create.wheat_flour": "Farinha de trigo", - "item.create.whisk": "Batedeira", - "item.create.wrench": "Chave Inglesa", - "item.create.zinc_ingot": "Barra de Zinco", - "item.create.zinc_nugget": "Pepita de Zinco", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bem vindo a Create", - "advancement.create.root.desc": "É hora de construir engenhocas maravilhosas", - "advancement.create.andesite_alloy": "Aliterações Em abundância", - "advancement.create.andesite_alloy.desc": "Materiais do Create têm nomes estranhos, a liga de andesito é um deles.", - "advancement.create.andesite_casing": "A era do andesito", - "advancement.create.andesite_casing.desc": "Use um pouco de liga de andesito e madeira para fazer um revestimento basico.", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "Crie algumas chapas na prensa mecânica", - "advancement.create.encased_fan": "Fazedor de vento", - "advancement.create.encased_fan.desc": "Coloque e ative um ventilador revestido", - "advancement.create.fan_processing": "Processando por particulas", - "advancement.create.fan_processing.desc": "Use um ventilador revestido para processar materiais", - "advancement.create.saw_processing": "O mais temido da oficina", - "advancement.create.saw_processing.desc": "Use uma serra mecânica de pé para processar materiais", - "advancement.create.compacting": "Compactação", - "advancement.create.compacting.desc": "Use uma prensa e uma bacia para criar menos itens de mais itens", - "advancement.create.belt": "Correia de alga", - "advancement.create.belt.desc": "Conecte dois eixos com uma esteira mecânica.", - "advancement.create.funnel": "Estética de aeroporto", - "advancement.create.funnel.desc": "Extraia ou insira itens num container usando um funil de andesito", - "advancement.create.chute": "Caindo", - "advancement.create.chute.desc": "coloque uma calha a versão vertical da esteira mecânica.", - "advancement.create.mechanical_mixer": "Misturando", - "advancement.create.mechanical_mixer.desc": "Combina ingredientes em uma batedeira mecânica", - "advancement.create.burner": "Fogueira viva", - "advancement.create.burner.desc": "Obtenha um queimador de blaze", - "advancement.create.water_wheel": "aproveitamento hidráulico", - "advancement.create.water_wheel.desc": "Coloque uma roda de água e tente conseguir gira-la!", - "advancement.create.windmill": "Uma brisa moderada", - "advancement.create.windmill.desc": "Monte um moinho de vento", - "advancement.create.shifting_gears": "Mudança de marcha", - "advancement.create.shifting_gears.desc": "Conecte uma roda dentada grande com uma roda dentada pequena, permitindo você a mudar a velocidade da engenhoca.", - "advancement.create.millstone": "Moedor portátil", - "advancement.create.millstone.desc": "Coloque e energize uma pedra de moer", - "advancement.create.super_glue": "Área de conexão", - "advancement.create.super_glue.desc": "Cole alguns blocos em um grupo", - "advancement.create.contraption_actors": "Movimento com proposito", - "advancement.create.contraption_actors.desc": "Crie uma engenhoca com brocas, serras ou coletores a bordo", - "advancement.create.portable_storage_interface": "Troca por drive-thru", - "advancement.create.portable_storage_interface.desc": "Use uma interface de armazenamento portátil para extrair ou inserir itens numa engenhoca", - "advancement.create.wrench_goggles": "Bem equipado", - "advancement.create.wrench_goggles.desc": "Equipe um óculos do engenheiro e uma chave inglesa", - "advancement.create.stressometer": "Mas quão estressado exatamente?", - "advancement.create.stressometer.desc": "Coloque e energise o estressômetro. Olhe a este por através dos seus óculos para ler o valor exato.", - "advancement.create.cuckoo_clock": "Mas é a hora?", - "advancement.create.cuckoo_clock.desc": "testemunhe seu relógio cuckoo anunciar a hora de dormir", - "advancement.create.windmill_maxed": "Uma brisa forte", - "advancement.create.windmill_maxed.desc": "Monte um moinho de vento com força maxima", - "advancement.create.ejector_maxed": "Campeão do trampolim", - "advancement.create.ejector_maxed.desc": "Seja lançado mais de 30 blocos por um ejetor ponderado", - "advancement.create.pulley_maxed": "Corda para lugar nenhum", - "advancement.create.pulley_maxed.desc": "Extenda uma corda por mais de 200 blocos de profundidade", - "advancement.create.cart_pickup": "Braçõs fortes", - "advancement.create.cart_pickup.desc": "Pegue uma engenhoca de carrinho de minas com pelos menos 200 blocos colados", - "advancement.create.anvil_plough": "Artilharia de ferreiro", - "advancement.create.anvil_plough.desc": "Lance uma bigorna com um arador mecânico", - "advancement.create.lava_wheel_00000": "Roda de magma", - "advancement.create.lava_wheel_00000.desc": "Isso nãoi deveria ter funcionado§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "Sessão de malhação", - "advancement.create.hand_crank_000.desc": "Use uma manivela até estar completamente exausto§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "Os pombinhos", - "advancement.create.belt_funnel_kiss.desc": "Faça dois funis de esteira beijarem.", - "advancement.create.stressometer_maxed": "Perfeitamente estressado", - "advancement.create.stressometer_maxed.desc": "Consiga uma leitura de 100% de um estressómetro§7\n(Hidden Advancement)", - "advancement.create.copper": "Rochas mais resistentes", - "advancement.create.copper.desc": "Acumule cobre para as suas explorações na manipulações de fluido", - "advancement.create.copper_casing": "A era do cobre", - "advancement.create.copper_casing.desc": "Use um pouco de chapas de cobre e madeira para criar um pouco de revestimentos de cobre.", - "advancement.create.spout": "Sploosh", - "advancement.create.spout.desc": "Assista um item ser enchido usando uma bica.", - "advancement.create.drain": "Cambalhotas de drenagem", - "advancement.create.drain.desc": "Assista um item contendo fluidos ser esvaziado por um dreno de itens", - "advancement.create.steam_engine": "A usina", - "advancement.create.steam_engine.desc": "Use um motor a vapor para gerar torque", - "advancement.create.steam_whistle": "Voz de um anjo", - "advancement.create.steam_whistle.desc": "Ative um apito a vapor", - "advancement.create.backtank": "Pressão para ir", - "advancement.create.backtank.desc": "Crie um tanque traseiro de cobre e faça ele acumular pressão", - "advancement.create.diving_suit": "Preparado para as profundezas", - "advancement.create.diving_suit.desc": "Equipe um capacete de mergulhador junto com o seu tanque traseiro de cobre e pule na água", - "advancement.create.mechanical_pump_0": "Sobre pressão", - "advancement.create.mechanical_pump_0.desc": "Coloque e ative uma bomba mecânica", - "advancement.create.glass_pipe": "Espião de fluxo", - "advancement.create.glass_pipe.desc": "Assista fluidos se propagarem por através de canos de fluido com janela. Canos retos ficam com janelas quando uma chave inglesa é usada neles.", - "advancement.create.water_supply": "Coletor de poças", - "advancement.create.water_supply.desc": "Use a extremidade sugante de um cano ou bomba para coletar blocos de água", - "advancement.create.hose_pulley": "Vazamento industrial", - "advancement.create.hose_pulley.desc": "desça uma polia de mangueira e assista esta drenar ou encher qualquer corpo de fluido.", - "advancement.create.chocolate_bucket": "Um mundo de imaginação", - "advancement.create.chocolate_bucket.desc": "Obtenha um balde de chocolate derretido", - "advancement.create.honey_drain": "Apicultura autônoma", - "advancement.create.honey_drain.desc": "Use canos para sugar o mel de colmeias ou colmeias artificiais", - "advancement.create.hose_pulley_lava": "Extraindo o manto", - "advancement.create.hose_pulley_lava.desc": "Bombeie de um corpo de lava grande o bastante para ser considerado infinito", - "advancement.create.steam_engine_maxed": "Todo o vapor", - "advancement.create.steam_engine_maxed.desc": "Opere uma caldeira na potencia maxima", - "advancement.create.foods": "Dieta equilibrada", - "advancement.create.foods.desc": "Crie bagas doces com chocolate, maçã com cobertura de mel e um rolinho doce; todas da mesma bica", - "advancement.create.diving_suit_lava": "Nadando com os lavagantes", - "advancement.create.diving_suit_lava.desc": "Tente mergulhar na lava com o seu equipamento de mergulho de cobre§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "Rolando", - "advancement.create.chained_drain.desc": "Assista um item se mover através de uma fileira de drenos de item§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "Não cruze os fluxos!", - "advancement.create.cross_streams.desc": "Assista dois fluidos se encontrarem na sua rede de canos§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "Órgão de tubo", - "advancement.create.pipe_organ.desc": "Conecte 12 apitos a vapor com afinação diferentes a um único tanque de fluidos§7\n(Hidden Advancement)", - "advancement.create.brass": "Ligas de verdade", - "advancement.create.brass.desc": "Use cobre esmagado e zinco esmagado para criar um pouco de latão.", - "advancement.create.brass_casing": "a era do latão", - "advancement.create.brass_casing.desc": "Use o recentemente obtido latão e um pouco de madeira para criar um revestimento mais avançado.", - "advancement.create.rose_quartz": "Diamantes rosa", - "advancement.create.rose_quartz.desc": "Pula alguns quartzos rosas", - "advancement.create.deployer": "Cutuque, coloque e ataque", - "advancement.create.deployer.desc": "coloque e energize um implantador, o reflexo perfeito de você mesmo.", - "advancement.create.precision_mechanism": "Curiosidades complexas", - "advancement.create.precision_mechanism.desc": "Monte um mecanismo de precisão.", - "advancement.create.speed_controller": "Engenheiros odiam ele!", - "advancement.create.speed_controller.desc": "Coloque um Controlador de velocidade rotacional, o dispositivo ultimato para mudança de marcha.", - "advancement.create.mechanical_arm": "Mâos ocupadas!", - "advancement.create.mechanical_arm.desc": "Fabrique um braço mecânico,selecione as entradas e saídas,Coloque e energize o; em seguida assista como elo faz todo o trabalho para você.", - "advancement.create.mechanical_crafter": "Fabricação automatica", - "advancement.create.mechanical_crafter.desc": "Coloque e ative alguns fabricadores mecânicos and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "Par de gigantes", - "advancement.create.crushing_wheel.desc": "Crie algumas rodas de moer para triturar alguns materiais eficientemente.", - "advancement.create.haunted_bell": "Sentido sombrio", - "advancement.create.haunted_bell.desc": "toque um sino assombrado", - "advancement.create.clockwork_bearing": "Hora da engenhoca", - "advancement.create.clockwork_bearing.desc": "Ative uma estrutura conectada a um rolamento de relógio.", - "advancement.create.display_link": "Grandes dados", - "advancement.create.display_link.desc": "Use uma conexão de placa de exibição para visualizar informações", - "advancement.create.potato_cannon": "Fwoomp!", - "advancement.create.potato_cannon.desc": "Derrote um inimigo com o seu canhão de batata.", - "advancement.create.extendo_grip": "Boioioing!", - "advancement.create.extendo_grip.desc": "Apossar-se de uma extensão de pegador.", - "advancement.create.linked_controller": "Ativação remota", - "advancement.create.linked_controller.desc": "Ative uma coneção de redstone usando um controle conectado", - "advancement.create.arm_blaze_burner": "Combuste-tron", - "advancement.create.arm_blaze_burner.desc": "Instrua um braço mecânico para alimentar seu queimador de blaze.", - "advancement.create.crusher_maxed_0000": "Triturando", - "advancement.create.crusher_maxed_0000.desc": "Opere um par de rodas de moer na velocidade maxima", - "advancement.create.arm_many_targets": "Organiza-tron", - "advancement.create.arm_many_targets.desc": "Programe um braço mecânico com dez ou mais locais de saída.", - "advancement.create.potato_cannon_collide": "Fogos de artificios vegetais", - "advancement.create.potato_cannon_collide.desc": "Colida diferentes tipos de projéteis do canhão de batata", - "advancement.create.self_deploying": "Carrinho com auto-condução", - "advancement.create.self_deploying.desc": "Crie uma engenhoca de carrinho de minas que coloque trilhos à frente de si mesmo", - "advancement.create.fist_bump": "Bate isso, mano!", - "advancement.create.fist_bump.desc": "Faça dois implantadores baterem com o punho.", - "advancement.create.crafter_lazy_000": "Medidas desesperadas", - "advancement.create.crafter_lazy_000.desc": "Drasticamente desacelere um fabricador mecânico para procrastinar numa verdadeira infraestrutura§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "Extensão completa", - "advancement.create.extendo_grip_dual.desc": "Empunhe duas extensões de pegadores para ter alcance super-humano§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "toque minha musica!", - "advancement.create.musical_arm.desc": "Assista um braço mecânico operar seu toca-discos.", - "advancement.create.sturdy_sheet": "As rochas mais resistentes", - "advancement.create.sturdy_sheet.desc": "Monte uma chapa resistente refinado obsidiana esmagada", - "advancement.create.train_casing_00": "A era da logistica", - "advancement.create.train_casing_00.desc": "Use chapas resistente para criar o revestimento para componentes ferroviários", - "advancement.create.train": "Todos a bordo!", - "advancement.create.train.desc": "Monte o seu primeiro trem", - "advancement.create.conductor": "Condutor instrutor", - "advancement.create.conductor.desc": "Instrua um maquinista com uma programação", - "advancement.create.track_signal": "Controle de tráfego", - "advancement.create.track_signal.desc": "Coloque um sinal de trem", - "advancement.create.display_board_0": "Horarios dinâmicos", - "advancement.create.display_board_0.desc": "Exiba a previsão de chegada de um trem na sua placa de exibição com a ajuda da conexão de placa de exibição", - "advancement.create.track_0": "Uma nova medida", - "advancement.create.track_0.desc": "Obtenha alguns trilhos de trem", - "advancement.create.train_whistle": "Choo choo!", - "advancement.create.train_whistle.desc": "Monte um apito a vapor no seu trem e ative ele enquanto dirige", - "advancement.create.train_portal": "Transporte dimensional", - "advancement.create.train_portal.desc": "Ande de trem através de um portal do Nether", - "advancement.create.track_crafting_factory": "Fabrica de trilhos", - "advancement.create.track_crafting_factory.desc": "Produza mais de 1000 trilhos de trem no mesmo fabricador mecânico", - "advancement.create.long_bend": "A curva mais longa", - "advancement.create.long_bend.desc": "Crie uma seção de trilho curvada que abrange mais de 30 blocos de comprimento", - "advancement.create.long_train": "Esforços ambiciosos", - "advancement.create.long_train.desc": "Crie um trem com pelo menos 6 vagões", - "advancement.create.long_travel": "Viagem de campo", - "advancement.create.long_travel.desc": "Deixe um assento de trem a mais de 5000 blocos de distância da onde você começou a viagem", - "advancement.create.train_roadkill": "Atropelamento", - "advancement.create.train_roadkill.desc": "Atropele um inimigo com o seu trem§7\n(Hidden Advancement)", - "advancement.create.red_signal": "Motorista expert", - "advancement.create.red_signal.desc": "Atravesse um sinal vermelho com o seu trem§7\n(Hidden Advancement)", - "advancement.create.train_crash": "Serviço terrivel", - "advancement.create.train_crash.desc": "Testemunhe uma batida de trem como um passageiro§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "Ponto cego", - "advancement.create.train_crash_backwards.desc": "Bata em outro trem enquanto dirige para trás§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Paletes Create", - - "death.attack.create.crush": "%1$s foi processado pelas Rodas de Moer", - "death.attack.create.crush.player": "%1$s foi jogando numa Roda de moer por %2$s", - "death.attack.create.fan_fire": "%1$s foi queimado por ar quente", - "death.attack.create.fan_fire.player": "%1$s Foi jogado num defumador por %2$s", - "death.attack.create.fan_lava": "%1$s foi queimado pelo ventilador de lava", - "death.attack.create.fan_lava.player": "U%1$s foi jogado numa fundidora por %2$s", - "death.attack.create.mechanical_drill": "%1$s foi empalado pela Broca Mecânica", - "death.attack.create.mechanical_drill.player": "%1$s foi jogado na frente de uma broca por %2$s", - "death.attack.create.mechanical_saw": "%1$s foi cortado ao meio por uma serra mecânica", - "death.attack.create.mechanical_saw.player": "%1$s foi jogado numa serra por %2$s", - "death.attack.create.potato_cannon": "%1$s foi atirado pelo canhão de batatas do %2$", - "death.attack.create.potato_cannon.item": "%1$s foi atirado por %2$s usando %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s foi explodido por relógio cuco adulterado", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado", - "death.attack.create.run_over": "%1$s foi atropelado por %2$s", - - "create.block.deployer.damage_source_name": "Implantador rebelde", - "create.block.cart_assembler.invalid": "Coloque o seu montador de carrinho de minas num trilho", - - "create.menu.return": "Retornar ao menu", - "create.menu.configure": "Configurar...", - "create.menu.ponder_index": "Tabela do ponderamento", - "create.menu.only_ingame": "Disponível no menu de pausa", - "create.menu.report_bugs": "Informar um erro", - "create.menu.support": "Suporte nós", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Triturando", - "create.recipe.milling": "Moendo", - "create.recipe.fan_washing": "Lavagem em massa", - "create.recipe.fan_washing.fan": "Ventilador atrás de água", - "create.recipe.fan_smoking": "Defumação em massa", - "create.recipe.fan_smoking.fan": "Ventilador atrás do fogo", - "create.recipe.fan_haunting": "Assombração em massa", - "create.recipe.fan_haunting.fan": "Ventilador atrás do fogo das almas ", - "create.recipe.fan_blasting": "Fundição em massa", - "create.recipe.fan_blasting.fan": "ventilador atrás de lava", - "create.recipe.pressing": "Prensando", - "create.recipe.mixing": "Misturando", - "create.recipe.deploying": "Implantando", - "create.recipe.automatic_shapeless": "Fabricação sem forma automático", - "create.recipe.automatic_brewing": "Produção de poções", - "create.recipe.packing": "Compactando", - "create.recipe.automatic_packing": "Compactação automático", - "create.recipe.sawing": "Serrando", - "create.recipe.mechanical_crafting": "Fabricação mecânica", - "create.recipe.automatic_shaped": "Fabricação com forma automática", - "create.recipe.block_cutting": "Corte de blocos", - "create.recipe.wood_cutting": "Corte de madeira", - "create.recipe.sandpaper_polishing": "Polimento com lixa", - "create.recipe.mystery_conversion": "Conversão misteriosa", - "create.recipe.spout_filling": "Preenchimento com bica", - "create.recipe.draining": "Drenação de item", - "create.recipe.item_application": "Aplicação de item manual", - "create.recipe.item_application.any_axe": "Qualquer machado", - "create.recipe.sequenced_assembly": "Montagem sequenciada", - "create.recipe.assembly.next": "Proximo: %1$s", - "create.recipe.assembly.step": "Passo %1$s:", - "create.recipe.assembly.progress": "Progresso: %1$s/%2$s", - "create.recipe.assembly.pressing": "Processa na prensa", - "create.recipe.assembly.spout_filling_fluid": "Despejar %1$s", - "create.recipe.assembly.deploying_item": "Implantar %1$s", - "create.recipe.assembly.cutting": "Cortado com serra", - "create.recipe.assembly.repeat": "Repetir sequência %1$s vezes", - "create.recipe.assembly.junk": "Recuperação aleatório", - "create.recipe.processing.chance": "%1$s%% Chance", - "create.recipe.deploying.not_consumed": "Não consumido", - "create.recipe.heat_requirement.none": "Aquecimento não requerido", - "create.recipe.heat_requirement.heated": "Aquecido", - "create.recipe.heat_requirement.superheated": "Super-aquecido", - - "create.generic.range": "Área", - "create.generic.radius": "Raio", - "create.generic.width": "Largura", - "create.generic.height": "Altura", - "create.generic.length": "Comprimento", - "create.generic.speed": "Velocidade", - "create.generic.delay": "Demorada", - "create.generic.duration": "Duração", - "create.generic.timeUnit": "Unidade de tempo", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Segundos", - "create.generic.unit.minutes": "Minutos", - "create.generic.daytime.hour": "Horas", - "create.generic.daytime.minute": "Minuto", - "create.generic.daytime.second": "Segundo", - "create.generic.daytime.pm": "Da tarde", - "create.generic.daytime.am": "Da manhã", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "us", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "Sentido horário", - "create.generic.counter_clockwise": "Sentido anti-horário", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "Afinação: %1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Rolar", - "create.action.confirm": "Confirmar", - "create.action.abort": "Abortar", - "create.action.saveToFile": "Salvar", - "create.action.discard": "Descartar", - - "create.keyinfo.toolmenu": "Menu Focal da Ferramenta", - "create.keyinfo.toolbelt": "Acessa caixas de ferramenta próximas", - "create.keyinfo.scrollup": "Simular a roda do mouse (para cima) (no mundo)", - "create.keyinfo.scrolldown": "Simular a roda do mouse (para baixo) (no mundo)", - - "create.gui.scrollInput.defaultTitle": "Escolha uma Opção:", - "create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar", - "create.gui.scrollInput.scrollToAdjustAmount": "Role o mouse para ajustar a quantidade", - "create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar", - "create.gui.scrollInput.shiftScrollsFaster": "Shift para rolar o mouse mais rapido", - "create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar", - "create.gui.toolmenu.cycle": "[SCROLL] para Circular", - - "create.toolbox.unequip": "Desequipar: %1$s", - "create.toolbox.outOfRange": "Caixa de ferramentas do item segurado fora de alcance", - "create.toolbox.detach": "Parar de rastrear e manter item", - "create.toolbox.depositAll": "Retorna itens para caixa de ferramenta próxima", - "create.toolbox.depositBox": "Retornar itens para caixa de ferramenta", - - "create.gui.symmetryWand.mirrorType": "Espelhar", - "create.gui.symmetryWand.orientation": "Orientação", - - "create.symmetry.mirror.plane": "Espelhar uma vez", - "create.symmetry.mirror.doublePlane": "Retangular", - "create.symmetry.mirror.triplePlane": "Octagonal", - - "create.orientation.orthogonal": "Ortogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "Através de Z", - "create.orientation.alongX": "Através de X", - - "create.gui.terrainzapper.title": "UNLOCALIZED: Handheld Blockzapper", - "create.gui.terrainzapper.searchDiagonal": "UNLOCALIZED: Follow Diagonals", - "create.gui.terrainzapper.searchFuzzy": "UNLOCALIZED: Ignore Material Borders", - "create.gui.terrainzapper.patternSection": "UNLOCALIZED: Pattern", - "create.gui.terrainzapper.pattern.solid": "UNLOCALIZED: Solid", - "create.gui.terrainzapper.pattern.checkered": "UNLOCALIZED: Checkerboard", - "create.gui.terrainzapper.pattern.inversecheckered": "UNLOCALIZED: Inverted Checkerboard", - "create.gui.terrainzapper.pattern.chance25": "UNLOCALIZED: 25% Roll", - "create.gui.terrainzapper.pattern.chance50": "UNLOCALIZED: 50% Roll", - "create.gui.terrainzapper.pattern.chance75": "UNLOCALIZED: 75% Roll", - "create.gui.terrainzapper.placement": "UNLOCALIZED: Placement", - "create.gui.terrainzapper.placement.merged": "UNLOCALIZED: Merged", - "create.gui.terrainzapper.placement.attached": "UNLOCALIZED: Attached", - "create.gui.terrainzapper.placement.inserted": "UNLOCALIZED: Inserted", - "create.gui.terrainzapper.brush": "UNLOCALIZED: Brush", - "create.gui.terrainzapper.brush.cuboid": "UNLOCALIZED: Cuboid", - "create.gui.terrainzapper.brush.sphere": "UNLOCALIZED: Sphere", - "create.gui.terrainzapper.brush.cylinder": "UNLOCALIZED: Cylinder", - "create.gui.terrainzapper.brush.surface": "UNLOCALIZED: Surface", - "create.gui.terrainzapper.brush.cluster": "UNLOCALIZED: Cluster", - "create.gui.terrainzapper.tool": "UNLOCALIZED: Tool", - "create.gui.terrainzapper.tool.fill": "UNLOCALIZED: Fill", - "create.gui.terrainzapper.tool.place": "UNLOCALIZED: Place", - "create.gui.terrainzapper.tool.replace": "UNLOCALIZED: Replace", - "create.gui.terrainzapper.tool.clear": "UNLOCALIZED: Clear", - "create.gui.terrainzapper.tool.overlay": "UNLOCALIZED: Overlay", - "create.gui.terrainzapper.tool.flatten": "UNLOCALIZED: Flatten", - - "create.terrainzapper.shiftRightClickToSet": "UNLOCALIZED: Shift-Right-Click to Select a Shape", - "create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s", - "create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material", - - "create.minecart_coupling.two_couplings_max": "Carrinhos de mina não podem ter mais de dois acoplamentos cada", - "create.minecart_coupling.unloaded": "Partes do seu trem aparentam estar em um chunk descarregado", - "create.minecart_coupling.no_loops": "Acoplamentos não podem formar um loop", - "create.minecart_coupling.removed": "Removeu todos os acoplamentos do carrinho de mina", - "create.minecart_coupling.too_far": "Carrinhos de mina estão muito distanciados", - - "create.contraptions.movement_mode": "Modo de movimento", - "create.contraptions.movement_mode.move_place": "Sempre colocar quando parado", - "create.contraptions.movement_mode.move_place_returned": "Colocar apenas na posição inicial", - "create.contraptions.movement_mode.move_never_place": "Colocar apenas caso a âncora seja destruída", - "create.contraptions.movement_mode.rotate_place": "Sempre colocar quando parado", - "create.contraptions.movement_mode.rotate_place_returned": "Apenas colocar perto do angulo inicial", - "create.contraptions.movement_mode.rotate_never_place": "Colocar apenas caso a âncora seja destruída", - "create.contraptions.cart_movement_mode": "Modo de movimento do carrinho", - "create.contraptions.cart_movement_mode.rotate": "Sempre apontar para a direção do movimento", - "create.contraptions.cart_movement_mode.rotate_paused": "Pausar atores quando girando", - "create.contraptions.cart_movement_mode.rotation_locked": "Travar a rotação", - "create.contraptions.windmill.rotation_direction": "Direção da rotação", - "create.contraptions.clockwork.clock_hands": "Ponteiros do relogio", - "create.contraptions.clockwork.hour_first": "Ponteiro da hora primeiro", - "create.contraptions.clockwork.minute_first": "Ponteiro do minuto primeiro", - "create.contraptions.clockwork.hour_first_24": "Ponteiro das 24 horas primeiro", - - "create.logistics.filter": "Filtro", - "create.logistics.recipe_filter": "Filtro de receitas", - "create.logistics.fluid_filter": "Filtro de fluido", - "create.logistics.firstFrequency": "Freq. #1", - "create.logistics.secondFrequency": "Freq. #2", - "create.logistics.filter.apply": "Aplicou filtro para %1$s.", - "create.logistics.filter.apply_click_again": "Aplicou filtro para %1$s, Clique denovo para copiar quantidade.", - "create.logistics.filter.apply_count": "Aplicou quantidade de extração para o filtro.", - - "create.gui.goggles.generator_stats": "Estatísticas do gerador:", - "create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:", - "create.gui.goggles.at_current_speed": "Na velocidade atual", - "create.gui.goggles.pole_length": "Comprimento da vara:", - "create.gui.goggles.fluid_container": "Informação do recipiente de fluido:", - "create.gui.goggles.fluid_container.capacity": "Capacidade: ", - "create.gui.assembly.exception": "Não foi possível montar essa engenhoca:", - "create.gui.assembly.exception.unmovableBlock": "Bloco imovel (%4$s) em [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "O bloco em [%1$s,%2$s,%3$s] não estava em um chunk carregado", - "create.gui.assembly.exception.structureTooLarge": "Tem muitos blocos incluídos na engenhoca. O limite configurado é: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Tem muitas varetas de extensão colocadas nesse pistão. O limite configurado é: %1$s", - "create.gui.assembly.exception.noPistonPoles": "O pistão esta faltando algumas varetas de extensão", - "create.gui.assembly.exception.not_enough_sails": "A estrutura conectada não possui o número suficiente de blocos tipo vela: %1$s\nUm mínimo de %2$s são requeridos", - "create.gui.gauge.info_header": "Informação do medidor:", - "create.gui.speedometer.title": "Velocidade de rotação", - "create.gui.stressometer.title": "Estresse do sistema", - "create.gui.stressometer.capacity": "Capacidade restante", - "create.gui.stressometer.overstressed": "Sobre estressado", - "create.gui.stressometer.no_rotation": "Nenhuma rotação", - "create.gui.contraptions.not_fast_enough": "Aparenta que esse %1$s não _está_ girando com _a velocidade_ _necessária_.", - "create.gui.contraptions.network_overstressed": "Aparenta que essa engenhoca está _sobre estressada_. Adicione mais fontes ou _desacelere_ __ os componentes que tem um _impacto de_ _stress alto_.", - "create.gui.adjustable_crate.title": "UNLOCALIZED: Adjustable Crate", - "create.gui.adjustable_crate.storageSpace": "UNLOCALIZED: Storage Space", - "create.gui.stockpile_switch.title": "Dijuntor de armazenamento", - "create.gui.stockpile_switch.invert_signal": "Inverter sinal", - "create.gui.stockpile_switch.move_to_lower_at": "Mover para a faixa mais baixa %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Mover para a faixa mais alta %1$s%%", - "create.gui.sequenced_gearshift.title": "Câmbio sequenciado", - "create.gui.sequenced_gearshift.instruction": "Instruções", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Rotacionar por angulo", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Giro", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angulo", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Rotacionar par mover Pistão/Polia/Portico", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistão", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distancia", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Espera", - "create.gui.sequenced_gearshift.instruction.delay": "Esperar", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Duração", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Terminar", - "create.gui.sequenced_gearshift.instruction.end": "Termino", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Esperar novo pulso de redstone", - "create.gui.sequenced_gearshift.instruction.await": "Espera", - "create.gui.sequenced_gearshift.speed": "Velocidade, Direção", - "create.gui.sequenced_gearshift.speed.forward": "Velocidade inicial, Para frente", - "create.gui.sequenced_gearshift.speed.forward_fast": "Dobro da velocidade, Para frente", - "create.gui.sequenced_gearshift.speed.back": "Velocidade inicial, Para trás", - "create.gui.sequenced_gearshift.speed.back_fast": "Dobro da velocidade, Para trás", - - "create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Primeira posição feita.", - "create.schematicAndQuill.secondPos": "Segunda posição feita.", - "create.schematicAndQuill.noTarget": "Seguro [Ctrl] para seleccionar Blocos de Ar.", - "create.schematicAndQuill.abort": "Seleção removida.", - "create.schematicAndQuill.title": "Nome do esquema:", - "create.schematicAndQuill.convert": "Salvar e carregar arquivo imediatamente", - "create.schematicAndQuill.fallbackName": "Meu Esquema", - "create.schematicAndQuill.saved": "Salvo como %1$s", - - "create.schematic.invalid": "[!] Item Inválido - Use a Mesa de Desenho no lugar", - "create.schematic.position": "Posição", - "create.schematic.rotation": "Rotação", - "create.schematic.rotation.none": "Nada", - "create.schematic.rotation.cw90": "Sentido horário 90", - "create.schematic.rotation.cw180": "Sentido horário 180", - "create.schematic.rotation.cw270": "Sentido horário 270", - "create.schematic.mirror": "Espelhar", - "create.schematic.mirror.none": "Nada", - "create.schematic.mirror.frontBack": "Frente para Trás", - "create.schematic.mirror.leftRight": "Esquerda para Direita", - "create.schematic.tool.deploy": "Concluir", - "create.schematic.tool.move": "Mover XZ", - "create.schematic.tool.movey": "Mover Y", - "create.schematic.tool.rotate": "Rodar", - "create.schematic.tool.print": "Imprimir", - "create.schematic.tool.flip": "Virar", - "create.schematic.tool.deploy.description.0": "Move o lugar da estrutura.", - "create.schematic.tool.deploy.description.1": "Botão-direito no chão para colocar.", - "create.schematic.tool.deploy.description.2": "Segure [Ctrl] para selecionar em uma distância fixa.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Rolar para mudar a distância.", - "create.schematic.tool.move.description.0": "Vira o Esquema Horizontalmente", - "create.schematic.tool.move.description.1": "Aponte ao Esquema e [CTRL]-Rolar para empurrar.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Vira o Esquema Verticalmente", - "create.schematic.tool.movey.description.1": "[CTRL]-Rolar para mover para cima/baixo", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Roda o Esquema em torno do seu centro.", - "create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Colocá estrutura no mundo instantaneamente", - "create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.", - "create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Gira o Esquema ao longo da face que você selecionar.", - "create.schematic.tool.flip.description.1": "Aponte para o Esquema e [CTRL]-Rolar para virá-lo.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Sincronizando...", - "create.schematics.uploadTooLarge": "Seu esquema é muito grande", - "create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:", - - "create.gui.schematicTable.refresh": "atualizar arquivos", - "create.gui.schematicTable.open_folder": "Abrir pasta", - "create.gui.schematicTable.title": "Mesa de Desenho", - "create.gui.schematicTable.availableSchematics": "Esquema disponíveis", - "create.gui.schematicTable.noSchematics": "Nenhum esquema salvo", - "create.gui.schematicTable.uploading": "Importando...", - "create.gui.schematicTable.finished": "Envio Concluído!", - "create.gui.schematicannon.title": "Canhão de esquema", - "create.gui.schematicannon.listPrinter": "Impressora de Lista de Materiais", - "create.gui.schematicannon.gunpowderLevel": "Pólvora em %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Disparos faltantes: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s", - "create.gui.schematicannon.optionEnabled": "Habilitado Atualmente", - "create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente", - "create.gui.schematicannon.showOptions": "Mostrar as configurações da impressora", - "create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos", - "create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos", - "create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer", - "create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio", - "create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes", - "create.gui.schematicannon.option.skipTileEntities": "Proteger tile entities", - "create.gui.schematicannon.slot.gunpowder": "Adicionar pólvora para carregar o canhão", - "create.gui.schematicannon.slot.listPrinter": "Coloque livros aqui para imprimir uma lista para o seu esquema", - "create.gui.schematicannon.slot.schematic": "Adicione o seu esquema aqui. Tenha certeza que ele está colocado em um lugar especifico.", - "create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próxima. Posição.", - "create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baús.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.", - "create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.", - "create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "O Canhão de esquema irá limpar todos os blocos na área de trabalho, incluindo os substituídos por Ar.", - - "create.schematicannon.status.idle": "Ocioso", - "create.schematicannon.status.ready": "Pronto", - "create.schematicannon.status.running": "Trabalhando", - "create.schematicannon.status.finished": "Concluído", - "create.schematicannon.status.paused": "Pausado", - "create.schematicannon.status.stopped": "Parada", - "create.schematicannon.status.noGunpowder": "Sem pólvora", - "create.schematicannon.status.targetNotLoaded": "Bloco não carregado", - "create.schematicannon.status.targetOutsideRange": "Alvo está muito Longe", - "create.schematicannon.status.searching": "Procurando", - "create.schematicannon.status.skipping": "Pulando", - "create.schematicannon.status.missingBlock": "Bloco Faltante:", - "create.schematicannon.status.placing": "Colocando", - "create.schematicannon.status.clearing": "Limpando Blocos", - "create.schematicannon.status.schematicInvalid": "Esquema Inválido", - "create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado", - "create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado", - - "create.materialChecklist": "Lista de materiais", - "create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", - - "create.gui.filter.deny_list": "Lista de negação", - "create.gui.filter.deny_list.description": "Itens passam se eles não encaixam em nenhum dos acima. Uma lista de negação vazia aceita tudo.", - "create.gui.filter.allow_list": "Lista de permissão", - "create.gui.filter.allow_list.description": "Itens passam se eles se encaixam em algum dos acima. Uma lista de permissão vazia rejeita tudo.", - "create.gui.filter.respect_data": "Respeitar informação", - "create.gui.filter.respect_data.description": "Itens apenas se encaixam caso a durabilidade, encantamentos e outros atributos se encaixam também.", - "create.gui.filter.ignore_data": "Ignorar informação", - "create.gui.filter.ignore_data.description": "Itens se enquadram não importa os seus atributos.", - - "create.item_attributes.placeable": "É colocavel", - "create.item_attributes.placeable.inverted": "Não é colocavel", - "create.item_attributes.consumable": "É comestivel", - "create.item_attributes.consumable.inverted": "Não é comestivel", - "create.item_attributes.fluid_container": "Pode armazenar fluidos", - "create.item_attributes.fluid_container.inverted": "Não pode armazenar fluidos", - "create.item_attributes.enchanted": "Está encantado", - "create.item_attributes.enchanted.inverted": "Não está encantado", - "create.item_attributes.max_enchanted": "Está encantado no nível máximo", - "create.item_attributes.max_enchanted.inverted": "Não está encantado no nível maximo", - "create.item_attributes.renamed": "Tem nome customizado", - "create.item_attributes.renamed.inverted": "Não tem nome customizado", - "create.item_attributes.damaged": "Está danificado", - "create.item_attributes.damaged.inverted": "Não está danificado", - "create.item_attributes.badly_damaged": "Está severamente danificado", - "create.item_attributes.badly_damaged.inverted": "Não está severamente danificado", - "create.item_attributes.not_stackable": "Não pode ser empilhado", - "create.item_attributes.not_stackable.inverted": "Pode ser empilhado", - "create.item_attributes.equipable": "Pode ser equipado", - "create.item_attributes.equipable.inverted": "Não pode ser equipado", - "create.item_attributes.furnace_fuel": "è combustivel", - "create.item_attributes.furnace_fuel.inverted": "Não é combustivel", - "create.item_attributes.washable": "Pode ser lavado", - "create.item_attributes.washable.inverted": "Não pode ser lavado", - "create.item_attributes.hauntable": "Pode ser amaldiçoado", - "create.item_attributes.hauntable.inverted": "Não pode ser amaldiçoado", - "create.item_attributes.crushable": "Pode ser triturado", - "create.item_attributes.crushable.inverted": "Não pode ser triturado", - "create.item_attributes.smeltable": "Pode ser fundido", - "create.item_attributes.smeltable.inverted": "Não pode ser fundido", - "create.item_attributes.smokable": "Pode ser defumado", - "create.item_attributes.smokable.inverted": "Não pode ser defumado", - "create.item_attributes.blastable": "È fundível no alto-forno", - "create.item_attributes.blastable.inverted": "Não é fundível no alto-forno", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "O shulker é %1$s", - "create.item_attributes.shulker_level.inverted": "O shulker não é %1$s", - "create.item_attributes.shulker_level.full": "Cheio", - "create.item_attributes.shulker_level.empty": "Vazio", - "create.item_attributes.shulker_level.partial": "Parcialmente cheio", - "create.item_attributes.in_tag": "è marcado %1$s", - "create.item_attributes.in_tag.inverted": "Não é marcado %1$s", - "create.item_attributes.in_item_group": "Está no grupo '%1$s'", - "create.item_attributes.in_item_group.inverted": "Não esta no grupo '%1$s'", - "create.item_attributes.added_by": "Foi adicionado por %1$s", - "create.item_attributes.added_by.inverted": "Não foi adicionado por %1$s", - "create.item_attributes.has_enchant": "Está encantado com %1$s", - "create.item_attributes.has_enchant.inverted": "Não esta encantado com %1$s", - "create.item_attributes.color": "Esta tingido de %1$s", - "create.item_attributes.color.inverted": "Não está tingido de %1$s", - "create.item_attributes.has_fluid": "Contem %1$s", - "create.item_attributes.has_fluid.inverted": "Não contem %1$s", - "create.item_attributes.has_name": "Tem o nome %1$s", - "create.item_attributes.has_name.inverted": "Não tem o nome %1$s", - "create.item_attributes.book_author": "Tem a autoria de %1$s", - "create.item_attributes.book_author.inverted": "Não tem a autoria de %1$s", - "create.item_attributes.book_copy_original": "É original", - "create.item_attributes.book_copy_original.inverted": "Não é original", - "create.item_attributes.book_copy_first": "É uma cópia da primeira geração", - "create.item_attributes.book_copy_first.inverted": "Não é uma copia de primeira geração", - "create.item_attributes.book_copy_second": "É uma cópia de segunda geração", - "create.item_attributes.book_copy_second.inverted": "Não é uma copia de segunda geração", - "create.item_attributes.book_copy_tattered": "É uma bagunça esfarrapada", - "create.item_attributes.book_copy_tattered.inverted": "Não é uma bagunça esfarrapada", - "create.item_attributes.astralsorcery_amulet": "Melhora %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "Não melhora %1$s", - "create.item_attributes.astralsorcery_constellation": "Esta sintonizado a %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "Não esta sintonizado a %1$s", - "create.item_attributes.astralsorcery_crystal": "Tem atributos de cristais %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "Não tem atributos de cristais %1$s", - "create.item_attributes.astralsorcery_perk_gem": " %1$s Tem um atributo de beneficio", - "create.item_attributes.astralsorcery_perk_gem.inverted": "%1$s Não tem um atributo de benefício", - - "create.gui.attribute_filter.no_selected_attributes": "Nenhum atributo selecionado", - "create.gui.attribute_filter.selected_attributes": "Atributos selecionados:", - "create.gui.attribute_filter.add_attribute": "Adicionar atributo a lista", - "create.gui.attribute_filter.add_inverted_attribute": "Adicionar atributo oposto a lista", - "create.gui.attribute_filter.allow_list_disjunctive": "Lista de permissão (Qualquer)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Itens passam se eles tiverem qualquer atributo selecionado.", - "create.gui.attribute_filter.allow_list_conjunctive": "Lista de permissão (Todos)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Itens passam se eles tiverem TODOS atributos selecionados.", - "create.gui.attribute_filter.deny_list": "lista de negação", - "create.gui.attribute_filter.deny_list.description": "Itens passam se eles NÃO tiverem qualquer atributo selecionado.", - "create.gui.attribute_filter.add_reference_item": "Adicionar item referência", - - "create.tooltip.holdForDescription": "Segure [%1$s] para o sumário", - "create.tooltip.holdForControls": "Segure [%1$s] para os controles", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Requerimento de velocidade: %1$s", - "create.tooltip.speedRequirement.none": "Nenhum", - "create.tooltip.speedRequirement.slow": "Devagar", - "create.tooltip.speedRequirement.medium": "Modereado", - "create.tooltip.speedRequirement.fast": "Rapido", - "create.tooltip.stressImpact": "Impacto de stress: %1$s", - "create.tooltip.stressImpact.low": " Baixo", - "create.tooltip.stressImpact.medium": " Moderado", - "create.tooltip.stressImpact.high": " Alto", - "create.tooltip.stressImpact.overstressed": ": Sobre estresse", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Capacidade de stress cinético: %1$s", - "create.tooltip.capacityProvided.low": " Pequeno", - "create.tooltip.capacityProvided.medium": " Médio", - "create.tooltip.capacityProvided.high": " Grande", - "create.tooltip.generationSpeed": " Gera em %1$s %2$s", - "create.tooltip.analogStrength": " Força analogica: %1$s/15", - - "create.mechanical_arm.extract_from": " Pegar itens de %1$s", - "create.mechanical_arm.deposit_to": " Depositar itens para %1$s", - "create.mechanical_arm.summary": "Braço mecânico tem %1$s entrada(s) e %2$s saida(s).", - "create.mechanical_arm.points_outside_range": "%1$s Ponto(s) de interação removidos pelas limitações de alcance.", - - "create.weighted_ejector.target_set": "Alvo selecionado", - "create.weighted_ejector.target_not_valid": "Ejetando para o bloco adjacente (Alvo não foi valido)", - "create.weighted_ejector.no_target": "Ejetando para o bloco adjacente (Nenhum alvo foi selecionado)", - "create.weighted_ejector.targeting": "Ejetando para [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Tamanho da pilha ejetada", - - "create.logistics.when_multiple_outputs_available": "Quando multiplas saidas selecionadas", - - "create.mechanical_arm.selection_mode.round_robin": "Rodízio", - "create.mechanical_arm.selection_mode.forced_round_robin": "Rodízio forçado", - "create.mechanical_arm.selection_mode.prefer_first": "Preferir primeiro alvo", - - "create.tunnel.selection_mode.split": "Dividir", - "create.tunnel.selection_mode.forced_split": "Divisão forçada", - "create.tunnel.selection_mode.round_robin": "Rodízio", - "create.tunnel.selection_mode.forced_round_robin": "Rodízio forçado", - "create.tunnel.selection_mode.prefer_nearest": "Preferir o mais perto", - "create.tunnel.selection_mode.randomize": "Aleatorizar", - "create.tunnel.selection_mode.synchronize": "Sincronizar as entradas", - - "create.tooltip.chute.header": "Informação da calha", - "create.tooltip.chute.items_move_down": "Itens movimentam para baixo", - "create.tooltip.chute.items_move_up": "Itens movem para cima", - "create.tooltip.chute.no_fans_attached": "Não conectado com um ventilador", - "create.tooltip.chute.fans_push_up": "Ventiladores sopram de baixo", - "create.tooltip.chute.fans_push_down": "Ventiladores sopram de cima", - "create.tooltip.chute.fans_pull_up": "Ventiladores sugam de cima", - "create.tooltip.chute.fans_pull_down": "Ventiladores sugam de baixo", - "create.tooltip.chute.contains": "Contem: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Distribuindo:", - "create.tooltip.brass_tunnel.contains_entry": " > %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Clique direito para recuperar item", - - "create.linked_controller.bind_mode": "Modo de vinculação", - "create.linked_controller.press_keybind": "Aperte %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, para vincular essa frequencia para tecla respectiva", - "create.linked_controller.key_bound": "Frequência vinculada com %1$s", - "create.linked_controller.frequency_slot_1": "Tecla: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "Tecla: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "Slot de ingrediente", - "create.crafting_blueprint.filter_items_viable": "Filtros avançados são viaveis", - "create.crafting_blueprint.display_slot": "Slot de exibição", - "create.crafting_blueprint.inferred": "Deduzido pela receita", - "create.crafting_blueprint.manually_assigned": "Designado manualmente", - "create.crafting_blueprint.secondary_display_slot": "Slot de exibição secundario", - "create.crafting_blueprint.optional": "Opcional", - - "create.potato_cannon.ammo.attack_damage": " %1$s Dano de ataque", - "create.potato_cannon.ammo.reload_ticks": " %1$s Velocidade de recarregamento", - "create.potato_cannon.ammo.knockback": " %1$s Repulsão do projetil", - - "create.hint.hose_pulley.title": "Abastecimento sem fundo", - "create.hint.hose_pulley": "O corpo de fluido selecionado é considerado infinito.", - "create.hint.mechanical_arm_no_targets.title": "Sem alvos", - "create.hint.mechanical_arm_no_targets": "Aparentemente esse _Braço_ _Mecânico_ não foi designado nenhum _alvo._ Selecione esteiras, depósitos, funis e outros blocos com o _botão direito do mouse_ enquanto _segurando_ o _Braço_ _Mecânico_ na sua _mão_.", - "create.hint.empty_bearing.title": "Atualizar o rolamento", - "create.hint.empty_bearing": " clique com o botão direito_ o rolamento com a _mão_ _vazia_ para _conectar_ a estrutura que você construiu não frente disso.", - "create.hint.full_deployer.title": "Implantador transbordando de itens", - "create.hint.full_deployer": "Aparenta que esse _inplantador_ contém _itens_ em _excesso_ que precisam ser _extraídos._ Use um _funil,_ _funil de andesito/latão_ ou outros meios para extrair os itens excedentes.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", - "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", - "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", - "create.gui.config.overlay4": "UNLOCALIZED: to move this preview", - "create.gui.config.overlay5": "UNLOCALIZED: Press ESC to exit this screen", - "create.gui.config.overlay6": "UNLOCALIZED: and save the new position", - "create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset", - "create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position", - - "create.command.killTPSCommand": " killtps", - "create.command.killTPSCommand.status.slowed_by.0": " [Create]: Server tick is currently slowed by %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": " [Create]: Server tick is slowed by %s ms now >:)", - "create.command.killTPSCommand.status.slowed_by.2": " [Create]: Server tick is back to regular speed :D", - "create.command.killTPSCommand.status.usage.0": " [Create]: use /killtps stop to bring back server tick to regular speed", - "create.command.killTPSCommand.status.usage.1": " [Create]: use /killtps start to artificially slow down the server tick", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Essa engenhoca de carrinho aparenta ser muita grande para pegar", - "create.contraption.minecart_contraption_illegal_pickup": "Uma força mistica esta segurando esta engenhoca de carrinho", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Engenhoca para", - "create.subtitle.peculiar_bell_use": "Sino peculiar toca", - "create.subtitle.worldshaper_place": "Zaps do terraformador", - "create.subtitle.whistle_train_manual": "Buzinas de trem", - "create.subtitle.steam": "Sons de vapor", - "create.subtitle.saw_activate_stone": "Serra mecânica ativa", - "create.subtitle.schematicannon_finish": "Ding do canhão de esquema", - "create.subtitle.crafter_craft": "Fabricador fábrica", - "create.subtitle.wrench_remove": "Componente quebra", - "create.subtitle.train3": "Tremer abafado das rodas do trem", - "create.subtitle.whistle": "Apito", - "create.subtitle.cogs": "tremer da rodas dentadas", - "create.subtitle.slime_added": "Slime sendo espremido", - "create.subtitle.whistle_train_low": "Apito baixo", - "create.subtitle.schematicannon_launch_block": "Canhão de esquema atira", - "create.subtitle.controller_take": "Atril esvaziado", - "create.subtitle.crafter_click": "Clicks do fabricador", - "create.subtitle.depot_plop": "Item pousa", - "create.subtitle.confirm": "Ding afirmativo", - "create.subtitle.mixing": "Sons de mistura", - "create.subtitle.mechanical_press_activation_belt": "Bonks da prensa mecanica", - "create.subtitle.fwoomp": "Fwoomps do canhão de batata", - "create.subtitle.sanding_long": "Sons de lixa", - "create.subtitle.crushing_1": "Sons de trituração", - "create.subtitle.depot_slide": "Item escorrega", - "create.subtitle.blaze_munch": "Queimador de blazer mastiga", - "create.subtitle.funnel_flap": "Abas do funil batendo", - "create.subtitle.haunted_bell_use": "Sino assombrado toca", - "create.subtitle.scroll_value": "click do scroll", - "create.subtitle.controller_put": "Thumps do controle", - "create.subtitle.cranking": "Manivela gira", - "create.subtitle.sanding_short": "Sons de lixa", - "create.subtitle.wrench_rotate": "Chave inglesa usada", - "create.subtitle.potato_hit": "Impacto vegetal", - "create.subtitle.saw_activate_wood": "Serra mecânica ativa", - "create.subtitle.whistle_high": "Apito alto", - "create.subtitle.whistle_train_manual_low": "Buzinas de trem", - "create.subtitle.whistle_train": "Apito", - "create.subtitle.haunted_bell_convert": "Sino assombrado acorda", - "create.subtitle.train": "Tremer das rodas do trem", - "create.subtitle.deny": "Boop de negação", - "create.subtitle.controller_click": "Clicks do controle", - "create.subtitle.whistle_low": "Apito baixo", - "create.subtitle.copper_armor_equip": "Tilintar dos equipamentos de mergulho", - "create.subtitle.mechanical_press_activation": "Clang da prensa mecânica", - "create.subtitle.contraption_assemble": "Engenhoca move", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "Quando this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And Quando this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "Quando Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "Suporte de madeira", - "block.create.wooden_bracket.tooltip.summary": "_Decore_ seus _eixos, rodas dentadas_ e _canos_com um pedaço aconchegante e de madeira de reforço.", - - "block.create.metal_bracket.tooltip": "Suporte de ferro", - "block.create.metal_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with an industrial and sturdy bit of reinforcement.", - - "block.create.seat.tooltip": "Assento", - "block.create.seat.tooltip.summary": "UNLOCALIZED: Sit yourself down and enjoy the ride! Will anchor a player onto a moving _contraption_. Great for static furniture too! Comes in a variety of colours.", - "block.create.seat.tooltip.condition1": "UNLOCALIZED: Right click on Seat", - "block.create.seat.tooltip.behaviour1": "UNLOCALIZED: Sits the player on the _Seat_. Press L-shift to leave the _Seat_.", - - "item.create.blaze_cake.tooltip": "UNLOCALIZED: BLAZE CAKE", - "item.create.blaze_cake.tooltip.summary": "UNLOCALIZED: A Delicious treat for your hard-working _Blaze Burners_. Gets them all fired up!", - - "item.create.wand_of_symmetry.tooltip": "VARINHA DE SIMETRIA", - "item.create.wand_of_symmetry.tooltip.summary": "Espelhar perfeitamente a colocação de blocos nos planos configurados.", - "item.create.wand_of_symmetry.tooltip.condition1": "Quando na Hotbar", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Mantem-se Ativo", - "item.create.wand_of_symmetry.tooltip.control1": "B-Direito no Chão", - "item.create.wand_of_symmetry.tooltip.action1": "_Cria_ ou _Move_ o Espelho", - "item.create.wand_of_symmetry.tooltip.control2": "B-Direito no Ar", - "item.create.wand_of_symmetry.tooltip.action2": "_Remove_ o Espelho ativo", - "item.create.wand_of_symmetry.tooltip.control3": "B-Direito enquanto Abaixado", - "item.create.wand_of_symmetry.tooltip.action3": "Abre _Interface_ de _Configuração_", - - "item.create.handheld_worldshaper.tooltip": "UNLOCALIZED: HANDHELD WORLDSHAPER", - "item.create.handheld_worldshaper.tooltip.summary": "UNLOCALIZED: Handy tool for creating _landscapes_ and _terrain features_.", - "item.create.handheld_worldshaper.tooltip.control1": "UNLOCALIZED: L-Click at Block", - "item.create.handheld_worldshaper.tooltip.action1": "UNLOCALIZED: Sets blocks placed by the tool to the targeted block.", - "item.create.handheld_worldshaper.tooltip.control2": "UNLOCALIZED: R-Click at Block", - "item.create.handheld_worldshaper.tooltip.action2": "UNLOCALIZED: Applies the currently selected _Brush_ and _Tool_ at the targeted location.", - "item.create.handheld_worldshaper.tooltip.control3": "UNLOCALIZED: R-Click while Sneaking", - "item.create.handheld_worldshaper.tooltip.action3": "UNLOCALIZED: Opens the _Configuration Interface_", - - "item.create.tree_fertilizer.tooltip": "FERTILIZANTE DE ÁRVORE", - "item.create.tree_fertilizer.tooltip.summary": "Uma combinação poderosa de minerais para tipos comuns de árvores", - "item.create.tree_fertilizer.tooltip.condition1": "Quando usada em Mudas", - "item.create.tree_fertilizer.tooltip.behaviour1": "Cresce Árvores independentemente das suas Regras de espaço", - - "item.create.extendo_grip.tooltip": "UNLOCALIZED: EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "UNLOCALIZED: Boioioing! Greatly _increases reach distance_ of the wielder. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.extendo_grip.tooltip.condition1": "UNLOCALIZED: When in Off-Hand", - "item.create.extendo_grip.tooltip.behaviour1": "UNLOCALIZED: Increases _reach distance_ of items used in the _Main-Hand_.", - "item.create.extendo_grip.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.extendo_grip.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.potato_cannon.tooltip": "UNLOCALIZED: POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "UNLOCALIZED: Fwoomp! Launch your home-grown vegetables at your Enemies. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.potato_cannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "item.create.potato_cannon.tooltip.behaviour1": "UNLOCALIZED: _Shoots_ a suitable item from your _Inventory_.", - "item.create.potato_cannon.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.potato_cannon.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.filter.tooltip": "UNLOCALIZED: FILTER", - "item.create.filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of items_ or several _nested filters_.", - "item.create.filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.attribute_filter.tooltip": "UNLOCALIZED: ATTRIBUTE FILTER", - "item.create.attribute_filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of_ item _attributes_ and _categories_.", - "item.create.attribute_filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.attribute_filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.attribute_filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.attribute_filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.empty_schematic.tooltip": "ESQUEMA VAZIO", - "item.create.empty_schematic.tooltip.summary": "Usado como ingrediente em receitas e para escrever na _Mesa_ _de_ _Esquematizar_", - - "item.create.schematic.tooltip": "ESQUEMA", - "item.create.schematic.tooltip.summary": "Contém uma estrutura para ser posicionada e colocada no mundo. Posicione o Holograma como desejar e use um _Esquemaannon_ para construí-lo.", - "item.create.schematic.tooltip.condition1": "Quando Em mãos", - "item.create.schematic.tooltip.behaviour1": "Pode ser posicionado usando as Ferramentas em Tela", - "item.create.schematic.tooltip.control1": "B-Direito enquanto Abaixado", - "item.create.schematic.tooltip.action1": "Abre uma _Interface_ para informar as _Coordenadas_ exatas.", - - "item.create.schematic_and_quill.tooltip": "ESQUEMA E PENA", - "item.create.schematic_and_quill.tooltip.summary": "Usado para salvar uma Estrutura no mundo para um arquivo .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Passo 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selecione duas coordenadas de extremidade usando B-Direito", - "item.create.schematic_and_quill.tooltip.condition2": "Passo 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Rolar_ nas faces para ajustar o tamanho. B-Direito de novo para Salvar.", - "item.create.schematic_and_quill.tooltip.control1": "B-Direito", - "item.create.schematic_and_quill.tooltip.action1": "Selecione um canto / confirmar salvamento", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Pressionado", - "item.create.schematic_and_quill.tooltip.action2": "Selecione pontos no _meio_ _do_ _ar_. _Rolar_ para ajustar a distância.", - "item.create.schematic_and_quill.tooltip.control3": "B-Direito enquanto Abaixado", - "item.create.schematic_and_quill.tooltip.action3": "_Cancela_ e remove a seleção.", - - "block.create.schematicannon.tooltip": "Canhão de esquema", - "block.create.schematicannon.tooltip.summary": "Dispara blocos para recriar um _Esquema_ no Mundo. Usa itens de Inventários adjacentes e _Pólvora_ como combustível.", - "block.create.schematicannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "block.create.schematicannon.tooltip.behaviour1": "UNLOCALIZED: Opens the _Interface_", - - "block.create.schematic_table.tooltip": "MESA DE ESQUEMATIZAR", - "block.create.schematic_table.tooltip.summary": "Escreve Esquemas salvos into um _Esquema_ _Vazio_", - "block.create.schematic_table.tooltip.condition1": "Quando recebe um Esquema Vazio", - "block.create.schematic_table.tooltip.behaviour1": "Importa um Arquivo escolhido da sua Pasta de Esquemas", - - "item.create.goggles.tooltip": "UNLOCALIZED: GOGGLES", - "item.create.goggles.tooltip.summary": "UNLOCALIZED: A pair of glasses to augment your vision with useful _kinetic information_.", - "item.create.goggles.tooltip.condition1": "UNLOCALIZED: When worn", - "item.create.goggles.tooltip.behaviour1": "UNLOCALIZED: Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", - "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", - "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", - "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", - "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", - - "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", - "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", - "item.create.wrench.tooltip.control1": "UNLOCALIZED: Right-Click a kinetic block", - "item.create.wrench.tooltip.action1": "UNLOCALIZED: _Rotates components_ toward or away from the face with which you interacted.", - "item.create.wrench.tooltip.control2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.wrench.tooltip.action2": "UNLOCALIZED: _Disassembles Kinetic components_ and places them back in _your inventory_.", - - "block.create.nozzle.tooltip": "UNLOCALIZED: NOZZLE", - "block.create.nozzle.tooltip.summary": "UNLOCALIZED: Attach to the front of an _Encased Fan_ to distribute its effect on Entities in _all directions_.", - - "block.create.cuckoo_clock.tooltip": "UNLOCALIZED: CUCKOO CLOCK", - "block.create.cuckoo_clock.tooltip.summary": "UNLOCALIZED: Fine craftsmanship for _decorating_ a space and _keeping track of time_.", - "block.create.cuckoo_clock.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.cuckoo_clock.tooltip.behaviour1": "UNLOCALIZED: Shows the _current time_ and plays a tune twice a day. _Activates_ once at _noon_ and at dusk, as soon as _players can sleep_.", - - "block.create.turntable.tooltip": "MESA GIRATÓRIA", - "block.create.turntable.tooltip.summary": "Muda a _Força_ _Rotacional_ em uma forma refinada de Enjoo.", - - "block.create.toolbox.tooltip": "UNLOCALIZED: TOOLBOX", - "block.create.toolbox.tooltip.summary": "UNLOCALIZED: Every Inventors' dearest Companion. Conveniently _holds_ a large amount of _8 Different_ item types.", - "block.create.toolbox.tooltip.condition1": "UNLOCALIZED: When Picked Up", - "block.create.toolbox.tooltip.behaviour1": "UNLOCALIZED: _Retains_ Inventory _Contents_.", - "block.create.toolbox.tooltip.condition2": "UNLOCALIZED: When placed in Range", - "block.create.toolbox.tooltip.behaviour2": "UNLOCALIZED: _Nearby_ _Players_ can hold the _Toolbox_ _Keybind_ to access its contents _Remotely_.", - "block.create.toolbox.tooltip.condition3": "UNLOCALIZED: When R-Clicked", - "block.create.toolbox.tooltip.behaviour3": "UNLOCALIZED: Opens the _Container Interface_.", - - "block.create.stockpile_switch.tooltip": "DISJUNTOR DE ARMAZENAMENTO", - "block.create.stockpile_switch.tooltip.summary": "Alterna um sinal de Redstone com base no _Espaço_ de _Armazenamento_ do Reciente conectado.", - "block.create.stockpile_switch.tooltip.condition1": "Quando abaixo do Limite Mínimo", - "block.create.stockpile_switch.tooltip.behaviour1": "Para de enviar _Sinal_ de _Redstone_", - - "block.create.content_observer.tooltip": "UNLOCALIZED: CONTENT OBSERVER", - "block.create.content_observer.tooltip.summary": "UNLOCALIZED: _Detects Items_ or _Fluids_ inside _containers_, _pipes_ or _conveyors_ matching a configured _filter_.", - "block.create.content_observer.tooltip.condition1": "UNLOCALIZED: When observing a Container", - "block.create.content_observer.tooltip.behaviour1": "UNLOCALIZED: Emits a _Redstone Signal_ while the observed container has _matching_ _content_.", - "block.create.content_observer.tooltip.condition2": "UNLOCALIZED: When observing a Funnel", - "block.create.content_observer.tooltip.behaviour2": "UNLOCALIZED: Emits a _Redstone Pulse_ when a _matching_ Item is _transferred_.", - - "block.create.creative_crate.tooltip": "Caixa Criativa", - "block.create.creative_crate.tooltip.summary": "Provê um suprimento infinito de blocos para Canhões de Esquema próximos", - "block.create.creative_crate.tooltip.condition1": "UNLOCALIZED: When Item in Filter Slot", - "block.create.creative_crate.tooltip.behaviour1": "UNLOCALIZED: Anything _extracting_ from this container will provide an _endless supply_ of the item specified. Items _inserted_ into this crate will be _voided._", - - "item.create.creative_blaze_cake.tooltip": "UNLOCALIZED: CREATIVE CAKE", - "item.create.creative_blaze_cake.tooltip.summary": "UNLOCALIZED: A very special treat for your _Blaze Burners_. After eating this cake, Blaze Burners will _never run out of fuel_.", - "item.create.creative_blaze_cake.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.creative_blaze_cake.tooltip.behaviour1": "UNLOCALIZED: _Cycles_ a Blaze Burner's heat level.", - - "block.create.controller_rail.tooltip": "UNLOCALIZED: CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "UNLOCALIZED: A _uni-directional powered rail_ capable of _fine control_ over a minecarts' _movement speed_.", - "block.create.controller_rail.tooltip.condition1": "UNLOCALIZED: When Powered by Redstone", - "block.create.controller_rail.tooltip.behaviour1": "UNLOCALIZED: _Accelerates_ or _Decelerates_ passing _minecarts_ corresponding to the _signal strength_. Propagates redstone power to adjacent controller rails. Powering two controller rails with different strengths will cause tracks between them to interpolate their signal.", - - "item.create.sand_paper.tooltip": "UNLOCALIZED: SAND PAPER", - "item.create.sand_paper.tooltip.summary": "UNLOCALIZED: A rough paper that can be used to _polish materials_. Can be automatically applied using the Deployer.", - "item.create.sand_paper.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.sand_paper.tooltip.behaviour1": "UNLOCALIZED: Applies polish to items held in the _offhand_ or lying on the _floor_ when _looking at them_", - - "item.create.builders_tea.tooltip": "UNLOCALIZED: BUILDERS TEA", - "item.create.builders_tea.tooltip.summary": "UNLOCALIZED: The perfect drink to get the day started- _Motivating_ and _Saturating._", - - "item.create.refined_radiance.tooltip": "UNLOCALIZED: REFINED RADIANCE", - "item.create.refined_radiance.tooltip.summary": "UNLOCALIZED: A Chromatic material forged from _absorbed light_.", - "item.create.refined_radiance.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.shadow_steel.tooltip": "UNLOCALIZED: SHADOW STEEL", - "item.create.shadow_steel.tooltip.summary": "UNLOCALIZED: A Chromatic material forged _in the void_.", - "item.create.shadow_steel.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.linked_controller.tooltip": "UNLOCALIZED: LINKED CONTROLLER", - "item.create.linked_controller.tooltip.summary": "UNLOCALIZED: Grants _handheld_ _control_ over _Redstone Link_ frequencies assigned to its _six_ _buttons_.", - "item.create.linked_controller.tooltip.condition1": "UNLOCALIZED: R-Click", - "item.create.linked_controller.tooltip.behaviour1": "UNLOCALIZED: _Toggles_ the controller. _Movement_ _controls_ are taken over while its active.", - "item.create.linked_controller.tooltip.condition2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.linked_controller.tooltip.behaviour2": "UNLOCALIZED: Opens the manual _Configuration Interface_.", - "item.create.linked_controller.tooltip.condition3": "UNLOCALIZED: R-Click on Redstone Link Receiver", - "item.create.linked_controller.tooltip.behaviour3": "UNLOCALIZED: Enables _Bind Mode_, press one of the _six controls_ to bind it to the _Links' Frequency_.", - "item.create.linked_controller.tooltip.condition4": "UNLOCALIZED: R-Click on Lectern", - "item.create.linked_controller.tooltip.behaviour4": "UNLOCALIZED: Places the Controller into the Lectern for easy activation. (R-Click while Sneaking to retrieve it)", - - "item.create.diving_helmet.tooltip": "UNLOCALIZED: DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "UNLOCALIZED: Together with a _Copper_ _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", - "item.create.diving_helmet.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_helmet.tooltip.behaviour1": "UNLOCALIZED: Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", - - "item.create.copper_backtank.tooltip": "UNLOCALIZED: COPPER BACKTANK", - "item.create.copper_backtank.tooltip.summary": "UNLOCALIZED: A _Wearable_ _Tank_ for carrying Pressurized Air.", - "item.create.copper_backtank.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.copper_backtank.tooltip.behaviour1": "UNLOCALIZED: Provides _Pressurized_ _Air_ to Equipment that requires it.", - "item.create.copper_backtank.tooltip.condition2": "UNLOCALIZED: When placed, Powered by Kinetics", - "item.create.copper_backtank.tooltip.behaviour2": "UNLOCALIZED: _Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "UNLOCALIZED: DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "UNLOCALIZED: A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", - "item.create.diving_boots.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_boots.tooltip.behaviour1": "UNLOCALIZED: Wielder _sinks_ _faster_ and _cannot_ _swim_. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", - - "item.create.crafting_blueprint.tooltip": "UNLOCALIZED: CRAFTING BLUEPRINT", - "item.create.crafting_blueprint.tooltip.summary": "UNLOCALIZED: _Placed_ on a wall, it can be used to _specify_ _ingredient_ _arrangements_ for easier manual crafting. Each slot represents a Recipe.", - "item.create.crafting_blueprint.condition1": "UNLOCALIZED: R-Click empty Slot", - "item.create.crafting_blueprint.behaviour1": "UNLOCALIZED: Opens a _Crafting_ _menu_ allowing you to _configure_ a _recipe_ and items to display.", - "item.create.crafting_blueprint.condition2": "UNLOCALIZED: R-Click configured Slot", - "item.create.crafting_blueprint.behaviour2": "UNLOCALIZED: _Applies_ the _configured_ _recipe_ with matching Ingredients found in your _Inventory_. _Sneak_ to craft up to a _Stack_ of items.", - - "item.create.minecart_coupling.tooltip": "UNLOCALIZED: MINECART COUPLING", - "item.create.minecart_coupling.tooltip.summary": "UNLOCALIZED: _Chains_ all your _Minecarts_ or _Carriage Contraptions_ together to form a majestic Train.", - "item.create.minecart_coupling.tooltip.condition1": "UNLOCALIZED: When Used on Minecart", - "item.create.minecart_coupling.tooltip.behaviour1": "UNLOCALIZED: _Couples_ two Minecarts together, attempting to keep them at a _constant distance_ while moving.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "UNLOCALIZED: PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "UNLOCALIZED: A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may cause side-effects...", - - "block.create.haunted_bell.tooltip": "UNLOCALIZED: HAUNTED BELL", - "block.create.haunted_bell.tooltip.summary": "UNLOCALIZED: A _Cursed Bell_ haunted by lost souls of the Nether.", - "block.create.haunted_bell.tooltip.condition1": "UNLOCALIZED: When Held or Rang", - "block.create.haunted_bell.tooltip.behaviour1": "UNLOCALIZED: Highlights nearby _Lightless Spots_ on which _Hostile Mobs_ can spawn.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", - "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", - "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", - "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", - "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", - "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Super Glue, larger structures can be moved.", - "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", - "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", - "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", - "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", - "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", - "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", - "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", - "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", - "create.ponder.tag.windmill_sails": "UNLOCALIZED: Sails for Windmill Bearings", - "create.ponder.tag.windmill_sails.description": "UNLOCALIZED: Blocks that count towards the strength of a Windmill Contraption when assembled. Each of these have equal efficiency in doing so.", - "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", - "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", - "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", - "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", - "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", - "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", - "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", - "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", - "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", - "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", - "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", - "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", - "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", - "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", - "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", - "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", - "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", - "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", - - "create.ponder.andesite_tunnel.header": "UNLOCALIZED: Using Andesite Tunnels", - "create.ponder.andesite_tunnel.text_1": "UNLOCALIZED: Andesite Tunnels can be used to cover up your belts", - "create.ponder.andesite_tunnel.text_2": "UNLOCALIZED: Whenever an Andesite Tunnel has connections to the sides...", - "create.ponder.andesite_tunnel.text_3": "UNLOCALIZED: ...they will split exactly one item off of any passing stacks", - "create.ponder.andesite_tunnel.text_4": "UNLOCALIZED: The remainder will continue on its path", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "UNLOCALIZED: Processing Items in the Basin", - "create.ponder.basin.text_1": "UNLOCALIZED: A Basin can hold Items and Fluids for Processing", - "create.ponder.basin.text_2": "UNLOCALIZED: After a processing step, basins try to output below to the side of them", - "create.ponder.basin.text_3": "UNLOCALIZED: When a valid component is present, the Basin will show an output faucet", - "create.ponder.basin.text_4": "UNLOCALIZED: A number of options are applicable here", - "create.ponder.basin.text_5": "UNLOCALIZED: Outputs will be caught by the inventory below", - "create.ponder.basin.text_6": "UNLOCALIZED: Without output faucet, the Basin will retain items created in its processing", - "create.ponder.basin.text_7": "UNLOCALIZED: This can be useful if outputs should be re-used as ingredients", - "create.ponder.basin.text_8": "UNLOCALIZED: Desired outputs will then have to be extracted from the basin", - "create.ponder.basin.text_9": "UNLOCALIZED: A Filter might be necessary to avoid pulling out un-processed items", - - "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", - "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", - "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", - - "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", - "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", - "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", - - "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", - "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", - "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", - "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", - "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", - "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", - "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", - - "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", - "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", - "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", - "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", - "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", - "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", - "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions. Belts can span any Length between 2 and 20 blocks", - - "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", - "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", - "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", - - "create.ponder.blaze_burner.header": "UNLOCALIZED: Feeding Blaze Burners", - "create.ponder.blaze_burner.text_1": "UNLOCALIZED: Blaze Burners can provide Heat to Items processed in a Basin", - "create.ponder.blaze_burner.text_2": "UNLOCALIZED: For this, the Blaze has to be fed with flammable items", - "create.ponder.blaze_burner.text_3": "UNLOCALIZED: With a Blaze Cake, the Burner can reach an even stronger level of heat", - "create.ponder.blaze_burner.text_4": "UNLOCALIZED: The feeding process can be automated using Deployers or Mechanical Arms", - - "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", - "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", - "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", - "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", - - "create.ponder.brass_tunnel.header": "UNLOCALIZED: Using Brass Tunnels", - "create.ponder.brass_tunnel.text_1": "UNLOCALIZED: Brass Tunnels can be used to cover up your belts", - "create.ponder.brass_tunnel.text_2": "UNLOCALIZED: Brass Tunnels have filter slots on each open side", - "create.ponder.brass_tunnel.text_3": "UNLOCALIZED: Filters on inbound connections simply block non-matching items", - "create.ponder.brass_tunnel.text_4": "UNLOCALIZED: Filters on outbound connections can be used to sort items by type", - "create.ponder.brass_tunnel.text_5": "UNLOCALIZED: Whenever a passing item has multiple valid exits, the distribution mode will decide how to handle it", - "create.ponder.brass_tunnel.text_6": "UNLOCALIZED: Brass Tunnels on parallel belts will form a group", - "create.ponder.brass_tunnel.text_7": "UNLOCALIZED: Incoming Items will now be distributed across all connected exits", - "create.ponder.brass_tunnel.text_8": "UNLOCALIZED: For this, items can also be inserted into the Tunnel block directly", - - "create.ponder.brass_tunnel_modes.header": "UNLOCALIZED: Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "UNLOCALIZED: Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", - "create.ponder.brass_tunnel_modes.text_10": "UNLOCALIZED: 'Synchronize Inputs' is a unique setting for Brass Tunnels", - "create.ponder.brass_tunnel_modes.text_11": "UNLOCALIZED: Items are only allowed past if every tunnel in the group has one waiting", - "create.ponder.brass_tunnel_modes.text_12": "UNLOCALIZED: This ensures that all affected belts supply items at the same rate", - "create.ponder.brass_tunnel_modes.text_2": "UNLOCALIZED: 'Split' will attempt to distribute the stack evenly between available outputs", - "create.ponder.brass_tunnel_modes.text_3": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_4": "UNLOCALIZED: 'Forced Split' will never skip outputs, and instead wait until they are free", - "create.ponder.brass_tunnel_modes.text_5": "UNLOCALIZED: 'Round Robin' keeps stacks whole, and cycles through outputs iteratively", - "create.ponder.brass_tunnel_modes.text_6": "UNLOCALIZED: Once Again, if an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_7": "UNLOCALIZED: 'Forced Round Robin' never skips outputs", - "create.ponder.brass_tunnel_modes.text_8": "UNLOCALIZED: 'Prefer Nearest' prioritizes the outputs closest to the items' input location", - "create.ponder.brass_tunnel_modes.text_9": "UNLOCALIZED: 'Randomize' will distribute whole stacks to randomly picked outputs", - - "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", - "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", - "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", - "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", - - "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", - "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", - "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", - "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", - - "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", - "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", - "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: This Arrow indicates which side of the Structure will be considered the front", - "create.ponder.cart_assembler_modes.text_3": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", - - "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", - "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", - "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", - "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", - "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", - - "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", - "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", - "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", - "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", - - "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", - "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exactly like Chain Drives", - "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", - "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", - "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", - "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", - "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", - - "create.ponder.chute.header": "UNLOCALIZED: Transporting Items downward via Chutes", - "create.ponder.chute.text_1": "UNLOCALIZED: Chutes can transport items vertically from and to inventories", - "create.ponder.chute.text_2": "UNLOCALIZED: Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "UNLOCALIZED: Placing chutes targeting the side faces of another will make it diagonal", - - "create.ponder.chute_upward.header": "UNLOCALIZED: Transporting Items upward via Chutes", - "create.ponder.chute_upward.text_1": "UNLOCALIZED: Using Encased Fans at the top or bottom, a Chute can move items upward", - "create.ponder.chute_upward.text_2": "UNLOCALIZED: Inspecting chutes with Engineers' Goggles reveals information about the movement direction", - "create.ponder.chute_upward.text_3": "UNLOCALIZED: On the 'blocked' end, items will have to be inserted/taken from the sides", - - "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", - "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", - "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", - "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", - "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", - "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", - "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", - "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure that the two Structures are not glued to each other", - "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", - - "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", - "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", - "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", - - "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", - "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", - "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", - "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", - - "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", - "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", - "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "UNLOCALIZED: Creative Fluid Tanks", - "create.ponder.creative_fluid_tank.text_1": "UNLOCALIZED: Creative Fluid Tanks can be used to provide a bottomless supply of fluid", - "create.ponder.creative_fluid_tank.text_2": "UNLOCALIZED: Right-Click with a fluid containing item to configure it", - "create.ponder.creative_fluid_tank.text_3": "UNLOCALIZED: Pipe Networks can now endlessly draw the assigned fluid from the tank", - "create.ponder.creative_fluid_tank.text_4": "UNLOCALIZED: Any Fluids pushed back into a Creative Fluid Tank will be voided", - - "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", - "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "UNLOCALIZED: Processing Items with Crushing Wheels", - "create.ponder.crushing_wheels.text_1": "UNLOCALIZED: A pair of Crushing Wheels can grind items very effectively", - "create.ponder.crushing_wheels.text_2": "UNLOCALIZED: Their Rotational Input has to make them spin into each other", - "create.ponder.crushing_wheels.text_3": "UNLOCALIZED: Items thrown or inserted into the top will get processed", - "create.ponder.crushing_wheels.text_4": "UNLOCALIZED: Items can be inserted and picked up through automated means as well", - - "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", - "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", - "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", - "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", - "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", - "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", - "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", - "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", - "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", - "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", - "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", - "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", - "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", - "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", - "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", - "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", - - "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", - "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", - "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", - "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", - - "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", - "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", - "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", - - "create.ponder.deployer_processing.header": "UNLOCALIZED: Processing Items using Deployers", - "create.ponder.deployer_processing.text_1": "UNLOCALIZED: With a fitting held item, Deployers can process items provided beneath them", - "create.ponder.deployer_processing.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Deployer", - "create.ponder.deployer_processing.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.deployer_processing.text_4": "UNLOCALIZED: The Deployer will hold and process them automatically", - - "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", - "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", - "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", - "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.depot.header": "UNLOCALIZED: Using Depots", - "create.ponder.depot.text_1": "UNLOCALIZED: Depots can serve as 'stationary' belt elements", - "create.ponder.depot.text_2": "UNLOCALIZED: Right-Click to manually place or remove Items from it", - "create.ponder.depot.text_3": "UNLOCALIZED: Just like Mechanical Belts, it can provide items to processing", - "create.ponder.depot.text_4": "UNLOCALIZED: ...as well as provide Items to Mechanical Arms", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "UNLOCALIZED: Using Empty Blaze Burners", - "create.ponder.empty_blaze_burner.text_1": "UNLOCALIZED: Right-click a Blaze with the empty burner to capture it", - "create.ponder.empty_blaze_burner.text_2": "UNLOCALIZED: Alternatively, Blazes can be collected from their Spawners directly", - "create.ponder.empty_blaze_burner.text_3": "UNLOCALIZED: You now have an ideal heat source for various machines", - "create.ponder.empty_blaze_burner.text_4": "UNLOCALIZED: For Aesthetic purposes, Empty Blaze Burners can also be lit using Flint and Steel", - "create.ponder.empty_blaze_burner.text_5": "UNLOCALIZED: The flame can be transformed using a soul-infused item", - "create.ponder.empty_blaze_burner.text_6": "UNLOCALIZED: However, without a blaze they are not suitable for industrial heating", - - "create.ponder.encased_fluid_pipe.header": "UNLOCALIZED: Encasing Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_1": "UNLOCALIZED: Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "UNLOCALIZED: Aside from being conceiled, Encased Pipes are locked into their connectivity state", - "create.ponder.encased_fluid_pipe.text_3": "UNLOCALIZED: It will no longer react to any neighbouring blocks being added or removed", - - "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", - "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", - - "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", - "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", - "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", - "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", - "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", - "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", - "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", - "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", - - "create.ponder.fluid_pipe_flow.header": "UNLOCALIZED: Moving Fluids using Copper Pipes", - "create.ponder.fluid_pipe_flow.text_1": "UNLOCALIZED: Fluid Pipes can connect two or more fluid sources and targets", - "create.ponder.fluid_pipe_flow.text_2": "UNLOCALIZED: Using a wrench, a straight pipe segment can be given a window", - "create.ponder.fluid_pipe_flow.text_3": "UNLOCALIZED: Windowed pipes will not connect to any other adjacent pipe segments", - "create.ponder.fluid_pipe_flow.text_4": "UNLOCALIZED: Powered by Mechanical Pumps, the Pipes can transport Fluids", - "create.ponder.fluid_pipe_flow.text_5": "UNLOCALIZED: No fluid is being extracted at first", - "create.ponder.fluid_pipe_flow.text_6": "UNLOCALIZED: Once the flow connects them, the endpoints gradually transfer their contents", - "create.ponder.fluid_pipe_flow.text_7": "UNLOCALIZED: Thus, the Pipe blocks themselves never 'physically' contain any fluid", - - "create.ponder.fluid_pipe_interaction.header": "UNLOCALIZED: Draining and Filling fluid containers", - "create.ponder.fluid_pipe_interaction.text_1": "UNLOCALIZED: Endpoints of a pipe network can interact with a variety of blocks", - "create.ponder.fluid_pipe_interaction.text_2": "UNLOCALIZED: Any block with fluid storage capabilities can be filled or drained", - "create.ponder.fluid_pipe_interaction.text_3": "UNLOCALIZED: Source blocks right in front of an open end can be picked up...", - "create.ponder.fluid_pipe_interaction.text_4": "UNLOCALIZED: ...while spilling into empty spaces can create fluid sources", - "create.ponder.fluid_pipe_interaction.text_5": "UNLOCALIZED: Pipes can also extract fluids from a handful of other blocks directly", - - "create.ponder.fluid_tank_sizes.header": "UNLOCALIZED: Dimensions of a Fluid tank", - "create.ponder.fluid_tank_sizes.text_1": "UNLOCALIZED: Fluid Tanks can be combined to increase the total capacity", - "create.ponder.fluid_tank_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.fluid_tank_sizes.text_3": "UNLOCALIZED: ...and grow in height by more than 30 additional layers", - "create.ponder.fluid_tank_sizes.text_4": "UNLOCALIZED: Using a Wrench, a tanks' window can be toggled", - - "create.ponder.fluid_tank_storage.header": "UNLOCALIZED: Storing Fluids in Fluid Tanks", - "create.ponder.fluid_tank_storage.text_1": "UNLOCALIZED: Fluid Tanks can be used to store large amounts of fluid", - "create.ponder.fluid_tank_storage.text_2": "UNLOCALIZED: Pipe networks can push and pull fluids from any side", - "create.ponder.fluid_tank_storage.text_3": "UNLOCALIZED: The contained fluid can be measured by a Comparator", - "create.ponder.fluid_tank_storage.text_4": "UNLOCALIZED: However, in Survival Mode Fluids cannot be added or taken manually", - "create.ponder.fluid_tank_storage.text_5": "UNLOCALIZED: You can use Basins, Item Drains and Spouts to drain or fill fluid containing items", - - "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", - "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", - "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", - "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", - "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", - - "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", - "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", - "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", - "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", - "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", - "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", - - "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", - "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", - - "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", - "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting", - - "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", - "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", - "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", - "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement. A mechanical belt should help here.", - - "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", - "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", - "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", - "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", - "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", - "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", - - "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", - "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", - "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", - "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", - "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", - - "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", - "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", - "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", - - "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", - "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", - "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", - "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", - "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", - "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", - "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", - - "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", - "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", - "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", - - "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", - "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", - "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - - "create.ponder.hose_pulley.header": "UNLOCALIZED: Source Filling and Draining using Hose Pulleys", - "create.ponder.hose_pulley.text_1": "UNLOCALIZED: Hose Pulleys can be used to fill or drain large bodies of Fluid", - "create.ponder.hose_pulley.text_2": "UNLOCALIZED: With the Kinetic Input, the height of the pulleys' hose can be controlled", - "create.ponder.hose_pulley.text_3": "UNLOCALIZED: The Pulley retracts while the input rotation is inverted", - "create.ponder.hose_pulley.text_4": "UNLOCALIZED: On the opposite side, pipes can be connected", - "create.ponder.hose_pulley.text_5": "UNLOCALIZED: Attached pipe networks can either provide fluid to the hose...", - "create.ponder.hose_pulley.text_6": "UNLOCALIZED: ...or pull from it, draining the pool instead", - "create.ponder.hose_pulley.text_7": "UNLOCALIZED: Fill and Drain speed of the pulley depends entirely on the fluid networks' throughput", - - "create.ponder.hose_pulley_infinite.header": "UNLOCALIZED: Passively Filling and Draining large bodies of Fluid", - "create.ponder.hose_pulley_infinite.text_1": "UNLOCALIZED: When deploying the Hose Pulley into a large enough ocean...", - "create.ponder.hose_pulley_infinite.text_2": "UNLOCALIZED: It will provide/dispose fluids without affecting the source", - "create.ponder.hose_pulley_infinite.text_3": "UNLOCALIZED: Pipe networks can limitlessly take fluids from/to such pulleys", - - "create.ponder.hose_pulley_level.header": "UNLOCALIZED: Fill and Drain level of Hose Pulleys", - "create.ponder.hose_pulley_level.text_1": "UNLOCALIZED: While fully retracted, the Hose Pulley cannot operate", - "create.ponder.hose_pulley_level.text_2": "UNLOCALIZED: Draining runs from top to bottom", - "create.ponder.hose_pulley_level.text_3": "UNLOCALIZED: The surface level will end up just below where the hose ends", - "create.ponder.hose_pulley_level.text_4": "UNLOCALIZED: Filling runs from bottom to top", - "create.ponder.hose_pulley_level.text_5": "UNLOCALIZED: The filled pool will not grow beyond the layer above the hose end", - - "create.ponder.item_drain.header": "UNLOCALIZED: Emptying Fluid Containers using Item Drains", - "create.ponder.item_drain.text_1": "UNLOCALIZED: Item Drains can extract fluids from items", - "create.ponder.item_drain.text_2": "UNLOCALIZED: Right-click it to pour fluids from your held item into it", - "create.ponder.item_drain.text_3": "UNLOCALIZED: When items are inserted from the side...", - "create.ponder.item_drain.text_4": "UNLOCALIZED: ...they roll across, emptying out their contained fluid", - "create.ponder.item_drain.text_5": "UNLOCALIZED: Pipe Networks can now pull the fluid from the drains' internal buffer", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", - "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", - "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", - - "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", - "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", - "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", - "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", - "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", - "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", - - "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "UNLOCALIZED: Setting up Mechanical Arms", - "create.ponder.mechanical_arm.text_1": "UNLOCALIZED: Mechanical Arms have to be assigned their in- and outputs before they are placed", - "create.ponder.mechanical_arm.text_2": "UNLOCALIZED: Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "UNLOCALIZED: Right-Click again to toggle between Input (Blue) and Output (Orange)", - "create.ponder.mechanical_arm.text_4": "UNLOCALIZED: Left-Click components to remove their Selection", - "create.ponder.mechanical_arm.text_5": "UNLOCALIZED: Once placed, the Mechanical Arm will target the blocks selected previously", - "create.ponder.mechanical_arm.text_6": "UNLOCALIZED: They can have any amount of in- and outputs within their range", - "create.ponder.mechanical_arm.text_7": "UNLOCALIZED: However, not every type of Inventory can be interacted with directly", - "create.ponder.mechanical_arm.text_8": "UNLOCALIZED: Funnels and Depots can help to Bridge that gap", - - "create.ponder.mechanical_arm_filtering.header": "UNLOCALIZED: Filtering Outputs of the Mechanical Arm", - "create.ponder.mechanical_arm_filtering.text_1": "UNLOCALIZED: Inputs", - "create.ponder.mechanical_arm_filtering.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_filtering.text_3": "UNLOCALIZED: Sometimes it is desirable to restrict targets of the Arm by matching a filter", - "create.ponder.mechanical_arm_filtering.text_4": "UNLOCALIZED: Mechanical Arms by themselves do not provide any options for filtering", - "create.ponder.mechanical_arm_filtering.text_5": "UNLOCALIZED: Brass Funnels as Targets do however communicate their own filter to the Arm", - "create.ponder.mechanical_arm_filtering.text_6": "UNLOCALIZED: The Arm is smart enough not to pick up items it couldn't distribute", - - "create.ponder.mechanical_arm_modes.header": "UNLOCALIZED: Distribution modes of the Mechanical Arm", - "create.ponder.mechanical_arm_modes.text_1": "UNLOCALIZED: Input", - "create.ponder.mechanical_arm_modes.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_modes.text_3": "UNLOCALIZED: Whenever an Arm has to choose between multiple valid outputs...", - "create.ponder.mechanical_arm_modes.text_4": "UNLOCALIZED: ...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "UNLOCALIZED: Scrolling with a Wrench will allow you to configure it", - "create.ponder.mechanical_arm_modes.text_6": "UNLOCALIZED: Round Robin mode simply cycles through all outputs that are available", - "create.ponder.mechanical_arm_modes.text_7": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.mechanical_arm_modes.text_8": "UNLOCALIZED: Forced Round Robin mode will never skip outputs, and instead wait until they are free", - "create.ponder.mechanical_arm_modes.text_9": "UNLOCALIZED: Prefer First prioritizes the outputs selected earliest when configuring this Arm", - - "create.ponder.mechanical_arm_redstone.header": "UNLOCALIZED: Controlling Mechanical Arms with Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Mechanical Arms will not activate", - "create.ponder.mechanical_arm_redstone.text_2": "UNLOCALIZED: Before stopping, it will finish any started cycles", - "create.ponder.mechanical_arm_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", - "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", - "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", - - "create.ponder.mechanical_crafter.header": "UNLOCALIZED: Setting up Mechanical Crafters", - "create.ponder.mechanical_crafter.text_1": "UNLOCALIZED: An array of Mechanical Crafters can be used to automate any Crafting Recipe", - "create.ponder.mechanical_crafter.text_2": "UNLOCALIZED: Using a Wrench, the Crafters' paths can be arranged", - "create.ponder.mechanical_crafter.text_3": "UNLOCALIZED: For a valid setup, all paths have to converge into one exit at any side", - "create.ponder.mechanical_crafter.text_4": "UNLOCALIZED: The outputs will be placed into the inventory at the exit", - "create.ponder.mechanical_crafter.text_5": "UNLOCALIZED: Mechanical Crafters require Rotational Force to operate", - "create.ponder.mechanical_crafter.text_6": "UNLOCALIZED: Right-Click the front to insert Items manually", - "create.ponder.mechanical_crafter.text_7": "UNLOCALIZED: Once every slot of a path contains an Item, the crafting process will begin", - "create.ponder.mechanical_crafter.text_8": "UNLOCALIZED: For recipes not fully occupying the crafter setup, the start can be forced using a Redstone Pulse", - - "create.ponder.mechanical_crafter_connect.header": "UNLOCALIZED: Connecting Inventories of Crafters", - "create.ponder.mechanical_crafter_connect.text_1": "UNLOCALIZED: Items can be inserted to Crafters automatically", - "create.ponder.mechanical_crafter_connect.text_2": "UNLOCALIZED: Using the Wrench at their backs, Mechanical Crafter inputs can be combined", - "create.ponder.mechanical_crafter_connect.text_3": "UNLOCALIZED: All connected Crafters can now be accessed by the same input location", - - "create.ponder.mechanical_crafter_covers.header": "UNLOCALIZED: Covering slots of Mechanical Crafters", - "create.ponder.mechanical_crafter_covers.text_1": "UNLOCALIZED: Some recipes will require additional Crafters to bridge gaps in the path", - "create.ponder.mechanical_crafter_covers.text_2": "UNLOCALIZED: Using Slot Covers, Crafters can be set to act as an Empty Slot in the arrangement", - "create.ponder.mechanical_crafter_covers.text_3": "UNLOCALIZED: Shared Inputs created with the Wrench at the back can also reach across covered Crafters", - - "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", - "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", - "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", - - "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", - "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", - "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", - - "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", - "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", - "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", - - "create.ponder.mechanical_mixer.header": "UNLOCALIZED: Processing Items with the Mechanical Mixer", - "create.ponder.mechanical_mixer.text_1": "UNLOCALIZED: With a Mixer and Basin, some Crafting Recipes can be automated", - "create.ponder.mechanical_mixer.text_2": "UNLOCALIZED: Available recipes include any Shapeless Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_mixer.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_mixer.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", - "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", - "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", - "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", - - "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", - "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", - "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", - "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", - "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", - "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", - "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", - - "create.ponder.mechanical_press.header": "UNLOCALIZED: Processing Items with the Mechanical Press", - "create.ponder.mechanical_press.text_1": "UNLOCALIZED: The Mechanical Press can process items provided beneath it", - "create.ponder.mechanical_press.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Press", - "create.ponder.mechanical_press.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.mechanical_press.text_4": "UNLOCALIZED: The Press will hold and process them automatically", - - "create.ponder.mechanical_press_compacting.header": "UNLOCALIZED: Compacting items with the Mechanical Press", - "create.ponder.mechanical_press_compacting.text_1": "UNLOCALIZED: Pressing items held in a Basin will cause them to be Compacted", - "create.ponder.mechanical_press_compacting.text_2": "UNLOCALIZED: Compacting includes any filled 2x2 or 3x3 Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_press_compacting.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_press_compacting.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_pump_flow.header": "UNLOCALIZED: Fluid Transportation using Mechanical Pumps", - "create.ponder.mechanical_pump_flow.text_1": "UNLOCALIZED: Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "UNLOCALIZED: When powered, their arrow indicates the direction of flow", - "create.ponder.mechanical_pump_flow.text_3": "UNLOCALIZED: The network behind is now pulling fluids...", - "create.ponder.mechanical_pump_flow.text_4": "UNLOCALIZED: ...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "UNLOCALIZED: Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "UNLOCALIZED: Use a Wrench to reverse the orientation of pumps manually", - - "create.ponder.mechanical_pump_speed.header": "UNLOCALIZED: Throughput of Mechanical Pumps", - "create.ponder.mechanical_pump_speed.text_1": "UNLOCALIZED: Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", - "create.ponder.mechanical_pump_speed.text_2": "UNLOCALIZED: Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "UNLOCALIZED: ...aswell as how quickly fluids are transferred", - "create.ponder.mechanical_pump_speed.text_4": "UNLOCALIZED: Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "UNLOCALIZED: Alternating their orientation can help align their flow directions", - - "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", - "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", - "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", - - "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", - "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", - "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", - - "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", - "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", - "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", - "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", - "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", - "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", - - "create.ponder.millstone.header": "UNLOCALIZED: Processing Items in the Millstone", - "create.ponder.millstone.text_1": "UNLOCALIZED: Millstones process items by grinding them", - "create.ponder.millstone.text_2": "UNLOCALIZED: They can be powered from the side using cogwheels", - "create.ponder.millstone.text_3": "UNLOCALIZED: Throw or Insert items at the top", - "create.ponder.millstone.text_4": "UNLOCALIZED: After some time, the result can be obtained via Right-click", - "create.ponder.millstone.text_5": "UNLOCALIZED: The outputs can also be extracted by automation", - - "create.ponder.nixie_tube.header": "UNLOCALIZED: Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "UNLOCALIZED: When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "UNLOCALIZED: Using name tags edited with an anvil, custom text can be displayed", - "create.ponder.nixie_tube.text_3": "UNLOCALIZED: Right-Click with Dye to change their display colour", - - "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", - "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", - "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", - - "create.ponder.portable_fluid_interface.header": "UNLOCALIZED: Contraption Fluid Exchange", - "create.ponder.portable_fluid_interface.text_1": "UNLOCALIZED: Fluid Tanks on moving contraptions cannot be accessed by any pipes", - "create.ponder.portable_fluid_interface.text_2": "UNLOCALIZED: This component can interact with fluid tanks without the need to stop the contraption", - "create.ponder.portable_fluid_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_fluid_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_fluid_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL Tanks on the contraption", - "create.ponder.portable_fluid_interface.text_6": "UNLOCALIZED: Fluid can now be inserted...", - "create.ponder.portable_fluid_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_fluid_interface.text_8": "UNLOCALIZED: After no contents have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", - "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", - "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", - "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", - - "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", - "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", - "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", - "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", - "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", - - "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", - "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", - "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", - "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", - "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", - "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", - "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", - "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", - "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", - "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", - "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", - "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", - - "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", - "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", - "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", - - "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", - "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", - "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", - "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", - "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", - "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", - "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", - - "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", - "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", - "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", - - "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", - "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", - "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", - "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", - - "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", - "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", - "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", - "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", - - "create.ponder.sail.header": "UNLOCALIZED: Assembling Windmills using Sails", - "create.ponder.sail.text_1": "UNLOCALIZED: Sails are handy blocks to create Windmills with", - "create.ponder.sail.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - "create.ponder.sail.text_3": "UNLOCALIZED: Right-Click with Dye to paint them", - "create.ponder.sail.text_4": "UNLOCALIZED: Right-Click with Shears to turn them back into frames", - - "create.ponder.sail_frame.header": "UNLOCALIZED: Assembling Windmills using Sail Frames", - "create.ponder.sail_frame.text_1": "UNLOCALIZED: Sail Frames are handy blocks to create Windmills with", - "create.ponder.sail_frame.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", - "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", - "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", - "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", - "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", - "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", - - "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", - "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", - - "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", - "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", - - "create.ponder.smart_chute.header": "UNLOCALIZED: Filtering Items using Smart Chutes", - "create.ponder.smart_chute.text_1": "UNLOCALIZED: Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "UNLOCALIZED: Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "UNLOCALIZED: Use the Mouse Wheel to specify the extracted stack size", - "create.ponder.smart_chute.text_4": "UNLOCALIZED: Redstone power will prevent Smart Chutes from acting.", - - "create.ponder.smart_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Smart Pipes", - "create.ponder.smart_pipe.text_1": "UNLOCALIZED: Smart pipes can help control flows by fluid type", - "create.ponder.smart_pipe.text_2": "UNLOCALIZED: When placed directly at the source, they can specify the type of fluid to extract", - "create.ponder.smart_pipe.text_3": "UNLOCALIZED: Simply Right-Click their filter slot with any item containing the desired fluid", - "create.ponder.smart_pipe.text_4": "UNLOCALIZED: When placed further down a pipe network, smart pipes will only let matching fluids continue", - - "create.ponder.speedometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "UNLOCALIZED: The Speedometer displays the current Speed of the attached components", - "create.ponder.speedometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.speedometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Speedometer's measurements", - - "create.ponder.spout_filling.header": "UNLOCALIZED: Filling Items using a Spout", - "create.ponder.spout_filling.text_1": "UNLOCALIZED: The Spout can fill fluid holding items provided beneath it", - "create.ponder.spout_filling.text_2": "UNLOCALIZED: The content of a Spout cannot be accessed manually", - "create.ponder.spout_filling.text_3": "UNLOCALIZED: Instead, Pipes can be used to supply it with fluids", - "create.ponder.spout_filling.text_4": "UNLOCALIZED: The Input items can be placed on a Depot under the Spout", - "create.ponder.spout_filling.text_5": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.spout_filling.text_6": "UNLOCALIZED: The Spout will hold and process them automatically", - - "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", - "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", - "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", - "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", - "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", - "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", - "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", - "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", - "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", - - "create.ponder.stressometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Stressometer", - "create.ponder.stressometer.text_1": "UNLOCALIZED: The Stressometer displays the current Stress Capacity of the attached kinetic network", - "create.ponder.stressometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.stressometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Stressometer's measurements", - - "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", - "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue groups blocks together into moving contraptions", - "create.ponder.super_glue.text_2": "UNLOCALIZED: Clicking two endpoints creates a new 'glued' area", - "create.ponder.super_glue.text_3": "UNLOCALIZED: To remove a box, punch it with the glue item in hand", - "create.ponder.super_glue.text_4": "UNLOCALIZED: Adjacent blocks sharing an area will pull each other along", - "create.ponder.super_glue.text_5": "UNLOCALIZED: Overlapping glue volumes will move together", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", - - "create.ponder.valve_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Valves", - "create.ponder.valve_pipe.text_1": "UNLOCALIZED: Valve pipes help control fluids propagating through pipe networks", - "create.ponder.valve_pipe.text_2": "UNLOCALIZED: Their shaft input controls whether fluid is currently allowed through", - "create.ponder.valve_pipe.text_3": "UNLOCALIZED: Given Rotational Force in the opening direction, the valve will open up", - "create.ponder.valve_pipe.text_4": "UNLOCALIZED: It can be closed again by reversing the input rotation", - - "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", - "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", - - "create.ponder.weighted_ejector.header": "UNLOCALIZED: Using Weighted Ejectors", - "create.ponder.weighted_ejector.text_1": "UNLOCALIZED: Sneak and Right-Click holding an Ejector to select its target location", - "create.ponder.weighted_ejector.text_10": "UNLOCALIZED: It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "UNLOCALIZED: Other Entities will always trigger an Ejector when stepping on it", - "create.ponder.weighted_ejector.text_2": "UNLOCALIZED: The placed ejector will now launch objects to the marked location", - "create.ponder.weighted_ejector.text_3": "UNLOCALIZED: A valid target can be at any height or distance within range", - "create.ponder.weighted_ejector.text_4": "UNLOCALIZED: They cannot however be off to a side", - "create.ponder.weighted_ejector.text_5": "UNLOCALIZED: If no valid Target was selected, it will simply target the block directly in front", - "create.ponder.weighted_ejector.text_6": "UNLOCALIZED: Supply Rotational Force in order to charge it up", - "create.ponder.weighted_ejector.text_7": "UNLOCALIZED: Items placed on the ejector cause it to trigger", - "create.ponder.weighted_ejector.text_8": "UNLOCALIZED: If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "UNLOCALIZED: Using the Wrench, a required Stack Size can be configured", - - "create.ponder.weighted_ejector_redstone.header": "UNLOCALIZED: Controlling Weighted Ejectors with Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "UNLOCALIZED: Furthermore, Observers can detect when Ejectors activate", - - "create.ponder.weighted_ejector_tunnel.header": "UNLOCALIZED: Splitting item stacks using Weighted Ejectors", - "create.ponder.weighted_ejector_tunnel.text_1": "UNLOCALIZED: Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", - "create.ponder.weighted_ejector_tunnel.text_2": "UNLOCALIZED: First, configure the Brass Tunnel to 'Prefer Nearest', in order to prioritize its side output", - "create.ponder.weighted_ejector_tunnel.text_3": "UNLOCALIZED: The Stack Size set on the Ejector now determines the amount to be split off", - "create.ponder.weighted_ejector_tunnel.text_4": "UNLOCALIZED: While a new stack of the configured size exits the side output...", - "create.ponder.weighted_ejector_tunnel.text_5": "UNLOCALIZED: ...the remainder will continue on its path", - - "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", - "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", - "create.ponder.windmill_source.text_2": "UNLOCALIZED: Create a movable structure with the help of Super Glue", - "create.ponder.windmill_source.text_3": "UNLOCALIZED: If enough Sail-like blocks are included, this can act as a Windmill", - "create.ponder.windmill_source.text_4": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", - "create.ponder.windmill_source.text_5": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "UNLOCALIZED: Use a Wrench to configure its rotation direction", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", - "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json deleted file mode 100644 index f5215d93e5..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 2177", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "UNLOCALIZED: Acacia Window", - "block.create.acacia_window_pane": "UNLOCALIZED: Acacia Window Pane", - "block.create.adjustable_chain_gearshift": "Mudança de engrenagem de corrente ajustável", - "block.create.analog_lever": "Alavanca Analógica", - "block.create.andesite_belt_funnel": "Funil de correia de andesito", - "block.create.andesite_casing": "Revestimento de Andesito", - "block.create.andesite_encased_cogwheel": "Roda dentada revestida com andesito", - "block.create.andesite_encased_large_cogwheel": "Roda dentada grande revestida com andesito", - "block.create.andesite_encased_shaft": "Eixo revestido com andesito", - "block.create.andesite_funnel": "Funil de Andesito", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "UNLOCALIZED: Andesite Pillar", - "block.create.andesite_tunnel": "Tunel de Andesito", - "block.create.asurine": "UNLOCALIZED: Asurine", - "block.create.asurine_pillar": "UNLOCALIZED: Asurine Pillar", - "block.create.basin": "Bacia", - "block.create.belt": "Correia", - "block.create.birch_window": "UNLOCALIZED: Birch Window", - "block.create.birch_window_pane": "UNLOCALIZED: Birch Window Pane", - "block.create.black_nixie_tube": "Tubo nixie preto", - "block.create.black_sail": "Vela preta", - "block.create.black_seat": "Assento preto", - "block.create.black_toolbox": "Caixa de ferramentas preta", - "block.create.black_valve_handle": "Manopla de válvula preta", - "block.create.blaze_burner": "Queimador de blaze", - "block.create.blue_nixie_tube": "Tubo nixie azul", - "block.create.blue_sail": "Vela azul", - "block.create.blue_seat": "Assento azul", - "block.create.blue_toolbox": "Caixa de ferramentas azul", - "block.create.blue_valve_handle": "Manopla de válvula azul", - "block.create.brass_belt_funnel": "Funil de correia de Latão", - "block.create.brass_block": "Bloco de Latão", - "block.create.brass_casing": "Revestimento de Latão", - "block.create.brass_encased_cogwheel": "Roda dentada revestida com latão", - "block.create.brass_encased_large_cogwheel": "Roda dentada grande revestida com latão", - "block.create.brass_encased_shaft": "Eixo Revestido com Latão", - "block.create.brass_funnel": "Funil de Latão", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "Tunel de Latão", - "block.create.brown_nixie_tube": "Tubo de nixie castanho", - "block.create.brown_sail": "Vela castanho", - "block.create.brown_seat": "Assento castanho", - "block.create.brown_toolbox": "Caixa de ferramentas castanho", - "block.create.brown_valve_handle": "Manopla de válvula castanho", - "block.create.calcite_pillar": "UNLOCALIZED: Calcite Pillar", - "block.create.cart_assembler": "Montador de carrinho", - "block.create.chocolate": "Chocolate", - "block.create.chute": "Calha", - "block.create.clockwork_bearing": "Rolamento de relôgio", - "block.create.clutch": "Embreagem", - "block.create.cogwheel": "Roda Dentada", - "block.create.content_observer": "Observador de Conteúdo", - "block.create.controller_rail": "Trilho Controlador", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "Tanque Traseiro de Cobre", - "block.create.copper_casing": "Revestimento de Cobre", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "UNLOCALIZED: Copper Shingle Slab", - "block.create.copper_shingle_stairs": "UNLOCALIZED: Copper Shingle Stairs", - "block.create.copper_shingles": "UNLOCALIZED: Copper Shingles", - "block.create.copper_tile_slab": "UNLOCALIZED: Copper Tile Slab", - "block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs", - "block.create.copper_tiles": "UNLOCALIZED: Copper Tiles", - "block.create.copper_valve_handle": "Manopla de válvula de Cobre", - "block.create.creative_crate": "Caixa Criativa", - "block.create.creative_fluid_tank": "Tanque de Fluidos Criativo", - "block.create.creative_motor": "Motor Criativo", - "block.create.crimsite": "UNLOCALIZED: Crimsite", - "block.create.crimsite_pillar": "UNLOCALIZED: Crimsite Pillar", - "block.create.crimson_window": "UNLOCALIZED: Crimson Window", - "block.create.crimson_window_pane": "UNLOCALIZED: Crimson Window Pane", - "block.create.crushing_wheel": "Roda de Moer", - "block.create.crushing_wheel_controller": "UNLOCALIZED: Crushing Wheel Controller", - "block.create.cuckoo_clock": "Relógio de cuco", - "block.create.cut_andesite": "UNLOCALIZED: Cut Andesite", - "block.create.cut_andesite_brick_slab": "UNLOCALIZED: Cut Andesite Brick Slab", - "block.create.cut_andesite_brick_stairs": "UNLOCALIZED: Cut Andesite Brick Stairs", - "block.create.cut_andesite_brick_wall": "UNLOCALIZED: Cut Andesite Brick Wall", - "block.create.cut_andesite_bricks": "UNLOCALIZED: Cut Andesite Bricks", - "block.create.cut_andesite_slab": "UNLOCALIZED: Cut Andesite Slab", - "block.create.cut_andesite_stairs": "UNLOCALIZED: Cut Andesite Stairs", - "block.create.cut_andesite_wall": "UNLOCALIZED: Cut Andesite Wall", - "block.create.cut_asurine": "UNLOCALIZED: Cut Asurine", - "block.create.cut_asurine_brick_slab": "UNLOCALIZED: Cut Asurine Brick Slab", - "block.create.cut_asurine_brick_stairs": "UNLOCALIZED: Cut Asurine Brick Stairs", - "block.create.cut_asurine_brick_wall": "UNLOCALIZED: Cut Asurine Brick Wall", - "block.create.cut_asurine_bricks": "UNLOCALIZED: Cut Asurine Bricks", - "block.create.cut_asurine_slab": "UNLOCALIZED: Cut Asurine Slab", - "block.create.cut_asurine_stairs": "UNLOCALIZED: Cut Asurine Stairs", - "block.create.cut_asurine_wall": "UNLOCALIZED: Cut Asurine Wall", - "block.create.cut_calcite": "UNLOCALIZED: Cut Calcite", - "block.create.cut_calcite_brick_slab": "UNLOCALIZED: Cut Calcite Brick Slab", - "block.create.cut_calcite_brick_stairs": "UNLOCALIZED: Cut Calcite Brick Stairs", - "block.create.cut_calcite_brick_wall": "UNLOCALIZED: Cut Calcite Brick Wall", - "block.create.cut_calcite_bricks": "UNLOCALIZED: Cut Calcite Bricks", - "block.create.cut_calcite_slab": "UNLOCALIZED: Cut Calcite Slab", - "block.create.cut_calcite_stairs": "UNLOCALIZED: Cut Calcite Stairs", - "block.create.cut_calcite_wall": "UNLOCALIZED: Cut Calcite Wall", - "block.create.cut_crimsite": "UNLOCALIZED: Cut Crimsite", - "block.create.cut_crimsite_brick_slab": "UNLOCALIZED: Cut Crimsite Brick Slab", - "block.create.cut_crimsite_brick_stairs": "UNLOCALIZED: Cut Crimsite Brick Stairs", - "block.create.cut_crimsite_brick_wall": "UNLOCALIZED: Cut Crimsite Brick Wall", - "block.create.cut_crimsite_bricks": "UNLOCALIZED: Cut Crimsite Bricks", - "block.create.cut_crimsite_slab": "UNLOCALIZED: Cut Crimsite Slab", - "block.create.cut_crimsite_stairs": "UNLOCALIZED: Cut Crimsite Stairs", - "block.create.cut_crimsite_wall": "UNLOCALIZED: Cut Crimsite Wall", - "block.create.cut_deepslate": "UNLOCALIZED: Cut Deepslate", - "block.create.cut_deepslate_brick_slab": "UNLOCALIZED: Cut Deepslate Brick Slab", - "block.create.cut_deepslate_brick_stairs": "UNLOCALIZED: Cut Deepslate Brick Stairs", - "block.create.cut_deepslate_brick_wall": "UNLOCALIZED: Cut Deepslate Brick Wall", - "block.create.cut_deepslate_bricks": "UNLOCALIZED: Cut Deepslate Bricks", - "block.create.cut_deepslate_slab": "UNLOCALIZED: Cut Deepslate Slab", - "block.create.cut_deepslate_stairs": "UNLOCALIZED: Cut Deepslate Stairs", - "block.create.cut_deepslate_wall": "UNLOCALIZED: Cut Deepslate Wall", - "block.create.cut_diorite": "UNLOCALIZED: Cut Diorite", - "block.create.cut_diorite_brick_slab": "UNLOCALIZED: Cut Diorite Brick Slab", - "block.create.cut_diorite_brick_stairs": "UNLOCALIZED: Cut Diorite Brick Stairs", - "block.create.cut_diorite_brick_wall": "UNLOCALIZED: Cut Diorite Brick Wall", - "block.create.cut_diorite_bricks": "UNLOCALIZED: Cut Diorite Bricks", - "block.create.cut_diorite_slab": "UNLOCALIZED: Cut Diorite Slab", - "block.create.cut_diorite_stairs": "UNLOCALIZED: Cut Diorite Stairs", - "block.create.cut_diorite_wall": "UNLOCALIZED: Cut Diorite Wall", - "block.create.cut_dripstone": "UNLOCALIZED: Cut Dripstone", - "block.create.cut_dripstone_brick_slab": "UNLOCALIZED: Cut Dripstone Brick Slab", - "block.create.cut_dripstone_brick_stairs": "UNLOCALIZED: Cut Dripstone Brick Stairs", - "block.create.cut_dripstone_brick_wall": "UNLOCALIZED: Cut Dripstone Brick Wall", - "block.create.cut_dripstone_bricks": "UNLOCALIZED: Cut Dripstone Bricks", - "block.create.cut_dripstone_slab": "UNLOCALIZED: Cut Dripstone Slab", - "block.create.cut_dripstone_stairs": "UNLOCALIZED: Cut Dripstone Stairs", - "block.create.cut_dripstone_wall": "UNLOCALIZED: Cut Dripstone Wall", - "block.create.cut_granite": "UNLOCALIZED: Cut Granite", - "block.create.cut_granite_brick_slab": "UNLOCALIZED: Cut Granite Brick Slab", - "block.create.cut_granite_brick_stairs": "UNLOCALIZED: Cut Granite Brick Stairs", - "block.create.cut_granite_brick_wall": "UNLOCALIZED: Cut Granite Brick Wall", - "block.create.cut_granite_bricks": "UNLOCALIZED: Cut Granite Bricks", - "block.create.cut_granite_slab": "UNLOCALIZED: Cut Granite Slab", - "block.create.cut_granite_stairs": "UNLOCALIZED: Cut Granite Stairs", - "block.create.cut_granite_wall": "UNLOCALIZED: Cut Granite Wall", - "block.create.cut_limestone": "UNLOCALIZED: Cut Limestone", - "block.create.cut_limestone_brick_slab": "UNLOCALIZED: Cut Limestone Brick Slab", - "block.create.cut_limestone_brick_stairs": "UNLOCALIZED: Cut Limestone Brick Stairs", - "block.create.cut_limestone_brick_wall": "UNLOCALIZED: Cut Limestone Brick Wall", - "block.create.cut_limestone_bricks": "UNLOCALIZED: Cut Limestone Bricks", - "block.create.cut_limestone_slab": "UNLOCALIZED: Cut Limestone Slab", - "block.create.cut_limestone_stairs": "UNLOCALIZED: Cut Limestone Stairs", - "block.create.cut_limestone_wall": "UNLOCALIZED: Cut Limestone Wall", - "block.create.cut_ochrum": "UNLOCALIZED: Cut Ochrum", - "block.create.cut_ochrum_brick_slab": "UNLOCALIZED: Cut Ochrum Brick Slab", - "block.create.cut_ochrum_brick_stairs": "UNLOCALIZED: Cut Ochrum Brick Stairs", - "block.create.cut_ochrum_brick_wall": "UNLOCALIZED: Cut Ochrum Brick Wall", - "block.create.cut_ochrum_bricks": "UNLOCALIZED: Cut Ochrum Bricks", - "block.create.cut_ochrum_slab": "UNLOCALIZED: Cut Ochrum Slab", - "block.create.cut_ochrum_stairs": "UNLOCALIZED: Cut Ochrum Stairs", - "block.create.cut_ochrum_wall": "UNLOCALIZED: Cut Ochrum Wall", - "block.create.cut_scorchia": "UNLOCALIZED: Cut Scorchia", - "block.create.cut_scorchia_brick_slab": "UNLOCALIZED: Cut Scorchia Brick Slab", - "block.create.cut_scorchia_brick_stairs": "UNLOCALIZED: Cut Scorchia Brick Stairs", - "block.create.cut_scorchia_brick_wall": "UNLOCALIZED: Cut Scorchia Brick Wall", - "block.create.cut_scorchia_bricks": "UNLOCALIZED: Cut Scorchia Bricks", - "block.create.cut_scorchia_slab": "UNLOCALIZED: Cut Scorchia Slab", - "block.create.cut_scorchia_stairs": "UNLOCALIZED: Cut Scorchia Stairs", - "block.create.cut_scorchia_wall": "UNLOCALIZED: Cut Scorchia Wall", - "block.create.cut_scoria": "UNLOCALIZED: Cut Scoria", - "block.create.cut_scoria_brick_slab": "UNLOCALIZED: Cut Scoria Brick Slab", - "block.create.cut_scoria_brick_stairs": "UNLOCALIZED: Cut Scoria Brick Stairs", - "block.create.cut_scoria_brick_wall": "UNLOCALIZED: Cut Scoria Brick Wall", - "block.create.cut_scoria_bricks": "UNLOCALIZED: Cut Scoria Bricks", - "block.create.cut_scoria_slab": "UNLOCALIZED: Cut Scoria Slab", - "block.create.cut_scoria_stairs": "UNLOCALIZED: Cut Scoria Stairs", - "block.create.cut_scoria_wall": "UNLOCALIZED: Cut Scoria Wall", - "block.create.cut_tuff": "UNLOCALIZED: Cut Tuff", - "block.create.cut_tuff_brick_slab": "UNLOCALIZED: Cut Tuff Brick Slab", - "block.create.cut_tuff_brick_stairs": "UNLOCALIZED: Cut Tuff Brick Stairs", - "block.create.cut_tuff_brick_wall": "UNLOCALIZED: Cut Tuff Brick Wall", - "block.create.cut_tuff_bricks": "UNLOCALIZED: Cut Tuff Bricks", - "block.create.cut_tuff_slab": "UNLOCALIZED: Cut Tuff Slab", - "block.create.cut_tuff_stairs": "UNLOCALIZED: Cut Tuff Stairs", - "block.create.cut_tuff_wall": "UNLOCALIZED: Cut Tuff Wall", - "block.create.cut_veridium": "UNLOCALIZED: Cut Veridium", - "block.create.cut_veridium_brick_slab": "UNLOCALIZED: Cut Veridium Brick Slab", - "block.create.cut_veridium_brick_stairs": "UNLOCALIZED: Cut Veridium Brick Stairs", - "block.create.cut_veridium_brick_wall": "UNLOCALIZED: Cut Veridium Brick Wall", - "block.create.cut_veridium_bricks": "UNLOCALIZED: Cut Veridium Bricks", - "block.create.cut_veridium_slab": "UNLOCALIZED: Cut Veridium Slab", - "block.create.cut_veridium_stairs": "UNLOCALIZED: Cut Veridium Stairs", - "block.create.cut_veridium_wall": "UNLOCALIZED: Cut Veridium Wall", - "block.create.cyan_nixie_tube": "Tubo nixie ciano", - "block.create.cyan_sail": "Vela ciano", - "block.create.cyan_seat": "Assento ciano", - "block.create.cyan_toolbox": "caixa de ferramentas ciano", - "block.create.cyan_valve_handle": "Manopla de válvula ciano", - "block.create.dark_oak_window": "UNLOCALIZED: Dark Oak Window", - "block.create.dark_oak_window_pane": "UNLOCALIZED: Dark Oak Window Pane", - "block.create.deepslate_pillar": "UNLOCALIZED: Deepslate Pillar", - "block.create.deepslate_zinc_ore": "Deepslate zinc ore", - "block.create.deployer": "Implantador", - "block.create.depot": "Depósito", - "block.create.diorite_pillar": "UNLOCALIZED: Diorite Pillar", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar", - "block.create.encased_chain_drive": "Correia Revestida", - "block.create.encased_fan": "Ventilador Revestida", - "block.create.encased_fluid_pipe": "Cano de Fluidos Revestido", - "block.create.exposed_copper_shingle_slab": "UNLOCALIZED: Exposed Copper Shingle Slab", - "block.create.exposed_copper_shingle_stairs": "UNLOCALIZED: Exposed Copper Shingle Stairs", - "block.create.exposed_copper_shingles": "UNLOCALIZED: Exposed Copper Shingles", - "block.create.exposed_copper_tile_slab": "UNLOCALIZED: Exposed Copper Tile Slab", - "block.create.exposed_copper_tile_stairs": "UNLOCALIZED: Exposed Copper Tile Stairs", - "block.create.exposed_copper_tiles": "UNLOCALIZED: Exposed Copper Tiles", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "Cano de Fluido", - "block.create.fluid_tank": "Tanque de fluido", - "block.create.fluid_valve": "Válvula de fluido", - "block.create.flywheel": "Volante de inércia", - "block.create.framed_glass": "UNLOCALIZED: Framed Glass", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "UNLOCALIZED: Framed Glass Pane", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "Carruagem de Pórtico", - "block.create.gantry_shaft": "Eixo de Pórtico", - "block.create.gearbox": "Caixa de Transmissão", - "block.create.gearshift": "Câmbio", - "block.create.glass_fluid_pipe": "Cano de Fluido de Vidro", - "block.create.granite_pillar": "UNLOCALIZED: Granite Pillar", - "block.create.gray_nixie_tube": "Tubo nixie cinza", - "block.create.gray_sail": "Vela cinza", - "block.create.gray_seat": "Assento cinza", - "block.create.gray_toolbox": "Caixa de ferramentas cinza", - "block.create.gray_valve_handle": "Válvula cinza", - "block.create.green_nixie_tube": "Tubo nixie verde", - "block.create.green_sail": "Vela verde", - "block.create.green_seat": "Assento verde", - "block.create.green_toolbox": "Caixa de ferramentas verde", - "block.create.green_valve_handle": "Válvula verde", - "block.create.hand_crank": "Manivela", - "block.create.haunted_bell": "Sino assombrado", - "block.create.honey": "Mel", - "block.create.horizontal_framed_glass": "UNLOCALIZED: Horizontal Framed Glass", - "block.create.horizontal_framed_glass_pane": "UNLOCALIZED: Horizontal Framed Glass Pane", - "block.create.hose_pulley": "Polia de Mangueira", - "block.create.item_drain": "Dreno de Item", - "block.create.item_vault": "Cofre de itens", - "block.create.jungle_window": "UNLOCALIZED: Jungle Window", - "block.create.jungle_window_pane": "UNLOCALIZED: Jungle Window Pane", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "UNLOCALIZED: Large Cogwheel", - "block.create.layered_andesite": "UNLOCALIZED: Layered Andesite", - "block.create.layered_asurine": "UNLOCALIZED: Layered Asurine", - "block.create.layered_calcite": "UNLOCALIZED: Layered Calcite", - "block.create.layered_crimsite": "UNLOCALIZED: Layered Crimsite", - "block.create.layered_deepslate": "UNLOCALIZED: Layered Deepslate", - "block.create.layered_diorite": "UNLOCALIZED: Layered Diorite", - "block.create.layered_dripstone": "UNLOCALIZED: Layered Dripstone", - "block.create.layered_granite": "UNLOCALIZED: Layered Granite", - "block.create.layered_limestone": "UNLOCALIZED: Layered Limestone", - "block.create.layered_ochrum": "UNLOCALIZED: Layered Ochrum", - "block.create.layered_scorchia": "UNLOCALIZED: Layered Scorchia", - "block.create.layered_scoria": "UNLOCALIZED: Layered Scoria", - "block.create.layered_tuff": "UNLOCALIZED: Layered Tuff", - "block.create.layered_veridium": "UNLOCALIZED: Layered Veridium", - "block.create.lectern_controller": "Controle de Atril", - "block.create.light_blue_nixie_tube": "tubo nixie azul claro", - "block.create.light_blue_sail": "Vela azul claro", - "block.create.light_blue_seat": "Assento azul claro", - "block.create.light_blue_toolbox": "Caixa de ferramentas azul claro", - "block.create.light_blue_valve_handle": "válvula azul claro", - "block.create.light_gray_nixie_tube": "Tubo nixie azul claro", - "block.create.light_gray_sail": "Vela cinza claro", - "block.create.light_gray_seat": "Assento cinza claro", - "block.create.light_gray_toolbox": "Caixa de ferramentas cinza claro", - "block.create.light_gray_valve_handle": "Válvula cinza claro", - "block.create.lime_nixie_tube": "Tubo nixie cinza claro", - "block.create.lime_sail": "Vela lima", - "block.create.lime_seat": "Assento lima", - "block.create.lime_toolbox": "Caixa de ferramentas lima", - "block.create.lime_valve_handle": "Válvula lima", - "block.create.limestone": "Calcário", - "block.create.limestone_pillar": "Pilar de Calcário", - "block.create.linear_chassis": "Chassis Linear", - "block.create.lit_blaze_burner": "Queimador de Blaze Acesso", - "block.create.magenta_nixie_tube": "Tubo nixie magenta", - "block.create.magenta_sail": "Vela magenta", - "block.create.magenta_seat": "Assento magenta", - "block.create.magenta_toolbox": "Caixa de ferramentas magenta", - "block.create.magenta_valve_handle": "Válvula magenta", - "block.create.mechanical_arm": "Braço mecânico", - "block.create.mechanical_bearing": "Rolamento mecânico", - "block.create.mechanical_crafter": "Fabricador mecânico", - "block.create.mechanical_drill": "Broca Mecânica", - "block.create.mechanical_harvester": "Coletor Mecânico", - "block.create.mechanical_mixer": "Batedeira mecânica", - "block.create.mechanical_piston": "Pistão Mecânico", - "block.create.mechanical_piston_head": "Cabeça do Pistão Mecânico", - "block.create.mechanical_plough": "Arador Mecânico", - "block.create.mechanical_press": "Prensa Mecânica", - "block.create.mechanical_pump": "Bomba Mecânica", - "block.create.mechanical_saw": "Serra Mecânica", - "block.create.metal_bracket": "Suporte de metal", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "Pedra de Moer", - "block.create.minecart_anchor": "Ancóra de carrinho de Mina", - "block.create.mysterious_cuckoo_clock": "Relógio cuckoo", - "block.create.nixie_tube": "Tubo Nixie", - "block.create.nozzle": "Bocal", - "block.create.oak_window": "UNLOCALIZED: Oak Window", - "block.create.oak_window_pane": "UNLOCALIZED: Oak Window Pane", - "block.create.ochrum": "UNLOCALIZED: Ochrum", - "block.create.ochrum_pillar": "UNLOCALIZED: Ochrum Pillar", - "block.create.orange_sail": "Vela laranja", - "block.create.orange_seat": "Assento laranja", - "block.create.orange_toolbox": "Caixa de ferramentas laranja", - "block.create.orange_valve_handle": "Válvula laranja", - "block.create.ornate_iron_window": "UNLOCALIZED: Ornate Iron Window", - "block.create.ornate_iron_window_pane": "UNLOCALIZED: Ornate Iron Window Pane", - "block.create.oxidized_copper_shingle_slab": "UNLOCALIZED: Oxidized Copper Shingle Slab", - "block.create.oxidized_copper_shingle_stairs": "UNLOCALIZED: Oxidized Copper Shingle Stairs", - "block.create.oxidized_copper_shingles": "UNLOCALIZED: Oxidized Copper Shingles", - "block.create.oxidized_copper_tile_slab": "UNLOCALIZED: Oxidized Copper Tile Slab", - "block.create.oxidized_copper_tile_stairs": "UNLOCALIZED: Oxidized Copper Tile Stairs", - "block.create.oxidized_copper_tiles": "UNLOCALIZED: Oxidized Copper Tiles", - "block.create.peculiar_bell": "Sino peculiar", - "block.create.pink_nixie_tube": "Tubo nixie rosa", - "block.create.pink_sail": "Vela rosa", - "block.create.pink_seat": "Assento rosa", - "block.create.pink_toolbox": "Caixa de ferramentas rosa", - "block.create.pink_valve_handle": "Válvula rosa", - "block.create.piston_extension_pole": "Vara de Extensão do Pistão", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "UNLOCALIZED: Polished Cut Andesite", - "block.create.polished_cut_andesite_slab": "UNLOCALIZED: Polished Cut Andesite Slab", - "block.create.polished_cut_andesite_stairs": "UNLOCALIZED: Polished Cut Andesite Stairs", - "block.create.polished_cut_andesite_wall": "UNLOCALIZED: Polished Cut Andesite Wall", - "block.create.polished_cut_asurine": "UNLOCALIZED: Polished Cut Asurine", - "block.create.polished_cut_asurine_slab": "UNLOCALIZED: Polished Cut Asurine Slab", - "block.create.polished_cut_asurine_stairs": "UNLOCALIZED: Polished Cut Asurine Stairs", - "block.create.polished_cut_asurine_wall": "UNLOCALIZED: Polished Cut Asurine Wall", - "block.create.polished_cut_calcite": "UNLOCALIZED: Polished Cut Calcite", - "block.create.polished_cut_calcite_slab": "UNLOCALIZED: Polished Cut Calcite Slab", - "block.create.polished_cut_calcite_stairs": "UNLOCALIZED: Polished Cut Calcite Stairs", - "block.create.polished_cut_calcite_wall": "UNLOCALIZED: Polished Cut Calcite Wall", - "block.create.polished_cut_crimsite": "UNLOCALIZED: Polished Cut Crimsite", - "block.create.polished_cut_crimsite_slab": "UNLOCALIZED: Polished Cut Crimsite Slab", - "block.create.polished_cut_crimsite_stairs": "UNLOCALIZED: Polished Cut Crimsite Stairs", - "block.create.polished_cut_crimsite_wall": "UNLOCALIZED: Polished Cut Crimsite Wall", - "block.create.polished_cut_deepslate": "UNLOCALIZED: Polished Cut Deepslate", - "block.create.polished_cut_deepslate_slab": "UNLOCALIZED: Polished Cut Deepslate Slab", - "block.create.polished_cut_deepslate_stairs": "UNLOCALIZED: Polished Cut Deepslate Stairs", - "block.create.polished_cut_deepslate_wall": "UNLOCALIZED: Polished Cut Deepslate Wall", - "block.create.polished_cut_diorite": "UNLOCALIZED: Polished Cut Diorite", - "block.create.polished_cut_diorite_slab": "UNLOCALIZED: Polished Cut Diorite Slab", - "block.create.polished_cut_diorite_stairs": "UNLOCALIZED: Polished Cut Diorite Stairs", - "block.create.polished_cut_diorite_wall": "UNLOCALIZED: Polished Cut Diorite Wall", - "block.create.polished_cut_dripstone": "UNLOCALIZED: Polished Cut Dripstone", - "block.create.polished_cut_dripstone_slab": "UNLOCALIZED: Polished Cut Dripstone Slab", - "block.create.polished_cut_dripstone_stairs": "UNLOCALIZED: Polished Cut Dripstone Stairs", - "block.create.polished_cut_dripstone_wall": "UNLOCALIZED: Polished Cut Dripstone Wall", - "block.create.polished_cut_granite": "UNLOCALIZED: Polished Cut Granite", - "block.create.polished_cut_granite_slab": "UNLOCALIZED: Polished Cut Granite Slab", - "block.create.polished_cut_granite_stairs": "UNLOCALIZED: Polished Cut Granite Stairs", - "block.create.polished_cut_granite_wall": "UNLOCALIZED: Polished Cut Granite Wall", - "block.create.polished_cut_limestone": "UNLOCALIZED: Polished Cut Limestone", - "block.create.polished_cut_limestone_slab": "UNLOCALIZED: Polished Cut Limestone Slab", - "block.create.polished_cut_limestone_stairs": "UNLOCALIZED: Polished Cut Limestone Stairs", - "block.create.polished_cut_limestone_wall": "UNLOCALIZED: Polished Cut Limestone Wall", - "block.create.polished_cut_ochrum": "UNLOCALIZED: Polished Cut Ochrum", - "block.create.polished_cut_ochrum_slab": "UNLOCALIZED: Polished Cut Ochrum Slab", - "block.create.polished_cut_ochrum_stairs": "UNLOCALIZED: Polished Cut Ochrum Stairs", - "block.create.polished_cut_ochrum_wall": "UNLOCALIZED: Polished Cut Ochrum Wall", - "block.create.polished_cut_scorchia": "UNLOCALIZED: Polished Cut Scorchia", - "block.create.polished_cut_scorchia_slab": "UNLOCALIZED: Polished Cut Scorchia Slab", - "block.create.polished_cut_scorchia_stairs": "UNLOCALIZED: Polished Cut Scorchia Stairs", - "block.create.polished_cut_scorchia_wall": "UNLOCALIZED: Polished Cut Scorchia Wall", - "block.create.polished_cut_scoria": "UNLOCALIZED: Polished Cut Scoria", - "block.create.polished_cut_scoria_slab": "UNLOCALIZED: Polished Cut Scoria Slab", - "block.create.polished_cut_scoria_stairs": "UNLOCALIZED: Polished Cut Scoria Stairs", - "block.create.polished_cut_scoria_wall": "UNLOCALIZED: Polished Cut Scoria Wall", - "block.create.polished_cut_tuff": "UNLOCALIZED: Polished Cut Tuff", - "block.create.polished_cut_tuff_slab": "UNLOCALIZED: Polished Cut Tuff Slab", - "block.create.polished_cut_tuff_stairs": "UNLOCALIZED: Polished Cut Tuff Stairs", - "block.create.polished_cut_tuff_wall": "UNLOCALIZED: Polished Cut Tuff Wall", - "block.create.polished_cut_veridium": "UNLOCALIZED: Polished Cut Veridium", - "block.create.polished_cut_veridium_slab": "UNLOCALIZED: Polished Cut Veridium Slab", - "block.create.polished_cut_veridium_stairs": "UNLOCALIZED: Polished Cut Veridium Stairs", - "block.create.polished_cut_veridium_wall": "UNLOCALIZED: Polished Cut Veridium Wall", - "block.create.portable_fluid_interface": "Interface de fluidos portátil", - "block.create.portable_storage_interface": "Interface de armazenamento portátil", - "block.create.powered_latch": "UNLOCALIZED: Powered Latch", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "UNLOCALIZED: Powered Toggle Latch", - "block.create.pulley_magnet": "Imã da Polia", - "block.create.pulse_extender": "Extensor de pulso", - "block.create.pulse_repeater": "Repetidor de Pulso", - "block.create.purple_nixie_tube": "Tubo nixie roxo", - "block.create.purple_sail": "Vela roxo", - "block.create.purple_seat": "Assento roxo", - "block.create.purple_toolbox": "Caixa de ferramentas roxa", - "block.create.purple_valve_handle": "válvula roxa", - "block.create.radial_chassis": "Chassis Radial", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "Bloco de zinco bruto", - "block.create.red_nixie_tube": "Tubo nixie vermelho", - "block.create.red_sail": "Vela vermelha", - "block.create.red_seat": "Assento vermelho", - "block.create.red_toolbox": "Caixa de ferramentas vermelha", - "block.create.red_valve_handle": "Válvula vermelha", - "block.create.redstone_contact": "Contato de Redstone", - "block.create.redstone_link": "Conexão de Redstone", - "block.create.refined_radiance_casing": "Revestimento Brilhante", - "block.create.rope": "Corda", - "block.create.rope_pulley": "Polia", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "Controlador de Velocidade Rotacional", - "block.create.sail_frame": "moldura de vela", - "block.create.schematic_table": "Mesa de Esquema", - "block.create.schematicannon": "Canhão de Esquema", - "block.create.scorchia": "UNLOCALIZED: Scorchia", - "block.create.scorchia_pillar": "UNLOCALIZED: Scorchia Pillar", - "block.create.scoria": "UNLOCALIZED: Scoria", - "block.create.scoria_pillar": "UNLOCALIZED: Scoria Pillar", - "block.create.secondary_linear_chassis": "Chassis linear secundário", - "block.create.sequenced_gearshift": "Câmbio sequenciado", - "block.create.shadow_steel_casing": "Revestiment das Sombras", - "block.create.shaft": "Eixo", - "block.create.small_andesite_brick_slab": "UNLOCALIZED: Small Andesite Brick Slab", - "block.create.small_andesite_brick_stairs": "UNLOCALIZED: Small Andesite Brick Stairs", - "block.create.small_andesite_brick_wall": "UNLOCALIZED: Small Andesite Brick Wall", - "block.create.small_andesite_bricks": "UNLOCALIZED: Small Andesite Bricks", - "block.create.small_asurine_brick_slab": "UNLOCALIZED: Small Asurine Brick Slab", - "block.create.small_asurine_brick_stairs": "UNLOCALIZED: Small Asurine Brick Stairs", - "block.create.small_asurine_brick_wall": "UNLOCALIZED: Small Asurine Brick Wall", - "block.create.small_asurine_bricks": "UNLOCALIZED: Small Asurine Bricks", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "UNLOCALIZED: Small Calcite Brick Slab", - "block.create.small_calcite_brick_stairs": "UNLOCALIZED: Small Calcite Brick Stairs", - "block.create.small_calcite_brick_wall": "UNLOCALIZED: Small Calcite Brick Wall", - "block.create.small_calcite_bricks": "UNLOCALIZED: Small Calcite Bricks", - "block.create.small_crimsite_brick_slab": "UNLOCALIZED: Small Crimsite Brick Slab", - "block.create.small_crimsite_brick_stairs": "UNLOCALIZED: Small Crimsite Brick Stairs", - "block.create.small_crimsite_brick_wall": "UNLOCALIZED: Small Crimsite Brick Wall", - "block.create.small_crimsite_bricks": "UNLOCALIZED: Small Crimsite Bricks", - "block.create.small_deepslate_brick_slab": "UNLOCALIZED: Small Deepslate Brick Slab", - "block.create.small_deepslate_brick_stairs": "UNLOCALIZED: Small Deepslate Brick Stairs", - "block.create.small_deepslate_brick_wall": "UNLOCALIZED: Small Deepslate Brick Wall", - "block.create.small_deepslate_bricks": "UNLOCALIZED: Small Deepslate Bricks", - "block.create.small_diorite_brick_slab": "UNLOCALIZED: Small Diorite Brick Slab", - "block.create.small_diorite_brick_stairs": "UNLOCALIZED: Small Diorite Brick Stairs", - "block.create.small_diorite_brick_wall": "UNLOCALIZED: Small Diorite Brick Wall", - "block.create.small_diorite_bricks": "UNLOCALIZED: Small Diorite Bricks", - "block.create.small_dripstone_brick_slab": "UNLOCALIZED: Small Dripstone Brick Slab", - "block.create.small_dripstone_brick_stairs": "UNLOCALIZED: Small Dripstone Brick Stairs", - "block.create.small_dripstone_brick_wall": "UNLOCALIZED: Small Dripstone Brick Wall", - "block.create.small_dripstone_bricks": "UNLOCALIZED: Small Dripstone Bricks", - "block.create.small_granite_brick_slab": "UNLOCALIZED: Small Granite Brick Slab", - "block.create.small_granite_brick_stairs": "UNLOCALIZED: Small Granite Brick Stairs", - "block.create.small_granite_brick_wall": "UNLOCALIZED: Small Granite Brick Wall", - "block.create.small_granite_bricks": "UNLOCALIZED: Small Granite Bricks", - "block.create.small_limestone_brick_slab": "UNLOCALIZED: Small Limestone Brick Slab", - "block.create.small_limestone_brick_stairs": "UNLOCALIZED: Small Limestone Brick Stairs", - "block.create.small_limestone_brick_wall": "UNLOCALIZED: Small Limestone Brick Wall", - "block.create.small_limestone_bricks": "UNLOCALIZED: Small Limestone Bricks", - "block.create.small_ochrum_brick_slab": "UNLOCALIZED: Small Ochrum Brick Slab", - "block.create.small_ochrum_brick_stairs": "UNLOCALIZED: Small Ochrum Brick Stairs", - "block.create.small_ochrum_brick_wall": "UNLOCALIZED: Small Ochrum Brick Wall", - "block.create.small_ochrum_bricks": "UNLOCALIZED: Small Ochrum Bricks", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "UNLOCALIZED: Small Scorchia Brick Slab", - "block.create.small_scorchia_brick_stairs": "UNLOCALIZED: Small Scorchia Brick Stairs", - "block.create.small_scorchia_brick_wall": "UNLOCALIZED: Small Scorchia Brick Wall", - "block.create.small_scorchia_bricks": "UNLOCALIZED: Small Scorchia Bricks", - "block.create.small_scoria_brick_slab": "UNLOCALIZED: Small Scoria Brick Slab", - "block.create.small_scoria_brick_stairs": "UNLOCALIZED: Small Scoria Brick Stairs", - "block.create.small_scoria_brick_wall": "UNLOCALIZED: Small Scoria Brick Wall", - "block.create.small_scoria_bricks": "UNLOCALIZED: Small Scoria Bricks", - "block.create.small_tuff_brick_slab": "UNLOCALIZED: Small Tuff Brick Slab", - "block.create.small_tuff_brick_stairs": "UNLOCALIZED: Small Tuff Brick Stairs", - "block.create.small_tuff_brick_wall": "UNLOCALIZED: Small Tuff Brick Wall", - "block.create.small_tuff_bricks": "UNLOCALIZED: Small Tuff Bricks", - "block.create.small_veridium_brick_slab": "UNLOCALIZED: Small Veridium Brick Slab", - "block.create.small_veridium_brick_stairs": "UNLOCALIZED: Small Veridium Brick Stairs", - "block.create.small_veridium_brick_wall": "UNLOCALIZED: Small Veridium Brick Wall", - "block.create.small_veridium_bricks": "UNLOCALIZED: Small Veridium Bricks", - "block.create.smart_chute": "calha Inteligente", - "block.create.smart_fluid_pipe": "Cano de Fluidos Inteligente", - "block.create.speedometer": "Velocímetro", - "block.create.spout": "Bica", - "block.create.spruce_window": "UNLOCALIZED: Spruce Window", - "block.create.spruce_window_pane": "UNLOCALIZED: Spruce Window Pane", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "Adesivo", - "block.create.sticky_mechanical_piston": "Pistão Mecânico Grudento", - "block.create.stockpile_switch": "Disjuntor de Armazenamento", - "block.create.stressometer": "Estressómetro", - "block.create.tiled_glass": "Vidro Entalhado", - "block.create.tiled_glass_pane": "Vidraça Entalhada", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "UNLOCALIZED: Tuff Pillar", - "block.create.turntable": "Mesa giratória", - "block.create.veridium": "UNLOCALIZED: Veridium", - "block.create.veridium_pillar": "UNLOCALIZED: Veridium Pillar", - "block.create.vertical_framed_glass": "UNLOCALIZED: Vertical Framed Glass", - "block.create.vertical_framed_glass_pane": "UNLOCALIZED: Vertical Framed Glass Pane", - "block.create.warped_window": "UNLOCALIZED: Warped Window", - "block.create.warped_window_pane": "UNLOCALIZED: Warped Window Pane", - "block.create.water_wheel": "Roda de Água", - "block.create.waxed_copper_shingle_slab": "UNLOCALIZED: Waxed Copper Shingle Slab", - "block.create.waxed_copper_shingle_stairs": "UNLOCALIZED: Waxed Copper Shingle Stairs", - "block.create.waxed_copper_shingles": "UNLOCALIZED: Waxed Copper Shingles", - "block.create.waxed_copper_tile_slab": "UNLOCALIZED: Waxed Copper Tile Slab", - "block.create.waxed_copper_tile_stairs": "UNLOCALIZED: Waxed Copper Tile Stairs", - "block.create.waxed_copper_tiles": "UNLOCALIZED: Waxed Copper Tiles", - "block.create.waxed_exposed_copper_shingle_slab": "UNLOCALIZED: Waxed Exposed Copper Shingle Slab", - "block.create.waxed_exposed_copper_shingle_stairs": "UNLOCALIZED: Waxed Exposed Copper Shingle Stairs", - "block.create.waxed_exposed_copper_shingles": "UNLOCALIZED: Waxed Exposed Copper Shingles", - "block.create.waxed_exposed_copper_tile_slab": "UNLOCALIZED: Waxed Exposed Copper Tile Slab", - "block.create.waxed_exposed_copper_tile_stairs": "UNLOCALIZED: Waxed Exposed Copper Tile Stairs", - "block.create.waxed_exposed_copper_tiles": "UNLOCALIZED: Waxed Exposed Copper Tiles", - "block.create.waxed_oxidized_copper_shingle_slab": "UNLOCALIZED: Waxed Oxidized Copper Shingle Slab", - "block.create.waxed_oxidized_copper_shingle_stairs": "UNLOCALIZED: Waxed Oxidized Copper Shingle Stairs", - "block.create.waxed_oxidized_copper_shingles": "UNLOCALIZED: Waxed Oxidized Copper Shingles", - "block.create.waxed_oxidized_copper_tile_slab": "UNLOCALIZED: Waxed Oxidized Copper Tile Slab", - "block.create.waxed_oxidized_copper_tile_stairs": "UNLOCALIZED: Waxed Oxidized Copper Tile Stairs", - "block.create.waxed_oxidized_copper_tiles": "UNLOCALIZED: Waxed Oxidized Copper Tiles", - "block.create.waxed_weathered_copper_shingle_slab": "UNLOCALIZED: Waxed Weathered Copper Shingle Slab", - "block.create.waxed_weathered_copper_shingle_stairs": "UNLOCALIZED: Waxed Weathered Copper Shingle Stairs", - "block.create.waxed_weathered_copper_shingles": "UNLOCALIZED: Waxed Weathered Copper Shingles", - "block.create.waxed_weathered_copper_tile_slab": "UNLOCALIZED: Waxed Weathered Copper Tile Slab", - "block.create.waxed_weathered_copper_tile_stairs": "UNLOCALIZED: Waxed Weathered Copper Tile Stairs", - "block.create.waxed_weathered_copper_tiles": "UNLOCALIZED: Waxed Weathered Copper Tiles", - "block.create.weathered_copper_shingle_slab": "UNLOCALIZED: Weathered Copper Shingle Slab", - "block.create.weathered_copper_shingle_stairs": "UNLOCALIZED: Weathered Copper Shingle Stairs", - "block.create.weathered_copper_shingles": "UNLOCALIZED: Weathered Copper Shingles", - "block.create.weathered_copper_tile_slab": "UNLOCALIZED: Weathered Copper Tile Slab", - "block.create.weathered_copper_tile_stairs": "UNLOCALIZED: Weathered Copper Tile Stairs", - "block.create.weathered_copper_tiles": "UNLOCALIZED: Weathered Copper Tiles", - "block.create.weighted_ejector": "Ejetor ´ponderado", - "block.create.white_nixie_tube": "Tubo nixie branco", - "block.create.white_sail": "Vela branca", - "block.create.white_seat": "Assento branco", - "block.create.white_toolbox": "Caixa de ferramentas branca", - "block.create.white_valve_handle": "Válvula branca", - "block.create.windmill_bearing": "Rolamento de moinho", - "block.create.wooden_bracket": "Suporte de madeira", - "block.create.yellow_nixie_tube": "Tubo nixie amarelo", - "block.create.yellow_sail": "Vela amarela", - "block.create.yellow_seat": "Assento amarelo", - "block.create.yellow_toolbox": "Caixa de amarela", - "block.create.yellow_valve_handle": "Válvula amarela", - "block.create.zinc_block": "Bloco de Zinco", - "block.create.zinc_ore": "Minério de Zinco", - - "enchantment.create.capacity": "Capacidade", - "enchantment.create.potato_recovery": "Recuperação de Batata", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "Engenhoca", - "entity.create.crafting_blueprint": "Esquema de Fabricação", - "entity.create.gantry_contraption": "Engenhoca de Pórticolo", - "entity.create.potato_projectile": "Projétil de batata", - "entity.create.seat": "Assento", - "entity.create.stationary_contraption": "Engenhoca estacionária", - "entity.create.super_glue": "Super Cola", - - "fluid.create.potion": "Poção", - "fluid.create.tea": "Chá do Construtor", - - "item.create.andesite_alloy": "Liga de Andesito", - "item.create.attribute_filter": "Filtro de Atributo", - "item.create.bar_of_chocolate": "Barra de Chocolate", - "item.create.belt_connector": "Esteira Mecânica", - "item.create.blaze_cake": "Bolo de Blaze", - "item.create.blaze_cake_base": "Base do Bolo de Blaze", - "item.create.brass_hand": "Mão de Latão", - "item.create.brass_ingot": "Barra de Latão", - "item.create.brass_nugget": "Pepita de Latão", - "item.create.brass_sheet": "Chapa de Latão", - "item.create.builders_tea": "Chá do Construtor", - "item.create.chest_minecart_contraption": "Engenhoca de carrinho de mina com baú", - "item.create.chocolate_bucket": "Balde de Chocolate", - "item.create.chocolate_glazed_berries": "Baga com Cobertura de Chocolate", - "item.create.chromatic_compound": "Composto Cromático", - "item.create.cinder_flour": "Farinha de Netherrack", - "item.create.copper_backtank": "Tanque Traseiro", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Pepita de Cobre", - "item.create.copper_sheet": "Chapa de Cobre", - "item.create.crafter_slot_cover": "Cobertura do slot de fabricador", - "item.create.crafting_blueprint": "Esquema de Fabricação", - "item.create.creative_blaze_cake": "Bolo de Blaze Criativo", - "item.create.crushed_aluminum_ore": "Minério de Alumínio Esmagado", - "item.create.crushed_copper_ore": "Minério de Cobre Esmagado", - "item.create.crushed_gold_ore": "Minério de Ouro Esmagado", - "item.create.crushed_iron_ore": "Minério de Ferro Esmagado", - "item.create.crushed_lead_ore": "Minério de Chumbo Esmagado", - "item.create.crushed_nickel_ore": "Minério de Niquel Esmagado", - "item.create.crushed_osmium_ore": "Minério de Osmio Esmagado", - "item.create.crushed_platinum_ore": "Minério de Pratina Esmagado", - "item.create.crushed_quicksilver_ore": "Minério de Mercúrio Esmagado", - "item.create.crushed_silver_ore": "Minério de Prata Esmagado", - "item.create.crushed_tin_ore": "Minério de Estanho Esmagado", - "item.create.crushed_uranium_ore": "Urânio Esmagado", - "item.create.crushed_zinc_ore": "Minério de Zinco Esmagado", - "item.create.diving_boots": "Botas de Mergulhador", - "item.create.diving_helmet": "Capacete de Mergulhador", - "item.create.dough": "Massa de pão", - "item.create.electron_tube": "Tubo de Elétron", - "item.create.empty_blaze_burner": "Queimador de Blaze Vazio", - "item.create.empty_schematic": "Esquema vazio", - "item.create.experience_nugget": "Pepita de experiencia", - "item.create.extendo_grip": "Extensão de Pegador", - "item.create.filter": "Filtro", - "item.create.furnace_minecart_contraption": "Engenhoca de Carrinho de Mina com Fornalha", - "item.create.goggles": "Óculos de Engenheiro", - "item.create.golden_sheet": "Chapa de Ouro", - "item.create.handheld_worldshaper": "Modelador de Mundo Criativo", - "item.create.honey_bucket": "Balde de Mel", - "item.create.honeyed_apple": "Maçã com Cobertura de Mel", - "item.create.incomplete_precision_mechanism": "Mecanismo de Precisão", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "Chapa de Ferro", - "item.create.linked_controller": "Controle conectado", - "item.create.minecart_contraption": "Engenhoca de Carrino de Mina", - "item.create.minecart_coupling": "Acoplamento de Carrinho de Mina", - "item.create.polished_rose_quartz": "Quartzo Rosa Polido", - "item.create.potato_cannon": "Canhão de Batata", - "item.create.powdered_obsidian": "Pó de Obsidiana", - "item.create.precision_mechanism": "Mecanismo de Precisão", - "item.create.propeller": "Hélice", - "item.create.raw_zinc": "Zinco bruto", - "item.create.red_sand_paper": "Lixa Vermelha", - "item.create.refined_radiance": "Luz Refinada", - "item.create.rose_quartz": "Quartzo Rosa", - "item.create.sand_paper": "Lixa", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Esquema", - "item.create.schematic_and_quill": "Esquema e pena", - "item.create.shadow_steel": "Aço sombrio", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "Super Cola", - "item.create.sweet_roll": "Rolinho Doce", - "item.create.tree_fertilizer": "Fertilizante de Árvore", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Caixa de Transmissão Vertical", - "item.create.wand_of_symmetry": "Varinha de Simetria", - "item.create.wheat_flour": "Farinha de trigo", - "item.create.whisk": "Batedeira", - "item.create.wrench": "Chave Inglesa", - "item.create.zinc_ingot": "Barra de Zinco", - "item.create.zinc_nugget": "Pepita de Zinco", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bem vindo a Create", - "advancement.create.root.desc": "É hora de construir engenhocas maravilhosas", - "advancement.create.andesite_alloy": "Alinterações Em abundância", - "advancement.create.andesite_alloy.desc": "Materiais do Create tem nomes estranhos, a liga de andesito é um deles.", - "advancement.create.andesite_casing": "A era do andesito", - "advancement.create.andesite_casing.desc": "Use um pouco de liga de andesito e madeira para fazer um revestimento basico.", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "Correia de alga", - "advancement.create.belt.desc": "Conecte dois eixos com uma esteira mecanica.", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "Caindo", - "advancement.create.chute.desc": "coloque uma calha a versão vertical da esteira mecanica.", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "aproveitamento hidráulico", - "advancement.create.water_wheel.desc": "Coloque uma roda de água e tente conseguir gira-la!", - "advancement.create.windmill": "Uma brisa moderada", - "advancement.create.windmill.desc": "Monte um moinho de vento", - "advancement.create.shifting_gears": "Mudança de marcha", - "advancement.create.shifting_gears.desc": "Conecte uma roda dentada grande com uma roda dentada pequena, permitindo você a mudar a velocidade da engenhoca.", - "advancement.create.millstone": "Moedor portátil", - "advancement.create.millstone.desc": "Coloque e energize uma pedra de moer", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "Mas quão estressado exatamente?", - "advancement.create.stressometer.desc": "Coloque e energise o estressómetro. Olhe a este por atraves dos seus óculos para ler o valor exato.", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "UNLOCALIZED: The Parrots and the Flaps", - "advancement.create.belt_funnel_kiss.desc": "UNLOCALIZED: Make two Belt-mounted Funnels kiss§7\n(Hidden Advancement)", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "A era do cobre", - "advancement.create.copper_casing.desc": "Use um pouco de chapas de cobre e madeira para criar um pouco de revestimentos de cobre.", - "advancement.create.spout": "Sploosh", - "advancement.create.spout.desc": "Assista um item ser enchido usando uma bica.", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "Espião de fluxo", - "advancement.create.glass_pipe.desc": "Assista fluidos se propagarem por através de canos de fluido com janela. Canos retos ficam com janelas quando uma chave inglesa é usada neles.", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "Vazamento industrial", - "advancement.create.hose_pulley.desc": "desça uma polia de mangueira e assista esta drenar ou encher qualquer corpo de fluido.", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "Ligas de verdade", - "advancement.create.brass.desc": "Use cobre esmagado e zinco esmagado para criar um pouco de latão.", - "advancement.create.brass_casing": "a era do latão", - "advancement.create.brass_casing.desc": "Use o recentemente obtido latão e um pouco de madeira para criar um revestimento mais avançado.", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "Cutuque, coloque e ataque", - "advancement.create.deployer.desc": "coloque e energize um implantador, o reflexo perfeito de voce mesmo.", - "advancement.create.precision_mechanism": "Curiosidades complexas", - "advancement.create.precision_mechanism.desc": "Monte um mecanismo de precisão.", - "advancement.create.speed_controller": "Engenheiros odiam ele!", - "advancement.create.speed_controller.desc": "Coloque um Controlador de velocidade rotacional, o dispositivo ultimato para mudança de marcha.", - "advancement.create.mechanical_arm": "Mâos ocupadas!", - "advancement.create.mechanical_arm.desc": "Fabrique um braço mecânico,selecione as entradas e saidas,Coloque e energize o; em seguida assista como elo faz todo o trabalho para você.", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "Par de gigantes", - "advancement.create.crushing_wheel.desc": "Crie algumas rodas de moer para triturar alguns materiais eficientemente.", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "Hora da engenhoca", - "advancement.create.clockwork_bearing.desc": "Ative uma estrutura conectada a um rolamento de rêlogio.", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "Fwoomp!", - "advancement.create.potato_cannon.desc": "Derrote um inimigo com o seu canhão de batata.", - "advancement.create.extendo_grip": "Boioioing!", - "advancement.create.extendo_grip.desc": "Apossar-se de uma extensão de pegador.", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "Combuste-tron", - "advancement.create.arm_blaze_burner.desc": "Instrua um braço mecânico para alimentar seu queimador de blaze.", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "Organiza-tron", - "advancement.create.arm_many_targets.desc": "Programe um braço mecânico com dez ou mais locais de saida.", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "UNLOCALIZED: Pound It, Bro!", - "advancement.create.fist_bump.desc": "UNLOCALIZED: Make two Deployers fist-bump§7\n(Hidden Advancement)", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "toque minha musica!", - "advancement.create.musical_arm.desc": "Assista um braço mecânico operar seu toca-discos.", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Paletes Create", - - "death.attack.create.crush": "%1$s foi processado pelas Rodas de Moer", - "death.attack.create.crush.player": "%1$s foi jogando numa Roda de moer por %2$s", - "death.attack.create.fan_fire": "%1$s foi queimado por ar quente", - "death.attack.create.fan_fire.player": "%1$s Foi jogado num defumador por %2$s", - "death.attack.create.fan_lava": "%1$s foi queimado pelo ventilador de lava", - "death.attack.create.fan_lava.player": "U%1$s foi jogado numa fundidora por %2$s", - "death.attack.create.mechanical_drill": "%1$s foi empalado pela Broca Mecânica", - "death.attack.create.mechanical_drill.player": "%1$s foi jogado na frente de uma broca por %2$s", - "death.attack.create.mechanical_saw": "%1$s foi cortado ao meio por uma serra mecânica", - "death.attack.create.mechanical_saw.player": "%1$s foi jogado numa serra por %2$s", - "death.attack.create.potato_cannon": "%1$s foi atirado pelo canhão de batatas do %2$", - "death.attack.create.potato_cannon.item": "%1$s foi atirado por %2$s usando %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s foi explodido por relógio cuco adulterado", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s foi explodido por relógio cuco adulterado", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer", - "create.block.cart_assembler.invalid": "UNLOCALIZED: Place your Cart Assembler on a rail block", - - "create.menu.return": "UNLOCALIZED: Return to Menu", - "create.menu.configure": "UNLOCALIZED: Configure...", - "create.menu.ponder_index": "UNLOCALIZED: Ponder Index", - "create.menu.only_ingame": "UNLOCALIZED: Available in the Pause Menu", - "create.menu.report_bugs": "UNLOCALIZED: Report Issues", - "create.menu.support": "UNLOCALIZED: Support Us", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Moendo", - "create.recipe.milling": "UNLOCALIZED: Milling", - "create.recipe.fan_washing": "Lavagem em massa", - "create.recipe.fan_washing.fan": "Ventilador atrás de água", - "create.recipe.fan_smoking": "Defumação em massa", - "create.recipe.fan_smoking.fan": "Ventilador atrás de fogo", - "create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", - "create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", - "create.recipe.fan_blasting": "Fundição em massa", - "create.recipe.fan_blasting.fan": "entilador atrás de lava", - "create.recipe.pressing": "Prensa Mecânica", - "create.recipe.mixing": "Misturando", - "create.recipe.deploying": "Implantando", - "create.recipe.automatic_shapeless": "UNLOCALIZED: Automated Shapeless Crafting", - "create.recipe.automatic_brewing": "UNLOCALIZED: Automated Brewing", - "create.recipe.packing": "Compactando", - "create.recipe.automatic_packing": "UNLOCALIZED: Automated Packing", - "create.recipe.sawing": "UNLOCALIZED: Sawing", - "create.recipe.mechanical_crafting": "UNLOCALIZED: Mechanical Crafting", - "create.recipe.automatic_shaped": "UNLOCALIZED: Automated Shaped Crafting", - "create.recipe.block_cutting": "UNLOCALIZED: Block Cutting", - "create.recipe.wood_cutting": "UNLOCALIZED: Wood Cutting", - "create.recipe.sandpaper_polishing": "UNLOCALIZED: Sandpaper Polishing", - "create.recipe.mystery_conversion": "UNLOCALIZED: Mysterious Conversion", - "create.recipe.spout_filling": "UNLOCALIZED: Filling by Spout", - "create.recipe.draining": "UNLOCALIZED: Item Draining", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "UNLOCALIZED: Recipe Sequence", - "create.recipe.assembly.next": "UNLOCALIZED: Next: %1$s", - "create.recipe.assembly.step": "UNLOCALIZED: Step %1$s:", - "create.recipe.assembly.progress": "UNLOCALIZED: Progress: %1$s/%2$s", - "create.recipe.assembly.pressing": "UNLOCALIZED: Process in Press", - "create.recipe.assembly.spout_filling_fluid": "UNLOCALIZED: Spout %1$s", - "create.recipe.assembly.deploying_item": "UNLOCALIZED: Deploy %1$s", - "create.recipe.assembly.cutting": "UNLOCALIZED: Cut with Saw", - "create.recipe.assembly.repeat": "UNLOCALIZED: Repeat Sequence %1$s Times", - "create.recipe.assembly.junk": "UNLOCALIZED: Random salvage", - "create.recipe.processing.chance": "UNLOCALIZED: %1$s%% Chance", - "create.recipe.deploying.not_consumed": "UNLOCALIZED: Not Consumed", - "create.recipe.heat_requirement.none": "UNLOCALIZED: No Heating Required", - "create.recipe.heat_requirement.heated": "UNLOCALIZED: Heated", - "create.recipe.heat_requirement.superheated": "UNLOCALIZED: Super-Heated", - - "create.generic.range": "Área", - "create.generic.radius": "Raio", - "create.generic.width": "Largura", - "create.generic.height": "Altura", - "create.generic.length": "Comprimento", - "create.generic.speed": "Velocidade", - "create.generic.delay": "Demorada", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Segundos", - "create.generic.unit.minutes": "Minutos", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "us", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "Sentido horário", - "create.generic.counter_clockwise": "Sentido anti-horário", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Rolar", - "create.action.confirm": "Confirmar", - "create.action.abort": "Abortar", - "create.action.saveToFile": "Salvar", - "create.action.discard": "Descartar", - - "create.keyinfo.toolmenu": "Menu Focal da Ferramenta", - "create.keyinfo.toolbelt": "UNLOCALIZED: Access Nearby Toolboxes", - "create.keyinfo.scrollup": "UNLOCALIZED: Simulate Mousewheel Up (inworld)", - "create.keyinfo.scrolldown": "UNLOCALIZED: Simulate Mousewheel Down (inworld)", - - "create.gui.scrollInput.defaultTitle": "Escolha uma Opção:", - "create.gui.scrollInput.scrollToModify": "Role o mouse para Modificar", - "create.gui.scrollInput.scrollToAdjustAmount": "UNLOCALIZED: Scroll to Adjust Amount", - "create.gui.scrollInput.scrollToSelect": "Role o mouse para Selecionar", - "create.gui.scrollInput.shiftScrollsFaster": "UNLOCALIZED: Shift to Scroll Faster", - "create.gui.toolmenu.focusKey": "Segure [%1$s] para Focar", - "create.gui.toolmenu.cycle": "[SCROLL] para Circular", - - "create.toolbox.unequip": "UNLOCALIZED: Unequip: %1$s", - "create.toolbox.outOfRange": "UNLOCALIZED: Toolbox of held item not in Range", - "create.toolbox.detach": "UNLOCALIZED: Stop tracking and keep item", - "create.toolbox.depositAll": "UNLOCALIZED: Return items to nearby Toolboxes", - "create.toolbox.depositBox": "UNLOCALIZED: Return items to Toolbox", - - "create.gui.symmetryWand.mirrorType": "Espelhar", - "create.gui.symmetryWand.orientation": "Orientação", - - "create.symmetry.mirror.plane": "Espelhar uma vez", - "create.symmetry.mirror.doublePlane": "Retangular", - "create.symmetry.mirror.triplePlane": "Octagonal", - - "create.orientation.orthogonal": "Ortogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Horizontal", - "create.orientation.alongZ": "Através de Z", - "create.orientation.alongX": "Através de X", - - "create.gui.terrainzapper.title": "UNLOCALIZED: Handheld Blockzapper", - "create.gui.terrainzapper.searchDiagonal": "UNLOCALIZED: Follow Diagonals", - "create.gui.terrainzapper.searchFuzzy": "UNLOCALIZED: Ignore Material Borders", - "create.gui.terrainzapper.patternSection": "UNLOCALIZED: Pattern", - "create.gui.terrainzapper.pattern.solid": "UNLOCALIZED: Solid", - "create.gui.terrainzapper.pattern.checkered": "UNLOCALIZED: Checkerboard", - "create.gui.terrainzapper.pattern.inversecheckered": "UNLOCALIZED: Inverted Checkerboard", - "create.gui.terrainzapper.pattern.chance25": "UNLOCALIZED: 25% Roll", - "create.gui.terrainzapper.pattern.chance50": "UNLOCALIZED: 50% Roll", - "create.gui.terrainzapper.pattern.chance75": "UNLOCALIZED: 75% Roll", - "create.gui.terrainzapper.placement": "UNLOCALIZED: Placement", - "create.gui.terrainzapper.placement.merged": "UNLOCALIZED: Merged", - "create.gui.terrainzapper.placement.attached": "UNLOCALIZED: Attached", - "create.gui.terrainzapper.placement.inserted": "UNLOCALIZED: Inserted", - "create.gui.terrainzapper.brush": "UNLOCALIZED: Brush", - "create.gui.terrainzapper.brush.cuboid": "UNLOCALIZED: Cuboid", - "create.gui.terrainzapper.brush.sphere": "UNLOCALIZED: Sphere", - "create.gui.terrainzapper.brush.cylinder": "UNLOCALIZED: Cylinder", - "create.gui.terrainzapper.brush.surface": "UNLOCALIZED: Surface", - "create.gui.terrainzapper.brush.cluster": "UNLOCALIZED: Cluster", - "create.gui.terrainzapper.tool": "UNLOCALIZED: Tool", - "create.gui.terrainzapper.tool.fill": "UNLOCALIZED: Fill", - "create.gui.terrainzapper.tool.place": "UNLOCALIZED: Place", - "create.gui.terrainzapper.tool.replace": "UNLOCALIZED: Replace", - "create.gui.terrainzapper.tool.clear": "UNLOCALIZED: Clear", - "create.gui.terrainzapper.tool.overlay": "UNLOCALIZED: Overlay", - "create.gui.terrainzapper.tool.flatten": "UNLOCALIZED: Flatten", - - "create.terrainzapper.shiftRightClickToSet": "UNLOCALIZED: Shift-Right-Click to Select a Shape", - "create.terrainzapper.usingBlock": "UNLOCALIZED: Using: %1$s", - "create.terrainzapper.leftClickToSet": "UNLOCALIZED: Left-Click a Block to set Material", - - "create.minecart_coupling.two_couplings_max": "UNLOCALIZED: Minecarts cannot have more than two couplings each", - "create.minecart_coupling.unloaded": "UNLOCALIZED: Parts of your train seem to be in unloaded chunks", - "create.minecart_coupling.no_loops": "UNLOCALIZED: Couplings cannot form a loop", - "create.minecart_coupling.removed": "UNLOCALIZED: Removed all couplings from minecart", - "create.minecart_coupling.too_far": "UNLOCALIZED: Minecarts are too far apart", - - "create.contraptions.movement_mode": "UNLOCALIZED: Movement Mode", - "create.contraptions.movement_mode.move_place": "UNLOCALIZED: Always Place when Stopped", - "create.contraptions.movement_mode.move_place_returned": "UNLOCALIZED: Place only in Starting Position", - "create.contraptions.movement_mode.move_never_place": "UNLOCALIZED: Place only when Anchor Destroyed", - "create.contraptions.movement_mode.rotate_place": "UNLOCALIZED: Always Place when Stopped", - "create.contraptions.movement_mode.rotate_place_returned": "UNLOCALIZED: Only Place near Initial Angle", - "create.contraptions.movement_mode.rotate_never_place": "UNLOCALIZED: Only Place when Anchor Destroyed", - "create.contraptions.cart_movement_mode": "UNLOCALIZED: Cart Movement Mode", - "create.contraptions.cart_movement_mode.rotate": "UNLOCALIZED: Always face toward motion", - "create.contraptions.cart_movement_mode.rotate_paused": "UNLOCALIZED: Pause actors while rotating", - "create.contraptions.cart_movement_mode.rotation_locked": "UNLOCALIZED: Lock rotation", - "create.contraptions.windmill.rotation_direction": "UNLOCALIZED: Rotation Direction", - "create.contraptions.clockwork.clock_hands": "UNLOCALIZED: Clock Hands", - "create.contraptions.clockwork.hour_first": "UNLOCALIZED: Hour hand first", - "create.contraptions.clockwork.minute_first": "UNLOCALIZED: Minute hand first", - "create.contraptions.clockwork.hour_first_24": "UNLOCALIZED: 24-Hour hand first", - - "create.logistics.filter": "UNLOCALIZED: Filter", - "create.logistics.recipe_filter": "UNLOCALIZED: Recipe Filter", - "create.logistics.fluid_filter": "UNLOCALIZED: Fluid Filter", - "create.logistics.firstFrequency": "UNLOCALIZED: Freq. #1", - "create.logistics.secondFrequency": "UNLOCALIZED: Freq. #2", - "create.logistics.filter.apply": "UNLOCALIZED: Applied filter to %1$s.", - "create.logistics.filter.apply_click_again": "UNLOCALIZED: Applied filter to %1$s, click again to copy the amount.", - "create.logistics.filter.apply_count": "UNLOCALIZED: Applied extraction count to filter.", - - "create.gui.goggles.generator_stats": "Estatísticas do gerador:", - "create.gui.goggles.kinetic_stats": "Estatísticas cinéticas:", - "create.gui.goggles.at_current_speed": "Na velocidade atual", - "create.gui.goggles.pole_length": "Comprimento da vara:", - "create.gui.goggles.fluid_container": "UNLOCALIZED: Fluid Container Info:", - "create.gui.goggles.fluid_container.capacity": "UNLOCALIZED: Capacity: ", - "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", - "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s,%2$s,%3$s] was not in a loaded chunk", - "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", - "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", - "create.gui.assembly.exception.not_enough_sails": "UNLOCALIZED: Attached structure does not include enough sail-like blocks: %1$s\nA minimum of %2$s are required", - "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", - "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", - "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", - "create.gui.stressometer.capacity": "UNLOCALIZED: Remaining Capacity", - "create.gui.stressometer.overstressed": "UNLOCALIZED: Overstressed", - "create.gui.stressometer.no_rotation": "UNLOCALIZED: No Rotation", - "create.gui.contraptions.not_fast_enough": "UNLOCALIZED: It appears that this %1$s is _not_ rotating with _enough_ _speed_.", - "create.gui.contraptions.network_overstressed": "UNLOCALIZED: It appears that this contraption is _overstressed_. Add more sources or _slow_ _down_ the components with a high _stress_ _impact_.", - "create.gui.adjustable_crate.title": "UNLOCALIZED: Adjustable Crate", - "create.gui.adjustable_crate.storageSpace": "UNLOCALIZED: Storage Space", - "create.gui.stockpile_switch.title": "UNLOCALIZED: Stockpile Switch", - "create.gui.stockpile_switch.invert_signal": "UNLOCALIZED: Invert Signal", - "create.gui.stockpile_switch.move_to_lower_at": "UNLOCALIZED: Move to lower lane at %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "UNLOCALIZED: Move to upper lane at %1$s%%", - "create.gui.sequenced_gearshift.title": "UNLOCALIZED: Sequenced Gearshift", - "create.gui.sequenced_gearshift.instruction": "UNLOCALIZED: Instruction", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "UNLOCALIZED: Turn by angle", - "create.gui.sequenced_gearshift.instruction.turn_angle": "UNLOCALIZED: Turn", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "UNLOCALIZED: Angle", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "UNLOCALIZED: Turn to move Piston/Pulley/Gantry", - "create.gui.sequenced_gearshift.instruction.turn_distance": "UNLOCALIZED: Piston", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "UNLOCALIZED: Distance", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "UNLOCALIZED: Timed Delay", - "create.gui.sequenced_gearshift.instruction.delay": "UNLOCALIZED: Delay", - "create.gui.sequenced_gearshift.instruction.delay.duration": "UNLOCALIZED: Duration", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "UNLOCALIZED: End", - "create.gui.sequenced_gearshift.instruction.end": "UNLOCALIZED: End", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "UNLOCALIZED: Await new Redstone Pulse", - "create.gui.sequenced_gearshift.instruction.await": "UNLOCALIZED: Await", - "create.gui.sequenced_gearshift.speed": "UNLOCALIZED: Speed, Direction", - "create.gui.sequenced_gearshift.speed.forward": "UNLOCALIZED: Input speed, Forwards", - "create.gui.sequenced_gearshift.speed.forward_fast": "UNLOCALIZED: Double speed, Forwards", - "create.gui.sequenced_gearshift.speed.back": "UNLOCALIZED: Input speed, Reversed", - "create.gui.sequenced_gearshift.speed.back_fast": "UNLOCALIZED: Double speed, Reversed", - - "create.schematicAndQuill.dimensions": "Tamanho Esquema: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Primeira posição feita.", - "create.schematicAndQuill.secondPos": "Segunda posição feita.", - "create.schematicAndQuill.noTarget": "Seguro [Ctrl] para selecionar Blocos de Ar.", - "create.schematicAndQuill.abort": "Seleção removida.", - "create.schematicAndQuill.title": "UNLOCALIZED: Schematic Name:", - "create.schematicAndQuill.convert": "UNLOCALIZED: Save and Upload Immediately", - "create.schematicAndQuill.fallbackName": "Meu Esquema", - "create.schematicAndQuill.saved": "Salvo como %1$s", - - "create.schematic.invalid": "[!] Item Inválido - Use a Mesa de Desenho no lugar", - "create.schematic.position": "Posição", - "create.schematic.rotation": "Rotação", - "create.schematic.rotation.none": "Nada", - "create.schematic.rotation.cw90": "Sentido horário 90", - "create.schematic.rotation.cw180": "Sentido horário 180", - "create.schematic.rotation.cw270": "Sentido horário 270", - "create.schematic.mirror": "Espelhar", - "create.schematic.mirror.none": "Nada", - "create.schematic.mirror.frontBack": "Frente para Trás", - "create.schematic.mirror.leftRight": "Esquerda para Direita", - "create.schematic.tool.deploy": "Concluir", - "create.schematic.tool.move": "Mover XZ", - "create.schematic.tool.movey": "Mover Y", - "create.schematic.tool.rotate": "Rodar", - "create.schematic.tool.print": "Imprimir", - "create.schematic.tool.flip": "Virar", - "create.schematic.tool.deploy.description.0": "Move o lugar da estrutura.", - "create.schematic.tool.deploy.description.1": "Botão-direito no chão para colocar.", - "create.schematic.tool.deploy.description.2": "Segure [Ctrl] para selecionar em uma distância fixa.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Rolar para mudar a distância.", - "create.schematic.tool.move.description.0": "Vira o Esquema Horizontalmente", - "create.schematic.tool.move.description.1": "Aponte ao Esquema e [CTRL]-Rolar para empurrar.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Vira o Esquema Verticalmente", - "create.schematic.tool.movey.description.1": "[CTRL]-Rolar para mover para cima/baixo", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Roda o Esquema em torno do seu centro.", - "create.schematic.tool.rotate.description.1": "[CTRL]-Rolar para rolar 90 Graus", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Coloca estrutura no mundo instantaneamente", - "create.schematic.tool.print.description.1": "[Botão-Direito] para confirmar a posição atual.", - "create.schematic.tool.print.description.2": "Esta ferramenta é para o Modo Criativo apenas.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Gira o Esquema ao longo da face que você selecionar.", - "create.schematic.tool.flip.description.1": "Aponte para o Esquema e [CTRL]-Rolar para virá-lo.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Sincronizando...", - "create.schematics.uploadTooLarge": "Seu esquema é muito grande", - "create.schematics.maxAllowedSize": "O tamanho máximo permitido para o esquema é:", - - "create.gui.schematicTable.refresh": "UNLOCALIZED: Refresh Files", - "create.gui.schematicTable.open_folder": "UNLOCALIZED: Open Folder", - "create.gui.schematicTable.title": "Mesa de Desenho", - "create.gui.schematicTable.availableSchematics": "UNLOCALIZED: Available Schematics", - "create.gui.schematicTable.noSchematics": "UNLOCALIZED: No Schematics Saved", - "create.gui.schematicTable.uploading": "Importando...", - "create.gui.schematicTable.finished": "Envio Concluído!", - "create.gui.schematicannon.title": "Canhão de esquema", - "create.gui.schematicannon.listPrinter": "Impressora de Lista de Materiais", - "create.gui.schematicannon.gunpowderLevel": "Pólvora em %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Disparos faltantes: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Com backup: %1$s", - "create.gui.schematicannon.optionEnabled": "Habilitado Atualmente", - "create.gui.schematicannon.optionDisabled": "Desabilitado Atualmente", - "create.gui.schematicannon.showOptions": "UNLOCALIZED: Show Printer Settings", - "create.gui.schematicannon.option.dontReplaceSolid": "Não Substituir Blocos Sólidos", - "create.gui.schematicannon.option.replaceWithSolid": "Substituir Blocos Sólidos", - "create.gui.schematicannon.option.replaceWithAny": "Substituir Sólidos com Qualquer", - "create.gui.schematicannon.option.replaceWithEmpty": "Substituir Sólidos com Vazio", - "create.gui.schematicannon.option.skipMissing": "Pulando Blocos faltantes", - "create.gui.schematicannon.option.skipTileEntities": "Proteger Entidades Entalhadas", - "create.gui.schematicannon.slot.gunpowder": "UNLOCALIZED: Add gunpowder to fuel the cannon", - "create.gui.schematicannon.slot.listPrinter": "UNLOCALIZED: Place books here to print a Checklist for your Schematic", - "create.gui.schematicannon.slot.schematic": "UNLOCALIZED: Add your Schematic here. Make sure it is deployed at a specific location.", - "create.gui.schematicannon.option.skipMissing.description": "Se o Canhão de esquema não encontrar o Bloco para colocar, ele irá continuar para a próx. Posição.", - "create.gui.schematicannon.option.skipTileEntities.description": "O Canhão de esquema vai evitar substituir blocos que contêm dados como Baus.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "O Canhão de esquema nunca irá substituir Blocos sólidos na área em trabalho, apenas não-Sólidos e Ar.", - "create.gui.schematicannon.option.replaceWithSolid.description": "O Canhão de esquema irá apenas substituir Blocos sólidos na área de trabalho, se o Esquema conter um bloco Sólido naquela posição.", - "create.gui.schematicannon.option.replaceWithAny.description": "O Canhão de esquema irá substituir Blocos sólidos na área de trabalho, se o Esquema conter qualquer Bloco naquela posição.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "O Canhão de esquema irá limpar todos os blocos na área de trabalho, incluindo os substituídos por Ar.", - - "create.schematicannon.status.idle": "Ocioso", - "create.schematicannon.status.ready": "Pronto", - "create.schematicannon.status.running": "Trabalhando", - "create.schematicannon.status.finished": "Concluído", - "create.schematicannon.status.paused": "Pausado", - "create.schematicannon.status.stopped": "Parada", - "create.schematicannon.status.noGunpowder": "UNLOCALIZED: Sem pólvora", - "create.schematicannon.status.targetNotLoaded": "Bloco não carregado", - "create.schematicannon.status.targetOutsideRange": "Alvo está muito Longe", - "create.schematicannon.status.searching": "Procurando", - "create.schematicannon.status.skipping": "Pulando", - "create.schematicannon.status.missingBlock": "Bloco Faltante:", - "create.schematicannon.status.placing": "Colocando", - "create.schematicannon.status.clearing": "Limpando Blocos", - "create.schematicannon.status.schematicInvalid": "Esquema Inválido", - "create.schematicannon.status.schematicNotPlaced": "Esquema não Colocado", - "create.schematicannon.status.schematicExpired": "Arquivo de Esquema Expirado", - - "create.materialChecklist": "UNLOCALIZED: Material Checklist", - "create.materialChecklist.blocksNotLoaded": "UNLOCALIZED: * Disclaimer *\n\nMaterial List may be inaccurate due to relevant chunks not being loaded.", - - "create.gui.filter.deny_list": "UNLOCALIZED: Deny-List", - "create.gui.filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT match any of the above. An empty Deny-List accepts everything.", - "create.gui.filter.allow_list": "UNLOCALIZED: Allow-List", - "create.gui.filter.allow_list.description": "UNLOCALIZED: Items pass if they match any of the above. An empty Allow-List rejects everything.", - "create.gui.filter.respect_data": "UNLOCALIZED: Respect Data", - "create.gui.filter.respect_data.description": "UNLOCALIZED: Items only match if their durability, enchantments, and other attributes match as well.", - "create.gui.filter.ignore_data": "UNLOCALIZED: Ignore Data", - "create.gui.filter.ignore_data.description": "UNLOCALIZED: Items match regardless of their attributes.", - - "create.item_attributes.placeable": "UNLOCALIZED: is placeable", - "create.item_attributes.placeable.inverted": "UNLOCALIZED: is not placeable", - "create.item_attributes.consumable": "UNLOCALIZED: can be eaten", - "create.item_attributes.consumable.inverted": "UNLOCALIZED: cannot be eaten", - "create.item_attributes.fluid_container": "UNLOCALIZED: can store fluids", - "create.item_attributes.fluid_container.inverted": "UNLOCALIZED: cannot store fluids", - "create.item_attributes.enchanted": "UNLOCALIZED: is enchanted", - "create.item_attributes.enchanted.inverted": "UNLOCALIZED: is unenchanted", - "create.item_attributes.max_enchanted": "UNLOCALIZED: is enchanted at max level", - "create.item_attributes.max_enchanted.inverted": "UNLOCALIZED: is not enchanted at max level", - "create.item_attributes.renamed": "UNLOCALIZED: has a custom name", - "create.item_attributes.renamed.inverted": "UNLOCALIZED: does not have a custom name", - "create.item_attributes.damaged": "UNLOCALIZED: is damaged", - "create.item_attributes.damaged.inverted": "UNLOCALIZED: is not damaged", - "create.item_attributes.badly_damaged": "UNLOCALIZED: is heavily damaged", - "create.item_attributes.badly_damaged.inverted": "UNLOCALIZED: is not heavily damaged", - "create.item_attributes.not_stackable": "UNLOCALIZED: cannot stack", - "create.item_attributes.not_stackable.inverted": "UNLOCALIZED: can be stacked", - "create.item_attributes.equipable": "UNLOCALIZED: can be equipped", - "create.item_attributes.equipable.inverted": "UNLOCALIZED: cannot be equipped", - "create.item_attributes.furnace_fuel": "UNLOCALIZED: is furnace fuel", - "create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel", - "create.item_attributes.washable": "UNLOCALIZED: can be Washed", - "create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed", - "create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", - "create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", - "create.item_attributes.crushable": "UNLOCALIZED: can be Crushed", - "create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed", - "create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted", - "create.item_attributes.smeltable.inverted": "UNLOCALIZED: cannot be Smelted", - "create.item_attributes.smokable": "UNLOCALIZED: can be Smoked", - "create.item_attributes.smokable.inverted": "UNLOCALIZED: cannot be Smoked", - "create.item_attributes.blastable": "UNLOCALIZED: can be Smelted in a Blast Furnace", - "create.item_attributes.blastable.inverted": "UNLOCALIZED: cannot be Smelted in a Blast Furnace", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "UNLOCALIZED: is shulker %1$s", - "create.item_attributes.shulker_level.inverted": "UNLOCALIZED: is shulker not %1$s", - "create.item_attributes.shulker_level.full": "UNLOCALIZED: full", - "create.item_attributes.shulker_level.empty": "UNLOCALIZED: empty", - "create.item_attributes.shulker_level.partial": "UNLOCALIZED: partially filled", - "create.item_attributes.in_tag": "UNLOCALIZED: is tagged %1$s", - "create.item_attributes.in_tag.inverted": "UNLOCALIZED: is not tagged %1$s", - "create.item_attributes.in_item_group": "UNLOCALIZED: is in group '%1$s'", - "create.item_attributes.in_item_group.inverted": "UNLOCALIZED: is not in group '%1$s'", - "create.item_attributes.added_by": "UNLOCALIZED: was added by %1$s", - "create.item_attributes.added_by.inverted": "UNLOCALIZED: was not added by %1$s", - "create.item_attributes.has_enchant": "UNLOCALIZED: is enchanted with %1$s", - "create.item_attributes.has_enchant.inverted": "UNLOCALIZED: is not enchanted with %1$s", - "create.item_attributes.color": "UNLOCALIZED: is dyed %1$s", - "create.item_attributes.color.inverted": "UNLOCALIZED: is not dyed %1$s", - "create.item_attributes.has_fluid": "UNLOCALIZED: contains %1$s", - "create.item_attributes.has_fluid.inverted": "UNLOCALIZED: does not contain %1$s", - "create.item_attributes.has_name": "UNLOCALIZED: has the custom name %1$s", - "create.item_attributes.has_name.inverted": "UNLOCALIZED: does not have the custom name %1$s", - "create.item_attributes.book_author": "UNLOCALIZED: was authored by %1$s", - "create.item_attributes.book_author.inverted": "UNLOCALIZED: was not authored by %1$s", - "create.item_attributes.book_copy_original": "UNLOCALIZED: is an original", - "create.item_attributes.book_copy_original.inverted": "UNLOCALIZED: is not an original", - "create.item_attributes.book_copy_first": "UNLOCALIZED: is a first-generation copy", - "create.item_attributes.book_copy_first.inverted": "UNLOCALIZED: is not a first-generation copy", - "create.item_attributes.book_copy_second": "UNLOCALIZED: is a second-generation copy", - "create.item_attributes.book_copy_second.inverted": "UNLOCALIZED: is not a second-generation copy", - "create.item_attributes.book_copy_tattered": "UNLOCALIZED: is a tattered mess", - "create.item_attributes.book_copy_tattered.inverted": "UNLOCALIZED: is not a tattered mess", - "create.item_attributes.astralsorcery_amulet": "UNLOCALIZED: improves %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "UNLOCALIZED: does not improve %1$s", - "create.item_attributes.astralsorcery_constellation": "UNLOCALIZED: is attuned to %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "UNLOCALIZED: is not attuned to %1$s", - "create.item_attributes.astralsorcery_crystal": "UNLOCALIZED: has crystal attribute %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "UNLOCALIZED: does not have crystal attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem": "UNLOCALIZED: has perk attribute %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "UNLOCALIZED: does not have perk attribute %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "UNLOCALIZED: No attributes selected", - "create.gui.attribute_filter.selected_attributes": "UNLOCALIZED: Selected attributes:", - "create.gui.attribute_filter.add_attribute": "UNLOCALIZED: Add attribute to List", - "create.gui.attribute_filter.add_inverted_attribute": "UNLOCALIZED: Add opposite attribute to List", - "create.gui.attribute_filter.allow_list_disjunctive": "UNLOCALIZED: Allow-List (Any)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "UNLOCALIZED: Items pass if they have any of the selected attributes.", - "create.gui.attribute_filter.allow_list_conjunctive": "UNLOCALIZED: Allow-List (All)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "UNLOCALIZED: Items pass only if they have ALL of the selected attributes.", - "create.gui.attribute_filter.deny_list": "UNLOCALIZED: Deny-List", - "create.gui.attribute_filter.deny_list.description": "UNLOCALIZED: Items pass if they do NOT have any of the selected attributes.", - "create.gui.attribute_filter.add_reference_item": "UNLOCALIZED: Add Reference Item", - - "create.tooltip.holdForDescription": "UNLOCALIZED: Hold [%1$s] for Summary", - "create.tooltip.holdForControls": "UNLOCALIZED: Hold [%1$s] for Controls", - "create.tooltip.keyShift": "UNLOCALIZED: Shift", - "create.tooltip.keyCtrl": "UNLOCALIZED: Ctrl", - "create.tooltip.speedRequirement": "UNLOCALIZED: Speed Requirement: %1$s", - "create.tooltip.speedRequirement.none": "UNLOCALIZED: None", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "UNLOCALIZED: Moderate", - "create.tooltip.speedRequirement.fast": "UNLOCALIZED: Fast", - "create.tooltip.stressImpact": "UNLOCALIZED: Kinetic Stress Impact: %1$s", - "create.tooltip.stressImpact.low": "UNLOCALIZED: Low", - "create.tooltip.stressImpact.medium": "UNLOCALIZED: Moderate", - "create.tooltip.stressImpact.high": "UNLOCALIZED: High", - "create.tooltip.stressImpact.overstressed": "UNLOCALIZED: Overstressed", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "UNLOCALIZED: Kinetic Stress Capacity: %1$s", - "create.tooltip.capacityProvided.low": "UNLOCALIZED: Small", - "create.tooltip.capacityProvided.medium": "UNLOCALIZED: Medium", - "create.tooltip.capacityProvided.high": "UNLOCALIZED: Large", - "create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s", - "create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15", - - "create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s", - "create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s", - "create.mechanical_arm.summary": "UNLOCALIZED: Mechanical Arm has %1$s input(s) and %2$s output(s).", - "create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.", - - "create.weighted_ejector.target_set": "UNLOCALIZED: Target Selected", - "create.weighted_ejector.target_not_valid": "UNLOCALIZED: Ejecting to Adjacent block (Target was not Valid)", - "create.weighted_ejector.no_target": "UNLOCALIZED: Ejecting to Adjacent block (No Target was Selected)", - "create.weighted_ejector.targeting": "UNLOCALIZED: Ejecting to [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "UNLOCALIZED: Ejected Stack Size", - - "create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available", - - "create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.mechanical_arm.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.mechanical_arm.selection_mode.prefer_first": "UNLOCALIZED: Prefer First Target", - - "create.tunnel.selection_mode.split": "UNLOCALIZED: Split", - "create.tunnel.selection_mode.forced_split": "UNLOCALIZED: Forced Split", - "create.tunnel.selection_mode.round_robin": "UNLOCALIZED: Round Robin", - "create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin", - "create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest", - "create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize", - "create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs", - - "create.tooltip.chute.header": "UNLOCALIZED: Chute Information", - "create.tooltip.chute.items_move_down": "UNLOCALIZED: Items move Downward", - "create.tooltip.chute.items_move_up": "UNLOCALIZED: Items move Upward", - "create.tooltip.chute.no_fans_attached": "UNLOCALIZED: No attached fans", - "create.tooltip.chute.fans_push_up": "UNLOCALIZED: Fans push from Below", - "create.tooltip.chute.fans_push_down": "UNLOCALIZED: Fans push from Above", - "create.tooltip.chute.fans_pull_up": "UNLOCALIZED: Fans pull from Above", - "create.tooltip.chute.fans_pull_down": "UNLOCALIZED: Fans pull from Below", - "create.tooltip.chute.contains": "UNLOCALIZED: Contains: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "UNLOCALIZED: Currently distributing:", - "create.tooltip.brass_tunnel.contains_entry": "UNLOCALIZED: > %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "UNLOCALIZED: Right-Click to retrieve", - - "create.linked_controller.bind_mode": "UNLOCALIZED: Bind mode active", - "create.linked_controller.press_keybind": "UNLOCALIZED: Press %1$s, %2$s, %3$s, %4$s, %5$s or %6$s, to bind this frequency to the respective key", - "create.linked_controller.key_bound": "UNLOCALIZED: Frequency bound to %1$s", - "create.linked_controller.frequency_slot_1": "UNLOCALIZED: Keybind: %1$s, Freq. #1", - "create.linked_controller.frequency_slot_2": "UNLOCALIZED: Keybind: %1$s, Freq. #2", - - "create.crafting_blueprint.crafting_slot": "UNLOCALIZED: Ingredient Slot", - "create.crafting_blueprint.filter_items_viable": "UNLOCALIZED: Advanced filter items are viable", - "create.crafting_blueprint.display_slot": "UNLOCALIZED: Display Slot", - "create.crafting_blueprint.inferred": "UNLOCALIZED: Inferred from recipe", - "create.crafting_blueprint.manually_assigned": "UNLOCALIZED: Manually assigned", - "create.crafting_blueprint.secondary_display_slot": "UNLOCALIZED: Secondary Display Slot", - "create.crafting_blueprint.optional": "UNLOCALIZED: Optional", - - "create.potato_cannon.ammo.attack_damage": "UNLOCALIZED: %1$s Attack Damage", - "create.potato_cannon.ammo.reload_ticks": "UNLOCALIZED: %1$s Reload Ticks", - "create.potato_cannon.ammo.knockback": "UNLOCALIZED: %1$s Knockback", - - "create.hint.hose_pulley.title": "UNLOCALIZED: Bottomless Supply", - "create.hint.hose_pulley": "UNLOCALIZED: The targeted body of fluid is considered infinite.", - "create.hint.mechanical_arm_no_targets.title": "UNLOCALIZED: No Targets", - "create.hint.mechanical_arm_no_targets": "UNLOCALIZED: It appears this _Mechanical_ _Arm_ has not been assigned any _targets._ Select belts, depots, funnels and other blocks by _right-clicking_ them while _holding_ the _Mechanical_ _Arm_ in your _hand_.", - "create.hint.empty_bearing.title": "UNLOCALIZED: Update Bearing", - "create.hint.empty_bearing": "UNLOCALIZED: _Right-click_ the bearing with an _empty_ _hand_ to _attach_ the structure you just built in front of it.", - "create.hint.full_deployer.title": "UNLOCALIZED: Deployer Item Overflow", - "create.hint.full_deployer": "UNLOCALIZED: It appears this _Deployer_ contains _excess_ _items_ that need to be _extracted._ Use a _hopper,_ _funnel_ or other means to free it from its overflow.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "UNLOCALIZED: Hi :)", - "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", - "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", - "create.gui.config.overlay4": "UNLOCALIZED: to move this preview", - "create.gui.config.overlay5": "UNLOCALIZED: Press ESC to exit this screen", - "create.gui.config.overlay6": "UNLOCALIZED: and save the new position", - "create.gui.config.overlay7": "UNLOCALIZED: Run /create overlay reset", - "create.gui.config.overlay8": "UNLOCALIZED: to reset to the default position", - - "create.command.killTPSCommand": "UNLOCALIZED: killtps", - "create.command.killTPSCommand.status.slowed_by.0": "UNLOCALIZED: [Create]: Server tick is currently slowed by %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "UNLOCALIZED: [Create]: Server tick is slowed by %s ms now >:)", - "create.command.killTPSCommand.status.slowed_by.2": "UNLOCALIZED: [Create]: Server tick is back to regular speed :D", - "create.command.killTPSCommand.status.usage.0": "UNLOCALIZED: [Create]: use /killtps stop to bring back server tick to regular speed", - "create.command.killTPSCommand.status.usage.1": "UNLOCALIZED: [Create]: use /killtps start to artificially slow down the server tick", - "create.command.killTPSCommand.argument.tickTime": "UNLOCALIZED: tickTime", - - "create.contraption.minecart_contraption_too_big": "UNLOCALIZED: This Cart Contraption seems too big to pick up", - "create.contraption.minecart_contraption_illegal_pickup": "UNLOCALIZED: A mystical force is binding this Cart Contraption to the world", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "UNLOCALIZED: Contraption stops", - "create.subtitle.peculiar_bell_use": "UNLOCALIZED: Peculiar Bell tolls", - "create.subtitle.worldshaper_place": "UNLOCALIZED: Worldshaper zaps", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.schematicannon_finish": "UNLOCALIZED: Schematicannon dings", - "create.subtitle.crafter_craft": "UNLOCALIZED: Crafter crafts", - "create.subtitle.wrench_remove": "UNLOCALIZED: Component breaks", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "UNLOCALIZED: Cogwheels rumble", - "create.subtitle.slime_added": "UNLOCALIZED: Slime squishes", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "UNLOCALIZED: Schematicannon fires", - "create.subtitle.controller_take": "UNLOCALIZED: Lectern empties", - "create.subtitle.crafter_click": "UNLOCALIZED: Crafter clicks", - "create.subtitle.depot_plop": "UNLOCALIZED: Item lands", - "create.subtitle.confirm": "UNLOCALIZED: Affirmative ding", - "create.subtitle.mixing": "UNLOCALIZED: Mixing noises", - "create.subtitle.mechanical_press_activation_belt": "UNLOCALIZED: Mechanical Press bonks", - "create.subtitle.fwoomp": "UNLOCALIZED: Potato Launcher fwoomps", - "create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", - "create.subtitle.crushing_1": "UNLOCALIZED: Crushing noises", - "create.subtitle.depot_slide": "UNLOCALIZED: Item slides", - "create.subtitle.blaze_munch": "UNLOCALIZED: Blaze Burner munches", - "create.subtitle.funnel_flap": "UNLOCALIZED: Funnel flaps", - "create.subtitle.haunted_bell_use": "UNLOCALIZED: Haunted Bell tolls", - "create.subtitle.scroll_value": "UNLOCALIZED: Scroll-input clicks", - "create.subtitle.controller_put": "UNLOCALIZED: Controller thumps", - "create.subtitle.cranking": "UNLOCALIZED: Hand Crank turns", - "create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", - "create.subtitle.wrench_rotate": "UNLOCALIZED: Wrench used", - "create.subtitle.potato_hit": "UNLOCALIZED: Vegetable impacts", - "create.subtitle.saw_activate_wood": "UNLOCALIZED: Mechanical Saw activates", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "UNLOCALIZED: Haunted Bell awakens", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "UNLOCALIZED: Declining boop", - "create.subtitle.controller_click": "UNLOCALIZED: Controller clicks", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "UNLOCALIZED: Diving equipment clinks", - "create.subtitle.mechanical_press_activation": "UNLOCALIZED: Mechanical Press clangs", - "create.subtitle.contraption_assemble": "UNLOCALIZED: Contraption moves", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "Quando this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And Quando this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "Quando Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "UNLOCALIZED: WOODEN BRACKET", - "block.create.wooden_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with a cozy and wooden bit of reinforcement.", - - "block.create.metal_bracket.tooltip": "UNLOCALIZED: METAL BRACKET", - "block.create.metal_bracket.tooltip.summary": "UNLOCALIZED: _Decorate_ your _Shafts, Cogwheels_ and _Pipes_ with an industrial and sturdy bit of reinforcement.", - - "block.create.seat.tooltip": "UNLOCALIZED: SEAT", - "block.create.seat.tooltip.summary": "UNLOCALIZED: Sit yourself down and enjoy the ride! Will anchor a player onto a moving _contraption_. Great for static furniture too! Comes in a variety of colours.", - "block.create.seat.tooltip.condition1": "UNLOCALIZED: Right click on Seat", - "block.create.seat.tooltip.behaviour1": "UNLOCALIZED: Sits the player on the _Seat_. Press L-shift to leave the _Seat_.", - - "item.create.blaze_cake.tooltip": "UNLOCALIZED: BLAZE CAKE", - "item.create.blaze_cake.tooltip.summary": "UNLOCALIZED: A Delicious treat for your hard-working _Blaze Burners_. Gets them all fired up!", - - "item.create.wand_of_symmetry.tooltip": "VARINHA DE SIMETRIA", - "item.create.wand_of_symmetry.tooltip.summary": "Espelhar perfeitamente a colocação de blocos nos planos configurados.", - "item.create.wand_of_symmetry.tooltip.condition1": "Quando na Hotbar", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Mantem-se Ativo", - "item.create.wand_of_symmetry.tooltip.control1": "B-Direito no Chão", - "item.create.wand_of_symmetry.tooltip.action1": "_Cria_ ou _Move_ o Espelho", - "item.create.wand_of_symmetry.tooltip.control2": "B-Direito no Ar", - "item.create.wand_of_symmetry.tooltip.action2": "_Remove_ o Espelho ativo", - "item.create.wand_of_symmetry.tooltip.control3": "B-Direito enquanto Abaixado", - "item.create.wand_of_symmetry.tooltip.action3": "Abre _Interface_ de _Configuração_", - - "item.create.handheld_worldshaper.tooltip": "UNLOCALIZED: HANDHELD WORLDSHAPER", - "item.create.handheld_worldshaper.tooltip.summary": "UNLOCALIZED: Handy tool for creating _landscapes_ and _terrain features_.", - "item.create.handheld_worldshaper.tooltip.control1": "UNLOCALIZED: L-Click at Block", - "item.create.handheld_worldshaper.tooltip.action1": "UNLOCALIZED: Sets blocks placed by the tool to the targeted block.", - "item.create.handheld_worldshaper.tooltip.control2": "UNLOCALIZED: R-Click at Block", - "item.create.handheld_worldshaper.tooltip.action2": "UNLOCALIZED: Applies the currently selected _Brush_ and _Tool_ at the targeted location.", - "item.create.handheld_worldshaper.tooltip.control3": "UNLOCALIZED: R-Click while Sneaking", - "item.create.handheld_worldshaper.tooltip.action3": "UNLOCALIZED: Opens the _Configuration Interface_", - - "item.create.tree_fertilizer.tooltip": "FERTILIZANTE DE ARVORE", - "item.create.tree_fertilizer.tooltip.summary": "Uma combinação poderosa de minerais para tipos comuns de arvores", - "item.create.tree_fertilizer.tooltip.condition1": "Quando usada em Mudas", - "item.create.tree_fertilizer.tooltip.behaviour1": "Cresce Arvores independentemente das suas Regras de espaço", - - "item.create.extendo_grip.tooltip": "UNLOCALIZED: EXTENDO GRIP", - "item.create.extendo_grip.tooltip.summary": "UNLOCALIZED: Boioioing! Greatly _increases reach distance_ of the wielder. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.extendo_grip.tooltip.condition1": "UNLOCALIZED: When in Off-Hand", - "item.create.extendo_grip.tooltip.behaviour1": "UNLOCALIZED: Increases _reach distance_ of items used in the _Main-Hand_.", - "item.create.extendo_grip.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.extendo_grip.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.potato_cannon.tooltip": "UNLOCALIZED: POTATO CANNON", - "item.create.potato_cannon.tooltip.summary": "UNLOCALIZED: Fwoomp! Launch your home-grown vegetables at your Enemies. Can be powered with Air Pressure from a _Copper_ _Backtank_", - "item.create.potato_cannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "item.create.potato_cannon.tooltip.behaviour1": "UNLOCALIZED: _Shoots_ a suitable item from your _Inventory_.", - "item.create.potato_cannon.tooltip.condition2": "UNLOCALIZED: While wearing Copper Backtank", - "item.create.potato_cannon.tooltip.behaviour2": "UNLOCALIZED: _No_ _Durability_ will be used. Instead, _Air_ _pressure_ is drained from the Tank", - - "item.create.filter.tooltip": "UNLOCALIZED: FILTER", - "item.create.filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of items_ or several _nested filters_.", - "item.create.filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.attribute_filter.tooltip": "UNLOCALIZED: ATTRIBUTE FILTER", - "item.create.attribute_filter.tooltip.summary": "UNLOCALIZED: _Controls outputs_ and _inputs_ of logistical devices with more _precision_, matching them against a _set of_ item _attributes_ and _categories_.", - "item.create.attribute_filter.tooltip.condition1": "UNLOCALIZED: When in filter slot", - "item.create.attribute_filter.tooltip.behaviour1": "UNLOCALIZED: _Controls_ item flow according to its _configuration_.", - "item.create.attribute_filter.tooltip.condition2": "UNLOCALIZED: When R-Clicked", - "item.create.attribute_filter.tooltip.behaviour2": "UNLOCALIZED: Opens the _configuration interface_.", - - "item.create.empty_schematic.tooltip": "ESQUEMA VAZIO", - "item.create.empty_schematic.tooltip.summary": "Usado como ingrediente em receitas e para escrever na _Mesa_ _de_ _Esquematizar_", - - "item.create.schematic.tooltip": "ESQUEMA", - "item.create.schematic.tooltip.summary": "Contem uma estrutura para ser posicionada e colocada no mundo. Posicione o Holograma como desejar e use um _Esquemaannon_ para construí-lo.", - "item.create.schematic.tooltip.condition1": "Quando Em mãos", - "item.create.schematic.tooltip.behaviour1": "Pode ser posicionado usando as Ferramentas em Tela", - "item.create.schematic.tooltip.control1": "B-Direito enquanto Abaixado", - "item.create.schematic.tooltip.action1": "Abre uma _Interface_ para informar as _Coordenadas_ exatas.", - - "item.create.schematic_and_quill.tooltip": "ESQUEMA E PENA", - "item.create.schematic_and_quill.tooltip.summary": "Usado para salvar uma Estrutura no mundo para um arquivo .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Passo 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selecione duas coordenadas de extremidade usando B-Direito", - "item.create.schematic_and_quill.tooltip.condition2": "Passo 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Rolar_ nas faces para ajustar o tamanho. B-Direito de novo para Salvar.", - "item.create.schematic_and_quill.tooltip.control1": "B-Direito", - "item.create.schematic_and_quill.tooltip.action1": "Selecione um canto / confirmar salvamento", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Pressionado", - "item.create.schematic_and_quill.tooltip.action2": "Selecione pontos no _meio_ _do_ _ar_. _Rolar_ para ajustar a distância.", - "item.create.schematic_and_quill.tooltip.control3": "B-Direito enquanto Abaixado", - "item.create.schematic_and_quill.tooltip.action3": "_Cancela_ e remove a seleção.", - - "block.create.schematicannon.tooltip": "Canhão de esquema", - "block.create.schematicannon.tooltip.summary": "Dispara blocos para recriar um _Esquema_ no Mundo. Usa itens de Inventários adjacentes e _Pólvora_ como combustível.", - "block.create.schematicannon.tooltip.condition1": "UNLOCALIZED: When R-Clicked", - "block.create.schematicannon.tooltip.behaviour1": "UNLOCALIZED: Opens the _Interface_", - - "block.create.schematic_table.tooltip": "MESA DE ESQUEMATIZAR", - "block.create.schematic_table.tooltip.summary": "Escreve Esquemas salvos into um _Esquema_ _Vazio_", - "block.create.schematic_table.tooltip.condition1": "Quando recebe um Esquema Vazio", - "block.create.schematic_table.tooltip.behaviour1": "Importa um Arquivo escolhido da sua Pasta de Esquemas", - - "item.create.goggles.tooltip": "UNLOCALIZED: GOGGLES", - "item.create.goggles.tooltip.summary": "UNLOCALIZED: A pair of glasses to augment your vision with useful _kinetic information_.", - "item.create.goggles.tooltip.condition1": "UNLOCALIZED: When worn", - "item.create.goggles.tooltip.behaviour1": "UNLOCALIZED: Shows _colored indicators_ corresponding to the _Speed Level_ of a placed kinetic component as well as _Stress Impact_ and _Capacity_ of individual components.", - "item.create.goggles.tooltip.condition2": "UNLOCALIZED: When looking at gauge", - "item.create.goggles.tooltip.behaviour2": "UNLOCALIZED: Shows detailed information about _Speed_ or _Stress_ of the network to which the gauge is connected.", - "item.create.goggles.tooltip.condition3": "UNLOCALIZED: When looking at fluid containers", - "item.create.goggles.tooltip.behaviour3": "UNLOCALIZED: Shows detailed information about the _Capacity_ of the block and any _Fluids_ stored within.", - - "item.create.wrench.tooltip": "UNLOCALIZED: WRENCH", - "item.create.wrench.tooltip.summary": "UNLOCALIZED: A useful tool for working on kinetic contraptions. Can be used to _Rotate_, _Dismantle_ and to _Configure_ components.", - "item.create.wrench.tooltip.control1": "UNLOCALIZED: Right-Click a kinetic block", - "item.create.wrench.tooltip.action1": "UNLOCALIZED: _Rotates components_ toward or away from the face with which you interacted.", - "item.create.wrench.tooltip.control2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.wrench.tooltip.action2": "UNLOCALIZED: _Disassembles Kinetic components_ and places them back in _your inventory_.", - - "block.create.nozzle.tooltip": "UNLOCALIZED: NOZZLE", - "block.create.nozzle.tooltip.summary": "UNLOCALIZED: Attach to the front of an _Encased Fan_ to distribute its effect on Entities in _all directions_.", - - "block.create.cuckoo_clock.tooltip": "UNLOCALIZED: CUCKOO CLOCK", - "block.create.cuckoo_clock.tooltip.summary": "UNLOCALIZED: Fine craftsmanship for _decorating_ a space and _keeping track of time_.", - "block.create.cuckoo_clock.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.cuckoo_clock.tooltip.behaviour1": "UNLOCALIZED: Shows the _current time_ and plays a tune twice a day. _Activates_ once at _noon_ and at dusk, as soon as _players can sleep_.", - - "block.create.turntable.tooltip": "MESA GIRATÓRIA", - "block.create.turntable.tooltip.summary": "Muda a _Força_ _Rotacional_ em uma forma refinada de Enjoo.", - - "block.create.toolbox.tooltip": "UNLOCALIZED: TOOLBOX", - "block.create.toolbox.tooltip.summary": "UNLOCALIZED: Every Inventors' dearest Companion. Conveniently _holds_ a large amount of _8 Different_ item types.", - "block.create.toolbox.tooltip.condition1": "UNLOCALIZED: When Picked Up", - "block.create.toolbox.tooltip.behaviour1": "UNLOCALIZED: _Retains_ Inventory _Contents_.", - "block.create.toolbox.tooltip.condition2": "UNLOCALIZED: When placed in Range", - "block.create.toolbox.tooltip.behaviour2": "UNLOCALIZED: _Nearby_ _Players_ can hold the _Toolbox_ _Keybind_ to access its contents _Remotely_.", - "block.create.toolbox.tooltip.condition3": "UNLOCALIZED: When R-Clicked", - "block.create.toolbox.tooltip.behaviour3": "UNLOCALIZED: Opens the _Container Interface_.", - - "block.create.stockpile_switch.tooltip": "DISJUNTOR DE ARMAZENAMENTO", - "block.create.stockpile_switch.tooltip.summary": "Alterna um sinal de Redstone com base no _Espaço_ de _Armazenamento_ do Reciente conectado.", - "block.create.stockpile_switch.tooltip.condition1": "Quando abaixo do Limite Mínimo", - "block.create.stockpile_switch.tooltip.behaviour1": "Para de enviar _Sinal_ de _Redstone_", - - "block.create.content_observer.tooltip": "UNLOCALIZED: CONTENT OBSERVER", - "block.create.content_observer.tooltip.summary": "UNLOCALIZED: _Detects Items_ or _Fluids_ inside _containers_, _pipes_ or _conveyors_ matching a configured _filter_.", - "block.create.content_observer.tooltip.condition1": "UNLOCALIZED: When observing a Container", - "block.create.content_observer.tooltip.behaviour1": "UNLOCALIZED: Emits a _Redstone Signal_ while the observed container has _matching_ _content_.", - "block.create.content_observer.tooltip.condition2": "UNLOCALIZED: When observing a Funnel", - "block.create.content_observer.tooltip.behaviour2": "UNLOCALIZED: Emits a _Redstone Pulse_ when a _matching_ Item is _transferred_.", - - "block.create.creative_crate.tooltip": "Caixa Criativa", - "block.create.creative_crate.tooltip.summary": "Provê um suprimento infinito de blocos para Canho~es de Esquema próximos", - "block.create.creative_crate.tooltip.condition1": "UNLOCALIZED: When Item in Filter Slot", - "block.create.creative_crate.tooltip.behaviour1": "UNLOCALIZED: Anything _extracting_ from this container will provide an _endless supply_ of the item specified. Items _inserted_ into this crate will be _voided._", - - "item.create.creative_blaze_cake.tooltip": "UNLOCALIZED: CREATIVE CAKE", - "item.create.creative_blaze_cake.tooltip.summary": "UNLOCALIZED: A very special treat for your _Blaze Burners_. After eating this cake, Blaze Burners will _never run out of fuel_.", - "item.create.creative_blaze_cake.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.creative_blaze_cake.tooltip.behaviour1": "UNLOCALIZED: _Cycles_ a Blaze Burner's heat level.", - - "block.create.controller_rail.tooltip": "UNLOCALIZED: CONTROLLER RAIL", - "block.create.controller_rail.tooltip.summary": "UNLOCALIZED: A _uni-directional powered rail_ capable of _fine control_ over a minecarts' _movement speed_.", - "block.create.controller_rail.tooltip.condition1": "UNLOCALIZED: When Powered by Redstone", - "block.create.controller_rail.tooltip.behaviour1": "UNLOCALIZED: _Accelerates_ or _Decelerates_ passing _minecarts_ corresponding to the _signal strength_. Propagates redstone power to adjacent controller rails. Powering two controller rails with different strengths will cause tracks between them to interpolate their signal.", - - "item.create.sand_paper.tooltip": "UNLOCALIZED: SAND PAPER", - "item.create.sand_paper.tooltip.summary": "UNLOCALIZED: A rough paper that can be used to _polish materials_. Can be automatically applied using the Deployer.", - "item.create.sand_paper.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.sand_paper.tooltip.behaviour1": "UNLOCALIZED: Applies polish to items held in the _offhand_ or lying on the _floor_ when _looking at them_", - - "item.create.builders_tea.tooltip": "UNLOCALIZED: BUILDERS TEA", - "item.create.builders_tea.tooltip.summary": "UNLOCALIZED: The perfect drink to get the day started- _Motivating_ and _Saturating._", - - "item.create.refined_radiance.tooltip": "UNLOCALIZED: REFINED RADIANCE", - "item.create.refined_radiance.tooltip.summary": "UNLOCALIZED: A Chromatic material forged from _absorbed light_.", - "item.create.refined_radiance.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.refined_radiance.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.shadow_steel.tooltip": "UNLOCALIZED: SHADOW STEEL", - "item.create.shadow_steel.tooltip.summary": "UNLOCALIZED: A Chromatic material forged _in the void_.", - "item.create.shadow_steel.tooltip.condition1": "UNLOCALIZED: Work In Progress", - "item.create.shadow_steel.tooltip.behaviour1": "UNLOCALIZED: Usages for this material will be available in a future release.", - - "item.create.linked_controller.tooltip": "UNLOCALIZED: LINKED CONTROLLER", - "item.create.linked_controller.tooltip.summary": "UNLOCALIZED: Grants _handheld_ _control_ over _Redstone Link_ frequencies assigned to its _six_ _buttons_.", - "item.create.linked_controller.tooltip.condition1": "UNLOCALIZED: R-Click", - "item.create.linked_controller.tooltip.behaviour1": "UNLOCALIZED: _Toggles_ the controller. _Movement_ _controls_ are taken over while its active.", - "item.create.linked_controller.tooltip.condition2": "UNLOCALIZED: R-Click while Sneaking", - "item.create.linked_controller.tooltip.behaviour2": "UNLOCALIZED: Opens the manual _Configuration Interface_.", - "item.create.linked_controller.tooltip.condition3": "UNLOCALIZED: R-Click on Redstone Link Receiver", - "item.create.linked_controller.tooltip.behaviour3": "UNLOCALIZED: Enables _Bind Mode_, press one of the _six controls_ to bind it to the _Links' Frequency_.", - "item.create.linked_controller.tooltip.condition4": "UNLOCALIZED: R-Click on Lectern", - "item.create.linked_controller.tooltip.behaviour4": "UNLOCALIZED: Places the Controller into the Lectern for easy activation. (R-Click while Sneaking to retrieve it)", - - "item.create.diving_helmet.tooltip": "UNLOCALIZED: DIVING HELMET", - "item.create.diving_helmet.tooltip.summary": "UNLOCALIZED: Together with a _Copper_ _Backtank_, allows the wielder to _breathe_ _underwater_ for an extended amount of time.", - "item.create.diving_helmet.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_helmet.tooltip.behaviour1": "UNLOCALIZED: Provides the _Water Breathing_ effect, slowly draining _Air Pressure_ from the Backtank.", - - "item.create.copper_backtank.tooltip": "UNLOCALIZED: COPPER BACKTANK", - "item.create.copper_backtank.tooltip.summary": "UNLOCALIZED: A _Wearable_ _Tank_ for carrying Pressurized Air.", - "item.create.copper_backtank.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.copper_backtank.tooltip.behaviour1": "UNLOCALIZED: Provides _Pressurized_ _Air_ to Equipment that requires it.", - "item.create.copper_backtank.tooltip.condition2": "UNLOCALIZED: When placed, Powered by Kinetics", - "item.create.copper_backtank.tooltip.behaviour2": "UNLOCALIZED: _Collects_ _Pressurized_ _Air_ at a rate depending on the Rotational Speed.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "UNLOCALIZED: DIVING BOOTS", - "item.create.diving_boots.tooltip.summary": "UNLOCALIZED: A pair of _heavy_ _boots_, allowing for better traversal of the Ocean floor.", - "item.create.diving_boots.tooltip.condition1": "UNLOCALIZED: When Worn", - "item.create.diving_boots.tooltip.behaviour1": "UNLOCALIZED: Wielder _sinks_ _faster_ and _cannot_ _swim_. Grants the ability to _walk_ and _jump_ underwater. Wielder also is no longer affected by _Mechanical_ _Belts_.", - - "item.create.crafting_blueprint.tooltip": "UNLOCALIZED: CRAFTING BLUEPRINT", - "item.create.crafting_blueprint.tooltip.summary": "UNLOCALIZED: _Placed_ on a wall, it can be used to _specify_ _ingredient_ _arrangements_ for easier manual crafting. Each slot represents a Recipe.", - "item.create.crafting_blueprint.condition1": "UNLOCALIZED: R-Click empty Slot", - "item.create.crafting_blueprint.behaviour1": "UNLOCALIZED: Opens a _Crafting_ _menu_ allowing you to _configure_ a _recipe_ and items to display.", - "item.create.crafting_blueprint.condition2": "UNLOCALIZED: R-Click configured Slot", - "item.create.crafting_blueprint.behaviour2": "UNLOCALIZED: _Applies_ the _configured_ _recipe_ with matching Ingredients found in your _Inventory_. _Sneak_ to craft up to a _Stack_ of items.", - - "item.create.minecart_coupling.tooltip": "UNLOCALIZED: MINECART COUPLING", - "item.create.minecart_coupling.tooltip.summary": "UNLOCALIZED: _Chains_ all your _Minecarts_ or _Carriage Contraptions_ together to form a majestic Train.", - "item.create.minecart_coupling.tooltip.condition1": "UNLOCALIZED: When Used on Minecart", - "item.create.minecart_coupling.tooltip.behaviour1": "UNLOCALIZED: _Couples_ two Minecarts together, attempting to keep them at a _constant distance_ while moving.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "UNLOCALIZED: PECULIAR BELL", - "block.create.peculiar_bell.tooltip.summary": "UNLOCALIZED: A decorative _Brass Bell_. Placing it right above open _Soul Fire_ may cause side-effects...", - - "block.create.haunted_bell.tooltip": "UNLOCALIZED: HAUNTED BELL", - "block.create.haunted_bell.tooltip.summary": "UNLOCALIZED: A _Cursed Bell_ haunted by lost souls of the Nether.", - "block.create.haunted_bell.tooltip.condition1": "UNLOCALIZED: When Held or Rang", - "block.create.haunted_bell.tooltip.behaviour1": "UNLOCALIZED: Highlights nearby _Lightless Spots_ on which _Hostile Mobs_ can spawn.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "UNLOCALIZED: 16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "UNLOCALIZED: This behaviour can be modified using a Wrench", - "create.ponder.shared.storage_on_contraption": "UNLOCALIZED: Inventories attached to the Contraption will pick up their drops automatically", - "create.ponder.shared.rpm8": "UNLOCALIZED: 8 RPM", - "create.ponder.shared.rpm32": "UNLOCALIZED: 32 RPM", - "create.ponder.shared.rpm16_source": "UNLOCALIZED: Source: 16 RPM", - "create.ponder.shared.movement_anchors": "UNLOCALIZED: With the help of Super Glue, larger structures can be moved.", - "create.ponder.tag.redstone": "UNLOCALIZED: Logic Components", - "create.ponder.tag.redstone.description": "UNLOCALIZED: Components which help with redstone engineering", - "create.ponder.tag.contraption_assembly": "UNLOCALIZED: Block Attachment Utility", - "create.ponder.tag.contraption_assembly.description": "UNLOCALIZED: Tools and Components used to assemble structures moved as an animated Contraption", - "create.ponder.tag.fluids": "UNLOCALIZED: Fluid Manipulators", - "create.ponder.tag.fluids.description": "UNLOCALIZED: Components which help relaying and making use of Fluids", - "create.ponder.tag.decoration": "UNLOCALIZED: Aesthetics", - "create.ponder.tag.decoration.description": "UNLOCALIZED: Components used mostly for decorative purposes", - "create.ponder.tag.windmill_sails": "UNLOCALIZED: Sails for Windmill Bearings", - "create.ponder.tag.windmill_sails.description": "UNLOCALIZED: Blocks that count towards the strength of a Windmill Contraption when assembled. Each of these have equal efficiency in doing so.", - "create.ponder.tag.arm_targets": "UNLOCALIZED: Targets for Mechanical Arms", - "create.ponder.tag.arm_targets.description": "UNLOCALIZED: Components which can be selected as inputs or outputs to the Mechanical Arm", - "create.ponder.tag.kinetic_appliances": "UNLOCALIZED: Kinetic Appliances", - "create.ponder.tag.kinetic_appliances.description": "UNLOCALIZED: Components which make use of Rotational Force", - "create.ponder.tag.kinetic_sources": "UNLOCALIZED: Kinetic Sources", - "create.ponder.tag.kinetic_sources.description": "UNLOCALIZED: Components which generate Rotational Force", - "create.ponder.tag.movement_anchor": "UNLOCALIZED: Movement Anchors", - "create.ponder.tag.movement_anchor.description": "UNLOCALIZED: Components which allow the creation of moving contraptions, animating an attached structure in a variety of ways", - "create.ponder.tag.kinetic_relays": "UNLOCALIZED: Kinetic Blocks", - "create.ponder.tag.kinetic_relays.description": "UNLOCALIZED: Components which help relaying Rotational Force elsewhere", - "create.ponder.tag.contraption_actor": "UNLOCALIZED: Contraption Actors", - "create.ponder.tag.contraption_actor.description": "UNLOCALIZED: Components which expose special behaviour when attached to a moving contraption", - "create.ponder.tag.creative": "UNLOCALIZED: Creative Mode", - "create.ponder.tag.creative.description": "UNLOCALIZED: Components not usually available for Survival Mode", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "UNLOCALIZED: Item Transportation", - "create.ponder.tag.logistics.description": "UNLOCALIZED: Components which help moving items around", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "UNLOCALIZED: Controlling signals using the Analog Lever", - "create.ponder.analog_lever.text_1": "UNLOCALIZED: Analog Levers make for a compact and precise source of redstone power", - "create.ponder.analog_lever.text_2": "UNLOCALIZED: Right-click to increase its analog power output", - "create.ponder.analog_lever.text_3": "UNLOCALIZED: Right-click while Sneaking to decrease the power output again", - - "create.ponder.andesite_tunnel.header": "UNLOCALIZED: Using Andesite Tunnels", - "create.ponder.andesite_tunnel.text_1": "UNLOCALIZED: Andesite Tunnels can be used to cover up your belts", - "create.ponder.andesite_tunnel.text_2": "UNLOCALIZED: Whenever an Andesite Tunnel has connections to the sides...", - "create.ponder.andesite_tunnel.text_3": "UNLOCALIZED: ...they will split exactly one item off of any passing stacks", - "create.ponder.andesite_tunnel.text_4": "UNLOCALIZED: The remainder will continue on its path", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "UNLOCALIZED: Processing Items in the Basin", - "create.ponder.basin.text_1": "UNLOCALIZED: A Basin can hold Items and Fluids for Processing", - "create.ponder.basin.text_2": "UNLOCALIZED: After a processing step, basins try to output below to the side of them", - "create.ponder.basin.text_3": "UNLOCALIZED: When a valid component is present, the Basin will show an output faucet", - "create.ponder.basin.text_4": "UNLOCALIZED: A number of options are applicable here", - "create.ponder.basin.text_5": "UNLOCALIZED: Outputs will be caught by the inventory below", - "create.ponder.basin.text_6": "UNLOCALIZED: Without output faucet, the Basin will retain items created in its processing", - "create.ponder.basin.text_7": "UNLOCALIZED: This can be useful if outputs should be re-used as ingredients", - "create.ponder.basin.text_8": "UNLOCALIZED: Desired outputs will then have to be extracted from the basin", - "create.ponder.basin.text_9": "UNLOCALIZED: A Filter might be necessary to avoid pulling out un-processed items", - - "create.ponder.bearing_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Bearing", - "create.ponder.bearing_modes.text_1": "UNLOCALIZED: When Stopped, the Bearing will place the structure at the nearest grid-aligned Angle", - "create.ponder.bearing_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only near the angle it started at", - - "create.ponder.belt_casing.header": "UNLOCALIZED: Encasing Belts", - "create.ponder.belt_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Mechanical Belts", - "create.ponder.belt_casing.text_2": "UNLOCALIZED: A wrench can be used to remove the casing", - - "create.ponder.belt_connector.header": "UNLOCALIZED: Using Mechanical Belts", - "create.ponder.belt_connector.text_1": "UNLOCALIZED: Right-Clicking two shafts with a belt item will connect them together", - "create.ponder.belt_connector.text_2": "UNLOCALIZED: Accidental selections can be canceled with Right-Click while Sneaking", - "create.ponder.belt_connector.text_3": "UNLOCALIZED: Additional Shafts can be added throughout the Belt", - "create.ponder.belt_connector.text_4": "UNLOCALIZED: Shafts connected via Belts will rotate with Identical Speed and Direction", - "create.ponder.belt_connector.text_5": "UNLOCALIZED: Added shafts can be removed using the wrench", - "create.ponder.belt_connector.text_6": "UNLOCALIZED: Mechanical Belts can be dyed for aesthetic purposes", - - "create.ponder.belt_directions.header": "UNLOCALIZED: Valid Orientations for Mechanical Belts", - "create.ponder.belt_directions.text_1": "UNLOCALIZED: Belts cannot connect in arbitrary directions", - "create.ponder.belt_directions.text_2": "UNLOCALIZED: 1. They can connect horizontally", - "create.ponder.belt_directions.text_3": "UNLOCALIZED: 2. They can connect diagonally", - "create.ponder.belt_directions.text_4": "UNLOCALIZED: 3. They can connect vertically", - "create.ponder.belt_directions.text_5": "UNLOCALIZED: 4. And they can connect vertical shafts horizontally", - "create.ponder.belt_directions.text_6": "UNLOCALIZED: These are all possible directions. Belts can span any Length between 2 and 20 blocks", - - "create.ponder.belt_transport.header": "UNLOCALIZED: Using Mechanical Belts for Logistics", - "create.ponder.belt_transport.text_1": "UNLOCALIZED: Moving belts will transport Items and other Entities", - "create.ponder.belt_transport.text_2": "UNLOCALIZED: Right-Click with an empty hand to take items off a belt", - - "create.ponder.blaze_burner.header": "UNLOCALIZED: Feeding Blaze Burners", - "create.ponder.blaze_burner.text_1": "UNLOCALIZED: Blaze Burners can provide Heat to Items processed in a Basin", - "create.ponder.blaze_burner.text_2": "UNLOCALIZED: For this, the Blaze has to be fed with flammable items", - "create.ponder.blaze_burner.text_3": "UNLOCALIZED: With a Blaze Cake, the Burner can reach an even stronger level of heat", - "create.ponder.blaze_burner.text_4": "UNLOCALIZED: The feeding process can be automated using Deployers or Mechanical Arms", - - "create.ponder.brass_funnel.header": "UNLOCALIZED: The Brass Funnel", - "create.ponder.brass_funnel.text_1": "UNLOCALIZED: Andesite Funnels can only ever extract single items.", - "create.ponder.brass_funnel.text_2": "UNLOCALIZED: Brass Funnels can extract up to a full stack.", - "create.ponder.brass_funnel.text_3": "UNLOCALIZED: Scrolling on the filter slot allows for precise control over the extracted stack size.", - "create.ponder.brass_funnel.text_4": "UNLOCALIZED: Using items on the filter slot will restrict the funnel to only transfer matching stacks.", - - "create.ponder.brass_tunnel.header": "UNLOCALIZED: Using Brass Tunnels", - "create.ponder.brass_tunnel.text_1": "UNLOCALIZED: Brass Tunnels can be used to cover up your belts", - "create.ponder.brass_tunnel.text_2": "UNLOCALIZED: Brass Tunnels have filter slots on each open side", - "create.ponder.brass_tunnel.text_3": "UNLOCALIZED: Filters on inbound connections simply block non-matching items", - "create.ponder.brass_tunnel.text_4": "UNLOCALIZED: Filters on outbound connections can be used to sort items by type", - "create.ponder.brass_tunnel.text_5": "UNLOCALIZED: Whenever a passing item has multiple valid exits, the distribution mode will decide how to handle it", - "create.ponder.brass_tunnel.text_6": "UNLOCALIZED: Brass Tunnels on parallel belts will form a group", - "create.ponder.brass_tunnel.text_7": "UNLOCALIZED: Incoming Items will now be distributed across all connected exits", - "create.ponder.brass_tunnel.text_8": "UNLOCALIZED: For this, items can also be inserted into the Tunnel block directly", - - "create.ponder.brass_tunnel_modes.header": "UNLOCALIZED: Distribution Modes of the Brass Tunnel", - "create.ponder.brass_tunnel_modes.text_1": "UNLOCALIZED: Using a Wrench, the distribution behaviour of Brass Tunnels can be configured", - "create.ponder.brass_tunnel_modes.text_10": "UNLOCALIZED: 'Synchronize Inputs' is a unique setting for Brass Tunnels", - "create.ponder.brass_tunnel_modes.text_11": "UNLOCALIZED: Items are only allowed past if every tunnel in the group has one waiting", - "create.ponder.brass_tunnel_modes.text_12": "UNLOCALIZED: This ensures that all affected belts supply items at the same rate", - "create.ponder.brass_tunnel_modes.text_2": "UNLOCALIZED: 'Split' will attempt to distribute the stack evenly between available outputs", - "create.ponder.brass_tunnel_modes.text_3": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_4": "UNLOCALIZED: 'Forced Split' will never skip outputs, and instead wait until they are free", - "create.ponder.brass_tunnel_modes.text_5": "UNLOCALIZED: 'Round Robin' keeps stacks whole, and cycles through outputs iteratively", - "create.ponder.brass_tunnel_modes.text_6": "UNLOCALIZED: Once Again, if an output is unable to take more items, it will be skipped", - "create.ponder.brass_tunnel_modes.text_7": "UNLOCALIZED: 'Forced Round Robin' never skips outputs", - "create.ponder.brass_tunnel_modes.text_8": "UNLOCALIZED: 'Prefer Nearest' prioritizes the outputs closest to the items' input location", - "create.ponder.brass_tunnel_modes.text_9": "UNLOCALIZED: 'Randomize' will distribute whole stacks to randomly picked outputs", - - "create.ponder.cart_assembler.header": "UNLOCALIZED: Moving Structures using Cart Assemblers", - "create.ponder.cart_assembler.text_1": "UNLOCALIZED: Powered Cart Assemblers mount attached structures to passing Minecarts", - "create.ponder.cart_assembler.text_2": "UNLOCALIZED: Without a redstone signal, it disassembles passing cart contraptions back into blocks", - "create.ponder.cart_assembler.text_3": "UNLOCALIZED: Using a Wrench on the Minecart will let you carry the Contraption elsewhere", - - "create.ponder.cart_assembler_dual.header": "UNLOCALIZED: Assembling Carriage Contraptions", - "create.ponder.cart_assembler_dual.text_1": "UNLOCALIZED: Whenever two Cart Assembers share an attached structure...", - "create.ponder.cart_assembler_dual.text_2": "UNLOCALIZED: Powering either of them will create a Carriage Contraption", - "create.ponder.cart_assembler_dual.text_3": "UNLOCALIZED: The carts will behave like those connected via Minecart Coupling", - - "create.ponder.cart_assembler_modes.header": "UNLOCALIZED: Orientation Settings for Minecart Contraptions", - "create.ponder.cart_assembler_modes.text_1": "UNLOCALIZED: Cart Contraptions will rotate to face towards their carts' motion", - "create.ponder.cart_assembler_modes.text_2": "UNLOCALIZED: This Arrow indicates which side of the Structure will be considered the front", - "create.ponder.cart_assembler_modes.text_3": "UNLOCALIZED: If the Assembler is set to Lock Rotation, the contraptions' orientation will never change", - - "create.ponder.cart_assembler_rails.header": "UNLOCALIZED: Other types of Minecarts and Rails", - "create.ponder.cart_assembler_rails.text_1": "UNLOCALIZED: Cart Assemblers on Regular Tracks will not affect the passing carts' motion", - "create.ponder.cart_assembler_rails.text_2": "UNLOCALIZED: When on Powered or Controller Rail, the carts will be held in place until it's Powered", - "create.ponder.cart_assembler_rails.text_3": "UNLOCALIZED: Other types of Minecarts can be used as the anchor", - "create.ponder.cart_assembler_rails.text_4": "UNLOCALIZED: Furnace Carts will keep themselves powered, pulling fuel from any attached inventories", - - "create.ponder.chain_drive.header": "UNLOCALIZED: Relaying rotational force with Chain Drives", - "create.ponder.chain_drive.text_1": "UNLOCALIZED: Chain Drives relay rotation to each other in a row", - "create.ponder.chain_drive.text_2": "UNLOCALIZED: All shafts connected like this will rotate in the same direction", - "create.ponder.chain_drive.text_3": "UNLOCALIZED: Any part of the row can be rotated by 90 degrees", - - "create.ponder.chain_gearshift.header": "UNLOCALIZED: Controlling rotational speed with Chain Gearshifts", - "create.ponder.chain_gearshift.text_1": "UNLOCALIZED: Unpowered Chain Gearshifts behave exactly like Chain Drives", - "create.ponder.chain_gearshift.text_2": "UNLOCALIZED: When Powered, the speed transmitted to other Chain Drives in the row is doubled", - "create.ponder.chain_gearshift.text_3": "UNLOCALIZED: Whenever the Powered Gearshift is not at the source, its speed will be halved instead", - "create.ponder.chain_gearshift.text_4": "UNLOCALIZED: In both cases, Chain Drives in the row always run at 2x the speed of the Powered Gearshift", - "create.ponder.chain_gearshift.text_5": "UNLOCALIZED: Using analog signals, the ratio can be adjusted more precisely between 1 and 2", - "create.ponder.chain_gearshift.text_6": "UNLOCALIZED: 12 RPM", - - "create.ponder.chute.header": "UNLOCALIZED: Transporting Items downward via Chutes", - "create.ponder.chute.text_1": "UNLOCALIZED: Chutes can transport items vertically from and to inventories", - "create.ponder.chute.text_2": "UNLOCALIZED: Using the Wrench, a window can be created", - "create.ponder.chute.text_3": "UNLOCALIZED: Placing chutes targeting the side faces of another will make it diagonal", - - "create.ponder.chute_upward.header": "UNLOCALIZED: Transporting Items upward via Chutes", - "create.ponder.chute_upward.text_1": "UNLOCALIZED: Using Encased Fans at the top or bottom, a Chute can move items upward", - "create.ponder.chute_upward.text_2": "UNLOCALIZED: Inspecting chutes with Engineers' Goggles reveals information about the movement direction", - "create.ponder.chute_upward.text_3": "UNLOCALIZED: On the 'blocked' end, items will have to be inserted/taken from the sides", - - "create.ponder.clockwork_bearing.header": "UNLOCALIZED: Animating Structures using Clockwork Bearings", - "create.ponder.clockwork_bearing.text_1": "UNLOCALIZED: Clockwork Bearings attach to blocks in front of them", - "create.ponder.clockwork_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, the structure will be rotated according to the hour of the day", - "create.ponder.clockwork_bearing.text_3": "UNLOCALIZED: 3:00", - "create.ponder.clockwork_bearing.text_4": "UNLOCALIZED: 4:00", - "create.ponder.clockwork_bearing.text_5": "UNLOCALIZED: Right-Click the bearing to start or stop animating the structure", - "create.ponder.clockwork_bearing.text_6": "UNLOCALIZED: In front of the Hour Hand, a second structure can be added", - "create.ponder.clockwork_bearing.text_7": "UNLOCALIZED: Ensure that the two Structures are not glued to each other", - "create.ponder.clockwork_bearing.text_8": "UNLOCALIZED: The Second Structure will now rotate as the Minute Hand", - - "create.ponder.clutch.header": "UNLOCALIZED: Controlling rotational force using a Clutch", - "create.ponder.clutch.text_1": "UNLOCALIZED: Clutches will relay rotation in a straight line", - "create.ponder.clutch.text_2": "UNLOCALIZED: When powered by Redstone, it breaks the connection", - - "create.ponder.cog_speedup.header": "UNLOCALIZED: Gearshifting with Cogs", - "create.ponder.cog_speedup.text_1": "UNLOCALIZED: Large and Small cogs can be connected diagonally", - "create.ponder.cog_speedup.text_2": "UNLOCALIZED: Shifting from large to small cogs, the conveyed speed will be doubled", - "create.ponder.cog_speedup.text_3": "UNLOCALIZED: Shifting the opposite way, the conveyed speed will be halved", - - "create.ponder.cogwheel.header": "UNLOCALIZED: Relaying rotational force using Cogwheels", - "create.ponder.cogwheel.text_1": "UNLOCALIZED: Cogwheels will relay rotation to other adjacent cogwheels", - "create.ponder.cogwheel.text_2": "UNLOCALIZED: Neighbouring shafts connected like this will rotate in opposite directions", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "UNLOCALIZED: Creative Fluid Tanks", - "create.ponder.creative_fluid_tank.text_1": "UNLOCALIZED: Creative Fluid Tanks can be used to provide a bottomless supply of fluid", - "create.ponder.creative_fluid_tank.text_2": "UNLOCALIZED: Right-Click with a fluid containing item to configure it", - "create.ponder.creative_fluid_tank.text_3": "UNLOCALIZED: Pipe Networks can now endlessly draw the assigned fluid from the tank", - "create.ponder.creative_fluid_tank.text_4": "UNLOCALIZED: Any Fluids pushed back into a Creative Fluid Tank will be voided", - - "create.ponder.creative_motor.header": "UNLOCALIZED: Generating Rotational Force using Creative Motors", - "create.ponder.creative_motor.text_1": "UNLOCALIZED: Creative motors are a compact and configurable source of Rotational Force", - "create.ponder.creative_motor.text_2": "UNLOCALIZED: Scrolling on the back panel changes the RPM of the motors' rotational output", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "UNLOCALIZED: Processing Items with Crushing Wheels", - "create.ponder.crushing_wheels.text_1": "UNLOCALIZED: A pair of Crushing Wheels can grind items very effectively", - "create.ponder.crushing_wheels.text_2": "UNLOCALIZED: Their Rotational Input has to make them spin into each other", - "create.ponder.crushing_wheels.text_3": "UNLOCALIZED: Items thrown or inserted into the top will get processed", - "create.ponder.crushing_wheels.text_4": "UNLOCALIZED: Items can be inserted and picked up through automated means as well", - - "create.ponder.deployer.header": "UNLOCALIZED: Using the Deployer", - "create.ponder.deployer.text_1": "UNLOCALIZED: Given Rotational Force, a Deployer can imitate player interactions", - "create.ponder.deployer.text_10": "UNLOCALIZED: Right-click the front to give it an Item to use", - "create.ponder.deployer.text_11": "UNLOCALIZED: Items can also be inserted automatically", - "create.ponder.deployer.text_12": "UNLOCALIZED: Deployers carry a filter slot", - "create.ponder.deployer.text_13": "UNLOCALIZED: When a filter is set, it activates only while holding a matching item", - "create.ponder.deployer.text_14": "UNLOCALIZED: Only items matching the filter can now be inserted...", - "create.ponder.deployer.text_15": "UNLOCALIZED: ...and only non-matching items will be extracted", - "create.ponder.deployer.text_2": "UNLOCALIZED: It will always interact with the position 2 blocks in front of itself", - "create.ponder.deployer.text_3": "UNLOCALIZED: Blocks directly in front will not obstruct it", - "create.ponder.deployer.text_4": "UNLOCALIZED: Deployers can:", - "create.ponder.deployer.text_5": "UNLOCALIZED: Place Blocks,", - "create.ponder.deployer.text_6": "UNLOCALIZED: Use Items,", - "create.ponder.deployer.text_7": "UNLOCALIZED: Activate Blocks,", - "create.ponder.deployer.text_8": "UNLOCALIZED: Harvest blocks", - "create.ponder.deployer.text_9": "UNLOCALIZED: and Attack Mobs", - - "create.ponder.deployer_contraption.header": "UNLOCALIZED: Using Deployers on Contraptions", - "create.ponder.deployer_contraption.text_1": "UNLOCALIZED: Whenever Deployers are moved as part of an animated Contraption...", - "create.ponder.deployer_contraption.text_2": "UNLOCALIZED: They activate at each visited location, using items from inventories anywhere on the contraption", - "create.ponder.deployer_contraption.text_3": "UNLOCALIZED: The Filter slot can be used to specify which items to pull", - - "create.ponder.deployer_modes.header": "UNLOCALIZED: Modes of the Deployer", - "create.ponder.deployer_modes.text_1": "UNLOCALIZED: By default, a Deployer imitates a Right-click interaction", - "create.ponder.deployer_modes.text_2": "UNLOCALIZED: Using a Wrench, it can be set to imitate a Left-click instead", - - "create.ponder.deployer_processing.header": "UNLOCALIZED: Processing Items using Deployers", - "create.ponder.deployer_processing.text_1": "UNLOCALIZED: With a fitting held item, Deployers can process items provided beneath them", - "create.ponder.deployer_processing.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Deployer", - "create.ponder.deployer_processing.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.deployer_processing.text_4": "UNLOCALIZED: The Deployer will hold and process them automatically", - - "create.ponder.deployer_redstone.header": "UNLOCALIZED: Controlling Deployers with Redstone", - "create.ponder.deployer_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Deployers will not activate", - "create.ponder.deployer_redstone.text_2": "UNLOCALIZED: Before stopping, the Deployer will finish any started cycles", - "create.ponder.deployer_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.depot.header": "UNLOCALIZED: Using Depots", - "create.ponder.depot.text_1": "UNLOCALIZED: Depots can serve as 'stationary' belt elements", - "create.ponder.depot.text_2": "UNLOCALIZED: Right-Click to manually place or remove Items from it", - "create.ponder.depot.text_3": "UNLOCALIZED: Just like Mechanical Belts, it can provide items to processing", - "create.ponder.depot.text_4": "UNLOCALIZED: ...as well as provide Items to Mechanical Arms", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "UNLOCALIZED: Using Empty Blaze Burners", - "create.ponder.empty_blaze_burner.text_1": "UNLOCALIZED: Right-click a Blaze with the empty burner to capture it", - "create.ponder.empty_blaze_burner.text_2": "UNLOCALIZED: Alternatively, Blazes can be collected from their Spawners directly", - "create.ponder.empty_blaze_burner.text_3": "UNLOCALIZED: You now have an ideal heat source for various machines", - "create.ponder.empty_blaze_burner.text_4": "UNLOCALIZED: For Aesthetic purposes, Empty Blaze Burners can also be lit using Flint and Steel", - "create.ponder.empty_blaze_burner.text_5": "UNLOCALIZED: The flame can be transformed using a soul-infused item", - "create.ponder.empty_blaze_burner.text_6": "UNLOCALIZED: However, without a blaze they are not suitable for industrial heating", - - "create.ponder.encased_fluid_pipe.header": "UNLOCALIZED: Encasing Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_1": "UNLOCALIZED: Copper Casing can be used to decorate Fluid Pipes", - "create.ponder.encased_fluid_pipe.text_2": "UNLOCALIZED: Aside from being conceiled, Encased Pipes are locked into their connectivity state", - "create.ponder.encased_fluid_pipe.text_3": "UNLOCALIZED: It will no longer react to any neighbouring blocks being added or removed", - - "create.ponder.fan_direction.header": "UNLOCALIZED: Air flow of Encased Fans", - "create.ponder.fan_direction.text_1": "UNLOCALIZED: Encased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "UNLOCALIZED: Strength and Direction of Flow depends on the Rotational Input", - - "create.ponder.fan_processing.header": "UNLOCALIZED: Processing Items using Encased Fans", - "create.ponder.fan_processing.text_1": "UNLOCALIZED: When passing through lava, the Air Flow becomes Heated", - "create.ponder.fan_processing.text_2": "UNLOCALIZED: Items caught in the area will be smelted", - "create.ponder.fan_processing.text_3": "UNLOCALIZED: Food items thrown here would be incinerated", - "create.ponder.fan_processing.text_4": "UNLOCALIZED: Instead, a setup for Smoking using Fire should be used for them", - "create.ponder.fan_processing.text_5": "UNLOCALIZED: Air Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "UNLOCALIZED: Some interesting new processing can be done with it", - "create.ponder.fan_processing.text_7": "UNLOCALIZED: The Speed of the Fan does NOT affect the processing speed, only its range", - "create.ponder.fan_processing.text_8": "UNLOCALIZED: Fan Processing can also be applied to Items on Depots and Belts", - - "create.ponder.fluid_pipe_flow.header": "UNLOCALIZED: Moving Fluids using Copper Pipes", - "create.ponder.fluid_pipe_flow.text_1": "UNLOCALIZED: Fluid Pipes can connect two or more fluid sources and targets", - "create.ponder.fluid_pipe_flow.text_2": "UNLOCALIZED: Using a wrench, a straight pipe segment can be given a window", - "create.ponder.fluid_pipe_flow.text_3": "UNLOCALIZED: Windowed pipes will not connect to any other adjacent pipe segments", - "create.ponder.fluid_pipe_flow.text_4": "UNLOCALIZED: Powered by Mechanical Pumps, the Pipes can transport Fluids", - "create.ponder.fluid_pipe_flow.text_5": "UNLOCALIZED: No fluid is being extracted at first", - "create.ponder.fluid_pipe_flow.text_6": "UNLOCALIZED: Once the flow connects them, the endpoints gradually transfer their contents", - "create.ponder.fluid_pipe_flow.text_7": "UNLOCALIZED: Thus, the Pipe blocks themselves never 'physically' contain any fluid", - - "create.ponder.fluid_pipe_interaction.header": "UNLOCALIZED: Draining and Filling fluid containers", - "create.ponder.fluid_pipe_interaction.text_1": "UNLOCALIZED: Endpoints of a pipe network can interact with a variety of blocks", - "create.ponder.fluid_pipe_interaction.text_2": "UNLOCALIZED: Any block with fluid storage capabilities can be filled or drained", - "create.ponder.fluid_pipe_interaction.text_3": "UNLOCALIZED: Source blocks right in front of an open end can be picked up...", - "create.ponder.fluid_pipe_interaction.text_4": "UNLOCALIZED: ...while spilling into empty spaces can create fluid sources", - "create.ponder.fluid_pipe_interaction.text_5": "UNLOCALIZED: Pipes can also extract fluids from a handful of other blocks directly", - - "create.ponder.fluid_tank_sizes.header": "UNLOCALIZED: Dimensions of a Fluid tank", - "create.ponder.fluid_tank_sizes.text_1": "UNLOCALIZED: Fluid Tanks can be combined to increase the total capacity", - "create.ponder.fluid_tank_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.fluid_tank_sizes.text_3": "UNLOCALIZED: ...and grow in height by more than 30 additional layers", - "create.ponder.fluid_tank_sizes.text_4": "UNLOCALIZED: Using a Wrench, a tanks' window can be toggled", - - "create.ponder.fluid_tank_storage.header": "UNLOCALIZED: Storing Fluids in Fluid Tanks", - "create.ponder.fluid_tank_storage.text_1": "UNLOCALIZED: Fluid Tanks can be used to store large amounts of fluid", - "create.ponder.fluid_tank_storage.text_2": "UNLOCALIZED: Pipe networks can push and pull fluids from any side", - "create.ponder.fluid_tank_storage.text_3": "UNLOCALIZED: The contained fluid can be measured by a Comparator", - "create.ponder.fluid_tank_storage.text_4": "UNLOCALIZED: However, in Survival Mode Fluids cannot be added or taken manually", - "create.ponder.fluid_tank_storage.text_5": "UNLOCALIZED: You can use Basins, Item Drains and Spouts to drain or fill fluid containing items", - - "create.ponder.funnel_compat.header": "UNLOCALIZED: Funnel compatibility", - "create.ponder.funnel_compat.text_1": "UNLOCALIZED: Funnels should also interact nicely with a handful of other components.", - "create.ponder.funnel_compat.text_2": "UNLOCALIZED: Vertical Saws", - "create.ponder.funnel_compat.text_3": "UNLOCALIZED: Depots", - "create.ponder.funnel_compat.text_4": "UNLOCALIZED: Item Drains", - - "create.ponder.funnel_direction.header": "UNLOCALIZED: Direction of Transfer", - "create.ponder.funnel_direction.text_1": "UNLOCALIZED: Placed normally, it pulls items from the inventory.", - "create.ponder.funnel_direction.text_2": "UNLOCALIZED: Placed while sneaking, it puts items into the inventory.", - "create.ponder.funnel_direction.text_3": "UNLOCALIZED: Using a wrench, the funnel can be flipped after placement.", - "create.ponder.funnel_direction.text_4": "UNLOCALIZED: Same rules will apply for most orientations.", - "create.ponder.funnel_direction.text_5": "UNLOCALIZED: Funnels on belts will extract/insert depending on its movement direction.", - - "create.ponder.funnel_intro.header": "UNLOCALIZED: Using funnels", - "create.ponder.funnel_intro.text_1": "UNLOCALIZED: Funnels are ideal for transferring items from and to inventories.", - - "create.ponder.funnel_redstone.header": "UNLOCALIZED: Redstone control", - "create.ponder.funnel_redstone.text_1": "UNLOCALIZED: Redstone power will prevent any funnel from acting", - - "create.ponder.funnel_transfer.header": "UNLOCALIZED: Direct transfer", - "create.ponder.funnel_transfer.text_1": "UNLOCALIZED: Funnels cannot ever transfer between closed inventories directly.", - "create.ponder.funnel_transfer.text_2": "UNLOCALIZED: Chutes or Smart chutes might be more suitable for such purposes.", - "create.ponder.funnel_transfer.text_3": "UNLOCALIZED: Same applies for horizontal movement. A mechanical belt should help here.", - - "create.ponder.gantry_carriage.header": "UNLOCALIZED: Using Gantry Carriages", - "create.ponder.gantry_carriage.text_1": "UNLOCALIZED: Gantry Carriages can mount to and slide along a Gantry Shaft.", - "create.ponder.gantry_carriage.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gantry_cascaded.header": "UNLOCALIZED: Cascaded Gantries", - "create.ponder.gantry_cascaded.text_1": "UNLOCALIZED: Gantry shafts attach to a carriage without the need of super glue", - "create.ponder.gantry_cascaded.text_2": "UNLOCALIZED: Same applies for carriages on moved Gantry Shafts", - "create.ponder.gantry_cascaded.text_3": "UNLOCALIZED: Thus, a gantry system can be cascaded to cover multiple axes of movement", - - "create.ponder.gantry_direction.header": "UNLOCALIZED: Gantry Movement Direction", - "create.ponder.gantry_direction.text_1": "UNLOCALIZED: Gantry Shafts can have opposite orientations", - "create.ponder.gantry_direction.text_2": "UNLOCALIZED: The movement direction of carriages depend on their shafts' orientation", - "create.ponder.gantry_direction.text_3": "UNLOCALIZED: ...as well as the rotation direction of the shaft", - "create.ponder.gantry_direction.text_4": "UNLOCALIZED: Same rules apply for the propagated rotation", - - "create.ponder.gantry_redstone.header": "UNLOCALIZED: Gantry Power Propagation", - "create.ponder.gantry_redstone.text_1": "UNLOCALIZED: Redstone-powered gantry shafts stop moving their carriages", - "create.ponder.gantry_redstone.text_2": "UNLOCALIZED: Instead, its rotational force is relayed to the carriages' output shaft", - - "create.ponder.gantry_shaft.header": "UNLOCALIZED: Using Gantry Shafts", - "create.ponder.gantry_shaft.text_1": "UNLOCALIZED: Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.", - "create.ponder.gantry_shaft.text_2": "UNLOCALIZED: Gantry setups can move attached Blocks.", - - "create.ponder.gearbox.header": "UNLOCALIZED: Relaying rotational force using Gearboxes", - "create.ponder.gearbox.text_1": "UNLOCALIZED: Jumping between axes of rotation can get bulky quickly", - "create.ponder.gearbox.text_2": "UNLOCALIZED: A gearbox is the more compact equivalent of this setup", - "create.ponder.gearbox.text_3": "UNLOCALIZED: Shafts around corners rotate in mirrored directions", - "create.ponder.gearbox.text_4": "UNLOCALIZED: Straight connections will be reversed", - - "create.ponder.gearshift.header": "UNLOCALIZED: Controlling rotational force using a Gearshift", - "create.ponder.gearshift.text_1": "UNLOCALIZED: Gearshifts will relay rotation in a straight line", - "create.ponder.gearshift.text_2": "UNLOCALIZED: When powered by Redstone, it reverses the transmission", - - "create.ponder.hand_crank.header": "UNLOCALIZED: Generating Rotational Force using Hand Cranks", - "create.ponder.hand_crank.text_1": "UNLOCALIZED: Hand Cranks can be used by players to apply rotational force manually", - "create.ponder.hand_crank.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.hand_crank.text_3": "UNLOCALIZED: Its conveyed speed is relatively high", - "create.ponder.hand_crank.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - - "create.ponder.hose_pulley.header": "UNLOCALIZED: Source Filling and Draining using Hose Pulleys", - "create.ponder.hose_pulley.text_1": "UNLOCALIZED: Hose Pulleys can be used to fill or drain large bodies of Fluid", - "create.ponder.hose_pulley.text_2": "UNLOCALIZED: With the Kinetic Input, the height of the pulleys' hose can be controlled", - "create.ponder.hose_pulley.text_3": "UNLOCALIZED: The Pulley retracts while the input rotation is inverted", - "create.ponder.hose_pulley.text_4": "UNLOCALIZED: On the opposite side, pipes can be connected", - "create.ponder.hose_pulley.text_5": "UNLOCALIZED: Attached pipe networks can either provide fluid to the hose...", - "create.ponder.hose_pulley.text_6": "UNLOCALIZED: ...or pull from it, draining the pool instead", - "create.ponder.hose_pulley.text_7": "UNLOCALIZED: Fill and Drain speed of the pulley depends entirely on the fluid networks' throughput", - - "create.ponder.hose_pulley_infinite.header": "UNLOCALIZED: Passively Filling and Draining large bodies of Fluid", - "create.ponder.hose_pulley_infinite.text_1": "UNLOCALIZED: When deploying the Hose Pulley into a large enough ocean...", - "create.ponder.hose_pulley_infinite.text_2": "UNLOCALIZED: It will provide/dispose fluids without affecting the source", - "create.ponder.hose_pulley_infinite.text_3": "UNLOCALIZED: Pipe networks can limitlessly take fluids from/to such pulleys", - - "create.ponder.hose_pulley_level.header": "UNLOCALIZED: Fill and Drain level of Hose Pulleys", - "create.ponder.hose_pulley_level.text_1": "UNLOCALIZED: While fully retracted, the Hose Pulley cannot operate", - "create.ponder.hose_pulley_level.text_2": "UNLOCALIZED: Draining runs from top to bottom", - "create.ponder.hose_pulley_level.text_3": "UNLOCALIZED: The surface level will end up just below where the hose ends", - "create.ponder.hose_pulley_level.text_4": "UNLOCALIZED: Filling runs from bottom to top", - "create.ponder.hose_pulley_level.text_5": "UNLOCALIZED: The filled pool will not grow beyond the layer above the hose end", - - "create.ponder.item_drain.header": "UNLOCALIZED: Emptying Fluid Containers using Item Drains", - "create.ponder.item_drain.text_1": "UNLOCALIZED: Item Drains can extract fluids from items", - "create.ponder.item_drain.text_2": "UNLOCALIZED: Right-click it to pour fluids from your held item into it", - "create.ponder.item_drain.text_3": "UNLOCALIZED: When items are inserted from the side...", - "create.ponder.item_drain.text_4": "UNLOCALIZED: ...they roll across, emptying out their contained fluid", - "create.ponder.item_drain.text_5": "UNLOCALIZED: Pipe Networks can now pull the fluid from the drains' internal buffer", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "UNLOCALIZED: Relaying rotational force using Large Cogwheels", - "create.ponder.large_cogwheel.text_1": "UNLOCALIZED: Large cogwheels can connect to each other at right angles", - "create.ponder.large_cogwheel.text_2": "UNLOCALIZED: It will help relaying conveyed speed to other axes of rotation", - - "create.ponder.linear_chassis_attachment.header": "UNLOCALIZED: Attaching blocks using Linear Chassis", - "create.ponder.linear_chassis_attachment.text_1": "UNLOCALIZED: The open faces of a Linear Chassis can be made Sticky", - "create.ponder.linear_chassis_attachment.text_2": "UNLOCALIZED: Click again to make the opposite side sticky", - "create.ponder.linear_chassis_attachment.text_3": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.linear_chassis_attachment.text_4": "UNLOCALIZED: Stickied faces of the Linear Chassis will attach a line of blocks in front of it", - "create.ponder.linear_chassis_attachment.text_5": "UNLOCALIZED: Using a Wrench, a precise Range can be specified for this chassis", - "create.ponder.linear_chassis_attachment.text_6": "UNLOCALIZED: Holding CTRL and scrolling adjusts the range of all attached Chassis Blocks", - "create.ponder.linear_chassis_attachment.text_7": "UNLOCALIZED: Attaching blocks to any other side requires the use of Super Glue", - "create.ponder.linear_chassis_attachment.text_8": "UNLOCALIZED: Using these mechanics, structures of any shape can move as a Contraption", - - "create.ponder.linear_chassis_group.header": "UNLOCALIZED: Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "UNLOCALIZED: Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "UNLOCALIZED: Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "UNLOCALIZED: Setting up Mechanical Arms", - "create.ponder.mechanical_arm.text_1": "UNLOCALIZED: Mechanical Arms have to be assigned their in- and outputs before they are placed", - "create.ponder.mechanical_arm.text_2": "UNLOCALIZED: Right-Click inventories while holding the Arm to assign them as Targets", - "create.ponder.mechanical_arm.text_3": "UNLOCALIZED: Right-Click again to toggle between Input (Blue) and Output (Orange)", - "create.ponder.mechanical_arm.text_4": "UNLOCALIZED: Left-Click components to remove their Selection", - "create.ponder.mechanical_arm.text_5": "UNLOCALIZED: Once placed, the Mechanical Arm will target the blocks selected previously", - "create.ponder.mechanical_arm.text_6": "UNLOCALIZED: They can have any amount of in- and outputs within their range", - "create.ponder.mechanical_arm.text_7": "UNLOCALIZED: However, not every type of Inventory can be interacted with directly", - "create.ponder.mechanical_arm.text_8": "UNLOCALIZED: Funnels and Depots can help to Bridge that gap", - - "create.ponder.mechanical_arm_filtering.header": "UNLOCALIZED: Filtering Outputs of the Mechanical Arm", - "create.ponder.mechanical_arm_filtering.text_1": "UNLOCALIZED: Inputs", - "create.ponder.mechanical_arm_filtering.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_filtering.text_3": "UNLOCALIZED: Sometimes it is desirable to restrict targets of the Arm by matching a filter", - "create.ponder.mechanical_arm_filtering.text_4": "UNLOCALIZED: Mechanical Arms by themselves do not provide any options for filtering", - "create.ponder.mechanical_arm_filtering.text_5": "UNLOCALIZED: Brass Funnels as Targets do however communicate their own filter to the Arm", - "create.ponder.mechanical_arm_filtering.text_6": "UNLOCALIZED: The Arm is smart enough not to pick up items it couldn't distribute", - - "create.ponder.mechanical_arm_modes.header": "UNLOCALIZED: Distribution modes of the Mechanical Arm", - "create.ponder.mechanical_arm_modes.text_1": "UNLOCALIZED: Input", - "create.ponder.mechanical_arm_modes.text_2": "UNLOCALIZED: Outputs", - "create.ponder.mechanical_arm_modes.text_3": "UNLOCALIZED: Whenever an Arm has to choose between multiple valid outputs...", - "create.ponder.mechanical_arm_modes.text_4": "UNLOCALIZED: ...it will act according to its setting", - "create.ponder.mechanical_arm_modes.text_5": "UNLOCALIZED: Scrolling with a Wrench will allow you to configure it", - "create.ponder.mechanical_arm_modes.text_6": "UNLOCALIZED: Round Robin mode simply cycles through all outputs that are available", - "create.ponder.mechanical_arm_modes.text_7": "UNLOCALIZED: If an output is unable to take more items, it will be skipped", - "create.ponder.mechanical_arm_modes.text_8": "UNLOCALIZED: Forced Round Robin mode will never skip outputs, and instead wait until they are free", - "create.ponder.mechanical_arm_modes.text_9": "UNLOCALIZED: Prefer First prioritizes the outputs selected earliest when configuring this Arm", - - "create.ponder.mechanical_arm_redstone.header": "UNLOCALIZED: Controlling Mechanical Arms with Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Mechanical Arms will not activate", - "create.ponder.mechanical_arm_redstone.text_2": "UNLOCALIZED: Before stopping, it will finish any started cycles", - "create.ponder.mechanical_arm_redstone.text_3": "UNLOCALIZED: Thus, a negative pulse can be used to trigger exactly one activation cycle", - - "create.ponder.mechanical_bearing.header": "UNLOCALIZED: Movings Structures using the Mechanical Bearing", - "create.ponder.mechanical_bearing.text_1": "UNLOCALIZED: Mechanical Bearings attach to the block in front of them", - "create.ponder.mechanical_bearing.text_2": "UNLOCALIZED: Upon receiving Rotational Force, it will assemble it into a Rotating Contraption", - - "create.ponder.mechanical_crafter.header": "UNLOCALIZED: Setting up Mechanical Crafters", - "create.ponder.mechanical_crafter.text_1": "UNLOCALIZED: An array of Mechanical Crafters can be used to automate any Crafting Recipe", - "create.ponder.mechanical_crafter.text_2": "UNLOCALIZED: Using a Wrench, the Crafters' paths can be arranged", - "create.ponder.mechanical_crafter.text_3": "UNLOCALIZED: For a valid setup, all paths have to converge into one exit at any side", - "create.ponder.mechanical_crafter.text_4": "UNLOCALIZED: The outputs will be placed into the inventory at the exit", - "create.ponder.mechanical_crafter.text_5": "UNLOCALIZED: Mechanical Crafters require Rotational Force to operate", - "create.ponder.mechanical_crafter.text_6": "UNLOCALIZED: Right-Click the front to insert Items manually", - "create.ponder.mechanical_crafter.text_7": "UNLOCALIZED: Once every slot of a path contains an Item, the crafting process will begin", - "create.ponder.mechanical_crafter.text_8": "UNLOCALIZED: For recipes not fully occupying the crafter setup, the start can be forced using a Redstone Pulse", - - "create.ponder.mechanical_crafter_connect.header": "UNLOCALIZED: Connecting Inventories of Crafters", - "create.ponder.mechanical_crafter_connect.text_1": "UNLOCALIZED: Items can be inserted to Crafters automatically", - "create.ponder.mechanical_crafter_connect.text_2": "UNLOCALIZED: Using the Wrench at their backs, Mechanical Crafter inputs can be combined", - "create.ponder.mechanical_crafter_connect.text_3": "UNLOCALIZED: All connected Crafters can now be accessed by the same input location", - - "create.ponder.mechanical_crafter_covers.header": "UNLOCALIZED: Covering slots of Mechanical Crafters", - "create.ponder.mechanical_crafter_covers.text_1": "UNLOCALIZED: Some recipes will require additional Crafters to bridge gaps in the path", - "create.ponder.mechanical_crafter_covers.text_2": "UNLOCALIZED: Using Slot Covers, Crafters can be set to act as an Empty Slot in the arrangement", - "create.ponder.mechanical_crafter_covers.text_3": "UNLOCALIZED: Shared Inputs created with the Wrench at the back can also reach across covered Crafters", - - "create.ponder.mechanical_drill.header": "UNLOCALIZED: Breaking Blocks with the Mechanical Drill", - "create.ponder.mechanical_drill.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Drill will break blocks directly in front of it", - "create.ponder.mechanical_drill.text_2": "UNLOCALIZED: Its mining speed depends on the Rotational Input", - - "create.ponder.mechanical_drill_contraption.header": "UNLOCALIZED: Using Mechanical Drills on Contraptions", - "create.ponder.mechanical_drill_contraption.text_1": "UNLOCALIZED: Whenever Drills are moved as part of an animated Contraption...", - "create.ponder.mechanical_drill_contraption.text_2": "UNLOCALIZED: ...they will break blocks the contraption runs them into", - - "create.ponder.mechanical_harvester.header": "UNLOCALIZED: Using Mechanical Harvesters on Contraptions", - "create.ponder.mechanical_harvester.text_1": "UNLOCALIZED: Whenever Harvesters are moved as part of an animated Contraption...", - "create.ponder.mechanical_harvester.text_2": "UNLOCALIZED: They will harvest and reset any mature crops on their way", - - "create.ponder.mechanical_mixer.header": "UNLOCALIZED: Processing Items with the Mechanical Mixer", - "create.ponder.mechanical_mixer.text_1": "UNLOCALIZED: With a Mixer and Basin, some Crafting Recipes can be automated", - "create.ponder.mechanical_mixer.text_2": "UNLOCALIZED: Available recipes include any Shapeless Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_mixer.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_mixer.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_piston.header": "UNLOCALIZED: Moving Structures using Mechanical Pistons", - "create.ponder.mechanical_piston.text_1": "UNLOCALIZED: Mechanical Pistons can move blocks in front of them", - "create.ponder.mechanical_piston.text_2": "UNLOCALIZED: Speed and direction of movement depend on the Rotational Input", - "create.ponder.mechanical_piston.text_3": "UNLOCALIZED: Sticky Mechanical Pistons can pull the attached blocks back", - - "create.ponder.mechanical_piston_modes.header": "UNLOCALIZED: Movement Modes of the Mechanical Piston", - "create.ponder.mechanical_piston_modes.text_1": "UNLOCALIZED: Whenever Pistons stop moving, the moved structure reverts to blocks", - "create.ponder.mechanical_piston_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.mechanical_plough.header": "UNLOCALIZED: Using Mechanical Ploughs on Contraptions", - "create.ponder.mechanical_plough.text_1": "UNLOCALIZED: Whenever Ploughs are moved as part of an animated Contraption...", - "create.ponder.mechanical_plough.text_2": "UNLOCALIZED: ...they will break blocks without a solid collision hitbox", - "create.ponder.mechanical_plough.text_3": "UNLOCALIZED: Additionally, ploughs can create farmland", - "create.ponder.mechanical_plough.text_4": "UNLOCALIZED: ...they can also launch entities without hurting them", - - "create.ponder.mechanical_press.header": "UNLOCALIZED: Processing Items with the Mechanical Press", - "create.ponder.mechanical_press.text_1": "UNLOCALIZED: The Mechanical Press can process items provided beneath it", - "create.ponder.mechanical_press.text_2": "UNLOCALIZED: The Input items can be dropped or placed on a Depot under the Press", - "create.ponder.mechanical_press.text_3": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.mechanical_press.text_4": "UNLOCALIZED: The Press will hold and process them automatically", - - "create.ponder.mechanical_press_compacting.header": "UNLOCALIZED: Compacting items with the Mechanical Press", - "create.ponder.mechanical_press_compacting.text_1": "UNLOCALIZED: Pressing items held in a Basin will cause them to be Compacted", - "create.ponder.mechanical_press_compacting.text_2": "UNLOCALIZED: Compacting includes any filled 2x2 or 3x3 Crafting Recipe, plus a couple extra ones", - "create.ponder.mechanical_press_compacting.text_3": "UNLOCALIZED: Some of those recipes may require the heat of a Blaze Burner", - "create.ponder.mechanical_press_compacting.text_4": "UNLOCALIZED: The filter slot can be used in case two recipes are conflicting.", - - "create.ponder.mechanical_pump_flow.header": "UNLOCALIZED: Fluid Transportation using Mechanical Pumps", - "create.ponder.mechanical_pump_flow.text_1": "UNLOCALIZED: Mechanical Pumps govern the flow of their attached pipe networks", - "create.ponder.mechanical_pump_flow.text_2": "UNLOCALIZED: When powered, their arrow indicates the direction of flow", - "create.ponder.mechanical_pump_flow.text_3": "UNLOCALIZED: The network behind is now pulling fluids...", - "create.ponder.mechanical_pump_flow.text_4": "UNLOCALIZED: ...while the network in front is transferring it outward", - "create.ponder.mechanical_pump_flow.text_5": "UNLOCALIZED: Reversing the input rotation reverses the direction of flow", - "create.ponder.mechanical_pump_flow.text_6": "UNLOCALIZED: Use a Wrench to reverse the orientation of pumps manually", - - "create.ponder.mechanical_pump_speed.header": "UNLOCALIZED: Throughput of Mechanical Pumps", - "create.ponder.mechanical_pump_speed.text_1": "UNLOCALIZED: Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away", - "create.ponder.mechanical_pump_speed.text_2": "UNLOCALIZED: Speeding up the input rotation changes the speed of flow propagation...", - "create.ponder.mechanical_pump_speed.text_3": "UNLOCALIZED: ...aswell as how quickly fluids are transferred", - "create.ponder.mechanical_pump_speed.text_4": "UNLOCALIZED: Pumps can combine their throughputs within shared pipe networks", - "create.ponder.mechanical_pump_speed.text_5": "UNLOCALIZED: Alternating their orientation can help align their flow directions", - - "create.ponder.mechanical_saw_breaker.header": "UNLOCALIZED: Cutting Trees with the Mechanical Saw", - "create.ponder.mechanical_saw_breaker.text_1": "UNLOCALIZED: When given Rotational Force, a Mechanical Saw will cut trees directly in front of it", - "create.ponder.mechanical_saw_breaker.text_2": "UNLOCALIZED: In order to cut the tree fully, the Saw has to break the last block connecting it to the ground", - - "create.ponder.mechanical_saw_contraption.header": "UNLOCALIZED: Using Mechanical Saws on Contraptions", - "create.ponder.mechanical_saw_contraption.text_1": "UNLOCALIZED: Whenever Saws are moved as part of an animated Contraption...", - "create.ponder.mechanical_saw_contraption.text_2": "UNLOCALIZED: ...they will cut any trees the contraption runs them into", - - "create.ponder.mechanical_saw_processing.header": "UNLOCALIZED: Processing Items on the Mechanical Saw", - "create.ponder.mechanical_saw_processing.text_1": "UNLOCALIZED: Upward facing Mechanical Saws can process a variety of items", - "create.ponder.mechanical_saw_processing.text_2": "UNLOCALIZED: The processed item always moves against the rotational input to the saw", - "create.ponder.mechanical_saw_processing.text_3": "UNLOCALIZED: Saws can work in-line with Mechanical Belts", - "create.ponder.mechanical_saw_processing.text_4": "UNLOCALIZED: When an ingredient has multiple possible outcomes, the filter slot can specify it", - "create.ponder.mechanical_saw_processing.text_5": "UNLOCALIZED: Without filter, the Saw would cycle through all outcomes instead", - - "create.ponder.millstone.header": "UNLOCALIZED: Processing Items in the Millstone", - "create.ponder.millstone.text_1": "UNLOCALIZED: Millstones process items by grinding them", - "create.ponder.millstone.text_2": "UNLOCALIZED: They can be powered from the side using cogwheels", - "create.ponder.millstone.text_3": "UNLOCALIZED: Throw or Insert items at the top", - "create.ponder.millstone.text_4": "UNLOCALIZED: After some time, the result can be obtained via Right-click", - "create.ponder.millstone.text_5": "UNLOCALIZED: The outputs can also be extracted by automation", - - "create.ponder.nixie_tube.header": "UNLOCALIZED: Using Nixie Tubes", - "create.ponder.nixie_tube.text_1": "UNLOCALIZED: When powered by Redstone, Nixie Tubes will display the redstone signals' strength", - "create.ponder.nixie_tube.text_2": "UNLOCALIZED: Using name tags edited with an anvil, custom text can be displayed", - "create.ponder.nixie_tube.text_3": "UNLOCALIZED: Right-Click with Dye to change their display colour", - - "create.ponder.piston_pole.header": "UNLOCALIZED: Piston Extension Poles", - "create.ponder.piston_pole.text_1": "UNLOCALIZED: Without attached Poles, a Mechanical Piston cannot move", - "create.ponder.piston_pole.text_2": "UNLOCALIZED: The Length of pole added at its back determines the Extension Range", - - "create.ponder.portable_fluid_interface.header": "UNLOCALIZED: Contraption Fluid Exchange", - "create.ponder.portable_fluid_interface.text_1": "UNLOCALIZED: Fluid Tanks on moving contraptions cannot be accessed by any pipes", - "create.ponder.portable_fluid_interface.text_2": "UNLOCALIZED: This component can interact with fluid tanks without the need to stop the contraption", - "create.ponder.portable_fluid_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_fluid_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_fluid_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL Tanks on the contraption", - "create.ponder.portable_fluid_interface.text_6": "UNLOCALIZED: Fluid can now be inserted...", - "create.ponder.portable_fluid_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_fluid_interface.text_8": "UNLOCALIZED: After no contents have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface.header": "UNLOCALIZED: Contraption Storage Exchange", - "create.ponder.portable_storage_interface.text_1": "UNLOCALIZED: Inventories on moving contraptions cannot be accessed by players.", - "create.ponder.portable_storage_interface.text_2": "UNLOCALIZED: This component can interact with storage without the need to stop the contraption.", - "create.ponder.portable_storage_interface.text_3": "UNLOCALIZED: Place a second one with a gap of 1 or 2 blocks inbetween", - "create.ponder.portable_storage_interface.text_4": "UNLOCALIZED: Whenever they pass by each other, they will engage in a connection", - "create.ponder.portable_storage_interface.text_5": "UNLOCALIZED: While engaged, the stationary interface will represent ALL inventories on the contraption", - "create.ponder.portable_storage_interface.text_6": "UNLOCALIZED: Items can now be inserted...", - "create.ponder.portable_storage_interface.text_7": "UNLOCALIZED: ...or extracted from the contraption", - "create.ponder.portable_storage_interface.text_8": "UNLOCALIZED: After no items have been exchanged for a while, the contraption will continue on its way", - - "create.ponder.portable_storage_interface_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.portable_storage_interface_redstone.text_1": "UNLOCALIZED: Redstone power will prevent the stationary interface from engaging", - - "create.ponder.powered_latch.header": "UNLOCALIZED: Controlling signals using the Powered Latch", - "create.ponder.powered_latch.text_1": "UNLOCALIZED: Powered Latches are redstone controllable Levers", - "create.ponder.powered_latch.text_2": "UNLOCALIZED: Signals at the back switch it on", - "create.ponder.powered_latch.text_3": "UNLOCALIZED: Signals from the side switch it back off", - "create.ponder.powered_latch.text_4": "UNLOCALIZED: Powered latches can also be toggled manually", - - "create.ponder.powered_toggle_latch.header": "UNLOCALIZED: Controlling signals using the Powered Toggle Latch", - "create.ponder.powered_toggle_latch.text_1": "UNLOCALIZED: Powered Toggle Latches are redstone controllable Levers", - "create.ponder.powered_toggle_latch.text_2": "UNLOCALIZED: Signals at the back will toggle its state", - "create.ponder.powered_toggle_latch.text_3": "UNLOCALIZED: ...on and back off", - "create.ponder.powered_toggle_latch.text_4": "UNLOCALIZED: Powered toggle latches can also be toggled manually", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "UNLOCALIZED: Controlling signals using Pulse Repeaters", - "create.ponder.pulse_repeater.text_1": "UNLOCALIZED: Pulse Repeaters emit a short pulse at a delay", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "UNLOCALIZED: Attaching blocks using Radial Chassis", - "create.ponder.radial_chassis.text_1": "UNLOCALIZED: Radial Chassis connect to identical Chassis blocks in a row", - "create.ponder.radial_chassis.text_2": "UNLOCALIZED: When one is moved by a Contraption, the others are dragged with it", - "create.ponder.radial_chassis.text_3": "UNLOCALIZED: The side faces of a Radial Chassis can be made Sticky", - "create.ponder.radial_chassis.text_4": "UNLOCALIZED: Click again to make all other sides sticky", - "create.ponder.radial_chassis.text_5": "UNLOCALIZED: Sneak and Right-Click with an empty hand to remove the slime", - "create.ponder.radial_chassis.text_6": "UNLOCALIZED: Whenever a Block is next to a sticky face...", - "create.ponder.radial_chassis.text_7": "UNLOCALIZED: ...it will attach all reachable blocks within a radius on that layer", - "create.ponder.radial_chassis.text_8": "UNLOCALIZED: Using a Wrench, a precise Radius can be specified for this chassis", - "create.ponder.radial_chassis.text_9": "UNLOCALIZED: Blocks not reachable by any sticky face will not attach", - - "create.ponder.redstone_contact.header": "UNLOCALIZED: Redstone Contacts", - "create.ponder.redstone_contact.text_1": "UNLOCALIZED: Redstone Contacts facing each other will emit a redstone signal", - "create.ponder.redstone_contact.text_2": "UNLOCALIZED: This still applies when one of them is part of a moving Contraption", - - "create.ponder.redstone_link.header": "UNLOCALIZED: Using Redstone Links", - "create.ponder.redstone_link.text_1": "UNLOCALIZED: Redstone Links can transmit redstone signals wirelessly", - "create.ponder.redstone_link.text_2": "UNLOCALIZED: Right-click while Sneaking to toggle receive mode", - "create.ponder.redstone_link.text_3": "UNLOCALIZED: A simple Right-click with a Wrench can do the same", - "create.ponder.redstone_link.text_4": "UNLOCALIZED: Receivers emit the redstone power of transmitters within 128 blocks", - "create.ponder.redstone_link.text_5": "UNLOCALIZED: Placing items in the two slots can specify a Frequency", - "create.ponder.redstone_link.text_6": "UNLOCALIZED: Only the links with matching Frequencies will communicate", - - "create.ponder.rope_pulley.header": "UNLOCALIZED: Moving Structures using Rope Pulleys", - "create.ponder.rope_pulley.text_1": "UNLOCALIZED: Rope Pulleys can move blocks vertically when given Rotational Force", - "create.ponder.rope_pulley.text_2": "UNLOCALIZED: Direction and Speed of movement depend on the Rotational Input", - - "create.ponder.rope_pulley_attachment.header": "UNLOCALIZED: Moving Pulleys as part of a Contraption", - "create.ponder.rope_pulley_attachment.text_1": "UNLOCALIZED: Whenever Pulleys are themselves being moved by a Contraption...", - "create.ponder.rope_pulley_attachment.text_2": "UNLOCALIZED: ...its attached structure will be dragged with it", - "create.ponder.rope_pulley_attachment.text_3": "UNLOCALIZED: Mind that pulleys are only movable while stopped", - - "create.ponder.rope_pulley_modes.header": "UNLOCALIZED: Movement Modes of the Rope Pulley", - "create.ponder.rope_pulley_modes.text_1": "UNLOCALIZED: Whenever Pulleys stop moving, the moved structure reverts to blocks", - "create.ponder.rope_pulley_modes.text_2": "UNLOCALIZED: It can be configured never to revert to solid blocks, or only at the location it started at", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "UNLOCALIZED: Using the Rotational Speed Controller", - "create.ponder.rotation_speed_controller.text_1": "UNLOCALIZED: Rot. Speed Controllers relay rotation from their axis to a Large Cogwheel above them", - "create.ponder.rotation_speed_controller.text_2": "UNLOCALIZED: Using the scroll input on its side, the conveyed speed can be configured", - - "create.ponder.sail.header": "UNLOCALIZED: Assembling Windmills using Sails", - "create.ponder.sail.text_1": "UNLOCALIZED: Sails are handy blocks to create Windmills with", - "create.ponder.sail.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - "create.ponder.sail.text_3": "UNLOCALIZED: Right-Click with Dye to paint them", - "create.ponder.sail.text_4": "UNLOCALIZED: Right-Click with Shears to turn them back into frames", - - "create.ponder.sail_frame.header": "UNLOCALIZED: Assembling Windmills using Sail Frames", - "create.ponder.sail_frame.text_1": "UNLOCALIZED: Sail Frames are handy blocks to create Windmills with", - "create.ponder.sail_frame.text_2": "UNLOCALIZED: They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "UNLOCALIZED: Controlling Rotational Speed using Sequenced Gearshifts", - "create.ponder.sequenced_gearshift.text_1": "UNLOCALIZED: Seq. Gearshifts relay rotation by following a timed list of instructions", - "create.ponder.sequenced_gearshift.text_2": "UNLOCALIZED: Right-click it to open the Configuration UI", - "create.ponder.sequenced_gearshift.text_3": "UNLOCALIZED: Upon receiving a Redstone Signal, it will start running its configured sequence", - "create.ponder.sequenced_gearshift.text_4": "UNLOCALIZED: Once finished, it waits for the next Redstone Signal and starts over", - "create.ponder.sequenced_gearshift.text_5": "UNLOCALIZED: A redstone comparator can be used to read the current progress", - - "create.ponder.shaft.header": "UNLOCALIZED: Relaying rotational force using Shafts", - "create.ponder.shaft.text_1": "UNLOCALIZED: Shafts will relay rotation in a straight line.", - - "create.ponder.shaft_casing.header": "UNLOCALIZED: Encasing Shafts", - "create.ponder.shaft_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Shafts", - - "create.ponder.smart_chute.header": "UNLOCALIZED: Filtering Items using Smart Chutes", - "create.ponder.smart_chute.text_1": "UNLOCALIZED: Smart Chutes are vertical chutes with additional control", - "create.ponder.smart_chute.text_2": "UNLOCALIZED: Items in the filter slot specify what exactly they can extract and transfer", - "create.ponder.smart_chute.text_3": "UNLOCALIZED: Use the Mouse Wheel to specify the extracted stack size", - "create.ponder.smart_chute.text_4": "UNLOCALIZED: Redstone power will prevent Smart Chutes from acting.", - - "create.ponder.smart_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Smart Pipes", - "create.ponder.smart_pipe.text_1": "UNLOCALIZED: Smart pipes can help control flows by fluid type", - "create.ponder.smart_pipe.text_2": "UNLOCALIZED: When placed directly at the source, they can specify the type of fluid to extract", - "create.ponder.smart_pipe.text_3": "UNLOCALIZED: Simply Right-Click their filter slot with any item containing the desired fluid", - "create.ponder.smart_pipe.text_4": "UNLOCALIZED: When placed further down a pipe network, smart pipes will only let matching fluids continue", - - "create.ponder.speedometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Speedometer", - "create.ponder.speedometer.text_1": "UNLOCALIZED: The Speedometer displays the current Speed of the attached components", - "create.ponder.speedometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.speedometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Speedometer's measurements", - - "create.ponder.spout_filling.header": "UNLOCALIZED: Filling Items using a Spout", - "create.ponder.spout_filling.text_1": "UNLOCALIZED: The Spout can fill fluid holding items provided beneath it", - "create.ponder.spout_filling.text_2": "UNLOCALIZED: The content of a Spout cannot be accessed manually", - "create.ponder.spout_filling.text_3": "UNLOCALIZED: Instead, Pipes can be used to supply it with fluids", - "create.ponder.spout_filling.text_4": "UNLOCALIZED: The Input items can be placed on a Depot under the Spout", - "create.ponder.spout_filling.text_5": "UNLOCALIZED: When items are provided on a belt...", - "create.ponder.spout_filling.text_6": "UNLOCALIZED: The Spout will hold and process them automatically", - - "create.ponder.stabilized_bearings.header": "UNLOCALIZED: Stabilized Contraptions", - "create.ponder.stabilized_bearings.text_1": "UNLOCALIZED: Whenever Mechanical Bearings are themselves part of a moving Structure..", - "create.ponder.stabilized_bearings.text_2": "UNLOCALIZED: ..they will attempt to keep themselves upright", - "create.ponder.stabilized_bearings.text_3": "UNLOCALIZED: Once again, the bearing will attach to the block in front of it", - "create.ponder.stabilized_bearings.text_4": "UNLOCALIZED: As a result, the entire sub-Contraption will stay upright", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "UNLOCALIZED: Attaching blocks using the Sticker", - "create.ponder.sticker.text_1": "UNLOCALIZED: Stickers are ideal for Redstone-controlled block attachment", - "create.ponder.sticker.text_2": "UNLOCALIZED: Upon receiving a signal, it will toggle its state", - "create.ponder.sticker.text_3": "UNLOCALIZED: If it is now moved in a contraption, the block will move with it", - "create.ponder.sticker.text_4": "UNLOCALIZED: Toggled once again, the block is no longer attached", - - "create.ponder.stressometer.header": "UNLOCALIZED: Monitoring Kinetic information using the Stressometer", - "create.ponder.stressometer.text_1": "UNLOCALIZED: The Stressometer displays the current Stress Capacity of the attached kinetic network", - "create.ponder.stressometer.text_2": "UNLOCALIZED: When wearing Engineers' Goggles, the player can get more detailed information from the Gauge", - "create.ponder.stressometer.text_3": "UNLOCALIZED: Comparators can emit analog Restone Signals relative to the Stressometer's measurements", - - "create.ponder.super_glue.header": "UNLOCALIZED: Attaching blocks using Super Glue", - "create.ponder.super_glue.text_1": "UNLOCALIZED: Super Glue groups blocks together into moving contraptions", - "create.ponder.super_glue.text_2": "UNLOCALIZED: Clicking two endpoints creates a new 'glued' area", - "create.ponder.super_glue.text_3": "UNLOCALIZED: To remove a box, punch it with the glue item in hand", - "create.ponder.super_glue.text_4": "UNLOCALIZED: Adjacent blocks sharing an area will pull each other along", - "create.ponder.super_glue.text_5": "UNLOCALIZED: Overlapping glue volumes will move together", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "UNLOCALIZED: Generating Rotational Force using Valve Handles", - "create.ponder.valve_handle.text_1": "UNLOCALIZED: Valve Handles can be used by players to apply rotational force manually", - "create.ponder.valve_handle.text_2": "UNLOCALIZED: Hold Right-Click to rotate it Counter-Clockwise", - "create.ponder.valve_handle.text_3": "UNLOCALIZED: Its conveyed speed is slow and precise", - "create.ponder.valve_handle.text_4": "UNLOCALIZED: Sneak and Hold Right-Click to rotate it Clockwise", - "create.ponder.valve_handle.text_5": "UNLOCALIZED: Valve handles can be dyed for aesthetic purposes", - - "create.ponder.valve_pipe.header": "UNLOCALIZED: Controlling Fluid flow using Valves", - "create.ponder.valve_pipe.text_1": "UNLOCALIZED: Valve pipes help control fluids propagating through pipe networks", - "create.ponder.valve_pipe.text_2": "UNLOCALIZED: Their shaft input controls whether fluid is currently allowed through", - "create.ponder.valve_pipe.text_3": "UNLOCALIZED: Given Rotational Force in the opening direction, the valve will open up", - "create.ponder.valve_pipe.text_4": "UNLOCALIZED: It can be closed again by reversing the input rotation", - - "create.ponder.water_wheel.header": "UNLOCALIZED: Generating Rotational Force using Water Wheels", - "create.ponder.water_wheel.text_1": "UNLOCALIZED: Water Wheels draw force from adjacent Water Currents", - "create.ponder.water_wheel.text_2": "UNLOCALIZED: The more faces are powered, the faster the Water Wheel will rotate", - "create.ponder.water_wheel.text_3": "UNLOCALIZED: The Wheels' blades should be oriented against the flow", - "create.ponder.water_wheel.text_4": "UNLOCALIZED: Facing the opposite way, they will not be as effective", - - "create.ponder.weighted_ejector.header": "UNLOCALIZED: Using Weighted Ejectors", - "create.ponder.weighted_ejector.text_1": "UNLOCALIZED: Sneak and Right-Click holding an Ejector to select its target location", - "create.ponder.weighted_ejector.text_10": "UNLOCALIZED: It is now limited to this stack size, and only activates when its held stack reaches this amount", - "create.ponder.weighted_ejector.text_11": "UNLOCALIZED: Other Entities will always trigger an Ejector when stepping on it", - "create.ponder.weighted_ejector.text_2": "UNLOCALIZED: The placed ejector will now launch objects to the marked location", - "create.ponder.weighted_ejector.text_3": "UNLOCALIZED: A valid target can be at any height or distance within range", - "create.ponder.weighted_ejector.text_4": "UNLOCALIZED: They cannot however be off to a side", - "create.ponder.weighted_ejector.text_5": "UNLOCALIZED: If no valid Target was selected, it will simply target the block directly in front", - "create.ponder.weighted_ejector.text_6": "UNLOCALIZED: Supply Rotational Force in order to charge it up", - "create.ponder.weighted_ejector.text_7": "UNLOCALIZED: Items placed on the ejector cause it to trigger", - "create.ponder.weighted_ejector.text_8": "UNLOCALIZED: If Inventories are targeted, the ejector will wait until there is space", - "create.ponder.weighted_ejector.text_9": "UNLOCALIZED: Using the Wrench, a required Stack Size can be configured", - - "create.ponder.weighted_ejector_redstone.header": "UNLOCALIZED: Controlling Weighted Ejectors with Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Ejectors will not activate", - "create.ponder.weighted_ejector_redstone.text_2": "UNLOCALIZED: Furthermore, Observers can detect when Ejectors activate", - - "create.ponder.weighted_ejector_tunnel.header": "UNLOCALIZED: Splitting item stacks using Weighted Ejectors", - "create.ponder.weighted_ejector_tunnel.text_1": "UNLOCALIZED: Combined with Brass Tunnels, Ejectors can split item stacks by specific amounts", - "create.ponder.weighted_ejector_tunnel.text_2": "UNLOCALIZED: First, configure the Brass Tunnel to 'Prefer Nearest', in order to prioritize its side output", - "create.ponder.weighted_ejector_tunnel.text_3": "UNLOCALIZED: The Stack Size set on the Ejector now determines the amount to be split off", - "create.ponder.weighted_ejector_tunnel.text_4": "UNLOCALIZED: While a new stack of the configured size exits the side output...", - "create.ponder.weighted_ejector_tunnel.text_5": "UNLOCALIZED: ...the remainder will continue on its path", - - "create.ponder.windmill_source.header": "UNLOCALIZED: Generating Rotational Force using Windmill Bearings", - "create.ponder.windmill_source.text_1": "UNLOCALIZED: Windmill Bearings attach to the block in front of them", - "create.ponder.windmill_source.text_2": "UNLOCALIZED: Create a movable structure with the help of Super Glue", - "create.ponder.windmill_source.text_3": "UNLOCALIZED: If enough Sail-like blocks are included, this can act as a Windmill", - "create.ponder.windmill_source.text_4": "UNLOCALIZED: Activated with Right-Click, the Windmill Bearing will start providing Rotational Force", - "create.ponder.windmill_source.text_5": "UNLOCALIZED: The Amount of Sail Blocks determine its Rotation Speed", - "create.ponder.windmill_source.text_6": "UNLOCALIZED: Use a Wrench to configure its rotation direction", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "UNLOCALIZED: Windmill Contraptions", - "create.ponder.windmill_structure.text_1": "UNLOCALIZED: Any Structure can count as a valid Windmill, as long as it contains at least 8 sail-like Blocks.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json b/src/generated/resources/assets/create/lang/unfinished/ro_ro.json deleted file mode 100644 index 566f7ab283..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 655", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Stică De Salcâm", - "block.create.acacia_window_pane": "Geam De Salcâm", - "block.create.adjustable_chain_gearshift": "Schimbător De Viteze Reglabil Înlănțuit", - "block.create.analog_lever": "Manetă Analogică", - "block.create.andesite_belt_funnel": "Pâlnie De Andezit Pentru Benzi", - "block.create.andesite_casing": "Carcasă De Andezit", - "block.create.andesite_encased_cogwheel": "Roată Dințată Încapsulată În Andezit", - "block.create.andesite_encased_large_cogwheel": "Roată Dințată Mare Încapsulată În Andezit", - "block.create.andesite_encased_shaft": "Rotor Încapsulat În Andezit", - "block.create.andesite_funnel": "Pâlnie De Andezit", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "Coloană De Andezit", - "block.create.andesite_tunnel": "Tunel De Andezit", - "block.create.asurine": "Asurină", - "block.create.asurine_pillar": "Coloană De Asurină", - "block.create.basin": "Bazin", - "block.create.belt": "Bandă", - "block.create.birch_window": "Sticlă De Mesteacăn", - "block.create.birch_window_pane": "Geam De Mesteacăn", - "block.create.black_nixie_tube": "Tub Nixie Negru", - "block.create.black_sail": "Velă Neagră", - "block.create.black_seat": "Scaun Negru", - "block.create.black_toolbox": "Trusă De Scule Neagră", - "block.create.black_valve_handle": "Mâner De Supapă Negru", - "block.create.blaze_burner": "Arzător De Dogoreală", - "block.create.blue_nixie_tube": "Tub Nixie Albastru", - "block.create.blue_sail": "Velă Albastră", - "block.create.blue_seat": "Scaun Albastru", - "block.create.blue_toolbox": "Trusă De Scule Albastră", - "block.create.blue_valve_handle": "Mâner De Supapă Albastru", - "block.create.brass_belt_funnel": "Pâlnie De Alamă Pentru Benzi", - "block.create.brass_block": "Bloc De Alamă", - "block.create.brass_casing": "Carcasă De Alamă", - "block.create.brass_encased_cogwheel": "Roată Dințată Încapsulată În Alamă", - "block.create.brass_encased_large_cogwheel": "Roată Dințată Mare Încapsulată În Alamă", - "block.create.brass_encased_shaft": "Rotor Încapsulat În Alamă", - "block.create.brass_funnel": "Pâlnie De Alamă", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "Tunel De Alamă", - "block.create.brown_nixie_tube": "Tub Nixie Maro", - "block.create.brown_sail": "Velă Maro", - "block.create.brown_seat": "Scaun Maro", - "block.create.brown_toolbox": "Cutie Cu Unelete Maro", - "block.create.brown_valve_handle": "Mâner De Supapă Maro", - "block.create.calcite_pillar": "Coloană De Calcit", - "block.create.cart_assembler": "Asamblator De Vagonet", - "block.create.chocolate": "Ciocolată", - "block.create.chute": "Tobogan", - "block.create.clockwork_bearing": "Rulment De Ceasornic", - "block.create.clutch": "Ambreiaj", - "block.create.cogwheel": "Roată Dințată", - "block.create.content_observer": "Observator De Conținut", - "block.create.controller_rail": "Controlor De Șină", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "Backtank De Cupru", - "block.create.copper_casing": "Carcasă De Cupru", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "Lespede De Șindrilă De Cupru", - "block.create.copper_shingle_stairs": "Scări De Șindrilă De Cupru", - "block.create.copper_shingles": "Șindrile De Cupru", - "block.create.copper_tile_slab": "Lespede De Țiglă De Cupru", - "block.create.copper_tile_stairs": "Scări De Țiglă De Cupru", - "block.create.copper_tiles": "Țigle De Cupru", - "block.create.copper_valve_handle": "Mâner De Supapă De Cupru", - "block.create.creative_crate": "Ladă Creativ", - "block.create.creative_fluid_tank": "Rezervor De Fluid Creativ", - "block.create.creative_motor": "Motor Creativ", - "block.create.crimsite": "Crimsite", - "block.create.crimsite_pillar": "Coloană De Crimsite", - "block.create.crimson_window": "Sticlă Stacojie", - "block.create.crimson_window_pane": "Geam Stacojiu", - "block.create.crushing_wheel": "Roată De Zdrobit", - "block.create.crushing_wheel_controller": "Controlor De Roată De Zdrobit", - "block.create.cuckoo_clock": "Ceas Cucu", - "block.create.cut_andesite": "Andezit Tăiat", - "block.create.cut_andesite_brick_slab": "Lespede De Cărămizi De Andezit Tăiat ", - "block.create.cut_andesite_brick_stairs": "Scări De Cărămizi De Andezit Tăiat", - "block.create.cut_andesite_brick_wall": "Zid De Cărămizi De Andezit Tăiat", - "block.create.cut_andesite_bricks": "Cărămizi De Andezit Tăiat", - "block.create.cut_andesite_slab": "Lespede De Andezit Tăiat", - "block.create.cut_andesite_stairs": "Scări De Andezit Tăiat", - "block.create.cut_andesite_wall": "Zid De Andezit Tăiat", - "block.create.cut_asurine": "Asurină Tăiată", - "block.create.cut_asurine_brick_slab": "Lespede De Cărămizi De Asurină Tăiată", - "block.create.cut_asurine_brick_stairs": "Scări De Cărămizi De Asurină Tăiată", - "block.create.cut_asurine_brick_wall": "Zid De Cărămizi De Asurină Tăiată", - "block.create.cut_asurine_bricks": "Cărămizi De Asurină Tăiată", - "block.create.cut_asurine_slab": "Lespede De Asurină Tăiată", - "block.create.cut_asurine_stairs": "Scări De Asurină Tăiată", - "block.create.cut_asurine_wall": "Zid De Asurină Tăiată", - "block.create.cut_calcite": "Calcit Tăiat", - "block.create.cut_calcite_brick_slab": "Lespede De Cărămizi De Calcit Tăiat", - "block.create.cut_calcite_brick_stairs": "Scări De Cărămizi De Calcit Tăiat", - "block.create.cut_calcite_brick_wall": "Zid De Căramizi De Calcit Tăiat", - "block.create.cut_calcite_bricks": "Cărămizi De Calcit Tăiat", - "block.create.cut_calcite_slab": "Lespede De Calcit Tăiat", - "block.create.cut_calcite_stairs": "Scări De Calcit Tăiat", - "block.create.cut_calcite_wall": "Zid De Calcit Tăiat", - "block.create.cut_crimsite": "Crimsite Tăiat", - "block.create.cut_crimsite_brick_slab": "Lespede De Cărămizi De Crimsite Tăiat", - "block.create.cut_crimsite_brick_stairs": "Scări De Cărămizi De Crimsite Tăiat", - "block.create.cut_crimsite_brick_wall": "Zid De Cărămizi De Crimsite Tăiat", - "block.create.cut_crimsite_bricks": "Cărămizi De Crimsite Tăiat", - "block.create.cut_crimsite_slab": "Lespede De Crimsite Tăiat", - "block.create.cut_crimsite_stairs": "Scări De Crimsite Tăiat", - "block.create.cut_crimsite_wall": "Zid De Crimsite Tăiat", - "block.create.cut_deepslate": "Deepslate Tăiat", - "block.create.cut_deepslate_brick_slab": "Lespede De Cărămizi De Deepslate Tăiat", - "block.create.cut_deepslate_brick_stairs": "Scări De Cărămizi De Deepslate Tăiat", - "block.create.cut_deepslate_brick_wall": "Zid De Cărămizi De Deepslate Tăiat", - "block.create.cut_deepslate_bricks": "Cărămizi De Deepslate Tăiat", - "block.create.cut_deepslate_slab": "Lespede De Deepslate Tăiat", - "block.create.cut_deepslate_stairs": "Scări De Deepslate Tăiat", - "block.create.cut_deepslate_wall": "Zid De Deepslate Tăiat", - "block.create.cut_diorite": "Diorit Tăiat", - "block.create.cut_diorite_brick_slab": "Lespede De Cărămizi De Diorit Tăiat", - "block.create.cut_diorite_brick_stairs": "Scări De Cărămizi De Diorit Tăiat", - "block.create.cut_diorite_brick_wall": "Zid De Cărămizi De Diorit Tăiat", - "block.create.cut_diorite_bricks": "Cărămizi De Diorit Tăiat", - "block.create.cut_diorite_slab": "Lespede De Diorit Tăiat", - "block.create.cut_diorite_stairs": "Scări De Diorit Tăiat", - "block.create.cut_diorite_wall": "Zid De Diorit Tăiat", - "block.create.cut_dripstone": "Dripstone Tăiat", - "block.create.cut_dripstone_brick_slab": "Lespede De Cărămizi De Dripstone Tăiat", - "block.create.cut_dripstone_brick_stairs": "Scări De Cărămizi De Dripstone Tăiat", - "block.create.cut_dripstone_brick_wall": "Zid De Cărămizi De Dripstone Tăiat", - "block.create.cut_dripstone_bricks": "Cărămizi De Dripstone Tăiat", - "block.create.cut_dripstone_slab": "Lespede De Dripstone Tăiat", - "block.create.cut_dripstone_stairs": "Scări De Dripstone Tăiat", - "block.create.cut_dripstone_wall": "Zid De Dripstone Tăiat", - "block.create.cut_granite": "Granit Tăiat", - "block.create.cut_granite_brick_slab": "Lespede De Cărămizi De Granit Tăiat", - "block.create.cut_granite_brick_stairs": "Scări De Cărămizi De Granit Tăiat", - "block.create.cut_granite_brick_wall": "Zid De Cărămizi De Granit Tăiat", - "block.create.cut_granite_bricks": "Cărămizi De Granit Tăiat", - "block.create.cut_granite_slab": "Lespede De Granit Tăiat", - "block.create.cut_granite_stairs": "Scări De Granit Tăiat", - "block.create.cut_granite_wall": "Zid De Granit Tăiat", - "block.create.cut_limestone": "Calcar Tăiat", - "block.create.cut_limestone_brick_slab": "Lespede De Cărămizi De Calcar Tăiat", - "block.create.cut_limestone_brick_stairs": "Scări De Cărămizi De Calcar Tăiat", - "block.create.cut_limestone_brick_wall": "Zid De Cărămizi De Calcar Tăiat", - "block.create.cut_limestone_bricks": "Cărămizi De Calcar Tăiat", - "block.create.cut_limestone_slab": "Lespede De Calcar Tăiat", - "block.create.cut_limestone_stairs": "Scări De Calcar Tăiat", - "block.create.cut_limestone_wall": "Zid De Calcar Tăiat", - "block.create.cut_ochrum": "Ochrum Tăiat", - "block.create.cut_ochrum_brick_slab": "Lespede De Cărămizi De Ochrum Tăiat", - "block.create.cut_ochrum_brick_stairs": "Scări De Cărămizi De Ochrum Tăiat", - "block.create.cut_ochrum_brick_wall": "Zid De Cărămizi De Ochrum Tăiat", - "block.create.cut_ochrum_bricks": "Cărămizi De Ochrum Tăiat", - "block.create.cut_ochrum_slab": "Lespede De Ochrum Tăiat", - "block.create.cut_ochrum_stairs": "Scări De Ochrum Tăiat", - "block.create.cut_ochrum_wall": "Zid De Ochrum Tăiat", - "block.create.cut_scorchia": "Scorchia Tăiată", - "block.create.cut_scorchia_brick_slab": "Lespede De Cărămizi De Scorchia Tăiată", - "block.create.cut_scorchia_brick_stairs": "Scări De Cărămizi De Scorchia Tăiată", - "block.create.cut_scorchia_brick_wall": "Zid De Cărămizi De Scorchia Tăiată", - "block.create.cut_scorchia_bricks": "Cărămizi De Scorchia Tăiată", - "block.create.cut_scorchia_slab": "Lespede De Scorchia Tăiată", - "block.create.cut_scorchia_stairs": "Scări De Scorchia Tăiată", - "block.create.cut_scorchia_wall": "Zid De Scorchia Tăiată", - "block.create.cut_scoria": "Scoria Tăiată", - "block.create.cut_scoria_brick_slab": "Lespede De Cărămizi De Scoria Tăiată", - "block.create.cut_scoria_brick_stairs": "Scări De Cărămizi De Scoria Tăiată", - "block.create.cut_scoria_brick_wall": "Zid De Cărămizi De Scoria Tăiată", - "block.create.cut_scoria_bricks": "Cărămizi De Scoria Tăiată", - "block.create.cut_scoria_slab": "Lespede De Scoria Tăiată", - "block.create.cut_scoria_stairs": "Scări De Scoria Tăiată", - "block.create.cut_scoria_wall": "Zid De Scoria Tăiată", - "block.create.cut_tuff": "Tuf Tăiat", - "block.create.cut_tuff_brick_slab": "Lespede De Cărămizi De Tuf Tăiat", - "block.create.cut_tuff_brick_stairs": "Scări De Cărămizi De Tuf Tăiat", - "block.create.cut_tuff_brick_wall": "Zid De Cărămizi De Tuf Tăiat", - "block.create.cut_tuff_bricks": "Cărămizi De Tuf Tăiat", - "block.create.cut_tuff_slab": "Lespede De Tuf Tăiat", - "block.create.cut_tuff_stairs": "Scări De Tuf Tăiat", - "block.create.cut_tuff_wall": "Zid De Tuf Tăiat", - "block.create.cut_veridium": "Veridium Tăiat", - "block.create.cut_veridium_brick_slab": "Lespede De Cărămizi De Veridium Tăiat", - "block.create.cut_veridium_brick_stairs": "Scări De Cărămizi De Veridium Tăiat", - "block.create.cut_veridium_brick_wall": "Zid De Cărămizi De Veridium Tăiat", - "block.create.cut_veridium_bricks": "Cărămizi De Veridium Tăiat", - "block.create.cut_veridium_slab": "Lespede De Veridium Tăiat", - "block.create.cut_veridium_stairs": "Scări De Veridium Tăiat", - "block.create.cut_veridium_wall": "Zid De Veridium Tăiat", - "block.create.cyan_nixie_tube": "Tub Nixie Turcoaz", - "block.create.cyan_sail": "Velă Turcoaz", - "block.create.cyan_seat": "Scaun Turcoaz", - "block.create.cyan_toolbox": "Trusă De Scule Turcoaz", - "block.create.cyan_valve_handle": "Mâner De Supapă Turcoaz", - "block.create.dark_oak_window": "Sticlă De Stejar Negru", - "block.create.dark_oak_window_pane": "Geam De Stejar Negru", - "block.create.deepslate_pillar": "Coloană De Deepslate", - "block.create.deepslate_zinc_ore": "Minereu De Zinc De Adâncime", - "block.create.deployer": "Deployer", - "block.create.depot": "Depot", - "block.create.diorite_pillar": "Coloană De Diorit", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "Coloană De Dripstone", - "block.create.encased_chain_drive": "Lanț De Distribuție Încapsulat", - "block.create.encased_fan": "Ventilator Încapsulat", - "block.create.encased_fluid_pipe": "Conductă De Fluide Încapsulată", - "block.create.exposed_copper_shingle_slab": "Lespede De Șindrilă De Cupru Expusă", - "block.create.exposed_copper_shingle_stairs": "Scări De Șindrilă De Cupru Expusă", - "block.create.exposed_copper_shingles": "Șindrile De Cupru Expuse", - "block.create.exposed_copper_tile_slab": "Lespede De Țiglă De Cupru Expusă", - "block.create.exposed_copper_tile_stairs": "Scări De Țiglă De Cupru Expuse", - "block.create.exposed_copper_tiles": "Țigle De Cupru Expuse", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "Conductă De Fluide", - "block.create.fluid_tank": "Rezervor De Fluid", - "block.create.fluid_valve": "Supapă De Fluid", - "block.create.flywheel": "Volant", - "block.create.framed_glass": "Sticlă Înrămată", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "Geam Înrămat", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "Cărucior Portal", - "block.create.gantry_shaft": "Rotor Portal", - "block.create.gearbox": "Cutie De Viteze", - "block.create.gearshift": "Schimbător De Viteze", - "block.create.glass_fluid_pipe": "Conductă De Fluide De Sticlă", - "block.create.granite_pillar": "Coloană De Granit", - "block.create.gray_nixie_tube": "Tub Nixie Gri", - "block.create.gray_sail": "Velă Gri", - "block.create.gray_seat": "Scaun Gri", - "block.create.gray_toolbox": "Trusă De Scule Gri", - "block.create.gray_valve_handle": "Mâner De Supapă Gri", - "block.create.green_nixie_tube": "Tub Nixie Verde", - "block.create.green_sail": "Velă Verde", - "block.create.green_seat": "Scaun Verde", - "block.create.green_toolbox": "Trusă De Scule Verde", - "block.create.green_valve_handle": "Mâner De Supapă Verde", - "block.create.hand_crank": "Manivelă", - "block.create.haunted_bell": "Clopot Bântuit", - "block.create.honey": "Miere", - "block.create.horizontal_framed_glass": "Sticlă Înrămată Orizontală", - "block.create.horizontal_framed_glass_pane": "Geam Înrămat Orizontal", - "block.create.hose_pulley": "Scripete De Furtun", - "block.create.item_drain": "Scurgere De Obiecte", - "block.create.item_vault": "Seif De Obiecte", - "block.create.jungle_window": "Sticlă De Junglă", - "block.create.jungle_window_pane": "Geam De Junglă", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "Roată Dințată Mare", - "block.create.layered_andesite": "Andezit Stratificat", - "block.create.layered_asurine": "Asurină Stratificată", - "block.create.layered_calcite": "Calcit Stratificat", - "block.create.layered_crimsite": "Crimsite Stratificat", - "block.create.layered_deepslate": "Deepslate Stratificat", - "block.create.layered_diorite": "Diorit Stratificat", - "block.create.layered_dripstone": "Dripstone Stratificat", - "block.create.layered_granite": "Granit Stratificat", - "block.create.layered_limestone": "Limestone Stratificat", - "block.create.layered_ochrum": "Ochrum Stratificat", - "block.create.layered_scorchia": "Scorchia Stratificată", - "block.create.layered_scoria": "Scoria Stratificată", - "block.create.layered_tuff": "Tuf Stratificat", - "block.create.layered_veridium": "Veridium Stratificat", - "block.create.lectern_controller": "Controlor De Pupitru", - "block.create.light_blue_nixie_tube": "Tub Nixie Albastru-Deschis", - "block.create.light_blue_sail": "Velă Albastru-Deschis", - "block.create.light_blue_seat": "Scaun Albastru-Deschis", - "block.create.light_blue_toolbox": "Trusă De Scule Albastru-Deschis", - "block.create.light_blue_valve_handle": "Mâner De Supapă Albastru-Deschis", - "block.create.light_gray_nixie_tube": "Tub Nixie Gri-Deschis", - "block.create.light_gray_sail": "Velă Gri-Deschisă", - "block.create.light_gray_seat": "Scaun Gri-Deschis", - "block.create.light_gray_toolbox": "Trusă De Scule Gri-Deschisă", - "block.create.light_gray_valve_handle": "Mâner De Supapă Gri-Deschis", - "block.create.lime_nixie_tube": "Tub Nixie Verde-Deschis", - "block.create.lime_sail": "Velă Verde-Deschisă", - "block.create.lime_seat": "Scaun Verde-Deschis", - "block.create.lime_toolbox": "Trusă De Scule Verde-Deschisă", - "block.create.lime_valve_handle": "Mâner De Supapă Verde Deschis", - "block.create.limestone": "Calcar", - "block.create.limestone_pillar": "Coloană De Calcar", - "block.create.linear_chassis": "Șasiu Liniar", - "block.create.lit_blaze_burner": "Arzător De Dogoreală Aprins", - "block.create.magenta_nixie_tube": "Tub Nixie Magenta", - "block.create.magenta_sail": "Velă Magenta", - "block.create.magenta_seat": "Scaun Magenta", - "block.create.magenta_toolbox": "Trusă De Scule Magenta", - "block.create.magenta_valve_handle": "Mâner De Supapă Magenta", - "block.create.mechanical_arm": "Braț Mecanic", - "block.create.mechanical_bearing": "Rulment Mecanic", - "block.create.mechanical_crafter": "Meșter Mecanic", - "block.create.mechanical_drill": "Burghiu Mecanic", - "block.create.mechanical_harvester": "Combină Mecanică", - "block.create.mechanical_mixer": "Mixer Mecanic", - "block.create.mechanical_piston": "Piston Mecanic", - "block.create.mechanical_piston_head": "Cap De Piston Mecanic", - "block.create.mechanical_plough": "Plug Mecanic", - "block.create.mechanical_press": "Presă Mecanică", - "block.create.mechanical_pump": "Pompă Mecanică", - "block.create.mechanical_saw": "Ferăstrău Mecanic", - "block.create.metal_bracket": "Brachetă De Metal", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "Moară De Piatră", - "block.create.minecart_anchor": "Ancoră De Vagonet", - "block.create.mysterious_cuckoo_clock": "Ceas Cucu", - "block.create.nixie_tube": "Tub Nixie", - "block.create.nozzle": "Plasă", - "block.create.oak_window": "Sticlă De Stejar", - "block.create.oak_window_pane": "Geam De Stejar", - "block.create.ochrum": "Ochrum", - "block.create.ochrum_pillar": "Coloană De Ochrum", - "block.create.orange_sail": "Velă Portocalie", - "block.create.orange_seat": "Scaun Portocaliu", - "block.create.orange_toolbox": "Trusă De Scule Portocalie", - "block.create.orange_valve_handle": "Mâner De Supapă Portocaliu", - "block.create.ornate_iron_window": "Sticlă De Fier Împodobită", - "block.create.ornate_iron_window_pane": "Geam De Fier Împodobită", - "block.create.oxidized_copper_shingle_slab": "Lespede De Șindrilă De Cupru Oxidată", - "block.create.oxidized_copper_shingle_stairs": "Scări De Șindilă De Cupru Oxidate", - "block.create.oxidized_copper_shingles": "Șindrile De Cupru Oxidate", - "block.create.oxidized_copper_tile_slab": "Lespede De Țiglă De Cupru Oxidată", - "block.create.oxidized_copper_tile_stairs": "Scări De Țigle De Cupru Oxidate", - "block.create.oxidized_copper_tiles": "Țigle De Cupru Oxidate", - "block.create.peculiar_bell": "Clopot Ciudat", - "block.create.pink_nixie_tube": "Tub Nixie Roz", - "block.create.pink_sail": "Velă Roz", - "block.create.pink_seat": "Scaun Roz", - "block.create.pink_toolbox": "Trusă De Scule Roz", - "block.create.pink_valve_handle": "Mâner De Supapă Roz", - "block.create.piston_extension_pole": "Braț De Extensie De Piston", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "Andezit Tăiat Șlefuit", - "block.create.polished_cut_andesite_slab": "Lespede De Andezit Tăiat Șlefuit", - "block.create.polished_cut_andesite_stairs": "Scări De Andezit Tăiat Șlefuit", - "block.create.polished_cut_andesite_wall": "Zid De Andezit Tăiat Șlefuit", - "block.create.polished_cut_asurine": "Asurină Tăiată Șlefuită", - "block.create.polished_cut_asurine_slab": "Lespede De Asurină Tăiată Șlefuită", - "block.create.polished_cut_asurine_stairs": "Scări De Asurină Tăiată Șlefuită", - "block.create.polished_cut_asurine_wall": "Zid De Asurină Tăiată Șlefuită", - "block.create.polished_cut_calcite": "Calcit Tăiat Șlefuit", - "block.create.polished_cut_calcite_slab": "Lespede De Calcit Tăiat Șlefuit", - "block.create.polished_cut_calcite_stairs": "Scări De Calcit Tăiat Șlefuit", - "block.create.polished_cut_calcite_wall": "Zid De Calcit Tăiat Șlefuit", - "block.create.polished_cut_crimsite": "Crimsite Tăiat Șlefuit", - "block.create.polished_cut_crimsite_slab": "Lespede De Crimsite Tăiat Șlefuit", - "block.create.polished_cut_crimsite_stairs": "Scări De Crimsite Tăiat Șlefuit", - "block.create.polished_cut_crimsite_wall": "Zid De Crimsite Tăiat Șlefuit", - "block.create.polished_cut_deepslate": "Deepslate Tăiat Șlefuit", - "block.create.polished_cut_deepslate_slab": "Lespede De Deepslate Tăiat Șlefuit", - "block.create.polished_cut_deepslate_stairs": "Scări De Deepslate Tăiat Șlefuit", - "block.create.polished_cut_deepslate_wall": "Zid De Deepslate Tăiat Șlefuit", - "block.create.polished_cut_diorite": "Diorit Tăiat Șlefuit", - "block.create.polished_cut_diorite_slab": "Lespede De Diorit Tăiat Șlefuit", - "block.create.polished_cut_diorite_stairs": "Scări De Diorit Tăiat Șlefuit", - "block.create.polished_cut_diorite_wall": "Zid De Diorit Tăiat Șlefuit", - "block.create.polished_cut_dripstone": "Dripstone Tăiat Șlefuit", - "block.create.polished_cut_dripstone_slab": "Lespede De Dripstone Tăiat Șlefuit", - "block.create.polished_cut_dripstone_stairs": "Scări De Dripstone Tăiat Șlefuit", - "block.create.polished_cut_dripstone_wall": "Zid De Dripstone Tăiat Șlefuit", - "block.create.polished_cut_granite": "Granit Tăiat Șlefuit", - "block.create.polished_cut_granite_slab": "Lespede De Granit Tăiat Șlefuit", - "block.create.polished_cut_granite_stairs": "Scări De Granit Tăiat Șlefuit", - "block.create.polished_cut_granite_wall": "Zid De Granit Tăiat Șlefuit", - "block.create.polished_cut_limestone": "Calcar Tăiat Șlefuit", - "block.create.polished_cut_limestone_slab": "Lespede De Calcar Tăiat Șlefuit", - "block.create.polished_cut_limestone_stairs": "Scări De Calcar Tăiat Șlefuit", - "block.create.polished_cut_limestone_wall": "Zid De Calcar Tăiat Șlefuit", - "block.create.polished_cut_ochrum": "Ochrum Tăiat Șlefuit", - "block.create.polished_cut_ochrum_slab": "Lespede De Ochrum Tăiat Șlefuit", - "block.create.polished_cut_ochrum_stairs": "Scări De Ochrum Tăiat Șlefuit", - "block.create.polished_cut_ochrum_wall": "Zid De Ochrum Tăiat Șlefuit", - "block.create.polished_cut_scorchia": "Scorchia Tăiată Șlefuită", - "block.create.polished_cut_scorchia_slab": "Lespede De Scorchia Tăiată Șlefuită", - "block.create.polished_cut_scorchia_stairs": "Scări De Scorchia Tăiată Șlefuită", - "block.create.polished_cut_scorchia_wall": "Zid De Scorchia Tăiată Șlefuită", - "block.create.polished_cut_scoria": "Scoria Tăiată Șlefuită", - "block.create.polished_cut_scoria_slab": "Lespede De Scoria Tăiată Șlefuită", - "block.create.polished_cut_scoria_stairs": "Scări De Scoria Tăiată Șlefuită", - "block.create.polished_cut_scoria_wall": "Zid De Scoria Tăiată Șlefuită", - "block.create.polished_cut_tuff": "Tuf Tăiat Șlefuit", - "block.create.polished_cut_tuff_slab": "Lespede De Tuf Tăiat Șlefuit", - "block.create.polished_cut_tuff_stairs": "Scări De Tuf Tăiat Șlefuit", - "block.create.polished_cut_tuff_wall": "Zid De Tuf Tăiat Șlefuit", - "block.create.polished_cut_veridium": "Veridium Tăiat Șlefuit", - "block.create.polished_cut_veridium_slab": "Lespede De Veridium Tăiat Șlefuit", - "block.create.polished_cut_veridium_stairs": "Scări De Veridium Tăiat Șlefuit", - "block.create.polished_cut_veridium_wall": "Zid De Veridium Tăiat Șlefuit", - "block.create.portable_fluid_interface": "Interfață De Fluid Portabilă", - "block.create.portable_storage_interface": "Interfață De Depozitare Portabilă", - "block.create.powered_latch": "Manetă Alimentată", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "Manetă Alimentată Comutatoare", - "block.create.pulley_magnet": "Magnet De Scripete", - "block.create.pulse_extender": "Prelungitor De Puls", - "block.create.pulse_repeater": "Repetor De Puls", - "block.create.purple_nixie_tube": "Tub Nixie Violet", - "block.create.purple_sail": "Velă Violetă", - "block.create.purple_seat": "Scaun Violet", - "block.create.purple_toolbox": "Trusă De Scule Violetă", - "block.create.purple_valve_handle": "Mâner De Supapă Violet", - "block.create.radial_chassis": "Șasiu Radial", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "Bloc De Zinc Brut", - "block.create.red_nixie_tube": "Tub Nixie Roșu", - "block.create.red_sail": "Velă Roșie", - "block.create.red_seat": "Scaun Roșu", - "block.create.red_toolbox": "Trusă De Scule Roșie", - "block.create.red_valve_handle": "Mâner De Supapă Roșie", - "block.create.redstone_contact": "Contact Redstone", - "block.create.redstone_link": "Legătură De Redstone", - "block.create.refined_radiance_casing": "Carcasă Radiantă", - "block.create.rope": "Sfoară", - "block.create.rope_pulley": "Scripete De Sfoară", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "Controlor De Viteză De Rotație", - "block.create.sail_frame": "Ramă De Velă", - "block.create.schematic_table": "Masă De Schemă", - "block.create.schematicannon": "Tun De Schemă", - "block.create.scorchia": "Scorchia", - "block.create.scorchia_pillar": "Coloană De Scorchia", - "block.create.scoria": "Scoria", - "block.create.scoria_pillar": "Coloană De Scoria", - "block.create.secondary_linear_chassis": "Șasiu Liniar Secundar", - "block.create.sequenced_gearshift": "Schimbător De Viteze Secvențial", - "block.create.shadow_steel_casing": "Carcasă De Umbră", - "block.create.shaft": "Rotor", - "block.create.small_andesite_brick_slab": "Lespede De Cărămizi Mici De Andezit", - "block.create.small_andesite_brick_stairs": "Scări De Cărămizi Mici De Andezit", - "block.create.small_andesite_brick_wall": "Zid De Cărămizi Mici De Andezit", - "block.create.small_andesite_bricks": "Cărămizi Mici De Andezit", - "block.create.small_asurine_brick_slab": "Lespede De Cărămizi Mici De Asurină", - "block.create.small_asurine_brick_stairs": "Scări De Cărămizi Mici De Asurină", - "block.create.small_asurine_brick_wall": "Zid De Cărămizi Mici De Asurină", - "block.create.small_asurine_bricks": "Cărămizi Mici De Asurină", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "Lespede De Cărămizi Mici De Calcit", - "block.create.small_calcite_brick_stairs": "Scări De Cărămizi Mici De Calcit", - "block.create.small_calcite_brick_wall": "Zid De Cărămizi Mici De Calcit", - "block.create.small_calcite_bricks": "Cărămizi Mici De Calcit", - "block.create.small_crimsite_brick_slab": "Lespede De Cărămizi Mici De Crimsite", - "block.create.small_crimsite_brick_stairs": "Scări De Cărămizi Mici De Crimsite", - "block.create.small_crimsite_brick_wall": "Zid De Cărămizi Mici De Crimsite", - "block.create.small_crimsite_bricks": "Cărămizi Mici De Crimsite", - "block.create.small_deepslate_brick_slab": "Lespede De Cărămizi Mici De Deepslate", - "block.create.small_deepslate_brick_stairs": "Scări De Cărămizi Mici De Deepslate", - "block.create.small_deepslate_brick_wall": "Zid De Cărămizi Mici De Deepslate", - "block.create.small_deepslate_bricks": "Cărămizi Mici De Deepslate", - "block.create.small_diorite_brick_slab": "Lespede De Cărămizi Mici De Diorit ", - "block.create.small_diorite_brick_stairs": "Scări De Cărămizi Mici De Diorit", - "block.create.small_diorite_brick_wall": "Zid De Cărămizi Mici De Diorit", - "block.create.small_diorite_bricks": "Cărămizi Mici De Diorit", - "block.create.small_dripstone_brick_slab": "Lespede De Cărămizi Mici De Dripstone", - "block.create.small_dripstone_brick_stairs": "Scări De Cărămizi Mici De Dripstone", - "block.create.small_dripstone_brick_wall": "Zid De Cărămizi Mici De Dripstone", - "block.create.small_dripstone_bricks": "Cărămizi Mici De Dripstone", - "block.create.small_granite_brick_slab": "Lespede De Cărămizi Mici De Granit", - "block.create.small_granite_brick_stairs": "Scări De Cărămizi Mici De Granit", - "block.create.small_granite_brick_wall": "Zid De Cărămizi Mici De Granit", - "block.create.small_granite_bricks": "Cărămizi Mici De Granit", - "block.create.small_limestone_brick_slab": "Lespede De Cărămizi Mici De Calcar", - "block.create.small_limestone_brick_stairs": "Scări De Cărămizi Mici De Calcar", - "block.create.small_limestone_brick_wall": "Zid De Cărămizi Mici De Calcar", - "block.create.small_limestone_bricks": "Cărămizi Mici De Calcar", - "block.create.small_ochrum_brick_slab": "Lespede De Cărămizi Mici De Ochrum", - "block.create.small_ochrum_brick_stairs": "Scări De Cărămizi Mici De Ochrum", - "block.create.small_ochrum_brick_wall": "Zid De Cărămizi Mici De Ochrum", - "block.create.small_ochrum_bricks": "Cărămizi Mici De Ochrum", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "Lespede De Cărămizi Mici De Scorchia", - "block.create.small_scorchia_brick_stairs": "Scări De Cărămizi Mici De Scorchia", - "block.create.small_scorchia_brick_wall": "Zid De Cărămizi Mici De Scorchia", - "block.create.small_scorchia_bricks": "Cărămizi Mici De Scorchia", - "block.create.small_scoria_brick_slab": "Lespede De Cărămizi Mici De Scoria", - "block.create.small_scoria_brick_stairs": "Scări De Cărămizi Mici De Scoria", - "block.create.small_scoria_brick_wall": "Zid De Cărămizi Mici De Scoria", - "block.create.small_scoria_bricks": "Cărămizi Mici De Scoria", - "block.create.small_tuff_brick_slab": "Lespede De Cărămizi Mici De Tuf", - "block.create.small_tuff_brick_stairs": "Scări De Cărămizi Mici De Tuf", - "block.create.small_tuff_brick_wall": "Zid De Cărămizi Mici De Tuf", - "block.create.small_tuff_bricks": "Cărămizi Mici De Tuf", - "block.create.small_veridium_brick_slab": "Lespede De Cărămizi Mici De Veridium", - "block.create.small_veridium_brick_stairs": "Scări De Cărămizi Mici De Veridium", - "block.create.small_veridium_brick_wall": "Zid De Cărămizi Mici De Veridium", - "block.create.small_veridium_bricks": "Cărămizi Mici De Veridium", - "block.create.smart_chute": "Tobogan Inteligent", - "block.create.smart_fluid_pipe": "Conductă De Fluide Inteligentă", - "block.create.speedometer": "Vitezometru", - "block.create.spout": "Duză", - "block.create.spruce_window": "Sticlă De Molid", - "block.create.spruce_window_pane": "Geam De Molid", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "Abțipild", - "block.create.sticky_mechanical_piston": "Piston Mecanic Lipicios", - "block.create.stockpile_switch": "Comutator De Depozitare", - "block.create.stressometer": "Stresometru", - "block.create.tiled_glass": "Sticlă De Țiglă", - "block.create.tiled_glass_pane": "Fereastră De Țiglă", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "Coloană De Tuf", - "block.create.turntable": "Placă Turnantă", - "block.create.veridium": "Veridium", - "block.create.veridium_pillar": "Coloană De Veridium", - "block.create.vertical_framed_glass": "Sticlă Înrămată Verticală", - "block.create.vertical_framed_glass_pane": "Geam Înrămat Vertical", - "block.create.warped_window": "Sticlă Deformată", - "block.create.warped_window_pane": "Geam Deformat", - "block.create.water_wheel": "Roată De Apă", - "block.create.waxed_copper_shingle_slab": "Lespede De Șindrilă De Cupru Ceruit", - "block.create.waxed_copper_shingle_stairs": "Scări De Șindrilă De Cupru Ceruit", - "block.create.waxed_copper_shingles": "Șindrile De Cupru Ceruite", - "block.create.waxed_copper_tile_slab": "Lespede De Țiglă De Cupru Ceruit", - "block.create.waxed_copper_tile_stairs": "Scări De Țiglă De Cupru Ceruit", - "block.create.waxed_copper_tiles": "Țigle De Cupru Ceruită", - "block.create.waxed_exposed_copper_shingle_slab": "Lespede De Șindrilă De Cupru Ceruit Expusă", - "block.create.waxed_exposed_copper_shingle_stairs": "Scări De Șindrilă De Cupru Ceruit Expuse", - "block.create.waxed_exposed_copper_shingles": "Șindrilă De Cupru Ceruit Expusă", - "block.create.waxed_exposed_copper_tile_slab": "Lespede De Țiglă De Cupru Ceruit Expusă", - "block.create.waxed_exposed_copper_tile_stairs": "Scări De Țiglă De Cupru Ceruit Expuse", - "block.create.waxed_exposed_copper_tiles": "Țiglă De Cupru Ceruit Expusă", - "block.create.waxed_oxidized_copper_shingle_slab": "Lespede De Șindrilă De Cupru Ceruit Oxidat", - "block.create.waxed_oxidized_copper_shingle_stairs": "Scări De Șindrilă De Cupru Ceruit Oxidat", - "block.create.waxed_oxidized_copper_shingles": "Șindrilă De Cupru Ceruit Oxidat", - "block.create.waxed_oxidized_copper_tile_slab": "Lespede De Țiglă De Cupru Ceruit Oxidat", - "block.create.waxed_oxidized_copper_tile_stairs": "Scări De Țiglă De Cupru Ceruit Oxidat", - "block.create.waxed_oxidized_copper_tiles": "Țiglă De Cupru Ceruit Oxidat", - "block.create.waxed_weathered_copper_shingle_slab": "Lespede De Șindrilă De Cupru Ceruit Erodat", - "block.create.waxed_weathered_copper_shingle_stairs": "Scări De Șindrilă De Cupru Ceruit Erodat", - "block.create.waxed_weathered_copper_shingles": "Șindrilă De Cupru Ceruit Erodat", - "block.create.waxed_weathered_copper_tile_slab": "Lespede De Țiglă De Cupru Ceruit Erodat", - "block.create.waxed_weathered_copper_tile_stairs": "Scări De Țiglă De Cupru Ceruit Erodat", - "block.create.waxed_weathered_copper_tiles": "Țiglă De Cupru Ceruit Erodat", - "block.create.weathered_copper_shingle_slab": "Lespede De Șindrilă De Cupru Erodat", - "block.create.weathered_copper_shingle_stairs": "Scări De Șindrilă De Cupru Erodat", - "block.create.weathered_copper_shingles": "Șindrilă De Cupru Erodat", - "block.create.weathered_copper_tile_slab": "Lespede De Țiglă De Cupru Erodat", - "block.create.weathered_copper_tile_stairs": "Scări De Țiglă De Cupru Erodat", - "block.create.weathered_copper_tiles": "Țiglă De Cupru Erodat", - "block.create.weighted_ejector": "Ejector Ponderat", - "block.create.white_nixie_tube": "Tub Nixie Alb", - "block.create.white_sail": "Velă Albă", - "block.create.white_seat": "Scaun Alb", - "block.create.white_toolbox": "Trusă De Scule Albă", - "block.create.white_valve_handle": "Mâner De Supapă Alb", - "block.create.windmill_bearing": "Rulment De Moară De Vânt", - "block.create.wooden_bracket": "Brachetă De Lemn", - "block.create.yellow_nixie_tube": "Tub Nixie Galben", - "block.create.yellow_sail": "Velă Galbenă", - "block.create.yellow_seat": "Scaun Galben", - "block.create.yellow_toolbox": "Trusă De Scule Galbenă", - "block.create.yellow_valve_handle": "Mâner De Supapă Galben", - "block.create.zinc_block": "Bloc De Zinc", - "block.create.zinc_ore": "Minereu De Zinc", - - "enchantment.create.capacity": "Capacitate", - "enchantment.create.potato_recovery": "Recuperare Cartofi", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "Invenție", - "entity.create.crafting_blueprint": "Plan De Meșteșugărit", - "entity.create.gantry_contraption": "Invenție De Portal", - "entity.create.potato_projectile": "Proiectil De Cartof", - "entity.create.seat": "Scaun", - "entity.create.stationary_contraption": "Invenție Staționară", - "entity.create.super_glue": "Super-Glue", - - "fluid.create.potion": "Poțiune", - "fluid.create.tea": "Ceaiul Constructorului", - - "item.create.andesite_alloy": "Aliaj De Andezit", - "item.create.attribute_filter": "Filtru De Atribut", - "item.create.bar_of_chocolate": "Baton De Ciocolată", - "item.create.belt_connector": "Bandă Mecanică", - "item.create.blaze_cake": "Tort De Dogoreală", - "item.create.blaze_cake_base": "Bază De Tort De Dogoreală", - "item.create.brass_hand": "Mână De Alamă", - "item.create.brass_ingot": "Lingou De Alamă", - "item.create.brass_nugget": "Pepită De Alamă", - "item.create.brass_sheet": "Placă De Alamă", - "item.create.builders_tea": "Ceaiul Constructorului", - "item.create.chest_minecart_contraption": "Invenție De Cufăr În Vagonet", - "item.create.chocolate_bucket": "Găleată De Ciocolată", - "item.create.chocolate_glazed_berries": "Fructe De Pădure Glazurate Cu Ciocolată", - "item.create.chromatic_compound": "Compus Cromatic", - "item.create.cinder_flour": "Făină De Zgură", - "item.create.copper_backtank": "Backtank De Cupru", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Pepită De Cupru", - "item.create.copper_sheet": "Placă De Cupru", - "item.create.crafter_slot_cover": "Capac De Meșter Mecanic", - "item.create.crafting_blueprint": "Plan De Meșteșugărit", - "item.create.creative_blaze_cake": "Tort De Dogoreală Creativ", - "item.create.crushed_aluminum_ore": "Minereu De Aluminium Zdrobit", - "item.create.crushed_copper_ore": "Minereu De Cupru Zdrobit", - "item.create.crushed_gold_ore": "Minereu De Aur Zdrobit", - "item.create.crushed_iron_ore": "Minereu De Fier Zdrobit", - "item.create.crushed_lead_ore": "Minereu De Plumb Zdrobit", - "item.create.crushed_nickel_ore": "Minereu De Nichel Zdrobit", - "item.create.crushed_osmium_ore": "Minereu De Osmium Zdrobit", - "item.create.crushed_platinum_ore": "Minereu De Platinum Zdrobit", - "item.create.crushed_quicksilver_ore": "Minereu De Mercur Zdrobit", - "item.create.crushed_silver_ore": "Minereu De Argint Zdrobit", - "item.create.crushed_tin_ore": "Minereu De Staniu Zdrobit", - "item.create.crushed_uranium_ore": "Minereu De Uraniu Zdrobit", - "item.create.crushed_zinc_ore": "Minereu De Zinc Zdrobit", - "item.create.diving_boots": "Bocanci De Scufundare", - "item.create.diving_helmet": "Cască De Scufundare", - "item.create.dough": "Aluat", - "item.create.electron_tube": "Tub De Electroni", - "item.create.empty_blaze_burner": "Arzător De Dogoreală Gol", - "item.create.empty_schematic": "Schemă Goală", - "item.create.experience_nugget": "Pepită De Experiență", - "item.create.extendo_grip": "Mâner Extendo", - "item.create.filter": "Filtru", - "item.create.furnace_minecart_contraption": "Invenție De Cuptor În Vagonet", - "item.create.goggles": "Ochelarii Inginerului", - "item.create.golden_sheet": "Placă De Aur", - "item.create.handheld_worldshaper": "Modelator De Lume Creativ", - "item.create.honey_bucket": "Găleată De Miere", - "item.create.honeyed_apple": "Măr Cu Miere", - "item.create.incomplete_precision_mechanism": "Mecanism De Precizie Incomplet", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "Placă De Fier", - "item.create.linked_controller": "Controlor Legat", - "item.create.minecart_contraption": "Invenție De Vagonet", - "item.create.minecart_coupling": "Cuplare De Vagonet", - "item.create.polished_rose_quartz": "Cuarț Roz Șlefuit", - "item.create.potato_cannon": "Tun De Cartofi", - "item.create.powdered_obsidian": "Praf De Obsidian", - "item.create.precision_mechanism": "Mecanism De Precizie", - "item.create.propeller": "Elice", - "item.create.raw_zinc": "Zinc Brut", - "item.create.red_sand_paper": "Șmirghel Roșu", - "item.create.refined_radiance": "Radianță Rafinată", - "item.create.rose_quartz": "Cuarț Roz", - "item.create.sand_paper": "Șmirghel", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Schemă", - "item.create.schematic_and_quill": "Schemă Și Condei", - "item.create.shadow_steel": "Oțel De Umbră", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "Super-Lipici", - "item.create.sweet_roll": "Rolă Dulce", - "item.create.tree_fertilizer": "Fertilizator De Copaci", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Cutie De Viteze Verticală", - "item.create.wand_of_symmetry": "Baghetă De Simetrie", - "item.create.wheat_flour": "Făină De Grâu", - "item.create.whisk": "Tel", - "item.create.wrench": "Cheie", - "item.create.zinc_ingot": "Lingou De Zinc", - "item.create.zinc_nugget": "Pepită De Zinc", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Bine ai venit pe Create!", - "advancement.create.root.desc": "E timpul sa începi sa construiesti invenții uimitoare!", - "advancement.create.andesite_alloy": "Aliterații Din Belșug", - "advancement.create.andesite_alloy.desc": "Materialele Create-ului au nume ciudate, Aliajul Din Andezit este unul dintre ele.", - "advancement.create.andesite_casing": "Epoca Andezitului", - "advancement.create.andesite_casing.desc": "Folosește niște Aliaj De Andezit și Lemn ca să creezi o Carcasă de bază.", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "Conducere de Alge", - "advancement.create.belt.desc": "Conectează două rotoare cu o Bandă Mecanică.", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "Rostogolind în Jos", - "advancement.create.chute.desc": "Plasează un Tobogan, partea verticală echivalentă a unei Benzi.", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "Valorificând Hidrualica", - "advancement.create.water_wheel.desc": "Plasează o Roată De Apă și încearcă să o faci să se rotească!", - "advancement.create.windmill": "O Briză Blândă", - "advancement.create.windmill.desc": "Asamblează o moară de vânt.", - "advancement.create.shifting_gears": "Schimbând Vitezele", - "advancement.create.shifting_gears.desc": "Conectează o Roată Dințată Mare cu o Roată Dințată Mică, permițându-ți să schimbi viteza invenției.", - "advancement.create.millstone": "Zdrobitor de buzunar", - "advancement.create.millstone.desc": "Plasează și alimentează o Moară De Piatră.", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "Dar Cât De Stresat, Mai Exact?", - "advancement.create.stressometer.desc": "Plasează și alimentează un Stresometru. Uită-te la el prin Ochelari ca să îi citești valoarea exactă.", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "Papagalii și Aripile", - "advancement.create.belt_funnel_kiss.desc": "Fă două săruturi de Pâlnii montate pe Bandă.", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "Epoca de cupru", - "advancement.create.copper_casing.desc": "Folosește niște and Wood to create some Copper Casings.", - "advancement.create.spout": "Splosh", - "advancement.create.spout.desc": "Privește un obiect de fluid fiind umplut folosind o Duză.", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "Spion De Flux", - "advancement.create.glass_pipe.desc": "Privește un fluid propagându-se printr-o Conductă De Fluide De Sticlă. Conducte De Fluide Drepte devin de sticlă când o cheie este folosită pe ele.", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "Vărsare Industrială", - "advancement.create.hose_pulley.desc": "Coboară un Scripete De Furtun și privește-l scurgând sau umplând un corp de fluid.", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "Aliaje reale", - "advancement.create.brass.desc": "Folosește Cupru Zdrobit și Zinc Zdrobit ca să creezi niște Alamă.", - "advancement.create.brass_casing": "Epoca Alamei", - "advancement.create.brass_casing.desc": "Folosește noua Alamă obținută și niște Lemn ca să creezo o Carcasă mai avansată.", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "Împinge, Plasează, și Atacă", - "advancement.create.deployer.desc": "Plasează și alimentează un Deployer, reflecția ta perfectă.", - "advancement.create.precision_mechanism": "Curiozități Complexe", - "advancement.create.precision_mechanism.desc": "Asamblează un Mecanism De Precizie.", - "advancement.create.speed_controller": "Inginerii Îl Urăsc!", - "advancement.create.speed_controller.desc": "Plasează un Controlor De Viteză De Rotație, dispozitivul fundamental pentru schimbarea vitezei.", - "advancement.create.mechanical_arm": "Mâini Ocupate!", - "advancement.create.mechanical_arm.desc": "Fabrică un Braț Mecanic, selectează intrarea și ieșirea, Plasează-l jos și dă-i putere; apoi privește cum face toată treaba pentru tine.", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "O Pereche de Giganți", - "advancement.create.crushing_wheel.desc": "Creează niște Roți De Zdrobit ca să spargi mai multe materiale mai eficient.", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "Ora Invențiilor", - "advancement.create.clockwork_bearing.desc": "Asamblează o structură montată pe un Rulment De Ceasornic.", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "Fwoomp!", - "advancement.create.potato_cannon.desc": "Înfrânge un inamic cu Tunul tău De Cartofi.", - "advancement.create.extendo_grip": "Boioioing!", - "advancement.create.extendo_grip.desc": "Fă rost de un Mâner Extendo.", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "Arzător-o-Tron", - "advancement.create.arm_blaze_burner.desc": "Instructează un Braț Mecanic să hrănească Arzătorul tău De Dogoreală.", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "Organiz-o-Tron", - "advancement.create.arm_many_targets.desc": "Programează un Braț Mecanic cu zece sau mai multe locații de ieșire.", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "Bate-o, Bro!", - "advancement.create.fist_bump.desc": "Fă două Deployere să bată pumnul.", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "Cântă-mi melodia mea tematică!", - "advancement.create.musical_arm.desc": "Privește un Braț Mecanic operând Tonomatul tău.", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Blocurile De Construit Create", - - "death.attack.create.crush": "%1$s a fost procesat de către Roți De Zdrobit", - "death.attack.create.crush.player": "%1$s a fost aruncat în Roți De Zdrobit de către %2$s", - "death.attack.create.fan_fire": "%1$s a fost afumat de către un Ventilator Încapsulat", - "death.attack.create.fan_fire.player": "%1$s a fost aruncat într-un afumator de către %2$s", - "death.attack.create.fan_lava": "%1$s a fost incinerat de către un Ventilator Încapsulat", - "death.attack.create.fan_lava.player": "%1$s a fost aruncat într-un topitor de către %2$s", - "death.attack.create.mechanical_drill": "%1$s a fost tras în țeapă de către un Burghiu Mecanic", - "death.attack.create.mechanical_drill.player": "%1$s a fost aruncat în fața unui Burghiu de către %2$s", - "death.attack.create.mechanical_saw": "%1$s a fost tăiat în jumătate de către un Ferăstrău Mecanic", - "death.attack.create.mechanical_saw.player": "%1$s a fost aruncat într-un Ferăstrău de către %2$s", - "death.attack.create.potato_cannon": "%1$s a fost împușcat de către Tunul De Cartofi al lui %2$s", - "death.attack.create.potato_cannon.item": "%1$s a fost împușcat de către %2$s folosind %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s a fost aruncat în aer de către un ceas cucu manipulat", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s a fost aruncat în aer de către un ceas cucu manipulat", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "un Deployer necinstit", - "create.block.cart_assembler.invalid": "Plasează Asamblatorul tău De Vagonet pe un bloc de șină", - - "create.menu.return": "Înapoi la Meniu", - "create.menu.configure": "Configurează...", - "create.menu.ponder_index": "Indecele de Chibzuire", - "create.menu.only_ingame": "Valabil în Meniul Jocului", - "create.menu.report_bugs": "Raportează Probleme", - "create.menu.support": "Susține-ne", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Strivire", - "create.recipe.milling": "Frezare", - "create.recipe.fan_washing": "Spălare În Vrac", - "create.recipe.fan_washing.fan": "Ventilator în spatele unei Ape Curgătoare", - "create.recipe.fan_smoking": "Afumare În Vrac", - "create.recipe.fan_smoking.fan": "Ventilator în spatele unui Foc", - "create.recipe.fan_haunting": "Bântuire În Vrac", - "create.recipe.fan_haunting.fan": "Ventilator în spatele unui Foc de Suflete", - "create.recipe.fan_blasting": "Topire În Vrac", - "create.recipe.fan_blasting.fan": "Ventilator în spatele Lavei", - "create.recipe.pressing": "Presare", - "create.recipe.mixing": "Amestecare", - "create.recipe.deploying": "Montare", - "create.recipe.automatic_shapeless": "Meșteșugărit Fără Formă Automatic", - "create.recipe.automatic_brewing": "Preparare Automată", - "create.recipe.packing": "Compactare", - "create.recipe.automatic_packing": "Compactare Automată", - "create.recipe.sawing": "Tăiere Prin Ferăstrău", - "create.recipe.mechanical_crafting": "Lucrare Mecanică", - "create.recipe.automatic_shaped": "Lucrare Profilată Automată", - "create.recipe.block_cutting": "Tăiere De Blocuri", - "create.recipe.wood_cutting": "Tăiere De Lemne", - "create.recipe.sandpaper_polishing": "Șlefuire Prin Șmirghel", - "create.recipe.mystery_conversion": "Conversie Misterioasă", - "create.recipe.spout_filling": "Umplere prin Duză", - "create.recipe.draining": "Drenaj De Obiecte", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "Asamblare Secvențială", - "create.recipe.assembly.next": "Următorul: %1$s", - "create.recipe.assembly.step": "Pasul %1$s:", - "create.recipe.assembly.progress": "Progres: %1$s/%2$s", - "create.recipe.assembly.pressing": "Procesare În Presă", - "create.recipe.assembly.spout_filling_fluid": "Duză %1$s", - "create.recipe.assembly.deploying_item": "Instalează %1$s", - "create.recipe.assembly.cutting": "Taie Cu Ferăstrău", - "create.recipe.assembly.repeat": "Repetă Secvența De %1$s Ori", - "create.recipe.assembly.junk": "Salvare Aleatorie", - "create.recipe.processing.chance": "Șansă de %1$s%%", - "create.recipe.deploying.not_consumed": "Neconsumat", - "create.recipe.heat_requirement.none": "Nu Necesită Încălzire", - "create.recipe.heat_requirement.heated": "Încălzit", - "create.recipe.heat_requirement.superheated": "Super-Încălzit", - - "create.generic.range": "Distanță", - "create.generic.radius": "Radius", - "create.generic.width": "Lățime", - "create.generic.height": "Înălțime", - "create.generic.length": "Lungime", - "create.generic.speed": "Viteză", - "create.generic.delay": "Întârziere", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Ticuri", - "create.generic.unit.seconds": "Secunde", - "create.generic.unit.minutes": "Minute", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "În sensul acelor de ceasornic", - "create.generic.counter_clockwise": "În sensul invers acelor de ceasornic", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Derulează", - "create.action.confirm": "Confirmă", - "create.action.abort": "Anulează", - "create.action.saveToFile": "Salvează", - "create.action.discard": "Renunță", - - "create.keyinfo.toolmenu": "Centrează Interfața Schemei", - "create.keyinfo.toolbelt": "Acesează Trusele De Scule Din Apropiere", - "create.keyinfo.scrollup": "Simulează Roată Mouse Sus (inworld)", - "create.keyinfo.scrolldown": "Simulează Roată Mouse Jos (inworld)", - - "create.gui.scrollInput.defaultTitle": "Alege O Opțiune:", - "create.gui.scrollInput.scrollToModify": "Derulează pentru a Modifica", - "create.gui.scrollInput.scrollToAdjustAmount": "Derulează pentru a Regla Cantitatea", - "create.gui.scrollInput.scrollToSelect": "Derulează pentru a Selecta", - "create.gui.scrollInput.shiftScrollsFaster": "Shift pentru a Derula Mai Rapid", - "create.gui.toolmenu.focusKey": "Ține Apăsat [%1$s] pentru a Centra", - "create.gui.toolmenu.cycle": "[SCROLL] pentru a Circula", - - "create.toolbox.unequip": "Dezechipează: %1$s", - "create.toolbox.outOfRange": "Trusa De Scule al obiectului ținut nu este în Rază", - "create.toolbox.detach": "Oprește urmărirea și păstrează obiectul", - "create.toolbox.depositAll": "Returnează obiectele la Truse De Scule în apropiere", - "create.toolbox.depositBox": "Returnează obiectele la Trusa De Scule", - - "create.gui.symmetryWand.mirrorType": "Oglindă", - "create.gui.symmetryWand.orientation": "Orientare", - - "create.symmetry.mirror.plane": "Oglindește odată", - "create.symmetry.mirror.doublePlane": "Dreptunghiular", - "create.symmetry.mirror.triplePlane": "Octagonal", - - "create.orientation.orthogonal": "Ortogonal", - "create.orientation.diagonal": "Diagonal", - "create.orientation.horizontal": "Orizontal", - "create.orientation.alongZ": "De-a lungul axei Z", - "create.orientation.alongX": "De-a lungul axei X", - - "create.gui.terrainzapper.title": "Blockzapper de mână", - "create.gui.terrainzapper.searchDiagonal": "Urmărește Diagonalele", - "create.gui.terrainzapper.searchFuzzy": "Ignoră Marginile Materialelor", - "create.gui.terrainzapper.patternSection": "Tipar", - "create.gui.terrainzapper.pattern.solid": "Solid", - "create.gui.terrainzapper.pattern.checkered": "Tablă De Șah", - "create.gui.terrainzapper.pattern.inversecheckered": "Tablă De Șah Inversată", - "create.gui.terrainzapper.pattern.chance25": "Rostogolire 25%", - "create.gui.terrainzapper.pattern.chance50": "Rostogolire 50%", - "create.gui.terrainzapper.pattern.chance75": "Rostogolire 75%", - "create.gui.terrainzapper.placement": "Plasare", - "create.gui.terrainzapper.placement.merged": "Combinat", - "create.gui.terrainzapper.placement.attached": "Atașat", - "create.gui.terrainzapper.placement.inserted": "Inserat", - "create.gui.terrainzapper.brush": "Pensulă", - "create.gui.terrainzapper.brush.cuboid": "Cuboid", - "create.gui.terrainzapper.brush.sphere": "Sferă", - "create.gui.terrainzapper.brush.cylinder": "Cilindru", - "create.gui.terrainzapper.brush.surface": "Suprafață", - "create.gui.terrainzapper.brush.cluster": "Roi", - "create.gui.terrainzapper.tool": "Unealtă", - "create.gui.terrainzapper.tool.fill": "Umple", - "create.gui.terrainzapper.tool.place": "Plasează", - "create.gui.terrainzapper.tool.replace": "Înlocuiește", - "create.gui.terrainzapper.tool.clear": "Curăță", - "create.gui.terrainzapper.tool.overlay": "Acoperire", - "create.gui.terrainzapper.tool.flatten": "Nivelează", - - "create.terrainzapper.shiftRightClickToSet": "Shift-Click-Dreapta pentru a Selecta o Formă", - "create.terrainzapper.usingBlock": "Folosing: %1$s", - "create.terrainzapper.leftClickToSet": "Click-Stânga pe un Bloc pentru a seta Materialul", - - "create.minecart_coupling.two_couplings_max": "Vagonetele nu pot avea nu mai mult de două cuplaje fiecare", - "create.minecart_coupling.unloaded": "Părți din trenul tău par să fie în chunkuri neîncărcate", - "create.minecart_coupling.no_loops": "Cuplajele nu pot forma o buclă", - "create.minecart_coupling.removed": "Eliminate toate cuplajele din vagonet", - "create.minecart_coupling.too_far": "Vagonetele sunt prea departe unul de celălalt", - - "create.contraptions.movement_mode": "Mod de Mișcare", - "create.contraptions.movement_mode.move_place": "Mereu Plasează când e Oprit", - "create.contraptions.movement_mode.move_place_returned": "Plasează doar în Poziția de Început", - "create.contraptions.movement_mode.move_never_place": "Plasează doar când Ancora e Distrusă", - "create.contraptions.movement_mode.rotate_place": "Mereu Plasează când e Oprit", - "create.contraptions.movement_mode.rotate_place_returned": "Plasează doar aproape de Unghiul Inițial", - "create.contraptions.movement_mode.rotate_never_place": "Plasează doar când Ancora e Distrusă", - "create.contraptions.cart_movement_mode": "Mod de Mișcare Vagonet", - "create.contraptions.cart_movement_mode.rotate": "Mereu stă cu fața spre mișcare", - "create.contraptions.cart_movement_mode.rotate_paused": "Oprește Actorii când se rotește", - "create.contraptions.cart_movement_mode.rotation_locked": "Blochează Rotația", - "create.contraptions.windmill.rotation_direction": "Direcție De Rotație", - "create.contraptions.clockwork.clock_hands": "Ace de Ceas", - "create.contraptions.clockwork.hour_first": "Acul orei primul", - "create.contraptions.clockwork.minute_first": "Acul minutului primul", - "create.contraptions.clockwork.hour_first_24": "Acul de 24 de ore primul", - - "create.logistics.filter": "Filtru", - "create.logistics.recipe_filter": "Filtru de Rețetă", - "create.logistics.fluid_filter": "Filtru de Fluid", - "create.logistics.firstFrequency": "Frecvența #1", - "create.logistics.secondFrequency": "Frecvența #2", - "create.logistics.filter.apply": "Filtru aplicat la %1$s.", - "create.logistics.filter.apply_click_again": "Filtru aplicat la %1$s, click din nou pentru a copia cantitatea.", - "create.logistics.filter.apply_count": "Număr de extracție applicat la filtru.", - - "create.gui.goggles.generator_stats": "Statistici Generator:", - "create.gui.goggles.kinetic_stats": "Statistici Cinetice:", - "create.gui.goggles.at_current_speed": "la viteza curentă", - "create.gui.goggles.pole_length": "Lungimea Stâlpului:", - "create.gui.goggles.fluid_container": "Informașii Container de Fluid:", - "create.gui.goggles.fluid_container.capacity": "Capacitate: ", - "create.gui.assembly.exception": "Această Invenție a fost incapabiă să se asambleze:", - "create.gui.assembly.exception.unmovableBlock": "Bloc Nemișcabil (%4$s) la [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Blocul la [%1$s,%2$s,%3$s] nu a fost într-un chunk încărcat", - "create.gui.assembly.exception.structureTooLarge": "Sunt prea multe Blocuri incluse în invenție.\nMaximul configurat este: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Sunt prea multe Brațe de extensie atașat la acest Piston.\nMaximul configurat este: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Pistonului îi lipsesc niște Brațe de extensie", - "create.gui.assembly.exception.not_enough_sails": "Structura atașată nu include destule blocuri de pânze: %1$s\nUn minim de %2$s e necesar", - "create.gui.gauge.info_header": "Informație Gabarit:", - "create.gui.speedometer.title": "Viteză de Rotație", - "create.gui.stressometer.title": "Rețea de Stres", - "create.gui.stressometer.capacity": "Capacitate Rămasă", - "create.gui.stressometer.overstressed": "Suprasolicitat", - "create.gui.stressometer.no_rotation": "Fără Rotație", - "create.gui.contraptions.not_fast_enough": "Se pare că acest %1$s _nu_ se rotește cu _destulă_ _viteză_.", - "create.gui.contraptions.network_overstressed": "Se pare că această invenție este _suprasolicitată_. Adaugă mai multe surse sau _încetinește_ componentele cu un _impact de stres_ mare.", - "create.gui.adjustable_crate.title": "Ladă Ajustabilă", - "create.gui.adjustable_crate.storageSpace": "Spațiu de Stocare", - "create.gui.stockpile_switch.title": "Comutator de Depozitare", - "create.gui.stockpile_switch.invert_signal": "Inversează Semnalul", - "create.gui.stockpile_switch.move_to_lower_at": "Mută pe banda iferioară la %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Mută pe banda superioară la %1$s%%", - "create.gui.sequenced_gearshift.title": "Schimbător De Viteze Secvențial", - "create.gui.sequenced_gearshift.instruction": "Instrucțiune", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Înroarce după unghi", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Întoarce", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Unghi", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Întoarce pentru a muta Piston/Scripete/Portal", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Piston", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distanță", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Întârziere Programată", - "create.gui.sequenced_gearshift.instruction.delay": "Întârziere", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Durată", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Sfârșit", - "create.gui.sequenced_gearshift.instruction.end": "Sfârșit", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Așteaptă noi Pulsuri de Redstone", - "create.gui.sequenced_gearshift.instruction.await": "Așteaptă", - "create.gui.sequenced_gearshift.speed": "Viteză, Direcție", - "create.gui.sequenced_gearshift.speed.forward": "Viteză de Intrare, Înainte", - "create.gui.sequenced_gearshift.speed.forward_fast": "Viteză Dublă, Înainte", - "create.gui.sequenced_gearshift.speed.back": "Viteză de Intrare, Înapoi", - "create.gui.sequenced_gearshift.speed.back_fast": "Viteză Dublă, Înapoi", - - "create.schematicAndQuill.dimensions": "Mărime Schemă: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Prima poziție setată.", - "create.schematicAndQuill.secondPos": "A doua poziție setată.", - "create.schematicAndQuill.noTarget": "Ține apasat [Ctrl] pentru a selecta Blocuri de Aer.", - "create.schematicAndQuill.abort": "Selecție eliminată.", - "create.schematicAndQuill.title": "Nume Schemă:", - "create.schematicAndQuill.convert": "Salvează și Încarcă Imediat", - "create.schematicAndQuill.fallbackName": "Schema Mea", - "create.schematicAndQuill.saved": "Salvat ca %1$s", - - "create.schematic.invalid": "[!] Obiect Invalid - În schimb, folosește Masa De Schemă", - "create.schematic.position": "Poziție", - "create.schematic.rotation": "Rotație", - "create.schematic.rotation.none": "Niciuna", - "create.schematic.rotation.cw90": "În sensul acelor de ceasornic 90", - "create.schematic.rotation.cw180": "În sensul acelor de ceasornic 180", - "create.schematic.rotation.cw270": "În sensul acelor de ceasornic 270", - "create.schematic.mirror": "Oglinește", - "create.schematic.mirror.none": "Niciuna", - "create.schematic.mirror.frontBack": "Față-Spate", - "create.schematic.mirror.leftRight": "Stânga-Dreapta", - "create.schematic.tool.deploy": "Poziție", - "create.schematic.tool.move": "Mișcă XZ", - "create.schematic.tool.movey": "Mișcă Y", - "create.schematic.tool.rotate": "Rotește", - "create.schematic.tool.print": "Printează", - "create.schematic.tool.flip": "Oglindește", - "create.schematic.tool.deploy.description.0": "Mișcă structura la o locație.", - "create.schematic.tool.deploy.description.1": "Click-Dreapa pe sol pentru a o plasa.", - "create.schematic.tool.deploy.description.2": "Ține apăsat [Ctrl] pentru a selecta la o distanță fixă.", - "create.schematic.tool.deploy.description.3": "[Ctrl]-Scroll pentru a schimba distanța.", - "create.schematic.tool.move.description.0": "Deplasează Schema Orizontal.", - "create.schematic.tool.move.description.1": "Arată spre Schemă și apasă [CTRL]-Scroll ca să îl deplasezi.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Deplasează Schema Vertical.", - "create.schematic.tool.movey.description.1": "[CTRL]-Scroll ca să îl miști sus/jos.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Rotește Schema în jurul centrului sale.", - "create.schematic.tool.rotate.description.1": "[CTRL]-Scroll ca să rotești cu 90 de Grade.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Plasează structura instant în lume.", - "create.schematic.tool.print.description.1": "[Click-Dreapta] pentru a confirma palsarea la locașia curentă.", - "create.schematic.tool.print.description.2": "Această unealtă este doar pentru Modul Creativ.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Întoarce Schema de-a lungul feței pe care o selectezi.", - "create.schematic.tool.flip.description.1": "Arată spre Schemă și apasă [CTRL]-Scroll ca să o întorci.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Se Sincronizează...", - "create.schematics.uploadTooLarge": "Schemal ta depășește limitele specificate de către server.", - "create.schematics.maxAllowedSize": "Mărimea maximă a fișierului de schemă permisă este:", - - "create.gui.schematicTable.refresh": "Reîmprospătează Fișierele", - "create.gui.schematicTable.open_folder": "Deschide Folderul", - "create.gui.schematicTable.title": "Masă De Schemă", - "create.gui.schematicTable.availableSchematics": "Scheme Disponibile", - "create.gui.schematicTable.noSchematics": "Nicio Schemă Salvată", - "create.gui.schematicTable.uploading": "Se Încarcă...", - "create.gui.schematicTable.finished": "Încărcare Finalizată!", - "create.gui.schematicannon.title": "Tun De Schemă", - "create.gui.schematicannon.listPrinter": "Imprimantă de listă de verificare", - "create.gui.schematicannon.gunpowderLevel": "Praf de pușcă la %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Împușcături rămase: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "Cu backup: %1$s", - "create.gui.schematicannon.optionEnabled": "În prezent Activat", - "create.gui.schematicannon.optionDisabled": "În prezent Dezactivat", - "create.gui.schematicannon.showOptions": "Afișează Setări Imprimantă", - "create.gui.schematicannon.option.dontReplaceSolid": "Nu Înlocui Blocuri Solide", - "create.gui.schematicannon.option.replaceWithSolid": "Înlocuiește Solid cu Solid", - "create.gui.schematicannon.option.replaceWithAny": "Înlocuiește Solid cu Orice", - "create.gui.schematicannon.option.replaceWithEmpty": "Înlocuiește Solid cu Gol", - "create.gui.schematicannon.option.skipMissing": "Ocolește Blocuri lipsă", - "create.gui.schematicannon.option.skipTileEntities": "Protejează Entități", - "create.gui.schematicannon.slot.gunpowder": "Adaugă praf de pușcă pentru a alimenta tunul", - "create.gui.schematicannon.slot.listPrinter": "Plasează cărți aici pentru a imprima o listă de verificare pentru Schema ta", - "create.gui.schematicannon.slot.schematic": "Adaugă-ti Schema aici. Asigură-te că este instalată la o locație specifică.", - "create.gui.schematicannon.option.skipMissing.description": "Dacă tunul nu poate găsi un bloc necesar pentru plasare, va continua la locația următoare.", - "create.gui.schematicannon.option.skipTileEntities.description": "Tunul va evita să înlocuiască blocuri care țin date, cum ar fi Cuferele..", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Tunul nu va înlocui niciodată orice bloc Solid în zona lui de locru, doar non-Solid și Aer.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Tunul va înlocui daor blocuri Solide în zona lui de lucru dacă Schema conține un Bloc solid la acea Locație.", - "create.gui.schematicannon.option.replaceWithAny.description": "Tunul va înlocui blocuri Solide în zona lui de lucru dacă Schema conține orice Bloc la acea Locație.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Tunul va elibera toate blocurile în zona lui de lucru, inclusiv cele înlocuite de Aer.", - - "create.schematicannon.status.idle": "Inactiv", - "create.schematicannon.status.ready": "Gata", - "create.schematicannon.status.running": "Rulează", - "create.schematicannon.status.finished": "Terminat", - "create.schematicannon.status.paused": "Pauză", - "create.schematicannon.status.stopped": "Oprit", - "create.schematicannon.status.noGunpowder": "Praf de Pușcă Epuizat", - "create.schematicannon.status.targetNotLoaded": "Ținta nu este încărcată", - "create.schematicannon.status.targetOutsideRange": "Ținta este prea departe", - "create.schematicannon.status.searching": "Se caută", - "create.schematicannon.status.skipping": "Se sare peste", - "create.schematicannon.status.missingBlock": "Obiect Lipsă:", - "create.schematicannon.status.placing": "Se plasează", - "create.schematicannon.status.clearing": "Se curătă Blocuri", - "create.schematicannon.status.schematicInvalid": "Schemă Invalidă", - "create.schematicannon.status.schematicNotPlaced": "Schema nu e Poziționată", - "create.schematicannon.status.schematicExpired": "Fișierul Schemei Expirat", - - "create.materialChecklist": "Listă De Verificare Materiale", - "create.materialChecklist.blocksNotLoaded": "* Disclaimer *\n\nLista materialelor s-ar putea să fie inexactă din cauza chunkurilor relevante neîncărcate.", - - "create.gui.filter.deny_list": "Listă-Respingere", - "create.gui.filter.deny_list.description": "Obiectele trec dacă NU se potrivesc cu niciunul de mai sus. O Listă-Respingere goală acceptă totul.", - "create.gui.filter.allow_list": "Listă-Permitere", - "create.gui.filter.allow_list.description": "Obiectele trec dacă se potrivesc cu orice de mai sus. O Listă-Permitere goală respinge totul.", - "create.gui.filter.respect_data": "Respectă Date", - "create.gui.filter.respect_data.description": "Obiectele se potrivesc numai dacă durabilitatea, farmecele, și alte atribute se potrivesc de asemenea.", - "create.gui.filter.ignore_data": "Ignoră Date", - "create.gui.filter.ignore_data.description": "Obiectele se potrivesc indefert de atribute.", - - "create.item_attributes.placeable": "este plasabil", - "create.item_attributes.placeable.inverted": "nu este plasabil", - "create.item_attributes.consumable": "poate fi mâncat", - "create.item_attributes.consumable.inverted": "nu poate fi mâncat", - "create.item_attributes.fluid_container": "poate stoca fluide", - "create.item_attributes.fluid_container.inverted": "nu poate stoca fluide", - "create.item_attributes.enchanted": "este fermecat", - "create.item_attributes.enchanted.inverted": "este nefermecat", - "create.item_attributes.max_enchanted": "este fermecat la nivelul maxim", - "create.item_attributes.max_enchanted.inverted": "nu este fermecat la nivelul maxim", - "create.item_attributes.renamed": "are un nume personalizat", - "create.item_attributes.renamed.inverted": "nu are un nume personalizat", - "create.item_attributes.damaged": "este deteriorat", - "create.item_attributes.damaged.inverted": "nu este deteriorat", - "create.item_attributes.badly_damaged": "este deteriorat grav", - "create.item_attributes.badly_damaged.inverted": "nu este deteriorat grav", - "create.item_attributes.not_stackable": "nu poate fi stacat", - "create.item_attributes.not_stackable.inverted": "poate fi stacat", - "create.item_attributes.equipable": "poate fi echipat", - "create.item_attributes.equipable.inverted": "nu poate fi echipat", - "create.item_attributes.furnace_fuel": "e combustibil de cuptor", - "create.item_attributes.furnace_fuel.inverted": "nu e combustibil de cuptor", - "create.item_attributes.washable": "poate fi Spălat", - "create.item_attributes.washable.inverted": "nu poate fi Spălat", - "create.item_attributes.hauntable": "poate fi Bântuit", - "create.item_attributes.hauntable.inverted": "nu poate fi Bântuit", - "create.item_attributes.crushable": "poate fi Strivit", - "create.item_attributes.crushable.inverted": "nu poate fi Strivit", - "create.item_attributes.smeltable": "poate fi Topit", - "create.item_attributes.smeltable.inverted": "nu poate fi Topit", - "create.item_attributes.smokable": "poate fi Afumat", - "create.item_attributes.smokable.inverted": "nu poate fi Afumat", - "create.item_attributes.blastable": "poate fi topit în Furnal", - "create.item_attributes.blastable.inverted": "nu poate fi topit în Furnal", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "este shulkerul %1$s", - "create.item_attributes.shulker_level.inverted": "nu este shulkerul %1$s", - "create.item_attributes.shulker_level.full": "plin", - "create.item_attributes.shulker_level.empty": "gol", - "create.item_attributes.shulker_level.partial": "plin parțial", - "create.item_attributes.in_tag": "este etichetat %1$s", - "create.item_attributes.in_tag.inverted": "nu este etichetat %1$s", - "create.item_attributes.in_item_group": "este în grupul '%1$s'", - "create.item_attributes.in_item_group.inverted": "nu este în grupul '%1$s'", - "create.item_attributes.added_by": "a fost adăugat de %1$s", - "create.item_attributes.added_by.inverted": "nu a fost adăugat de %1$s", - "create.item_attributes.has_enchant": "este fermecat cu %1$s", - "create.item_attributes.has_enchant.inverted": "nu este fermecat cu %1$s", - "create.item_attributes.color": "este vopsit %1$s", - "create.item_attributes.color.inverted": "nu este vopsit %1$s", - "create.item_attributes.has_fluid": "conține %1$s", - "create.item_attributes.has_fluid.inverted": "nu conține %1$s", - "create.item_attributes.has_name": "are numele personalizat %1$s", - "create.item_attributes.has_name.inverted": "nu are numele personalizat %1$s", - "create.item_attributes.book_author": "a fost scrisă de %1$s", - "create.item_attributes.book_author.inverted": "nu a fost scrisă de %1$s", - "create.item_attributes.book_copy_original": "este un original", - "create.item_attributes.book_copy_original.inverted": "nu este un original", - "create.item_attributes.book_copy_first": "este o copie de prima generație", - "create.item_attributes.book_copy_first.inverted": "nu este o copie de prima generație", - "create.item_attributes.book_copy_second": "este o copie de a doua generație", - "create.item_attributes.book_copy_second.inverted": "nu este o copie de a doua generație", - "create.item_attributes.book_copy_tattered": "este o mizerie zdrențuită", - "create.item_attributes.book_copy_tattered.inverted": "nu este o mizerie zdrențuită", - "create.item_attributes.astralsorcery_amulet": "îmbunătățește %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "nu îmbunătățește %1$s", - "create.item_attributes.astralsorcery_constellation": "este pus în acord cu %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "nu este pus în acord cu %1$s", - "create.item_attributes.astralsorcery_crystal": "are atributul cristal %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "nu are atributul cristal %1$s", - "create.item_attributes.astralsorcery_perk_gem": "are atributul avantaj %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "nu are atributul abantaj %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Niciun atribut selectat", - "create.gui.attribute_filter.selected_attributes": "Atribute selectate:", - "create.gui.attribute_filter.add_attribute": "Adaugă atributul în Listă", - "create.gui.attribute_filter.add_inverted_attribute": "Adaugă atributul opus în Listă", - "create.gui.attribute_filter.allow_list_disjunctive": "Listă-Permitere (Orice)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Obiectele trec dacă au oricare dintre atributele selectate.", - "create.gui.attribute_filter.allow_list_conjunctive": "Listă-Permitere (Totul)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Obiectele trec doar dacă au TOATE atributele selectate.", - "create.gui.attribute_filter.deny_list": "Listă-Respingere", - "create.gui.attribute_filter.deny_list.description": "Obiectele trec dacă NU au oricare dintre atributele selectate.", - "create.gui.attribute_filter.add_reference_item": "Adaugă Obiect de Referință", - - "create.tooltip.holdForDescription": "Ține apăsat [%1$s] pentru Rezumat", - "create.tooltip.holdForControls": "Ține apăsat [%1$s] pentru Controale", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Cerință De Viteză: %1$s", - "create.tooltip.speedRequirement.none": "Niciunul", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "Moderat", - "create.tooltip.speedRequirement.fast": "UNLOCALIZED: Fast", - "create.tooltip.stressImpact": "Impact Stres Cinetic: %1$s", - "create.tooltip.stressImpact.low": "Scăzut", - "create.tooltip.stressImpact.medium": "Moderat", - "create.tooltip.stressImpact.high": "Ridicat", - "create.tooltip.stressImpact.overstressed": "Suprasolicitat", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Capacitate Stres Cinetic: %1$s", - "create.tooltip.capacityProvided.low": "Mică", - "create.tooltip.capacityProvided.medium": "Medie", - "create.tooltip.capacityProvided.high": "Mare", - "create.tooltip.generationSpeed": "Generează la %1$s %2$s", - "create.tooltip.analogStrength": "Putere Analog: %1$s/15", - - "create.mechanical_arm.extract_from": "Ia Obiecte din %1$s", - "create.mechanical_arm.deposit_to": "Depozitează obiecte în %1$s", - "create.mechanical_arm.summary": "Brațul mecanic are %1$s intrare(intrări) și %2$s ieșire(ieșiri).", - "create.mechanical_arm.points_outside_range": "%1$s punct(e) de intracțiune selectat(e) a(u) fost îndepărtat(e) din cauza limitațiilor de rază.", - - "create.weighted_ejector.target_set": "Țintă Selectată", - "create.weighted_ejector.target_not_valid": "Se Ejectează la blocul Adiacent (Ținta nu a fost Validă)", - "create.weighted_ejector.no_target": "Se Ejectează la blocul Adiacent (Nicio Țintă nu a fost Selectată)", - "create.weighted_ejector.targeting": "Se Ejectează la [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "S-a ejectat Mărimea Stacului", - - "create.logistics.when_multiple_outputs_available": "Când sunt disponibile ieșiri multiple", - - "create.mechanical_arm.selection_mode.round_robin": "Robin Rotund", - "create.mechanical_arm.selection_mode.forced_round_robin": "Robin Rotund Forțat", - "create.mechanical_arm.selection_mode.prefer_first": "Preferă Prima Țintă", - - "create.tunnel.selection_mode.split": "Împărțire", - "create.tunnel.selection_mode.forced_split": "Împărțire Forțată", - "create.tunnel.selection_mode.round_robin": "Robin Rotund", - "create.tunnel.selection_mode.forced_round_robin": "Robin Rotund Forțat", - "create.tunnel.selection_mode.prefer_nearest": "Preferă Cel Mai Apropiat", - "create.tunnel.selection_mode.randomize": "Randomizare", - "create.tunnel.selection_mode.synchronize": "Sincronizare Intrări", - - "create.tooltip.chute.header": "Informație Tobogan", - "create.tooltip.chute.items_move_down": "Obiectele se mișcă În Jos", - "create.tooltip.chute.items_move_up": "Obiectele se mișcă În Sus", - "create.tooltip.chute.no_fans_attached": "Niciun ventilator atașat", - "create.tooltip.chute.fans_push_up": "Ventilatoarele împing de Jos", - "create.tooltip.chute.fans_push_down": "Ventilatoarele împing de Sus", - "create.tooltip.chute.fans_pull_up": "Ventilatoarele trag de Sus", - "create.tooltip.chute.fans_pull_down": "Ventilatoarele trag de Jos", - "create.tooltip.chute.contains": "Conține: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "Distribuie Curent:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "Click Dreapta pentru a recupera", - - "create.linked_controller.bind_mode": "Mod de legare activat", - "create.linked_controller.press_keybind": "Apasă %1$s, %2$s, %3$s, %4$s, %5$s sau %6$s, pentru a lega această frecvenșă la tasta respectivă", - "create.linked_controller.key_bound": "Frecvență legată la %1$s", - "create.linked_controller.frequency_slot_1": "Tasta: %1$s, Frecvența #1", - "create.linked_controller.frequency_slot_2": "Tasta: %1$s, Frecvența #2", - - "create.crafting_blueprint.crafting_slot": "Slot de Ingredient", - "create.crafting_blueprint.filter_items_viable": "Obiecte de filtru avansat sunt viabile", - "create.crafting_blueprint.display_slot": "Slot de Afișaj", - "create.crafting_blueprint.inferred": "Deduse de la rețetă", - "create.crafting_blueprint.manually_assigned": "Atribuit manual", - "create.crafting_blueprint.secondary_display_slot": "Slot de Afișaj Secundar", - "create.crafting_blueprint.optional": "Opțional", - - "create.potato_cannon.ammo.attack_damage": "%1$s Puncte de Atac", - "create.potato_cannon.ammo.reload_ticks": "%1$s Ticuri de Reîncărcare", - "create.potato_cannon.ammo.knockback": "%1$s Împingere", - - "create.hint.hose_pulley.title": "Aprovizionare fără fund", - "create.hint.hose_pulley": "Corpul de fluid vizat este considerat infinit.", - "create.hint.mechanical_arm_no_targets.title": "Nicio Țintă", - "create.hint.mechanical_arm_no_targets": "Se pare că acest _Braț_ _Mecanic_ nu i s-a atribuit nicio _țintă._ Selectează benzi, depoturi, pâlnii și alte blocuri apăsând _Click-Dreapta_ pe ele _ținând_ _Brațul_ _Mecanic_ în _mână_.", - "create.hint.empty_bearing.title": "Actualizează Rulmentul", - "create.hint.empty_bearing": "Apasă _Click-Dreapta_ pe rulment cu o _mână_ _goală_ pentru a _atașa_ structura pe care tocmai a construit-o în fața ei.", - "create.hint.full_deployer.title": "Revărsare De Obiecte Deployer", - "create.hint.full_deployer": "De pare că acest _Deployer_ conține _obiecte în_ _exces_ care trebuie să fie _extrase._ Folosește o _pâlnie_ sau alte mijloace pentru a-l elibera din revărsare.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "Hi :)", - "create.gui.config.overlay2": "This is a sample overlay", - "create.gui.config.overlay3": "Click or drag with your mouse", - "create.gui.config.overlay4": "to move this preview", - "create.gui.config.overlay5": "Press ESC to exit this screen", - "create.gui.config.overlay6": "and save the new position", - "create.gui.config.overlay7": "Run /create overlay reset", - "create.gui.config.overlay8": "to reset to the default position", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Ticul serverului este încetinit cu %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Ticul serverului este încetinit cu %s ms acum >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Ticul serverului este înapoi la viteza normală :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: folosește /killtps stop pentru a readuce ticul serverului la viteza normală", - "create.command.killTPSCommand.status.usage.1": "[Create]: folosește /killtps start pentru a încetini artificial ticul serverului", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "Această Invenție de Vagonet pare ca este prea mare pentru a fi luat.", - "create.contraption.minecart_contraption_illegal_pickup": "O forță mistică leagă această Invenție de Vagonet de lume", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Invenție se oprește", - "create.subtitle.peculiar_bell_use": "Clopot Ciudat bate", - "create.subtitle.worldshaper_place": "Modelator de Lume face zap", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "Ferăstrău Mecanic se activează", - "create.subtitle.schematicannon_finish": "Tun de Schemă face ding", - "create.subtitle.crafter_craft": "Meșter lucrează", - "create.subtitle.wrench_remove": "Component se sparge", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "Roți Dințate vuie", - "create.subtitle.slime_added": "Mâzgă zdrobește", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "Tun de Schemă trage", - "create.subtitle.controller_take": "Pupitru se golește", - "create.subtitle.crafter_click": "Meșter clickuiește", - "create.subtitle.depot_plop": "Obiect aterizează", - "create.subtitle.confirm": "Ding afirmativ", - "create.subtitle.mixing": "Sunete de amestecare", - "create.subtitle.mechanical_press_activation_belt": "Presă Mecanică face bonk", - "create.subtitle.fwoomp": "Lansator de Cartofi face fwoomp", - "create.subtitle.sanding_long": "Sunete de șlefuit", - "create.subtitle.crushing_1": "Sunete de zdrobit", - "create.subtitle.depot_slide": "Obiect alunecă", - "create.subtitle.blaze_munch": "Arzător de Dogoreală plescăie", - "create.subtitle.funnel_flap": "Pâlnie falfâie", - "create.subtitle.haunted_bell_use": "Clopot Bântuit bate", - "create.subtitle.scroll_value": "Acțiune de Scroll clickuiește", - "create.subtitle.controller_put": "Controlor bocăne", - "create.subtitle.cranking": "Manivelă se rotește", - "create.subtitle.sanding_short": "Sunete de șlefuit", - "create.subtitle.wrench_rotate": "Cheie folosită", - "create.subtitle.potato_hit": "Impact de legumă", - "create.subtitle.saw_activate_wood": "Ferăstrău Mecanic se activează", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "Clopot Bântuit se trezețte", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "Boop de refuz", - "create.subtitle.controller_click": "Controlor clickuiește", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "Echipament de scufundare ciocăne", - "create.subtitle.mechanical_press_activation": "Presă Mecanică zăngăne", - "create.subtitle.contraption_assemble": "Invenție se mișcă", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "OBIECT EXEMPLU (doar un marker că acest tooltip există)", - "item.create.example_item.tooltip.summary": "O scurtă descriere a obiectului. _Sublinierile_ evidențiază un termen.", - "item.create.example_item.tooltip.condition1": "Când asta", - "item.create.example_item.tooltip.behaviour1": "atunci acest obiect face asta. (comportamentele se afișează pe shift)", - "item.create.example_item.tooltip.condition2": "Și Când Asta", - "item.create.example_item.tooltip.behaviour2": "Poți adăuga cât de multe comportamente îți place", - "item.create.example_item.tooltip.control1": "Când Ctrl e apăsat", - "item.create.example_item.tooltip.action1": "Aceste controale se afișează.", - - "block.create.wooden_bracket.tooltip": "BRACHETĂ DE LEMN", - "block.create.wooden_bracket.tooltip.summary": "_Decorează_-ți _Rotoarele, Roțile Dințate_ și _Conducele_ cu o comodă și lemnoasă piesă de întărire.", - - "block.create.metal_bracket.tooltip": "BRACHETĂ DE METAL", - "block.create.metal_bracket.tooltip.summary": "_Decorează_-ți _Rotoarele, Roțile Dințate_ și _Conducele_ cu o industrială și rezistentă piesă de întărire.", - - "block.create.seat.tooltip": "SCAUN", - "block.create.seat.tooltip.summary": "Stai jos și bucură-te de plimbare! Va ancora un jucător pe o _invenție_ în mișcare. De asemenea, grozav pentru mobilier static! Vine într-o varietate de culori.", - "block.create.seat.tooltip.condition1": "Click Dreapta pe Scaun", - "block.create.seat.tooltip.behaviour1": "Așează jucătorul pe _Scaun_. Apasă shift stânga pentru a părăsi _Scaunul_.", - - "item.create.blaze_cake.tooltip": "TORT DE DOGOREALĂ", - "item.create.blaze_cake.tooltip.summary": "Un Ospăț delicios pentru muncitorii tăi, _Arzătorii De Dogoreală_. Îi face pe toți aprinși!", - - "item.create.wand_of_symmetry.tooltip": "BAGHETĂ DE SIMETRIE", - "item.create.wand_of_symmetry.tooltip.summary": "Oglindește perfect plasarea Blocurilor peste planuri configurate", - "item.create.wand_of_symmetry.tooltip.condition1": "Când e în hotbar", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Stă Activă", - "item.create.wand_of_symmetry.tooltip.control1": "Click-D pe Sol", - "item.create.wand_of_symmetry.tooltip.action1": "_Creează_ sau _Mută_ Oglinda", - "item.create.wand_of_symmetry.tooltip.control2": "Click-D în Aer", - "item.create.wand_of_symmetry.tooltip.action2": "_Elimină_ Oglinda activă", - "item.create.wand_of_symmetry.tooltip.control3": "Click-D în timpul Furișării", - "item.create.wand_of_symmetry.tooltip.action3": "Deschide _Interfața de Configurare_", - - "item.create.handheld_worldshaper.tooltip": "MODELATOR DE LUME", - "item.create.handheld_worldshaper.tooltip.summary": "Unealtă la îndemână pentru crearea _peisajelor_ și _caracteristicilor de teren_.", - "item.create.handheld_worldshaper.tooltip.control1": "Click-S pe Bloc", - "item.create.handheld_worldshaper.tooltip.action1": "Setează blocul plasat de unealtă la blocul vizat.", - "item.create.handheld_worldshaper.tooltip.control2": "Click-D pe Bloc", - "item.create.handheld_worldshaper.tooltip.action2": "Aplică _Pensula_ și _Unealta_ selectată în prezent la locația vizată.", - "item.create.handheld_worldshaper.tooltip.control3": "Click-D în timpul Furișării", - "item.create.handheld_worldshaper.tooltip.action3": "Deschide _Interfața de Configurare_", - - "item.create.tree_fertilizer.tooltip": "FERTILIZATOR DE COPACI", - "item.create.tree_fertilizer.tooltip.summary": "O combinație puternică de minerale potrivite pentru accelerarea creșterii a tipurilor de copaci obișnuiți.", - "item.create.tree_fertilizer.tooltip.condition1": "Când este folosit pe puiet", - "item.create.tree_fertilizer.tooltip.behaviour1": "Crește Copacii _indiferent_ de _condițiile de spațiu_", - - "item.create.extendo_grip.tooltip": "GRIP EXTENDO", - "item.create.extendo_grip.tooltip.summary": "Boioioing! _Mărește_ cu mult _distanța de atingere_ a purtătorului. Poate fi alimentat cu Presiune de Aer de la un _Backtank de Cupru_", - "item.create.extendo_grip.tooltip.condition1": "Când este în mâna opusă", - "item.create.extendo_grip.tooltip.behaviour1": "Mărește _distanța de atingere_ a obiectelor folosite în _Mâna Principală_.", - "item.create.extendo_grip.tooltip.condition2": "Când se poartă Backtank de Cupru", - "item.create.extendo_grip.tooltip.behaviour2": "_Durabilitatea_ _nu_ va fi folosită. În schimb, _Presiunea_ _aerului_ este stoarsă din Rezervor", - - "item.create.potato_cannon.tooltip": "TUN DE CARTOFI", - "item.create.potato_cannon.tooltip.summary": "Fwoomp! Lansează-ți legumele de casă către Inamicii tăi. Poate fi alimentat cu Presiune de Aer de la un _Backtank de Cupru_", - "item.create.potato_cannon.tooltip.condition1": "Când Click-D este apăsat", - "item.create.potato_cannon.tooltip.behaviour1": "_Trage_ un obiect potrivit din _Inventar_.", - "item.create.potato_cannon.tooltip.condition2": "Când se poartă Backtank de Cupru", - "item.create.potato_cannon.tooltip.behaviour2": "_Durabilitatea_ _nu_ va fi folosită. În schimb, _Presiunea_ _aerului_ este stoarsă din Rezervor", - - "item.create.filter.tooltip": "FILTRU", - "item.create.filter.tooltip.summary": "_Controlează ieșirile_ și _intrările_ dispozitivelor logistice cu mai multă _precizie_, potrivindu-le împotriva unui _set de obiecte_ sau mai multe _filtre cuibărite_.", - "item.create.filter.tooltip.condition1": "Când este în slot de filtru", - "item.create.filter.tooltip.behaviour1": "_Controlează_ fluxul de obiecte conform _configurației_ sale.", - "item.create.filter.tooltip.condition2": "Când Click-D este apăsat", - "item.create.filter.tooltip.behaviour2": "Deschide _interfața de configurare_.", - - "item.create.attribute_filter.tooltip": "FILTRU DE ATRIBUT", - "item.create.attribute_filter.tooltip.summary": "_Controlează ieșirile_ și _intrările_ dispozitivelor logistice cu mai multă _precizie_, potrivindu-le împotriva unor _seturi de atribute_ de obiecte și _categorii_.", - "item.create.attribute_filter.tooltip.condition1": "Când este în slot de filtru", - "item.create.attribute_filter.tooltip.behaviour1": "_Controlează_ fluxul de obiecte conform _configurației_ sale.", - "item.create.attribute_filter.tooltip.condition2": "Când Click-D este apăsat", - "item.create.attribute_filter.tooltip.behaviour2": "Deschide _interfața de configurare_.", - - "item.create.empty_schematic.tooltip": "SCHEMĂ GOALĂ", - "item.create.empty_schematic.tooltip.summary": "Folosită ca un ingredient de rețetă și pentru scriere la _Masa de Schemă_.", - - "item.create.schematic.tooltip": "SCHEMĂ", - "item.create.schematic.tooltip.summary": "Ține o structură pentru a fi poziționată și plasată în lume. Poziționează Holograma cum dorești și folosește un _Tun de Schemă_ pentru a o construi.", - "item.create.schematic.tooltip.condition1": "Când este ținută", - "item.create.schematic.tooltip.behaviour1": "Poate fi poziționată fikisind Uneltele de pe Ecran.", - "item.create.schematic.tooltip.control1": "Click-D în timpul Furișării", - "item.create.schematic.tooltip.action1": "Deschide o _Interfață_ pentru introducerea _Coordonatelor_ exacte.", - - "item.create.schematic_and_quill.tooltip": "SCHEMĂ ȘI CONDEI", - "item.create.schematic_and_quill.tooltip.summary": "Folosit pentru salvarea unei Structuri în lumea ta pe un fișier .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Pasul 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Selectează două puncte-colț folosind Click-D.", - "item.create.schematic_and_quill.tooltip.condition2": "Pasul 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl-Scroll_ pe fețe pentru a le regla mărimea. Click-D din nou pentru a Salva.", - "item.create.schematic_and_quill.tooltip.control1": "Click-D", - "item.create.schematic_and_quill.tooltip.action1": "Selectează un punct colț / confirmă salvarea.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl Apăsat", - "item.create.schematic_and_quill.tooltip.action2": "Selectează puncte _în aer_. _Derulează_ pentru a regla distanța.", - "item.create.schematic_and_quill.tooltip.control3": "Click-D în timpul furișării", - "item.create.schematic_and_quill.tooltip.action3": "_Resetează_ și șterge selecția.", - - "block.create.schematicannon.tooltip": "TUN DE SCHEMĂ", - "block.create.schematicannon.tooltip.summary": "Trage cu blocuri pentru a recreea o _Schemă_ instituită în Lume. Folosește obiecte din Inventare adiacente și _Praf de Pușcă_ ca combustibil.", - "block.create.schematicannon.tooltip.condition1": "Când Click-D este apăsat", - "block.create.schematicannon.tooltip.behaviour1": "Deschide _Interfața_", - - "block.create.schematic_table.tooltip": "MASĂ DE SCHEMĂ", - "block.create.schematic_table.tooltip.summary": "Scrie Scheme salvate într-o _Schemă Goală_.", - "block.create.schematic_table.tooltip.condition1": "Când primește o Schemă Goală", - "block.create.schematic_table.tooltip.behaviour1": "Încarcă un Fișier ales din Folderul tău de Scheme.", - - "item.create.goggles.tooltip": "OCHELARI", - "item.create.goggles.tooltip.summary": "O pereche de ochelari pentru a-ți spri vederea cu _informații cinetice_ folositoare.", - "item.create.goggles.tooltip.condition1": "Când sunt purtați", - "item.create.goggles.tooltip.behaviour1": "Arată _indicatoare colorate_ care corespund cu _Nivelul Vitezei_ al unui component cinetic plasat precum și _Impactul Stresului_ și _Capacitatea_ componentelor individuale.", - "item.create.goggles.tooltip.condition2": "Când se uită la gabarit", - "item.create.goggles.tooltip.behaviour2": "Afișează informațiile detaliate despre _Viteză_ sau _Stres_ are rețelei la care gabaritul este conectat.", - "item.create.goggles.tooltip.condition3": "Când se uită la rezervoare de fluid", - "item.create.goggles.tooltip.behaviour3": "fișează informații detaliate despre _Capacitatea_ blocului și orice _Fluid_ stocat în interior.", - - "item.create.wrench.tooltip": "CHEIE", - "item.create.wrench.tooltip.summary": "O unealtă folositoare pentru lucrul cu invenții cinetice. Poate fi folosită pentru a _Roti_, _Demonta_ și a _Configura_ componente.", - "item.create.wrench.tooltip.control1": "Click-Dreapta pe un bloc cinetic", - "item.create.wrench.tooltip.action1": "_Rotește componentele_ spre sau departe de fața cu care ai interacționat.", - "item.create.wrench.tooltip.control2": "Click-D în timpul Furișării", - "item.create.wrench.tooltip.action2": "_Dezasamblează componente Cinetice_ și le plasează înapoi în _inventarul tău_.", - - "block.create.nozzle.tooltip": "PLASĂ", - "block.create.nozzle.tooltip.summary": "Atașează în fața unui _Ventilator Încapsulat_ pentru a-i distribui efectul pe Entități în _toate direcțiile_.", - - "block.create.cuckoo_clock.tooltip": "CEAS CUCU", - "block.create.cuckoo_clock.tooltip.summary": "Măiestrie fină pentru _decorarea_ unui spațiu și pentru _ținerea noțiunii timpului_.", - "block.create.cuckoo_clock.tooltip.condition1": "Când este alimentat de Cinetice", - "block.create.cuckoo_clock.tooltip.behaviour1": "Arată _ora actuală_ și cântă un ton de două ori pe zi. _Se activează_ odată la _amiază_ și la amurg, de îndată ce _jucătorii pot dormi_.", - - "block.create.turntable.tooltip": "PLACĂ TURNANTĂ", - "block.create.turntable.tooltip.summary": "Transformă _Forța de Rotație_ într-un fin Rău De Mișcare.", - - "block.create.toolbox.tooltip": "TRUSĂ DE SCULE", - "block.create.toolbox.tooltip.summary": "Cea mai dragă companie a oricărui inventator. _Ține_ convenabil o cantitate mare de _8 Diferite_ tipuri de obiecte.", - "block.create.toolbox.tooltip.condition1": "Când este ridicat", - "block.create.toolbox.tooltip.behaviour1": "_Reține Conținutul_ Inventarului.", - "block.create.toolbox.tooltip.condition2": "Când este plasat în rază", - "block.create.toolbox.tooltip.behaviour2": "_Jucătorii din apropiere_ pot apăsa _Tasta de Toolbox_ pentru a-i accesa conținutul _De la distanță_.", - "block.create.toolbox.tooltip.condition3": "Când Click-D este apăsat", - "block.create.toolbox.tooltip.behaviour3": "Deschide _Interfața Recipientului_.", - - "block.create.stockpile_switch.tooltip": "COMUTATOR DE DEPOZITARE", - "block.create.stockpile_switch.tooltip.summary": "Comută un semnal Redstone bazat pe cantitatea de _Obiecte Stocate_ sau _Fluide_ în recipientul atașat. Vine cu un filtru la îndemână. În contrast cu _Comparatorul, Comutatorul de Depozitare_ permite configurarea unor _praguri,_ la care semnale sunt inversate.", - "block.create.stockpile_switch.tooltip.condition1": "Când Click-D este apăsat", - "block.create.stockpile_switch.tooltip.behaviour1": "Deschide _Interfața de Configurare_.", - - "block.create.content_observer.tooltip": "OBSERVATOR DE CONȚINUT", - "block.create.content_observer.tooltip.summary": "_Detectează obiecte_ sau _Fluide_ în interiorul _recipientelor_, _conductelor_ sau _benzilor rulante_ potrivind un _filtru_ configurat.", - "block.create.content_observer.tooltip.condition1": "Când se observă un Recipient", - "block.create.content_observer.tooltip.behaviour1": "Emite un _Semnal Redstone_ în timp ce recipientul observat are _conținut_ _potrivit_.", - "block.create.content_observer.tooltip.condition2": "Când se observă o Pâlnie", - "block.create.content_observer.tooltip.behaviour2": "Emită un _Puls de redstone_ când un obiect _potrivit_ este _transferat_.", - - "block.create.creative_crate.tooltip": "LADĂ AJUSTABILĂ CREATIV", - "block.create.creative_crate.tooltip.summary": "Acest _Recipient de Depozitare_ permite replici infinite a oricărui obiect. Plasează lângă un _Tun de Schemă_ pentru a elimina orice cerințe de material.", - "block.create.creative_crate.tooltip.condition1": "Când un Obiect este în slot de filtru", - "block.create.creative_crate.tooltip.behaviour1": "Orice se _extrage_ din acest recipient va oferi o _aprovizionare nesfârșită_ a obiectului specificat. Obiecte _introduse_ în această ladă vor fi _golite._", - - "item.create.creative_blaze_cake.tooltip": "TORT CREATIV", - "item.create.creative_blaze_cake.tooltip.summary": "Un ospăț foarte specal pentru _Arzători de Dogoreașă_ care permite _controlarea nivelului de încălzire_. După mâncarea acestui tort, Arzătorii de Dogoreală nu vor _rămâne fără combustibil niciodată_.", - "item.create.creative_blaze_cake.tooltip.condition1": "Click-D pe Arzător de Dogoreală", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Blochează_ nivelul de încălzire a arzătorului de dogoreală. Dacă este folosit din nou, _circulă_ nivelul de încălzire a Arzătorului de Dogoreală.", - - "block.create.controller_rail.tooltip": "CONTROLOR DE ȘINĂ", - "block.create.controller_rail.tooltip.summary": "O _șină alimentată uni-direcțională_ capabilă de _control fin_ asupra _vitezei de mișcare_ a vagonetului.", - "block.create.controller_rail.tooltip.condition1": "Când este Alimentat de Redstone", - "block.create.controller_rail.tooltip.behaviour1": "_Accelerează_ sau _Decelerează_ _vagonete_ trecătoare corespunzător cu _puterea semnalului_. Propagă putere redstone la șine controlor adiacente. Alimentând două șine controlor cu diferite puteri va cauza șine între ele să le interpoleze semnalul.", - - "item.create.sand_paper.tooltip": "ȘMIRGHEL", - "item.create.sand_paper.tooltip.summary": "O hârtie brută care poate fi folosită la _șlefuirea materialelor_. Poate fi aplicată automat folosing Deployerul.", - "item.create.sand_paper.tooltip.condition1": "Când este Folosit", - "item.create.sand_paper.tooltip.behaviour1": "Aplică lustruire la obiecte când sunt ținute în _mâna opusă_ sau întinse pe _podea_ când _te uiți la ele_", - - "item.create.builders_tea.tooltip": "CEAIUL CONSTRUCTORULUI", - "item.create.builders_tea.tooltip.summary": "Băutura perfectă pentru a începe ziua- _Motivant_ și _Saturant._", - - "item.create.refined_radiance.tooltip": "RADIANȚĂ RAFINANTĂ", - "item.create.refined_radiance.tooltip.summary": "Un material Cromatic făurit din _lumina absorbită_.", - "item.create.refined_radiance.tooltip.condition1": "Lucru în curs", - "item.create.refined_radiance.tooltip.behaviour1": "Utilizări pentru acest material vor fi valabile într-o viitoare lansare.", - - "item.create.shadow_steel.tooltip": "OȚEL DE UMBRĂ", - "item.create.shadow_steel.tooltip.summary": "Un material Cromatic făurit _în void_.", - "item.create.shadow_steel.tooltip.condition1": "Lucru în curs", - "item.create.shadow_steel.tooltip.behaviour1": "Utilizări pentru acest material vor fi valabile într-o viitoare lansare.", - - "item.create.linked_controller.tooltip": "CONTROLOR LEGAT", - "item.create.linked_controller.tooltip.summary": "Acordă _control_ _de mână_ prin frecvențe de _Legătură De Redstone_ atribuite la cele _șase_ _butoane_ ale lui.", - "item.create.linked_controller.tooltip.condition1": "Click-D", - "item.create.linked_controller.tooltip.behaviour1": "_Comută_ controlorul. _Controalele de_ _Mișcare_ sunt preluate în timp ce e activ.", - "item.create.linked_controller.tooltip.condition2": "Click-D în timpul Furișării", - "item.create.linked_controller.tooltip.behaviour2": "Deschide _Interfața de Configurare_ manuală.", - "item.create.linked_controller.tooltip.condition3": "Click-D pe Receptor de Legătură de Redstone", - "item.create.linked_controller.tooltip.behaviour3": "Activează _Modul de Legare_, apasă una dintre cele _șase controale_ pentru a le lega la _Frecvențele Legăturilor_.", - "item.create.linked_controller.tooltip.condition4": "Click-D pe Pupitru", - "item.create.linked_controller.tooltip.behaviour4": "Plasează Controlorul în Pupitru pentru activare ușoară. (Click-D în timpul Furișării pentru a-l recupera)", - - "item.create.diving_helmet.tooltip": "CASCĂ DE SCUFUNDARE", - "item.create.diving_helmet.tooltip.summary": "Împreună cu un _Backtank De_ _cupru_, permite purtătorul să _respire_ _sub apă_ pentru o perioadă extinsă de timp.", - "item.create.diving_helmet.tooltip.condition1": "Când este purtat", - "item.create.diving_helmet.tooltip.behaviour1": "Oferă efectul _Respirație Subacvatică_, scurgându-se încet _Presiunea de Aer_ din Backtank.", - - "item.create.copper_backtank.tooltip": "BACKTANK DE CUPRU", - "item.create.copper_backtank.tooltip.summary": "Un _Rezervor_ _Purtabil_ pentru cărarea de Presiune de Aer.", - "item.create.copper_backtank.tooltip.condition1": "Când este purtat", - "item.create.copper_backtank.tooltip.behaviour1": "Oferă _Presiune de_ _Aer_ Echipamentului care are nevoie.", - "item.create.copper_backtank.tooltip.condition2": "Când este plasat, Alimentat de Cinetice", - "item.create.copper_backtank.tooltip.behaviour2": "_Colectează_ _Presiune de_ _Aer_ într-un ritm depinzând de Viteză de Rotație.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "BOCANCI DE SCUFUNDARE", - "item.create.diving_boots.tooltip.summary": "O pereche de _bocanci_ _grei_, permițând traversare mai bună a fundului Oceanului.", - "item.create.diving_boots.tooltip.condition1": "Când sunt purtați", - "item.create.diving_boots.tooltip.behaviour1": "Purtătorul _se scufundă_ _mai repede_ și _nu poate_ _înota_. Acordă abilitatea să _meargă_ și să _sară_ sub apă. De asemenea, purtătorul nu mai este afectat de _Benzi_ _Mecanice_.", - - "item.create.crafting_blueprint.tooltip": "PLAN DE MEȘTEȘUGĂRIT", - "item.create.crafting_blueprint.tooltip.summary": "_Plasat_ pe un perete, poate fi folosit pentru a _specifica_ _aranjamente de_ _ingrediente_ pentru meșteșugărit manual mai ușor. Fiecare slot reprezintă o Rețetă.", - "item.create.crafting_blueprint.condition1": "Click-D pe slot gol", - "item.create.crafting_blueprint.behaviour1": "Deschide un _meniu de_ _Lucru_ permițându-ți să _configurezi_ o _rețetă_ și obiecte de afișaj.", - "item.create.crafting_blueprint.condition2": "Click-D pe slot configurat", - "item.create.crafting_blueprint.behaviour2": "_Aplică_ _rețeta_ _configurată_ cu Ingrediente potrvite găsite în _Inventarul_ tău. _Furișează-te_ pentru a crafta un _Stack_ de obiecte.", - - "item.create.minecart_coupling.tooltip": "CUPLARE DE VAGONET", - "item.create.minecart_coupling.tooltip.summary": "_Înlănțuiește_ toate _Vagonetele_ tale sau _Invențiile de Portal_ împreunp pentru a forma un Tren maiestuos.", - "item.create.minecart_coupling.tooltip.condition1": "Când este folosit pe Vagonet", - "item.create.minecart_coupling.tooltip.behaviour1": "_Cuplează_ două Vagonete împreună, încercând să le păstreze la o _distanță constantă_ în timpul mișcării.", - - "item.create.experience_nugget.tooltip": "PEPITĂ DE EXPERIENȚĂ", - "item.create.experience_nugget.tooltip.summary": "_Ding!_ O fărâmă de _inspirație_ de la invențiile tale fantastice.", - "item.create.experience_nugget.tooltip.condition1": "Când este folosită", - "item.create.experience_nugget.tooltip.behaviour1": "_Revendică_ puncte de _Experiență_ cuprinse înăuntru.", - - "block.create.peculiar_bell.tooltip": "CLOPOT CIUDAT", - "block.create.peculiar_bell.tooltip.summary": "Un _Clopot de Alamă decorativ_. Plasând-ul peste un _Foc de Suflete_ deschis ar putea cauza efecte adverse...", - - "block.create.haunted_bell.tooltip": "CLOPOT BÂNTUIT", - "block.create.haunted_bell.tooltip.summary": "Un _Clopot Blestemat_ bântuit de sufletele pierdute ale Netherului.", - "block.create.haunted_bell.tooltip.condition1": "Când este ținut sau bătut", - "block.create.haunted_bell.tooltip.behaviour1": "Evidențiază _Locuri fără Lumină_ apropiate pe care _Monștri Ostili_ se pot spawna.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "Acest comportament poate fi modificat folosind o Cheie", - "create.ponder.shared.storage_on_contraption": "Inventarele atașate la Invenție vor strânge dropurile lor automat", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "Sursă: 16 RPM", - "create.ponder.shared.movement_anchors": "Cu ajutorul unui Șasiu sau cu Super Glue, structuri mai mari pot fi mișcate.", - "create.ponder.tag.redstone": "Componente Logice", - "create.ponder.tag.redstone.description": "Componente ce ajută cu inginerie de redstone", - "create.ponder.tag.contraption_assembly": "Utilitate de Atașarea Blocurilor", - "create.ponder.tag.contraption_assembly.description": "Unelte și componente folosite pentru asamblarea structurilor mișcare ca o Invenșie animată", - "create.ponder.tag.fluids": "Manipulatoare de Fluid", - "create.ponder.tag.fluids.description": "Componente ce ajută la transmiterea și folosirea Fluidelor", - "create.ponder.tag.decoration": "Aestetice", - "create.ponder.tag.decoration.description": "Componente folosite în cea mai mare parte pentru scopuri decorative", - "create.ponder.tag.windmill_sails": "Vele pentru Rulmente de Mori de Vânt", - "create.ponder.tag.windmill_sails.description": "Blocuri care se pun spre puterea unei Invenții de Moară de Vânt când sunt asamblate. Fiecare din acestea au eficiență egală făcând asta.", - "create.ponder.tag.arm_targets": "Ținte pentru Brațe Mecanice", - "create.ponder.tag.arm_targets.description": "Componente ce pot fi selectate ca intrări sau ieșiri ale Brațului Mecanic", - "create.ponder.tag.kinetic_appliances": "Dispozitive Cinetice", - "create.ponder.tag.kinetic_appliances.description": "Componente ce folosesc Forță de Rotație", - "create.ponder.tag.kinetic_sources": "Surse Cinetice", - "create.ponder.tag.kinetic_sources.description": "Componente ce generează Forță de Rotație", - "create.ponder.tag.movement_anchor": "Ancore de Mișcare", - "create.ponder.tag.movement_anchor.description": "Componente ce permit creația invenșiilor mișcătoare, animând o structură atașată într-o varietate de moduri", - "create.ponder.tag.kinetic_relays": "Blocuri Cinetice", - "create.ponder.tag.kinetic_relays.description": "Componente ce ajută la transmiterea Forței de Rotație altundeva", - "create.ponder.tag.contraption_actor": "Actori de Invenții", - "create.ponder.tag.contraption_actor.description": "Componente ce expun comportament special când sunt atașate la o invenție mișcătoare", - "create.ponder.tag.creative": "Modul Creativ", - "create.ponder.tag.creative.description": "Componente care nu sunt valabile deobicei în Modul Supraviețuire", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "Transport de Obiecte", - "create.ponder.tag.logistics.description": "Componente ce ajută la mișcarea obiectelor în jur", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "Controlarea semnalelor folosind Maneta Analogică", - "create.ponder.analog_lever.text_1": "Manetele Analogice fac pentru o sursă de redstone compactă și precisă", - "create.ponder.analog_lever.text_2": "Click-Dreapta pentru a-i crește puterea de ieșire analogică", - "create.ponder.analog_lever.text_3": "Click-Dreapta în timpul Furișării pentru a-i scădea puterea de ieșire din nou", - - "create.ponder.andesite_tunnel.header": "Folosirea Tuneleurilor de Andezit", - "create.ponder.andesite_tunnel.text_1": "Tunelurile de Andezit pot fi folosite pentru a-ți acoperi benzile", - "create.ponder.andesite_tunnel.text_2": "Când un Tunel de Andezit are conexiuni pe laterale...", - "create.ponder.andesite_tunnel.text_3": "...ele vor împărți exact un obiect din orice stack care trece", - "create.ponder.andesite_tunnel.text_4": "Restul își va continua drumul", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "Procesarea Obiectelor în Bazin", - "create.ponder.basin.text_1": "Un Bazin poate ține Obiecte și Fluide pentru Procesare", - "create.ponder.basin.text_2": "După un pas de procesare, bazinele încearcă să scoată rezultatul jos, în lateralele lui", - "create.ponder.basin.text_3": "Când un component valid este prezent, Bazinul va arăta un robinet de ieșire", - "create.ponder.basin.text_4": "Un număr de opțiuni este aplicabil aici", - "create.ponder.basin.text_5": "Ieșirile vor fi prinse de inventarul de jos", - "create.ponder.basin.text_6": "Fără un robinet de ieșire, Bazinul va reține obiectele creeate în procesarea lui", - "create.ponder.basin.text_7": "Acest lucru poate fi folositor dacă ieșirile ar trebui să fie refolosite ca ingrediente", - "create.ponder.basin.text_8": "Atunci, ieșirile dorite vor trebui să fie extrase din bazin", - "create.ponder.basin.text_9": "Un filtru ar putea fi necesar pentru a evita tragerea afară a obiectelor neprocesate.", - - "create.ponder.bearing_modes.header": "Modurile de Milcare ale Rulmentului Mecanic", - "create.ponder.bearing_modes.text_1": "Când este oprit, Rulmentul va plasa structura la cel mai apropiat Unghi aliniat la grilă", - "create.ponder.bearing_modes.text_2": "Poate fi configurat să nu revină niciodată la blocuri solide, sau doar în apopierea unghiului de unde a început", - - "create.ponder.belt_casing.header": "Încăpsularea Benzilor", - "create.ponder.belt_casing.text_1": "Carcasa de Alamă sau Andezit poate fi folosită pentru a decora Benzi Mecanice", - "create.ponder.belt_casing.text_2": "O cheie poate fi folosită pentru a îndepărta carcasa", - - "create.ponder.belt_connector.header": "Folosirea Benzilor Mecanice", - "create.ponder.belt_connector.text_1": "Click-Dreapta pe două rotoare cu un obiect de bandă le va conecta împreună", - "create.ponder.belt_connector.text_2": "Selecțiile accidentașe pot fi anulate cu Click-Dreapta în timpul Furișării", - "create.ponder.belt_connector.text_3": "Rotoare Adiționale pot fi adăugate pe tot parcursul Benzii", - "create.ponder.belt_connector.text_4": "Rotoarele conectate prin Benzi se vor roti cu Viteză și Direcție Identică", - "create.ponder.belt_connector.text_5": "Rotoarele adăugate pot fi îndepărtate folosind cheia", - "create.ponder.belt_connector.text_6": "Benzile Mecanice pot fi vopsite pentru scopuri aestetice", - - "create.ponder.belt_directions.header": "Orientări Valide pentru Benzi Mecanice", - "create.ponder.belt_directions.text_1": "Benzile nu se pot conecta în direcții arbitrarii", - "create.ponder.belt_directions.text_2": "1. Se pot conecta orizontal", - "create.ponder.belt_directions.text_3": "2. Se pot conecta diagonal", - "create.ponder.belt_directions.text_4": "3. Se pot conecta vertical", - "create.ponder.belt_directions.text_5": "4. Și pot conecta rotoare verticale orizontal", - "create.ponder.belt_directions.text_6": "Acestea sunt toate direcțiile posibile. Benzile se pot întinde pe orice Lungime între 2 și 20 de blocuri", - - "create.ponder.belt_transport.header": "Folosirea Benzilor Mecanice pentru Logistică", - "create.ponder.belt_transport.text_1": "Benzile Mișcătoare vor transporta Obiecte și alte Entități", - "create.ponder.belt_transport.text_2": "Click-Dreapta cu o mână goală pentru a lua obiecte de pe bandă", - - "create.ponder.blaze_burner.header": "Hrănirea Arzătorilor de Dogoreală", - "create.ponder.blaze_burner.text_1": "Arzătorii de Dogoreală pot oferi Căldură Obiectelor procesate într-un Bazin", - "create.ponder.blaze_burner.text_2": "Pentru asta, Dogoreala trebuie hrănită cu obiecte inflamabile", - "create.ponder.blaze_burner.text_3": "Cu un Tort de Dogoreală, Arzătorul poate ajunge la un nivel de căldură mai puternic", - "create.ponder.blaze_burner.text_4": "Procesul hrănirii poate fi automat folosind Deployere sau Brațe Mecanice", - - "create.ponder.brass_funnel.header": "Pâlnia de Alamă", - "create.ponder.brass_funnel.text_1": "Pâlniile de Andezit pot să extragă doar obiecte individuale.", - "create.ponder.brass_funnel.text_2": "Pâlniile de Alamă pot extracta până la un stack plin.", - "create.ponder.brass_funnel.text_3": "Derulând pe slotul de filtru permite controlul precis asupra mărimii stackului extractat.", - "create.ponder.brass_funnel.text_4": "Folosind obiecte pe slotul de filtru va limita pâlnia să transfereze doar stackuri potrivite.", - - "create.ponder.brass_tunnel.header": "Folosirea Tunelelor de Alamă", - "create.ponder.brass_tunnel.text_1": "Tunelele de Alamă pot fi folosite pentru a=ți acoperi benzile", - "create.ponder.brass_tunnel.text_2": "Tunelele de Alamă au sloturi de filtru pe fiecare parte deschisă", - "create.ponder.brass_tunnel.text_3": "Filtrele pe conexiunile de intrare blochează pur și simplu obiecte nepotrivite", - "create.ponder.brass_tunnel.text_4": "Filtrele pe conexiunile de ieșire pot fi folosite pentru a sorta obiecte după tip", - "create.ponder.brass_tunnel.text_5": "Oricând un obiect trecător are mai multe ieșiri valabile, modul de distribuție va decide cum îl va trata", - "create.ponder.brass_tunnel.text_6": "Tunele de Alamă pe benzi paralele vor forma un grup", - "create.ponder.brass_tunnel.text_7": "Acum, Obiectele Primite vor fi distribuite pe toate ieșirile conectate", - "create.ponder.brass_tunnel.text_8": "Pentru asta, obiectele pot fi de asemenea introduse în blocul de Tunel direct", - - "create.ponder.brass_tunnel_modes.header": "Modurile de Distribuție a Tunelului de Alamă", - "create.ponder.brass_tunnel_modes.text_1": "Folosind o Cheie, comportamentul de distribuire a Tunelelor de Alamă poate fi configurat", - "create.ponder.brass_tunnel_modes.text_10": "'Sincronizare Intrări' este o setare unică pentru Tunelele de Alamă", - "create.ponder.brass_tunnel_modes.text_11": "Obiectele sunt permise să treacă dacă fiecare tunel în grup are o așteptare", - "create.ponder.brass_tunnel_modes.text_12": "Asta asigură că toate benzile aprovizionează obiecte la aceeași rată", - "create.ponder.brass_tunnel_modes.text_2": "'Împărțire' va încerca să distribuie stackul uniform între ieșirile valabile", - "create.ponder.brass_tunnel_modes.text_3": "Dacă o ieșire este incapabilă sa ia mai multe obiecte, va fi ocolită", - "create.ponder.brass_tunnel_modes.text_4": "'Împărțire Forțată' nu va ocoli niciodată ieșiri, și în schimb va aștepta până când sunt libere", - "create.ponder.brass_tunnel_modes.text_5": "'Robin Rotund' păstrează stackurile întregi, și circulă prin ieșiri iterativ", - "create.ponder.brass_tunnel_modes.text_6": "Din nou, dacă o ieșire este incapabilă să ia mai multe obiecte, va fi ocolită", - "create.ponder.brass_tunnel_modes.text_7": "'Robin Rotund Forțat' nu ocolește niciodată ieșiri", - "create.ponder.brass_tunnel_modes.text_8": "'Preferă Cel Mai Apropiat' prioritizează cele mai apropiate ieșiri față de locația de intrare a obiectelor", - "create.ponder.brass_tunnel_modes.text_9": "'Randomizare' va distribui stackuri întregi la ieșiri alese aleatoriu", - - "create.ponder.cart_assembler.header": "Mișcarea Structurilor folosind Asamblatoare de Vagonet", - "create.ponder.cart_assembler.text_1": "Asamblatoarele de Vagonet Alimentate montează structurile atașate pe Vagonete trecătoare", - "create.ponder.cart_assembler.text_2": "Fără un semnal redstone, dezasamblează invenșiile de vagonete trecătoare înapoi în blocuri", - "create.ponder.cart_assembler.text_3": "Folosind o Cheie pe Vagonet te va lăsa să cari Invenția altundeva", - - "create.ponder.cart_assembler_dual.header": "Asamblarea Invențiilor de Portal", - "create.ponder.cart_assembler_dual.text_1": "Oricând două Asamblatoare de Vagonet împart o structură atașată...", - "create.ponder.cart_assembler_dual.text_2": "Alimentând oricare dintre ele va crea o Invenție de Portal", - "create.ponder.cart_assembler_dual.text_3": "Vagonetele se vor comporta ca unele conectate prin Cuplare de Vagonet", - - "create.ponder.cart_assembler_modes.header": "Setări de Orientare pentru Invenșiile de Vagonet", - "create.ponder.cart_assembler_modes.text_1": "Invențiile de Vagonet se vor roti pentru a sta cu fața spre direcția de mișcare a vagonetelor", - "create.ponder.cart_assembler_modes.text_2": "Acestă Săgeată indică ce parte a Structurii se va considera ca fața", - "create.ponder.cart_assembler_modes.text_3": "Dacă Asamblatorul este setat pe Blochează Rotația, orientarea invenției nu se va schimba niciodată", - - "create.ponder.cart_assembler_rails.header": "Alte tipuri de Vagonete și Șine", - "create.ponder.cart_assembler_rails.text_1": "Asamblatoarele de Vagonete pe Șine Normale nu vor affecta mișcarea vagonetelor trecătoare", - "create.ponder.cart_assembler_rails.text_2": "Când este pe o Șină Propulsoare sau Controlor, vagonetele vor fi ținute pe loc până când este Alimentată", - "create.ponder.cart_assembler_rails.text_3": "Alte tipuri de Vagonete pot fi folosite ca ancoră", - "create.ponder.cart_assembler_rails.text_4": "Vagonetele cu Cuptor se păstrează alimentate, trăgând combustibil din orice inventar atașat", - - "create.ponder.chain_drive.header": "Transmiterea forței rotaționale cu Lanțuri de Distribuție", - "create.ponder.chain_drive.text_1": "Lanțurile de Distribuție transmit rotație de la unul la altul într-un rând", - "create.ponder.chain_drive.text_2": "Toate rotoarele conectate așa se vor roti în aceeași direcție", - "create.ponder.chain_drive.text_3": "Orice parte a rândului poate fi rotită cu 90 de grade", - - "create.ponder.chain_gearshift.header": "Controlarea vitezei de rotație cu Schimbătoare de Viteze Înlănțuite", - "create.ponder.chain_gearshift.text_1": "Schimvătoarele de Viteze Înlănțuite nealimentate se comportă exact ca Lanțurile de Distribuție", - "create.ponder.chain_gearshift.text_2": "Când sunt Alimentate, viteza transmisă catre alte Lanțuti de Distribuție în rând este dublată", - "create.ponder.chain_gearshift.text_3": "În schimb, oricând Schimbătorul de Viteze Alimentat nu este la sursă, viteza lui va fi injumătățită", - "create.ponder.chain_gearshift.text_4": "În ambele cazuri, Lanțurile de Distribuție în rând mereu rulează cu viteza dublă a Schimbătorului de Viteză Alimentat", - "create.ponder.chain_gearshift.text_5": "Folsind semnale analogice, raportul poate fi adjustat mai precis între 1 și 2", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "Transportarea Obiectelor în jos prin Tobogane", - "create.ponder.chute.text_1": "Toboganele pot transporta obiecte vertical către și de la inventare", - "create.ponder.chute.text_2": "Folosind Cheia, o fereastră poate fi creată", - "create.ponder.chute.text_3": "Plasând Toboganele selectând fețele laterale a altuia îl va face diagonal", - - "create.ponder.chute_upward.header": "Transportarea Obiectelor în sus prin Tobogane", - "create.ponder.chute_upward.text_1": "Folosind Ventilatoare Încapsulate în partea de sus sau jos, un Tobogan poate muta obiecte în sus", - "create.ponder.chute_upward.text_2": "Inspectând tobogane cu Ochelarii Inginerului dezvăluie informații despre direcția de mișcare", - "create.ponder.chute_upward.text_3": "Pe capătul 'blocat', obiectele vor trebui să fie introduse/luate de pe laterale", - - "create.ponder.clockwork_bearing.header": "Animarea Structurilor folosind Rulmente de Ceasornic", - "create.ponder.clockwork_bearing.text_1": "Rulmentele de Ceasornic se atașează de blocurile din fața lor", - "create.ponder.clockwork_bearing.text_2": "La primirea Forței de Rotație, structura va fi rotită conform ora zilei", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "Click-Dreapta pe rulment pentru a începe sau a opri animarea structurii", - "create.ponder.clockwork_bearing.text_6": "În fața acului de Oră, o structură secundară poate fi adăugată", - "create.ponder.clockwork_bearing.text_7": "Asigură-te că cele două structuri nu sunt atașate între ele prin super glue sau ceva asemănător", - "create.ponder.clockwork_bearing.text_8": "Acum, a doua structură se va roti ca Acul de Minut", - - "create.ponder.clutch.header": "Controlarea forței de rotație folosing un Ambreiaj", - "create.ponder.clutch.text_1": "Ambreiajele vor transmite rotația într-o linie dreaptă", - "create.ponder.clutch.text_2": "Când este alimentat de Redstone, întrerupe conexiunea", - - "create.ponder.cog_speedup.header": "Schimbarea Vitezelor cu Roți Dințate", - "create.ponder.cog_speedup.text_1": "Roțile Dințate Mari și Mici pot fi conectate diagonal", - "create.ponder.cog_speedup.text_2": "Schimbând de la roți dințate mari la mici, viteza transmisă va fi dublată", - "create.ponder.cog_speedup.text_3": "Schimbând în sens invers, viteza transmisă va fi înjumătățită", - - "create.ponder.cogwheel.header": "Transmisia forței de rotație folosind Roți Dințate", - "create.ponder.cogwheel.text_1": "Roțile Dințate vor transmite rotația către alte Roți Dințate adiacente", - "create.ponder.cogwheel.text_2": "Rotoare vecine conectate astfel de vor roti în direcții opuse", - - "create.ponder.cogwheel_casing.header": "Încapsularea Roților Dințate", - "create.ponder.cogwheel_casing.text_1": "Carcasele de Andezit sau Alamă pot fi folosite pentru a decora Roțile Dințate", - "create.ponder.cogwheel_casing.text_2": "Componentele adăugate după încapsulare nu se vor conecta cu ieșirile rotoarelor", - "create.ponder.cogwheel_casing.text_3": "Cheia poate fi folosită pentru a comuta conecxiuni", - - "create.ponder.creative_fluid_tank.header": "Rezervoare De Fluid Creativ", - "create.ponder.creative_fluid_tank.text_1": "Rezervoarele De Fluid Creativ pot fi folosite pentru a oferi o aprovizionare de fluid fără fund", - "create.ponder.creative_fluid_tank.text_2": "Click-Dreapta cu un obiect care conține fluid pentru a-l configura", - "create.ponder.creative_fluid_tank.text_3": "Acum, Rețelele de Conducte pot să tragă fără sfârșit fluidul atribuit din rezervor", - "create.ponder.creative_fluid_tank.text_4": "Orice Fluid împins înapoi într-un Rezervor De Fluid Creativ va fi golit", - - "create.ponder.creative_motor.header": "Generarea Forței de Rotație folosind Motoare Creativ", - "create.ponder.creative_motor.text_1": "Motoarele Creativ sunt o sursă compactă și configurabilă de Forță de Rotație", - "create.ponder.creative_motor.text_2": "Derulând pe panoul din spate schimbă RPM a ieșirii rotaționale a motorului", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "Procesarea Obiectectelor cu Roți de Zdrobit", - "create.ponder.crushing_wheels.text_1": "O pereche de Roți de Zdrobit poate pisa obiecte foarte eficient", - "create.ponder.crushing_wheels.text_2": "Intrarea lor Rotațională trebuie să le facă să se rotească între ele", - "create.ponder.crushing_wheels.text_3": "Obiectele aruncate sau introduse în vârf vor fi procesate", - "create.ponder.crushing_wheels.text_4": "De asemenea, obiectele pot fi introduse și luate prin medii automate", - - "create.ponder.deployer.header": "Folosirea Deployerului", - "create.ponder.deployer.text_1": "Dat Forță de Rotație, un Deployer poate imita interacțiuni ale jucătorului", - "create.ponder.deployer.text_10": "Click-Dreapte pe față pentru a-i da un Obiect să folosească", - "create.ponder.deployer.text_11": "De asemenea, obiectele pot fi introduse automat", - "create.ponder.deployer.text_12": "Deployerele car un slot de filtru", - "create.ponder.deployer.text_13": "Când un filtru este setat, se activează doar în timp ce ține un obiect potrivit", - "create.ponder.deployer.text_14": "Doar obiecte care se potrivesc cu filtrul pot fi introduse...", - "create.ponder.deployer.text_15": "...și doar obiectele nepotrivite vor fi extrase", - "create.ponder.deployer.text_2": "El mereu va interacționa cu poziția cu 2 blocuri în fața lui", - "create.ponder.deployer.text_3": "Blocurile direct în fața lui nu îl va impiedica", - "create.ponder.deployer.text_4": "Deployerele pot:", - "create.ponder.deployer.text_5": "Să Plaseze Blocuri,", - "create.ponder.deployer.text_6": "Să Folosească Obiecte,", - "create.ponder.deployer.text_7": "Să Activeze Blocuri,", - "create.ponder.deployer.text_8": "Să Recolteze Blocuri", - "create.ponder.deployer.text_9": "și Să Atace Mobi", - - "create.ponder.deployer_contraption.header": "Folosirea Deployerelor pe Invenții", - "create.ponder.deployer_contraption.text_1": "Oricând un Deployer este mișcat ca parte a unei Invenții animate...", - "create.ponder.deployer_contraption.text_2": "Se activează la fiecare locație vizitată, folosind obiecte din inventare oriunde de pe invenție", - "create.ponder.deployer_contraption.text_3": "Slotul De Filtru poate fi folosit pentru a specifica ce obiecte să tragă", - - "create.ponder.deployer_modes.header": "Modurile Deployerului", - "create.ponder.deployer_modes.text_1": "În mod implicit, un Deployer imită oo interacțiune de Click-Dreapta", - "create.ponder.deployer_modes.text_2": "În schimb, folosind o Cheie, poate fi setat să imite Click-Stânga", - - "create.ponder.deployer_processing.header": "Procesarea Obiectelor folosind Deployere", - "create.ponder.deployer_processing.text_1": "Cu un obiect potrivit ținut, Deployerele pot procesa obiecte oferite sub ele", - "create.ponder.deployer_processing.text_2": "Obiectele de Intrare pot fi aruncate sau plasate pe un Depot sub Deployer", - "create.ponder.deployer_processing.text_3": "Când obiectele sunt oferite pe o bandă...", - "create.ponder.deployer_processing.text_4": "Deployerul le va ține și le va procesa automat", - - "create.ponder.deployer_redstone.header": "Controlarea Deployerelor cu Redstone", - "create.ponder.deployer_redstone.text_1": "Când sunt alimentate de Redstone, Deployerele nu se vor activa", - "create.ponder.deployer_redstone.text_2": "Înainte să se oprească, Deployerul va termina orice ciclu început", - "create.ponder.deployer_redstone.text_3": "Astfel, un puls negativ poate fi folosit pentru a declanșa exact un ciclu de activare", - - "create.ponder.depot.header": "Folosirea Depoturilor", - "create.ponder.depot.text_1": "Depoturile pot servi ca elemente de bandă 'staționare'", - "create.ponder.depot.text_2": "Click-Dreapta pentru a plasa sau îndepărta manual Obiecte de la el", - "create.ponder.depot.text_3": "La fel ca Benzile Mecanice, poate oferi obiecte către procesare", - "create.ponder.depot.text_4": "...precum și oferirea Obiectelor Brațelor Mecanice", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "Folosirea Arzătorilor De Dogorală Goi", - "create.ponder.empty_blaze_burner.text_1": "Click-Dreapta pe Dogorală cu arzătorul gol pentru a-l captura", - "create.ponder.empty_blaze_burner.text_2": "Alternativ, Dogorelile pot fi conectate de la Spanwerele lor direct", - "create.ponder.empty_blaze_burner.text_3": "Acum ai o sursă de încălzire ideală pentru diverse mașinării", - "create.ponder.empty_blaze_burner.text_4": "Pentru scopuri Aerstetice, Arzătoarii De Dogoreală Goi pot fi de asemenea aprinși folosind Cremenele și Amnarul", - "create.ponder.empty_blaze_burner.text_5": "Flacăra poate fi tranformată folosind un obiect infuzat cu suflete", - "create.ponder.empty_blaze_burner.text_6": "Totuși, fără o dogoreală ele nu sunt potrivite pentru încălzire industrială", - - "create.ponder.encased_fluid_pipe.header": "Încapsularea Conductelor De Fluide", - "create.ponder.encased_fluid_pipe.text_1": "Carcasa De Cupru poate fi folosită pentru a decora Conducte De Fluid", - "create.ponder.encased_fluid_pipe.text_2": "Deoparte de a fi ascunse, Conductele Încapsulate sunt blocate în statul lor de conectivitate", - "create.ponder.encased_fluid_pipe.text_3": "Nu va mai reacționa la orice blocuri vecine fiind adăugate sau îndepărtate", - - "create.ponder.fan_direction.header": "Fluxul de Aer al unui Ventilator Încapsulat", - "create.ponder.fan_direction.text_1": "Ventilatoarele Încapsulate folosesc Forță De Rotație pentru a crea un Curent De AerEncased Fans use Rotational Force to create an Air Current", - "create.ponder.fan_direction.text_2": "Puterea și Direcția Fluzului depinde de Intrarea Rotațională", - - "create.ponder.fan_processing.header": "Procesarea Obiectelor folosind Ventilatoare Încapsulate", - "create.ponder.fan_processing.text_1": "Când trece prin lavă, Fluxul de Aer devine Încălzit", - "create.ponder.fan_processing.text_2": "Obiectele prinse în zonă vor fi topite", - "create.ponder.fan_processing.text_3": "Obiectele de mâncare aruncate aici ar fi incinerate", - "create.ponder.fan_processing.text_4": "În schimb , o amplasare de Afumare folosind Foc ar trebui folosit pentru ele", - "create.ponder.fan_processing.text_5": "Fluxurile De Aer trecând prin apă creează o Amplasare De SpălareAir Flows passing through water create a Washing Setup", - "create.ponder.fan_processing.text_6": "Niște procesare nouă interesantă poate fi făcută cu acest lucru", - "create.ponder.fan_processing.text_7": "Viteza Ventilatorului NU afectează viteza procesării, doar raza sa", - "create.ponder.fan_processing.text_8": "De asemenea, Procesarea Cu Ventilator poate fi aplicată la Obiecte pe Depoturi și Benzi", - - "create.ponder.fluid_pipe_flow.header": "Mișcarea Fluidelor folosind Conducte De Cupru", - "create.ponder.fluid_pipe_flow.text_1": "Conductele De Fluid pot conecta două sau mai multe surse și ținte", - "create.ponder.fluid_pipe_flow.text_2": "Folosind o Cheie, unui segment de conductă dreaptă poate fi dat o fereastră", - "create.ponder.fluid_pipe_flow.text_3": "Conductele cu fereastră nu se vor conecta cu alte segmente de conducte adiacente", - "create.ponder.fluid_pipe_flow.text_4": "Alimentate de Pompe Mecanice, Conductele pot transporta Fluide", - "create.ponder.fluid_pipe_flow.text_5": "La început, niciun fluid nu este extractat", - "create.ponder.fluid_pipe_flow.text_6": "Odată ce fluxul le conectează, capetele transferă treptat conținutul lor", - "create.ponder.fluid_pipe_flow.text_7": "Astfel, blocurile de Conducte însuși niciodată nu conțin 'fizic' niciun fluid", - - "create.ponder.fluid_pipe_interaction.header": "Scurgerea și Umplerea rezervoarelor de fluid", - "create.ponder.fluid_pipe_interaction.text_1": "Capetele ale unei rețele de conducte pot interacționa cu o varietate de blocuri", - "create.ponder.fluid_pipe_interaction.text_2": "Orice bloc cu capabilități de stocare de fluid pot fi umplute sau scurse", - "create.ponder.fluid_pipe_interaction.text_3": "Blocuri de sursă chiar în fața unui capăt deschis pot fi luate...", - "create.ponder.fluid_pipe_interaction.text_4": "...în timp ce vărsarea în spații goale poate crea surse de fluid", - "create.ponder.fluid_pipe_interaction.text_5": "De asemenea, Conductele extrag fluide dintr-o sumedenii de alte blocuri direct", - - "create.ponder.fluid_tank_sizes.header": "Dimensiunile unui Rezervor De Fluid", - "create.ponder.fluid_tank_sizes.text_1": "Rezervoarele De Fluid pot fi combinate pentru a crește capacitatea totală", - "create.ponder.fluid_tank_sizes.text_2": "Pătratul lor de bază poate fi până la 3 blocuri lățime...", - "create.ponder.fluid_tank_sizes.text_3": "...și crește în înălțime cu mai mult de 30 de straturi suplimentare", - "create.ponder.fluid_tank_sizes.text_4": "Folosind o Cheie, fereastra unui rezervor poate fi comutată", - - "create.ponder.fluid_tank_storage.header": "Stocarea Fluidelor în Rezervoare de Fluid", - "create.ponder.fluid_tank_storage.text_1": "Rezervoarele De Fluid pot fi folosite pentru stocarea unor cantități mari de fluid", - "create.ponder.fluid_tank_storage.text_2": "Rețelele de Conducte pot să împingă și să tragă fluide din orice parte", - "create.ponder.fluid_tank_storage.text_3": "Fluidul conținut poate fi măsurat de către un Comparator", - "create.ponder.fluid_tank_storage.text_4": "Totuși, în modul de Supraviețuire Fluidele nu pot fi adăugate sau luate manual", - "create.ponder.fluid_tank_storage.text_5": "Poți folosi Bazine, Scurgeri De Obiecte și Duze pentru a scurge sau a umple obiecte care conțin fluid", - - "create.ponder.funnel_compat.header": "Compatibilitatea Pâlniilor", - "create.ponder.funnel_compat.text_1": "Pâlniile ar trebui să interacționeze frumos de asemenea cu o varietate de alte componente.", - "create.ponder.funnel_compat.text_2": "Ferăstraie Verticale", - "create.ponder.funnel_compat.text_3": "Depoturi", - "create.ponder.funnel_compat.text_4": "Scurgeri De Obiecte", - - "create.ponder.funnel_direction.header": "Direcția Transferului", - "create.ponder.funnel_direction.text_1": "Plasat normal, trage obiecte din inventar.", - "create.ponder.funnel_direction.text_2": "Plasat în timpul furișării, pune obiecte în inventar.", - "create.ponder.funnel_direction.text_3": "Folosind o cheie, pâlnia poate fi răsturnată după plasare.", - "create.ponder.funnel_direction.text_4": "Aceleași reguli vor fi aplicate pentru majoritatea orientărilor.", - "create.ponder.funnel_direction.text_5": "Pâlniile pe benzi vor extracta/introduce în funcție de direcța ei de mișcare.", - - "create.ponder.funnel_intro.header": "Folosirea Pâlniilor", - "create.ponder.funnel_intro.text_1": "Pâlniile sund ideale pentru transferarea obiectelor către și de la inventare.", - - "create.ponder.funnel_redstone.header": "Control redstone", - "create.ponder.funnel_redstone.text_1": "Puterea redstone va preveni orice pâlnie să acționeze", - - "create.ponder.funnel_transfer.header": "Transfer direct", - "create.ponder.funnel_transfer.text_1": "Pâlniile nu pot niciodată să transfere între inventare închise direct.", - "create.ponder.funnel_transfer.text_2": "Toboganele sau Toboganele deștepte ar putea să fie mai potrivite pentru astfel de scopuri.", - "create.ponder.funnel_transfer.text_3": "Același lucru se aplică pentru mișcare orizontală. O bandă mecanică ar trebui să ajute aici.", - - "create.ponder.gantry_carriage.header": "Folosirea Cărucioarelor Portale", - "create.ponder.gantry_carriage.text_1": "Cărucioarele Portale pot monta și aluneca de-a lungul unui Rotor Portal.", - "create.ponder.gantry_carriage.text_2": "Amplasările de portale pot mișca Blocuri atașate.", - - "create.ponder.gantry_cascaded.header": "Portale în Cascadă", - "create.ponder.gantry_cascaded.text_1": "Rotoarele portale se atașează cu un cărucior fără nevoie de super glue", - "create.ponder.gantry_cascaded.text_2": "Același lucru se aplică pentru cărucioarele care sunt pe Rotoare Portale", - "create.ponder.gantry_cascaded.text_3": "Astfel, un sistem portal poate fi în cascadă pentru a acoperi multiple axe de mișcare", - - "create.ponder.gantry_direction.header": "Direcția de Mișcare a unui Portal", - "create.ponder.gantry_direction.text_1": "Rotoarele Portale pot avea orientări opuse", - "create.ponder.gantry_direction.text_2": "Direcția de mișcare a cărucioarelor depind de orientarea rotoarelor lor", - "create.ponder.gantry_direction.text_3": "...precum și de direcția de rotașie a rotorului", - "create.ponder.gantry_direction.text_4": "Aceleasi reguli se aplică pentru rotația propagată", - - "create.ponder.gantry_redstone.header": "Propagarea de Putere a Portalelor", - "create.ponder.gantry_redstone.text_1": "Rotoarele portale alimentate de redstone opresc mișcarea cărucioarelor lor", - "create.ponder.gantry_redstone.text_2": "În schimb, forța lui rotațională este transmisă către rotorul de ieșire a căruciorului", - - "create.ponder.gantry_shaft.header": "Folosirea Rotoarelor Portale", - "create.ponder.gantry_shaft.text_1": "Rotoarele Portale formează baza unui sistem portal. Cărucioarele atațate se vor mișca de-a lungul lor.", - "create.ponder.gantry_shaft.text_2": "Sistemele portal pot muta Blocuri atașate.", - - "create.ponder.gearbox.header": "Transmisia forței de rotație folosind Cutii De Viteze", - "create.ponder.gearbox.text_1": "Sărirea între axe de rotație poate deveni voluminos repede", - "create.ponder.gearbox.text_2": "O Cutie De Viteze este echivalentul mai compact al acestui sistem", - "create.ponder.gearbox.text_3": "Rotoarele după colțuri se rotesc în direcții oglindite", - "create.ponder.gearbox.text_4": "Conexiunile drepte vor fi inversate", - - "create.ponder.gearshift.header": "Controlarea forței de rotație folosind un Schimbător De Viteze", - "create.ponder.gearshift.text_1": "Schimbătoarele De Viteze vor transmite rotație într-o singură direcție", - "create.ponder.gearshift.text_2": "Când sunt alimentate de Redstone, inversează transmisia", - - "create.ponder.hand_crank.header": "Generarea Forței De Rotație folosind Manivele", - "create.ponder.hand_crank.text_1": "Manivelele pot fi folosite de către jucători pentru a aplica forță de rotație manual", - "create.ponder.hand_crank.text_2": "Ține apăsat Click-Dreapta pentru a o roti În Sens Invers Acelor De Ceasornic", - "create.ponder.hand_crank.text_3": "Viteza ei transmisă este relativ ridicată", - "create.ponder.hand_crank.text_4": "Furișează-te și ține apăsat Click Dreapta pentru a o roti În Sensul Acelor De Ceasornic", - - "create.ponder.hose_pulley.header": "Umplerea și Scurgerea surselor folosind Scripete De Furtun", - "create.ponder.hose_pulley.text_1": "Scripetele De Furtun pot fi folosite pentru a umple sau pentru a scurge corpuri mari de Fluid", - "create.ponder.hose_pulley.text_2": "Cu Intrarea Cinetică, înălțimea furtunului scripetelor poate fi controlat", - "create.ponder.hose_pulley.text_3": "Scripetele se retrage în timp ce intrarea de rotație este inversată", - "create.ponder.hose_pulley.text_4": "Pe partea opusă, conducte pot fi conectate", - "create.ponder.hose_pulley.text_5": "Rețele de conducte atașate pot ori să ofere fluid către furtun...", - "create.ponder.hose_pulley.text_6": "...ori să tragă din el, scurgând bazinul în schimb", - "create.ponder.hose_pulley.text_7": "Viteza de Umplere și de Scurgere depinde în totalitate de debitul rețelei de fluid", - - "create.ponder.hose_pulley_infinite.header": "Umplerea și Scurgerea Pasivă a corpurilor mari de Fluid", - "create.ponder.hose_pulley_infinite.text_1": "Când poziționezi Scripetele De Furtun într-un ochean destul de mare...", - "create.ponder.hose_pulley_infinite.text_2": "Va oferi/dispune fluide fără a afecta sursa", - "create.ponder.hose_pulley_infinite.text_3": "Rețelele de conducte pot lua fără limită fluide de la/către scripete asemănătoare", - - "create.ponder.hose_pulley_level.header": "Nivelul de Umplere și Scurgere a Scripetelor de Furtun", - "create.ponder.hose_pulley_level.text_1": "În timp ce sunt retrase complet, Scripetele de Furtun nu pot opera", - "create.ponder.hose_pulley_level.text_2": "Scurgerea merge de sus în jos", - "create.ponder.hose_pulley_level.text_3": "Nivelul suprafeței va ajunge să fie chiar sub locul unde furtunul se termină furtunul", - "create.ponder.hose_pulley_level.text_4": "Umplerea merge de jos în sus", - "create.ponder.hose_pulley_level.text_5": "Bazinul umplut nu va crește dincolo de stratul deasupra capătului de furtun", - - "create.ponder.item_drain.header": "Golirea Rezervoarelor De Fluid folosind Scurgeri De Obiecte", - "create.ponder.item_drain.text_1": "Scurgerile De Obiecte pot extrage fluide din obiecte", - "create.ponder.item_drain.text_2": "Click-Dreapta pe el pentru a turna fluide din obiectul tău ținut în el", - "create.ponder.item_drain.text_3": "Când obiectele sunt introduse din lateral...", - "create.ponder.item_drain.text_4": "...se rostogolesc peste, golindu-și fluidul conținut", - "create.ponder.item_drain.text_5": "Rețelele De Conducte pot acum să tragă fluidul din intermediarul intern al scurgerii", - - "create.ponder.item_vault_sizes.header": "Dimensiunile unui Seif De Obiecte", - "create.ponder.item_vault_sizes.text_1": "Seifele De Obiecte pot fi combinate pentru a crește capacitatea totală", - "create.ponder.item_vault_sizes.text_2": "Pătratul lor de bază poate fi până la 3 blocuri lățime...", - "create.ponder.item_vault_sizes.text_3": "...și cresc în lungime de 3 ori diametrul lor", - - "create.ponder.item_vault_storage.header": "Stocarea Obiectelor în Seife", - "create.ponder.item_vault_storage.text_1": "Seifele de Obiecte pot fi folosite pentru a stoca cantități mari de obiecte", - "create.ponder.item_vault_storage.text_2": "Totuși, conținuturile nu pot fi adăugate sau luate manual", - "create.ponder.item_vault_storage.text_3": "Orice component pentru transfer de obiecte poate atât să introducă...", - "create.ponder.item_vault_storage.text_4": "...cât și să ia conținuturi din acest recipient", - - "create.ponder.large_cogwheel.header": "Transmiterea forței de rotație folosind Roți Dințate Mari", - "create.ponder.large_cogwheel.text_1": "Roțile dințate mari se pot conecta între ele la unghiuri potrivite", - "create.ponder.large_cogwheel.text_2": "Va ajuta transmiterea vitezei către alte axe de rotație", - - "create.ponder.linear_chassis_attachment.header": "Atașarea blocurilor folosind Șasiuri Liniare", - "create.ponder.linear_chassis_attachment.text_1": "Fețele deschise ale unui Șasiu Liniar pot fi făcute Lipicioase", - "create.ponder.linear_chassis_attachment.text_2": "Click din nou pentru a face partea opusă lipicioasă", - "create.ponder.linear_chassis_attachment.text_3": "Furișează-te și apasă Click-Dreapta cu o mână goală pentru a îndepărta mâzga", - "create.ponder.linear_chassis_attachment.text_4": "Fețele lipicioase a Șasiului Liniar vor atașa o linie de blocuri în fața lor", - "create.ponder.linear_chassis_attachment.text_5": "Folosind o Cheie, o Rază precisă poate fi specificată pentru acest șasiu", - "create.ponder.linear_chassis_attachment.text_6": "Ținând apăsat CTRL și derulând reglează raza a toate Blocurile De Șasiu atașate", - "create.ponder.linear_chassis_attachment.text_7": "Atașarea blocurilor cu orice altă față necesită folosința Super Glue-ului", - "create.ponder.linear_chassis_attachment.text_8": "Folosind aceste mecanici, structuri de orice formă se pot mișca sub forma unei Invenții", - - "create.ponder.linear_chassis_group.header": "Moving Linear Chassis in groups", - "create.ponder.linear_chassis_group.text_1": "Linear Chassis connect to identical Chassis blocks next to them", - "create.ponder.linear_chassis_group.text_2": "When one is moved by a Contraption, the others are dragged with it", - "create.ponder.linear_chassis_group.text_3": "Chassis of a different type or facing another direction will not attach", - - "create.ponder.mechanical_arm.header": "Configurarea Brațelor Mecanice", - "create.ponder.mechanical_arm.text_1": "Brațele Mecanice trebuie să le fie atribuite intrări și ieșiri înainte să fie plasate", - "create.ponder.mechanical_arm.text_2": "Click-Dreapta pe inventare în timp ce ții Brațul pentru a le atribui ca Ținte", - "create.ponder.mechanical_arm.text_3": "Click-Dreapta din nou pentru a comuta între Intrare (Albastru) și Ieșire (Portocaliu)", - "create.ponder.mechanical_arm.text_4": "Click-Stânga pe componente pentru a le îndepărta Selecția", - "create.ponder.mechanical_arm.text_5": "Odată plasat, Brațul Mecanic va viza blocurile selectate anterior", - "create.ponder.mechanical_arm.text_6": "Ele pot avea orice cantitate de intrări și ieșiri în raza lor", - "create.ponder.mechanical_arm.text_7": "Totuși, nu orice tip de Inventar poate fi interacționat direct", - "create.ponder.mechanical_arm.text_8": "Pâlniile și Depoturile pot ajuta sa treacă peste acel prag", - - "create.ponder.mechanical_arm_filtering.header": "Filtrarea Ieșirilor a Brațului Mecanic", - "create.ponder.mechanical_arm_filtering.text_1": "Intrări", - "create.ponder.mechanical_arm_filtering.text_2": "Ieșiri", - "create.ponder.mechanical_arm_filtering.text_3": "Uneori este de dorit ca țintele Brațului să fie restricționate de la potrivirea unui filtru", - "create.ponder.mechanical_arm_filtering.text_4": "De ele însuși, Brațele Mecanice nu oferă nicio opțiune pentru filtrat", - "create.ponder.mechanical_arm_filtering.text_5": "Totuși, Pâlniile De Alamă ca Ținte comunică filtrul lor propriu către Braț", - "create.ponder.mechanical_arm_filtering.text_6": "Brațul este destul de deștept încât să nu ia obiecte ce nu poate distribui", - - "create.ponder.mechanical_arm_modes.header": "Modurile de distribuție ale Brațului Mecanic", - "create.ponder.mechanical_arm_modes.text_1": "Intrare", - "create.ponder.mechanical_arm_modes.text_2": "Ieșiri", - "create.ponder.mechanical_arm_modes.text_3": "Oricând un Braț trebuie să aleagă intre ieșiri valide multiple...", - "create.ponder.mechanical_arm_modes.text_4": "...nu va acționa conform setării lui", - "create.ponder.mechanical_arm_modes.text_5": "Derulând cu o Cheie îți va permite să îl configurezi", - "create.ponder.mechanical_arm_modes.text_6": "Modul Robin Rotund pur și simplu circulă prin toate ieșirile care sunt valabile", - "create.ponder.mechanical_arm_modes.text_7": "Dacă o ieșire este incapabilă să ia mai multe obiecte, va fi sărită", - "create.ponder.mechanical_arm_modes.text_8": "Modul Robin Rotund Forțat nu va sări peste ieșiri niciodată, și în schimb va aștepta până când sunt libere", - "create.ponder.mechanical_arm_modes.text_9": "Preferă Prima Țintă prioritizează ieșirile selectate mai devreme când acest Braț a fost configurat", - - "create.ponder.mechanical_arm_redstone.header": "Controlarea Brațelor Mecanice cu Redstone", - "create.ponder.mechanical_arm_redstone.text_1": "Când este activat de Redstone, Brațele Mecanice nu se vor activa", - "create.ponder.mechanical_arm_redstone.text_2": "Înainte să se oprească, va termina orice ciclu început", - "create.ponder.mechanical_arm_redstone.text_3": "Astfel, un puls negativ poate fi folosit pentru a comuta exact un ciclu de activare", - - "create.ponder.mechanical_bearing.header": "Mișcarea Structurilor folosind Rulmentul Mecanic", - "create.ponder.mechanical_bearing.text_1": "Rulmentele Mecanice se atașează la blocurile din fața lor", - "create.ponder.mechanical_bearing.text_2": "La primirea Forței Rotaționale, o va asambla într-o Invenție Rotativă", - - "create.ponder.mechanical_crafter.header": "Amplasarea Meșterilor Mecanici", - "create.ponder.mechanical_crafter.text_1": "O mulțime de Meșteri Mecanici poate fi folosită pentru a automa orice Rețetă De Fabricare", - "create.ponder.mechanical_crafter.text_2": "Folosind o Cheie, calea Meșterului poate fi aranjată", - "create.ponder.mechanical_crafter.text_3": "Pentru o amplasare validă, toate căile trebuie să se unească într-o ieșire în orice parte", - "create.ponder.mechanical_crafter.text_4": "Ieșirile vor vi plasate în inventarul de la ieșire", - "create.ponder.mechanical_crafter.text_5": "Meșterii Mecanici necesită Forță Rotațională pentru a opera", - "create.ponder.mechanical_crafter.text_6": "Click-Dreapta pe față pentru a introduce Obiecte manual", - "create.ponder.mechanical_crafter.text_7": "Odată ce fiecare slot a unei căi conține un Obiect, procesul de lucrare va începe", - "create.ponder.mechanical_crafter.text_8": "Pentru rețetele care nu ocupă pe deplin amplasarea de meșter, startul poate fi forțat folosind un Puls Redstone", - - "create.ponder.mechanical_crafter_connect.header": "Conectarea Inventoarelor Meșterilor", - "create.ponder.mechanical_crafter_connect.text_1": "Obiectele pot fi introduse Meșterilor automat", - "create.ponder.mechanical_crafter_connect.text_2": "Folosind Cheia pe spatele lor, intrările Meșterilor Mecanici pot fi combinate", - "create.ponder.mechanical_crafter_connect.text_3": "Toți Meșterii conectați pot fi accesați acum de aceeași locație de intrare", - - "create.ponder.mechanical_crafter_covers.header": "Acoperirea sloturilor Meșterilor Mecanici", - "create.ponder.mechanical_crafter_covers.text_1": "Unele rețete vor necesita Meșteri suplimentari pentru a acoperi golurile în cale", - "create.ponder.mechanical_crafter_covers.text_2": "Folosind Capace De Slot, Meșterii pot fi setați să se comporte ca un Slot Gol în aranjament", - "create.ponder.mechanical_crafter_covers.text_3": "Intrările Împărțite create cu Cheia pe spate pot să ajungă de asemenea peste Meșteri acoperiți", - - "create.ponder.mechanical_drill.header": "Spargerea Blocurilor cu Burghiul Mecanic", - "create.ponder.mechanical_drill.text_1": "Când îi este dat Forță De Rotație, un Burgiu Mecanic va sparge blocuri direct în fața lui", - "create.ponder.mechanical_drill.text_2": "Viteza lui de spart depinde de Intrarea De Rotație", - - "create.ponder.mechanical_drill_contraption.header": "Folosirea Burghiului Mecanic pe Invenții", - "create.ponder.mechanical_drill_contraption.text_1": "Oricând Burghiile sunt mișcate ca o parte dintr-o Invenție animată...", - "create.ponder.mechanical_drill_contraption.text_2": "...ele vor sparge blocurile pe care invenția le lovește", - - "create.ponder.mechanical_harvester.header": "Folosirea Combinei Mecanice pe Invenții", - "create.ponder.mechanical_harvester.text_1": "Oricând Combinele sunt mișcate ca o parte dintr-o Invenție animată...", - "create.ponder.mechanical_harvester.text_2": "Ele vor recolta li reseta orice cultură matură în calea lor", - - "create.ponder.mechanical_mixer.header": "Procesarea Obiectelor cu Mixerul Mecanic", - "create.ponder.mechanical_mixer.text_1": "Cu un Mixer și un Bazin, unele Rețete De Fabricare pot fi automate", - "create.ponder.mechanical_mixer.text_2": "Rețetele valabile includ orice Rețetă De Fabricare Fără Formă, plus câteva extra", - "create.ponder.mechanical_mixer.text_3": "Unele dintre aceste rețete ar putea necesita căldura unui Arzător De Dogoreală", - "create.ponder.mechanical_mixer.text_4": "Slotul de filtru poate fi folosit în cazul în care două rețete se contrazic.", - - "create.ponder.mechanical_piston.header": "Mișcarea Structurilor folosind Pistoane Mecanice", - "create.ponder.mechanical_piston.text_1": "Pistoanele Mecanice pot mișca blocuri în fața lor", - "create.ponder.mechanical_piston.text_2": "Viteza și direcția mișcării depinde de Intrarea De Rotație", - "create.ponder.mechanical_piston.text_3": "Pistoanele Mecanice Lipicioase pot trage blocurile atașate înapoi", - - "create.ponder.mechanical_piston_modes.header": "Modurile De Mișcare ale unui Piston Mecanic", - "create.ponder.mechanical_piston_modes.text_1": "Oricând Pistoanele se opresc din mișcare, structura mișcată revine la blocuri", - "create.ponder.mechanical_piston_modes.text_2": "Poate fi configurat să nu revină niciodată la blocuri solide, sau doar la locația de unde a început", - - "create.ponder.mechanical_plough.header": "Folosind Pluguri Mecanice pe Invenții", - "create.ponder.mechanical_plough.text_1": "Oricând Plugurile sunt mișcate ca o parte dintr-o Invenție animată...", - "create.ponder.mechanical_plough.text_2": "...ele vor sparge blocuri fără un hitbox de coliziune solid", - "create.ponder.mechanical_plough.text_3": "În plus, plugurile pot crea teren agricol", - "create.ponder.mechanical_plough.text_4": "...ele pot de asemenea să lanseze entități fără să le rănească", - - "create.ponder.mechanical_press.header": "Procesarea Obiectelor cu Presa Mecanică", - "create.ponder.mechanical_press.text_1": "Presa Mecanică poate procesa obiecte oferite sub ea", - "create.ponder.mechanical_press.text_2": "Obiectele De Intrare pot fi aruncate sau plasate pe un Depot sub Presă", - "create.ponder.mechanical_press.text_3": "Când obiectele sunt oferite pe o bandă...", - "create.ponder.mechanical_press.text_4": "Presa le va ține și le va procesa automat", - - "create.ponder.mechanical_press_compacting.header": "Compactarea obiectelor cu Presa Mecanică", - "create.ponder.mechanical_press_compacting.text_1": "Presarea obiectelor ținute într-un Bazin le va face să fie Compactate", - "create.ponder.mechanical_press_compacting.text_2": "Compacyatea include orice Rețetă De Fabricare de 2x2 sau 3x3, plus câteva extra", - "create.ponder.mechanical_press_compacting.text_3": "Unele dintre aceste rețete ar putea necesită căldura unui Arzător De Dogoreală", - "create.ponder.mechanical_press_compacting.text_4": "Slotul de filtru poate fi folosit în cazul în care două rețete se contrazic.", - - "create.ponder.mechanical_pump_flow.header": "Transportarea Fluidului folosind Pompe Mecanice", - "create.ponder.mechanical_pump_flow.text_1": "Pompele Mecanice conduc fluzul rețelelor de conducte atașate lor", - "create.ponder.mechanical_pump_flow.text_2": "Când este alimentată, săgeata lor indică direcția fluxului", - "create.ponder.mechanical_pump_flow.text_3": "Rețeaua din spate trage fluide acum...", - "create.ponder.mechanical_pump_flow.text_4": "...în timp ce rețeaua din față o tranferă în exterior", - "create.ponder.mechanical_pump_flow.text_5": "Inversarea rotației de intrare inversează direcția fluxului", - "create.ponder.mechanical_pump_flow.text_6": "Folosește o Cheie pentru a inversa orientarea pompelor manual", - - "create.ponder.mechanical_pump_speed.header": "Debitul Pompelor Mecanice", - "create.ponder.mechanical_pump_speed.text_1": "Indiferent de viteză, Pompele Mecanice afectează conductele conectate până la 16 blocuri distanță", - "create.ponder.mechanical_pump_speed.text_2": "Accelerând intrarea de rotație schimbă propagarea vitezei fluxului...", - "create.ponder.mechanical_pump_speed.text_3": "...precum și cât de rapid sunt tranferate fluidele", - "create.ponder.mechanical_pump_speed.text_4": "Pompele își pot combina debitele lor în rețelele de conducte partajate", - "create.ponder.mechanical_pump_speed.text_5": "Alternarea orientației lor poate ajuta să alinieze direcțiile lor de flux", - - "create.ponder.mechanical_saw_breaker.header": "Tăierea Copacilor cu Ferăstrăul Mecanic", - "create.ponder.mechanical_saw_breaker.text_1": "Când îi este dat Forță De Rotație, un Ferăstrău Mecanic va tăia copacii care sunt direct în fața lui", - "create.ponder.mechanical_saw_breaker.text_2": "Pentru a tăia copacul în plin, Ferăstrăul trebuie să spargă ultimul bloc de care este conectat cu solul", - - "create.ponder.mechanical_saw_contraption.header": "Folosirea Ferăstraielor Mecanice pe Invenții", - "create.ponder.mechanical_saw_contraption.text_1": "Oricând Ferăstraiele sunt mișcate ca o parte dintr-o Invenție animată...", - "create.ponder.mechanical_saw_contraption.text_2": "...ele vor tăia orice copaci pe care invenția îi lovește", - - "create.ponder.mechanical_saw_processing.header": "Procesarea Obiectelor pe Ferăstrăul Mecanic", - "create.ponder.mechanical_saw_processing.text_1": "Ferăstraiele Mecanice care stau cu fața în sus pot procesa o varietate de obiecte", - "create.ponder.mechanical_saw_processing.text_2": "Obiectul procesat se mișcă mereu împotriva intrării de rotație contra ferăstrăului", - "create.ponder.mechanical_saw_processing.text_3": "Ferăstraiele pot lucra în linie cu Benzi Mecanice", - "create.ponder.mechanical_saw_processing.text_4": "Când un ingredient are rezultate posibile multiple, slotul de filtru îl poate specifica", - "create.ponder.mechanical_saw_processing.text_5": "Fără vreun filtru, Ferăstrăul ar circula prin toate rezultatele în schimb", - - "create.ponder.millstone.header": "Procesarea Obiectelor în Moara De Piatră", - "create.ponder.millstone.text_1": "Morile De Piatră procesează obiecte prin măcinarea lor", - "create.ponder.millstone.text_2": "Ele pot fi alimentate dintr-o parte folosind roți dințate", - "create.ponder.millstone.text_3": "Aruncă sau Introduce obiecte în vârf", - "create.ponder.millstone.text_4": "După ceva timp, rezultatul poate fi obținut prin Click-Dreapta", - "create.ponder.millstone.text_5": "Ieșirile pot fi extrase de asemenea prin automare", - - "create.ponder.nixie_tube.header": "Folosirea Tuburilor Nixie", - "create.ponder.nixie_tube.text_1": "Când sunt alimentate de Redstone, Tuburile Nixie vor afișa puterea semnalului redstone", - "create.ponder.nixie_tube.text_2": "Folosind etichete de nume editate cu o nicovală, text personalizat poate fi afișat", - "create.ponder.nixie_tube.text_3": "Click-Dreapta cu Colorant pentru a le schimba culoarea de afișare", - - "create.ponder.piston_pole.header": "Brațe De Extensie De Piston", - "create.ponder.piston_pole.text_1": "Fără Brațe atașate, un Piston Mecanic nu se poate mișca", - "create.ponder.piston_pole.text_2": "Lungimea unui braț adăugat în spatele lui determină Raza De Extensie", - - "create.ponder.portable_fluid_interface.header": "Schimb De Fluide în Invenție", - "create.ponder.portable_fluid_interface.text_1": "Rezervoarele De Fluid pe invenții mișcătoare nu pot fi accesate de nicio conductă", - "create.ponder.portable_fluid_interface.text_2": "Acest component oate interacționa cu rezervoare de fluid fără nevoia de a opri invenția", - "create.ponder.portable_fluid_interface.text_3": "Plasează alta cu o gaură de 1 sau 2 blocuri între", - "create.ponder.portable_fluid_interface.text_4": "Oricând trec una pe lângă cealaltă, ele se vor angaja într-o conexiune", - "create.ponder.portable_fluid_interface.text_5": "În timp ce sunt angajate, interfața staționară va reprezenta TOATE Rezervoarele de pe invenție", - "create.ponder.portable_fluid_interface.text_6": "Acum fluid poate fi introdus...", - "create.ponder.portable_fluid_interface.text_7": "...sau extractat din invenție", - "create.ponder.portable_fluid_interface.text_8": "După ce niciun conținut nu a fost schimbat pentru un timp, invenția își va continua drumul", - - "create.ponder.portable_storage_interface.header": "Schimbare De Stocare în Invenție", - "create.ponder.portable_storage_interface.text_1": "Inventarele pe invenții mișcătoare nu pot fi accesate de către jucători.", - "create.ponder.portable_storage_interface.text_2": "Acest component poate interacționa cu depozitoare fără nevoia de a opri invenția.", - "create.ponder.portable_storage_interface.text_3": "Plasează alta cu o gaură de 1 sau 2 blocuri între", - "create.ponder.portable_storage_interface.text_4": "Oricând trec una pe lângă alta, ele se vor angaja într-o conexiune", - "create.ponder.portable_storage_interface.text_5": "În timp ce sunt angajate, interfața staționară va reprezenta TOATE inventariile de pe invenție", - "create.ponder.portable_storage_interface.text_6": "Acum obiecte pot fi introduse...", - "create.ponder.portable_storage_interface.text_7": "...sau extrase din invenție", - "create.ponder.portable_storage_interface.text_8": "După ce niciun obiect nu au mai fost schimbate pentru un timp, invenția își va continua drumul", - - "create.ponder.portable_storage_interface_redstone.header": "Control Redstone", - "create.ponder.portable_storage_interface_redstone.text_1": "Puterea redstone va preveni interfața staționară de la angajare", - - "create.ponder.powered_latch.header": "Controlarea semnalelor folosind Maneta Alimentată", - "create.ponder.powered_latch.text_1": "Manetele Alimentate sunt Manete controlabile cu redstone", - "create.ponder.powered_latch.text_2": "Semnalele din spate o pornesc", - "create.ponder.powered_latch.text_3": "Semnalele din laterală o opresc din nou", - "create.ponder.powered_latch.text_4": "Manetele alimentate pot fi de asemenea comutate manual", - - "create.ponder.powered_toggle_latch.header": "Controlarea semnalelor folosind Maneta Alimentată Comutatoare", - "create.ponder.powered_toggle_latch.text_1": "Manetele Alimentate Comutatoare sunt Manete controlabile cu redstone", - "create.ponder.powered_toggle_latch.text_2": "Semnalele din pate îi vor comuta starea", - "create.ponder.powered_toggle_latch.text_3": "...pornită și înapoi oprită", - "create.ponder.powered_toggle_latch.text_4": "Manetele alimentate comutatoare pot fi de asemenea comutate manual", - - "create.ponder.pulse_extender.header": "Controlarea semnalelor folosind Prelungitoarele De Puls", - "create.ponder.pulse_extender.text_1": "Prelungitoarele De Puls pot lungi un semnal care trece", - "create.ponder.pulse_extender.text_2": "Ele se activează dupa o întârziere scurtă...", - "create.ponder.pulse_extender.text_3": "...și se liniștesc pentru durata configurată", - "create.ponder.pulse_extender.text_4": "Folosind roata de la mouse, timpul de descărcare poate fi configurat", - "create.ponder.pulse_extender.text_5": "Durata configurată poate ajunge până la 30 de minute", - - "create.ponder.pulse_repeater.header": "Controlarea Semnalelor folosind Repetoarele De Puls", - "create.ponder.pulse_repeater.text_1": "Repetoarele De Puls emită un puls scurt la o întârziere", - "create.ponder.pulse_repeater.text_2": "Folosind roata de la mouse, timpul de încărcare poate fi configurat", - "create.ponder.pulse_repeater.text_3": "Întârzierile configurate pot ajunge până la 30 de minute", - - "create.ponder.radial_chassis.header": "Atașarea blocurilor folosind Șasiuri Radiale", - "create.ponder.radial_chassis.text_1": "Șasiurile Radiale se conectează cu blocuri de Șasiuri identice într-un rând", - "create.ponder.radial_chassis.text_2": "Când unul este mișcat de către o Invenție, celelalte sunt trase cu el", - "create.ponder.radial_chassis.text_3": "Fețele laterale ale unui Șasiu Radial pot fi făcute lipicioase", - "create.ponder.radial_chassis.text_4": "Click din nou pentru a face toate fețele lipicioase", - "create.ponder.radial_chassis.text_5": "Furișează-te și apasă Click-Dreapta cu o mână goală pentru a îndepărta mâzga", - "create.ponder.radial_chassis.text_6": "Oricând un Block este lângă o față lipicioase...", - "create.ponder.radial_chassis.text_7": "...va atașa toate blocurile accesibile într-o rază pe acel strat", - "create.ponder.radial_chassis.text_8": "Folosind o Cheie, o Rază prrecisă poate fi specificată pentru acest șasiu", - "create.ponder.radial_chassis.text_9": "Blocurile inaccesibile de către de oricare față lipicioasă nu se va atașa", - - "create.ponder.redstone_contact.header": "Contacte Redstone", - "create.ponder.redstone_contact.text_1": "Contactele Redstone față în față vor emite un semnal redstone", - "create.ponder.redstone_contact.text_2": "Acest lucru încă se aplică atunci când una dintre ele este o parte dintr-o Invenție mișcătoare", - - "create.ponder.redstone_link.header": "Folosirea Legăturilor De Redstone", - "create.ponder.redstone_link.text_1": "Legăturile De Redstone pot transmite semnale redstone fără vreun fir", - "create.ponder.redstone_link.text_2": "Click-Dreapta în timpul Furișării pentru a comuta modul de primire", - "create.ponder.redstone_link.text_3": "Un Click-Dreapta simplu cu o Cheie poate face același lucru", - "create.ponder.redstone_link.text_4": "Receptorii emit puterea redstone a transmițătorilor în 128 de blocuri", - "create.ponder.redstone_link.text_5": "Plasând obiecte în cele două sloturi poate specifica o Frecvență", - "create.ponder.redstone_link.text_6": "Doar legăturile cu Frecvențe potrivite vor comunica", - - "create.ponder.rope_pulley.header": "Mișcarea Structurilor folosind Scripete", - "create.ponder.rope_pulley.text_1": "Scripetele De Sfoară pot mișca bolocuri vertical când îi este dat Forță De Rotație", - "create.ponder.rope_pulley.text_2": "Direcția și Viteza mișcării depind de Intrarea De Rotație", - - "create.ponder.rope_pulley_attachment.header": "Mișcarea Scripetelor ca o parte dintr-o Invenție", - "create.ponder.rope_pulley_attachment.text_1": "Oricând Scripetele sunt ele însuși mutate pe o Invenție...", - "create.ponder.rope_pulley_attachment.text_2": "...structura ei atașată fa fi trasă cu ea", - "create.ponder.rope_pulley_attachment.text_3": "Nu uita că scripetele pot fi mișcate doar când sunt oprite", - - "create.ponder.rope_pulley_modes.header": "Modurile De Mișcare ale Scripetelui De Sfoară", - "create.ponder.rope_pulley_modes.text_1": "Oricând Scripetele se opresc din mișcare, structura mutată revine la blocuri", - "create.ponder.rope_pulley_modes.text_2": "Poate fi configurat să nu revină la blocuri solide niciodată, sau doar la locația de unde a început", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "Folosirea Controlorului De Viteză De Rotație", - "create.ponder.rotation_speed_controller.text_1": "Controlorii De Viteză De Rotație transmit rotație din axa lor către o Roată Dințată Mare deasupra lor", - "create.ponder.rotation_speed_controller.text_2": "Folosind intrarea de delurare pe fața lui, viteza transmisă poate fi configurată", - - "create.ponder.sail.header": "Asamblarea Morilor De Vânt folosind Vele", - "create.ponder.sail.text_1": "Velele sunt blocuri folositoare cu care poți crea Mori De Vânt", - "create.ponder.sail.text_2": "Ele se vor atașa cu blocuri și cu ele însățo fără nevoia de Super Glue sau de Blocuri De Șasiu", - "create.ponder.sail.text_3": "Click-Dreapta cu Colorant pentru a le picta", - "create.ponder.sail.text_4": "Click-Dreapta cu Foarfece pentru a le aduce înapoi în Rame", - - "create.ponder.sail_frame.header": "Asamblarea Morilor De Vânt folosind Rame De Vele", - "create.ponder.sail_frame.text_1": "ramele De Vele sunt blocuri folositoare cu care poți crea Mori De Vânt", - "create.ponder.sail_frame.text_2": "They will attach to blocks and each other without the need of Super Glue or Chassis Blocks", - - "create.ponder.sequenced_gearshift.header": "Controlarea Vitezei De Rotație folosind Schimbătoare De Viteză Secvențiale", - "create.ponder.sequenced_gearshift.text_1": "Schimbătoarele De Viteză Secvențiale transmit rotație urmărind o listă de instrucțiuni planificată", - "create.ponder.sequenced_gearshift.text_2": "Click-Dreapta pe el pentru a deschide Interfața De Configurare", - "create.ponder.sequenced_gearshift.text_3": "La primirea unui Semnal Redstone, va începe să își ruleze secvența configurată", - "create.ponder.sequenced_gearshift.text_4": "Odată ce a terminat, așteaptă după următorul Semnal Redstone și începe din nou", - "create.ponder.sequenced_gearshift.text_5": "Un comparator de redstone poate fi folosit pentru a citi progresul actual", - - "create.ponder.shaft.header": "Transmiterea forței de rotație folosind Rotoare", - "create.ponder.shaft.text_1": "Rotoarele vor transmite rotație într-o linie dreaptă.", - - "create.ponder.shaft_casing.header": "Încapsularea Rotoarelor", - "create.ponder.shaft_casing.text_1": "Carcasele de Alamă sau de Andezit pot fi folosite pentru a decora Rotoare", - - "create.ponder.smart_chute.header": "Filtrarea Obiectelor folosind Tobogane Inteligente", - "create.ponder.smart_chute.text_1": "Toboganele Inteligente sunt tobogane verticale cu control adițional", - "create.ponder.smart_chute.text_2": "Obiectele în slotul de filtru specifică exact pe pot extracta și transfera", - "create.ponder.smart_chute.text_3": "Folosește Roata De La Mouse pentru a specifica mărimea stackului extractat", - "create.ponder.smart_chute.text_4": "Puterea redstone va preveni Toboganele Inteligente să acționeze.", - - "create.ponder.smart_pipe.header": "Controlarea fluxului de Fluid folosind Conducte Inteligente", - "create.ponder.smart_pipe.text_1": "Conductele inteligente pot ajuta controlarea fluxurilor cu tipuri de fluid", - "create.ponder.smart_pipe.text_2": "Când este plasat direct la sursă, pot specifica tipul de fluid care să fie extractat", - "create.ponder.smart_pipe.text_3": "Pur și simplu apasă Click-Dreapta pe slotul lor de filtru cu orice obiect care conține fluidul dorit", - "create.ponder.smart_pipe.text_4": "Când este plasat mai jos în rețeaua de conducte, conductele inteligente vor lăsa doar fluidele potrivite să continue", - - "create.ponder.speedometer.header": "Monitorizarea informațiilor Cinetice folosind Vitezometrul", - "create.ponder.speedometer.text_1": "Vitezometrul afișează Viteza actuală a componentelor atașate", - "create.ponder.speedometer.text_2": "Când se poartă Ochelarii Inginerului, jucătorul primește informații mai detaliate de la Gabarit", - "create.ponder.speedometer.text_3": "Comparatoarele pot emite Semnale Redstone analogice relative la măsurătorile Vitezometrului", - - "create.ponder.spout_filling.header": "Umplerea Obiectelor folosind o Duză", - "create.ponder.spout_filling.text_1": "Duza poate umple obiecte care țin fluid oferite dedesubtul ei", - "create.ponder.spout_filling.text_2": "Conținutul unei Duze nu poate fi accesat manual", - "create.ponder.spout_filling.text_3": "În schimb, Conducte pot fi folosite pentru a o aproviziona cu fluide", - "create.ponder.spout_filling.text_4": "Obiectele de Intrare pot fi plasate pe un Depot sub Duză", - "create.ponder.spout_filling.text_5": "Când obiectele sunt oferite pe o bandă...", - "create.ponder.spout_filling.text_6": "Duza le va ține și le va procesa automat", - - "create.ponder.stabilized_bearings.header": "Invenții Stabilizate", - "create.ponder.stabilized_bearings.text_1": "Oricând Rulmentele Mecanice sunt ele înseși parte dintr-o Structură mișcătoare..", - "create.ponder.stabilized_bearings.text_2": "..ele vor încerca să se țină drepte", - "create.ponder.stabilized_bearings.text_3": "Încă odată, rulmentul se va atașa cu blocul din fața lui", - "create.ponder.stabilized_bearings.text_4": "Ca rezultat, sub-Invenția întreagă va sta dreaptă", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "Atașarea blocurilor folosind Abțipildul", - "create.ponder.sticker.text_1": "Abțipildele sunt ideale pentru atașament de blocuri controlate de Redstone", - "create.ponder.sticker.text_2": "La primirea unui semnal, își va comuta starea", - "create.ponder.sticker.text_3": "Dacă este acum mutat într-o invenție, blocul se va muta cu el", - "create.ponder.sticker.text_4": "Comutat încă odată, blocul nu mai este atașat", - - "create.ponder.stressometer.header": "Monitorizarea inormațiilor Cinetice folosind Stresometrul", - "create.ponder.stressometer.text_1": "Stresometrul afișează Capacitatea De Stres actuală a rețelei cinetice atașate", - "create.ponder.stressometer.text_2": "Când se poartă Ochelarii Inginerului, jucătorul primește informații mai detaliate de la Gabarit", - "create.ponder.stressometer.text_3": "Comparatoarele pot emite Semnale Redstone analogice relative la măsurătorile Stresometrului", - - "create.ponder.super_glue.header": "Atașarea blocurilor folosind Super Glue", - "create.ponder.super_glue.text_1": "Super Glue-ul poate fi folosit între oricare două blocuri", - "create.ponder.super_glue.text_2": "Blocurile atașate se vor mișca împreuna când sunt asamblate într-o Invenție", - "create.ponder.super_glue.text_3": "Oricând Super Glue-ul este pus în mâna opusă...", - "create.ponder.super_glue.text_4": "...blocurile adăugate vor fi lipite cu fața cu care au fost plasate automat", - "create.ponder.super_glue.text_5": "Super Glue-ul poate fi îndepărtat cu Click-Stânga", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "Generarea Forței De Rotație folosind Mânere De Supapă", - "create.ponder.valve_handle.text_1": "Mânerele De Supapă pot fi folosite de jucători pentru a aplica forță de rotație manual", - "create.ponder.valve_handle.text_2": "Ține apăsat Click-Dreapta pentru a o roti În Sensul Invers Acelor De Ceasornic", - "create.ponder.valve_handle.text_3": "Viteza transmisă este lentă și precisă", - "create.ponder.valve_handle.text_4": "Furișează-te și Apasă Click-Dreapta pentru a o roti În Sensul Acelor De Ceasornic", - "create.ponder.valve_handle.text_5": "Mânerele de supapă pot fi vopsite pentru scopuri aestetice", - - "create.ponder.valve_pipe.header": "Controlarea fluxului de Fluid folosind Supape", - "create.ponder.valve_pipe.text_1": "Conductele de supape ajută controlul fluidelor propagându-se prin rețele de conducte", - "create.ponder.valve_pipe.text_2": "Intrarea lor de rotor controlează dacă fluidul este permis actual", - "create.ponder.valve_pipe.text_3": "Dat Forță De Rotație în direcția deschiderii, supapa se va deschide", - "create.ponder.valve_pipe.text_4": "Poate fi închisă din nou prin inversarea rotației de intrare", - - "create.ponder.water_wheel.header": "Generarea Forței De Rotație folosind Roți De Apă", - "create.ponder.water_wheel.text_1": "Roțile De Apă atrag forță din Curente De Apă adiacente", - "create.ponder.water_wheel.text_2": "Cu cât mai multe fețe sunt alimentate, mai repede se va roti Roata De Apă", - "create.ponder.water_wheel.text_3": "Lamele Roții ar trebui să fie orientate contra fluxului", - "create.ponder.water_wheel.text_4": "Cu fața spre partea opusă, ele nu vor fi atât de eficiente", - - "create.ponder.weighted_ejector.header": "Folosirea Ejectorului Ponderat", - "create.ponder.weighted_ejector.text_1": "Furișează-te și apasă Click-Dreapta ținând un Ejector pentru a-i selecta locația țintei", - "create.ponder.weighted_ejector.text_10": "Este acum limitat la această mărime a stackului, și se activează doar când stackul ținut ajunge la această cantitate", - "create.ponder.weighted_ejector.text_11": "Alte entități vor declanșa mereu un Ejector când calcă pe ele", - "create.ponder.weighted_ejector.text_2": "Ejectorul plasat va lansa acum obiecte către locația marcată", - "create.ponder.weighted_ejector.text_3": "O țintă poate fi la orice înălțime sau distanță în rază", - "create.ponder.weighted_ejector.text_4": "Totuși, ele nu pot ejecta într-o parte", - "create.ponder.weighted_ejector.text_5": "Dacă nicio Șintă validă a fost selectată, va ținti pur și simplu blocul direct în față", - "create.ponder.weighted_ejector.text_6": "Aprovizinează-i Forță De Rotație pentru a-l încărca", - "create.ponder.weighted_ejector.text_7": "Obiectele plasate pe un ejector îl va cauza să se declanșeze", - "create.ponder.weighted_ejector.text_8": "Dacă Inventarele sunt țintite, ejectorul va aștepta până când este spațiu", - "create.ponder.weighted_ejector.text_9": "Folosind Cheia, o Mărime De Stack necesară poate fi configurată", - - "create.ponder.weighted_ejector_redstone.header": "Controlarea Ejectoarelor Ponderate cu Redstone", - "create.ponder.weighted_ejector_redstone.text_1": "Când sunt alimentate de Redstone, Ejectoarele nu se vor activa", - "create.ponder.weighted_ejector_redstone.text_2": "În plus, Observatoarele pot detecta când Ejectoarele se activează", - - "create.ponder.weighted_ejector_tunnel.header": "Împărțirea stackurilor de obiecte folosind Ejectoare Ponderate", - "create.ponder.weighted_ejector_tunnel.text_1": "Combinate cu Tunelele De Alamă, Ejectoarele pot împărți stackurile de obicecte de cantități specifice", - "create.ponder.weighted_ejector_tunnel.text_2": "În primul rând, configură Tunelul De Alamă la 'Preferă Cel Mai Apropiat'", - "create.ponder.weighted_ejector_tunnel.text_3": "Mărimea Stackului setată pe Ejector determină acum cantitatea care trebuie împărțită", - "create.ponder.weighted_ejector_tunnel.text_4": "În timp ce un stack now al mărimii configurate iese din ieșirea de pe laterală...", - "create.ponder.weighted_ejector_tunnel.text_5": "...restul își va continua drumul", - - "create.ponder.windmill_source.header": "Generarea Forței De Rotație folosind Rulmente De Moară De Vânt", - "create.ponder.windmill_source.text_1": "Rulmentele De Moară De Vânt se atașează cu blocul din fața lor", - "create.ponder.windmill_source.text_2": "Dacă sunt atașate destule blocuri velă cu acel bloc, poate acționa ca o Moară De Vânt", - "create.ponder.windmill_source.text_3": "Activată cu Click-Dreapta, Rulmentrul De Moară De Vând va începe să ofere Forță De Rotație", - "create.ponder.windmill_source.text_4": "Cantitatea de Blocuri Velă îi determină Viteza De Rotație", - "create.ponder.windmill_source.text_5": "Folosește o Cheie pentru a-i configura direcția de rotație", - "create.ponder.windmill_source.text_6": "Click-Dreapta pe Rulment oricând pentru a opri și a modifica Structura din nou", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "Invenții de Moară De Vânt", - "create.ponder.windmill_structure.text_1": "Orice Structură se pune ca o Moară De Vânt Validă, atâta timp cât conține cel puțin 8 Blocuri velă.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json deleted file mode 100644 index 2e34cb7cfe..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 1", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Акациевое окно", - "block.create.acacia_window_pane": "Панель из акациевого окна", - "block.create.adjustable_chain_gearshift": "Регулируемая цепная коробка передач", - "block.create.analog_lever": "Аналоговый рычаг", - "block.create.andesite_belt_funnel": "Андезитовая конвейерная воронка", - "block.create.andesite_casing": "Андезитовый корпус", - "block.create.andesite_encased_cogwheel": "Шестерня в андезитовом корпусе", - "block.create.andesite_encased_large_cogwheel": "Большая шестерня в андезитовом корпусе", - "block.create.andesite_encased_shaft": "Вал в андезитовом корпусе", - "block.create.andesite_funnel": "Андезитовая воронка", - "block.create.andesite_ladder": "Андезитовая лестница", - "block.create.andesite_pillar": "Андезитовая колонна", - "block.create.andesite_tunnel": "Андезитовый туннель", - "block.create.asurine": "Азурин", - "block.create.asurine_pillar": "Азуринновая колонна", - "block.create.basin": "Чаша", - "block.create.belt": "Конвейер", - "block.create.birch_window": "Берёзовое окно", - "block.create.birch_window_pane": "Панель из берёзового окна", - "block.create.black_nixie_tube": "Чёрный газоразрядный индикатор", - "block.create.black_sail": "Чёрный парус", - "block.create.black_seat": "Чёрное сиденье", - "block.create.black_toolbox": "Чёрный ящик для инструментов", - "block.create.black_valve_handle": "Чёрный ручной вентиль", - "block.create.blaze_burner": "Горелка всполоха", - "block.create.blue_nixie_tube": "Синий газоразрядный индикатор", - "block.create.blue_sail": "Синий парус", - "block.create.blue_seat": "Синее сиденье", - "block.create.blue_toolbox": "Синий ящик для инструментов", - "block.create.blue_valve_handle": "Синий ручной вентиль", - "block.create.brass_belt_funnel": "Латунная конвейерная воронка", - "block.create.brass_block": "Латунный блок", - "block.create.brass_casing": "Латунный корпус", - "block.create.brass_encased_cogwheel": "Шестерня в латунном корпусе", - "block.create.brass_encased_large_cogwheel": "Большая шестерня в латунном корпусе", - "block.create.brass_encased_shaft": "Вал в латунном корпусе", - "block.create.brass_funnel": "Латунная воронка", - "block.create.brass_ladder": "Латунная лестница", - "block.create.brass_tunnel": "Латунный туннель", - "block.create.brown_nixie_tube": "Коричневый газоразрядный индикатор", - "block.create.brown_sail": "Коричневый парус", - "block.create.brown_seat": "Коричневое сиденье", - "block.create.brown_toolbox": "Коричневый ящик для инструментов", - "block.create.brown_valve_handle": "Коричневый ручной вентиль", - "block.create.calcite_pillar": "Кальцитовая колонна", - "block.create.cart_assembler": "Сборщик вагонеток", - "block.create.chocolate": "Шоколад", - "block.create.chute": "Жёлоб", - "block.create.clockwork_bearing": "Часовой механизм", - "block.create.clutch": "Сцепление", - "block.create.cogwheel": "Шестерня", - "block.create.content_observer": "Наблюдатель за содержимым", - "block.create.controller_rail": "Контролирующие рельсы", - "block.create.controls": "Контроллер поезда", - "block.create.copper_backtank": "Медный баллон", - "block.create.copper_casing": "Медный корпус", - "block.create.copper_ladder": "Медная лестница", - "block.create.copper_shingle_slab": "Плита из медной черепицы", - "block.create.copper_shingle_stairs": "Ступеньки из медной черепицы", - "block.create.copper_shingles": "Медная черепица", - "block.create.copper_tile_slab": "Плита из медной плитки", - "block.create.copper_tile_stairs": "Ступеньки из медной плитки", - "block.create.copper_tiles": "Медная плитка", - "block.create.copper_valve_handle": "Медный ручной вентиль", - "block.create.creative_crate": "Творческий ящик", - "block.create.creative_fluid_tank": "Творческий жидкостный бак", - "block.create.creative_motor": "Творческий мотор", - "block.create.crimsite": "Кримзит", - "block.create.crimsite_pillar": "Кримзитовая колонна", - "block.create.crimson_window": "Багровое окно", - "block.create.crimson_window_pane": "Панель из багрового окна", - "block.create.crushing_wheel": "Колесо дробления", - "block.create.crushing_wheel_controller": "Контроллер колеса дробления", - "block.create.cuckoo_clock": "Часы с кукушкой", - "block.create.cut_andesite": "Резной андезит", - "block.create.cut_andesite_brick_slab": "Плита из резных андезитовых кирпичей", - "block.create.cut_andesite_brick_stairs": "Ступеньки из резного андезитового кирпича", - "block.create.cut_andesite_brick_wall": "Ограда из резных андезитовых кирпичей", - "block.create.cut_andesite_bricks": "Резные андезитовые кирпичи", - "block.create.cut_andesite_slab": "Резная андезитовая плита", - "block.create.cut_andesite_stairs": "Резные андезитовые ступеньки", - "block.create.cut_andesite_wall": "Резная андезитовая ограда", - "block.create.cut_asurine": "Резной азурин", - "block.create.cut_asurine_brick_slab": "Плита из резного азуринового кирпича", - "block.create.cut_asurine_brick_stairs": "Ступеньки из резного азуринового кирпича", - "block.create.cut_asurine_brick_wall": "Ограда из резных азуриновых кирпичей", - "block.create.cut_asurine_bricks": "Резные азуриновые кирпичи", - "block.create.cut_asurine_slab": "Резная азуриновая плита", - "block.create.cut_asurine_stairs": "Резные азуриновые ступеньки", - "block.create.cut_asurine_wall": "Резная азуриновая ограда", - "block.create.cut_calcite": "Резной кальцит", - "block.create.cut_calcite_brick_slab": "Плита из резных кальцитовых кирпичей", - "block.create.cut_calcite_brick_stairs": "Ступеньки из резных кальцитовых кирпичей", - "block.create.cut_calcite_brick_wall": "Ограда из резных кальцитовых кирпичей", - "block.create.cut_calcite_bricks": "Резные кальцитовые кирпичи", - "block.create.cut_calcite_slab": "Резная кальцитовая плита", - "block.create.cut_calcite_stairs": "Резные кальцитовые ступеньки", - "block.create.cut_calcite_wall": "Резная кальцитовая ограда", - "block.create.cut_crimsite": "Резной кримзит", - "block.create.cut_crimsite_brick_slab": "Плита из резного кримзитового кирпича", - "block.create.cut_crimsite_brick_stairs": "Ступеньки из резного кримзитового кирпича", - "block.create.cut_crimsite_brick_wall": "Ограда из резного кримзитового кирпича", - "block.create.cut_crimsite_bricks": "Резной кримзитовый кирпич", - "block.create.cut_crimsite_slab": "Резная кримзитовая плита", - "block.create.cut_crimsite_stairs": "Резные кримзитовые ступеньки", - "block.create.cut_crimsite_wall": "Резная кримзитовая ограда", - "block.create.cut_deepslate": "Резной глубинный сланец", - "block.create.cut_deepslate_brick_slab": "Плита из резных глубинносланцевых кирпичей", - "block.create.cut_deepslate_brick_stairs": "Ступеньки из резных глубинносланцевых кирпичей", - "block.create.cut_deepslate_brick_wall": "Ограда из резных глубинносланцевых кирпичей", - "block.create.cut_deepslate_bricks": "Резные глубинносланцевые кирпичи", - "block.create.cut_deepslate_slab": "Резная глубинносланцевая плита", - "block.create.cut_deepslate_stairs": "Резные глубинносланцевые ступеньки", - "block.create.cut_deepslate_wall": "Резная глубинносланцевая ограда", - "block.create.cut_diorite": "Резной диорит", - "block.create.cut_diorite_brick_slab": "Плита из резных диоритовых кирпичей", - "block.create.cut_diorite_brick_stairs": "Ступеньки из резных диоритовых кирпичей", - "block.create.cut_diorite_brick_wall": "Ограда из резных диоритовых кирпичей", - "block.create.cut_diorite_bricks": "Резные диоритовые кирпичи", - "block.create.cut_diorite_slab": "Резная диоритовая плита", - "block.create.cut_diorite_stairs": "Резные диоритовые ступеньки", - "block.create.cut_diorite_wall": "Резная диоритовая ограда", - "block.create.cut_dripstone": "Резной натёчный камень", - "block.create.cut_dripstone_brick_slab": "Плита из натёчнокаменного кирпича", - "block.create.cut_dripstone_brick_stairs": "Ступеньки из натёчнокаменного кирпича", - "block.create.cut_dripstone_brick_wall": "Ограда из натёчнокаменного кирпича", - "block.create.cut_dripstone_bricks": "Резные кирпичи из натёчного камня", - "block.create.cut_dripstone_slab": "Плита из резного натёчного камня", - "block.create.cut_dripstone_stairs": "Ступеньки из резного натёчного камня", - "block.create.cut_dripstone_wall": "Ограда из резного натёчного камня", - "block.create.cut_granite": "Резной гранит", - "block.create.cut_granite_brick_slab": "Плита из резных гранитных кирпичей", - "block.create.cut_granite_brick_stairs": "Ступеньки из резных гранитных кирпичей", - "block.create.cut_granite_brick_wall": "Ограда из резных гранитных кирпичей", - "block.create.cut_granite_bricks": "Резные гранитные кирпичи", - "block.create.cut_granite_slab": "Резная гранитная плита", - "block.create.cut_granite_stairs": "Резные гранитные ступеньки", - "block.create.cut_granite_wall": "Резная гранитная ограда", - "block.create.cut_limestone": "Резной известняк", - "block.create.cut_limestone_brick_slab": "Плита из резных известковых кирпичей", - "block.create.cut_limestone_brick_stairs": "Ступеньки из резных известковых кирпичей", - "block.create.cut_limestone_brick_wall": "Ограда из резных известковых кирпичей", - "block.create.cut_limestone_bricks": "Резные известковые кирпичи", - "block.create.cut_limestone_slab": "Резная известковая плита", - "block.create.cut_limestone_stairs": "Резные известковые ступеньки", - "block.create.cut_limestone_wall": "Резная известковая ограда", - "block.create.cut_ochrum": "Резной охрум", - "block.create.cut_ochrum_brick_slab": "Плита из резных охрумывых кирпичей", - "block.create.cut_ochrum_brick_stairs": "Ступеньки из резных охрумывых кирпичей", - "block.create.cut_ochrum_brick_wall": "Ограда из резных охрумывых кирпичей", - "block.create.cut_ochrum_bricks": "Резные охрумывые кирпичи", - "block.create.cut_ochrum_slab": "Резная охрумывая плита", - "block.create.cut_ochrum_stairs": "Резные охрумывые ступеньки", - "block.create.cut_ochrum_wall": "Резная ограда из охрума", - "block.create.cut_scorchia": "Резной тёмный пепел", - "block.create.cut_scorchia_brick_slab": "Плита из резного тёмнопеплового кирпича", - "block.create.cut_scorchia_brick_stairs": "Ступеньки из резного тёмнопеплового кирпича", - "block.create.cut_scorchia_brick_wall": "Ограда из резного тёмнопеплового кирпича", - "block.create.cut_scorchia_bricks": "Резные кирпичи из тёмного пепла", - "block.create.cut_scorchia_slab": "Резная плита из тёмного пепла", - "block.create.cut_scorchia_stairs": "Резные ступеньки из тёмного пепла", - "block.create.cut_scorchia_wall": "Резная ограда из тёмного пепла", - "block.create.cut_scoria": "Резной пепел", - "block.create.cut_scoria_brick_slab": "Плита из резного пеплового кирпича", - "block.create.cut_scoria_brick_stairs": "Ступеньки из резного пеплового кирпича", - "block.create.cut_scoria_brick_wall": "Ограда из резного пеплового кирпича", - "block.create.cut_scoria_bricks": "Резные пепловые кирпичи", - "block.create.cut_scoria_slab": "Плита из резного пепла", - "block.create.cut_scoria_stairs": "Ступеньки из резного пепла", - "block.create.cut_scoria_wall": "Ограда из резного пепла", - "block.create.cut_tuff": "Резной туф", - "block.create.cut_tuff_brick_slab": "Плита из резного туфового кирпича", - "block.create.cut_tuff_brick_stairs": "Ступеньки из резного туфового кирпича", - "block.create.cut_tuff_brick_wall": "Ограда из резного туфового кирпича", - "block.create.cut_tuff_bricks": "Резные туфовые кирпичи", - "block.create.cut_tuff_slab": "Резная туфовая плита", - "block.create.cut_tuff_stairs": "Резные туфовые ступеньки", - "block.create.cut_tuff_wall": "Резная туфовая ограда", - "block.create.cut_veridium": "Резной веридиум", - "block.create.cut_veridium_brick_slab": "Плита из резного веридиумого кирпича", - "block.create.cut_veridium_brick_stairs": "Ступеньки из резного веридиумого кирпича", - "block.create.cut_veridium_brick_wall": "Ограда из резного веридиумого кирпича", - "block.create.cut_veridium_bricks": "Резные веридиумывые кирпичи", - "block.create.cut_veridium_slab": "Плита из резного веридиума", - "block.create.cut_veridium_stairs": "Ступеньки из резного веридиума", - "block.create.cut_veridium_wall": "Ограда из резного веридиума", - "block.create.cyan_nixie_tube": "Бирюзовый газоразрядный индикатор", - "block.create.cyan_sail": "Бирюзовый парус", - "block.create.cyan_seat": "Бирюзовое сиденье", - "block.create.cyan_toolbox": "Бирюзовый ящик для инструментов", - "block.create.cyan_valve_handle": "Бирюзовый ручной вентиль", - "block.create.dark_oak_window": "Окно из тёмного дуба", - "block.create.dark_oak_window_pane": "Панель из окна из тёмного дуб", - "block.create.deepslate_pillar": "Глубинносланцевая колонна", - "block.create.deepslate_zinc_ore": "Цинконосный глубинный сланец", - "block.create.deployer": "Автономный активатор", - "block.create.depot": "Депо", - "block.create.diorite_pillar": "Диоритовая колонна", - "block.create.display_board": "Механическое табло", - "block.create.display_link": "Передатчик информации", - "block.create.dripstone_pillar": "Колонна из натёчного камня", - "block.create.encased_chain_drive": "Цепной привод в корпусе", - "block.create.encased_fan": "Вентилятор в корпусе", - "block.create.encased_fluid_pipe": "Жидкостная труба в корпусе", - "block.create.exposed_copper_shingle_slab": "Плита из потемневший медной черепицы", - "block.create.exposed_copper_shingle_stairs": "Ступеньки из потемневший медной черепицы", - "block.create.exposed_copper_shingles": "Потемневшая медная черепица", - "block.create.exposed_copper_tile_slab": "Плита из потемневший медной плитки", - "block.create.exposed_copper_tile_stairs": "Ступеньки из потемневший медной плитки", - "block.create.exposed_copper_tiles": "Потемневшая медная плитка", - "block.create.fake_track": "Маркер станции для карты", - "block.create.fluid_pipe": "Жидкостная труба", - "block.create.fluid_tank": "Жидкостный бак", - "block.create.fluid_valve": "Жидкостный клапан", - "block.create.flywheel": "Маховик", - "block.create.framed_glass": "Обрамлённое стекло", - "block.create.framed_glass_door": "Обрамлённая стеклянная дверь", - "block.create.framed_glass_pane": "Обрамлённая стеклянная панель", - "block.create.framed_glass_trapdoor": "Обрамлённый стеклянный люк", - "block.create.gantry_carriage": "Шасси портального крана", - "block.create.gantry_shaft": "Вал портального крана", - "block.create.gearbox": "Коробка передач", - "block.create.gearshift": "Реверсивная коробка передач", - "block.create.glass_fluid_pipe": "Стеклянная жидкостная труба", - "block.create.granite_pillar": "Гранитная колонна", - "block.create.gray_nixie_tube": "Серый газоразрядный индикатор", - "block.create.gray_sail": "Серый парус", - "block.create.gray_seat": "Серое сиденье", - "block.create.gray_toolbox": "Серый ящик для инструментов", - "block.create.gray_valve_handle": "Серый ручной вентиль", - "block.create.green_nixie_tube": "Зелёный газоразрядный индикатор", - "block.create.green_sail": "Зелёный парус", - "block.create.green_seat": "Зелёное сиденье", - "block.create.green_toolbox": "Зелёный ящик для инструментов", - "block.create.green_valve_handle": "Зелёный ручной вентиль", - "block.create.hand_crank": "Рукоятка", - "block.create.haunted_bell": "Призрачный колокол", - "block.create.honey": "Мёд", - "block.create.horizontal_framed_glass": "Горизонтальное обрамлённое стекло", - "block.create.horizontal_framed_glass_pane": "Горизонтальная обрамлённая стеклянная панель", - "block.create.hose_pulley": "Шкив со шлангом", - "block.create.item_drain": "Осушитель предметов", - "block.create.item_vault": "Хранилище предметов", - "block.create.jungle_window": "Окно из тропического дерева", - "block.create.jungle_window_pane": "Панель окна из тропического дерева", - "block.create.large_bogey": "Большая вагонная тележка", - "block.create.large_cogwheel": "Большая шестерня", - "block.create.layered_andesite": "Слоистый андезит", - "block.create.layered_asurine": "Слоистый азурин", - "block.create.layered_calcite": "Слоистый кальцит", - "block.create.layered_crimsite": "Слоистый кримзит", - "block.create.layered_deepslate": "Слоистый известняк", - "block.create.layered_diorite": "Слоистый диорит", - "block.create.layered_dripstone": "Слоистый натёчный камень", - "block.create.layered_granite": "Слоистый гранит", - "block.create.layered_limestone": "Слоистый известняк", - "block.create.layered_ochrum": "Слоистый охрум", - "block.create.layered_scorchia": "Слоистый тёмный пепел", - "block.create.layered_scoria": "Слоистый пепел", - "block.create.layered_tuff": "Слоистый туф", - "block.create.layered_veridium": "Слоистый веридиум", - "block.create.lectern_controller": "Контроллер связей на кафедре", - "block.create.light_blue_nixie_tube": "Голубой газоразрядный индикатор", - "block.create.light_blue_sail": "Голубой парус", - "block.create.light_blue_seat": "Голубое сиденье", - "block.create.light_blue_toolbox": "Голубой ящик для инструментов", - "block.create.light_blue_valve_handle": "Голубой ручной вентиль", - "block.create.light_gray_nixie_tube": "Светло-серый газоразрядный индикатор", - "block.create.light_gray_sail": "Светло-серый парус", - "block.create.light_gray_seat": "Светло-серое сиденье", - "block.create.light_gray_toolbox": "Светло-серый ящик для инструментов", - "block.create.light_gray_valve_handle": "Светло-серый ручной вентиль", - "block.create.lime_nixie_tube": "Лаймовый газоразрядный индикатор", - "block.create.lime_sail": "Лаймовый парус", - "block.create.lime_seat": "Лаймовое сиденье", - "block.create.lime_toolbox": "Лаймовый ящик для инструментов", - "block.create.lime_valve_handle": "Лаймовый ручной вентиль", - "block.create.limestone": "Известняк", - "block.create.limestone_pillar": "Известковая колонна", - "block.create.linear_chassis": "Линейное шасси", - "block.create.lit_blaze_burner": "Зажжённая горелка всполоха", - "block.create.magenta_nixie_tube": "Пурпурный газоразрядный индикатор", - "block.create.magenta_sail": "Пурпурный парус", - "block.create.magenta_seat": "Пурпурное сиденье", - "block.create.magenta_toolbox": "Пурпурный ящик для инструментов", - "block.create.magenta_valve_handle": "Пурпурный ручной вентиль", - "block.create.mechanical_arm": "Механическая рука", - "block.create.mechanical_bearing": "Механический вращатель", - "block.create.mechanical_crafter": "Механический крафтер", - "block.create.mechanical_drill": "Механическая дрель", - "block.create.mechanical_harvester": "Механический комбайн", - "block.create.mechanical_mixer": "Механический смешиватель", - "block.create.mechanical_piston": "Механический поршень", - "block.create.mechanical_piston_head": "Механическая головка поршня", - "block.create.mechanical_plough": "Механический плуг", - "block.create.mechanical_press": "Механический пресс", - "block.create.mechanical_pump": "Механическая помпа", - "block.create.mechanical_saw": "Механическая пила", - "block.create.metal_bracket": "Металлическая скоба", - "block.create.metal_girder": "Металлическая балка", - "block.create.metal_girder_encased_shaft": "Вал в металлической балке", - "block.create.millstone": "Жёрнов", - "block.create.minecart_anchor": "Вагонеточная опора", - "block.create.mysterious_cuckoo_clock": "Странные часы с кукушкой", - "block.create.nixie_tube": "Газоразрядный индикатор", - "block.create.nozzle": "Форсунка", - "block.create.oak_window": "Дубовое окно", - "block.create.oak_window_pane": "Панель из дубового окна", - "block.create.ochrum": "Охрум", - "block.create.ochrum_pillar": "Охрумывая колонна", - "block.create.orange_sail": "Оранжевый парус", - "block.create.orange_seat": "Оранжевое сиденье", - "block.create.orange_toolbox": "Оранжевый ящик для инструментов", - "block.create.orange_valve_handle": "Оранжевый ручной вентиль", - "block.create.ornate_iron_window": "Украшенное железное окно", - "block.create.ornate_iron_window_pane": "Панель из украшенного железного окна", - "block.create.oxidized_copper_shingle_slab": "Окисленная плита из медной черепицы", - "block.create.oxidized_copper_shingle_stairs": "Окисленные ступеньки из медной черепицы", - "block.create.oxidized_copper_shingles": "Окисленная медная черепица", - "block.create.oxidized_copper_tile_slab": "Плита из окисленной медной черепицы", - "block.create.oxidized_copper_tile_stairs": "Ступеньки из окисленной медной черепицы", - "block.create.oxidized_copper_tiles": "Окисленная медная плитка", - "block.create.peculiar_bell": "Особенный колокол", - "block.create.pink_nixie_tube": "Розовый газоразрядный индикатор", - "block.create.pink_sail": "Розовый парус", - "block.create.pink_seat": "Розовое сиденье", - "block.create.pink_toolbox": "Розовый ящик для инструментов", - "block.create.pink_valve_handle": "Розовый ручной вентиль", - "block.create.piston_extension_pole": "Удлинитель поршня", - "block.create.placard": "Умная рамка", - "block.create.polished_cut_andesite": "Полированный резной андезит", - "block.create.polished_cut_andesite_slab": "Полированная резная андезитовая плита", - "block.create.polished_cut_andesite_stairs": "Полированные резные андезитовые ступеньки", - "block.create.polished_cut_andesite_wall": "Полированная резная андезитовая ограда", - "block.create.polished_cut_asurine": "Полированный резной азурин", - "block.create.polished_cut_asurine_slab": "Полированная резная азуриновая плита", - "block.create.polished_cut_asurine_stairs": "Полированные резные азуриновые ступеньки", - "block.create.polished_cut_asurine_wall": "Полированная резная азуриновая ограда", - "block.create.polished_cut_calcite": "Полированный резной кальцит", - "block.create.polished_cut_calcite_slab": "Полированная резная кальцитовая плита", - "block.create.polished_cut_calcite_stairs": "Полированные резные кальцитовые ступеньки", - "block.create.polished_cut_calcite_wall": "Полированная резная кальцитовая ограда", - "block.create.polished_cut_crimsite": "Полированный резной кримзит", - "block.create.polished_cut_crimsite_slab": "Полированная резная кримзитовая плита", - "block.create.polished_cut_crimsite_stairs": "Полированные резные кримзитовые ступеньки", - "block.create.polished_cut_crimsite_wall": "Полированная резная кримзитовая ограда", - "block.create.polished_cut_deepslate": "Полированный резной глубинный сланец", - "block.create.polished_cut_deepslate_slab": "Полированная резная глубинносланцевая плита", - "block.create.polished_cut_deepslate_stairs": "Полированные резные глубинносланцевые ступеньки", - "block.create.polished_cut_deepslate_wall": "Полированная резная глубинносланцевая ограда", - "block.create.polished_cut_diorite": "Полированный резной диорит", - "block.create.polished_cut_diorite_slab": "Полированная резная диоритовая плита", - "block.create.polished_cut_diorite_stairs": "Полированные резные диоритовые ступеньки", - "block.create.polished_cut_diorite_wall": "Полированная резная диоритовая ограда", - "block.create.polished_cut_dripstone": "Полированный резной натёчный камень", - "block.create.polished_cut_dripstone_slab": "Полированная резная плита из натёчного камня", - "block.create.polished_cut_dripstone_stairs": "Полированные резные ступеньки из натёчного камня", - "block.create.polished_cut_dripstone_wall": "Полированная резная ограда из натёчного камня", - "block.create.polished_cut_granite": "Полированный резной гранит", - "block.create.polished_cut_granite_slab": "Полированная резная гранитная плита", - "block.create.polished_cut_granite_stairs": "Полированные резные гранитные ступеньки", - "block.create.polished_cut_granite_wall": "Полированная резная гранитная ограда", - "block.create.polished_cut_limestone": "Полированный резной известняк", - "block.create.polished_cut_limestone_slab": "Полированная резная известковая плита", - "block.create.polished_cut_limestone_stairs": "Полированные резные известковые ступеньки", - "block.create.polished_cut_limestone_wall": "Полированная резная известковая ограда", - "block.create.polished_cut_ochrum": "Полированный резной охрум", - "block.create.polished_cut_ochrum_slab": "Полированная резная охрумывая плита", - "block.create.polished_cut_ochrum_stairs": "Полированные резные охрумывые ступеньки", - "block.create.polished_cut_ochrum_wall": "Полированная резная охрумывая ограда", - "block.create.polished_cut_scorchia": "Полированный резной тёмный пепел", - "block.create.polished_cut_scorchia_slab": "Полированная резная тёмнопепловая плита", - "block.create.polished_cut_scorchia_stairs": "Полированные резные тёмнопепловые ступеньки", - "block.create.polished_cut_scorchia_wall": "Полированная резная тёмнопепловая ограда", - "block.create.polished_cut_scoria": "Полированный резной пепел", - "block.create.polished_cut_scoria_slab": "Полированная резная пепловая плита", - "block.create.polished_cut_scoria_stairs": "Полированные резные пепловые ступеньки", - "block.create.polished_cut_scoria_wall": "Полированная резная пепловая ограда", - "block.create.polished_cut_tuff": "Полированный резной туф", - "block.create.polished_cut_tuff_slab": "Полированная резная туфовая плита", - "block.create.polished_cut_tuff_stairs": "Полированные резные туфовые ступеньки", - "block.create.polished_cut_tuff_wall": "Полированная резная туфовая ограда", - "block.create.polished_cut_veridium": "Полированный резной веридиум", - "block.create.polished_cut_veridium_slab": "Полированная резная веридиумавая плита", - "block.create.polished_cut_veridium_stairs": "Полированные резные веридиумывые ступеньки", - "block.create.polished_cut_veridium_wall": "Полированная резная веридиумавая ограда", - "block.create.portable_fluid_interface": "Портативный жидкостный интерфейс", - "block.create.portable_storage_interface": "Портативный интерфейс хранения", - "block.create.powered_latch": "Питаемый рычаг", - "block.create.powered_shaft": "Приводной вал", - "block.create.powered_toggle_latch": "Питаемый рычаг-переключатель", - "block.create.pulley_magnet": "Магнитный шкив", - "block.create.pulse_extender": "Редстоуновый удлинитель импульса", - "block.create.pulse_repeater": "Редстоуновый повторитель импульса", - "block.create.purple_nixie_tube": "Фиолетовый газоразрядный индикатор", - "block.create.purple_sail": "Фиолетовый парус", - "block.create.purple_seat": "Фиолетовое сиденье", - "block.create.purple_toolbox": "Фиолетовый ящик для инструментов", - "block.create.purple_valve_handle": "Фиолетовый ручной вентиль", - "block.create.radial_chassis": "Радиальное шасси", - "block.create.railway_casing": "Железнодорожный корпус", - "block.create.raw_zinc_block": "Блок рудного цинка", - "block.create.red_nixie_tube": "Красный газоразрядный индикатор", - "block.create.red_sail": "Красный парус", - "block.create.red_seat": "Красное сиденье", - "block.create.red_toolbox": "Красный ящик для инструментов", - "block.create.red_valve_handle": "Красный ручной вентиль", - "block.create.redstone_contact": "Редстоуновый контакт", - "block.create.redstone_link": "Редстоуновый беспроводной передатчик сигнала", - "block.create.refined_radiance_casing": "Сияющий корпус", - "block.create.rope": "Канат", - "block.create.rope_pulley": "Лебёдка", - "block.create.rose_quartz_block": "Блок розового кварца", - "block.create.rose_quartz_lamp": "Редстоуновый фонарь из розового кварца", - "block.create.rose_quartz_tiles": "Плитка из розового кварца", - "block.create.rotation_speed_controller": "Регулятор скорости вращения", - "block.create.sail_frame": "Рама паруса", - "block.create.schematic_table": "Схематичный стол", - "block.create.schematicannon": "Схематичная пушка", - "block.create.scorchia": "Тёмный пепел", - "block.create.scorchia_pillar": "Тёмнопепловая колонна", - "block.create.scoria": "Пепел", - "block.create.scoria_pillar": "Пепловая колонна", - "block.create.secondary_linear_chassis": "Вторичное линейное шасси", - "block.create.sequenced_gearshift": "Последовательная коробка передач", - "block.create.shadow_steel_casing": "Теневой корпус", - "block.create.shaft": "Вал", - "block.create.small_andesite_brick_slab": "Плита из мелких андезитовых кирпичей", - "block.create.small_andesite_brick_stairs": "Ступеньки из мелких андезитовых кирпичей", - "block.create.small_andesite_brick_wall": "Ограда из мелких андезитовых кирпичей", - "block.create.small_andesite_bricks": "Мелкие андезитовые кирпичи", - "block.create.small_asurine_brick_slab": "Плита из мелких азуриновых кирпичей", - "block.create.small_asurine_brick_stairs": "Ступеньки из мелких азуриновых кирпичей", - "block.create.small_asurine_brick_wall": "Ограда из мелких азуриновых кирпичей", - "block.create.small_asurine_bricks": "Мелкие азуриновые кирпичи", - "block.create.small_bogey": "Малая вагонная тележка", - "block.create.small_calcite_brick_slab": "Плита из мелких кальцитовых кирпичей", - "block.create.small_calcite_brick_stairs": "Ступеньки из мелких кальцитовых кирпичей", - "block.create.small_calcite_brick_wall": "Ограда из мелких кальцитовых кирпичей", - "block.create.small_calcite_bricks": "Мелкие кальцитовые кирпичи", - "block.create.small_crimsite_brick_slab": "Плита из мелких кримзитовых кирпичей", - "block.create.small_crimsite_brick_stairs": "Ступеньки из мелких кримзитовых кирпичей", - "block.create.small_crimsite_brick_wall": "Ограда из мелких кримзитовых кирпичей", - "block.create.small_crimsite_bricks": "Мелкие кримзитовые кирпичи", - "block.create.small_deepslate_brick_slab": "Плита из мелких глубинносланцевых кирпичей", - "block.create.small_deepslate_brick_stairs": "Ступеньки из мелких глубинносланцевых кирпичей", - "block.create.small_deepslate_brick_wall": "Ограда из мелких кримзитовых кирпичей", - "block.create.small_deepslate_bricks": "Мелкие глубинносланцевые кирпичи", - "block.create.small_diorite_brick_slab": "Плита из мелких диоритовых кирпичей", - "block.create.small_diorite_brick_stairs": "Ступеньки из мелких диоритовых кирпичей", - "block.create.small_diorite_brick_wall": "Ограда из мелких диоритовых кирпичей", - "block.create.small_diorite_bricks": "Мелкие диоритовые кирпичи", - "block.create.small_dripstone_brick_slab": "Плита из мелких натёчнокаменных кирпичей", - "block.create.small_dripstone_brick_stairs": "Ступеньки из мелких натёчнокаменных кирпичей", - "block.create.small_dripstone_brick_wall": "Ограда из мелких натёчнокаменных кирпичей", - "block.create.small_dripstone_bricks": "Мелкие натёчнокаменные кирпичи", - "block.create.small_granite_brick_slab": "Плита из мелких гранитных кирпичей", - "block.create.small_granite_brick_stairs": "Ступеньки из мелких гранитных кирпичей", - "block.create.small_granite_brick_wall": "Ограда из мелких гранитных кирпичей", - "block.create.small_granite_bricks": "Мелкие гранитные кирпичи", - "block.create.small_limestone_brick_slab": "Плита из мелкого известкового кирпича", - "block.create.small_limestone_brick_stairs": "Ступеньки из мелкого известкового кирпича", - "block.create.small_limestone_brick_wall": "Ограда из мелкого известкового кирпича", - "block.create.small_limestone_bricks": "Мелкий известковый кирпич", - "block.create.small_ochrum_brick_slab": "Плита из мелкого охрумыго кирпича", - "block.create.small_ochrum_brick_stairs": "Ступеньки из мелкого охрумыго кирпича", - "block.create.small_ochrum_brick_wall": "Ограда из мелкого охрумыго кирпича", - "block.create.small_ochrum_bricks": "Мелкие охрумывые кирпичи", - "block.create.small_rose_quartz_tiles": "Мелкая плитка из розового кварца", - "block.create.small_scorchia_brick_slab": "Плита из мелкого тёмнопеплового кирпича", - "block.create.small_scorchia_brick_stairs": "Ступеньки из мелкого тёмнопеплового кирпича", - "block.create.small_scorchia_brick_wall": "Ограда из мелкого тёмнопеплового кирпича", - "block.create.small_scorchia_bricks": "Мелкие тёмнопепловые кирпичи", - "block.create.small_scoria_brick_slab": "Плита из мелких пепловых кирпичей", - "block.create.small_scoria_brick_stairs": "Ступеньки из мелких пепловых кирпичей", - "block.create.small_scoria_brick_wall": "Ограда из мелких пепловых кирпичей", - "block.create.small_scoria_bricks": "Мелкие пепловые кирпичи", - "block.create.small_tuff_brick_slab": "Плита из мелких туфовых кирпичей", - "block.create.small_tuff_brick_stairs": "Ступеньки из мелких туфовых кирпичей", - "block.create.small_tuff_brick_wall": "Ограда из мелких туфовых кирпичей", - "block.create.small_tuff_bricks": "Мелкие туфовые кирпичи", - "block.create.small_veridium_brick_slab": "Плита из мелких веридиумывых кирпичей", - "block.create.small_veridium_brick_stairs": "Ступеньки из мелких веридиумывых кирпичей", - "block.create.small_veridium_brick_wall": "Ограда из мелких веридиумывых кирпичей", - "block.create.small_veridium_bricks": "Мелкие веридиумывые кирпичи", - "block.create.smart_chute": "Умный жёлоб", - "block.create.smart_fluid_pipe": "Умная жидкостная труба", - "block.create.speedometer": "Спидометр", - "block.create.spout": "Дозатор", - "block.create.spruce_window": "Еловое окно", - "block.create.spruce_window_pane": "Панель из елового окна", - "block.create.steam_engine": "Паровой двигатель", - "block.create.steam_whistle": "Паровой свисток", - "block.create.steam_whistle_extension": "Удлинитель парового свистка", - "block.create.sticker": "Блок-липучка", - "block.create.sticky_mechanical_piston": "Липкий механический поршень", - "block.create.stockpile_switch": "Наблюдатель заполненности", - "block.create.stressometer": "Стрессометр", - "block.create.tiled_glass": "Плиточное стекло", - "block.create.tiled_glass_pane": "Плиточная стеклянная панель", - "block.create.track": "Железнодорожный путь", - "block.create.track_observer": "Железнодорожный наблюдатель", - "block.create.track_signal": "Железнодорожный светофор", - "block.create.track_station": "Железнодорожная станция", - "block.create.train_door": "Дверь поезда", - "block.create.train_trapdoor": "Люк поезда", - "block.create.tuff_pillar": "Туфовая колонна", - "block.create.turntable": "Поворотный стол", - "block.create.veridium": "Веридиум", - "block.create.veridium_pillar": "Веридиумавая колонна", - "block.create.vertical_framed_glass": "Вертикальное обрамлённое стекло", - "block.create.vertical_framed_glass_pane": "Вертикальная обрамлённая стеклянная панель", - "block.create.warped_window": "Искажённое окно", - "block.create.warped_window_pane": "Панель из искажённого окна", - "block.create.water_wheel": "Водяное колесо", - "block.create.waxed_copper_shingle_slab": "Вощёная плита из медной черепицы", - "block.create.waxed_copper_shingle_stairs": "Вощёные ступеньки из медной черепицы", - "block.create.waxed_copper_shingles": "Вощёная медная черепица", - "block.create.waxed_copper_tile_slab": "Вощёная плита из медной плитки", - "block.create.waxed_copper_tile_stairs": "Вощёные ступеньки из медной плитки", - "block.create.waxed_copper_tiles": "Вощёная медная плитка", - "block.create.waxed_exposed_copper_shingle_slab": "Вощёная потемневшая плита из медной черепицы", - "block.create.waxed_exposed_copper_shingle_stairs": "Вощёные потемневшие ступеньки из медной черепицы", - "block.create.waxed_exposed_copper_shingles": "Вощёная потемневшая медная черепица", - "block.create.waxed_exposed_copper_tile_slab": "Вощёная потемневшая плита из медной плитки", - "block.create.waxed_exposed_copper_tile_stairs": "Вощёные потемневшие ступеньки из медной плитки", - "block.create.waxed_exposed_copper_tiles": "Вощёная потемневшая медная плитка", - "block.create.waxed_oxidized_copper_shingle_slab": "Вощёная окисленная плита из медной черепицы", - "block.create.waxed_oxidized_copper_shingle_stairs": "Вощёные окисленные ступеньки из медной черепицы", - "block.create.waxed_oxidized_copper_shingles": "Вощёная окисленная медная черепица", - "block.create.waxed_oxidized_copper_tile_slab": "Вощёная окисленная плита из медной плитки", - "block.create.waxed_oxidized_copper_tile_stairs": "Вощёные окисленные ступеньки из медной плитки", - "block.create.waxed_oxidized_copper_tiles": "Вощёная окисленная медная плитка", - "block.create.waxed_weathered_copper_shingle_slab": "Вощёная состаренная плита из медной черепицы", - "block.create.waxed_weathered_copper_shingle_stairs": "Вощёные состаренные ступеньки из медной черепицы", - "block.create.waxed_weathered_copper_shingles": "Вощёная состаренная медная черепица", - "block.create.waxed_weathered_copper_tile_slab": "Вощёная состаренная плита из медной плитки", - "block.create.waxed_weathered_copper_tile_stairs": "Вощёные состаренные ступеньки из медной плитки", - "block.create.waxed_weathered_copper_tiles": "Вощёная состаренная медная плитка", - "block.create.weathered_copper_shingle_slab": "Состаренная плита из медной черепицы", - "block.create.weathered_copper_shingle_stairs": "Состаренные ступеньки из медной черепицы", - "block.create.weathered_copper_shingles": "Состаренная медная черепица", - "block.create.weathered_copper_tile_slab": "Состаренная плита из медной плитки", - "block.create.weathered_copper_tile_stairs": "Состаренные ступеньки из медной плитки", - "block.create.weathered_copper_tiles": "Состаренные медные ступеньки", - "block.create.weighted_ejector": "Взвешенная катапульта", - "block.create.white_nixie_tube": "Белый газоразрядный индикатор", - "block.create.white_sail": "Белый парус", - "block.create.white_seat": "Белое сиденье", - "block.create.white_toolbox": "Белый ящик для инструментов", - "block.create.white_valve_handle": "Белый ручной вентиль", - "block.create.windmill_bearing": "Подшипник ветряной мельницы", - "block.create.wooden_bracket": "Деревянная скоба", - "block.create.yellow_nixie_tube": "Жёлтый газоразрядный индикатор", - "block.create.yellow_sail": "Жёлтый парус", - "block.create.yellow_seat": "Жёлтое сиденье", - "block.create.yellow_toolbox": "Жёлтый ящик для инструментов", - "block.create.yellow_valve_handle": "Жёлтый ручной вентиль", - "block.create.zinc_block": "Цинковый блок", - "block.create.zinc_ore": "Цинковая руда", - - "enchantment.create.capacity": "Вместимость", - "enchantment.create.potato_recovery": "Возобновление картофеля", - - "entity.create.carriage_contraption": "Вагонная штуковина", - "entity.create.contraption": "Штуковина", - "entity.create.crafting_blueprint": "Чертёж", - "entity.create.gantry_contraption": "Крановая штуковина", - "entity.create.potato_projectile": "Картофельный снаряд", - "entity.create.seat": "Сиденье", - "entity.create.stationary_contraption": "Стационарная штуковина", - "entity.create.super_glue": "Суперклей", - - "fluid.create.potion": "Зелье", - "fluid.create.tea": "Чай строителя", - - "item.create.andesite_alloy": "Андезитовый сплав", - "item.create.attribute_filter": "Фильтр атрибутов", - "item.create.bar_of_chocolate": "Плитка шоколада", - "item.create.belt_connector": "Механический ремень", - "item.create.blaze_cake": "Торт всполоха", - "item.create.blaze_cake_base": "Основа торта всполоха", - "item.create.brass_hand": "Латунная рука", - "item.create.brass_ingot": "Латунный слиток", - "item.create.brass_nugget": "Кусочек латуни", - "item.create.brass_sheet": "Латунный лист", - "item.create.builders_tea": "Чай строителя", - "item.create.chest_minecart_contraption": "Грузовая вагонеточная штуковина", - "item.create.chocolate_bucket": "Ведро шоколада", - "item.create.chocolate_glazed_berries": "Ягоды в шоколадной глазури", - "item.create.chromatic_compound": "Хроматический компаунд", - "item.create.cinder_flour": "Незераковая пыль", - "item.create.copper_backtank": "Медный баллон", - "item.create.copper_backtank_placeable": "Размещаемый медный баллон", - "item.create.copper_nugget": "Кусочек меди", - "item.create.copper_sheet": "Медный лист", - "item.create.crafter_slot_cover": "Заглушка на слот крафтера", - "item.create.crafting_blueprint": "Чертёж", - "item.create.creative_blaze_cake": "Творческий торт всполоха", - "item.create.crushed_aluminum_ore": "Дроблёная алюминиевая руда", - "item.create.crushed_copper_ore": "Дроблёная медная руда", - "item.create.crushed_gold_ore": "Дроблёная золотая руда", - "item.create.crushed_iron_ore": "Дроблёная железная руда", - "item.create.crushed_lead_ore": "Дроблёная свинцовая руда", - "item.create.crushed_nickel_ore": "Дроблёная никелевая руда", - "item.create.crushed_osmium_ore": "Дроблёная осмиевая руда", - "item.create.crushed_platinum_ore": "Дроблёная платиновая руда", - "item.create.crushed_quicksilver_ore": "Дроблёная ртутная руда", - "item.create.crushed_silver_ore": "Дроблёная серебряная руда", - "item.create.crushed_tin_ore": "Дроблёная оловянная руда", - "item.create.crushed_uranium_ore": "Дроблёная урановая руда", - "item.create.crushed_zinc_ore": "Дроблёная цинковая руда", - "item.create.diving_boots": "Ботинки для дайвинга", - "item.create.diving_helmet": "Шлем для дайвинга", - "item.create.dough": "Тесто", - "item.create.electron_tube": "Электронная лампа", - "item.create.empty_blaze_burner": "Пустая горелка всполоха", - "item.create.empty_schematic": "Пустая схематика", - "item.create.experience_nugget": "Кусочек опыта", - "item.create.extendo_grip": "Удлинённая рука", - "item.create.filter": "Фильтр", - "item.create.furnace_minecart_contraption": "Самоходная вагонеточная штуковина", - "item.create.goggles": "Инженерные очки", - "item.create.golden_sheet": "Золотой лист", - "item.create.handheld_worldshaper": "Ручной редактор мира", - "item.create.honey_bucket": "Ведро мёда", - "item.create.honeyed_apple": "Яблоко в меду", - "item.create.incomplete_precision_mechanism": "Незаконченный механизм точности", - "item.create.incomplete_track": "Незаконченный железнодорожный путь", - "item.create.iron_sheet": "Железный лист", - "item.create.linked_controller": "Контроллер связей", - "item.create.minecart_contraption": "Вагонеточная штуковина", - "item.create.minecart_coupling": "Соединитель вагонеток", - "item.create.polished_rose_quartz": "Полированный розовый кварц", - "item.create.potato_cannon": "Картофельная пушка", - "item.create.powdered_obsidian": "Порошкообразный обсидиан", - "item.create.precision_mechanism": "Механизм точности", - "item.create.propeller": "Пропеллер", - "item.create.raw_zinc": "Рудный цинк", - "item.create.red_sand_paper": "Красная наждачная бумага", - "item.create.refined_radiance": "Изысканное сияние", - "item.create.rose_quartz": "Розовый кварц", - "item.create.sand_paper": "Наждачная бумага", - "item.create.schedule": "Расписание поезда", - "item.create.schematic": "Схематика", - "item.create.schematic_and_quill": "Схематика и перо", - "item.create.shadow_steel": "Теневая сталь", - "item.create.sturdy_sheet": "Прочный лист", - "item.create.super_glue": "Суперклей", - "item.create.sweet_roll": "Сладкий рулет", - "item.create.tree_fertilizer": "Удобрение для деревьев", - "item.create.unprocessed_obsidian_sheet": "Незаконченный прочный лист", - "item.create.vertical_gearbox": "Вертикальная коробка передач", - "item.create.wand_of_symmetry": "Жезл симметрии", - "item.create.wheat_flour": "Пшеничная мука", - "item.create.whisk": "Венчик", - "item.create.wrench": "Гаечный ключ", - "item.create.zinc_ingot": "Цинковый слиток", - "item.create.zinc_nugget": "Кусочек цинка", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Добро пожаловать в Create!", - "advancement.create.root.desc": "Пришло время начать строить удивительные штуковины!", - "advancement.create.andesite_alloy": "Повторение — мать учения", - "advancement.create.andesite_alloy.desc": "Материалы Create имеют странные названия, одно из них — Андезитовый сплав", - "advancement.create.andesite_casing": "Андезитовый век", - "advancement.create.andesite_casing.desc": "Используйте Андезитовый сплав и обтёсанное дерево для создания Андезитового корпуса", - "advancement.create.mechanical_press": "Пресс делает «Бонк!»", - "advancement.create.mechanical_press.desc": "Создайте несколько листов в Механическом прессе", - "advancement.create.encased_fan": "Механический маг воздуха", - "advancement.create.encased_fan.desc": "Разместите и активируйте Вентилятор в корпусе", - "advancement.create.fan_processing": "Обработка воздухом", - "advancement.create.fan_processing.desc": "Используйте Вентилятор в корпусе для обработки предметов", - "advancement.create.saw_processing": "Ужас лесопилки", - "advancement.create.saw_processing.desc": "Используйте вертикальную Механическую пилу для обработки материалов", - "advancement.create.compacting": "Компактификация", - "advancement.create.compacting.desc": "Используйте Механический пресс и Чашу, чтобы сжать предметы", - "advancement.create.belt": "Передайте за проезд!", - "advancement.create.belt.desc": "Соедините два Вала с помощью Механического ремня", - "advancement.create.funnel": "Эстетика аэропорта", - "advancement.create.funnel.desc": "Извлеките или добавьте предмет в контейнер с помощью Воронки", - "advancement.create.chute": "Упало", - "advancement.create.chute.desc": "Разместите Жёлоб, вертикальный аналог конвейера", - "advancement.create.mechanical_mixer": "Смешать, но не взбалтывать", - "advancement.create.mechanical_mixer.desc": "Смешайте ингредиенты в Чаше с помощью Механического смешивателя", - "advancement.create.burner": "Разумный камин", - "advancement.create.burner.desc": "Получите Горелку всполоха", - "advancement.create.water_wheel": "Обузданная гидравлика", - "advancement.create.water_wheel.desc": "Поставьте Водяное колесо и попытайтесь заставить его вращаться", - "advancement.create.windmill": "Куда дует ветер", - "advancement.create.windmill.desc": "Соберите Ветряную мельницу", - "advancement.create.shifting_gears": "Механизм переключения", - "advancement.create.shifting_gears.desc": "Подсоедините Большую шестерню к обычной Шестерне для изменения скорости вращения", - "advancement.create.millstone": "Карманная дробилка", - "advancement.create.millstone.desc": "Поставьте и приведите в действие Жёрнов", - "advancement.create.super_glue": "Площадь соединена", - "advancement.create.super_glue.desc": "Объедините несколько блоков в группу с помощью Суперклея", - "advancement.create.contraption_actors": "Движение с целью", - "advancement.create.contraption_actors.desc": "Создайте штуковину с Дрелью, Пилой или Комбайном на борту", - "advancement.create.portable_storage_interface": "Обмен на ходу", - "advancement.create.portable_storage_interface.desc": "Используйте Портативный интерфейс хранения, чтобы извлекать или добавлять предметы во время работы штуковины", - "advancement.create.wrench_goggles": "Дресс-код механика", - "advancement.create.wrench_goggles.desc": "Наденьте Инженерные очки и возьмите Гаечный ключ", - "advancement.create.stressometer": "Так сильно?", - "advancement.create.stressometer.desc": "Поставьте и подключите Стрессометр. Посмотрите на Стрессометр через Инженерные очки, чтобы узнать точное значение", - "advancement.create.cuckoo_clock": "Который час?", - "advancement.create.cuckoo_clock.desc": "Станьте свидетелем того, как ваши Часы с кукушкой объявляют время сна", - "advancement.create.windmill_maxed": "Ветер крепчает", - "advancement.create.windmill_maxed.desc": "Соберите Ветряную мельницу максимальной силы", - "advancement.create.ejector_maxed": "Чемпион катапульты", - "advancement.create.ejector_maxed.desc": "Отлетите больше чем на 30 блоков с помощью Взвешенной катапульты", - "advancement.create.pulley_maxed": "Верёвка в никуда", - "advancement.create.pulley_maxed.desc": "Растяните Лебёдку на глубину более 200 блоков", - "advancement.create.cart_pickup": "Сильные руки", - "advancement.create.cart_pickup.desc": "Поднимите Вагонеточную штуковину с не менее чем 200 прикреплёнными блоками", - "advancement.create.anvil_plough": "Кузнечная артиллерия", - "advancement.create.anvil_plough.desc": "Оттолкните падающую наковальню двигающимися Механическими плугами", - "advancement.create.lava_wheel_00000": "Адское колесо", - "advancement.create.lava_wheel_00000.desc": "Это не должно было работать!§7\n(Секретное достижение)", - "advancement.create.hand_crank_000": "Кручу-верчу", - "advancement.create.hand_crank_000.desc": "Используйте Рукоятку до полного истощения§7\n(Секретное достижение)", - "advancement.create.belt_funnel_kiss": "Механический ужин", - "advancement.create.belt_funnel_kiss.desc": "Заставьте две смонтированные на конвейере Воронки поцеловаться!", - "advancement.create.stressometer_maxed": "Миллиметраж", - "advancement.create.stressometer_maxed.desc": "Получите предельные показания Стрессометра§7\n(Секретное достижение)", - "advancement.create.copper": "Более прочные камни", - "advancement.create.copper.desc": "Получите медь за хитрости с водой", - "advancement.create.copper_casing": "Медный век", - "advancement.create.copper_casing.desc": "Используйте медный слиток для создания Медного корпуса", - "advancement.create.spout": "Буль", - "advancement.create.spout.desc": "Посмотрите как предмет наполняется с помощью Дозатора", - "advancement.create.drain": "Промышленное осушение", - "advancement.create.drain.desc": "Наблюдайте за тем, как предмет, содержащий жидкость, опустошается с помощью Осушителя предметов", - "advancement.create.steam_engine": "Сила пара", - "advancement.create.steam_engine.desc": "Используйте Паровой двигатель для создания вращательной силы", - "advancement.create.steam_whistle": "Голос ангела", - "advancement.create.steam_whistle.desc": "Активируйте Паровой свисток", - "advancement.create.backtank": "Повышение давления", - "advancement.create.backtank.desc": "Создайте Медный баллон и заставьте его закачивать воздух в себя", - "advancement.create.diving_suit": "Кто проживает на дне океана?", - "advancement.create.diving_suit.desc": "Наденьте Водолазный шлем вместе с Баллоном и прыгайте в воду", - "advancement.create.mechanical_pump_0": "Закачаешься", - "advancement.create.mechanical_pump_0.desc": "Разместите и включите Механическую помпу", - "advancement.create.glass_pipe": "Шпион за потоками", - "advancement.create.glass_pipe.desc": "Наблюдайте через окно в Трубе за тем как распространяется жидкость. Окно появится на Трубе при использовании Гаечного ключа", - "advancement.create.water_supply": "Сборщик луж", - "advancement.create.water_supply.desc": "Используйте Трубу или Помпу, чтобы собрать водный блок", - "advancement.create.hose_pulley": "Промышленный полив", - "advancement.create.hose_pulley.desc": "Опустите Шланг и смотрите как он осушает или заполняет пространство жидкостью", - "advancement.create.chocolate_bucket": "Не слипнется!", - "advancement.create.chocolate_bucket.desc": "Получите Ведро шоколада", - "advancement.create.honey_drain": "Укуси меня пчела!", - "advancement.create.honey_drain.desc": "Используйте Трубы, чтобы вытащить мёд из пчелиного улья или гнезда, пока пчёлы не понимают что их обворовывают", - "advancement.create.hose_pulley_lava": "Прикосновение к мантии", - "advancement.create.hose_pulley_lava.desc": "Выкачивайте лаву из бесконечного источника", - "advancement.create.steam_engine_maxed": "С мёртвой точки!", - "advancement.create.steam_engine_maxed.desc": "Запустите Котёл на максимальном уровне мощности", - "advancement.create.foods": "Правильное питание", - "advancement.create.foods.desc": "Создайте Ягоды в шоколадной глазури, Яблоко в меду и Сладкий рулет; всё из одного Дозатора", - "advancement.create.diving_suit_lava": "Плохая идея", - "advancement.create.diving_suit_lava.desc": "Попытайтесь нырнуть в лаву с медным водолазным снаряжением. Сделайте из этого выводы§7\n(Секретное достижение)", - "advancement.create.chained_drain": "Смотри как могу!", - "advancement.create.chained_drain.desc": "Наблюдайте как предмет переворачивается по ряду Осушителей предметов§7\n(Секретное достижение)", - "advancement.create.cross_streams": "Не пересекайте потоки!", - "advancement.create.cross_streams.desc": "Наблюдайте за тем, как две разные жидкости встречаются в ваших Трубах§7\n(Секретное достижение)", - "advancement.create.pipe_organ": "Иоганн Бах", - "advancement.create.pipe_organ.desc": "Сделайте орган, прикрепив 12 Паровых свистков с уникальным звуком к одному резервуару с жидкостью§7\n(Секретное достижение)", - "advancement.create.brass": "Реальный сплав", - "advancement.create.brass.desc": "Используйте Дроблёную медь и Дроблёный цинк, чтобы создать Латунь", - "advancement.create.brass_casing": "Латунный век", - "advancement.create.brass_casing.desc": "Используйте только что полученную Латунь и обтёсанную древесину, чтобы создать более продвинутый корпус", - "advancement.create.rose_quartz": "Розовые алмазы", - "advancement.create.rose_quartz.desc": "Отполируйте Розовый кварц", - "advancement.create.deployer": "Тыкайте, ставьте и атакуйте", - "advancement.create.deployer.desc": "Приведите в действие Автономный активатор, идеальное отражение себя", - "advancement.create.precision_mechanism": "Сложные любопытства", - "advancement.create.precision_mechanism.desc": "Создайте Механизм точности", - "advancement.create.speed_controller": "Его ненавидят инженеры!", - "advancement.create.speed_controller.desc": "Установите Регулятор скорости вращения, идеальное устройство для переключения передач", - "advancement.create.mechanical_arm": "Золотые руки!", - "advancement.create.mechanical_arm.desc": "Активируйте Механическую руку. Затем смотрите как она делает за вас всю работу", - "advancement.create.mechanical_crafter": "Лень — двигатель прогресса", - "advancement.create.mechanical_crafter.desc": "Разместите и включите несколько Механических крафтеров, чтобы создавать всякое", - "advancement.create.crushing_wheel": "Пара гигантов", - "advancement.create.crushing_wheel.desc": "Создайте несколько Дробящих колес, чтобы более эффективно разрушать больше предметов", - "advancement.create.haunted_bell": "По ком звонит колокол", - "advancement.create.haunted_bell.desc": "Позвоните в Призрачный колокол", - "advancement.create.clockwork_bearing": "Хитрые часы", - "advancement.create.clockwork_bearing.desc": "Соберите штуковину, расположенную на Часовом механизме", - "advancement.create.display_link": "Большие данные", - "advancement.create.display_link.desc": "Используйте Передатчик информации для её визуализации", - "advancement.create.potato_cannon": "Свомп!", - "advancement.create.potato_cannon.desc": "Победите врага с помощью своей Картофельной пушки!", - "advancement.create.extendo_grip": "Дальше — больше", - "advancement.create.extendo_grip.desc": "Возьмите Удлинённую руку", - "advancement.create.linked_controller": "Восстановление связей", - "advancement.create.linked_controller.desc": "Используйте Контроллер связей для удалённой активации Беспроводного приёмника редстоун-сигнала", - "advancement.create.arm_blaze_burner": "Поджигателе-трон", - "advancement.create.arm_blaze_burner.desc": "Запрограммируйте Механическую руку на кормление Горелки всполоха", - "advancement.create.crusher_maxed_0000": "Раздроби это!", - "advancement.create.crusher_maxed_0000.desc": "Управляйте парой Дробящих колес на максимальной скорости", - "advancement.create.arm_many_targets": "Организа-трон", - "advancement.create.arm_many_targets.desc": "Запрограммируйте Механическую руку на 10 и больше выходов", - "advancement.create.potato_cannon_collide": "Картофегиляция", - "advancement.create.potato_cannon_collide.desc": "Заставь снаряды Картофельных пушек разных типов столкнуться друг с другом", - "advancement.create.self_deploying": "До чего дошёл прогресс!", - "advancement.create.self_deploying.desc": "Создайте вагонеточную штуковину, которая размещает рельсы перед собой", - "advancement.create.fist_bump": "Здарова, бро!", - "advancement.create.fist_bump.desc": "Сделайте так, чтобы два Автономных активатора ударили кулаками", - "advancement.create.crafter_lazy_000": "Отчаянные меры", - "advancement.create.crafter_lazy_000.desc": "Значительно замедлите Механический крафтер, чтобы сделать плохое производство§7\n(Секретное достижение)", - "advancement.create.extendo_grip_dual": "В полной мере", - "advancement.create.extendo_grip_dual.desc": "Используйте две Удлинённые руки для супер-досягаемости§7\n(Секретное достижение)", - "advancement.create.musical_arm": "Сбацай что-нибудь!", - "advancement.create.musical_arm.desc": "Посмотрите как Механическая рука меняет пластинки", - "advancement.create.sturdy_sheet": "Ещё более твёрдые камни", - "advancement.create.sturdy_sheet.desc": "Соберите Прочный лист из Порошкообразного обсидиана", - "advancement.create.train_casing_00": "Железнодорожная эра", - "advancement.create.train_casing_00.desc": "Используйте Прочные листы и Латунный корпус для создания Железнодорожного корпуса", - "advancement.create.train": "Все на борт!", - "advancement.create.train.desc": "Соберите свой первый поезд", - "advancement.create.conductor": "Машинист-инструктор", - "advancement.create.conductor.desc": "Проинструктируйте машиниста следовать по Расписанию", - "advancement.create.track_signal": "Управление движением", - "advancement.create.track_signal.desc": "Разместите Железнодорожный светофор", - "advancement.create.display_board_0": "Эстетика вокзала", - "advancement.create.display_board_0.desc": "Прогнозируйте прибытие поезда на Табло с помощью Передатчика информации", - "advancement.create.track_0": "Новая колея", - "advancement.create.track_0.desc": "Создайте Железнодорожный путь", - "advancement.create.train_whistle": "Чу-Чу!", - "advancement.create.train_whistle.desc": "Прикрепите Паровой свисток к вашему поезду и погудите в него!", - "advancement.create.train_portal": "Сквозь измерения", - "advancement.create.train_portal.desc": "Проедьте на поезде через портал Незера", - "advancement.create.track_crafting_factory": "Железнодорожная фабрика", - "advancement.create.track_crafting_factory.desc": "Произведите более 1000 Железнодорожных путей на одном Механическом прессе", - "advancement.create.long_bend": "Крутой поворот", - "advancement.create.long_bend.desc": "Создайте участок изогнутых Путей длиной более 30 блоков", - "advancement.create.long_train": "Амбициозные усилия", - "advancement.create.long_train.desc": "Создайте поезд как минимум с шестью вагонами", - "advancement.create.long_travel": "На дальней станции сойду", - "advancement.create.long_travel.desc": "Встаньте с сидения поезда на расстоянии более 5000 блоков от того места, где вы начали путешествие", - "advancement.create.train_roadkill": "Убийство «Восточным экспрессом»", - "advancement.create.train_roadkill.desc": "Переедьте врага своим поездом!§7\n(Секретное достижение)", - "advancement.create.red_signal": "Я знаю короткую дорогу!", - "advancement.create.red_signal.desc": "Проедьте поездом на красный сигнал Светофора§7\n(Секретное достижение)", - "advancement.create.train_crash": "Ужасное обслуживание", - "advancement.create.train_crash.desc": "Станьте свидетелем железнодорожной аварии в качестве пассажира§7\n(Секретное достижение)", - "advancement.create.train_crash_backwards": "Слепая зона", - "advancement.create.train_crash_backwards.desc": "Врежьтесь в другой поезд, двигаясь задним ходом§7\n(Секретное достижение)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create: Основные", - "itemGroup.create.palettes": "Create: Декор", - - "death.attack.create.crush": "%1$s был передроблен", - "death.attack.create.crush.player": "%1$s был передроблен благодаря %2$s", - "death.attack.create.fan_fire": "%1$s был высушен до смерти горячим воздухом", - "death.attack.create.fan_fire.player": "%1$s был высушен до смерти горячим воздухом благодаря %2$s", - "death.attack.create.fan_lava": "%1$s был сожжён огненным потоком", - "death.attack.create.fan_lava.player": "%1$s был сожжён огненным потоком благодаря %2$s", - "death.attack.create.mechanical_drill": "%1$s был пронзён механической дрелью", - "death.attack.create.mechanical_drill.player": "%1$s был пронзён механической дрелью благодаря %2$s", - "death.attack.create.mechanical_saw": "%1$s был разрезан пополам механической пилой", - "death.attack.create.mechanical_saw.player": "%1$s был разрезан пополам механической пилой благодаря %2$s", - "death.attack.create.potato_cannon": "%1$s был застрелен из картофельной пушки %2$s", - "death.attack.create.potato_cannon.item": "%1$s был застрелен %2$s с помощью %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s был взорван фальшивыми часами с кукушкой", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s был взорван фальшивыми часами с кукушкой благодаря %2$s", - "death.attack.create.run_over": "%1$s был размазан по путям %2$s", - - "create.block.deployer.damage_source_name": "автономным активатором", - "create.block.cart_assembler.invalid": "Установите сборщик вагонеток на рельсы", - - "create.menu.return": "Вернуться в меню", - "create.menu.configure": "Настроить...", - "create.menu.ponder_index": "Все размышления", - "create.menu.only_ingame": "Доступны только во время игры", - "create.menu.report_bugs": "Нашли ошибку?", - "create.menu.support": "Поддержите нас", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Дробление", - "create.recipe.milling": "Помол", - "create.recipe.fan_washing": "Массовая промывка", - "create.recipe.fan_washing.fan": "Вентилятор за водой", - "create.recipe.fan_smoking": "Массовое копчение", - "create.recipe.fan_smoking.fan": "Вентилятор за огнём", - "create.recipe.fan_haunting": "Призрачное наполнение", - "create.recipe.fan_haunting.fan": "Вентилятор за огнём душ", - "create.recipe.fan_blasting": "Массовое плавление", - "create.recipe.fan_blasting.fan": "Вентилятор за лавой", - "create.recipe.pressing": "Прессование", - "create.recipe.mixing": "Смешивание", - "create.recipe.deploying": "Автономное создание", - "create.recipe.automatic_shapeless": "Бесформенная сборка", - "create.recipe.automatic_brewing": "Автоматическая варка", - "create.recipe.packing": "Спрессовывание", - "create.recipe.automatic_packing": "Сжатие предметов", - "create.recipe.sawing": "Распиловка", - "create.recipe.mechanical_crafting": "Механическое создание", - "create.recipe.automatic_shaped": "Форменная сборка", - "create.recipe.block_cutting": "Резка блоков", - "create.recipe.wood_cutting": "Резка древесины", - "create.recipe.sandpaper_polishing": "Полирование", - "create.recipe.mystery_conversion": "Таинственное преобразование", - "create.recipe.spout_filling": "Наполнение дозатором", - "create.recipe.draining": "Осушение предметов", - "create.recipe.item_application": "Ручное создание", - "create.recipe.item_application.any_axe": "Любой топор", - "create.recipe.sequenced_assembly": "Последовательная сборка", - "create.recipe.assembly.next": "Следующее: %1$s", - "create.recipe.assembly.step": "Шаг %1$s:", - "create.recipe.assembly.progress": "Прогресс: %1$s/%2$s", - "create.recipe.assembly.pressing": "Обработайте прессом", - "create.recipe.assembly.spout_filling_fluid": "Добавьте жидкость: %1$s", - "create.recipe.assembly.deploying_item": "Добавьте предмет: %1$s", - "create.recipe.assembly.cutting": "Разрежьте пилой", - "create.recipe.assembly.repeat": "Повторите последовательность %1$s раз", - "create.recipe.assembly.junk": "Случайный мусор", - "create.recipe.processing.chance": "%1$s%% шанса", - "create.recipe.deploying.not_consumed": "Не тратится", - "create.recipe.heat_requirement.none": "Не требует нагрева", - "create.recipe.heat_requirement.heated": "Нагрето", - "create.recipe.heat_requirement.superheated": "Перегрето", - - "create.generic.range": "Диапазон", - "create.generic.radius": "Радиус", - "create.generic.width": "Ширина", - "create.generic.height": "Высота", - "create.generic.length": "Длина", - "create.generic.speed": "Скорость", - "create.generic.delay": "Задержка", - "create.generic.duration": "Продолжительность", - "create.generic.timeUnit": "Единица времени", - "create.generic.unit.ticks": "Тиков", - "create.generic.unit.seconds": "Секунд", - "create.generic.unit.minutes": "Минут", - "create.generic.daytime.hour": "Час", - "create.generic.daytime.minute": "Минута", - "create.generic.daytime.second": "Секунда", - "create.generic.daytime.pm": "pm", - "create.generic.daytime.am": "am", - "create.generic.unit.rpm": "об./мин.", - "create.generic.unit.stress": "ЕН", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$s мВ", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "По часовой стрелке", - "create.generic.counter_clockwise": "Против часовой стрелки", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "♪: %1$s", - "create.generic.notes": "фа♯;фа;ми;ре♯;ре;до♯;до;си;ля♯;ля;соль♯;соль", - - "create.action.scroll": "Прокрутка", - "create.action.confirm": "Подтвердить", - "create.action.abort": "Прервать", - "create.action.saveToFile": "Сохранить", - "create.action.discard": "Отменить", - - "create.keyinfo.toolmenu": "Меню инструмента фокусировки", - "create.keyinfo.toolbelt": "Доступ к ближайшим ящикам с инструментами", - "create.keyinfo.scrollup": "Имитация движения мыши вверх (в мире)", - "create.keyinfo.scrolldown": "Имитация движения мыши вниз (в мире)", - - "create.gui.scrollInput.defaultTitle": "Выбрать опцию:", - "create.gui.scrollInput.scrollToModify": "Прокрутите, чтобы изменить", - "create.gui.scrollInput.scrollToAdjustAmount": "Прокрутите, чтобы настроить количество", - "create.gui.scrollInput.scrollToSelect": "Прокрутите, чтобы выбрать", - "create.gui.scrollInput.shiftScrollsFaster": "Зажмите Shift для быстрой прокрутки", - "create.gui.toolmenu.focusKey": "Удерживайте [%1$s] для смены действия", - "create.gui.toolmenu.cycle": "[Прокрутка] для переключения", - - "create.toolbox.unequip": "Убрать: %1$s", - "create.toolbox.outOfRange": "Ящик для инструментов выбранного предмета слишком далеко...", - "create.toolbox.detach": "Убрать выбранный предмет в ящик для инструментов", - "create.toolbox.depositAll": "Вернуть все предметы в ближайшие ящики для инструментов", - "create.toolbox.depositBox": "Вернуть все предметы в ящик для инструментов", - - "create.gui.symmetryWand.mirrorType": "Зеркало", - "create.gui.symmetryWand.orientation": "Ориентация", - - "create.symmetry.mirror.plane": "Одинарное", - "create.symmetry.mirror.doublePlane": "Двойное", - "create.symmetry.mirror.triplePlane": "Тройное", - - "create.orientation.orthogonal": "Перпендикулярная", - "create.orientation.diagonal": "Диагональная", - "create.orientation.horizontal": "Горизонтальная", - "create.orientation.alongZ": "Вдоль Z", - "create.orientation.alongX": "Вдоль X", - - "create.gui.terrainzapper.title": "Ручной редактор мира", - "create.gui.terrainzapper.searchDiagonal": "Следовать диагоналям", - "create.gui.terrainzapper.searchFuzzy": "Игнорировать границы материала", - "create.gui.terrainzapper.patternSection": "Шаблоны", - "create.gui.terrainzapper.pattern.solid": "Полное заполнение", - "create.gui.terrainzapper.pattern.checkered": "Шахматный порядок", - "create.gui.terrainzapper.pattern.inversecheckered": "Обратный шахматный порядок", - "create.gui.terrainzapper.pattern.chance25": "25% заполнение", - "create.gui.terrainzapper.pattern.chance50": "50% заполнение", - "create.gui.terrainzapper.pattern.chance75": "75% заполнение", - "create.gui.terrainzapper.placement": "Установка", - "create.gui.terrainzapper.placement.merged": "Слитая", - "create.gui.terrainzapper.placement.attached": "Прикреплённая", - "create.gui.terrainzapper.placement.inserted": "Вставленная", - "create.gui.terrainzapper.brush": "Кисти", - "create.gui.terrainzapper.brush.cuboid": "Куб", - "create.gui.terrainzapper.brush.sphere": "Сфера", - "create.gui.terrainzapper.brush.cylinder": "Цилиндр", - "create.gui.terrainzapper.brush.surface": "Поверхность", - "create.gui.terrainzapper.brush.cluster": "Скопление", - "create.gui.terrainzapper.tool": "Инструменты", - "create.gui.terrainzapper.tool.fill": "Заполнить", - "create.gui.terrainzapper.tool.place": "Поставить", - "create.gui.terrainzapper.tool.replace": "Заменить", - "create.gui.terrainzapper.tool.clear": "Очистить", - "create.gui.terrainzapper.tool.overlay": "Наложение", - "create.gui.terrainzapper.tool.flatten": "Сглаживание", - - "create.terrainzapper.shiftRightClickToSet": "Нажмите ПКМ крадучись, чтобы выбрать кисть", - "create.terrainzapper.usingBlock": "Используется: %1$s", - "create.terrainzapper.leftClickToSet": "Нажмите ЛКМ по блоку, что бы использовать материал", - - "create.minecart_coupling.two_couplings_max": "Вагонетки могут иметь только два соединения", - "create.minecart_coupling.unloaded": "Кажется, в данный момент часть вашей вагонеточной штуковины в незагруженных чанках", - "create.minecart_coupling.no_loops": "Соединители не могут образовывать петлю", - "create.minecart_coupling.removed": "Убраны все соединения между вагонетками", - "create.minecart_coupling.too_far": "Вагонетки слишком далеко друг от друга...", - - "create.contraptions.movement_mode": "Режим движения", - "create.contraptions.movement_mode.move_place": "Превращать в блоки при остановке", - "create.contraptions.movement_mode.move_place_returned": "Превращать в блоки только в исх. положении", - "create.contraptions.movement_mode.move_never_place": "Превращать в блоки, если опора уничтожена", - "create.contraptions.movement_mode.rotate_place": "Превращать в блоки при остановке", - "create.contraptions.movement_mode.rotate_place_returned": "Превращать в блоки только в исх. положении", - "create.contraptions.movement_mode.rotate_never_place": "Превращать в блоки, если опора уничтожена", - "create.contraptions.cart_movement_mode": "Режим движения вагонетки", - "create.contraptions.cart_movement_mode.rotate": "Вращение в сторону движения", - "create.contraptions.cart_movement_mode.rotate_paused": "Пауза во время вращения", - "create.contraptions.cart_movement_mode.rotation_locked": "Блокировка вращения", - "create.contraptions.windmill.rotation_direction": "Направление вращения", - "create.contraptions.clockwork.clock_hands": "Стрелки часов", - "create.contraptions.clockwork.hour_first": "Сначала часовая стрелка", - "create.contraptions.clockwork.minute_first": "Сначала минутная стрелка", - "create.contraptions.clockwork.hour_first_24": "Сначала 24-часовая стрелка", - - "create.logistics.filter": "Фильтр", - "create.logistics.recipe_filter": "Фильтр рецепта", - "create.logistics.fluid_filter": "Фильтр жидкости", - "create.logistics.firstFrequency": "Частота #1", - "create.logistics.secondFrequency": "Частота #2", - "create.logistics.filter.apply": "Фильтр применён к %1$s", - "create.logistics.filter.apply_click_again": "Фильтр применён к %1$s; кликните ещё раз, чтобы скопировать количество", - "create.logistics.filter.apply_count": "Применено извлекаемое количество к фильтру", - - "create.gui.goggles.generator_stats": "Статистика генератора:", - "create.gui.goggles.kinetic_stats": "Кинетическая статистика:", - "create.gui.goggles.at_current_speed": "При текущей скорости", - "create.gui.goggles.pole_length": "Длина поршня:", - "create.gui.goggles.fluid_container": "Информация о жидкостном контейнере:", - "create.gui.goggles.fluid_container.capacity": "Ёмкость: ", - "create.gui.assembly.exception": "Невозможно собрать эту штуковину:", - "create.gui.assembly.exception.unmovableBlock": "Несдвигаемый блок (%4$s) на [%1$s|%2$s|%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Блок на [%1$s|%2$s|%3$s] был в незагруженном чанке", - "create.gui.assembly.exception.structureTooLarge": "Штуковина состоит из слишком большого количества блоков.\nТекущий максимум: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Слишком много удлинителей прикреплено к этому поршню.\nТекущий максимум: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Поршню не хватает удлинителей", - "create.gui.assembly.exception.not_enough_sails": "Присоединённая структура содержит недостаточно парусоподобных блоков; %1$s из минимум %2$s необходимых", - "create.gui.gauge.info_header": "Калибровочная информация:", - "create.gui.speedometer.title": "Скорость вращения", - "create.gui.stressometer.title": "Нагрузка на сеть", - "create.gui.stressometer.capacity": "Оставшаяся ёмкость", - "create.gui.stressometer.overstressed": "Перегрузка", - "create.gui.stressometer.no_rotation": "Нет вращения", - "create.gui.contraptions.not_fast_enough": "Похоже, что %1$s вращается с _недостаточной_ _скоростью_.", - "create.gui.contraptions.network_overstressed": "Похоже, что эта штуковина _перегружена_. Добавьте больше источников или _понизьте_ _скорость_ компонентов, _создающих_ высокую _нагрузку_.", - "create.gui.adjustable_crate.title": "Регулируемый ящик", - "create.gui.adjustable_crate.storageSpace": "Ёмкость", - "create.gui.stockpile_switch.title": "Наблюдатель заполненности", - "create.gui.stockpile_switch.invert_signal": "Инвертировать сигнал", - "create.gui.stockpile_switch.move_to_lower_at": "Переключатся на нижнюю линию при %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Переключатся на верхнюю линию при %1$s%%", - "create.gui.sequenced_gearshift.title": "Последов. коробка передач", - "create.gui.sequenced_gearshift.instruction": "Инструкция", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Повернуть на угол", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Угол", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Угол", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Перемещение Поршня/Шкива/Крана", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Поршень", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Расстояние", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Временная задержка", - "create.gui.sequenced_gearshift.instruction.delay": "Задержка", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Длительность", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Конец", - "create.gui.sequenced_gearshift.instruction.end": "Конец", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Ожидать нового редстоун-сигнала", - "create.gui.sequenced_gearshift.instruction.await": "Сигнал", - "create.gui.sequenced_gearshift.speed": "Скорость, направление", - "create.gui.sequenced_gearshift.speed.forward": "Обычная скорость, вперёд", - "create.gui.sequenced_gearshift.speed.forward_fast": "Двойная скорость, вперёд", - "create.gui.sequenced_gearshift.speed.back": "Обычная скорость, реверс", - "create.gui.sequenced_gearshift.speed.back_fast": "Двойная скорость, реверс", - - "create.schematicAndQuill.dimensions": "Размер схематики: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Первая позиция установлена", - "create.schematicAndQuill.secondPos": "Вторая позиция установлена", - "create.schematicAndQuill.noTarget": "Удерживайте Ctrl, чтобы выбрать блоки воздуха", - "create.schematicAndQuill.abort": "Выделение отменено", - "create.schematicAndQuill.title": "Имя схематики:", - "create.schematicAndQuill.convert": "Сохранить и развернуть немедленно", - "create.schematicAndQuill.fallbackName": "Моя схематика", - "create.schematicAndQuill.saved": "Сохранено как %1$s", - - "create.schematic.invalid": "[!] Недопустимый предмет — вместо этого используйте схематичный стол", - "create.schematic.position": "Позиция", - "create.schematic.rotation": "Вращение", - "create.schematic.rotation.none": "Нет", - "create.schematic.rotation.cw90": "По час. стрелке 90", - "create.schematic.rotation.cw180": "По час. стрелке 180", - "create.schematic.rotation.cw270": "По час. стрелке 270", - "create.schematic.mirror": "Отразить", - "create.schematic.mirror.none": "Нет", - "create.schematic.mirror.frontBack": "Спереди-сзади", - "create.schematic.mirror.leftRight": "Влево-вправо", - "create.schematic.tool.deploy": "Развёртывание", - "create.schematic.tool.move": "Подвинуть XZ", - "create.schematic.tool.movey": "Подвинуть Y", - "create.schematic.tool.rotate": "Вращать", - "create.schematic.tool.print": "Печать", - "create.schematic.tool.flip": "Перевернуть", - "create.schematic.tool.deploy.description.0": "Перемещает структуру в локации.", - "create.schematic.tool.deploy.description.1": "Щёлкните ПКМ по блоку, чтобы разместить.", - "create.schematic.tool.deploy.description.2": "Зажмите Ctrl, чтобы выбрать фиксированное расстояние.", - "create.schematic.tool.deploy.description.3": "Ctrl и прокрутка, чтобы изменить расстояние.", - "create.schematic.tool.move.description.0": "Сдвинуть схему по горизонтали.", - "create.schematic.tool.move.description.1": "Наведите курсор на схему и зажмите Ctrl и прокрутка,", - "create.schematic.tool.move.description.2": "для перемещения по горизонтали.", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Сдвигает схему по вертикали.", - "create.schematic.tool.movey.description.1": "Ctrl и прокрутка для перемещения вверх/вниз.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Вращает схематику вокруг её центра.", - "create.schematic.tool.rotate.description.1": "Ctrl и прокрутка для вращения на 90 градусов.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Мгновенно размещает структуру в мире.", - "create.schematic.tool.print.description.1": "ПКМ, чтобы подтвердить размещение в текущем месте.", - "create.schematic.tool.print.description.2": "Этот инструмент предназначен только", - "create.schematic.tool.print.description.3": "для творческого режима.", - "create.schematic.tool.flip.description.0": "Переверните схему вдоль выбранной стороны.", - "create.schematic.tool.flip.description.1": "Наведите курсор на схему и Ctrl и прокрутка,", - "create.schematic.tool.flip.description.2": "чтобы перевернуть её.", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Синхронизация...", - "create.schematics.uploadTooLarge": "Файл схематики слишком большой.", - "create.schematics.maxAllowedSize": "Максимально допустимый размер файла:", - - "create.gui.schematicTable.refresh": "Обновить файлы", - "create.gui.schematicTable.open_folder": "Открыть папку со схематиками", - "create.gui.schematicTable.title": "Схематичный стол", - "create.gui.schematicTable.availableSchematics": "Доступные схемы", - "create.gui.schematicTable.noSchematics": "Схемы не сохранены", - "create.gui.schematicTable.uploading": "Загрузка...", - "create.gui.schematicTable.finished": "Загрузка завершена!", - "create.gui.schematicannon.title": "Схематичная пушка", - "create.gui.schematicannon.listPrinter": "Список материалов", - "create.gui.schematicannon.gunpowderLevel": "Порох: %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Выстрелов осталось: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "С порохом в запасе: %1$s", - "create.gui.schematicannon.optionEnabled": "Включено", - "create.gui.schematicannon.optionDisabled": "Отключено", - "create.gui.schematicannon.showOptions": "Показать настройки строительства", - "create.gui.schematicannon.option.dontReplaceSolid": "Не заменять целые блоки", - "create.gui.schematicannon.option.replaceWithSolid": "Заменять целые блоки целыми блоками", - "create.gui.schematicannon.option.replaceWithAny": "Заменять целые блоки чем угодно", - "create.gui.schematicannon.option.replaceWithEmpty": "Заменять целые блоки пустотой", - "create.gui.schematicannon.option.skipMissing": "Пропускать отсутствующие блоки", - "create.gui.schematicannon.option.skipTileEntities": "Защитить имущество", - "create.gui.schematicannon.slot.gunpowder": "Добавьте порох, чтобы заправить пушку", - "create.gui.schematicannon.slot.listPrinter": "Положите книгу, чтобы создать список предметов для схематики", - "create.gui.schematicannon.slot.schematic": "Положите свою схематику здесь. Убедитесь что она размещена в правильном месте", - "create.gui.schematicannon.option.skipMissing.description": "Если пушка не сможет найти требуемый блок, то она перейдёт к следующему.", - "create.gui.schematicannon.option.skipTileEntities.description": "Пушка не будет заменять блоки-хранилища, такие как сундуки.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Пушка никогда не заменит целые блоки, только не целые и воздух.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Пушка будет заменять целый блок только в случае, если в схеме в этом месте расположен целый блок.", - "create.gui.schematicannon.option.replaceWithAny.description": "Пушка будет заменять целые блоки, если в схеме в этом месте есть что-либо.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Пушка уберёт все блоки, включая замену на воздух.", - - "create.schematicannon.status.idle": "Бездействует", - "create.schematicannon.status.ready": "Готова", - "create.schematicannon.status.running": "Работает", - "create.schematicannon.status.finished": "Закончила", - "create.schematicannon.status.paused": "Приостановлена", - "create.schematicannon.status.stopped": "Остановлена", - "create.schematicannon.status.noGunpowder": "Требуется порох", - "create.schematicannon.status.targetNotLoaded": "Цель не загружена", - "create.schematicannon.status.targetOutsideRange": "Цель слишком далеко", - "create.schematicannon.status.searching": "Поиск", - "create.schematicannon.status.skipping": "Пропуск", - "create.schematicannon.status.missingBlock": "Требует блок:", - "create.schematicannon.status.placing": "Стройка", - "create.schematicannon.status.clearing": "Очистка", - "create.schematicannon.status.schematicInvalid": "Неверная схема", - "create.schematicannon.status.schematicNotPlaced": "Схема не развёрнута", - "create.schematicannon.status.schematicExpired": "Файл схемы устарел", - - "create.materialChecklist": "Список материалов", - "create.materialChecklist.blocksNotLoaded": "* Внимание! *\n\nСписок материалов может быть неточным из-за незагруженных чанков.", - - "create.gui.filter.deny_list": "Чёрный список", - "create.gui.filter.deny_list.description": "Предметы проходят, если они не соответствуют ни одному из вышеперечисленных. Пустой чёрный список принимает всё.", - "create.gui.filter.allow_list": "Белый список", - "create.gui.filter.allow_list.description": "Предметы проходят, если они соответствуют любому из вышеперечисленных. Пустой белый список отвергает всё.", - "create.gui.filter.respect_data": "Использовать данные", - "create.gui.filter.respect_data.description": "Предметы проходят только в том случае, если их прочность, чары и другие атрибуты совпадают.", - "create.gui.filter.ignore_data": "Игнорировать данные", - "create.gui.filter.ignore_data.description": "Предметы проходят независимо от их атрибутов.", - - "create.item_attributes.placeable": "можно разместить", - "create.item_attributes.placeable.inverted": "нельзя разместить", - "create.item_attributes.consumable": "можно съесть", - "create.item_attributes.consumable.inverted": "нельзя съесть", - "create.item_attributes.fluid_container": "может хранить жидкости", - "create.item_attributes.fluid_container.inverted": "не может хранить жидкости", - "create.item_attributes.enchanted": "зачарован", - "create.item_attributes.enchanted.inverted": "не зачарован", - "create.item_attributes.max_enchanted": "зачарован на максимальный уровень", - "create.item_attributes.max_enchanted.inverted": "зачарован не на максимальный уровень", - "create.item_attributes.renamed": "имеет пользовательское имя", - "create.item_attributes.renamed.inverted": "не имеет пользовательского имени", - "create.item_attributes.damaged": "повреждён", - "create.item_attributes.damaged.inverted": "не повреждён", - "create.item_attributes.badly_damaged": "сильно повреждён", - "create.item_attributes.badly_damaged.inverted": "повреждён не сильно", - "create.item_attributes.not_stackable": "не может складываться", - "create.item_attributes.not_stackable.inverted": "складывается", - "create.item_attributes.equipable": "можно надеть", - "create.item_attributes.equipable.inverted": "нельзя надеть", - "create.item_attributes.furnace_fuel": "является топливом", - "create.item_attributes.furnace_fuel.inverted": "не является топливом", - "create.item_attributes.washable": "можно промыть", - "create.item_attributes.washable.inverted": "нельзя промыть", - "create.item_attributes.hauntable": "можно наполнить призраками", - "create.item_attributes.hauntable.inverted": "нельзя наполнить призраками", - "create.item_attributes.crushable": "можно раздробить", - "create.item_attributes.crushable.inverted": "нельзя раздробить", - "create.item_attributes.smeltable": "можно расплавить", - "create.item_attributes.smeltable.inverted": "нельзя расплавить", - "create.item_attributes.smokable": "можно прокоптить", - "create.item_attributes.smokable.inverted": "нельзя прокоптить", - "create.item_attributes.blastable": "можно расплавить в доменной печи", - "create.item_attributes.blastable.inverted": "нельзя расплавить в доменной печи", - "create.item_attributes.compostable": "можно компостировать", - "create.item_attributes.compostable.inverted": "нельзя компостировать", - "create.item_attributes.shulker_level": "шалкеровый ящик %1$s", - "create.item_attributes.shulker_level.inverted": "шалкеровый ящик не %1$s", - "create.item_attributes.shulker_level.full": "полон", - "create.item_attributes.shulker_level.empty": "пуст", - "create.item_attributes.shulker_level.partial": "частично заполнен", - "create.item_attributes.in_tag": "с тегом %1$s", - "create.item_attributes.in_tag.inverted": "без тега %1$s", - "create.item_attributes.in_item_group": "из группы «%1$s»", - "create.item_attributes.in_item_group.inverted": "не из группы «%1$s»", - "create.item_attributes.added_by": "был добавлен %1$s", - "create.item_attributes.added_by.inverted": "был добавлен не %1$s", - "create.item_attributes.has_enchant": "зачарован на %1$s", - "create.item_attributes.has_enchant.inverted": "зачарован не на %1$s", - "create.item_attributes.color": "окрашен в %1$s", - "create.item_attributes.color.inverted": "окрашен не в %1$s", - "create.item_attributes.has_fluid": "содержит %1$s", - "create.item_attributes.has_fluid.inverted": "не содержит %1$s", - "create.item_attributes.has_name": "назван как %1$s", - "create.item_attributes.has_name.inverted": "назван не как %1$s", - "create.item_attributes.book_author": "подписан %1$s", - "create.item_attributes.book_author.inverted": "подписан не %1$s", - "create.item_attributes.book_copy_original": "оригинал", - "create.item_attributes.book_copy_original.inverted": "не оригинал", - "create.item_attributes.book_copy_first": "копия", - "create.item_attributes.book_copy_first.inverted": "не копия", - "create.item_attributes.book_copy_second": "копия копии", - "create.item_attributes.book_copy_second.inverted": "не копия копии", - "create.item_attributes.book_copy_tattered": "ветхий", - "create.item_attributes.book_copy_tattered.inverted": "не ветхий", - "create.item_attributes.astralsorcery_amulet": "исправляет %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "исправляет не %1$s", - "create.item_attributes.astralsorcery_constellation": "настроено на %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "настроено не на %1$s", - "create.item_attributes.astralsorcery_crystal": "имеет характеристики кристалла %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "не имеет характеристик кристалла %1$s", - "create.item_attributes.astralsorcery_perk_gem": "имеет характеристики перка %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "не имеет характеристик перка %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Атрибуты не выбраны", - "create.gui.attribute_filter.selected_attributes": "Выбранные атрибуты:", - "create.gui.attribute_filter.add_attribute": "Добавить атрибут в фильтр", - "create.gui.attribute_filter.add_inverted_attribute": "Добавить обратный атрибут в фильтр", - "create.gui.attribute_filter.allow_list_disjunctive": "Белый список (любой)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Предметы проходят, если у них есть какой-либо из выбранных атрибутов.", - "create.gui.attribute_filter.allow_list_conjunctive": "Белый список (все)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Предметы проходят, только если они имеют ВСЕ выбранные атрибуты.", - "create.gui.attribute_filter.deny_list": "Чёрный список", - "create.gui.attribute_filter.deny_list.description": "Предметы проходят, если они НЕ имеют ни одного из выбранных атрибутов.", - "create.gui.attribute_filter.add_reference_item": "Положите предмет", - - "create.tooltip.holdForDescription": "Удерживайте [%1$s] для сводки", - "create.tooltip.holdForControls": "Удерживайте [%1$s] для управления", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Требование к скорости: %1$s", - "create.tooltip.speedRequirement.none": "Нет", - "create.tooltip.speedRequirement.slow": "Медленная", - "create.tooltip.speedRequirement.medium": "Умеренная", - "create.tooltip.speedRequirement.fast": "Быстрая", - "create.tooltip.stressImpact": "Создаваемая нагрузка: %1$s", - "create.tooltip.stressImpact.low": "Низкая", - "create.tooltip.stressImpact.medium": "Средняя", - "create.tooltip.stressImpact.high": "Высокая", - "create.tooltip.stressImpact.overstressed": "Перегрузка", - "create.tooltip.up_to": "До %1$s", - "create.tooltip.capacityProvided": "Допустимая нагрузка: %1$s", - "create.tooltip.capacityProvided.low": "Низкая", - "create.tooltip.capacityProvided.medium": "Средняя", - "create.tooltip.capacityProvided.high": "Высокая", - "create.tooltip.generationSpeed": "Создаёт %1$s %2$s", - "create.tooltip.analogStrength": "Аналоговая сила: %1$s/15", - - "create.mechanical_arm.extract_from": "Берёт предметы из %1$s", - "create.mechanical_arm.deposit_to": "Складывает предметы в %1$s", - "create.mechanical_arm.summary": "Механическая рука имеет %1$s вход(ов) и %2$s выход(ов)", - "create.mechanical_arm.points_outside_range": "Выбранные цели (%1$s) удалены из-за ограничений диапазона", - - "create.weighted_ejector.target_set": "Цель выбрана", - "create.weighted_ejector.target_not_valid": "Бросает до ближайшего блока (Неподходящая цель)", - "create.weighted_ejector.no_target": "Бросает до ближайшего блока (Цель не была выбрана)", - "create.weighted_ejector.targeting": "Бросает до [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Размер бросаемого стака", - - "create.logistics.when_multiple_outputs_available": "Режим распределения", - - "create.mechanical_arm.selection_mode.round_robin": "По кругу", - "create.mechanical_arm.selection_mode.forced_round_robin": "Строго по кругу", - "create.mechanical_arm.selection_mode.prefer_first": "Предпочитать первичную цель", - - "create.tunnel.selection_mode.split": "Разделение", - "create.tunnel.selection_mode.forced_split": "Строгое разделение", - "create.tunnel.selection_mode.round_robin": "По кругу", - "create.tunnel.selection_mode.forced_round_robin": "Строго по кругу", - "create.tunnel.selection_mode.prefer_nearest": "Предпочтительно ближайший", - "create.tunnel.selection_mode.randomize": "Случайно", - "create.tunnel.selection_mode.synchronize": "Синхронизировать входы", - - "create.tooltip.chute.header": "Информация о жёлобе:", - "create.tooltip.chute.items_move_down": "Предметы двигаются вниз", - "create.tooltip.chute.items_move_up": "Предметы двигаются вверх", - "create.tooltip.chute.no_fans_attached": "Нет подключенных вентиляторов", - "create.tooltip.chute.fans_push_up": "Вентилятор толкает снизу", - "create.tooltip.chute.fans_push_down": "Вентилятор толкает сверху", - "create.tooltip.chute.fans_pull_up": "Вентилятор тянет сверху", - "create.tooltip.chute.fans_pull_down": "Вентилятор тянет снизу", - "create.tooltip.chute.contains": "Содержит: %1$s x%2$s", - "create.tooltip.deployer.header": "Информация об автономном активаторе:", - "create.tooltip.deployer.using": "Режим: Атака/Разрушение", - "create.tooltip.deployer.punching": "Режим: Использование/Стройка", - "create.tooltip.deployer.contains": "Держит: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "В данный момент распределяют:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "ПКМ, чтобы получить", - - "create.linked_controller.bind_mode": "Режим привязки активирован", - "create.linked_controller.press_keybind": "Нажмите %1$s, %2$s, %3$s, %4$s, %5$s или %6$s, чтобы привязать эту частоту к соответствующей клавише.", - "create.linked_controller.key_bound": "Частота привязана к %1$s", - "create.linked_controller.frequency_slot_1": "Клавиша: %1$s, Частота #1", - "create.linked_controller.frequency_slot_2": "Клавиша: %1$s, Частота #2", - - "create.crafting_blueprint.crafting_slot": "Слот для ингредиентов", - "create.crafting_blueprint.filter_items_viable": "Продвинутые фильтры предметов применимы", - "create.crafting_blueprint.display_slot": "Отображаемая ячейка", - "create.crafting_blueprint.inferred": "Производные от рецепта", - "create.crafting_blueprint.manually_assigned": "Назначен вручную", - "create.crafting_blueprint.secondary_display_slot": "Дополнительная отображаемая ячейка", - "create.crafting_blueprint.optional": "Опционально", - - "create.potato_cannon.ammo.attack_damage": "%1$s урона от попадания", - "create.potato_cannon.ammo.reload_ticks": "%1$s тиков перезарядки", - "create.potato_cannon.ammo.knockback": "%1$s силы отбрасывания", - - "create.hint.hose_pulley.title": "Бесконечное снабжение", - "create.hint.hose_pulley": "Целевой водный резервуар считается бесконечным.", - "create.hint.mechanical_arm_no_targets.title": "Нет целей", - "create.hint.mechanical_arm_no_targets": "Кажется, эта _механическая рука_ не имеет никаких целей. Выберите _ремни_, _депо_, _воронки_, или другие блоки, с помощью _правого клика_, удерживая _механическую руку_.", - "create.hint.empty_bearing.title": "Обновить подшипник", - "create.hint.empty_bearing": "_Правый клик_ по подшипнику _пустой рукой_, чтобы _присоединить_ к нему структуру, которую вы построили перед ним.", - "create.hint.full_deployer.title": "Переполнение автономного активатора", - "create.hint.full_deployer": "Похоже, что этот _автономный активатор_ содержит _лишние_ _предметы_, которые необходимо _извлечь_. Используйте _воронку_ или _другие способы_, чтобы освободить его от переполнения.", - - "create.backtank.low": "Низкое давление в баллоне!", - "create.backtank.depleted": "Давление в баллоне исчерпано!", - - "create.hint.derailed_train.title": "Железнодорожная авария", - "create.hint.derailed_train": "Похоже, что этот _поезд_ сошёл с путей. Щёлкните _ПКМ_ _гаечным ключом_, чтобы заново установить его на ближайшие пути.", - - "create.boiler.status": "Статус котла: %1$s", - "create.boiler.status_short": "Котёл: %1$s", - "create.boiler.passive": "Нач.", - "create.boiler.idle": "Выкл", - "create.boiler.lvl": "%1$s ур.", - "create.boiler.max_lvl": "Макс.", - "create.boiler.size": "Объём", - "create.boiler.size_dots": "....... ", - "create.boiler.water": "Вода", - "create.boiler.water_dots": "......... ", - "create.boiler.heat": "Нагрев", - "create.boiler.heat_dots": "..... ", - "create.boiler.via_one_engine": "с помощью 1 двигателя", - "create.boiler.via_engines": "с помощью %1$s двигателей", - - "create.gui.schedule.lmb_edit": "ЛКМ для редактирования", - "create.gui.schedule.rmb_remove": "ПКМ для удаления", - "create.gui.schedule.duplicate": "Дублировать", - "create.gui.schedule.remove_entry": "Удалить инструкцию", - "create.gui.schedule.add_entry": "Добавить инструкцию", - "create.gui.schedule.move_up": "Переместить выше", - "create.gui.schedule.move_down": "Переместить ниже", - "create.gui.schedule.add_condition": "Добавить условие", - "create.gui.schedule.alternative_condition": "Альтернативное условие", - - "create.schedule.instruction_type": "Следующая инструкция:", - "create.schedule.instruction.editor": "Редактор инструкций", - "create.schedule.instruction.destination": "Следовать до станции", - "create.schedule.instruction.destination.summary": "Следовать до станции:", - "create.schedule.instruction.filter_edit_box": "Название станции", - "create.schedule.instruction.filter_edit_box_1": "Используйте * в качестве текстового подстановочного знака", - "create.schedule.instruction.filter_edit_box_2": "Пример: 'Моя Станция, платформа *'", - "create.schedule.instruction.filter_edit_box_3": "Поезд выберет наименьшее совпадение", - "create.schedule.instruction.rename": "Сменить имя расписания", - "create.schedule.instruction.rename.summary": "Новое название:", - "create.schedule.instruction.name_edit_box": "Название расписания", - "create.schedule.instruction.name_edit_box_1": "Влияет на текст, отображаемый на табло", - "create.schedule.instruction.name_edit_box_2": "По умолчанию используется имя следующего отправления", - "create.schedule.instruction.throttle": "Изменить тягу", - "create.schedule.instruction.throttle.summary": "Изменить тягу до %1$s", - "create.schedule.instruction.throttle_edit_box": "Тяга", - "create.schedule.instruction.throttle_edit_box_1": "Влияет на максимальную скорость поезда", - "create.schedule.condition_type": "Продолжить, если/после:", - "create.schedule.condition.editor": "Редактор условий", - "create.schedule.condition.delay": "Пауза расписания", - "create.schedule.condition.delay_short": "Ожидание: %1$s", - "create.schedule.condition.delay.status": "До отправления %1$s", - "create.schedule.condition.idle": "Неизменение груза", - "create.schedule.condition.idle_short": "Простой груза: %1$s %1$s", - "create.schedule.condition.idle.status": "Простой груза: %1$s", - "create.schedule.condition.for_x_time": "в течение %1$s", - "create.schedule.condition.unloaded": "Чанк выгружен", - "create.schedule.condition.unloaded.status": "Ожидание выгрузки чанка", - "create.schedule.condition.powered": "Станция запитана", - "create.schedule.condition.powered.status": "Станция ожидает сигнал", - "create.schedule.condition.time_of_day": "Время суток", - "create.schedule.condition.time_of_day.scheduled": "Отправление в %1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "Интервал движения", - "create.schedule.condition.time_of_day.rotation.every_24": "Ежедневно", - "create.schedule.condition.time_of_day.rotation.every_12": "Каждые 12ч", - "create.schedule.condition.time_of_day.rotation.every_6": "Каждые 6ч", - "create.schedule.condition.time_of_day.rotation.every_4": "Каждые 4ч", - "create.schedule.condition.time_of_day.rotation.every_3": "Каждые 3ч", - "create.schedule.condition.time_of_day.rotation.every_2": "Каждые 2ч", - "create.schedule.condition.time_of_day.rotation.every_1": "Каждый час", - "create.schedule.condition.time_of_day.rotation.every_0_45": "Каждые 45м", - "create.schedule.condition.time_of_day.rotation.every_0_30": "Каждые 30м", - "create.schedule.condition.time_of_day.rotation.every_0_15": "Каждые 15м", - "create.schedule.condition.time_of_day.status": "Отправление в ", - "create.schedule.condition.threshold.train_holds": "Поезд содержит %1$s", - "create.schedule.condition.threshold.greater": "больше, чем", - "create.schedule.condition.threshold.less": "меньше, чем", - "create.schedule.condition.threshold.equal": "точно", - "create.schedule.condition.threshold.x_units_of_item": "%1$s %2$s (%3$s)", - "create.schedule.condition.threshold.matching_content": "Определённое содержимое", - "create.schedule.condition.threshold.anything": "предметов", - "create.schedule.condition.threshold.item_measure": "Количество предметов", - "create.schedule.condition.threshold.items": "штук", - "create.schedule.condition.threshold.stacks": "стаков", - "create.schedule.condition.threshold.buckets": "вёдер", - "create.schedule.condition.threshold.status": "Груз: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "Эталонный предмет", - "create.schedule.condition.threshold.place_item_2": "Можно использовать фильтры", - "create.schedule.condition.threshold.place_item_3": "Оставьте пустым, чтобы выбрать все предметы", - "create.schedule.condition.fluid_threshold": "Состояние жидкого груза", - "create.schedule.condition.item_threshold": "Состояние груза", - "create.schedule.condition.redstone_link": "Беспроводной сигнал", - "create.schedule.condition.redstone_link.status": "Поезд ожидает сигнал", - "create.schedule.condition.redstone_link_on": "Сигнал включён", - "create.schedule.condition.redstone_link_off": "Сигнал выключен", - "create.schedule.condition.redstone_link.powered": "Включёна", - "create.schedule.condition.redstone_link.unpowered": "Выключена", - "create.schedule.condition.redstone_link.frequency_state": "Состояние частоты:", - "create.schedule.condition.redstone_link.frequency_powered": "Частота включена:", - "create.schedule.condition.redstone_link.frequency_unpowered": "Частота выключена:", - "create.schedule.condition.player_count": "Посадка пассажиров", - "create.schedule.condition.player_count.summary": "%1$s игрок", - "create.schedule.condition.player_count.summary_plural": "%1$s игрока(ов)", - "create.schedule.condition.player_count.seated": "%1$s сидит(ят)", - "create.schedule.condition.player_count.players": "Игроков", - "create.schedule.condition.player_count.condition": "Условие", - "create.schedule.condition.player_count.exactly": "точно", - "create.schedule.condition.player_count.or_above": "больше", - "create.schedule.condition.player_count.status": "Пассажиров: %1$s/%2$s", - "create.schedule.loop": "Повторять расписание", - "create.schedule.loop1": "Начинать расписание сначала,", - "create.schedule.loop2": "после завершения", - "create.schedule.reset": "Начать расписание сначала", - "create.schedule.skip": "Пропустить текущий шаг расписания", - "create.schedule.applied_to_train": "Теперь поезд следует по этому расписанию", - "create.schedule.non_controlling_seat": "Машинист должен сидеть перед блоком управления", - "create.schedule.remove_with_empty_hand": "Отзовите текущее расписание пустой рукой", - "create.schedule.auto_removed_from_train": "Автоматическое расписание отозвано", - "create.schedule.removed_from_train": "Расписание отозвано от машиниста", - "create.schedule.no_stops": "В этом расписании нет остановок", - "create.schedule.continued": "Расписание возобновлено", - - "create.track.selection_cleared": "Выбор отменён", - "create.track.valid_connection": "Можно соединить ✔", - "create.track.second_point": "Разместите пути на горизонтальной поверхности или выберите другие", - "create.track.too_far": "Слишком далеко...", - "create.track.original_missing": "Выбранные пути разрушены, нажмите ПКМ крадучись, чтобы выйти из режима размещения", - "create.track.perpendicular": "Невозможно соединить пути перпендикулярно", - "create.track.ascending_s_curve": "Невозможно создать наклонные S-образные изгибы", - "create.track.too_sharp": "Слишком резкий угол поворота", - "create.track.too_steep": "Слишком крутой склон", - "create.track.slope_turn": "Невозможно сделать склон на повороте", - "create.track.opposing_slopes": "Невозможно соединить противоположные склоны", - "create.track.leave_slope_ascending": "Нельзя покидать этот склон при подъеме", - "create.track.leave_slope_descending": "Нельзя покидать этот склон при спуске", - "create.track.turn_90": "Можно поворачивать только на 90 градусов", - "create.track.junction_start": "Нельзя начинать соединение со стыка рельс", - "create.track.turn_start": "Нельзя начинать соединение с поворота", - "create.track.not_enough_tracks": "Не хватает путей", - "create.track.not_enough_pavement": "Не хватает поддерживающих блоков", - - "create.portal_track.failed": "Невозможно разместить портальные пути:", - "create.portal_track.missing": "Целевой портал ещё не сгенерирован", - "create.portal_track.blocked": "Целевое местоположение заблокировано (%1$s,%2$s,%3$s)", - - "create.station.idle": "Станция в ожидании", - "create.station.assembly_title": "Сборка поезда", - "create.station.close": "Закрыть окно", - "create.station.cancel": "Отменить сборку", - "create.station.failed": "Ошибка при сборке", - "create.station.icon_type": "Тип значка", - "create.station.create_train": "Создать новый поезд", - "create.station.assemble_train": "Собрать поезд", - "create.station.disassemble_train": "Разобрать поезд", - "create.station.remove_schedule": "Отозвать расписание", - "create.station.remove_auto_schedule": "Отозвать автоматическое расписание", - "create.station.no_assembly_diagonal": "Нельзя строить поезда", - "create.station.no_assembly_diagonal_1": "на пересечениях путей", - "create.station.no_assembly_curve": "Нельзя строить поезда", - "create.station.no_assembly_curve_1": "на изогнутых путях.", - "create.station.train_not_aligned": "Невозможно разобрать, не все", - "create.station.train_not_aligned_1": "вагонные тележки были выровнены.", - "create.station.carriage_number": "Вагон № %1$s:", - "create.station.retry": "Исправьте это и повторите попытку.", - "create.station.no_bogeys": "Нет вагонных тележек", - "create.station.one_bogey": "1 вагонная тележка", - "create.station.more_bogeys": "%1$s вагонные(ых) тележки(ек)", - "create.station.how_to": "Нажмите Ж/д корпусом по выделенным путям, чтобы сделать тележку.", - "create.station.how_to_1": "Тележку можно убрать, сломав блок над ней.", - "create.station.how_to_2": "Один вагон может иметь до двух тележек.", - - "create.train_assembly.too_many_bogeys": "Слишком много вагонных тележек прицеплено: %1$s шт.", - "create.train_assembly.frontmost_bogey_at_station": "Передняя вагонная тележка должна быть на указателе станции.", - "create.train_assembly.no_bogeys": "Вагонные тележки не найдены.", - "create.train_assembly.not_connected_in_order": "Вагонные тележки соединены не по порядку.", - "create.train_assembly.bogeys_too_close": "Вагонные тележки %1$s и %2$s слишком близко друг к другу.", - "create.train_assembly.single_bogey_carriage": "Эта вагонная тележка не может поддерживать вагон самостоятельно.", - "create.train_assembly.nothing_attached": "Структура не склеена с вагонной тележкой № %1$s.", - "create.train_assembly.no_controls": "В поезде должен быть установлен как минимум один контроллер, обращённый вперёд.", - "create.train_assembly.sideways_controls": "Контроллер поезда направлен не вперёд.", - "create.train_assembly.bogey_created": "Разместите ещё одну тележку, нажав на выделенные пути", - "create.train_assembly.requires_casing": "Используйте Ж/д корпус для создания вагонных тележек на путях", - - "create.track_target.set": "Пути выбраны", - "create.track_target.success": "Успешно привязана к выбранным путям", - "create.track_target.clear": "Выбор путей отменён", - "create.track_target.missing": "Сначала выберите пути, нажав ПКМ по ним", - "create.track_target.too_far": "Установите станцию ближе к путям...", - "create.track_target.no_junctions": "Невозможно установить маркер станции на перекрёстке", - "create.track_target.occupied": "Выбранные пути заняты", - "create.track_target.invalid": "Невозможно выбрать эти пути", - - "create.train.unnamed": "Безымянный поезд", - "create.train.cannot_relocate_moving": "Невозможно переместить движущийся поезд", - "create.train.relocate": "Нажмите по путям, чтобы переместить %1$s. ПКМ крадучись для отмены", - "create.train.relocate.abort": "Перенос отменён", - "create.train.relocate.success": "Успешно перенесён", - "create.train.relocate.valid": "Можно переместить сюда, нажмите для подтверждения", - "create.train.relocate.invalid": "Невозможно переместить поезд сюда", - "create.train.relocate.too_far": "Невозможно переместить поезд так далеко...", - "create.train.departing_from": "Отправился от %1$s", - "create.train.arrived_at": "Прибыл на %1$s", - "create.train.status": " Информация о поезде: %1$s", - "create.train.status.back_on_track": "Поезд снова на ходу", - "create.train.status.collision": "Авария с другим поездом", - "create.train.status.end_of_track": "Поезд достиг конца путей", - "create.train.status.double_portal": "Поезд не может войти в портал, покидая другой", - "create.train.status.coupling_stress": "Аварийная остановка из-за нагрузки на сцепление вагонов", - "create.train.status.track_missing": "Под поездом нет путей", - "create.train.status.paused_for_manual": "Расписание приостановлено для ручного управления", - "create.train.status.opposite_driver": "Путь требует, чтобы машинист смотрел в противоположном направлении", - "create.train.status.missing_driver": "Машинист пропал", - "create.train.status.found_driver": "Найден новый машинист", - "create.train.status.navigation_success": "Движение успешно восстановлено", - "create.train.status.no_match": "Станция '%1$s' не найдена", - "create.train.status.no_path": "Не удалось найти подходящий путь к следующему запланированному пункту назначения", - - "create.track_signal.cannot_change_mode": "Невозможно переключить режим этого светофора", - "create.track_signal.mode_change.entry_signal": "-> Разрешить проезд, если сегмент не занят", - "create.track_signal.mode_change.cross_signal": "-> Разрешить проезд, если сегмент полностью проходим и не занят", - - "create.contraption.controls.start_controlling": "Под управлением: %1$s", - "create.contraption.controls.stop_controlling": "Выход из режима управления", - "create.contraption.controls.approach_station": "Зажмите %1$s для прибытия на %2$s", - - "create.display_link.set": "Выбрана целевая позиция", - "create.display_link.success": "Успешно привязан к целевой позиции", - "create.display_link.clear": "Выбор целевой позиции отменён", - "create.display_link.too_far": "Целевая позиция слишком далеко...", - "create.display_link.invalid": "Передатчик не имеет выбранной цели, привяжите его и попробуйте ещё раз", - "create.display_link.title": "Передатчик информации", - "create.display_link.no_source": "Не источник информации", - "create.display_link.no_target": "Не цель для отображения", - "create.display_link.reading_from": "Считывать из:", - "create.display_link.writing_to": "Записывать в:", - "create.display_link.attached_side": "Блок, к которому прикреплён", - "create.display_link.targeted_location": "Блок, куда присылает информацию", - "create.display_link.view_compatible": "Нажмите, чтобы увидеть все совместимые блоки", - "create.display_link.information_type": "Тип информации", - "create.display_link.display_on": "Записывать информацию в:", - "create.display_link.display_on_multiline": "Начать записывать в:", - - "create.display_source.label": "Добавочная надпись", - "create.display_source.combine_item_names": "Названия предметов", - "create.display_source.count_items": "Количество предметов", - "create.display_source.list_items": "Список предметов", - "create.display_source.fluid_amount": "Количество жидкостей", - "create.display_source.list_fluids": "Список жидкостей", - "create.display_source.nixie_tube": "Скопировать значение", - "create.display_source.fill_level": "Уровень заполнения", - "create.display_source.fill_level.display": "Формат отображения", - "create.display_source.fill_level.percent": "Процент", - "create.display_source.fill_level.progress_bar": "Полоса прогресса", - "create.display_source.value_list.display": "Отображение значения", - "create.display_source.value_list.shortened": "Сокращённо", - "create.display_source.value_list.full_number": "Полностью", - "create.display_source.value_list.thousand": "т", - "create.display_source.value_list.million": "М", - "create.display_source.player_deaths": "Смерти игрока", - "create.display_source.scoreboard": "Скорборд", - "create.display_source.scoreboard.objective": "Название скорборда", - "create.display_source.scoreboard.objective_not_found": "'%1$s' не найден", - "create.display_source.scoreboard.objective.deaths": "Смерти игрока", - "create.display_source.time_of_day": "Время суток", - "create.display_source.stop_watch": "Секундомер", - "create.display_source.time.format": "Формат времени", - "create.display_source.time.12_hour": "12 часов", - "create.display_source.time.24_hour": "24 часа", - "create.display_source.accumulate_items": "Счётчик предметов", - "create.display_source.item_throughput": "Производительность", - "create.display_source.item_throughput.interval": "Интервал", - "create.display_source.item_throughput.interval.second": "в секунду", - "create.display_source.item_throughput.interval.minute": "в минуту", - "create.display_source.item_throughput.interval.hour": "в час", - "create.display_source.train_status": "Статус расписания", - "create.display_source.station_summary": "Сводка станции", - "create.display_source.station_summary.filter": "Фильтр названия станции", - "create.display_source.station_summary.train_name_column": "Размер столбца Поезд", - "create.display_source.station_summary.platform_column": "Размер столбца Платформа", - "create.display_source.station_summary.now": "отп.", - "create.display_source.station_summary.minutes": " мин", - "create.display_source.station_summary.seconds": "%1$sс", - "create.display_source.observed_train_name": "Название поезда", - "create.display_source.max_enchant_level": "Уровень чар", - "create.display_source.boiler_status": "Статус котла", - "create.display_source.entity_name": "Имя существа", - "create.display_source.kinetic_speed": "Обороты в минуту", - "create.display_source.kinetic_speed.absolute": "Без направления", - "create.display_source.kinetic_speed.directional": "С направлением", - "create.display_source.kinetic_stress": "Стресс сети", - "create.display_source.kinetic_stress.display": "Отображаемая информация", - "create.display_source.kinetic_stress.progress_bar": "Полоса прогресса", - "create.display_source.kinetic_stress.percent": "Процент нагрузки", - "create.display_source.kinetic_stress.current": "Нагрузка в ЕН", - "create.display_source.kinetic_stress.max": "Общая ёмкость", - "create.display_source.kinetic_stress.remaining": "Осталось ЕН", - "create.display_source.redstone_power": "Редстоун-сигнал", - "create.display_source.redstone_power.display": "Формат отображения", - "create.display_source.redstone_power.number": "Число", - "create.display_source.redstone_power.progress_bar": "Полоса прогресса", - "create.display_source.boiler.not_enough_space": "нет места", - "create.display_source.boiler.for_boiler_status": "для текста", - - "create.display_target.line": "%1$s строка", - "create.display_target.page": "%1$s страница", - "create.display_target.single_line": "Одна строка", - - "create.flap_display.cycles.alphabet": " ;А;Б;В;Г;Д;Е;Ё;Ж;З;И;Й;К;Л;М;Н;О;П;Р;С;Т;У;Ф;Х;Ц;Ч;Ш;Щ;Ъ;Ы;Ь;Э;Ю;Я", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; мин;отп.;15с;30с;45с", - "create.flap_display.cycles.shortened_numbers": " ;Т;М", - "create.flap_display.cycles.fluid_units": "мВ;В ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "Выбранная область слишком большая", - "create.super_glue.cannot_reach": "Выбранные блоки должны быть соединены", - "create.super_glue.click_to_confirm": "Нажмите ещё раз, чтобы подтвердить", - "create.super_glue.click_to_discard": "Нажмите ПКМ крадучись, чтобы отменить выбор", - "create.super_glue.first_pos": "Выбрана первая позиция", - "create.super_glue.abort": "Выбор отменён", - "create.super_glue.not_enough": "Мало клея...", - "create.super_glue.success": "Нанесение клея...", - - "create.gui.config.overlay1": "Привет :)", - "create.gui.config.overlay2": "Это образец оверлея", - "create.gui.config.overlay3": "Кликни и тащи с помощью мыши", - "create.gui.config.overlay4": "чтобы переместить его", - "create.gui.config.overlay5": "Нажми ESC чтобы выйти", - "create.gui.config.overlay6": "и сохранить новую позицию", - "create.gui.config.overlay7": "Введи /create overlay reset", - "create.gui.config.overlay8": "чтобы сбросить позицию до стандартной", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Тики сервера в настоящее время замедлены на %s мс :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Тики сервера теперь замедлены на %s мс >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Тики сервера вернулись в норму :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: используйте /killtps stop , чтобы вернуть тик сервера на обычную скорость", - "create.command.killTPSCommand.status.usage.1": "[Create]: используйте /killtps start <Время тика>, чтобы искусственно замедлить тик сервера", - "create.command.killTPSCommand.argument.tickTime": "Время тика", - - "create.contraption.minecart_contraption_too_big": "Эта вагонеточная штуковина кажется слишком большой, чтобы её можно было поднять", - "create.contraption.minecart_contraption_illegal_pickup": "Мистическая сила связывает эту вагонеточную штуковину с миром", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Штуковина останавливается", - "create.subtitle.peculiar_bell_use": "Особенный колокол звонит", - "create.subtitle.worldshaper_place": "Ручной редактор мира делает «Зап»", - "create.subtitle.whistle_train_manual": "Поезд гудит", - "create.subtitle.steam": "Шум пара", - "create.subtitle.saw_activate_stone": "Активируется механическая пила", - "create.subtitle.schematicannon_finish": "Схематичная пушка закончила работу", - "create.subtitle.crafter_craft": "Крафтер создаёт", - "create.subtitle.wrench_remove": "Компонент ломается", - "create.subtitle.train3": "Приглушенный шум вагонетки", - "create.subtitle.whistle": "Свист", - "create.subtitle.cogs": "Шестерни грохочут", - "create.subtitle.slime_added": "Намазывание слизи", - "create.subtitle.whistle_train_low": "Низкое гудение поезда", - "create.subtitle.schematicannon_launch_block": "Схематичная пушка строит", - "create.subtitle.controller_take": "Кафедра опустошается", - "create.subtitle.crafter_click": "Крафтер кликает", - "create.subtitle.depot_plop": "Предмет упал на депо", - "create.subtitle.confirm": "Утвердительный «Динь»", - "create.subtitle.mixing": "Смешивание", - "create.subtitle.mechanical_press_activation_belt": "Механический пресс делает «Бонк»", - "create.subtitle.fwoomp": "Картофельная пушка делает «Свомп»", - "create.subtitle.sanding_long": "Короткий звук полировки", - "create.subtitle.crushing_1": "Шум разрушения", - "create.subtitle.depot_slide": "Шелест предметов", - "create.subtitle.blaze_munch": "Всполох радостно жуёт", - "create.subtitle.funnel_flap": "Занавески воронок хлопают", - "create.subtitle.haunted_bell_use": "Призрачный колокол звонит", - "create.subtitle.scroll_value": "Щелчки прокрутки", - "create.subtitle.controller_put": "Контроллер стучит", - "create.subtitle.cranking": "Рукоятка вращается", - "create.subtitle.sanding_short": "Звук полировки", - "create.subtitle.wrench_rotate": "Использован гаечный ключ", - "create.subtitle.potato_hit": "Еда врезается", - "create.subtitle.saw_activate_wood": "Механическая пила работает", - "create.subtitle.whistle_high": "Высокий свист", - "create.subtitle.whistle_train_manual_low": "Низкое гудение поезда", - "create.subtitle.whistle_train": "Гудение поезда", - "create.subtitle.haunted_bell_convert": "Призрачный колокол пробуждается", - "create.subtitle.train": "Грохот колёс", - "create.subtitle.deny": "Отрицательный «Буп»", - "create.subtitle.controller_click": "Клики контроллера", - "create.subtitle.whistle_low": "Низкий свист", - "create.subtitle.copper_armor_equip": "Позвякивание снаряжения для дайвинга", - "create.subtitle.mechanical_press_activation": "Механический пресс активирован", - "create.subtitle.contraption_assemble": "Штуковина движется", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "ДЕРЕВЯННАЯ СКОБА", - "block.create.wooden_bracket.tooltip.summary": "_Украсьте_ ваши _Валы, Шестерни_ и _Трубы_, используя уютное деревянное укрепление.", - - "block.create.metal_bracket.tooltip": "МЕТАЛЛИЧЕСКАЯ СКОБА", - "block.create.metal_bracket.tooltip.summary": "_Украсьте_ ваши _Валы, Шестерни_ и _Трубы_, используя прочное индустриальное укрепление.", - - "block.create.seat.tooltip": "СИДЕНЬЕ", - "block.create.seat.tooltip.summary": "Присядьте и насладитесь поездкой! Привязывает игроков к собранным _устройствам_. Отлично выглядит как простая мебель! Можно окрасить в разные цвета.", - "block.create.seat.tooltip.condition1": "ПКМ по сиденью", - "block.create.seat.tooltip.behaviour1": "Сажает игрока на _Сиденье_. Нажмите _кнопку_ _приседания_ чтобы слезть (Shift по умолчанию).", - - "item.create.blaze_cake.tooltip": "ТОРТ ВСПОЛОХА", - "item.create.blaze_cake.tooltip.summary": "Вкусное угощения для вашей трудяги — _Горелки всполоха_. Зажигает их всех!", - - "item.create.wand_of_symmetry.tooltip": "ЖЕЗЛ СИММЕТРИИ", - "item.create.wand_of_symmetry.tooltip.summary": "Идеально отражает размещаемые блоки по настроенным плоскостям.", - "item.create.wand_of_symmetry.tooltip.condition1": "На панели быстрого доступа.", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Остаётся активным.", - "item.create.wand_of_symmetry.tooltip.control1": "ПКМ по блоку", - "item.create.wand_of_symmetry.tooltip.action1": "_Создаёт_ или _перемещает_ зеркало.", - "item.create.wand_of_symmetry.tooltip.control2": "ПКМ в воздух", - "item.create.wand_of_symmetry.tooltip.action2": "_Убирает_ зеркало.", - "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадучись", - "item.create.wand_of_symmetry.tooltip.action3": "Открывает _интерфейс_ _конфигурации_.", - - "item.create.handheld_worldshaper.tooltip": "РУЧНОЙ РЕДАКТОР МИРА", - "item.create.handheld_worldshaper.tooltip.summary": "Удобный инструмент для создания _ландшафтов_ и _рельефа_ _местности_.", - "item.create.handheld_worldshaper.tooltip.control1": "ЛКМ на блок", - "item.create.handheld_worldshaper.tooltip.action1": "Устанавливает блоки, выбранным инструментом, в целевое место.", - "item.create.handheld_worldshaper.tooltip.control2": "ПКМ на блок", - "item.create.handheld_worldshaper.tooltip.action2": "Применяет выбранную _кисть_ и _инструмент_ в выбранном месте.", - "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадучись", - "item.create.handheld_worldshaper.tooltip.action3": "Открывает _интерфейс_ _конфигурации_.", - - "item.create.tree_fertilizer.tooltip": "УДОБРЕНИЕ ДЛЯ ДЕРЕВЬЕВ", - "item.create.tree_fertilizer.tooltip.summary": "Мощная комбинация минералов подходит для ускорения роста деревьев.", - "item.create.tree_fertilizer.tooltip.condition1": "ПКМ с предметом на саженце", - "item.create.tree_fertilizer.tooltip.behaviour1": "Выращивает деревья, _независимо_ от _условий_ _их_ _расположения_.", - - "item.create.extendo_grip.tooltip": "УДЛИНЕННАЯ РУКА", - "item.create.extendo_grip.tooltip.summary": "Значительно _увеличивает_ _досягаемость_ владельца.", - "item.create.extendo_grip.tooltip.condition1": "Находясь в левой руке", - "item.create.extendo_grip.tooltip.behaviour1": "Увеличивает _расстояние_ _досягаемости_ предметов, используемых в _правой_ _руке_.", - "item.create.extendo_grip.tooltip.condition2": "Когда надет Медный баллон", - "item.create.extendo_grip.tooltip.behaviour2": "_НЕ_ тратится _прочность_. Вместо этого будет тратиться _воздух_ из баллона.", - - "item.create.potato_cannon.tooltip": "КАРТОФЕЛЬНАЯ ПУШКА", - "item.create.potato_cannon.tooltip.summary": "Свомп! Запускайте выращенные вами овощи в своих врагов. Может работать от давления воздуха из _Медного_ _баллона_.", - "item.create.potato_cannon.tooltip.condition1": "ПКМ с предметом в инвентаре", - "item.create.potato_cannon.tooltip.behaviour1": "_Выстреливает_ подходящим предметом из вашего _инвентаря_.", - "item.create.potato_cannon.tooltip.condition2": "Когда надет Медный баллон", - "item.create.potato_cannon.tooltip.behaviour2": "_НЕ_ тратится _прочность_. Вместо этого будет тратиться _воздух_ из Баллона.", - - "item.create.filter.tooltip": "ФИЛЬТР", - "item.create.filter.tooltip.summary": "Управляет_ _выходами_ и входами логистических устройств с _большей_ _точностью_, _сопоставляя_ их со _списком_ _предметов_ или несколькими _вложенными_ _фильтрами_.", - "item.create.filter.tooltip.condition1": "Когда в слоте фильтра", - "item.create.filter.tooltip.behaviour1": "_Управляет_ потоком предметов в соответствии с его _конфигурацией_.", - "item.create.filter.tooltip.condition2": "ПКМ с предметом", - "item.create.filter.tooltip.behaviour2": "Открывает _интерфейс_ _конфигурации_.", - - "item.create.attribute_filter.tooltip": "ФИЛЬТР АТРИБУТОВ", - "item.create.attribute_filter.tooltip.summary": "_Управляет_ _выходами_ и _входами_ логистических устройств с _большей_ _точностью_, сопоставляя их с набором _атрибутов_ и _категорий предметов_.", - "item.create.attribute_filter.tooltip.condition1": "Когда в слоте фильтра", - "item.create.attribute_filter.tooltip.behaviour1": "_Управляет_ потоком предметов в соответствии с его _конфигурацией_.", - "item.create.attribute_filter.tooltip.condition2": "ПКМ с предметом", - "item.create.attribute_filter.tooltip.behaviour2": "Открывает _интерфейс_ _конфигурации_.", - - "item.create.empty_schematic.tooltip": "ПУСТАЯ СХЕМАТИКА", - "item.create.empty_schematic.tooltip.summary": "Используется в качестве ингредиента рецепта и для записи в _Схематичный столе_.", - - "item.create.schematic.tooltip": "СХЕМАТИКА", - "item.create.schematic.tooltip.summary": "Содержит структуру, которая может позиционироваться и помещаться в мир. Расположите голограмму по своему усмотрению и используйте _Схематичную пушку_ для её построения.", - "item.create.schematic.tooltip.condition1": "ПКМ с предметом", - "item.create.schematic.tooltip.behaviour1": "Может быть позиционирован с помощью инструментов на экране.", - "item.create.schematic.tooltip.control1": "ПКМ крадучись", - "item.create.schematic.tooltip.action1": "Открывает _интерфейс_ для ввода _точных_ _координат_.", - - "item.create.schematic_and_quill.tooltip": "СХЕМАТИКА И ПЕРО", - "item.create.schematic_and_quill.tooltip.summary": "Используется для сохранения структуры в вашем мире в файл формата .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Шаг 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Выберите две угловые точки, используя ПКМ.", - "item.create.schematic_and_quill.tooltip.condition2": "Шаг 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl_ и _прокрутка_ на голограмме для изменения размера. Нажмите ПКМ, чтобы сохранить.", - "item.create.schematic_and_quill.tooltip.control1": "ПКМ с предметом", - "item.create.schematic_and_quill.tooltip.action1": "Выбирает угловые точки / подтверждает сохранение.", - "item.create.schematic_and_quill.tooltip.control2": "Ctrl с предметом", - "item.create.schematic_and_quill.tooltip.action2": "Позволяет выбрать угловые точки в воздухе. Прокрутка для настройки расстояния.", - "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадучись", - "item.create.schematic_and_quill.tooltip.action3": "_Сбрасывает_ и _удаляет_ выделение.", - - "block.create.schematicannon.tooltip": "СХЕМАТИЧНАЯ ПУШКА", - "block.create.schematicannon.tooltip.summary": "_Ставит блоки_ для воссоздания _схематики_ в мире. Использует предметы из _соседнего_ _инвентаря_ и _порох_ в качестве _топлива_.", - "block.create.schematicannon.tooltip.condition1": "ПКМ по блоку", - "block.create.schematicannon.tooltip.behaviour1": "Открывает _интерфейс_.", - - "block.create.schematic_table.tooltip": "СХЕМАТИЧНЫЙ СТОЛ", - "block.create.schematic_table.tooltip.summary": "Записывает сохраненные схематики в _пустые_ _схематики_.", - "block.create.schematic_table.tooltip.condition1": "Когда дана пустая схема", - "block.create.schematic_table.tooltip.behaviour1": "Загружает выбранный файл из вашей папки Schematics.", - - "item.create.goggles.tooltip": "ИНЖЕНЕРНЫЕ ОЧКИ", - "item.create.goggles.tooltip.summary": "Очки для улучшения зрения с помощью полезной кинетической информации.", - "item.create.goggles.tooltip.condition1": "Когда надеты", - "item.create.goggles.tooltip.behaviour1": "Показывает _цветные_ _индикаторы_, соответствующие _уровню_ _скорости_ размещённого кинетического компонента, а также _создаваемой нагрузки_ и _мощности_ отдельных компонентов.", - "item.create.goggles.tooltip.condition2": "При взгляде на датчик", - "item.create.goggles.tooltip.behaviour2": "Показывает подробную информацию о скорости или нагрузки сети, к которой подключён датчик.", - "item.create.goggles.tooltip.condition3": "При взгляде на жидкостные контейнеры", - "item.create.goggles.tooltip.behaviour3": "Показывает детализированную информацию о _ёмкости_ блока и о хранящейся в нём хранится _жидкости_.", - - "item.create.wrench.tooltip": "ГАЕЧНЫЙ КЛЮЧ", - "item.create.wrench.tooltip.summary": "Полезный _инструмент_ для работы с _кинетическими_ штуковинами. Может использоваться для _поворота_, _демонтажа_ и _настройки_ компонентов.", - "item.create.wrench.tooltip.control1": "ПКМ по кинетическому блоку", - "item.create.wrench.tooltip.action1": "_Поворачивает_ _компонент_ с которым вы взаимодействуете _к_ _лицу_ или _от_ _лица_.", - "item.create.wrench.tooltip.control2": "ПКМ крадучись", - "item.create.wrench.tooltip.action2": "Разбирает кинетические компоненты и помещает их обратно в ваш инвентарь.", - - "block.create.nozzle.tooltip": "ФОРСУНКА", - "block.create.nozzle.tooltip.summary": "Прикрепите к передней части _Вентилятора_, чтобы распределить его влияние на сущностей _во_ _всех_ _направлениях_.", - - "block.create.cuckoo_clock.tooltip": "ЧАСЫ С КУКУШКОЙ", - "block.create.cuckoo_clock.tooltip.summary": "Прекрасная _вещица_ для _украшения_ пространства и _отслеживания_ _времени_.", - "block.create.cuckoo_clock.tooltip.condition1": "При вращении", - "block.create.cuckoo_clock.tooltip.behaviour1": "Показывают текущее время и напевает мелодию два раза в день. _Активируется_ _один_ _раз_ в _полдень_ и в _сумерках_, как только _игроки_ _могут_ _спать_.", - - "block.create.turntable.tooltip": "ПОВОРОТНЫЙ СТОЛ", - "block.create.turntable.tooltip.summary": "Преобразует _силу_ _вращения_ прямиком в морскую болезнь.", - - "block.create.toolbox.tooltip": "ЯЩИК ДЛЯ ИНСТРУМЕНТОВ", - "block.create.toolbox.tooltip.summary": "Самый дорогой компаньон каждого изобретателя. Удобно _вмещает_ большое количество _восьми различных_ типов предметов.", - "block.create.toolbox.tooltip.condition1": "ЛКМ по блоку", - "block.create.toolbox.tooltip.behaviour1": "_Сохраняет_ _содержимое_ и складывается в инвентарь игрока.", - "block.create.toolbox.tooltip.condition2": "ALT в диапазоне досягаемости", - "block.create.toolbox.tooltip.behaviour2": "Позволяет _получить быстрый доступ_ к содержимому _Ящика_ _для_ _инструментов_.", - "block.create.toolbox.tooltip.condition3": "ПКМ по блоку", - "block.create.toolbox.tooltip.behaviour3": "Открывает _интерфейс контейнера_.", - - "block.create.stockpile_switch.tooltip": "НАБЛЮДАТЕЛЬ ЗАПОЛНЕННОСТИ", - "block.create.stockpile_switch.tooltip.summary": "Подаёт редстоун-сигнал в зависимости от _заполненности_ _прикреплённого_ _ящика_.", - "block.create.stockpile_switch.tooltip.condition1": "Когда достигнут нижний предел", - "block.create.stockpile_switch.tooltip.behaviour1": "Не подаёт _редстоун-сигнал_.", - - "block.create.content_observer.tooltip": "НАБЛЮДАТЕЛЬ ЗА СОДЕРЖИМЫМ", - "block.create.content_observer.tooltip.summary": "_Обнаруживает предметы внутри _контейнеров_ и на _конвейерах_, соответствующие настроенному _фильтру_. Если наблюдаемый блок-хранилище, ремень или шланг содержит совпадающий предмет, этот компонент излучает редстоун-сигнал. Когда наблюдаемая _воронка передает_ соответствующий предмет, этот компонент испускает _редстоун-импульс_.", - "block.create.content_observer.tooltip.condition1": "Когда наблюдает за контейнером", - "block.create.content_observer.tooltip.behaviour1": "Выдаёт _редстоун-сигнал_, пока наблюдаемое содержимое совпадает с _фильтром_.", - "block.create.content_observer.tooltip.condition2": "Когда наблюдает за воронкой", - "block.create.content_observer.tooltip.behaviour2": "Выдаёт _редстоун-сигнал_, пока содержимое совпадает с _перемещаемым_ предметом.", - - "block.create.creative_crate.tooltip": "ТВОРЧЕСКИЙ ЯЩИК", - "block.create.creative_crate.tooltip.summary": "Это _хранилище_ позволяет _бесконечно_ _дублировать_ любой предмет. Поместите рядом со Схематичной пушкой, чтобы удалить любые требования к материалам.", - "block.create.creative_crate.tooltip.condition1": "Когда предмет в слоте фильтра", - "block.create.creative_crate.tooltip.behaviour1": "Всё, что извлечено из этого контейнера, обеспечит бесконечную поставку указанного предмета. Предметы, _помещённые_ в этот ящик, будут _уничтожены_.", - - "item.create.creative_blaze_cake.tooltip": "ТВОРЧЕСКИЙ ТОРТ", - "item.create.creative_blaze_cake.tooltip.summary": "Особое угощение для ваших _Горелок всполоха_. После поедания этого торта у Горелки всполоха _никогда не закончится топливо_.", - "item.create.creative_blaze_cake.tooltip.condition1": "ПКМ по Горелке всполоха", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Циклически_ изменяет уровень нагрева.", - - "block.create.controller_rail.tooltip": "КОНТРОЛИРУЮЩИЕ РЕЛЬСЫ", - "block.create.controller_rail.tooltip.summary": "_Всенаправленные запитанные рельсы_, позволяющие провести _точную настройку_ _скорости_ вагонеток.", - "block.create.controller_rail.tooltip.condition1": "Когда подан редстоун-сигнал", - "block.create.controller_rail.tooltip.behaviour1": "_Ускоряет_ или _замедляет_ _прошедшие вагонетки_, на величину зависящую от _силы сигнала_. Распространяя редстоун-сигнал на соседние контролирующие рельсы. Питание двух контролирующих рельс с разной мощностью приведет к тому, что дорожки между ними будут интерполировать свой сигнал.", - - "item.create.sand_paper.tooltip": "НАЖДАЧНАЯ БУМАГА", - "item.create.sand_paper.tooltip.summary": "Грубая бумага, которую можно использовать для _полировки материалов_. Может применяться автоматически с помощью Автономного активатора.", - "item.create.sand_paper.tooltip.condition1": "ПКМ с предметом", - "item.create.sand_paper.tooltip.behaviour1": "Полирует предметы во _второй руке_, или лежащие _на полу_, если _смотреть на них_.", - - "item.create.builders_tea.tooltip": "ЧАЙ СТРОИТЕЛЯ", - "item.create.builders_tea.tooltip.summary": "Идеальный напиток для начала дня. _Мотивирует и насыщает_.", - - "item.create.refined_radiance.tooltip": "ИЗЫСКАННОЕ СИЯНИЕ", - "item.create.refined_radiance.tooltip.summary": "Хроматический материал, _добытый_ _из_ _поглощенного_ _света_.", - "item.create.refined_radiance.tooltip.condition1": "Работа в процессе", - "item.create.refined_radiance.tooltip.behaviour1": "Использование этого материала будет доступно в следующем обновлении.", - - "item.create.shadow_steel.tooltip": "ТЕНЕВАЯ СТАЛЬ", - "item.create.shadow_steel.tooltip.summary": "Хроматический материал, _добытый_ _в_ _пустоте_.", - "item.create.shadow_steel.tooltip.condition1": "Работа в процессе", - "item.create.shadow_steel.tooltip.behaviour1": "Использование этого материала будет доступно в следующем обновлении.", - - "item.create.linked_controller.tooltip": "КОНТРОЛЛЕР СВЯЗИ", - "item.create.linked_controller.tooltip.summary": "Предоставляет _ручной_ _контроль_ над частотами _Редстоунового беспроводного передатчика сигнала_, присвоенные его _шести_ кнопкам.", - "item.create.linked_controller.tooltip.condition1": "ПКМ с предметом", - "item.create.linked_controller.tooltip.behaviour1": "Включает контроллер. _Управление_ _движением_ перехвачено, пока он активен.", - "item.create.linked_controller.tooltip.condition2": "ПКМ крадучись", - "item.create.linked_controller.tooltip.behaviour2": "Открывает _интерфейс_ _конфигурации_.", - "item.create.linked_controller.tooltip.condition3": "ПКМ по Редстоуновому беспроводному приёмнику сигнала", - "item.create.linked_controller.tooltip.behaviour3": "Включает _режим привязки_, нажмите одну из _шести кнопок_, чтобы привязать её к _частоте передатчика_.", - "item.create.linked_controller.tooltip.condition4": "ПКМ по кафедре", - "item.create.linked_controller.tooltip.behaviour4": "Помещает Контроллер на кафедру для удобства использования (ПКМ крадучись, чтобы забрать его).", - - "item.create.diving_helmet.tooltip": "ШЛЕМ ДЛЯ ДАЙВИНГА", - "item.create.diving_helmet.tooltip.summary": "Вместе с _Медным_ _баллоном_, позволяет владельцу _дышать_ _под водой_ в течение длительного времени.", - "item.create.diving_helmet.tooltip.condition1": "Когда надето", - "item.create.diving_helmet.tooltip.behaviour1": "Даёт эффект _водного Дыхания_, медленно тратя _воздух_ из Баллона.", - - "item.create.copper_backtank.tooltip": "МЕДНЫЙ БАЛЛОН", - "item.create.copper_backtank.tooltip.summary": "_Носимый_ _резервуар_ для транспортировки воздуха под давлением.", - "item.create.copper_backtank.tooltip.condition1": "Когда надето", - "item.create.copper_backtank.tooltip.behaviour1": "Обеспечивает подачу _воздуха_ под _давлением_ к оборудованию, которое в этом нуждается.", - "item.create.copper_backtank.tooltip.condition2": "При вращении", - "item.create.copper_backtank.tooltip.behaviour2": "Собирает и сжимает воздух со скоростью, зависящей от скорости вращения.", - - "block.create.placard.tooltip": "УМНАЯ РАМКА", - "block.create.placard.tooltip.summary": "_Обрамите_ свои предметы латунью с помощью этой красивой рамки. Безопасна для штуковин!", - "block.create.placard.tooltip.condition1": "ПКМ по рамке с предметом в руках", - "block.create.placard.tooltip.behaviour1": "_Добавляет_ удерживаемый _предмет_ в рамку. _Издаёт_ короткий _редстоун-сигнал_, если соответствующий предмет уже присутствует.", - "block.create.placard.tooltip.condition2": "ЛКМ по рамке с предметом", - "block.create.placard.tooltip.behaviour2": "_Убирает_ текущий _предмет_ из рамки.", - - "block.create.flywheel.tooltip": "МАХОВИК", - "block.create.flywheel.tooltip.summary": "_Украсьте_ свои _машины_ этим внушительным медным колесом.", - "block.create.flywheel.tooltip.condition1": "При вращении", - "block.create.flywheel.tooltip.behaviour1": "Начинает вращаться. Удивительно!", - - "item.create.diving_boots.tooltip": "БОТИНКИ ДЛЯ ДАЙВИНГА", - "item.create.diving_boots.tooltip.summary": "Пара _тяжелых_ _ботинок_, позволяющая лучше передвигаться по океанскому дну.", - "item.create.diving_boots.tooltip.condition1": "Когда надеты", - "item.create.diving_boots.tooltip.behaviour1": "Владелец _тонет_ _быстрее_ и _не_ может _плавать_. Ботинки дают возможность _ходить_ и _прыгать_ под водой. Носящий может беспрепятственно ходить по работающим конвейерам.", - - "item.create.crafting_blueprint.tooltip": "ЧЕРТЁЖ", - "item.create.crafting_blueprint.tooltip.summary": "_Разместив_ на стене, его можно использовать для _определения_ _расположения_ _предметов_ для более простого ручного создания. Каждый слот показывает отдельный рецепт крафта.", - "item.create.crafting_blueprint.condition1": "ПКМ по пустому слоту", - "item.create.crafting_blueprint.behaviour1": "Открывает меню _крафта_, позволяющее _настроить_ _рецепт_ и отображаемые предметы.", - "item.create.crafting_blueprint.condition2": "ПКМ по настроенному слоту", - "item.create.crafting_blueprint.behaviour2": "_Применяет_ _заданный_ _рецепт_ с подходящими ингредиентами, из вашего _инвентаря_. Зажмите _Shift_, чтобы создать до _стака_ предметов.", - - "item.create.minecart_coupling.tooltip": "СОЕДИНИТЕЛЬ ВАГОНЕТОК", - "item.create.minecart_coupling.tooltip.summary": "_Соединяет_ ваши _вагонетки_ или _Вагонеточные штуковины_ вместе, чтобы создать великолепный мини-поезд.", - "item.create.minecart_coupling.tooltip.condition1": "ПКМ по вагонеткам", - "item.create.minecart_coupling.tooltip.behaviour1": "_Соединяет_ две вагонетки вместе, пытаясь держать их на _определённой дистанции_ при движении.", - - "item.create.experience_nugget.tooltip": "КУСОЧЕК ОПЫТА", - "item.create.experience_nugget.tooltip.summary": "_Дзинь!_ Частичка _вдохновения_ от ваших фантастических изобретений.", - "item.create.experience_nugget.tooltip.condition1": "ПКМ с предметом", - "item.create.experience_nugget.tooltip.behaviour1": "_Высвобождает_ _очки опыта_, находящиеся внутри.", - - "block.create.peculiar_bell.tooltip": "ОСОБЕННЫЙ КОЛОКОЛ", - "block.create.peculiar_bell.tooltip.summary": "Декоративный _латунный колокол_. Установка его прямо над горящем _огнём душ_ может вызвать непредвиденные последствия...", - - "block.create.haunted_bell.tooltip": "ПРИЗРАЧНЫЙ КОЛОКОЛ", - "block.create.haunted_bell.tooltip.summary": "_Проклятый колокол_ населённый потерянными душами Нижнего мира.", - "block.create.haunted_bell.tooltip.condition1": "При ношении в руке или ПКМ по блоку", - "block.create.haunted_bell.tooltip.behaviour1": "Подсвечивает ближайшие _места без света_ на которых могут появляться _враждебные существа_.", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 об./мин.", - "create.ponder.shared.behaviour_modify_wrench": "Это поведение может быть изменено Гаечным ключом", - "create.ponder.shared.storage_on_contraption": "Присоединённые к штуковине инвентари будут подбирать предметы автоматически", - "create.ponder.shared.rpm8": "8 об./мин.", - "create.ponder.shared.rpm32": "32 об./мин.", - "create.ponder.shared.rpm16_source": "Источник: 16 об./мин.", - "create.ponder.shared.movement_anchors": "С помощью Суперклея или Шасси, более крупные структуры могут быть сдвинуты", - "create.ponder.tag.redstone": "Логические компоненты", - "create.ponder.tag.redstone.description": "Компоненты, помогающие с конструированием редстоуновых схем", - "create.ponder.tag.contraption_assembly": "Соединители блоков", - "create.ponder.tag.contraption_assembly.description": "Блоки и компоненты, используемые для соединения и склеивания передвигаемых структур", - "create.ponder.tag.fluids": "Жидкостные манипуляторы", - "create.ponder.tag.fluids.description": "Компоненты, помогающие перемещать и использовать жидкости", - "create.ponder.tag.decoration": "Эстетика", - "create.ponder.tag.decoration.description": "Компоненты, чаще всего используемые для декоративных целей", - "create.ponder.tag.windmill_sails": "Парусоподобные блоки", - "create.ponder.tag.windmill_sails.description": "Блоки, число которых увеличивает силу Ветряной мельницы; каждый из этих блоков имеет одинаковую эффективность в работе", - "create.ponder.tag.arm_targets": "Цели для Механической руки", - "create.ponder.tag.arm_targets.description": "Компоненты, которые могут быть выбраны входами или выходами для Механической руки", - "create.ponder.tag.kinetic_appliances": "Кинетические приборы", - "create.ponder.tag.kinetic_appliances.description": "Компоненты, использующие силу вращения", - "create.ponder.tag.kinetic_sources": "Кинетические источники", - "create.ponder.tag.kinetic_sources.description": "Компоненты, генерирующие силу вращения", - "create.ponder.tag.movement_anchor": "Опоры движения", - "create.ponder.tag.movement_anchor.description": "Компоненты, позволяющие создавать двигающиеся штуковины, оживляя прикреплённую структуру разными способами", - "create.ponder.tag.kinetic_relays": "Кинетические блоки", - "create.ponder.tag.kinetic_relays.description": "Компоненты, помогающие передавать силу вращения куда-нибудь", - "create.ponder.tag.contraption_actor": "Компоненты штуковин", - "create.ponder.tag.contraption_actor.description": "Компоненты, проявляющие особое поведение когда прикреплены к двигающейся штуковине", - "create.ponder.tag.creative": "Творческий режим", - "create.ponder.tag.creative.description": "Компоненты, обычно недоступные в режиме выживания", - "create.ponder.tag.display_sources": "Источники информации", - "create.ponder.tag.display_sources.description": "Компоненты или блоки, которые предлагают данные, которые можно прочитать с помощью Передатчика информации", - "create.ponder.tag.logistics": "Логистика", - "create.ponder.tag.logistics.description": "Компоненты, помогающие перемещать предметы", - "create.ponder.tag.display_targets": "Визуализаторы информации", - "create.ponder.tag.display_targets.description": "Компоненты или блоки, которые могут обрабатывать и отображать данные, полученные от Передатчика информации", - "create.ponder.tag.train_related": "Железнодорожное оборудование", - "create.ponder.tag.train_related.description": "Компоненты, используемые при строительстве или управлении железнодорожных штуковин", - - "create.ponder.analog_lever.header": "Управлением редстоун-сигналом используя Аналоговый рычаг", - "create.ponder.analog_lever.text_1": "Аналоговый рычаг создан как компактный и точный источник редстоун-сигнала", - "create.ponder.analog_lever.text_2": "ПКМ, чтобы увеличить силу выходного сигнала", - "create.ponder.analog_lever.text_3": "ПКМ крадучись, чтобы уменьшить силу выходного сигнала", - - "create.ponder.andesite_tunnel.header": "Использованием Андезитовых туннелей", - "create.ponder.andesite_tunnel.text_1": "Андезитовые туннели могут быть использованы, чтобы накрывать конвейеры", - "create.ponder.andesite_tunnel.text_2": "Всегда, когда у Андезитового туннеля есть доступный выход сбоку...", - "create.ponder.andesite_tunnel.text_3": "...он будет отделять ровно один предмет из любых проходящих мимо стаков", - "create.ponder.andesite_tunnel.text_4": "Остаток продолжит свой путь", - - "create.ponder.auto_schedule.header": "Станцией и автоматической выдачей Расписания", - "create.ponder.auto_schedule.text_1": "Расписания могут использоваться для предоставления машинистам пункта назначения", - "create.ponder.auto_schedule.text_2": "Компараторы будут получать редстоун-сигнал всегда, когда поезд прибыл на Станцию", - "create.ponder.auto_schedule.text_3": "Имейте в виду, что к Станции можно подойти только с указанного направления", - "create.ponder.auto_schedule.text_4": "Станции также можно использовать для автоматического назначения новых Расписаний", - "create.ponder.auto_schedule.text_5": "Расписание, положенное на Станцию, будет автоматически скопировано для машиниста поезда", - "create.ponder.auto_schedule.text_6": "В отличии от ручной выдачи, машинисты не заберут его с собой", - - "create.ponder.basin.header": "Обработкой предметов в Чашах", - "create.ponder.basin.text_1": "Чаша может хранить предметы и жидкости для обработки", - "create.ponder.basin.text_2": "После обработки, Чаши пытаются вывести результат под любую доступную сторону", - "create.ponder.basin.text_3": "Когда предоставлен подходящий компонент, у Чаши появится выходящий кран", - "create.ponder.basin.text_4": "Несколько вариантов применимы здесь", - "create.ponder.basin.text_5": "Вывод чаши будет пойман инвентарём ниже", - "create.ponder.basin.text_6": "Без выходящего крана, Чаша будет оставлять предметы, полученные в результате обработки", - "create.ponder.basin.text_7": "Это может быть полезно, если продукт должен быть использован повторно как ингредиент", - "create.ponder.basin.text_8": "Желаемые продукты должны быть в таком случае извлечены из Чаши", - "create.ponder.basin.text_9": "Фильтр может быть необходим для избежания извлечения необработанных предметов", - - "create.ponder.bearing_modes.header": "Режимами движения Механического подшипника", - "create.ponder.bearing_modes.text_1": "Когда остановлен, Подшипник установит структуру на ближайшем выровненным по сетке блоков углу", - "create.ponder.bearing_modes.text_2": "Он может быть настроен никогда не превращать структуру в блоки, или только на начальной позиции", - - "create.ponder.belt_casing.header": "Обрамлением конвейеров", - "create.ponder.belt_casing.text_1": "Латунный или Андезитовый корпус может быть использован для декорации конвейеров", - "create.ponder.belt_casing.text_2": "Используйте Гаечный ключ, чтобы убрать обрамление", - - "create.ponder.belt_connector.header": "Использованием Механических ремней", - "create.ponder.belt_connector.text_1": "ПКМ по двум валам Ремнём соединит их вместе в конвейер", - "create.ponder.belt_connector.text_2": "Ошибочные выделения могут быть отменены нажатием ПКМ крадучись", - "create.ponder.belt_connector.text_3": "Дополнительные валы могут быть добавлены в любую часть конвейера", - "create.ponder.belt_connector.text_4": "Валы, соединённые через ремни, будут вращаться с той же скоростью и направлением", - "create.ponder.belt_connector.text_5": "Добавленные Валы могут быть убраны Гаечным ключом", - "create.ponder.belt_connector.text_6": "Механические ремни могут быть окрашены в эстетических целях", - - "create.ponder.belt_directions.header": "Возможными расположениями Механических ремней", - "create.ponder.belt_directions.text_1": "Ремни не могут соединяться в произвольных направлениях", - "create.ponder.belt_directions.text_2": "1. Они могут соединяться горизонтально;", - "create.ponder.belt_directions.text_3": "2. по диагонали;", - "create.ponder.belt_directions.text_4": "3. и вертикально;", - "create.ponder.belt_directions.text_5": "4. И также они могут соединять вертикальные Валы горизонтально", - "create.ponder.belt_directions.text_6": "Это все возможные направления. Ремни могут достигать длины от 2 до 20 блоков", - - "create.ponder.belt_transport.header": "Использованием Механических ремней для логистики", - "create.ponder.belt_transport.text_1": "Двигающиеся ремни будут перемещать предметы и другие сущности", - "create.ponder.belt_transport.text_2": "ПКМ пустой рукой, чтобы забрать предметы с конвейера", - - "create.ponder.blaze_burner.header": "Кормлением Горелок всполоха", - "create.ponder.blaze_burner.text_1": "Горелки всполохов нагревают предметы, обрабатывающиеся в Чаше", - "create.ponder.blaze_burner.text_2": "Для этого, всполох должен быть накормлен воспламеняемыми предметами", - "create.ponder.blaze_burner.text_3": "С Тортом всполоха, горелка может достигать ещё большего уровня нагрева", - "create.ponder.blaze_burner.text_4": "Процесс кормления может быть автоматизирован, используя Автономный активатор или Механическую руку", - - "create.ponder.brass_funnel.header": "Использованием Латунных воронок", - "create.ponder.brass_funnel.text_1": "Андезитовая Воронка может извлекать только один предмет за раз", - "create.ponder.brass_funnel.text_2": "Латунная Воронка может извлекать их до целого стака", - "create.ponder.brass_funnel.text_3": "Прокрутка на слоте фильтра позволяет точно регулировать размер извлекаемого стака", - "create.ponder.brass_funnel.text_4": "Использование предмет на слоте фильтра, ограничит воронку до передачи только совпадающих предметов", - - "create.ponder.brass_tunnel.header": "Использованием Латунных туннелей", - "create.ponder.brass_tunnel.text_1": "Латунные туннели могут быть использованы, чтобы накрывать конвейеры", - "create.ponder.brass_tunnel.text_2": "Латунные туннели имеют слот для фильтра на каждой открытой стороне", - "create.ponder.brass_tunnel.text_3": "Фильтр на входящих соединениях блокирует неподходящие предметы", - "create.ponder.brass_tunnel.text_4": "Фильтр на выходящих соединениях может быть использован для сортировки предметов", - "create.ponder.brass_tunnel.text_5": "Всегда, когда у проходящего предмета есть несколько доступных выходов, режим распределения решит что с ним делать", - "create.ponder.brass_tunnel.text_6": "Латунные туннели на параллельных конвейерах формируют группы", - "create.ponder.brass_tunnel.text_7": "Входящие предметы будут распределены между всеми соединёнными выходами", - "create.ponder.brass_tunnel.text_8": "Для этого предметы также могут быть вложены в блок Туннеля напрямую", - - "create.ponder.brass_tunnel_modes.header": "Режимами распределения Латунного туннеля", - "create.ponder.brass_tunnel_modes.text_1": "Используя Гаечный ключ, вы можете настроить режим распределения Латунного туннеля", - "create.ponder.brass_tunnel_modes.text_10": "«Синхронизировать входы» — уникальный режим для Латунных туннелей", - "create.ponder.brass_tunnel_modes.text_11": "Предметы могут пройти только если у каждого туннеля в группе есть ожидающий у входа предмет", - "create.ponder.brass_tunnel_modes.text_12": "Это подразумевает, что все конвейеры поставляют предметы с равной скоростью", - "create.ponder.brass_tunnel_modes.text_2": "«Разделение» попытается распределить стак поровну между доступными выходами", - "create.ponder.brass_tunnel_modes.text_3": "Если выход не может принять больше предметов, он будет пропущен", - "create.ponder.brass_tunnel_modes.text_4": "«Строгое разделение» никогда не пропустит выходы и вместо этого будет ждать пока они не освободятся", - "create.ponder.brass_tunnel_modes.text_5": "«По Кругу» сохраняет цельные стаки и отдаёт их выходам по очереди", - "create.ponder.brass_tunnel_modes.text_6": "Опять же, если выход не может принять больше предметов, он будет пропущен", - "create.ponder.brass_tunnel_modes.text_7": "«Строго по кругу» никогда не пропускает выходы", - "create.ponder.brass_tunnel_modes.text_8": "«Предпочтительно ближайший» приоритизирует ближайшие выходы от места подачи предметов", - "create.ponder.brass_tunnel_modes.text_9": "«Случайно» будет отдавать целые стаки случайно выбранным выходам", - - "create.ponder.cart_assembler.header": "Движением структур при помощи Сборщиков вагонеток", - "create.ponder.cart_assembler.text_1": "Активированные Сборщики вагонеток устанавливают прикреплённые сверху структуры к проезжающим через них вагонетки", - "create.ponder.cart_assembler.text_2": "Без редстоун-сигнала они разбирают штуковины обратно в блоки", - "create.ponder.cart_assembler.text_3": "Использование Гаечного ключа на вагонетке позволит вам унести Вагонеточную штуковину куда-то ещё", - - "create.ponder.cart_assembler_dual.header": "Сборкой Штуковин-экипажей", - "create.ponder.cart_assembler_dual.text_1": "Всегда, когда два Сборщика вагонеток имеют общую прикреплённую структуру...", - "create.ponder.cart_assembler_dual.text_2": "...активация любого из них создаст Штуковину-экипаж", - "create.ponder.cart_assembler_dual.text_3": "Эти вагонетки будут вести себя так, будто они соединены Соединителем вагонеток", - - "create.ponder.cart_assembler_modes.header": "Настройкой ориентации Вагонеточных штуковин", - "create.ponder.cart_assembler_modes.text_1": "Вагонеточные штуковины будут поворачиваться в сторону движения их вагонеток", - "create.ponder.cart_assembler_modes.text_2": "Стрелкой показано, какая сторона штуковины будет считаться передней", - "create.ponder.cart_assembler_modes.text_3": "Если Сборщик настроен на блокирование вращения, то ориентация штуковин никогда не изменится", - - "create.ponder.cart_assembler_rails.header": "Другими типами вагонеток и рельс", - "create.ponder.cart_assembler_rails.text_1": "Сборщики вагонеток на обычных рельсах не будут влиять на движение проходящих вагонеток", - "create.ponder.cart_assembler_rails.text_2": "На активных Контролирующих рельсах или энергорельсах вагонетки будут стоять на месте до тех, пока Сборщик не будет активирован", - "create.ponder.cart_assembler_rails.text_3": "Другие типы вагонеток могут быть использованы как основания для Вагонеточных штуковин", - "create.ponder.cart_assembler_rails.text_4": "Самоходные вагонетки будут ехать самостоятельно, используя топливо из присоединённых инвентарей", - - "create.ponder.chain_drive.header": "Передачей силы вращения Цепными приводами в корпусе", - "create.ponder.chain_drive.text_1": "Цепные приводы передают силу вращения друг другу", - "create.ponder.chain_drive.text_2": "Все Валы соединённые таким образом будут вращаться в одном направлении", - "create.ponder.chain_drive.text_3": "Любая часть в ряду может быть повёрнута на 90 градусов", - - "create.ponder.chain_gearshift.header": "Управлением скоростью вращения Регулируемыми цепными коробками передач", - "create.ponder.chain_gearshift.text_1": "Неактивные Цепные коробки передач ведут себя точно так же, как Цепные приводы", - "create.ponder.chain_gearshift.text_2": "При активации, скорость, передаваемая другим Цепным коробкам передач в ряду удваивается", - "create.ponder.chain_gearshift.text_3": "Когда активированная Цепная коробка передач не является источником, его скорость будет снижена вдвое", - "create.ponder.chain_gearshift.text_4": "В обоих случаях Цепные приводы в ряду всегда вращаются с 2x скоростью активированной Цепной коробки передач", - "create.ponder.chain_gearshift.text_5": "Используя аналоговые сигналы, изменение скорости может быть настроено более точно, нежели в 1 или в 2 раза", - "create.ponder.chain_gearshift.text_6": "12 об./мин.", - - "create.ponder.chute.header": "Транспортировкой предметов вниз через Желоба", - "create.ponder.chute.text_1": "Желоба могут транспортировать предметы вертикально вниз", - "create.ponder.chute.text_2": "Используя Гаечный ключ, вы можете создать окно", - "create.ponder.chute.text_3": "Установка Желобов на стороны других желобов сделает их диагональными", - - "create.ponder.chute_upward.header": "Транспортировкой предметов вверх через Желоба", - "create.ponder.chute_upward.text_1": "Используя Вентилятор в корпусе внизу или наверху, Жёлоб может перемещать предметы вверх", - "create.ponder.chute_upward.text_2": "Осмотр Желобов в Инженерных очках показывает информацию о направлении движения", - "create.ponder.chute_upward.text_3": "На «заблокированном» конце предметы должны быть введены/выведены сбоку", - - "create.ponder.clockwork_bearing.header": "Оживлением структур Часовыми механизмами", - "create.ponder.clockwork_bearing.text_1": "Часовые механизмы прикрепляются к блокам спереди", - "create.ponder.clockwork_bearing.text_2": "При получении силы вращения структура повернётся в зависимости от текущего часа", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "ПКМ по механизму, чтобы остановить или вновь запустить структуру", - "create.ponder.clockwork_bearing.text_6": "Вторая структура может быть добавлена спереди Часовой стрелки", - "create.ponder.clockwork_bearing.text_7": "Убедитесь, что две структуры не соединены между собой суперклеем или чем-то схожим", - "create.ponder.clockwork_bearing.text_8": "Вторая структура станет вращаться как минутная стрелка", - - "create.ponder.clutch.header": "Управлением силой вращения с помощью Сцеплений", - "create.ponder.clutch.text_1": "Сцепление передаёт вращение по прямой", - "create.ponder.clutch.text_2": "При активации редстоун-сигналом оно разрывает соединение", - - "create.ponder.cog_speedup.header": "Переключением передач Шестернями", - "create.ponder.cog_speedup.text_1": "Большие и Маленькие шестерни могут соединяться по диагонали", - "create.ponder.cog_speedup.text_2": "Переходя с больших на маленькие шестерни, переданная скорость удвоится", - "create.ponder.cog_speedup.text_3": "Переходя в обратном направлении, переданная скорость сократится вдвое", - - "create.ponder.cogwheel.header": "Передачей силы вращения Шестернями", - "create.ponder.cogwheel.text_1": "Шестерни передают вращение другим соседним шестерням", - "create.ponder.cogwheel.text_2": "Соседние валы соединённые таким образом будут вращаться в противоположных направлениях", - - "create.ponder.cogwheel_casing.header": "Обрамлением Шестерней", - "create.ponder.cogwheel_casing.text_1": "Латунный или Андезитовый корпус можно использовать для украшения Шестерней", - "create.ponder.cogwheel_casing.text_2": "Компоненты, заключённые в корпус, не будут иметь выхода вала", - "create.ponder.cogwheel_casing.text_3": "Гаечный ключ можно использовать для переключения соединений", - - "create.ponder.creative_fluid_tank.header": "Использованием Творческих жидкостных баков", - "create.ponder.creative_fluid_tank.text_1": "Творческий жидкостный бак может использоваться для обеспечения бесконечного запаса жидкости", - "create.ponder.creative_fluid_tank.text_2": "Щёлкните ПКМ предметом, содержащим жидкость, чтобы настроить его", - "create.ponder.creative_fluid_tank.text_3": "Трубопроводы могут бесконечно вытягивать заданную жидкость из резервуара", - "create.ponder.creative_fluid_tank.text_4": "Любые жидкости, закачанные обратно в творческий жидкостный бак, будут уничтожены", - - "create.ponder.creative_motor.header": "Генерацией силы вращения Творческими моторами", - "create.ponder.creative_motor.text_1": "Творческие моторы — это компактные и настраиваемые источники Силы Вращения", - "create.ponder.creative_motor.text_2": "Прокрутка по задней панели изменяет кол-во об./мин. у вращающегося вала мотора", - - "create.ponder.creative_motor_mojang.header": "Загадкой от Mojang", - - "create.ponder.crushing_wheels.header": "Обработкой предметов Колёсами дробления", - "create.ponder.crushing_wheels.text_1": "Пара Колёс дробления может очень эффективно дробить предметы", - "create.ponder.crushing_wheels.text_2": "Кинетическая энергия должна вращать их друг в друга", - "create.ponder.crushing_wheels.text_3": "Предметы брошенные или введённые в них сверху будут обработаны", - "create.ponder.crushing_wheels.text_4": "Предметы также могут быть введены и подобраны автоматически", - - "create.ponder.deployer.header": "Использованием Автономных активаторов", - "create.ponder.deployer.text_1": "При наличии силы вращения Автономный активатор может имитировать действия игрока", - "create.ponder.deployer.text_10": "ПКМ спереди, чтобы дать ему предмет для использования", - "create.ponder.deployer.text_11": "Предметы также могут быть введены автоматически", - "create.ponder.deployer.text_12": "Автономные активаторы имеют слот для фильтра", - "create.ponder.deployer.text_13": "Когда фильтр установлен, Активатор работает только держа подходящий предмет", - "create.ponder.deployer.text_14": "Только предметы подходящие по фильтру могут быть введены...", - "create.ponder.deployer.text_15": "...и только неподходящие предметы будут выведены", - "create.ponder.deployer.text_2": "Он всегда будет взаимодействовать с местом на два блока перед ним", - "create.ponder.deployer.text_3": "Блоки прямо перед ним не будут мешать ему", - "create.ponder.deployer.text_4": "Автономные активаторы умеют:", - "create.ponder.deployer.text_5": "Ставить блоки;", - "create.ponder.deployer.text_6": "Использовать предметы;", - "create.ponder.deployer.text_7": "Активировать блоки;", - "create.ponder.deployer.text_8": "Собирать блоки;", - "create.ponder.deployer.text_9": "и атаковать мобов", - - "create.ponder.deployer_contraption.header": "Использованием Автономного активатора на штуковинах", - "create.ponder.deployer_contraption.text_1": "Всегда, когда Автономные активаторы движутся как часть штуковины...", - "create.ponder.deployer_contraption.text_2": "...они активируются на каждом посещённом блоке, используя предметы из любых хранилищ на штуковине", - "create.ponder.deployer_contraption.text_3": "Слот для фильтра может быть использован, чтобы уточнить, какие предметы ему использовать", - - "create.ponder.deployer_modes.header": "Режимами Автономного активатора", - "create.ponder.deployer_modes.text_1": "По умолчанию, Активатор имитирует ПКМ-взаимодействие", - "create.ponder.deployer_modes.text_2": "Используя Гаечный ключ, вы можете установить его на имитацию ЛКМ", - - "create.ponder.deployer_processing.header": "Обработкой предметов с помощью Автономного активатора", - "create.ponder.deployer_processing.text_1": "Держа подходящий предмет/инструмент, автономные активаторы могут обрабатывать предметы под собой", - "create.ponder.deployer_processing.text_2": "Принимаемые предметы можно бросить или положить на депо под автономным активатором", - "create.ponder.deployer_processing.text_3": "Когда предметы находятся на конвейере...", - "create.ponder.deployer_processing.text_4": "...автономный активатор будет удерживать и обрабатывать их автоматически", - - "create.ponder.deployer_redstone.header": "Управлением Автономным активатором редстоун-сигналом", - "create.ponder.deployer_redstone.text_1": "При активации редстоун-сигналом активатор перестанет работать", - "create.ponder.deployer_redstone.text_2": "Перед остановкой, Активатор завершит все начатые действия", - "create.ponder.deployer_redstone.text_3": "Таким образом, инвертированный импульс может быть использован для вызова ровно одного срабатывания", - - "create.ponder.depot.header": "Использованием Депо", - "create.ponder.depot.text_1": "Депо могут служить как «стационарный» элемент конвейера", - "create.ponder.depot.text_2": "ПКМ, что бы самостоятельно положить или забрать предметы с них", - "create.ponder.depot.text_3": "Так же, как Механические ремни, оно может предоставлять предметы для обработки", - "create.ponder.depot.text_4": "А также поставлять предметы Механическим рукам", - - "create.ponder.display_board.header": "Использованием Механического табло", - "create.ponder.display_board.text_1": "Механическое табло — это масштабируемая альтернатива табличкам", - "create.ponder.display_board.text_2": "Для работы ему требуется вращательная сила", - "create.ponder.display_board.text_3": "Текст может отображаться с помощью бирок...", - "create.ponder.display_board.text_4": "...или с помощью Передатчика информации", - "create.ponder.display_board.text_5": "Красители можно наносить на отдельные строки табло", - "create.ponder.display_board.text_6": "Цвет строки можно убрать, нажав на них пустой рукой", - - "create.ponder.display_link.header": "Настройкой Передатчиков информации", - "create.ponder.display_link.text_1": "Передатчик информации может использоваться для визуализации динамической информации", - "create.ponder.display_link.text_2": "Нажмите ПКМ на выбранное Табло...", - "create.ponder.display_link.text_3": "...затем прикрепите его к блоку для чтения информации из него", - "create.ponder.display_link.text_4": "Откройте интерфейс, чтобы выбрать и настроить то, куда и какая информация будет отправляется", - "create.ponder.display_link.text_5": "Теперь Табло будет получать информацию от Передатчика", - "create.ponder.display_link.text_6": "Не каждый блок может выступать в качестве источника информации", - "create.ponder.display_link.text_7": "Каждый совместимый блок предоставляет уникальную информацию", - "create.ponder.display_link.text_8": "Передатчик информации может отправлять информацию некоторым другим блокам", - - "create.ponder.display_link_redstone.header": "Управлением Передатчиком информации редстоун-сигналом", - "create.ponder.display_link_redstone.text_1": "При питании от редстоун-сигнала Передатчик информации перестаёт отправлять обновления", - "create.ponder.display_link_redstone.text_2": "После отключения питания таймер сбрасывается, и новая информация отправляется немедленно", - "create.ponder.display_link_redstone.text_3": "Редстоун-сигналы, отправляемые Источниками информации, не оказывают эффекта на Передатчик", - - "create.ponder.empty_blaze_burner.header": "Поимкой всполохов в Горелку", - "create.ponder.empty_blaze_burner.text_1": "ПКМ по всполоху с пустой горелкой, чтобы захватить его", - "create.ponder.empty_blaze_burner.text_2": "Также всполохи могут быть захвачены из спавнера напрямую", - "create.ponder.empty_blaze_burner.text_3": "Теперь у вас есть идеальный источник тепла для ряда машин", - "create.ponder.empty_blaze_burner.text_4": "В эстетических целях, Пустые горелки могут быть зажжены огнивом", - "create.ponder.empty_blaze_burner.text_5": "Пламя можно трансформировать, используя наполненный душами предмет", - "create.ponder.empty_blaze_burner.text_6": "Однако они не будут подходить для промышленного нагрева", - - "create.ponder.encased_fluid_pipe.header": "Обрамлением Жидкостных труб", - "create.ponder.encased_fluid_pipe.text_1": "Медный корпус можно использовать для обрамления Труб", - "create.ponder.encased_fluid_pipe.text_2": "Помимо того, что они будут скрыты в корпусе, обрамлённые Трубы блокируются в текущем состоянии", - "create.ponder.encased_fluid_pipe.text_3": "Также они больше не будут реагировать на добавление или удаление каких-либо соседних блоков", - - "create.ponder.fan_direction.header": "Воздушным потоком Вентиляторов в корпусе", - "create.ponder.fan_direction.text_1": "Вентиляторы в корпусе используют силу вращения для создания воздушного потока", - "create.ponder.fan_direction.text_2": "Сила и направление потока зависят от подаваемого вращения", - - "create.ponder.fan_processing.header": "Обработкой предметов используя Вентилятор в корпусе", - "create.ponder.fan_processing.text_1": "Проходя через лаву, воздушный поток становится горячим", - "create.ponder.fan_processing.text_2": "Предметы в его области действия будут переплавлены", - "create.ponder.fan_processing.text_3": "Съедобные предметы брошенные сюда сгорят", - "create.ponder.fan_processing.text_4": "Вместо этого, для них должна быть использована установка для копчения дымом от огня", - "create.ponder.fan_processing.text_5": "Поток, проходящий через Воду, создаёт промывающую установку", - "create.ponder.fan_processing.text_6": "Несколько новых вариантов обработки делаются с её помощью", - "create.ponder.fan_processing.text_7": "Скорость вентилятора НЕ влияет на скорость обработки, а только на дальность установки", - "create.ponder.fan_processing.text_8": "Обработка Вентиляторами может быть применена к предметам на конвейерах или депо", - - "create.ponder.fluid_pipe_flow.header": "Перемещением жидкостей при помощи Жидкостных труб", - "create.ponder.fluid_pipe_flow.text_1": "Жидкостные трубы могут соединять два или более источников и потребителей жидкости", - "create.ponder.fluid_pipe_flow.text_2": "При помощи Гаечного ключа можно создать окно на прямом отрезке трубы", - "create.ponder.fluid_pipe_flow.text_3": "Трубы с окнами не будут соединяться ни с какими другими рядом идущими отрезками труб", - "create.ponder.fluid_pipe_flow.text_4": "Приводимые в действие Механическими помпами, трубы могут транспортировать жидкости", - "create.ponder.fluid_pipe_flow.text_5": "Сначала жидкость не выкачивается", - "create.ponder.fluid_pipe_flow.text_6": "Как только поток соединит концы, они постепенно перекачают своё содержимое", - "create.ponder.fluid_pipe_flow.text_7": "Таким образом, сами блоки Труб никогда «физически» не содержат никакой жидкости", - - "create.ponder.fluid_pipe_interaction.header": "Опустошением и наполнением Жидкостных контейнеров", - "create.ponder.fluid_pipe_interaction.text_1": "Концы трубопровода могут взаимодействовать с различными блоками", - "create.ponder.fluid_pipe_interaction.text_2": "Любой блок с возможностью хранения жидкости может быть заполнен или опустошен", - "create.ponder.fluid_pipe_interaction.text_3": "Источники прямо перед открытым концом можно откачать...", - "create.ponder.fluid_pipe_interaction.text_4": "...в то время как выливание в незаполненное пространство может создать источники", - "create.ponder.fluid_pipe_interaction.text_5": "Трубы также могут извлекать жидкости непосредственно из нескольких других блоков", - - "create.ponder.fluid_tank_sizes.header": "Размерами Жидкостных баков", - "create.ponder.fluid_tank_sizes.text_1": "Жидкостные баки можно объединить для увеличения общей вместимости", - "create.ponder.fluid_tank_sizes.text_2": "Их площадь основания может составлять до 3 блоков в ширину...", - "create.ponder.fluid_tank_sizes.text_3": "...и увеличиваются в высоту более чем на 30 дополнительных уровней", - "create.ponder.fluid_tank_sizes.text_4": "При помощи Гаечного ключа можно создать окно на резервуаре", - - "create.ponder.fluid_tank_storage.header": "Хранением жидкостей в Жидкостных баках", - "create.ponder.fluid_tank_storage.text_1": "Жидкостные баки можно использовать для хранения большого количества жидкости", - "create.ponder.fluid_tank_storage.text_2": "Трубы могут закачивать и выкачивать жидкости с любой стороны", - "create.ponder.fluid_tank_storage.text_3": "Содержащаяся жидкость может быть измерена с помощью компаратора", - "create.ponder.fluid_tank_storage.text_4": "Однако, в режиме выживания жидкость нельзя добавлять или извлекать вручную", - "create.ponder.fluid_tank_storage.text_5": "Вы можете использовать Чаши, Осушители предметов и Дозаторы для опустошения или наполнения содержащих жидкость предметов", - - "create.ponder.funnel_compat.header": "Совместимостью Воронки", - "create.ponder.funnel_compat.text_1": "Воронки должны хорошо взаимодействовать с многими компонентами:", - "create.ponder.funnel_compat.text_2": "Вертикальные пилы;", - "create.ponder.funnel_compat.text_3": "Депо;", - "create.ponder.funnel_compat.text_4": "и Осушители предметов", - - "create.ponder.funnel_direction.header": "Направлением передачи Воронки", - "create.ponder.funnel_direction.text_1": "Поставленная обычным образом, Воронка забирает предметы из хранилища", - "create.ponder.funnel_direction.text_2": "Поставленная крадучись, она добавляет предметы в инвентарь", - "create.ponder.funnel_direction.text_3": "Используя Гаечный ключ, вы можете изменить направление Воронки", - "create.ponder.funnel_direction.text_4": "Те же правила применяются для большинства направлений", - "create.ponder.funnel_direction.text_5": "Воронки на конвейерах будут извлекать/вводить предметы в зависимости от направления их движения", - - "create.ponder.funnel_intro.header": "Использованием Воронок", - "create.ponder.funnel_intro.text_1": "Воронки идеально подходят для перемещения предметов из/в хранилища", - - "create.ponder.funnel_redstone.header": "Управлением Воронкой редстоун-сигналом", - "create.ponder.funnel_redstone.text_1": "Редстоун-сигнал не даст любой Воронке работать", - - "create.ponder.funnel_transfer.header": "Передачей Воронкой напрямую", - "create.ponder.funnel_transfer.text_1": "Воронки не могут перемещать предметы напрямую между закрытыми инвентарями", - "create.ponder.funnel_transfer.text_2": "Желоба или Умные желоба могут лучше подходить для этих целей", - "create.ponder.funnel_transfer.text_3": "То же касается и горизонтального перемещения. Механический ремень должен здесь помочь", - - "create.ponder.gantry_carriage.header": "Использованием Шасси портальных кранов", - "create.ponder.gantry_carriage.text_1": "Шасси портального крана могут прикрепляться и двигаться вдоль Вала портального крана", - "create.ponder.gantry_carriage.text_2": "Крановые установки могут двигать присоединённые Блоки", - - "create.ponder.gantry_cascaded.header": "Созданием Многоступенчатого портального крана", - "create.ponder.gantry_cascaded.text_1": "Валы портального крана прикрепляются к Шасси без нужды в Суперклее", - "create.ponder.gantry_cascaded.text_2": "То же относится и к Шасси на движущихся Валах портального крана", - "create.ponder.gantry_cascaded.text_3": "Таким образом крановая установка может покрывать несколько осей движения", - - "create.ponder.gantry_direction.header": "Направлением движения крана", - "create.ponder.gantry_direction.text_1": "Валы портального крана могут иметь два противоположных направления", - "create.ponder.gantry_direction.text_2": "Направление движения Шасси зависит от ориентации их Валов", - "create.ponder.gantry_direction.text_3": "А также от направления вращения Вала", - "create.ponder.gantry_direction.text_4": "Те же правила относятся к передаваемому вращению", - - "create.ponder.gantry_redstone.header": "Краном и редстоун-сигнале", - "create.ponder.gantry_redstone.text_1": "Активированные редстоун-сигналом валы крана перестают двигать Шасси", - "create.ponder.gantry_redstone.text_2": "Вместо этого сила вращения передаётся выходному валу Шасси", - - "create.ponder.gantry_shaft.header": "Использованием Валов портального крана", - "create.ponder.gantry_shaft.text_1": "Валы портального крана составляют основу крановой установки. По ним будут двигаться присоединённые Шасси", - "create.ponder.gantry_shaft.text_2": "Крановые установки могут двигать присоединённые Блоки", - - "create.ponder.gearbox.header": "Передачей силы вращения с помощью Коробок передач", - "create.ponder.gearbox.text_1": "Переходы между осями вращения могут быстро стать очень громоздкими", - "create.ponder.gearbox.text_2": "Коробка Передач — это более компактный эквивалент этой установки", - "create.ponder.gearbox.text_3": "Валы по углам поворачиваются в зеркальных направлениях", - "create.ponder.gearbox.text_4": "Прямые соединения будут реверсированны", - - "create.ponder.gearshift.header": "Управлением силы вращения при помощи Реверсивных коробок передач", - "create.ponder.gearshift.text_1": "Реверсивные коробки передач передают вращение по прямой", - "create.ponder.gearshift.text_2": "При активации редстоун-сигналом, они реверсируют передачу", - - "create.ponder.hand_crank.header": "Генерацией силы вращения Рукоятками", - "create.ponder.hand_crank.text_1": "Рукоятки могут быть использованы игроками для создания силы вращения вручную", - "create.ponder.hand_crank.text_2": "Зажмите ПКМ, чтобы повернуть их против часовой стрелки", - "create.ponder.hand_crank.text_3": "Их скорость вращения относительно высока", - "create.ponder.hand_crank.text_4": "Зажмите ПКМ крадучись, чтобы повернуть её по часовой стрелке", - - "create.ponder.hose_pulley.header": "Наполнением и осушением источников при помощи Шкивов со шлангом", - "create.ponder.hose_pulley.text_1": "Шкивы со шлангом можно использовать для заполнения или осушения больших объёмов жидкости", - "create.ponder.hose_pulley.text_2": "С помощью кинетической энергии можно регулировать длину шланга", - "create.ponder.hose_pulley.text_3": "Шкив сматывается, если обратить вращение", - "create.ponder.hose_pulley.text_4": "С противоположной стороны можно подключать Трубы", - "create.ponder.hose_pulley.text_5": "Присоединённый водопровод может либо подавать жидкость в шланг...", - "create.ponder.hose_pulley.text_6": "...либо вытягивать её, осушая водоем", - "create.ponder.hose_pulley.text_7": "Скорость заполнения и осушения Шкивом полностью зависит от пропускной способности трубопровода", - - "create.ponder.hose_pulley_infinite.header": "Пассивным заполнением и осушением больших объёмов жидкости", - "create.ponder.hose_pulley_infinite.text_1": "При развертывании Шкива со шлангом в достаточно большой океан...", - "create.ponder.hose_pulley_infinite.text_2": "...он будет выкачивать/закачивать жидкость без влияния на источник", - "create.ponder.hose_pulley_infinite.text_3": "Трубопроводы могут неограниченно передавать жидкости из/в такие Шкивы", - - "create.ponder.hose_pulley_level.header": "Уровнем заполнения и осушения Шкива со шлангом", - "create.ponder.hose_pulley_level.text_1": "При полностью убранном рукаве — он не может работать", - "create.ponder.hose_pulley_level.text_2": "Осушение происходит сверху вниз", - "create.ponder.hose_pulley_level.text_3": "Уровень поверхности окажется чуть ниже того места, где заканчивается шланг", - "create.ponder.hose_pulley_level.text_4": "Заполнение происходит снизу вверх", - "create.ponder.hose_pulley_level.text_5": "Заполняемый бассейн не будет наполняться выше уровня конца шланга", - - "create.ponder.item_drain.header": "Опустошением жидкостных резервуаров с помощью Осушителей предметов", - "create.ponder.item_drain.text_1": "Осушители предметов могут извлекать жидкости из предметов", - "create.ponder.item_drain.text_2": "Щёлкните ПКМ по нему, чтобы перелить в него жидкость из предмета в ваших руках", - "create.ponder.item_drain.text_3": "Когда предметы подаются со стороны...", - "create.ponder.item_drain.text_4": "...они переворачиваются, выливая содержащуюся в них жидкость", - "create.ponder.item_drain.text_5": "Трубы могут вытягивать жидкость из внутреннего хранилища Осушителей", - - "create.ponder.item_vault_sizes.header": "Свойствами Хранилищ предметов", - "create.ponder.item_vault_sizes.text_1": "Хранилища предметов можно объединять для увеличения общей вместимости", - "create.ponder.item_vault_sizes.text_2": "Их базовая площадь может быть шириной до 3 блоков...", - "create.ponder.item_vault_sizes.text_3": "...и увеличиваться в длину до 3 диаметров", - - "create.ponder.item_vault_storage.header": "Хранением предметов в Хранилищах предметов", - "create.ponder.item_vault_storage.text_1": "Хранилища предметов можно использовать для хранения большого количества предметов", - "create.ponder.item_vault_storage.text_2": "Однако содержимое не может быть добавлено или взято вручную", - "create.ponder.item_vault_storage.text_3": "Любые компоненты для передачи предметов могут как добавлять...", - "create.ponder.item_vault_storage.text_4": "...так и забирать содержимое из этого контейнера", - - "create.ponder.large_cogwheel.header": "Передачей силы вращения при помощи Больших шестерней", - "create.ponder.large_cogwheel.text_1": "Большие шестерни могут соединяться между собой под прямым углом", - "create.ponder.large_cogwheel.text_2": "Это поможет передавать скорость на другие оси вращения", - - "create.ponder.linear_chassis_attachment.header": "Прикреплением блоков при помощи Линейных шасси", - "create.ponder.linear_chassis_attachment.text_1": "Открытые грани Линейных шасси можно сделать Липкими", - "create.ponder.linear_chassis_attachment.text_2": "Кликните ещё раз, чтобы сделать противоположную сторону липкой", - "create.ponder.linear_chassis_attachment.text_3": "ПКМ крадучись, пустой рукой, чтобы убрать слизь", - "create.ponder.linear_chassis_attachment.text_4": "Липкие грани Линейных шасси будут прикреплять ряд блоков перед ним", - "create.ponder.linear_chassis_attachment.text_5": "Используйте Гаечный ключ, чтобы настроить радиус прикрепления для этого шасси", - "create.ponder.linear_chassis_attachment.text_6": "Прокрутка при удерживании Ctrl настраивает радиус всех присоединённых шасси", - "create.ponder.linear_chassis_attachment.text_7": "Прикрепление блоков на другие стороны требует использования Суперклея", - "create.ponder.linear_chassis_attachment.text_8": "При помощи этих механик, структуры любой формы могут двигаться как Штуковина", - - "create.ponder.linear_chassis_group.header": "Движением Линейных шасси группами", - "create.ponder.linear_chassis_group.text_1": "Линейные шасси соединяются с такими же блоками Шасси рядом с ними", - "create.ponder.linear_chassis_group.text_2": "Когда один блок перемещается Штуковиной, другие двигаются с ним", - "create.ponder.linear_chassis_group.text_3": "Шасси других типов или направленные в другом направлении не будут прикрепляться", - - "create.ponder.mechanical_arm.header": "Настройкой Механических рук", - "create.ponder.mechanical_arm.text_1": "Входы и выходы для Механических рук должны быть назначены перед их установкой", - "create.ponder.mechanical_arm.text_2": "ПКМ по компонентам, держа Механическую руку, чтобы назначить их целями", - "create.ponder.mechanical_arm.text_3": "ПКМ ещё раз, для переключения между Входом (Синий) и Выходом (Оранжевый)", - "create.ponder.mechanical_arm.text_4": "ЛКМ по компонентам, чтобы убрать выделение с них", - "create.ponder.mechanical_arm.text_5": "После установки, Механические руки будут нацелены на ранее выбранные блоки", - "create.ponder.mechanical_arm.text_6": "У них может быть неограниченное кол-во входов и выходов в зоне их досягаемости", - "create.ponder.mechanical_arm.text_7": "Однако, не каждый вид компонента может взаимодействовать с ними напрямую", - "create.ponder.mechanical_arm.text_8": "Воронки и Депо могут помочь заполнить этот пробел", - - "create.ponder.mechanical_arm_filtering.header": "Фильтрацией выходов Механической руки", - "create.ponder.mechanical_arm_filtering.text_1": "Входы", - "create.ponder.mechanical_arm_filtering.text_2": "Выходы", - "create.ponder.mechanical_arm_filtering.text_3": "Иногда желательно ограничить цели руки фильтром", - "create.ponder.mechanical_arm_filtering.text_4": "Сами Механические руки не имеют возможности фильтрации", - "create.ponder.mechanical_arm_filtering.text_5": "Однако, Латунные воронки как цели сообщают свой фильтр руке", - "create.ponder.mechanical_arm_filtering.text_6": "Рука достаточно умна, чтобы не подбирать предметы, которые она не сможет распределить", - - "create.ponder.mechanical_arm_modes.header": "Режимами распределения Механической руки", - "create.ponder.mechanical_arm_modes.text_1": "Входы", - "create.ponder.mechanical_arm_modes.text_2": "Выходы", - "create.ponder.mechanical_arm_modes.text_3": "Когда Рука выбирает между несколькими доступными выходами...", - "create.ponder.mechanical_arm_modes.text_4": "...она сделает выбор исходя из выбранного режима распределения", - "create.ponder.mechanical_arm_modes.text_5": "Прокрутка с Гаечным ключом в руке позволит вам настроить это", - "create.ponder.mechanical_arm_modes.text_6": "Режим «По кругу» переключается между всеми доступными выходами по очереди", - "create.ponder.mechanical_arm_modes.text_7": "Если выход не может принять больше предметов, он будет пропущен", - "create.ponder.mechanical_arm_modes.text_8": "«Строго по кругу» никогда не пропускает выходы, а ждёт пока они не освободятся", - "create.ponder.mechanical_arm_modes.text_9": "«Предпочитать первичную цель» приоритизирует выходы, выбранные ранее при настройке этой Руки", - - "create.ponder.mechanical_arm_redstone.header": "Управлением Механической рукой редстоун-сигналом", - "create.ponder.mechanical_arm_redstone.text_1": "При активации редстоун-сигналом, Механические руки перестают работать", - "create.ponder.mechanical_arm_redstone.text_2": "Перед остановкой, они завершат все начатые действия", - "create.ponder.mechanical_arm_redstone.text_3": "Таким образом, инвертированный импульс может использоваться для вызова ровно одного срабатывания", - - "create.ponder.mechanical_bearing.header": "Передвижением структур при помощи Механических подшипников", - "create.ponder.mechanical_bearing.text_1": "Механические подшипники прикрепляют блоки перед ними", - "create.ponder.mechanical_bearing.text_2": "При получении силы вращения, они соберутся во вращающуюся штуковину", - - "create.ponder.mechanical_crafter.header": "Настройкой Механических крафтеров", - "create.ponder.mechanical_crafter.text_1": "Массив из Механических крафтеров можно использовать для автоматизации создания любого рецепта", - "create.ponder.mechanical_crafter.text_2": "Можно настроить пути крафтеров при помощи Гаечного ключа", - "create.ponder.mechanical_crafter.text_3": "Для правильной установки все пути должны сходиться в один выход с любой стороны", - "create.ponder.mechanical_crafter.text_4": "Продукты будут помещены в инвентарь у выхода", - "create.ponder.mechanical_crafter.text_5": "Механическим крафтерам нужна сила вращения для работы", - "create.ponder.mechanical_crafter.text_6": "ПКМ спереди, чтобы вставить предметы вручную", - "create.ponder.mechanical_crafter.text_7": "Когда каждый слот на пути содержит предмет, процесс создания начнётся", - "create.ponder.mechanical_crafter.text_8": "Для рецептов, не полностью занимающих крафтер-установку, старт можно спровоцировать редстоун-импульсом", - - "create.ponder.mechanical_crafter_connect.header": "Объединением инвентарей Механических крафтеров", - "create.ponder.mechanical_crafter_connect.text_1": "Предметы можно поместить в Крафтеры автоматически", - "create.ponder.mechanical_crafter_connect.text_2": "При помощи Гаечного ключа сзади крафтеров, их инвентари можно объединить", - "create.ponder.mechanical_crafter_connect.text_3": "Все соединённые Крафтеры теперь будут доступны из одного места ввода", - - "create.ponder.mechanical_crafter_covers.header": "Закрытием слотов Механических крафтеров", - "create.ponder.mechanical_crafter_covers.text_1": "Некоторые рецепты требуют дополнительных Крафтеров, чтобы закрыть пробелы на пути", - "create.ponder.mechanical_crafter_covers.text_2": "При помощи Заглушек на слоты, Крафтеры могут играть роль пустых слотов в схеме", - "create.ponder.mechanical_crafter_covers.text_3": "Общие входы созданные Гаечным ключом сзади также могут быть доступны через закрытые Крафтеры", - - "create.ponder.mechanical_drill.header": "Разрушением блоков Механическими дрелями", - "create.ponder.mechanical_drill.text_1": "При подаче вращения, Механическая дрель будет ломать блоки перед ней", - "create.ponder.mechanical_drill.text_2": "Скорость добычи зависит от подаваемой скорости вращения", - - "create.ponder.mechanical_drill_contraption.header": "Использованием Механических дрелей на штуковинах", - "create.ponder.mechanical_drill_contraption.text_1": "Когда Дрели движутся как часть движимой штуковины...", - "create.ponder.mechanical_drill_contraption.text_2": "...они будут ломать блоки, на которые они натыкаются", - - "create.ponder.mechanical_harvester.header": "Использованием Механических комбайнов на штуковинах", - "create.ponder.mechanical_harvester.text_1": "Когда Комбайны движутся как часть движимой штуковины...", - "create.ponder.mechanical_harvester.text_2": "...они будут убирать зрелый урожай на своём пути и высаживать его снова", - - "create.ponder.mechanical_mixer.header": "Обработкой предметов Механическим миксером", - "create.ponder.mechanical_mixer.text_1": "При помощи Миксера и Чаши можно автоматизировать некоторые рецепты крафта", - "create.ponder.mechanical_mixer.text_2": "Доступные рецепты включают бесформенную сборку и автоматическую варку зелий", - "create.ponder.mechanical_mixer.text_3": "Некоторым рецептам может потребоваться тепло от Горелки всполоха", - "create.ponder.mechanical_mixer.text_4": "Слот для фильтра можно использовать в случае конфликта двух рецептов", - - "create.ponder.mechanical_piston.header": "Перемещением структур при помощи Механических поршней", - "create.ponder.mechanical_piston.text_1": "Механические поршни могут двигать блоки перед ними", - "create.ponder.mechanical_piston.text_2": "Скорость и Направление движения зависят от исходного вращения", - "create.ponder.mechanical_piston.text_3": "Липкие Механические поршни могут тянуть назад присоединённые блоки", - - "create.ponder.mechanical_piston_modes.header": "Режимами движения Механического поршня", - "create.ponder.mechanical_piston_modes.text_1": "Когда поршень останавливается, сдвинутая структура обратно становится блоками", - "create.ponder.mechanical_piston_modes.text_2": "Можно настроить его так, чтобы структура никогда не становилась блоками или только на начальной позиции", - - "create.ponder.mechanical_plough.header": "Использованием Механических плугов на штуковинах", - "create.ponder.mechanical_plough.text_1": "Когда Плуги движутся как часть движимой штуковины...", - "create.ponder.mechanical_plough.text_2": "...они будут ломать блоки без твёрдого хитбокса", - "create.ponder.mechanical_plough.text_3": "К тому же, плуги могут создавать пашню", - "create.ponder.mechanical_plough.text_4": "Также они могут толкать сущностей не причиняя им вреда", - - "create.ponder.mechanical_press.header": "Обработкой предметов Механическими прессами", - "create.ponder.mechanical_press.text_1": "Механический пресс может обрабатывать предметы под собой", - "create.ponder.mechanical_press.text_2": "Подаваемые предметы должны быть брошены или помещены на Депо под Пресс", - "create.ponder.mechanical_press.text_3": "Когда предметы подаются на конвейере...", - "create.ponder.mechanical_press.text_4": "...Пресс будет задерживать и прессовать их автоматически", - - "create.ponder.mechanical_press_compacting.header": "Спрессовыванием и сжатием предметов Механическим прессом", - "create.ponder.mechanical_press_compacting.text_1": "Спрессовывание предметов в Чаше скомпонует их", - "create.ponder.mechanical_press_compacting.text_2": "Сжатие предметов и спрессовывание включают в себя любые заполненные 2x2 или 3x3 рецепты крафта и некоторые другие", - "create.ponder.mechanical_press_compacting.text_3": "Некоторым рецептам может потребоваться тепло от Горелки всполоха", - "create.ponder.mechanical_press_compacting.text_4": "Слот для фильтра можно использовать в случае конфликта двух рецептов", - - "create.ponder.mechanical_pump_flow.header": "Транспортировкой жидкостей при помощи Механических помп", - "create.ponder.mechanical_pump_flow.text_1": "Механические помпы направляют поток в присоединённые трубопровод", - "create.ponder.mechanical_pump_flow.text_2": "Когда работает, стрелка указывает направление потока", - "create.ponder.mechanical_pump_flow.text_3": "Часть трубопровода сзади теперь качает жидкости...", - "create.ponder.mechanical_pump_flow.text_4": "...в то время как часть трубопровода спереди передаёт их наружу", - "create.ponder.mechanical_pump_flow.text_5": "Смена направления вращения изменяет направление потока", - "create.ponder.mechanical_pump_flow.text_6": "Используйте Гаечный ключ, чтобы изменить направление Помпы вручную", - - "create.ponder.mechanical_pump_speed.header": "Производительностью Механической помпы", - "create.ponder.mechanical_pump_speed.text_1": "Независимо от скорости, Механические помпы оказывают влияние на Трубы в радиусе 16 блоков", - "create.ponder.mechanical_pump_speed.text_2": "Ускорение подаваемого вращения изменяет скорость распространения потоков...", - "create.ponder.mechanical_pump_speed.text_3": "...также, как и скорость передачи жидкостей", - "create.ponder.mechanical_pump_speed.text_4": "Помпы могут объединять свою производительность в одних трубопроводах", - "create.ponder.mechanical_pump_speed.text_5": "Изменение их направления может помочь сонаправить направление их потоков", - - "create.ponder.mechanical_saw_breaker.header": "Спиливанием деревьев Механическими пилами", - "create.ponder.mechanical_saw_breaker.text_1": "При подаче вращения, Механическая пила будет пилить деревья прямо перед ней", - "create.ponder.mechanical_saw_breaker.text_2": "Для спиливания дерева полностью пила должна ломать самый нижний блок дерева, соединённый с землёй", - - "create.ponder.mechanical_saw_contraption.header": "Использованием Механических пил на штуковинах", - "create.ponder.mechanical_saw_contraption.text_1": "Когда пилы движутся как часть движимой штуковины...", - "create.ponder.mechanical_saw_contraption.text_2": "...они будут ломать блоки, на которые они натыкаются", - - "create.ponder.mechanical_saw_processing.header": "Обработкой предметов на Механических пилах", - "create.ponder.mechanical_saw_processing.text_1": "Направленные вверх Механические пилы могут обрабатывать множество предметов", - "create.ponder.mechanical_saw_processing.text_2": "Обработанные предметы всегда движутся против подаваемого на пилу вращения", - "create.ponder.mechanical_saw_processing.text_3": "Пилы могут работать с конвейером", - "create.ponder.mechanical_saw_processing.text_4": "Когда из ингредиента можно получить несколько результатов, фильтр может уточнить его", - "create.ponder.mechanical_saw_processing.text_5": "Без фильтра пила будет выбирать все возможные результаты по очереди", - - "create.ponder.millstone.header": "Обработкой предметов Жерновами", - "create.ponder.millstone.text_1": "Жернова обрабатывают предметы перемалывая их", - "create.ponder.millstone.text_2": "Их можно запустить при помощи шестерней с любой стороны или валом снизу", - "create.ponder.millstone.text_3": "Бросьте или положите предметы сверху", - "create.ponder.millstone.text_4": "После некоторого времени результат можно забрать при помощи ПКМ", - "create.ponder.millstone.text_5": "Продукты помола также можно вывести автоматически", - - "create.ponder.nixie_tube.header": "Использованием Газоразрядных индикаторов", - "create.ponder.nixie_tube.text_1": "При подаче редстоун-сигнала, Газоразрядные индикаторы отобразят его силу", - "create.ponder.nixie_tube.text_2": "С помощью бирок, отредактированных на наковальне, вы можете отобразить любой текст", - "create.ponder.nixie_tube.text_3": "Щёлкните ПКМ с красителем, чтобы изменить цвет их индикаторов", - - "create.ponder.piston_pole.header": "Удлинителями Механического поршня", - "create.ponder.piston_pole.text_1": "Без присоединённых Удлинителей, Механический поршень не может двигаться", - "create.ponder.piston_pole.text_2": "Длина стержня, добавленного к задней части Механического поршня, определяет диапазон выдвижения", - - "create.ponder.portable_fluid_interface.header": "Портативным жидкостным интерфейсом на штуковинах", - "create.ponder.portable_fluid_interface.text_1": "Жидкостные баки на движущихся штуковинах не могут быть доступны никаким трубам", - "create.ponder.portable_fluid_interface.text_2": "Этот интерфейс может взаимодействовать с жидкостными баками без необходимости останавливать штуковину", - "create.ponder.portable_fluid_interface.text_3": "Установите второй с промежутком в 1 или 2 блока между ними", - "create.ponder.portable_fluid_interface.text_4": "Они установят соединение, когда встретятся", - "create.ponder.portable_fluid_interface.text_5": "Пока они соединены, стационарный интерфейс будет представлять собой ВСЕ баки на штуковине", - "create.ponder.portable_fluid_interface.text_6": "Теперь можно закачать жидкости...", - "create.ponder.portable_fluid_interface.text_7": "...или выкачать их из штуковины", - "create.ponder.portable_fluid_interface.text_8": "Если на какое-то время прекратится обмен содержимым — штуковина продолжит свой путь", - - "create.ponder.portable_storage_interface.header": "Портативным интерфейсом хранения на штуковинах", - "create.ponder.portable_storage_interface.text_1": "Инвентари на двигающихся штуковинах не могут быть открыты игроками", - "create.ponder.portable_storage_interface.text_2": "Этот компонент может взаимодействовать с хранилищем без необходимости останавливать штуковину", - "create.ponder.portable_storage_interface.text_3": "Установите второй с промежутком в 1 или 2 блока между ними", - "create.ponder.portable_storage_interface.text_4": "Когда они проходят мимо друг друга, они соединятся", - "create.ponder.portable_storage_interface.text_5": "Пока они соединены, стационарный интерфейс будет представлять собой ВСЕ инвентари на штуковине", - "create.ponder.portable_storage_interface.text_6": "Теперь можно положить предметы...", - "create.ponder.portable_storage_interface.text_7": "...или вывести их из штуковины", - "create.ponder.portable_storage_interface.text_8": "Если на какое-то время прекратится обмен предметами — штуковина продолжит свой путь", - - "create.ponder.portable_storage_interface_redstone.header": "Управлением Портативного интерфейса хранения редстоун-сигналом", - "create.ponder.portable_storage_interface_redstone.text_1": "Редстоун-сигнал предотвратит включение Портативного интерфейса", - - "create.ponder.powered_latch.header": "Управлением редстоун-сигналами при помощи Питаемого рычага", - "create.ponder.powered_latch.text_1": "Питаемый рычаг — управляемый редстоуном рычаг", - "create.ponder.powered_latch.text_2": "Сигнал сзади включает его", - "create.ponder.powered_latch.text_3": "Сигналы сбоку, обратно, выключают его", - "create.ponder.powered_latch.text_4": "Питаемые рычаги также можно переключать вручную", - - "create.ponder.powered_toggle_latch.header": "Управлением редстоун-сигналами при помощи Питаемого рычага-переключателя", - "create.ponder.powered_toggle_latch.text_1": "Питаемый рычаг-переключатель — управляемый редстоуном рычаг", - "create.ponder.powered_toggle_latch.text_2": "Сигналы сзади переключают его состояние...", - "create.ponder.powered_toggle_latch.text_3": "...включают и снова выключают", - "create.ponder.powered_toggle_latch.text_4": "Питаемые рычаги-переключатели также можно переключать вручную", - - "create.ponder.pulse_extender.header": "Использованием Редстоуновых удлинителей импульса", - "create.ponder.pulse_extender.text_1": "Редстоуновый удлинитель импульса может увеличить продолжительность редстоун-сигнала, проходящего через него", - "create.ponder.pulse_extender.text_2": "Он активируется после небольшой задержки...", - "create.ponder.pulse_extender.text_3": "...и выключается через настраиваемое время", - "create.ponder.pulse_extender.text_4": "С помощь прокрутки можно настроить время Удлинителя импульса", - "create.ponder.pulse_extender.text_5": "Можно настроить задержку вплоть до 30 минут", - - "create.ponder.pulse_repeater.header": "Использованием Редстоуновых повторителей импульса", - "create.ponder.pulse_repeater.text_1": "Повторители импульса укоротят любой поступающий редстоун-сигнал до одного импульса", - "create.ponder.pulse_repeater.text_2": "С помощь прокрутки можно настроить время Повторителя импульса", - "create.ponder.pulse_repeater.text_3": "Можно настроить задержку вплоть до 30 минут", - - "create.ponder.radial_chassis.header": "Присоединением блоков при помощи Радиальных шасси", - "create.ponder.radial_chassis.text_1": "Радиальное шасси соединяются с идентичными блоками шасси в ряд", - "create.ponder.radial_chassis.text_2": "Когда один блок перемещается штуковиной, остальные двигаются с ним", - "create.ponder.radial_chassis.text_3": "Боковые грани Радиального шасси можно сделать липкими", - "create.ponder.radial_chassis.text_4": "Кликните ещё раз, чтобы сделать все остальные грани липкими", - "create.ponder.radial_chassis.text_5": "Нажмите ПКМ крадучись пустой рукой, чтобы убрать слизь", - "create.ponder.radial_chassis.text_6": "Когда блок находится рядом с липкой гранью...", - "create.ponder.radial_chassis.text_7": "...он присоединит все достижимые блоки в пределах радиуса на этом слое", - "create.ponder.radial_chassis.text_8": "При помощи Гаечного ключа можно указать точный радиус для этого шасси", - "create.ponder.radial_chassis.text_9": "Блоки не достижимые ни одной липкой гранью не прикрепятся", - - "create.ponder.redstone_contact.header": "Использованием Редстоуновых контактов", - "create.ponder.redstone_contact.text_1": "Редстоуновые контакты, направленные друг на друга, будут излучать редстоун-сигнал", - "create.ponder.redstone_contact.text_2": "Также работает, когда один из них — часть двигающейся штуковины", - - "create.ponder.redstone_link.header": "Использованием Редстоуновых беспроводных передатчиков сигнала", - "create.ponder.redstone_link.text_1": "Редстоуновые передатчики сигнала могут передавать редстоун-сигнал без проводов", - "create.ponder.redstone_link.text_2": "Нажмите ПКМ крадучись, чтобы переключить режим приёмника", - "create.ponder.redstone_link.text_3": "ПКМ Гаечным ключом сделает то же самое", - "create.ponder.redstone_link.text_4": "Приёмники улавливают редстоун-сигнал передатчиков в радиусе 128 блоков", - "create.ponder.redstone_link.text_5": "Положите предметы в два слота, чтобы указать частоту", - "create.ponder.redstone_link.text_6": "Передатчики только одной частоты могут сообщаться", - - "create.ponder.rope_pulley.header": "Перемещением структур при помощи Лебёдки", - "create.ponder.rope_pulley.text_1": "Лебёдки могут двигать блоки вертикально при подаче вращения", - "create.ponder.rope_pulley.text_2": "Направление и скорость движения зависят от исходного вращения", - - "create.ponder.rope_pulley_attachment.header": "Перемещением Лебёдок как частей штуковин", - "create.ponder.rope_pulley_attachment.text_1": "Когда лебёдки перемещаются штуковиной...", - "create.ponder.rope_pulley_attachment.text_2": "...их присоединённая структура движется с ними", - "create.ponder.rope_pulley_attachment.text_3": "Учитывайте, что лебёдки можно выдвигать только пока они простаивают", - - "create.ponder.rope_pulley_modes.header": "Режимами движения Лебёдки", - "create.ponder.rope_pulley_modes.text_1": "Когда лебёдка останавливается, сдвинутая структура обратно становится блоками", - "create.ponder.rope_pulley_modes.text_2": "Можно настроить её так, чтобы структура никогда не становилась блоками или только на начальной позиции", - - "create.ponder.rose_quartz_lamp.header": "Особенностями Фонаря из розового кварца", - "create.ponder.rose_quartz_lamp.text_1": "Фонарь из розового кварца активируются по редстоун-сигналу", - "create.ponder.rose_quartz_lamp.text_2": "После этого он сам станет источником сигнала", - "create.ponder.rose_quartz_lamp.text_3": "Когда несколько Фонарей расположены в группе...", - "create.ponder.rose_quartz_lamp.text_4": "...активация одного из Фонарей, сфокусирует сигнал на нём, деактивируя все остальные", - "create.ponder.rose_quartz_lamp.text_5": "Компараторы выводят сигнал исходя из дистанции до ближайшего включённого Фонаря", - "create.ponder.rose_quartz_lamp.text_6": "Фонари также можно переключать вручную с помощью Гаечного ключа", - - "create.ponder.rotation_speed_controller.header": "Использованием Регуляторов скорости вращения", - "create.ponder.rotation_speed_controller.text_1": "Регуляторы скорости вращения передают вращение от своих осей на Большую шестерню выше них", - "create.ponder.rotation_speed_controller.text_2": "Можно настроить передаваемую скорость при помощи прокрутки по соответствующему месту сбоку", - - "create.ponder.sail.header": "Сборкой Мельниц при помощи Парусов", - "create.ponder.sail.text_1": "Паруса — удобные блоки для создания мельниц", - "create.ponder.sail.text_2": "Они будут прикрепляться к блокам и друг к другу без использования суперклея или блоков шасси", - "create.ponder.sail.text_3": "ПКМ красителем, чтобы покрасить их", - "create.ponder.sail.text_4": "ПКМ ножницами, чтобы превратить их снова в раму", - - "create.ponder.sail_frame.header": "Сборкой Мельниц при помощи Рам парусов", - "create.ponder.sail_frame.text_1": "Рамы парусов — удобные блоки для создания мельниц", - "create.ponder.sail_frame.text_2": "Они будут прикрепляться к блокам и друг к другу без использования суперклея или блоков шасси", - - "create.ponder.sequenced_gearshift.header": "Использованием Последовательных коробок передач", - "create.ponder.sequenced_gearshift.text_1": "Последовательная коробка передач передает вращение по списку заданных инструкций", - "create.ponder.sequenced_gearshift.text_2": "ПКМ, чтобы отрыть интерфейс для настройки", - "create.ponder.sequenced_gearshift.text_3": "При получении редстоун-сигнал, он начнёт выполнять заданные инструкции по порядку", - "create.ponder.sequenced_gearshift.text_4": "По завершению она будет дожидаться следующего сигнала и начнёт сначала", - "create.ponder.sequenced_gearshift.text_5": "Можно использовать компаратор для считывания текущего прогресса выполнения инструкций", - - "create.ponder.shaft.header": "Передачей силы вращения при помощи Валов", - "create.ponder.shaft.text_1": "Валы передают вращение по прямой", - - "create.ponder.shaft_casing.header": "Обрамлением Валов", - "create.ponder.shaft_casing.text_1": "Латунный или андезитовый корпус можно использовать для обрамления Валов", - - "create.ponder.smart_chute.header": "Фильтрацией предметов при помощи Умных желобов", - "create.ponder.smart_chute.text_1": "Умные желоба — вертикальные желоба с дополнительным контролем", - "create.ponder.smart_chute.text_2": "Предметы в слоте фильтра уточняют, что они могут забирать и передавать", - "create.ponder.smart_chute.text_3": "Используйте Колесо Мыши для уточнения размера забираемого стака", - "create.ponder.smart_chute.text_4": "Редстоун-сигнал выключает их", - - "create.ponder.smart_pipe.header": "Управлением жидкостным потоком с помощью Умных труб", - "create.ponder.smart_pipe.text_1": "Умные трубы могут помочь управлять потоками по типам жидкостей", - "create.ponder.smart_pipe.text_2": "Размещённые непосредственно у источника, они могут указывать тип извлекаемой жидкости", - "create.ponder.smart_pipe.text_3": "Просто щёлкните ПКМ по слоту фильтра с любым предметом, содержащим нужную жидкость", - "create.ponder.smart_pipe.text_4": "И при размещении дальше по трубопроводу Умные трубы будут пропускать только подходящие жидкости", - - "create.ponder.speedometer.header": "Мониторингом кинетической информации при помощи Спидометра", - "create.ponder.speedometer.text_1": "Спидометры отображают текущую скорость присоединённых компонентов", - "create.ponder.speedometer.text_2": "При ношении Инженерных очков игрок может получить более полную информацию от прибора", - "create.ponder.speedometer.text_3": "Компараторы могут испускать аналоговый редстоун-сигнал относительно измерений Спидометра", - - "create.ponder.spout_filling.header": "Наполнением предметов при помощи Дозатора", - "create.ponder.spout_filling.text_1": "Дозатор может заполнять подходящие предметы, расположенные под ним", - "create.ponder.spout_filling.text_2": "К содержимому Дозатора невозможно получить доступ вручную", - "create.ponder.spout_filling.text_3": "Вместо этого можно использовать трубы для подачи в него жидкостей", - "create.ponder.spout_filling.text_4": "Наполняемые предметы могут быть размещены на депо под дозатором", - "create.ponder.spout_filling.text_5": "Когда предметы подаются конвейером...", - "create.ponder.spout_filling.text_6": "...Дозатор будет удерживать и обрабатывать их автоматически", - - "create.ponder.stabilized_bearings.header": "Стабилизацией Штуковин", - "create.ponder.stabilized_bearings.text_1": "Когда Механические подшипники являются частью двигающейся структуры...", - "create.ponder.stabilized_bearings.text_2": "...они будут пытаться держаться ровно", - "create.ponder.stabilized_bearings.text_3": "Опять же, подшипники присоединяют блоки перед ними", - "create.ponder.stabilized_bearings.text_4": "И в результате целая под-структура будет держаться ровно", - - "create.ponder.steam_engine.header": "Генерацией силы вращения Паровыми двигателями", - "create.ponder.steam_engine.text_1": "Паровые двигатели можно разместить на Жидкостном баке", - "create.ponder.steam_engine.text_10": "4 уровень", - "create.ponder.steam_engine.text_11": "4 двигателя", - "create.ponder.steam_engine.text_12": "8 уровень", - "create.ponder.steam_engine.text_13": "8 двигателей", - "create.ponder.steam_engine.text_2": "Нажмите по Двигателю Валом в руке, чтобы создать выход кинетической энергии", - "create.ponder.steam_engine.text_3": "С достаточным количеством воды, уровнем нагрева и объёмом котла...", - "create.ponder.steam_engine.text_4": "...они будут генерировать вращательную силу", - "create.ponder.steam_engine.text_5": "Для минимальной установки требуется 4 Жидкостных бака", - "create.ponder.steam_engine.text_6": "С помощью Горелки всполоха можно увеличить выходную мощность", - "create.ponder.steam_engine.text_7": "Более высокие уровни мощности требуют больше воды, размера котла и уровня нагрева", - "create.ponder.steam_engine.text_8": "Текущий уровень мощности котла можно проверить с помощью Инженерных очков", - "create.ponder.steam_engine.text_9": "С каждым добавленным уровнем мощности, каждый дополнительный Двигатель может работать на полную мощность", - - "create.ponder.steam_whistle.header": "Использованием Паровых свистков", - "create.ponder.steam_whistle.text_1": "Паровые свистки можно разместить на Жидкостном баке", - "create.ponder.steam_whistle.text_2": "Если Бак получает достаточно тепла...", - "create.ponder.steam_whistle.text_3": "...Свисток будет играть определённую ноту при активации", - "create.ponder.steam_whistle.text_4": "Используйте дополнительный Свисток на блоке, чтобы понизить высоту его звука", - "create.ponder.steam_whistle.text_5": "Переключайтесь между тремя разными октавами с помощью Гаечного ключа", - "create.ponder.steam_whistle.text_6": "Инженерные очки помогут узнать текущую высоту звука", - - "create.ponder.sticker.header": "Прикреплением блоков при помощи Блоков-липучек", - "create.ponder.sticker.text_1": "Блоки-липучки идеально подходят для редстоун-управляемого присоединения блоков", - "create.ponder.sticker.text_2": "При получении редстоун-сигнала они переключают своё состояние", - "create.ponder.sticker.text_3": "Если он движется в штуковине, то блок будет двигаться с ним", - "create.ponder.sticker.text_4": "При повторном сигнале блок больше не будет прикреплён", - - "create.ponder.stressometer.header": "Мониторингом кинетической информации при помощи Стрессометра", - "create.ponder.stressometer.text_1": "Стрессометр отображает текущую допустимую нагрузку присоединённой кинетической сети", - "create.ponder.stressometer.text_2": "При ношении Инженерных очков игрок может получить более полную информацию от прибора", - "create.ponder.stressometer.text_3": "Компараторы могут испускать аналоговый редстоун-сигнал относительно измерений стрессометра", - - "create.ponder.super_glue.header": "Присоединением блоков при помощи Суперклея", - "create.ponder.super_glue.text_1": "Суперклей можно использовать между двумя любыми блоками", - "create.ponder.super_glue.text_2": "Скреплённые блоки будут двигаться вместе при сборке в штуковину", - "create.ponder.super_glue.text_3": "Когда вы суперклей во второй руке...", - "create.ponder.super_glue.text_4": "...добавленные блоки будут сразу приклеены к грани, на которую они были поставлены", - "create.ponder.super_glue.text_5": "Суперклей можно удалить левым кликом", - "create.ponder.super_glue.text_6": "Блоки, висящие на других, обычно не требуют клея", - - "create.ponder.track_chunks.header": "Пересечением поездом незагруженных чанков", - "create.ponder.track_chunks.text_1": "Железнодорожные пути остаются функциональными вне загруженных чанков", - "create.ponder.track_chunks.text_2": "Поезда будут путешествовать по неактивным участкам мира без каких либо проблем", - "create.ponder.track_chunks.text_3": "Они по-прежнему будут останавливаться на станциях или запрещающих сигналах Светофора", - "create.ponder.track_chunks.text_4": "Однако дрели и другие машины на борту работать не будут", - "create.ponder.track_chunks.text_5": "Оказавшись рядом с игроком, поезд снова появится", - - "create.ponder.track_observer.header": "Обнаружением проходящих поездов", - "create.ponder.track_observer.text_1": "Выберите Путь, затем поместите Железнодорожный наблюдатель рядом", - "create.ponder.track_observer.text_2": "Наблюдатель обнаружит любые поезда, проходящие через маркер на рельсах", - "create.ponder.track_observer.text_3": "Наблюдатели могут быть настроены для обнаружения определённого груза", - - "create.ponder.track_placement.header": "Размещением Железнодорожных путей", - "create.ponder.track_placement.text_1": "Встречайте новый тип рельсов, разработанный для Железнодорожных штуковин!", - "create.ponder.track_placement.text_2": "Чтобы разместить несколько путей сразу, нажмите на существующие Пути", - "create.ponder.track_placement.text_3": "Затем разместите или выберите вторые Пути", - "create.ponder.track_placement.text_4": "Железнодорожные пути также могут быть размещены в виде поворотов или склонов", - "create.ponder.track_placement.text_5": "При соединении дорожки будут пытаться сделать каждый поворот одинакового размера", - "create.ponder.track_placement.text_6": "Удержание Ctrl при размещении...", - "create.ponder.track_placement.text_7": "...создаст самый длинный возможный изгиб", - "create.ponder.track_placement.text_8": "Материалы во второй руке будут подкладываться под Пути автоматически", - - "create.ponder.track_portal.header": "Железнодорожными путями и портале Незера", - "create.ponder.track_portal.text_1": "Пути, размещённые напротив портала Незера...", - "create.ponder.track_portal.text_2": "...попытаются создать Пути на другой стороне", - "create.ponder.track_portal.text_3": "Теперь поезда на данном направлении могут путешествовать по измерениям", - - "create.ponder.train_assembly.header": "Сборкой поездов на Железнодорожных станциях", - "create.ponder.train_assembly.text_1": "Выберите участок Железнодорожных путей, затем разместите рядом Станцию", - "create.ponder.train_assembly.text_10": "Каждый поезд требует Контроллер поезда на борту", - "create.ponder.train_assembly.text_11": "Дополнительный Контроллер позволяет отправляться со Станций в обоих направлениях", - "create.ponder.train_assembly.text_12": "Откройте интерфейс Станции и подтвердите процесс сборки", - "create.ponder.train_assembly.text_13": "Поезда можно разобрать обратно на блоки только на Станциях", - "create.ponder.train_assembly.text_14": "Использование на Станции карты — добавит на неё станционный маркер", - "create.ponder.train_assembly.text_15": "Собранные поезда можно перемещать на ближайшие пути с помощью Гаечного ключа", - "create.ponder.train_assembly.text_2": "Станции — это путевые точки вашей железнодорожной сети", - "create.ponder.train_assembly.text_3": "Чтобы создать новый поезд, откройте интерфейс Станции и переключитесь в режим сборки", - "create.ponder.train_assembly.text_4": "Во время сборки к этой Станции не будут подъезжать поезда, следующие по Расписанию", - "create.ponder.train_assembly.text_5": "Создавайте новые вагонные тележки, используя Железнодорожный корпус на путях", - "create.ponder.train_assembly.text_6": "Нажмите на тележку ещё раз, чтобы переключаться между их вариациями внешнего вида", - "create.ponder.train_assembly.text_7": "Приклейте блоки с помощью Суперклея", - "create.ponder.train_assembly.text_8": "Собранные поезда будут двигаться быстрее, если они смогут найти топливо в прикреплённых сундуках или бочках", - "create.ponder.train_assembly.text_9": "Топливо, находящееся в Хранилищах, не будет потребляться поездом", - - "create.ponder.train_controls.header": "Управлением поездами с помощью Контроллера поезда", - "create.ponder.train_controls.text_1": "Контроллер поезда требуются на каждой железнодорожной штуковине", - "create.ponder.train_controls.text_2": "После сборки щёлкните ПКМ по блоку, чтобы начать движение", - "create.ponder.train_controls.text_3": "Ускоряйте и управляйте поездом, используя клавиши движения", - "create.ponder.train_controls.text_4": "При желании максимальную тягу можно настроить с помощью колёсика мыши", - "create.ponder.train_controls.text_5": "Удерживайте Пробел, чтобы прибыть на Станцию рядом", - "create.ponder.train_controls.text_6": "Поезда можно разобрать обратно на блоки только на Станциях", - "create.ponder.train_controls.text_7": "Прикреплённые Свистки можно активировать клавишей бега", - "create.ponder.train_controls.text_8": "Нажмите левый Shift или ПКМ по Контроллеру, чтобы перестать управлять поездом", - - "create.ponder.train_schedule.header": "Использованием Расписаний поездов", - "create.ponder.train_schedule.text_1": "Расписания позволяют другим машинистам управлять поездами", - "create.ponder.train_schedule.text_2": "Щёлкните ПКМ с предметом в руке, чтобы открыть его интерфейс", - "create.ponder.train_schedule.text_3": "После составления расписание может быть передано машинисту поезда", - "create.ponder.train_schedule.text_4": "Любой моб или Горелка всполоха, сидящий перед Контроллером поезда, является подходящим кандидатом в машинисты", - "create.ponder.train_schedule.text_5": "С помощью поводка можно легче усадить потенциального машиниста на его место", - "create.ponder.train_schedule.text_6": "Расписания можно отзывать от машинистов в любой момент времени", - - "create.ponder.train_signal_placement.header": "Размещением Железнодорожных светофоров", - "create.ponder.train_signal_placement.text_1": "Выберите Железнодорожный путь, затем разместите Светофор поблизости", - "create.ponder.train_signal_placement.text_2": "Светофоры регулируют поток поездов, которые управляются не игроками", - "create.ponder.train_signal_placement.text_3": "Поезда следующие по расписанию никогда не будут пересекать Светофоры в противоположном направлении...", - "create.ponder.train_signal_placement.text_4": "...если не был добавлен второй Светофор, направленный в противоположную сторону", - "create.ponder.train_signal_placement.text_5": "К Светофорам можно прикрепить Газоразрядный индикатор, чтобы сделать их сигнальные огни более заметными", - - "create.ponder.train_signal_redstone.header": "Железнодорожным светофором и редстоун-сигнале", - "create.ponder.train_signal_redstone.text_1": "Сигнал Светофора может быть переключен вручную с помощью редстоун-сигнала", - "create.ponder.train_signal_redstone.text_2": "И наоборот, запрещающий сигнал Светофора, испускает редстоун-сигнал, получаемый компаратором", - - "create.ponder.train_signal_signaling.header": "Предотвращением аварий с помощью Железнодорожных светофоров", - "create.ponder.train_signal_signaling.text_1": "Светофоры делят пути на сегменты", - "create.ponder.train_signal_signaling.text_2": "Если сегмент занят — проезд другим поездам запрещён", - "create.ponder.train_signal_signaling.text_3": "Таким образом, каждый сегмент будет содержать только один поезд одновременно", - "create.ponder.train_signal_signaling.text_4": "Второй режим Светофора доступен через переключение Гаечным ключом", - "create.ponder.train_signal_signaling.text_5": "Сегменты латунного Светофора обычно переходят в режим стандартного Светофора автоматически", - "create.ponder.train_signal_signaling.text_6": "Этот особый сигнал может останавливать поезда при втором условии", - "create.ponder.train_signal_signaling.text_7": "Он остановит поезда, которые при подъезде...", - "create.ponder.train_signal_signaling.text_8": "...не смогут сразу покинуть сегмент", - "create.ponder.train_signal_signaling.text_9": "Это помогает удерживать поезда, стоящие в очереди, вне загруженного сегмента", - - "create.ponder.valve_handle.header": "Генерацией силы вращения Вентилями", - "create.ponder.valve_handle.text_1": "Игроки могут использовать Вентили для применения силы вращения вручную", - "create.ponder.valve_handle.text_2": "Держите ПКМ для вращения против часовой стрелки", - "create.ponder.valve_handle.text_3": "Передаваемая ими скорость медленная и поступательная", - "create.ponder.valve_handle.text_4": "Держите ПКМ крадучись для вращения по часовой стрелке", - "create.ponder.valve_handle.text_5": "Вентили можно окрашивать в эстетических целях", - - "create.ponder.valve_pipe.header": "Управлением потоком с помощью Жидкостных клапанов", - "create.ponder.valve_pipe.text_1": "Жидкостные клапаны помогают контролировать распространение жидкостей по трубопроводу", - "create.ponder.valve_pipe.text_2": "Их входной вал контролирует, разрешена ли подача жидкости в данный момент", - "create.ponder.valve_pipe.text_3": "При вращении в нужном направлении — клапан откроется", - "create.ponder.valve_pipe.text_4": "Его можно снова закрыть, изменив направление вращения", - - "create.ponder.water_wheel.header": "Генерацией силы вращения Водяными колёс", - "create.ponder.water_wheel.text_1": "Водяные колёса берут силу соседних потоков воды", - "create.ponder.water_wheel.text_2": "Чем больше сторон запитано, тем быстрее будет вращаться Водяное колесо", - "create.ponder.water_wheel.text_3": "Лопасти колеса должны быть направлены против течения", - "create.ponder.water_wheel.text_4": "Направленное в противоположную сторону, не будет так же эффективно", - - "create.ponder.weighted_ejector.header": "Использованием Взвешенных катапульт", - "create.ponder.weighted_ejector.text_1": "Нажмите ПКМ крадучись, держа Катапульту, чтобы выбрать место цели", - "create.ponder.weighted_ejector.text_10": "Теперь она ограниченна этим размера стака и будет активироваться только тогда, когда удерживаемый стак достигнет этого количества", - "create.ponder.weighted_ejector.text_11": "Другие сущности, встав на катапульту, будут всегда активировать её", - "create.ponder.weighted_ejector.text_2": "Установленная Катапульта будет запускать объекты до отмеченного места", - "create.ponder.weighted_ejector.text_3": "Подходящая цель может быть на любой дистанции и высоте в радиусе", - "create.ponder.weighted_ejector.text_4": "Однако они не могут быть сбоку", - "create.ponder.weighted_ejector.text_5": "Если не было выбрано подходящей цели, она будет целиться в блок перед ней", - "create.ponder.weighted_ejector.text_6": "Предоставьте силу вращения, чтобы зарядить её", - "create.ponder.weighted_ejector.text_7": "Попадание предметов на Катапульту вызывает её срабатывание", - "create.ponder.weighted_ejector.text_8": "Если целью был выбран инвентарь, то катапульта будет ждать, пока в нём не появится место", - "create.ponder.weighted_ejector.text_9": "При помощи Гаечного ключа можно настроить необходимый размер стака", - - "create.ponder.weighted_ejector_redstone.header": "Управлением Взвешенной катапультой редстоун-сигналом", - "create.ponder.weighted_ejector_redstone.text_1": "При подаче редстоун-сигнала катапульты не будут активироваться", - "create.ponder.weighted_ejector_redstone.text_2": "Кроме того, наблюдатели могут определить, когда катапульты срабатывают", - - "create.ponder.weighted_ejector_tunnel.header": "Разделением стаков предметов при помощи Взвешенной катапульты", - "create.ponder.weighted_ejector_tunnel.text_1": "Объединённые с Латунными туннелями, катапульты могут делить стаки предметов по определённому количеству", - "create.ponder.weighted_ejector_tunnel.text_2": "Сперва, настройте Латунный туннель на режим «Предпочтительно ближайший», чтобы приоритизировать выход сбоку", - "create.ponder.weighted_ejector_tunnel.text_3": "Размер стака, установленный на катапульте, теперь определяет отделяемое количество", - "create.ponder.weighted_ejector_tunnel.text_4": "Пока новый стак нужного количества лежит на боковом выходе...", - "create.ponder.weighted_ejector_tunnel.text_5": "...остаток продолжит свой путь", - - "create.ponder.windmill_source.header": "Генерацией силы вращения Подшипниками ветряной мельницы", - "create.ponder.windmill_source.text_1": "Подшипники ветряной мельницы прикрепляются к блокам перед ними", - "create.ponder.windmill_source.text_2": "Если прикреплено достаточно парусоподобных блоков, он может стать мельницей", - "create.ponder.windmill_source.text_3": "Активированный, при помощи ПКМ, Подшипник ветряной мельницы начнёт вырабатывать силу вращения", - "create.ponder.windmill_source.text_4": "Количество парусов определяет скорость вращения", - "create.ponder.windmill_source.text_5": "Используйте Гаечный ключ, чтобы настроить направление вращения", - "create.ponder.windmill_source.text_6": "ПКМ по подшипнику в любое время, чтобы остановить его и изменить структуру", - "create.ponder.windmill_source.text_7": "Щёлкните ПКМ по подшипнику в любое время, чтобы остановить и снова изменить структуру", - - "create.ponder.windmill_structure.header": "Установкой Ветряной мельницы", - "create.ponder.windmill_structure.text_1": "Любая структура может считаться мельницей, пока она содержит как минимум 8 парусоподобных блоков", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/uk_ua.json b/src/generated/resources/assets/create/lang/unfinished/uk_ua.json deleted file mode 100644 index 07fead7a3f..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/uk_ua.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 986", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "Скло з акацією", - "block.create.acacia_window_pane": "Склянна панель з акацією", - "block.create.adjustable_chain_gearshift": "Регульований коробка передач", - "block.create.analog_lever": "Аналоговий важіль", - "block.create.andesite_belt_funnel": "Андезитова воронка на конвеєрі", - "block.create.andesite_casing": "Андезитовий корпус", - "block.create.andesite_encased_cogwheel": "UNLOCALIZED: Andesite Encased Cogwheel", - "block.create.andesite_encased_large_cogwheel": "UNLOCALIZED: Andesite Encased Large Cogwheel", - "block.create.andesite_encased_shaft": "Облицьований андезитовий вал", - "block.create.andesite_funnel": "Андезитова воронка", - "block.create.andesite_ladder": "UNLOCALIZED: Andesite Ladder", - "block.create.andesite_pillar": "Андезитова колона", - "block.create.andesite_tunnel": "Андезитовий тунель", - "block.create.asurine": "UNLOCALIZED: Asurine", - "block.create.asurine_pillar": "UNLOCALIZED: Asurine Pillar", - "block.create.basin": "Чаша", - "block.create.belt": "Конвеєр", - "block.create.birch_window": "Скло з березою", - "block.create.birch_window_pane": "Склянна панель з березою", - "block.create.black_nixie_tube": "Чорна ніксі-труба", - "block.create.black_sail": "Чорне вітрило", - "block.create.black_seat": "Чорне сидіння", - "block.create.black_toolbox": "Чорний ящик для інструментів", - "block.create.black_valve_handle": "Чорний ручний клапан", - "block.create.blaze_burner": "Пальник блейза", - "block.create.blue_nixie_tube": "Синя ніксі-труба", - "block.create.blue_sail": "Синє вітрило", - "block.create.blue_seat": "Синє сидіння", - "block.create.blue_toolbox": "Синій ящик для інструментів", - "block.create.blue_valve_handle": "Синій ручний клапан", - "block.create.brass_belt_funnel": "Латунна воронка на конвеєрі", - "block.create.brass_block": "Латунний блок", - "block.create.brass_casing": "Латунний корпус", - "block.create.brass_encased_cogwheel": "UNLOCALIZED: Brass Encased Cogwheel", - "block.create.brass_encased_large_cogwheel": "UNLOCALIZED: Brass Encased Large Cogwheel", - "block.create.brass_encased_shaft": "Вал у латунному корпусі", - "block.create.brass_funnel": "Латунна воронка", - "block.create.brass_ladder": "UNLOCALIZED: Brass Ladder", - "block.create.brass_tunnel": "Латунний тунель", - "block.create.brown_nixie_tube": "Коричнева ніксі-труба", - "block.create.brown_sail": "Коричневе вітрило", - "block.create.brown_seat": "Коричневе сидіння", - "block.create.brown_toolbox": "Коричневий ящик для інструментів", - "block.create.brown_valve_handle": "Коричневий ручний клапан", - "block.create.calcite_pillar": "UNLOCALIZED: Calcite Pillar", - "block.create.cart_assembler": "Складальник вагонеток", - "block.create.chocolate": "Шоколад", - "block.create.chute": "Жолоб", - "block.create.clockwork_bearing": "Підшипник годинника", - "block.create.clutch": "Зчеплення", - "block.create.cogwheel": "Шестірня", - "block.create.content_observer": "Спостерігач вмісту", - "block.create.controller_rail": "Контролерна рейка", - "block.create.controls": "UNLOCALIZED: Train Controls", - "block.create.copper_backtank": "Мідний резервуар", - "block.create.copper_casing": "Мідний корпус", - "block.create.copper_ladder": "UNLOCALIZED: Copper Ladder", - "block.create.copper_shingle_slab": "UNLOCALIZED: Copper Shingle Slab", - "block.create.copper_shingle_stairs": "UNLOCALIZED: Copper Shingle Stairs", - "block.create.copper_shingles": "Мідна черепиця", - "block.create.copper_tile_slab": "UNLOCALIZED: Copper Tile Slab", - "block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs", - "block.create.copper_tiles": "Мідна плитка", - "block.create.copper_valve_handle": "Мідний ручний клапан", - "block.create.creative_crate": "Творчий ящик", - "block.create.creative_fluid_tank": "Творчий бак для рідини", - "block.create.creative_motor": "Творчий мотор", - "block.create.crimsite": "UNLOCALIZED: Crimsite", - "block.create.crimsite_pillar": "UNLOCALIZED: Crimsite Pillar", - "block.create.crimson_window": "Скло з багряним деревом", - "block.create.crimson_window_pane": "Склянна панель з багряним деревом", - "block.create.crushing_wheel": "Дробильне колесо", - "block.create.crushing_wheel_controller": "Контролер дробильного колеса", - "block.create.cuckoo_clock": "Годинник із зозулею", - "block.create.cut_andesite": "UNLOCALIZED: Cut Andesite", - "block.create.cut_andesite_brick_slab": "UNLOCALIZED: Cut Andesite Brick Slab", - "block.create.cut_andesite_brick_stairs": "UNLOCALIZED: Cut Andesite Brick Stairs", - "block.create.cut_andesite_brick_wall": "UNLOCALIZED: Cut Andesite Brick Wall", - "block.create.cut_andesite_bricks": "Цегла з тесаного андезиту", - "block.create.cut_andesite_slab": "Плита з тесаного андезиту", - "block.create.cut_andesite_stairs": "UNLOCALIZED: Cut Andesite Stairs", - "block.create.cut_andesite_wall": "UNLOCALIZED: Cut Andesite Wall", - "block.create.cut_asurine": "UNLOCALIZED: Cut Asurine", - "block.create.cut_asurine_brick_slab": "UNLOCALIZED: Cut Asurine Brick Slab", - "block.create.cut_asurine_brick_stairs": "UNLOCALIZED: Cut Asurine Brick Stairs", - "block.create.cut_asurine_brick_wall": "UNLOCALIZED: Cut Asurine Brick Wall", - "block.create.cut_asurine_bricks": "UNLOCALIZED: Cut Asurine Bricks", - "block.create.cut_asurine_slab": "UNLOCALIZED: Cut Asurine Slab", - "block.create.cut_asurine_stairs": "UNLOCALIZED: Cut Asurine Stairs", - "block.create.cut_asurine_wall": "UNLOCALIZED: Cut Asurine Wall", - "block.create.cut_calcite": "UNLOCALIZED: Cut Calcite", - "block.create.cut_calcite_brick_slab": "UNLOCALIZED: Cut Calcite Brick Slab", - "block.create.cut_calcite_brick_stairs": "UNLOCALIZED: Cut Calcite Brick Stairs", - "block.create.cut_calcite_brick_wall": "UNLOCALIZED: Cut Calcite Brick Wall", - "block.create.cut_calcite_bricks": "UNLOCALIZED: Cut Calcite Bricks", - "block.create.cut_calcite_slab": "UNLOCALIZED: Cut Calcite Slab", - "block.create.cut_calcite_stairs": "UNLOCALIZED: Cut Calcite Stairs", - "block.create.cut_calcite_wall": "UNLOCALIZED: Cut Calcite Wall", - "block.create.cut_crimsite": "UNLOCALIZED: Cut Crimsite", - "block.create.cut_crimsite_brick_slab": "UNLOCALIZED: Cut Crimsite Brick Slab", - "block.create.cut_crimsite_brick_stairs": "UNLOCALIZED: Cut Crimsite Brick Stairs", - "block.create.cut_crimsite_brick_wall": "UNLOCALIZED: Cut Crimsite Brick Wall", - "block.create.cut_crimsite_bricks": "UNLOCALIZED: Cut Crimsite Bricks", - "block.create.cut_crimsite_slab": "UNLOCALIZED: Cut Crimsite Slab", - "block.create.cut_crimsite_stairs": "UNLOCALIZED: Cut Crimsite Stairs", - "block.create.cut_crimsite_wall": "UNLOCALIZED: Cut Crimsite Wall", - "block.create.cut_deepslate": "UNLOCALIZED: Cut Deepslate", - "block.create.cut_deepslate_brick_slab": "UNLOCALIZED: Cut Deepslate Brick Slab", - "block.create.cut_deepslate_brick_stairs": "UNLOCALIZED: Cut Deepslate Brick Stairs", - "block.create.cut_deepslate_brick_wall": "UNLOCALIZED: Cut Deepslate Brick Wall", - "block.create.cut_deepslate_bricks": "UNLOCALIZED: Cut Deepslate Bricks", - "block.create.cut_deepslate_slab": "UNLOCALIZED: Cut Deepslate Slab", - "block.create.cut_deepslate_stairs": "UNLOCALIZED: Cut Deepslate Stairs", - "block.create.cut_deepslate_wall": "UNLOCALIZED: Cut Deepslate Wall", - "block.create.cut_diorite": "UNLOCALIZED: Cut Diorite", - "block.create.cut_diorite_brick_slab": "UNLOCALIZED: Cut Diorite Brick Slab", - "block.create.cut_diorite_brick_stairs": "UNLOCALIZED: Cut Diorite Brick Stairs", - "block.create.cut_diorite_brick_wall": "UNLOCALIZED: Cut Diorite Brick Wall", - "block.create.cut_diorite_bricks": "Цегла з тесаного діориту", - "block.create.cut_diorite_slab": "UNLOCALIZED: Cut Diorite Slab", - "block.create.cut_diorite_stairs": "UNLOCALIZED: Cut Diorite Stairs", - "block.create.cut_diorite_wall": "UNLOCALIZED: Cut Diorite Wall", - "block.create.cut_dripstone": "UNLOCALIZED: Cut Dripstone", - "block.create.cut_dripstone_brick_slab": "UNLOCALIZED: Cut Dripstone Brick Slab", - "block.create.cut_dripstone_brick_stairs": "UNLOCALIZED: Cut Dripstone Brick Stairs", - "block.create.cut_dripstone_brick_wall": "UNLOCALIZED: Cut Dripstone Brick Wall", - "block.create.cut_dripstone_bricks": "UNLOCALIZED: Cut Dripstone Bricks", - "block.create.cut_dripstone_slab": "UNLOCALIZED: Cut Dripstone Slab", - "block.create.cut_dripstone_stairs": "UNLOCALIZED: Cut Dripstone Stairs", - "block.create.cut_dripstone_wall": "UNLOCALIZED: Cut Dripstone Wall", - "block.create.cut_granite": "UNLOCALIZED: Cut Granite", - "block.create.cut_granite_brick_slab": "UNLOCALIZED: Cut Granite Brick Slab", - "block.create.cut_granite_brick_stairs": "UNLOCALIZED: Cut Granite Brick Stairs", - "block.create.cut_granite_brick_wall": "UNLOCALIZED: Cut Granite Brick Wall", - "block.create.cut_granite_bricks": "UNLOCALIZED: Cut Granite Bricks", - "block.create.cut_granite_slab": "UNLOCALIZED: Cut Granite Slab", - "block.create.cut_granite_stairs": "UNLOCALIZED: Cut Granite Stairs", - "block.create.cut_granite_wall": "UNLOCALIZED: Cut Granite Wall", - "block.create.cut_limestone": "UNLOCALIZED: Cut Limestone", - "block.create.cut_limestone_brick_slab": "UNLOCALIZED: Cut Limestone Brick Slab", - "block.create.cut_limestone_brick_stairs": "UNLOCALIZED: Cut Limestone Brick Stairs", - "block.create.cut_limestone_brick_wall": "UNLOCALIZED: Cut Limestone Brick Wall", - "block.create.cut_limestone_bricks": "UNLOCALIZED: Cut Limestone Bricks", - "block.create.cut_limestone_slab": "UNLOCALIZED: Cut Limestone Slab", - "block.create.cut_limestone_stairs": "UNLOCALIZED: Cut Limestone Stairs", - "block.create.cut_limestone_wall": "UNLOCALIZED: Cut Limestone Wall", - "block.create.cut_ochrum": "UNLOCALIZED: Cut Ochrum", - "block.create.cut_ochrum_brick_slab": "UNLOCALIZED: Cut Ochrum Brick Slab", - "block.create.cut_ochrum_brick_stairs": "UNLOCALIZED: Cut Ochrum Brick Stairs", - "block.create.cut_ochrum_brick_wall": "UNLOCALIZED: Cut Ochrum Brick Wall", - "block.create.cut_ochrum_bricks": "UNLOCALIZED: Cut Ochrum Bricks", - "block.create.cut_ochrum_slab": "UNLOCALIZED: Cut Ochrum Slab", - "block.create.cut_ochrum_stairs": "UNLOCALIZED: Cut Ochrum Stairs", - "block.create.cut_ochrum_wall": "UNLOCALIZED: Cut Ochrum Wall", - "block.create.cut_scorchia": "UNLOCALIZED: Cut Scorchia", - "block.create.cut_scorchia_brick_slab": "UNLOCALIZED: Cut Scorchia Brick Slab", - "block.create.cut_scorchia_brick_stairs": "UNLOCALIZED: Cut Scorchia Brick Stairs", - "block.create.cut_scorchia_brick_wall": "UNLOCALIZED: Cut Scorchia Brick Wall", - "block.create.cut_scorchia_bricks": "UNLOCALIZED: Cut Scorchia Bricks", - "block.create.cut_scorchia_slab": "UNLOCALIZED: Cut Scorchia Slab", - "block.create.cut_scorchia_stairs": "UNLOCALIZED: Cut Scorchia Stairs", - "block.create.cut_scorchia_wall": "UNLOCALIZED: Cut Scorchia Wall", - "block.create.cut_scoria": "UNLOCALIZED: Cut Scoria", - "block.create.cut_scoria_brick_slab": "UNLOCALIZED: Cut Scoria Brick Slab", - "block.create.cut_scoria_brick_stairs": "UNLOCALIZED: Cut Scoria Brick Stairs", - "block.create.cut_scoria_brick_wall": "UNLOCALIZED: Cut Scoria Brick Wall", - "block.create.cut_scoria_bricks": "UNLOCALIZED: Cut Scoria Bricks", - "block.create.cut_scoria_slab": "UNLOCALIZED: Cut Scoria Slab", - "block.create.cut_scoria_stairs": "UNLOCALIZED: Cut Scoria Stairs", - "block.create.cut_scoria_wall": "UNLOCALIZED: Cut Scoria Wall", - "block.create.cut_tuff": "UNLOCALIZED: Cut Tuff", - "block.create.cut_tuff_brick_slab": "UNLOCALIZED: Cut Tuff Brick Slab", - "block.create.cut_tuff_brick_stairs": "UNLOCALIZED: Cut Tuff Brick Stairs", - "block.create.cut_tuff_brick_wall": "UNLOCALIZED: Cut Tuff Brick Wall", - "block.create.cut_tuff_bricks": "UNLOCALIZED: Cut Tuff Bricks", - "block.create.cut_tuff_slab": "UNLOCALIZED: Cut Tuff Slab", - "block.create.cut_tuff_stairs": "UNLOCALIZED: Cut Tuff Stairs", - "block.create.cut_tuff_wall": "UNLOCALIZED: Cut Tuff Wall", - "block.create.cut_veridium": "UNLOCALIZED: Cut Veridium", - "block.create.cut_veridium_brick_slab": "UNLOCALIZED: Cut Veridium Brick Slab", - "block.create.cut_veridium_brick_stairs": "UNLOCALIZED: Cut Veridium Brick Stairs", - "block.create.cut_veridium_brick_wall": "UNLOCALIZED: Cut Veridium Brick Wall", - "block.create.cut_veridium_bricks": "UNLOCALIZED: Cut Veridium Bricks", - "block.create.cut_veridium_slab": "UNLOCALIZED: Cut Veridium Slab", - "block.create.cut_veridium_stairs": "UNLOCALIZED: Cut Veridium Stairs", - "block.create.cut_veridium_wall": "UNLOCALIZED: Cut Veridium Wall", - "block.create.cyan_nixie_tube": "Бірюзова ніксі-труба", - "block.create.cyan_sail": "Бірюзове вітрило", - "block.create.cyan_seat": "Бірюзове сидіння", - "block.create.cyan_toolbox": "Бірюзовий ящик для інструментів", - "block.create.cyan_valve_handle": "Бірюзовий ручний клапан", - "block.create.dark_oak_window": "Скло з темним дубом", - "block.create.dark_oak_window_pane": "Склянна панель з темним дубом", - "block.create.deepslate_pillar": "UNLOCALIZED: Deepslate Pillar", - "block.create.deepslate_zinc_ore": "UNLOCALIZED: Deepslate Zinc Ore", - "block.create.deployer": "Автономний активатор", - "block.create.depot": "Депо", - "block.create.diorite_pillar": "Колона з діоритового кругляка", - "block.create.display_board": "UNLOCALIZED: Display Board", - "block.create.display_link": "UNLOCALIZED: Display Link", - "block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar", - "block.create.encased_chain_drive": "Ланцюговий привід у корпусі", - "block.create.encased_fan": "Вентилятор у корпусі", - "block.create.encased_fluid_pipe": "Труба для рідини в корпусі", - "block.create.exposed_copper_shingle_slab": "UNLOCALIZED: Exposed Copper Shingle Slab", - "block.create.exposed_copper_shingle_stairs": "UNLOCALIZED: Exposed Copper Shingle Stairs", - "block.create.exposed_copper_shingles": "UNLOCALIZED: Exposed Copper Shingles", - "block.create.exposed_copper_tile_slab": "UNLOCALIZED: Exposed Copper Tile Slab", - "block.create.exposed_copper_tile_stairs": "UNLOCALIZED: Exposed Copper Tile Stairs", - "block.create.exposed_copper_tiles": "UNLOCALIZED: Exposed Copper Tiles", - "block.create.fake_track": "UNLOCALIZED: Track Marker for Maps", - "block.create.fluid_pipe": "Труба для рідини", - "block.create.fluid_tank": "Резервуар для рідини", - "block.create.fluid_valve": "Клапан для рідини", - "block.create.flywheel": "Маховик", - "block.create.framed_glass": "Скло в рамі", - "block.create.framed_glass_door": "UNLOCALIZED: Framed Glass Door", - "block.create.framed_glass_pane": "Склнна панель в рамі", - "block.create.framed_glass_trapdoor": "UNLOCALIZED: Framed Glass Trapdoor", - "block.create.gantry_carriage": "Шасі портального крана", - "block.create.gantry_shaft": "Портальний вал", - "block.create.gearbox": "Коробка", - "block.create.gearshift": "Перемикач передач", - "block.create.glass_fluid_pipe": "Скляна трубка для рідини", - "block.create.granite_pillar": "Колона з гранітового кругляку", - "block.create.gray_nixie_tube": "Сіра ніксі-труба", - "block.create.gray_sail": "Сіре вітрило", - "block.create.gray_seat": "Сіре сидіння", - "block.create.gray_toolbox": "Сірий ящик для інструментів", - "block.create.gray_valve_handle": "Сірий ручний клапан", - "block.create.green_nixie_tube": "Зелена ніксі-труба", - "block.create.green_sail": "Зелене вітрило", - "block.create.green_seat": "Зелене сидіння", - "block.create.green_toolbox": "Зелений ящик для інструментів", - "block.create.green_valve_handle": "Зелений ручний клапан", - "block.create.hand_crank": "Ручна рукоятка", - "block.create.haunted_bell": "Примарний дзвін", - "block.create.honey": "Мед", - "block.create.horizontal_framed_glass": "Скло в горизонтальній рамці", - "block.create.horizontal_framed_glass_pane": "Склянна панель в горизонтальній рамі", - "block.create.hose_pulley": "Шків шланга", - "block.create.item_drain": "Осушувач предметів", - "block.create.item_vault": "UNLOCALIZED: Item Vault", - "block.create.jungle_window": "Скло з тропічним деревом", - "block.create.jungle_window_pane": "Склянна панель з тропічним деревом", - "block.create.large_bogey": "UNLOCALIZED: Large Bogey", - "block.create.large_cogwheel": "Велика шестірня", - "block.create.layered_andesite": "Багатошаровий андезит", - "block.create.layered_asurine": "UNLOCALIZED: Layered Asurine", - "block.create.layered_calcite": "UNLOCALIZED: Layered Calcite", - "block.create.layered_crimsite": "UNLOCALIZED: Layered Crimsite", - "block.create.layered_deepslate": "UNLOCALIZED: Layered Deepslate", - "block.create.layered_diorite": "Багатошаровий діорит", - "block.create.layered_dripstone": "UNLOCALIZED: Layered Dripstone", - "block.create.layered_granite": "Багатошаровий граніт", - "block.create.layered_limestone": "Багатошаровий вапняк", - "block.create.layered_ochrum": "UNLOCALIZED: Layered Ochrum", - "block.create.layered_scorchia": "UNLOCALIZED: Layered Scorchia", - "block.create.layered_scoria": "Багатошаровий попіл", - "block.create.layered_tuff": "UNLOCALIZED: Layered Tuff", - "block.create.layered_veridium": "UNLOCALIZED: Layered Veridium", - "block.create.lectern_controller": "Багатошаровий контролер", - "block.create.light_blue_nixie_tube": "Блакитна ніксі-труба", - "block.create.light_blue_sail": "Блакитне вітрило", - "block.create.light_blue_seat": "Блакитне сидіння", - "block.create.light_blue_toolbox": "Блакитний ящик для інструментів", - "block.create.light_blue_valve_handle": "Блакитний ручний клапан", - "block.create.light_gray_nixie_tube": "Світло-сіра ніксі-труба", - "block.create.light_gray_sail": "Світло-сіре вітрило", - "block.create.light_gray_seat": "Світло-сіре сидіння", - "block.create.light_gray_toolbox": "Світло-сірий ящик для інструментів", - "block.create.light_gray_valve_handle": "Світло-сірий ручний клапан", - "block.create.lime_nixie_tube": "Лаймова ніксі-труба", - "block.create.lime_sail": "Лаймове вітрило", - "block.create.lime_seat": "Лаймове сидіння", - "block.create.lime_toolbox": "Лаймовий ящик для інструментів", - "block.create.lime_valve_handle": "Лаймовий ручний клапан", - "block.create.limestone": "Вапняк", - "block.create.limestone_pillar": "Вапнякова колона", - "block.create.linear_chassis": "Лінійне шасі", - "block.create.lit_blaze_burner": "Запалений пальник блейза", - "block.create.magenta_nixie_tube": "Пурпурна ніксі-труба", - "block.create.magenta_sail": "Пурпурне вітрило", - "block.create.magenta_seat": "Пурпурне сидіння", - "block.create.magenta_toolbox": "Пурпурний ящик для інструментів", - "block.create.magenta_valve_handle": "Пурпурний ручний клапан", - "block.create.mechanical_arm": "Механічна рука", - "block.create.mechanical_bearing": "Механічний підшипник", - "block.create.mechanical_crafter": "Механічний крафтер", - "block.create.mechanical_drill": "Механічна дриль", - "block.create.mechanical_harvester": "Механічний комбайн", - "block.create.mechanical_mixer": "Механічний міксер", - "block.create.mechanical_piston": "Механічний поршень", - "block.create.mechanical_piston_head": "Головка Механічного поршня", - "block.create.mechanical_plough": "Механічний плуг", - "block.create.mechanical_press": "Механічний прес", - "block.create.mechanical_pump": "Механічний насос", - "block.create.mechanical_saw": "Механічна пила", - "block.create.metal_bracket": "Металевий кронштейн", - "block.create.metal_girder": "UNLOCALIZED: Metal Girder", - "block.create.metal_girder_encased_shaft": "UNLOCALIZED: Metal Girder Encased Shaft", - "block.create.millstone": "Жорна", - "block.create.minecart_anchor": "Якір вагонетки", - "block.create.mysterious_cuckoo_clock": "Годинник із зозулею", - "block.create.nixie_tube": "Ніксі-труба", - "block.create.nozzle": "Насадка", - "block.create.oak_window": "Скло з дубом", - "block.create.oak_window_pane": "Склянна панель з дубом", - "block.create.ochrum": "UNLOCALIZED: Ochrum", - "block.create.ochrum_pillar": "UNLOCALIZED: Ochrum Pillar", - "block.create.orange_sail": "Помаранчеве вітрило", - "block.create.orange_seat": "Помаранчеве сидіння", - "block.create.orange_toolbox": "Помаранчевий ящик для інструментів", - "block.create.orange_valve_handle": "Помаранчевий ручний клапан", - "block.create.ornate_iron_window": "Вишукане залізне скло", - "block.create.ornate_iron_window_pane": "Вишукане залізна склянна панель", - "block.create.oxidized_copper_shingle_slab": "UNLOCALIZED: Oxidized Copper Shingle Slab", - "block.create.oxidized_copper_shingle_stairs": "UNLOCALIZED: Oxidized Copper Shingle Stairs", - "block.create.oxidized_copper_shingles": "UNLOCALIZED: Oxidized Copper Shingles", - "block.create.oxidized_copper_tile_slab": "UNLOCALIZED: Oxidized Copper Tile Slab", - "block.create.oxidized_copper_tile_stairs": "UNLOCALIZED: Oxidized Copper Tile Stairs", - "block.create.oxidized_copper_tiles": "UNLOCALIZED: Oxidized Copper Tiles", - "block.create.peculiar_bell": "Дивний дзвін", - "block.create.pink_nixie_tube": "Рожева ніксі-труба", - "block.create.pink_sail": "Рожеве вітрило", - "block.create.pink_seat": "Рожеве сидіння", - "block.create.pink_toolbox": "Рожевий ящик для інструментів", - "block.create.pink_valve_handle": "Рожевий ручний клапан", - "block.create.piston_extension_pole": "Поршневий подовжувач", - "block.create.placard": "UNLOCALIZED: Placard", - "block.create.polished_cut_andesite": "UNLOCALIZED: Polished Cut Andesite", - "block.create.polished_cut_andesite_slab": "UNLOCALIZED: Polished Cut Andesite Slab", - "block.create.polished_cut_andesite_stairs": "UNLOCALIZED: Polished Cut Andesite Stairs", - "block.create.polished_cut_andesite_wall": "UNLOCALIZED: Polished Cut Andesite Wall", - "block.create.polished_cut_asurine": "UNLOCALIZED: Polished Cut Asurine", - "block.create.polished_cut_asurine_slab": "UNLOCALIZED: Polished Cut Asurine Slab", - "block.create.polished_cut_asurine_stairs": "UNLOCALIZED: Polished Cut Asurine Stairs", - "block.create.polished_cut_asurine_wall": "UNLOCALIZED: Polished Cut Asurine Wall", - "block.create.polished_cut_calcite": "UNLOCALIZED: Polished Cut Calcite", - "block.create.polished_cut_calcite_slab": "UNLOCALIZED: Polished Cut Calcite Slab", - "block.create.polished_cut_calcite_stairs": "UNLOCALIZED: Polished Cut Calcite Stairs", - "block.create.polished_cut_calcite_wall": "UNLOCALIZED: Polished Cut Calcite Wall", - "block.create.polished_cut_crimsite": "UNLOCALIZED: Polished Cut Crimsite", - "block.create.polished_cut_crimsite_slab": "UNLOCALIZED: Polished Cut Crimsite Slab", - "block.create.polished_cut_crimsite_stairs": "UNLOCALIZED: Polished Cut Crimsite Stairs", - "block.create.polished_cut_crimsite_wall": "UNLOCALIZED: Polished Cut Crimsite Wall", - "block.create.polished_cut_deepslate": "UNLOCALIZED: Polished Cut Deepslate", - "block.create.polished_cut_deepslate_slab": "UNLOCALIZED: Polished Cut Deepslate Slab", - "block.create.polished_cut_deepslate_stairs": "UNLOCALIZED: Polished Cut Deepslate Stairs", - "block.create.polished_cut_deepslate_wall": "UNLOCALIZED: Polished Cut Deepslate Wall", - "block.create.polished_cut_diorite": "UNLOCALIZED: Polished Cut Diorite", - "block.create.polished_cut_diorite_slab": "UNLOCALIZED: Polished Cut Diorite Slab", - "block.create.polished_cut_diorite_stairs": "UNLOCALIZED: Polished Cut Diorite Stairs", - "block.create.polished_cut_diorite_wall": "UNLOCALIZED: Polished Cut Diorite Wall", - "block.create.polished_cut_dripstone": "UNLOCALIZED: Polished Cut Dripstone", - "block.create.polished_cut_dripstone_slab": "UNLOCALIZED: Polished Cut Dripstone Slab", - "block.create.polished_cut_dripstone_stairs": "UNLOCALIZED: Polished Cut Dripstone Stairs", - "block.create.polished_cut_dripstone_wall": "UNLOCALIZED: Polished Cut Dripstone Wall", - "block.create.polished_cut_granite": "UNLOCALIZED: Polished Cut Granite", - "block.create.polished_cut_granite_slab": "UNLOCALIZED: Polished Cut Granite Slab", - "block.create.polished_cut_granite_stairs": "UNLOCALIZED: Polished Cut Granite Stairs", - "block.create.polished_cut_granite_wall": "UNLOCALIZED: Polished Cut Granite Wall", - "block.create.polished_cut_limestone": "UNLOCALIZED: Polished Cut Limestone", - "block.create.polished_cut_limestone_slab": "UNLOCALIZED: Polished Cut Limestone Slab", - "block.create.polished_cut_limestone_stairs": "UNLOCALIZED: Polished Cut Limestone Stairs", - "block.create.polished_cut_limestone_wall": "UNLOCALIZED: Polished Cut Limestone Wall", - "block.create.polished_cut_ochrum": "UNLOCALIZED: Polished Cut Ochrum", - "block.create.polished_cut_ochrum_slab": "UNLOCALIZED: Polished Cut Ochrum Slab", - "block.create.polished_cut_ochrum_stairs": "UNLOCALIZED: Polished Cut Ochrum Stairs", - "block.create.polished_cut_ochrum_wall": "UNLOCALIZED: Polished Cut Ochrum Wall", - "block.create.polished_cut_scorchia": "UNLOCALIZED: Polished Cut Scorchia", - "block.create.polished_cut_scorchia_slab": "UNLOCALIZED: Polished Cut Scorchia Slab", - "block.create.polished_cut_scorchia_stairs": "UNLOCALIZED: Polished Cut Scorchia Stairs", - "block.create.polished_cut_scorchia_wall": "UNLOCALIZED: Polished Cut Scorchia Wall", - "block.create.polished_cut_scoria": "UNLOCALIZED: Polished Cut Scoria", - "block.create.polished_cut_scoria_slab": "UNLOCALIZED: Polished Cut Scoria Slab", - "block.create.polished_cut_scoria_stairs": "UNLOCALIZED: Polished Cut Scoria Stairs", - "block.create.polished_cut_scoria_wall": "UNLOCALIZED: Polished Cut Scoria Wall", - "block.create.polished_cut_tuff": "UNLOCALIZED: Polished Cut Tuff", - "block.create.polished_cut_tuff_slab": "UNLOCALIZED: Polished Cut Tuff Slab", - "block.create.polished_cut_tuff_stairs": "UNLOCALIZED: Polished Cut Tuff Stairs", - "block.create.polished_cut_tuff_wall": "UNLOCALIZED: Polished Cut Tuff Wall", - "block.create.polished_cut_veridium": "UNLOCALIZED: Polished Cut Veridium", - "block.create.polished_cut_veridium_slab": "UNLOCALIZED: Polished Cut Veridium Slab", - "block.create.polished_cut_veridium_stairs": "UNLOCALIZED: Polished Cut Veridium Stairs", - "block.create.polished_cut_veridium_wall": "UNLOCALIZED: Polished Cut Veridium Wall", - "block.create.portable_fluid_interface": "Портативний рідинний інтерфейс", - "block.create.portable_storage_interface": "Портативний інтерфейс зберігання", - "block.create.powered_latch": "Живлений важіль", - "block.create.powered_shaft": "UNLOCALIZED: Powered Shaft", - "block.create.powered_toggle_latch": "Живлюваний важіль-перемикач", - "block.create.pulley_magnet": "Магніт для шківа", - "block.create.pulse_extender": "UNLOCALIZED: Pulse Extender", - "block.create.pulse_repeater": "Повторювач імпульсів", - "block.create.purple_nixie_tube": "Фіолетова ніксі-труба", - "block.create.purple_sail": "Фіолетове вітрило", - "block.create.purple_seat": "Фіолетове сидіння", - "block.create.purple_toolbox": "Фіолетовий ящик для інструментів", - "block.create.purple_valve_handle": "Фіолетове ручний клапан", - "block.create.radial_chassis": "Радіальне шасі", - "block.create.railway_casing": "UNLOCALIZED: Train Casing", - "block.create.raw_zinc_block": "UNLOCALIZED: Block of Raw Zinc", - "block.create.red_nixie_tube": "Червона ніксі-труба", - "block.create.red_sail": "Червоне вітрило", - "block.create.red_seat": "Червоне сидіння", - "block.create.red_toolbox": "Червоний ящик для інструментів", - "block.create.red_valve_handle": "Червоний ручний клапан", - "block.create.redstone_contact": "Редстоун контакт", - "block.create.redstone_link": "Редстоун посилання", - "block.create.refined_radiance_casing": "Сяючий корпус", - "block.create.rope": "Канат", - "block.create.rope_pulley": "Лебідка", - "block.create.rose_quartz_block": "UNLOCALIZED: Block of Rose Quartz", - "block.create.rose_quartz_lamp": "UNLOCALIZED: Rose Quartz Lamp", - "block.create.rose_quartz_tiles": "UNLOCALIZED: Rose Quartz Tiles", - "block.create.rotation_speed_controller": "Контролер швидкості обертання", - "block.create.sail_frame": "Каркас вітрила", - "block.create.schematic_table": "Схематичний стіл", - "block.create.schematicannon": "Схематична гармата", - "block.create.scorchia": "UNLOCALIZED: Scorchia", - "block.create.scorchia_pillar": "UNLOCALIZED: Scorchia Pillar", - "block.create.scoria": "Попіл", - "block.create.scoria_pillar": "Колона з пепельного кругляку", - "block.create.secondary_linear_chassis": "Вторинне лінійне шасі", - "block.create.sequenced_gearshift": "Послідовне перемикання передач", - "block.create.shadow_steel_casing": "Тіньовий корпус", - "block.create.shaft": "Вал", - "block.create.small_andesite_brick_slab": "UNLOCALIZED: Small Andesite Brick Slab", - "block.create.small_andesite_brick_stairs": "UNLOCALIZED: Small Andesite Brick Stairs", - "block.create.small_andesite_brick_wall": "UNLOCALIZED: Small Andesite Brick Wall", - "block.create.small_andesite_bricks": "UNLOCALIZED: Small Andesite Bricks", - "block.create.small_asurine_brick_slab": "UNLOCALIZED: Small Asurine Brick Slab", - "block.create.small_asurine_brick_stairs": "UNLOCALIZED: Small Asurine Brick Stairs", - "block.create.small_asurine_brick_wall": "UNLOCALIZED: Small Asurine Brick Wall", - "block.create.small_asurine_bricks": "UNLOCALIZED: Small Asurine Bricks", - "block.create.small_bogey": "UNLOCALIZED: Small Bogey", - "block.create.small_calcite_brick_slab": "UNLOCALIZED: Small Calcite Brick Slab", - "block.create.small_calcite_brick_stairs": "UNLOCALIZED: Small Calcite Brick Stairs", - "block.create.small_calcite_brick_wall": "UNLOCALIZED: Small Calcite Brick Wall", - "block.create.small_calcite_bricks": "UNLOCALIZED: Small Calcite Bricks", - "block.create.small_crimsite_brick_slab": "UNLOCALIZED: Small Crimsite Brick Slab", - "block.create.small_crimsite_brick_stairs": "UNLOCALIZED: Small Crimsite Brick Stairs", - "block.create.small_crimsite_brick_wall": "UNLOCALIZED: Small Crimsite Brick Wall", - "block.create.small_crimsite_bricks": "UNLOCALIZED: Small Crimsite Bricks", - "block.create.small_deepslate_brick_slab": "UNLOCALIZED: Small Deepslate Brick Slab", - "block.create.small_deepslate_brick_stairs": "UNLOCALIZED: Small Deepslate Brick Stairs", - "block.create.small_deepslate_brick_wall": "UNLOCALIZED: Small Deepslate Brick Wall", - "block.create.small_deepslate_bricks": "UNLOCALIZED: Small Deepslate Bricks", - "block.create.small_diorite_brick_slab": "UNLOCALIZED: Small Diorite Brick Slab", - "block.create.small_diorite_brick_stairs": "UNLOCALIZED: Small Diorite Brick Stairs", - "block.create.small_diorite_brick_wall": "UNLOCALIZED: Small Diorite Brick Wall", - "block.create.small_diorite_bricks": "UNLOCALIZED: Small Diorite Bricks", - "block.create.small_dripstone_brick_slab": "UNLOCALIZED: Small Dripstone Brick Slab", - "block.create.small_dripstone_brick_stairs": "UNLOCALIZED: Small Dripstone Brick Stairs", - "block.create.small_dripstone_brick_wall": "UNLOCALIZED: Small Dripstone Brick Wall", - "block.create.small_dripstone_bricks": "UNLOCALIZED: Small Dripstone Bricks", - "block.create.small_granite_brick_slab": "UNLOCALIZED: Small Granite Brick Slab", - "block.create.small_granite_brick_stairs": "UNLOCALIZED: Small Granite Brick Stairs", - "block.create.small_granite_brick_wall": "UNLOCALIZED: Small Granite Brick Wall", - "block.create.small_granite_bricks": "UNLOCALIZED: Small Granite Bricks", - "block.create.small_limestone_brick_slab": "UNLOCALIZED: Small Limestone Brick Slab", - "block.create.small_limestone_brick_stairs": "UNLOCALIZED: Small Limestone Brick Stairs", - "block.create.small_limestone_brick_wall": "UNLOCALIZED: Small Limestone Brick Wall", - "block.create.small_limestone_bricks": "UNLOCALIZED: Small Limestone Bricks", - "block.create.small_ochrum_brick_slab": "UNLOCALIZED: Small Ochrum Brick Slab", - "block.create.small_ochrum_brick_stairs": "UNLOCALIZED: Small Ochrum Brick Stairs", - "block.create.small_ochrum_brick_wall": "UNLOCALIZED: Small Ochrum Brick Wall", - "block.create.small_ochrum_bricks": "UNLOCALIZED: Small Ochrum Bricks", - "block.create.small_rose_quartz_tiles": "UNLOCALIZED: Small Rose Quartz Tiles", - "block.create.small_scorchia_brick_slab": "UNLOCALIZED: Small Scorchia Brick Slab", - "block.create.small_scorchia_brick_stairs": "UNLOCALIZED: Small Scorchia Brick Stairs", - "block.create.small_scorchia_brick_wall": "UNLOCALIZED: Small Scorchia Brick Wall", - "block.create.small_scorchia_bricks": "UNLOCALIZED: Small Scorchia Bricks", - "block.create.small_scoria_brick_slab": "UNLOCALIZED: Small Scoria Brick Slab", - "block.create.small_scoria_brick_stairs": "UNLOCALIZED: Small Scoria Brick Stairs", - "block.create.small_scoria_brick_wall": "UNLOCALIZED: Small Scoria Brick Wall", - "block.create.small_scoria_bricks": "UNLOCALIZED: Small Scoria Bricks", - "block.create.small_tuff_brick_slab": "UNLOCALIZED: Small Tuff Brick Slab", - "block.create.small_tuff_brick_stairs": "UNLOCALIZED: Small Tuff Brick Stairs", - "block.create.small_tuff_brick_wall": "UNLOCALIZED: Small Tuff Brick Wall", - "block.create.small_tuff_bricks": "UNLOCALIZED: Small Tuff Bricks", - "block.create.small_veridium_brick_slab": "UNLOCALIZED: Small Veridium Brick Slab", - "block.create.small_veridium_brick_stairs": "UNLOCALIZED: Small Veridium Brick Stairs", - "block.create.small_veridium_brick_wall": "UNLOCALIZED: Small Veridium Brick Wall", - "block.create.small_veridium_bricks": "UNLOCALIZED: Small Veridium Bricks", - "block.create.smart_chute": "Розумний жолоб", - "block.create.smart_fluid_pipe": "Розумна рідинна труба", - "block.create.speedometer": "Спідометр", - "block.create.spout": "Дозатор", - "block.create.spruce_window": "Скло з смерекою", - "block.create.spruce_window_pane": "Склянна панель з смерекою", - "block.create.steam_engine": "UNLOCALIZED: Steam Engine", - "block.create.steam_whistle": "UNLOCALIZED: Steam Whistle", - "block.create.steam_whistle_extension": "UNLOCALIZED: Steam Whistle Extension", - "block.create.sticker": "Блок-липучка", - "block.create.sticky_mechanical_piston": "Липкий механічний поршень", - "block.create.stockpile_switch": "Налаштований компаратор", - "block.create.stressometer": "Стресометр", - "block.create.tiled_glass": "Кахельне скло", - "block.create.tiled_glass_pane": "Кахельне склянна панель", - "block.create.track": "UNLOCALIZED: Train Track", - "block.create.track_observer": "UNLOCALIZED: Train Observer", - "block.create.track_signal": "UNLOCALIZED: Train Signal", - "block.create.track_station": "UNLOCALIZED: Train Station", - "block.create.train_door": "UNLOCALIZED: Train Door", - "block.create.train_trapdoor": "UNLOCALIZED: Train Trapdoor", - "block.create.tuff_pillar": "UNLOCALIZED: Tuff Pillar", - "block.create.turntable": "Поворотний стіл", - "block.create.veridium": "UNLOCALIZED: Veridium", - "block.create.veridium_pillar": "UNLOCALIZED: Veridium Pillar", - "block.create.vertical_framed_glass": "Скло у вертикальній рамі", - "block.create.vertical_framed_glass_pane": "Склянна панель у вертикальній рамі", - "block.create.warped_window": "Скло з багряного дерева", - "block.create.warped_window_pane": "Склянна панель з багряного дерева", - "block.create.water_wheel": "Водяне колесо", - "block.create.waxed_copper_shingle_slab": "UNLOCALIZED: Waxed Copper Shingle Slab", - "block.create.waxed_copper_shingle_stairs": "UNLOCALIZED: Waxed Copper Shingle Stairs", - "block.create.waxed_copper_shingles": "UNLOCALIZED: Waxed Copper Shingles", - "block.create.waxed_copper_tile_slab": "UNLOCALIZED: Waxed Copper Tile Slab", - "block.create.waxed_copper_tile_stairs": "UNLOCALIZED: Waxed Copper Tile Stairs", - "block.create.waxed_copper_tiles": "UNLOCALIZED: Waxed Copper Tiles", - "block.create.waxed_exposed_copper_shingle_slab": "UNLOCALIZED: Waxed Exposed Copper Shingle Slab", - "block.create.waxed_exposed_copper_shingle_stairs": "UNLOCALIZED: Waxed Exposed Copper Shingle Stairs", - "block.create.waxed_exposed_copper_shingles": "UNLOCALIZED: Waxed Exposed Copper Shingles", - "block.create.waxed_exposed_copper_tile_slab": "UNLOCALIZED: Waxed Exposed Copper Tile Slab", - "block.create.waxed_exposed_copper_tile_stairs": "UNLOCALIZED: Waxed Exposed Copper Tile Stairs", - "block.create.waxed_exposed_copper_tiles": "UNLOCALIZED: Waxed Exposed Copper Tiles", - "block.create.waxed_oxidized_copper_shingle_slab": "UNLOCALIZED: Waxed Oxidized Copper Shingle Slab", - "block.create.waxed_oxidized_copper_shingle_stairs": "UNLOCALIZED: Waxed Oxidized Copper Shingle Stairs", - "block.create.waxed_oxidized_copper_shingles": "UNLOCALIZED: Waxed Oxidized Copper Shingles", - "block.create.waxed_oxidized_copper_tile_slab": "UNLOCALIZED: Waxed Oxidized Copper Tile Slab", - "block.create.waxed_oxidized_copper_tile_stairs": "UNLOCALIZED: Waxed Oxidized Copper Tile Stairs", - "block.create.waxed_oxidized_copper_tiles": "UNLOCALIZED: Waxed Oxidized Copper Tiles", - "block.create.waxed_weathered_copper_shingle_slab": "UNLOCALIZED: Waxed Weathered Copper Shingle Slab", - "block.create.waxed_weathered_copper_shingle_stairs": "UNLOCALIZED: Waxed Weathered Copper Shingle Stairs", - "block.create.waxed_weathered_copper_shingles": "UNLOCALIZED: Waxed Weathered Copper Shingles", - "block.create.waxed_weathered_copper_tile_slab": "UNLOCALIZED: Waxed Weathered Copper Tile Slab", - "block.create.waxed_weathered_copper_tile_stairs": "UNLOCALIZED: Waxed Weathered Copper Tile Stairs", - "block.create.waxed_weathered_copper_tiles": "UNLOCALIZED: Waxed Weathered Copper Tiles", - "block.create.weathered_copper_shingle_slab": "UNLOCALIZED: Weathered Copper Shingle Slab", - "block.create.weathered_copper_shingle_stairs": "UNLOCALIZED: Weathered Copper Shingle Stairs", - "block.create.weathered_copper_shingles": "UNLOCALIZED: Weathered Copper Shingles", - "block.create.weathered_copper_tile_slab": "UNLOCALIZED: Weathered Copper Tile Slab", - "block.create.weathered_copper_tile_stairs": "UNLOCALIZED: Weathered Copper Tile Stairs", - "block.create.weathered_copper_tiles": "UNLOCALIZED: Weathered Copper Tiles", - "block.create.weighted_ejector": "Зважена катапульта", - "block.create.white_nixie_tube": "Біла ніксі-труба", - "block.create.white_sail": "Біле вітрило", - "block.create.white_seat": "Біле сидіння", - "block.create.white_toolbox": "Білий ящик для інструментів", - "block.create.white_valve_handle": "Білий ручний клапан", - "block.create.windmill_bearing": "Підшипник вітряка", - "block.create.wooden_bracket": "Дерев'яний кронштейн", - "block.create.yellow_nixie_tube": "Жовта ніксі-труба", - "block.create.yellow_sail": "Жовте вітрило", - "block.create.yellow_seat": "Жовте сидіння", - "block.create.yellow_toolbox": "Жовтий ящик для інструментів", - "block.create.yellow_valve_handle": "Жовтий ручний клапан", - "block.create.zinc_block": "Цинковий блок", - "block.create.zinc_ore": "Цинкова руда", - - "enchantment.create.capacity": "Ємність", - "enchantment.create.potato_recovery": "Відновлення картоплі", - - "entity.create.carriage_contraption": "UNLOCALIZED: Carriage Contraption", - "entity.create.contraption": "Пристосування", - "entity.create.crafting_blueprint": "Створення креслення", - "entity.create.gantry_contraption": "Gantry Contraption", - "entity.create.potato_projectile": "Картопляний снаряд", - "entity.create.seat": "Сідло", - "entity.create.stationary_contraption": "Стаціонарне пристосування", - "entity.create.super_glue": "Суперклей", - - "fluid.create.potion": "Зілля", - "fluid.create.tea": "Чай будівельника", - - "item.create.andesite_alloy": "Андезитовий сплав", - "item.create.attribute_filter": "Фільтр атрибутів", - "item.create.bar_of_chocolate": "Плитка шоколаду", - "item.create.belt_connector": "Конвеєр", - "item.create.blaze_cake": "Торт «Вогняний».", - "item.create.blaze_cake_base": "Основа для «Вогняного» торта", - "item.create.brass_hand": "Латунна рука", - "item.create.brass_ingot": "Латунний злиток", - "item.create.brass_nugget": "Латунний самородок", - "item.create.brass_sheet": "Латунний лист", - "item.create.builders_tea": "Чай будівельника", - "item.create.chest_minecart_contraption": "Пристосований візок для скрині", - "item.create.chocolate_bucket": "Відерце шоколаду", - "item.create.chocolate_glazed_berries": "Ягоди в шоколадній глазурі", - "item.create.chromatic_compound": "Хроматична сполука", - "item.create.cinder_flour": "Борошно з незераку", - "item.create.copper_backtank": "Мідний балон", - "item.create.copper_backtank_placeable": "UNLOCALIZED: Copper Backtank Placeable", - "item.create.copper_nugget": "Мідний самородок", - "item.create.copper_sheet": "Мідний лист", - "item.create.crafter_slot_cover": "Кришка слота крафта", - "item.create.crafting_blueprint": "Створення креслення", - "item.create.creative_blaze_cake": "Творчий «Вогняний» торт", - "item.create.crushed_aluminum_ore": "Подрібнена алюмінієва руда", - "item.create.crushed_copper_ore": "Подрібнена мідна руда", - "item.create.crushed_gold_ore": "Подрібнена мідна руда", - "item.create.crushed_iron_ore": "Подрібнена залізна руда", - "item.create.crushed_lead_ore": "Подрібнена свинцева руда", - "item.create.crushed_nickel_ore": "Подрібнена нікелева руда", - "item.create.crushed_osmium_ore": "Подрібнена осмієва руда", - "item.create.crushed_platinum_ore": "Подрібнена платинова руда", - "item.create.crushed_quicksilver_ore": "Подрібнена ртутна руда", - "item.create.crushed_silver_ore": "Подрібнена Срібна руда", - "item.create.crushed_tin_ore": "Подрібнена олов'яна руда", - "item.create.crushed_uranium_ore": "Подрібнена уранова руда", - "item.create.crushed_zinc_ore": "Подрібнена цинкова руда", - "item.create.diving_boots": "Чоботи для дайвінгу", - "item.create.diving_helmet": "Шолом для дайвінгу", - "item.create.dough": "Тісто", - "item.create.electron_tube": "Електронна лампа", - "item.create.empty_blaze_burner": "Пустий пальник блейза", - "item.create.empty_schematic": "Порожня схема", - "item.create.experience_nugget": "UNLOCALIZED: Nugget of Experience", - "item.create.extendo_grip": "Довга рука", - "item.create.filter": "Фільтер", - "item.create.furnace_minecart_contraption": "Штуковина самоходной вагонетки", - "item.create.goggles": "Інженерні окуляри", - "item.create.golden_sheet": "Золотий лист", - "item.create.handheld_worldshaper": "Творчий світотворець", - "item.create.honey_bucket": "Відро з медом", - "item.create.honeyed_apple": "Яблуко з медом", - "item.create.incomplete_precision_mechanism": "Неповний прецизійний механізм", - "item.create.incomplete_track": "UNLOCALIZED: Incomplete Track", - "item.create.iron_sheet": "Залізний лист", - "item.create.linked_controller": "Підключений контролер", - "item.create.minecart_contraption": "Вагонеточна штуковина", - "item.create.minecart_coupling": "З'єднувач вагонеток", - "item.create.polished_rose_quartz": "Полірований рожевий кварц", - "item.create.potato_cannon": "Картопляна гармата", - "item.create.powdered_obsidian": "Обсідіановий порошок", - "item.create.precision_mechanism": "Прецизійний механізм", - "item.create.propeller": "Пропеллер", - "item.create.raw_zinc": "UNLOCALIZED: Raw Zinc", - "item.create.red_sand_paper": "Червоний наждачний папір", - "item.create.refined_radiance": "Вишукане сяйво", - "item.create.rose_quartz": "Hожевий кварц", - "item.create.sand_paper": "Наждачний папір", - "item.create.schedule": "UNLOCALIZED: Train Schedule", - "item.create.schematic": "Схема", - "item.create.schematic_and_quill": "Схема і перо", - "item.create.shadow_steel": "Тіньова сталь", - "item.create.sturdy_sheet": "UNLOCALIZED: Sturdy Sheet", - "item.create.super_glue": "Суперклей", - "item.create.sweet_roll": "Солодкий рулет", - "item.create.tree_fertilizer": "Добриво для дерев", - "item.create.unprocessed_obsidian_sheet": "UNLOCALIZED: Unprocessed Obsidian Sheet", - "item.create.vertical_gearbox": "Вертикальна коробка передач", - "item.create.wand_of_symmetry": "Палиця симетрії", - "item.create.wheat_flour": "Пшеничне борошно", - "item.create.whisk": "Віничок для збивання", - "item.create.wrench": "Гайковий ключ", - "item.create.zinc_ingot": "Цинковий злиток", - "item.create.zinc_nugget": "Цинковий самородок", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "Ласкаво просимо до Create", - "advancement.create.root.desc": "Настав час почати будувати дивовижні пристрої!", - "advancement.create.andesite_alloy": "Повторення - мати навчання", - "advancement.create.andesite_alloy.desc": "Матеріали Create мають дивні назви, одна з них – Андезитовий сплав..", - "advancement.create.andesite_casing": "Андезитова епоха", - "advancement.create.andesite_casing.desc": "Використовуйте трохи Андезитового Сплаву та дерева, щоб створити Корпус.", - "advancement.create.mechanical_press": "UNLOCALIZED: Bonk!", - "advancement.create.mechanical_press.desc": "UNLOCALIZED: Create some sheets in a Mechanical Press", - "advancement.create.encased_fan": "UNLOCALIZED: Wind Maker", - "advancement.create.encased_fan.desc": "UNLOCALIZED: Place and power an Encased Fan", - "advancement.create.fan_processing": "UNLOCALIZED: Processing by Particle", - "advancement.create.fan_processing.desc": "UNLOCALIZED: Use an Encased Fan to process materials", - "advancement.create.saw_processing": "UNLOCALIZED: Workshop's Most Feared", - "advancement.create.saw_processing.desc": "UNLOCALIZED: Use an upright Mechanical Saw to process materials", - "advancement.create.compacting": "UNLOCALIZED: Compactification", - "advancement.create.compacting.desc": "UNLOCALIZED: Use a Mechanical Press and a Basin to create fewer items from more", - "advancement.create.belt": "Передайте за проїзд", - "advancement.create.belt.desc": "З'єднайте два вали за допомогою конвеєру.", - "advancement.create.funnel": "UNLOCALIZED: Airport Aesthetic", - "advancement.create.funnel.desc": "UNLOCALIZED: Extract or insert items into a container using a Funnel", - "advancement.create.chute": "Впало", - "advancement.create.chute.desc": "Розмістіть жолоб, вертикальний аналог конвеєра.", - "advancement.create.mechanical_mixer": "UNLOCALIZED: Mixing It Up", - "advancement.create.mechanical_mixer.desc": "UNLOCALIZED: Combine ingredients in a Mechanical Mixer", - "advancement.create.burner": "UNLOCALIZED: Sentient Fireplace", - "advancement.create.burner.desc": "UNLOCALIZED: Obtain a Blaze Burner", - "advancement.create.water_wheel": "Підключення гідравліки", - "advancement.create.water_wheel.desc": "Поставте Водяне колесо та спробуйте змусити його обертатися!", - "advancement.create.windmill": "Легкий вітерець", - "advancement.create.windmill.desc": "Зберіть Вітряк.", - "advancement.create.shifting_gears": "Перемикання передач", - "advancement.create.shifting_gears.desc": "З’єднайте велику шестірню з малою шестернею, щоб змінити швидкість вашого пристрою.", - "advancement.create.millstone": "Кишеньковий подрібнювач", - "advancement.create.millstone.desc": "Розмістіть і заставте Жорна крутитись", - "advancement.create.super_glue": "UNLOCALIZED: Area of Connect", - "advancement.create.super_glue.desc": "UNLOCALIZED: Super Glue some blocks into a group", - "advancement.create.contraption_actors": "UNLOCALIZED: Moving with Purpose", - "advancement.create.contraption_actors.desc": "UNLOCALIZED: Create a Contraption with drills, saws, or harvesters on board", - "advancement.create.portable_storage_interface": "UNLOCALIZED: Drive-By Exchange", - "advancement.create.portable_storage_interface.desc": "UNLOCALIZED: Use a Portable Storage Interface to take or insert items into a Contraption", - "advancement.create.wrench_goggles": "UNLOCALIZED: Kitted Out", - "advancement.create.wrench_goggles.desc": "UNLOCALIZED: Equip Engineer's Goggles and a Wrench", - "advancement.create.stressometer": "Так сильно?", - "advancement.create.stressometer.desc": "Розмістіть і підключіть стресометр. Подивіться на нього крізь окуляри, щоб прочитати його точне значення.", - "advancement.create.cuckoo_clock": "UNLOCALIZED: Is It Time?", - "advancement.create.cuckoo_clock.desc": "UNLOCALIZED: Witness your Cuckoo Clock announce bedtime", - "advancement.create.windmill_maxed": "UNLOCALIZED: A Strong Breeze", - "advancement.create.windmill_maxed.desc": "UNLOCALIZED: Assemble a windmill of maximum strength", - "advancement.create.ejector_maxed": "UNLOCALIZED: Springboard Champion", - "advancement.create.ejector_maxed.desc": "UNLOCALIZED: Get launched more than 30 blocks by a Weighted Ejector", - "advancement.create.pulley_maxed": "UNLOCALIZED: Rope to Nowhere", - "advancement.create.pulley_maxed.desc": "UNLOCALIZED: Extend a Rope Pulley over 200 blocks deep", - "advancement.create.cart_pickup": "UNLOCALIZED: Strong Arms", - "advancement.create.cart_pickup.desc": "UNLOCALIZED: Pick up a Minecart Contraption with at least 200 attached blocks", - "advancement.create.anvil_plough": "UNLOCALIZED: Blacksmith Artillery", - "advancement.create.anvil_plough.desc": "UNLOCALIZED: Launch an Anvil with Mechanical Ploughs", - "advancement.create.lava_wheel_00000": "UNLOCALIZED: Magma Wheel", - "advancement.create.lava_wheel_00000.desc": "UNLOCALIZED: This shouldn't have worked§7\n(Hidden Advancement)", - "advancement.create.hand_crank_000": "UNLOCALIZED: Workout Session", - "advancement.create.hand_crank_000.desc": "UNLOCALIZED: Use a Hand Crank until fully exhausted§7\n(Hidden Advancement)", - "advancement.create.belt_funnel_kiss": "Папуги і клапті", - "advancement.create.belt_funnel_kiss.desc": "Зробіть поцілунок двох воронок, встановлених на конвеєрі.", - "advancement.create.stressometer_maxed": "UNLOCALIZED: Perfectly Stressed", - "advancement.create.stressometer_maxed.desc": "UNLOCALIZED: Get a 100% readout from a Stressometer§7\n(Hidden Advancement)", - "advancement.create.copper": "UNLOCALIZED: Cuprum Bokum", - "advancement.create.copper.desc": "UNLOCALIZED: Amass some Copper Ingots for your exploits in fluid manipulation", - "advancement.create.copper_casing": "Мідна епоха", - "advancement.create.copper_casing.desc": "Використовуйте Мідні листи та деревину, щоб створити кілька Мідних корпусів.", - "advancement.create.spout": "Буль", - "advancement.create.spout.desc": "Спостерігайте, як рідина наповнюється за допомогою носика.", - "advancement.create.drain": "UNLOCALIZED: Tumble Draining", - "advancement.create.drain.desc": "UNLOCALIZED: Watch a fluid-containing item be emptied by an Item Drain", - "advancement.create.steam_engine": "UNLOCALIZED: The Powerhouse", - "advancement.create.steam_engine.desc": "UNLOCALIZED: Use a Steam Engine to generate torque", - "advancement.create.steam_whistle": "UNLOCALIZED: Voice of an Angel", - "advancement.create.steam_whistle.desc": "UNLOCALIZED: Activate a Steam Whistle", - "advancement.create.backtank": "UNLOCALIZED: Pressure to Go", - "advancement.create.backtank.desc": "UNLOCALIZED: Create a Copper Backtank and make it accumulate air pressure", - "advancement.create.diving_suit": "UNLOCALIZED: Ready for the Depths", - "advancement.create.diving_suit.desc": "UNLOCALIZED: Equip a Diving Helmet and a Copper Backtank, then jump into water", - "advancement.create.mechanical_pump_0": "UNLOCALIZED: Under Pressure", - "advancement.create.mechanical_pump_0.desc": "UNLOCALIZED: Place and power a Mechanical Pump", - "advancement.create.glass_pipe": "Шпигун за потоками", - "advancement.create.glass_pipe.desc": "Спостерігайте через вікно у трубі за тим, як поширюється рідина. Вікно з'явиться на трубі під час використання гайкового ключа.", - "advancement.create.water_supply": "UNLOCALIZED: Puddle Collector", - "advancement.create.water_supply.desc": "UNLOCALIZED: Use the pulling end of a Fluid Pipe or Mechanical Pump to collect water", - "advancement.create.hose_pulley": "Промисловий розлив", - "advancement.create.hose_pulley.desc": "Опустіть шків шланга та спостерігайте, як він стікає або наповнює тіло рідиною.", - "advancement.create.chocolate_bucket": "UNLOCALIZED: A World of Imagination", - "advancement.create.chocolate_bucket.desc": "UNLOCALIZED: Obtain a bucket of molten chocolate", - "advancement.create.honey_drain": "UNLOCALIZED: Autonomous Bee-Keeping", - "advancement.create.honey_drain.desc": "UNLOCALIZED: Use pipes to pull honey from a Bee Nest or Beehive", - "advancement.create.hose_pulley_lava": "UNLOCALIZED: Tapping the Mantle", - "advancement.create.hose_pulley_lava.desc": "UNLOCALIZED: Pump from a body of lava large enough to be considered infinite", - "advancement.create.steam_engine_maxed": "UNLOCALIZED: Full Steam", - "advancement.create.steam_engine_maxed.desc": "UNLOCALIZED: Run a boiler at the maximum level of power", - "advancement.create.foods": "UNLOCALIZED: Balanced Diet", - "advancement.create.foods.desc": "UNLOCALIZED: Create Chocolate Glazed Berries, a Honeyed Apple, and a Sweet Roll all from the same Spout", - "advancement.create.diving_suit_lava": "UNLOCALIZED: Swimming with the Striders", - "advancement.create.diving_suit_lava.desc": "UNLOCALIZED: Attempt to take a dive in lava with your diving gear§7\n(Hidden Advancement)", - "advancement.create.chained_drain": "UNLOCALIZED: On a Roll", - "advancement.create.chained_drain.desc": "UNLOCALIZED: Watch an item move across a row of Item Drains§7\n(Hidden Advancement)", - "advancement.create.cross_streams": "UNLOCALIZED: Don't Cross the Streams!", - "advancement.create.cross_streams.desc": "UNLOCALIZED: Watch two fluids meet in your pipe network§7\n(Hidden Advancement)", - "advancement.create.pipe_organ": "UNLOCALIZED: The Pipe Organ", - "advancement.create.pipe_organ.desc": "UNLOCALIZED: Attach 12 uniquely pitched Steam Whistles to a single Fluid Tank§7\n(Hidden Advancement)", - "advancement.create.brass": "Фактичні сплави", - "advancement.create.brass.desc": "Використовуйте Подрібнену мідь і Подрібнений цинк, щоб створити трохи Латуні.", - "advancement.create.brass_casing": "Латунна епоха", - "advancement.create.brass_casing.desc": "Використовуйте щойно отриману латунь і трохи дерева, щоб створити більш досконалий корпус.", - "advancement.create.rose_quartz": "UNLOCALIZED: Pink Diamonds", - "advancement.create.rose_quartz.desc": "UNLOCALIZED: Polish some Rose Quartz", - "advancement.create.deployer": "Тикай, клади та атакуй", - "advancement.create.deployer.desc": "Приведіть у дію Автономний активатор, ідеальне відображення вас самих.", - "advancement.create.precision_mechanism": "Складні цікавості", - "advancement.create.precision_mechanism.desc": "Зберіть Прецизійний механізм.", - "advancement.create.speed_controller": "Інженери його ненавидять!", - "advancement.create.speed_controller.desc": "Розмістіть регулятор швидкості обертання, найкращий пристрій для перемикання передач.", - "advancement.create.mechanical_arm": "Золоті руки!", - "advancement.create.mechanical_arm.desc": "Зробіть Механічну руку, виберіть входи та виходи, розмістіть та приведіть у дію; потім спостерігайте, як вона виконує всю роботу за вас.", - "advancement.create.mechanical_crafter": "UNLOCALIZED: Automated Assembly", - "advancement.create.mechanical_crafter.desc": "UNLOCALIZED: Place and power some Mechanical Crafters", - "advancement.create.crushing_wheel": "Пара гігантів", - "advancement.create.crushing_wheel.desc": "Створіть Дробильні колеса, щоб ефективніше руйнувати більше матеріалів.", - "advancement.create.haunted_bell": "UNLOCALIZED: Shadow Sense", - "advancement.create.haunted_bell.desc": "UNLOCALIZED: Toll a Haunted Bell", - "advancement.create.clockwork_bearing": "Хитрий годинник", - "advancement.create.clockwork_bearing.desc": "Зберіть структуру, розташовану на годинниковому механізмі.", - "advancement.create.display_link": "UNLOCALIZED: Big Data", - "advancement.create.display_link.desc": "UNLOCALIZED: Use a Display Link to visualise information", - "advancement.create.potato_cannon": "Свомп!", - "advancement.create.potato_cannon.desc": "Переможіть ворога за допомогою Картопляної гармати.", - "advancement.create.extendo_grip": "Боіоіоіпг!", - "advancement.create.extendo_grip.desc": "Отримайте Довгу руку.", - "advancement.create.linked_controller": "UNLOCALIZED: Remote Activation", - "advancement.create.linked_controller.desc": "UNLOCALIZED: Activate a Redstone Link using a Linked Controller", - "advancement.create.arm_blaze_burner": "Підпаль-трон", - "advancement.create.arm_blaze_burner.desc": "Доручіть Механічній руці живити ваш Пальник блейза.", - "advancement.create.crusher_maxed_0000": "UNLOCALIZED: Crushing It", - "advancement.create.crusher_maxed_0000.desc": "UNLOCALIZED: Operate a pair of Crushing Wheels at maximum speed", - "advancement.create.arm_many_targets": "Організа-трон", - "advancement.create.arm_many_targets.desc": "Запрограмуйте механічну руку з десятьма або більше виходів.", - "advancement.create.potato_cannon_collide": "UNLOCALIZED: Veggie Fireworks", - "advancement.create.potato_cannon_collide.desc": "UNLOCALIZED: Cause Potato Cannon projectiles of different types to collide with each other", - "advancement.create.self_deploying": "UNLOCALIZED: Self-Driving Cart", - "advancement.create.self_deploying.desc": "UNLOCALIZED: Create a Minecart Contraption that places tracks in front of itself", - "advancement.create.fist_bump": "Розбий це, брате!", - "advancement.create.fist_bump.desc": "Зробіть два удари кулаками Автономних активаторів.", - "advancement.create.crafter_lazy_000": "UNLOCALIZED: Desperate Measures", - "advancement.create.crafter_lazy_000.desc": "UNLOCALIZED: Drastically slow down a Mechanical Crafter to procrastinate on proper infrastructure§7\n(Hidden Advancement)", - "advancement.create.extendo_grip_dual": "UNLOCALIZED: To Full Extent", - "advancement.create.extendo_grip_dual.desc": "UNLOCALIZED: Dual-wield Extendo Grips for superhuman reach§7\n(Hidden Advancement)", - "advancement.create.musical_arm": "Зіграй мені мою мелодію!", - "advancement.create.musical_arm.desc": "Подивіться, як Механічна рука міняє пластинки.", - "advancement.create.sturdy_sheet": "UNLOCALIZED: The Sturdiest Rocks", - "advancement.create.sturdy_sheet.desc": "UNLOCALIZED: Assemble a Sturdy Sheet by refining Powdered Obsidian", - "advancement.create.train_casing_00": "UNLOCALIZED: The Logistical Age", - "advancement.create.train_casing_00.desc": "UNLOCALIZED: Use Sturdy Sheets to create a casing for railway components", - "advancement.create.train": "UNLOCALIZED: All Aboard!", - "advancement.create.train.desc": "UNLOCALIZED: Assemble your first Train", - "advancement.create.conductor": "UNLOCALIZED: Conductor Instructor", - "advancement.create.conductor.desc": "UNLOCALIZED: Instruct a Train driver with a Train Schedule", - "advancement.create.track_signal": "UNLOCALIZED: Traffic Control", - "advancement.create.track_signal.desc": "UNLOCALIZED: Place a Train Signal", - "advancement.create.display_board_0": "UNLOCALIZED: Dynamic Timetables", - "advancement.create.display_board_0.desc": "UNLOCALIZED: Forecast a Train's arrival on your Display Board with the help of Display Links", - "advancement.create.track_0": "UNLOCALIZED: A New Gauge", - "advancement.create.track_0.desc": "UNLOCALIZED: Obtain some Train Tracks", - "advancement.create.train_whistle": "UNLOCALIZED: Choo Choo!", - "advancement.create.train_whistle.desc": "UNLOCALIZED: Assemble a Steam Whistle to your Train and activate it while driving", - "advancement.create.train_portal": "UNLOCALIZED: Dimensional Commuter", - "advancement.create.train_portal.desc": "UNLOCALIZED: Ride a Train through a Nether portal", - "advancement.create.track_crafting_factory": "UNLOCALIZED: Track Factory", - "advancement.create.track_crafting_factory.desc": "UNLOCALIZED: Produce more than 1000 Train Tracks with the same Mechanical Press", - "advancement.create.long_bend": "UNLOCALIZED: The Longest Bend", - "advancement.create.long_bend.desc": "UNLOCALIZED: Create a curved track section that spans more than 30 blocks in length", - "advancement.create.long_train": "UNLOCALIZED: Ambitious Endeavours", - "advancement.create.long_train.desc": "UNLOCALIZED: Create a Train with at least 6 carriages", - "advancement.create.long_travel": "UNLOCALIZED: Field Trip", - "advancement.create.long_travel.desc": "UNLOCALIZED: Leave a Train Seat over 5000 blocks away from where you started travelling", - "advancement.create.train_roadkill": "UNLOCALIZED: Road Kill", - "advancement.create.train_roadkill.desc": "UNLOCALIZED: Run over an enemy with your Train§7\n(Hidden Advancement)", - "advancement.create.red_signal": "UNLOCALIZED: Expert Driver", - "advancement.create.red_signal.desc": "UNLOCALIZED: Run a red Train Signal§7\n(Hidden Advancement)", - "advancement.create.train_crash": "UNLOCALIZED: Terrible Service", - "advancement.create.train_crash.desc": "UNLOCALIZED: Witness a Train crash as a passenger§7\n(Hidden Advancement)", - "advancement.create.train_crash_backwards": "UNLOCALIZED: Blind Spot", - "advancement.create.train_crash_backwards.desc": "UNLOCALIZED: Crash into another Train while driving backwards§7\n(Hidden Advancement)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "Create", - "itemGroup.create.palettes": "Create Палітри", - - "death.attack.create.crush": "%1$s був передроблений", - "death.attack.create.crush.player": "%1$s був кинутий у Дробильне колесо %2$s", - "death.attack.create.fan_fire": "%1$s був спалений до смерті гарячим повітрям", - "death.attack.create.fan_fire.player": "%2$s скинув%1$s в коптильну", - "death.attack.create.fan_lava": "%1$s був спалений Вентилятором", - "death.attack.create.fan_lava.player": "%2$s скинув %1$s в плавильну", - "death.attack.create.mechanical_drill": "%1$s був проколений Механічною дрелью", - "death.attack.create.mechanical_drill.player": "%2$s скинув %1$s під Механічну дрель", - "death.attack.create.mechanical_saw": "%1$s був розрізаний навпіл Механічною пилою", - "death.attack.create.mechanical_saw.player": "%2$s скинув %1$s у пилу ", - "death.attack.create.potato_cannon": "%1$s був вбитий %2$s за допомогою Картопляної гармати", - "death.attack.create.potato_cannon.item": "%1$s був вбитий %2$s використовуючи %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s підірвали підробленим годинником з зозулею", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s був підірваний підробленим годинником з зозулею", - "death.attack.create.run_over": "UNLOCALIZED: %1$s was run over by %2$s", - - "create.block.deployer.damage_source_name": "автономним активатором", - "create.block.cart_assembler.invalid": "Помістіть свій Збирач вагонеток на блок рейок", - - "create.menu.return": "Повернутись у меню", - "create.menu.configure": "Налаштувати...", - "create.menu.ponder_index": "Зміст роздумів", - "create.menu.only_ingame": "Доступно в Меню Паузи", - "create.menu.report_bugs": "Повідомити про проблеми", - "create.menu.support": "Підтримати нас", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "Дроблення", - "create.recipe.milling": "Помел", - "create.recipe.fan_washing": "Масове вимивання", - "create.recipe.fan_washing.fan": "Вентилятор за Текучою водою", - "create.recipe.fan_smoking": "Масове копчення", - "create.recipe.fan_smoking.fan": "Вентилятор за Вогнем", - "create.recipe.fan_haunting": "UNLOCALIZED: Bulk Haunting", - "create.recipe.fan_haunting.fan": "UNLOCALIZED: Fan behind Soul Fire", - "create.recipe.fan_blasting": "Bulk Blasting", - "create.recipe.fan_blasting.fan": "Вентилятор за Лавоб", - "create.recipe.pressing": "Пресування", - "create.recipe.mixing": "Змішування", - "create.recipe.deploying": "Автономна активація", - "create.recipe.automatic_shapeless": "Автоматизоване безформне виготовлення", - "create.recipe.automatic_brewing": "Автоматичне зіллє-варіння", - "create.recipe.packing": "Ущільнення", - "create.recipe.automatic_packing": "Автопатичне пакування", - "create.recipe.sawing": "Пиляння", - "create.recipe.mechanical_crafting": "Механічне виготовлення", - "create.recipe.automatic_shaped": "Автоматизоване формне виготовлення", - "create.recipe.block_cutting": "Різання блоків", - "create.recipe.wood_cutting": "Розпилювання деревини", - "create.recipe.sandpaper_polishing": "Полірування наждачним папером", - "create.recipe.mystery_conversion": "Таємниче перетворення", - "create.recipe.spout_filling": "Наповнення носиком", - "create.recipe.draining": "Осушуванян предметів", - "create.recipe.item_application": "UNLOCALIZED: Manual Item Application", - "create.recipe.item_application.any_axe": "UNLOCALIZED: Any Axe", - "create.recipe.sequenced_assembly": "Послідовне складання", - "create.recipe.assembly.next": "Далі: %1$s", - "create.recipe.assembly.step": "Крок %1$s:", - "create.recipe.assembly.progress": "Прогрес: %1$s/%2$s", - "create.recipe.assembly.pressing": "Процес у пресі", - "create.recipe.assembly.spout_filling_fluid": "Налийте %1$s", - "create.recipe.assembly.deploying_item": "Добавте %1$s", - "create.recipe.assembly.cutting": "Розріжте пилою", - "create.recipe.assembly.repeat": "Повторіть послідовність %1$s раз", - "create.recipe.assembly.junk": "Випадкове сміття", - "create.recipe.processing.chance": "%1$s%% Шанс", - "create.recipe.deploying.not_consumed": "Не спожито", - "create.recipe.heat_requirement.none": "Не потребує нагрівання", - "create.recipe.heat_requirement.heated": "Нагріте", - "create.recipe.heat_requirement.superheated": "Дуже нагрітий", - - "create.generic.range": "Діапазон", - "create.generic.radius": "Радіус", - "create.generic.width": "Ширина", - "create.generic.height": "Висота", - "create.generic.length": "Довжина", - "create.generic.speed": "Швидкість", - "create.generic.delay": "Затримка", - "create.generic.duration": "UNLOCALIZED: Duration", - "create.generic.timeUnit": "UNLOCALIZED: Time Unit", - "create.generic.unit.ticks": "Тіків", - "create.generic.unit.seconds": "Секунд", - "create.generic.unit.minutes": "Хвилин", - "create.generic.daytime.hour": "UNLOCALIZED: Hour", - "create.generic.daytime.minute": "UNLOCALIZED: Minute", - "create.generic.daytime.second": "UNLOCALIZED: Second", - "create.generic.daytime.pm": "UNLOCALIZED: pm", - "create.generic.daytime.am": "UNLOCALIZED: am", - "create.generic.unit.rpm": "об./хв", - "create.generic.unit.stress": "su(одиниця напруги)", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "UNLOCALIZED: B", - "create.generic.clockwise": "За годинниковою стрілкою", - "create.generic.counter_clockwise": "Проти годинникової стрілки", - "create.generic.in_quotes": "UNLOCALIZED: \"%1$s\"", - "create.generic.pitch": "UNLOCALIZED: Pitch: %1$s", - "create.generic.notes": "UNLOCALIZED: F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "Прокрутка", - "create.action.confirm": "Підтвердити", - "create.action.abort": "Перервати", - "create.action.saveToFile": "Зберегти", - "create.action.discard": "Відкинути", - - "create.keyinfo.toolmenu": "Меню інструмента фокусування", - "create.keyinfo.toolbelt": "Доступ до Ящиків інструментів поблизу", - "create.keyinfo.scrollup": "Імітація руху миші вверх (в світі)", - "create.keyinfo.scrolldown": "Імітація руху миші вниз (в світі)", - - "create.gui.scrollInput.defaultTitle": "Виберіть опцію:", - "create.gui.scrollInput.scrollToModify": "Прокрутіть щоб змінити", - "create.gui.scrollInput.scrollToAdjustAmount": "Прокрутіть щоб налаштувати кількість", - "create.gui.scrollInput.scrollToSelect": "Прокрутіть щоб вибрати", - "create.gui.scrollInput.shiftScrollsFaster": "Shift шоб прокручувати швидше", - "create.gui.toolmenu.focusKey": "Зажміть [%1$s] щоб зосередитися", - "create.gui.toolmenu.cycle": "[SCROLL] для переключения", - - "create.toolbox.unequip": "Зняти спорядження: %1$s", - "create.toolbox.outOfRange": "Ящик для інструментів з утримуваним предметом задалеко", - "create.toolbox.detach": "Припинити збереження та відстеження предметів", - "create.toolbox.depositAll": "Повернути предмети до найближчих Ящиків з інструментами", - "create.toolbox.depositBox": "Повернути предмети до Ящику з інструментами", - - "create.gui.symmetryWand.mirrorType": "Дзеркало", - "create.gui.symmetryWand.orientation": "Орієнтація", - - "create.symmetry.mirror.plane": "Одинарне", - "create.symmetry.mirror.doublePlane": "Двойне", - "create.symmetry.mirror.triplePlane": "Тройне", - - "create.orientation.orthogonal": "Перпендикуляр", - "create.orientation.diagonal": "Діагональ", - "create.orientation.horizontal": "Горизонталь", - "create.orientation.alongZ": "Уздовж Z", - "create.orientation.alongX": "Уздовж X", - - "create.gui.terrainzapper.title": "Ручний редактор світу", - "create.gui.terrainzapper.searchDiagonal": "Слідування діагоналям", - "create.gui.terrainzapper.searchFuzzy": "Ігнорувати границі матеріала", - "create.gui.terrainzapper.patternSection": "Шаблон", - "create.gui.terrainzapper.pattern.solid": "Суцільний", - "create.gui.terrainzapper.pattern.checkered": "Шахматний порядок", - "create.gui.terrainzapper.pattern.inversecheckered": "Зворотний шаховий порядок", - "create.gui.terrainzapper.pattern.chance25": "25% заповнення", - "create.gui.terrainzapper.pattern.chance50": "50% заповнення", - "create.gui.terrainzapper.pattern.chance75": "75% заповнення", - "create.gui.terrainzapper.placement": "Розміщення", - "create.gui.terrainzapper.placement.merged": "Злитий", - "create.gui.terrainzapper.placement.attached": "Прикріплений", - "create.gui.terrainzapper.placement.inserted": "Вставлений", - "create.gui.terrainzapper.brush": "Простий", - "create.gui.terrainzapper.brush.cuboid": "Куб", - "create.gui.terrainzapper.brush.sphere": "Сфера", - "create.gui.terrainzapper.brush.cylinder": "Циліндр", - "create.gui.terrainzapper.brush.surface": "Поверхність", - "create.gui.terrainzapper.brush.cluster": "Скупчення", - "create.gui.terrainzapper.tool": "Інструмент", - "create.gui.terrainzapper.tool.fill": "Заповнити", - "create.gui.terrainzapper.tool.place": "Поставити", - "create.gui.terrainzapper.tool.replace": "Замінити", - "create.gui.terrainzapper.tool.clear": "Очистити", - "create.gui.terrainzapper.tool.overlay": "Накладення", - "create.gui.terrainzapper.tool.flatten": "Вирівнювання", - - "create.terrainzapper.shiftRightClickToSet": "ПКМ щоб вибрати форму", - "create.terrainzapper.usingBlock": "Використовується: %1$s", - "create.terrainzapper.leftClickToSet": "Left-Click a Block to set Material", - - "create.minecart_coupling.two_couplings_max": "Вагонетки можуть мати лише два зв'язки", - "create.minecart_coupling.unloaded": "Здається, частина вашого поїзда у незавантажених чанках", - "create.minecart_coupling.no_loops": "З'єднувачі не можуть утворювати петлю", - "create.minecart_coupling.removed": "Прибрано всі зв'язки між вагонетками", - "create.minecart_coupling.too_far": "Вагонетки надто далеко один від одного", - - "create.contraptions.movement_mode": "Режим руху", - "create.contraptions.movement_mode.move_place": "Завжди розміщувати, коли Зупинено", - "create.contraptions.movement_mode.move_place_returned": "Розміщуйте лише у Вихідному положенні", - "create.contraptions.movement_mode.move_never_place": "Розміщувати лише після Знищення якоря", - "create.contraptions.movement_mode.rotate_place": "Завжди розміщувати, коли Зупинено", - "create.contraptions.movement_mode.rotate_place_returned": "Розміщуйте лише біля Початкового Кута", - "create.contraptions.movement_mode.rotate_never_place": "Розміщувати лише після Знищення якоря", - "create.contraptions.cart_movement_mode": "Режим руху вагонетки", - "create.contraptions.cart_movement_mode.rotate": "Завжди обличчям до руху", - "create.contraptions.cart_movement_mode.rotate_paused": "Пауза під час обертання", - "create.contraptions.cart_movement_mode.rotation_locked": "Завблокувати обертання", - "create.contraptions.windmill.rotation_direction": "Напрям обертання", - "create.contraptions.clockwork.clock_hands": "Стрілки годинника", - "create.contraptions.clockwork.hour_first": "Спочатку годинна стрілка", - "create.contraptions.clockwork.minute_first": "Спочатку хвилинна стрілка", - "create.contraptions.clockwork.hour_first_24": "Спочатку 24-годинна стрілка", - - "create.logistics.filter": "Фільтр", - "create.logistics.recipe_filter": "Фільтр рецептів", - "create.logistics.fluid_filter": "Фільтр рідини", - "create.logistics.firstFrequency": "Частота #1", - "create.logistics.secondFrequency": "Частота #2", - "create.logistics.filter.apply": "Фільтр використаний до %1$s.", - "create.logistics.filter.apply_click_again": "Фільтр використаний до %1$s, нажміть ще раз, щоб скопіювати кількість.", - "create.logistics.filter.apply_count": "Застосовано кількість, що витягується до фільтра.", - - "create.gui.goggles.generator_stats": "Статистика генератора:", - "create.gui.goggles.kinetic_stats": "Кінетична статистика:", - "create.gui.goggles.at_current_speed": "на поточній швидкості", - "create.gui.goggles.pole_length": "Довжина поршня:", - "create.gui.goggles.fluid_container": "Інформація про рідинний контейнер:", - "create.gui.goggles.fluid_container.capacity": "Ємність: ", - "create.gui.assembly.exception": "Цю штуковину не вдалося зібрати:", - "create.gui.assembly.exception.unmovableBlock": "Непересувний блок (%4$s) на координатах: [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "Блок на координатах: [%1$s,%2$s,%3$s] не в завантаженому чанку", - "create.gui.assembly.exception.structureTooLarge": "Штуковина складається із занадто великої кількості блоків.\nПоточний максимум: %1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "Надто багато Подовжувачів прикріплено до цього поршня.\nПоточний максимум: %1$s", - "create.gui.assembly.exception.noPistonPoles": "Поршню не вистачає Подовжувачів", - "create.gui.assembly.exception.not_enough_sails": "Приєднана структура не містить достатньо парусоподібних блоків: %1$s\nМінімум з %2$s необхідних", - "create.gui.gauge.info_header": "Калібрувальна інформація:", - "create.gui.speedometer.title": "Швидкість обертання", - "create.gui.stressometer.title": "Нагрузка на мережу", - "create.gui.stressometer.capacity": "Місткість, що залишилася", - "create.gui.stressometer.overstressed": "Перегрузка", - "create.gui.stressometer.no_rotation": "Немає обертання", - "create.gui.contraptions.not_fast_enough": "Похоже що цей %1$s is _не_ обертається _достатньою_ _швидкістю_.", - "create.gui.contraptions.network_overstressed": "Здається ця штуковина _перегружена_. Додати більше джерел або _зменшіть_ _швидкість_ компонентів які створюють велику _нагрузку_.", - "create.gui.adjustable_crate.title": "Регульований ящик", - "create.gui.adjustable_crate.storageSpace": "Ємність", - "create.gui.stockpile_switch.title": "Налаштований компаратор", - "create.gui.stockpile_switch.invert_signal": "Інвертувати сигнал", - "create.gui.stockpile_switch.move_to_lower_at": "Рухатися до нижньої лінії при %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "Рухатися до верхньої лінії при %1$s%%", - "create.gui.sequenced_gearshift.title": "Послідовне перемикання передач", - "create.gui.sequenced_gearshift.instruction": "Інструкція", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "Повернути на кут", - "create.gui.sequenced_gearshift.instruction.turn_angle": "Повернути", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Кут", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "Пверніть для руху Поршня/Pulley/Gantry", - "create.gui.sequenced_gearshift.instruction.turn_distance": "Поршень", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Відстань", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "Тимчасова затримка", - "create.gui.sequenced_gearshift.instruction.delay": "Затримка", - "create.gui.sequenced_gearshift.instruction.delay.duration": "Тривалість", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "Кінець", - "create.gui.sequenced_gearshift.instruction.end": "Кінець", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "Чекати на новий Імпульс редстоун Сигналу", - "create.gui.sequenced_gearshift.instruction.await": "Очікувати", - "create.gui.sequenced_gearshift.speed": "Швидкість, Напрям", - "create.gui.sequenced_gearshift.speed.forward": "Швидкість введення, вперед", - "create.gui.sequenced_gearshift.speed.forward_fast": "Двойна швидкість, вперед", - "create.gui.sequenced_gearshift.speed.back": "Швидкість введення, реверс", - "create.gui.sequenced_gearshift.speed.back_fast": "Двойна швидкість, реверс", - - "create.schematicAndQuill.dimensions": "Розмір схематики: %1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "Перша позиція установлена.", - "create.schematicAndQuill.secondPos": "Друга позиція установлена.", - "create.schematicAndQuill.noTarget": "Утримуйте [Ctrl], щоб вибрати пусті блоки.", - "create.schematicAndQuill.abort": "Виділення прибрано.", - "create.schematicAndQuill.title": "Ім'я схематики:", - "create.schematicAndQuill.convert": "Зберегти та розгорнути негайно", - "create.schematicAndQuill.fallbackName": "Моя схематика", - "create.schematicAndQuill.saved": "Збережено як %1$s", - - "create.schematic.invalid": "[!] Неприпустимий предмет — натомість використовуйте схематичний стіл", - "create.schematic.position": "Позизія", - "create.schematic.rotation": "Обертання", - "create.schematic.rotation.none": "Немає", - "create.schematic.rotation.cw90": "За год. стрілкою 90", - "create.schematic.rotation.cw180": "За год. стрілкою 180", - "create.schematic.rotation.cw270": "За год. стрілкою 270", - "create.schematic.mirror": "Відзеркалити", - "create.schematic.mirror.none": "Немає", - "create.schematic.mirror.frontBack": "Спереду-Ззаду", - "create.schematic.mirror.leftRight": "Зліва-Справа", - "create.schematic.tool.deploy": "Розгортання", - "create.schematic.tool.move": "Посунути XZ", - "create.schematic.tool.movey": "Посунути Y", - "create.schematic.tool.rotate": "Обертати", - "create.schematic.tool.print": "Друк", - "create.schematic.tool.flip": "Перевернути", - "create.schematic.tool.deploy.description.0": "Переміщує структуру у локації.", - "create.schematic.tool.deploy.description.1": "Натисніть ПКМ на землі, щоб розмістити.", - "create.schematic.tool.deploy.description.2": "Утримуйте [Ctrl], щоб вибрати фіксовану відстань.", - "create.schematic.tool.deploy.description.3": "[Ctrl] та прокручування, щоб змінити відстань", - "create.schematic.tool.move.description.0": "Зрушити схему по горизонталі.", - "create.schematic.tool.move.description.1": "Наведіть курсор на схему та натисніть [CTRL] та прокрутіть, щоб натиснути на неї.", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "Зсув схеми по вертикалі.", - "create.schematic.tool.movey.description.1": "[CTRL] та прокручування - перемістити вгору/вниз.", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "Обертає схематику навколо її центру.", - "create.schematic.tool.rotate.description.1": "[CTRL] та прокрутка щоб обертати на 90 градусів.", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "Миттєво розміщує структуру у світі.", - "create.schematic.tool.print.description.1": "[ПКМ], щоб підтвердити розміщення у поточному місці.", - "create.schematic.tool.print.description.2": "Цей інструмент призначений лише для творчого режиму.", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "Переверніть схему вздовж обраної сторони.", - "create.schematic.tool.flip.description.1": "Наведіть курсор на схему та [CTRL] + прокручування, щоб перевернути її.", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "Синхронізація...", - "create.schematics.uploadTooLarge": "Ваша схема занадто велика.", - "create.schematics.maxAllowedSize": "Максимальний розмір файла:", - - "create.gui.schematicTable.refresh": "Обновити файли", - "create.gui.schematicTable.open_folder": "Відкрити папку", - "create.gui.schematicTable.title": "Схематичний стіл", - "create.gui.schematicTable.availableSchematics": "Доступні схеми", - "create.gui.schematicTable.noSchematics": "Схеми не збережені", - "create.gui.schematicTable.uploading": "Загрузка...", - "create.gui.schematicTable.finished": "Загрузка завершена!", - "create.gui.schematicannon.title": "Схематична гармата", - "create.gui.schematicannon.listPrinter": "Список матеріалів", - "create.gui.schematicannon.gunpowderLevel": "Порох на %1$s%%", - "create.gui.schematicannon.shotsRemaining": "Пострілів залишилося: %1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "З резервним копіюванням: %1$s", - "create.gui.schematicannon.optionEnabled": "В даний час включено", - "create.gui.schematicannon.optionDisabled": "В даний час виключено", - "create.gui.schematicannon.showOptions": "Показати налаштування друку", - "create.gui.schematicannon.option.dontReplaceSolid": "Не замінювати цілі блоки", - "create.gui.schematicannon.option.replaceWithSolid": "Замінювати цілі блоки цілими блоками", - "create.gui.schematicannon.option.replaceWithAny": "Замінювати цілі блоки чим завгодно", - "create.gui.schematicannon.option.replaceWithEmpty": "Замінювати цілі блоки пустотою", - "create.gui.schematicannon.option.skipMissing": "Пропускати відсутні блоки", - "create.gui.schematicannon.option.skipTileEntities": "Захистити майно", - "create.gui.schematicannon.slot.gunpowder": "Додати порох щоб запитати гармату", - "create.gui.schematicannon.slot.listPrinter": "Покладіть книгу, щоб створити список предметів для схематики", - "create.gui.schematicannon.slot.schematic": "Покладіть власну схематику тут. Переконайтеся, що вона розміщена у правильному місці.", - "create.gui.schematicannon.option.skipMissing.description": "Якщо гармата не може знайти необхідний блок, вона будуватиме в наступному місці.", - "create.gui.schematicannon.option.skipTileEntities.description": "Гармата не замінюватиме блоки зберігання, такі як скрині.", - "create.gui.schematicannon.option.dontReplaceSolid.description": "Гармата ніколи не замінить цілі блоки, тільки не цілі та повітря.", - "create.gui.schematicannon.option.replaceWithSolid.description": "Гармата замінюватиме цілий блок лише у випадку, якщо у схемі в цьому місці розташований цілий блок.", - "create.gui.schematicannon.option.replaceWithAny.description": "Гармата буде замінювати цілі блоки, якщо в схемі є що-небудь.", - "create.gui.schematicannon.option.replaceWithEmpty.description": "Гармата відчистить всі блоки, включаючи заміну повітря.", - - "create.schematicannon.status.idle": "Не діє", - "create.schematicannon.status.ready": "Готова", - "create.schematicannon.status.running": "Працює", - "create.schematicannon.status.finished": "Закінчила", - "create.schematicannon.status.paused": "Припинено", - "create.schematicannon.status.stopped": "Зупинено", - "create.schematicannon.status.noGunpowder": "Потрібен порох", - "create.schematicannon.status.targetNotLoaded": "Ціль не завантажена", - "create.schematicannon.status.targetOutsideRange": "Ціль занадто далеко", - "create.schematicannon.status.searching": "Пошук", - "create.schematicannon.status.skipping": "Пропуск", - "create.schematicannon.status.missingBlock": "Потребує блок:", - "create.schematicannon.status.placing": "Будівництво", - "create.schematicannon.status.clearing": "Очистка блоків", - "create.schematicannon.status.schematicInvalid": "Неправильна схема", - "create.schematicannon.status.schematicNotPlaced": "Схема не завантажена", - "create.schematicannon.status.schematicExpired": "Термін дії файлу схеми минув", - - "create.materialChecklist": "Список матеріалів", - "create.materialChecklist.blocksNotLoaded": "* Дисклеймер *\n\nСписок матеріалів може бути неточним через незавантажені чанки.", - - "create.gui.filter.deny_list": "Чорний список", - "create.gui.filter.deny_list.description": "Предмети проходять, якщо вони не відповідають жодному з перерахованих вище. Порожній чорний список приймає все..", - "create.gui.filter.allow_list": "Білий список", - "create.gui.filter.allow_list.description": "Предмети проходять, якщо вони відповідають будь-якому з перерахованих вище. Порожній білий список відкидає все.", - "create.gui.filter.respect_data": "Використання даних", - "create.gui.filter.respect_data.description": "Предмети збігаються тільки в тому випадку, якщо їхня міцність, чари та інші атрибути збігаються.", - "create.gui.filter.ignore_data": "Ігнорування даних", - "create.gui.filter.ignore_data.description": "Предмети збігаються незалежно від своїх атрибутів.", - - "create.item_attributes.placeable": "Можна розмістити", - "create.item_attributes.placeable.inverted": "не можна розмістити", - "create.item_attributes.consumable": "можна з'їсти", - "create.item_attributes.consumable.inverted": "не можна з'їсти", - "create.item_attributes.fluid_container": "може зберігати рідини", - "create.item_attributes.fluid_container.inverted": "не може зберігати рідини", - "create.item_attributes.enchanted": "зачарований", - "create.item_attributes.enchanted.inverted": "не зачарований", - "create.item_attributes.max_enchanted": "зачаровано на максимальному рівні", - "create.item_attributes.max_enchanted.inverted": "не зачаровано на максимальному рівні", - "create.item_attributes.renamed": "має спеціальну назву", - "create.item_attributes.renamed.inverted": "не має спеціальної назви", - "create.item_attributes.damaged": "пошкоджено", - "create.item_attributes.damaged.inverted": "не пошкоджено", - "create.item_attributes.badly_damaged": "сильно пошкоджений", - "create.item_attributes.badly_damaged.inverted": "не сильно пошкоджений", - "create.item_attributes.not_stackable": "не може складатися", - "create.item_attributes.not_stackable.inverted": "може складатися", - "create.item_attributes.equipable": "може бути одягнений", - "create.item_attributes.equipable.inverted": "не може бути одягнений", - "create.item_attributes.furnace_fuel": "є паливом", - "create.item_attributes.furnace_fuel.inverted": "не є паливом", - "create.item_attributes.washable": "може бути Вимитим", - "create.item_attributes.washable.inverted": "не може бути Вимитим", - "create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted", - "create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted", - "create.item_attributes.crushable": "можна Подрібнити", - "create.item_attributes.crushable.inverted": "не можна Подрібнити", - "create.item_attributes.smeltable": "можна Виплавити", - "create.item_attributes.smeltable.inverted": "не можна Виплавити", - "create.item_attributes.smokable": "можна Коптити", - "create.item_attributes.smokable.inverted": "не можна Коптити", - "create.item_attributes.blastable": "плавиться в Плавильній печі", - "create.item_attributes.blastable.inverted": "не плавиться в Плавильній печі", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "шалкер %1$s", - "create.item_attributes.shulker_level.inverted": "шалкер не %1$s", - "create.item_attributes.shulker_level.full": "повний", - "create.item_attributes.shulker_level.empty": "пустий", - "create.item_attributes.shulker_level.partial": "частично заповнений", - "create.item_attributes.in_tag": "позначено тегами %1$s", - "create.item_attributes.in_tag.inverted": "не позначено тегами %1$s", - "create.item_attributes.in_item_group": "знаходиться в групі '%1$s'", - "create.item_attributes.in_item_group.inverted": "не знаходиться в групі '%1$s'", - "create.item_attributes.added_by": "були добавлені: %1$s", - "create.item_attributes.added_by.inverted": "не були добавлені: %1$s", - "create.item_attributes.has_enchant": "зачарований на %1$s", - "create.item_attributes.has_enchant.inverted": "не зачарований на %1$s", - "create.item_attributes.color": "покрашено в %1$s", - "create.item_attributes.color.inverted": "не покрашено в %1$s", - "create.item_attributes.has_fluid": "містить %1$s", - "create.item_attributes.has_fluid.inverted": "не містить %1$s", - "create.item_attributes.has_name": "має нестандартне ім'я %1$s", - "create.item_attributes.has_name.inverted": "не має нестандарного імені %1$s", - "create.item_attributes.book_author": "підписана %1$s", - "create.item_attributes.book_author.inverted": "не підписана %1$s", - "create.item_attributes.book_copy_original": "оригінал", - "create.item_attributes.book_copy_original.inverted": "не оригінал", - "create.item_attributes.book_copy_first": "копія першого порядку", - "create.item_attributes.book_copy_first.inverted": "не копія першого порядку", - "create.item_attributes.book_copy_second": "копія другого порядку", - "create.item_attributes.book_copy_second.inverted": "не копія другого порядку", - "create.item_attributes.book_copy_tattered": "повний безлад", - "create.item_attributes.book_copy_tattered.inverted": "не повний безлад", - "create.item_attributes.astralsorcery_amulet": "виправляє %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "не виправляє %1$s", - "create.item_attributes.astralsorcery_constellation": "настроено на %1$s", - "create.item_attributes.astralsorcery_constellation.inverted": "не настроено на %1$s", - "create.item_attributes.astralsorcery_crystal": "має характеристики кристала %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "не має характеристики кристала %1$s", - "create.item_attributes.astralsorcery_perk_gem": "має характеристики перку %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "не має характеристики перку %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "Атрибути не вибрані", - "create.gui.attribute_filter.selected_attributes": "Вибрані атрибути:", - "create.gui.attribute_filter.add_attribute": "Добавлені атрибути", - "create.gui.attribute_filter.add_inverted_attribute": "Додані протилежні атрибути до списку", - "create.gui.attribute_filter.allow_list_disjunctive": "Біоий список (Любий)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "Предмети проходять, якщо вони мають будь-який з обраних атрибутів.", - "create.gui.attribute_filter.allow_list_conjunctive": "Білий список (Всі)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "Предмети проходять, тільки якщо вони мають ВСІ вибрані атрибути.", - "create.gui.attribute_filter.deny_list": "Чорний список", - "create.gui.attribute_filter.deny_list.description": "Предмети проходять, якщо вони НЕ мають жодного з вибраних атрибутів.", - "create.gui.attribute_filter.add_reference_item": "Додати предмет", - - "create.tooltip.holdForDescription": "Утримуйте [%1$s] для Зведення", - "create.tooltip.holdForControls": "Утримуйте [%1$s] для Управління", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "Вимога до швидкості: %1$s", - "create.tooltip.speedRequirement.none": "Немає", - "create.tooltip.speedRequirement.slow": "UNLOCALIZED: Slow", - "create.tooltip.speedRequirement.medium": "Помірна", - "create.tooltip.speedRequirement.fast": "UNLOCALIZED: Fast", - "create.tooltip.stressImpact": "Навантаження, що створюється: %1$s", - "create.tooltip.stressImpact.low": "Низька", - "create.tooltip.stressImpact.medium": "Середня", - "create.tooltip.stressImpact.high": "Висока", - "create.tooltip.stressImpact.overstressed": "Перевантаження", - "create.tooltip.up_to": "UNLOCALIZED: Up to %1$s", - "create.tooltip.capacityProvided": "Допустиме навантаження: %1$s", - "create.tooltip.capacityProvided.low": "Маленький", - "create.tooltip.capacityProvided.medium": "Середній", - "create.tooltip.capacityProvided.high": "Великий", - "create.tooltip.generationSpeed": "Створює %1$s %2$s", - "create.tooltip.analogStrength": "Аналогова сила: %1$s/15", - - "create.mechanical_arm.extract_from": "Бере предмети з %1$s", - "create.mechanical_arm.deposit_to": "Складає предмети в %1$s", - "create.mechanical_arm.summary": "Механічна рука має %1$s вход(ів) і %2$s виход(ів).", - "create.mechanical_arm.points_outside_range": "%1$s вибрані точки взаємодії видалені через обмеження діапазону.", - - "create.weighted_ejector.target_set": "Ціль вибрані", - "create.weighted_ejector.target_not_valid": "Кидає до найближчого блоку (Невідповідна Мета)", - "create.weighted_ejector.no_target": "Кидає до найближчого блоку (Ціль не була Вибрана)", - "create.weighted_ejector.targeting": "Кидає до [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "Розмір стака, що кидається.", - - "create.logistics.when_multiple_outputs_available": "Коли доступно кілька виходів", - - "create.mechanical_arm.selection_mode.round_robin": "По колу", - "create.mechanical_arm.selection_mode.forced_round_robin": "Примусово по колу", - "create.mechanical_arm.selection_mode.prefer_first": "Віддавати перевагу первинній цілі", - - "create.tunnel.selection_mode.split": "Розділити", - "create.tunnel.selection_mode.forced_split": "Примусово поділити", - "create.tunnel.selection_mode.round_robin": "По колу", - "create.tunnel.selection_mode.forced_round_robin": "Примусово по колу", - "create.tunnel.selection_mode.prefer_nearest": "Переважно найближче", - "create.tunnel.selection_mode.randomize": "Випадковий", - "create.tunnel.selection_mode.synchronize": "Синхронізувати входи", - - "create.tooltip.chute.header": "Інформація про жолоб", - "create.tooltip.chute.items_move_down": "Предмети рухаються вниз", - "create.tooltip.chute.items_move_up": "Предмети рухаються вверх", - "create.tooltip.chute.no_fans_attached": "Немає підключених вентиляторів", - "create.tooltip.chute.fans_push_up": "Вентилятор штовхає знизу", - "create.tooltip.chute.fans_push_down": "Вентилятор штовхає зверху", - "create.tooltip.chute.fans_pull_up": "Вентилятор тягне зверху", - "create.tooltip.chute.fans_pull_down": "Вентилятор тягне знизу", - "create.tooltip.chute.contains": "Містить: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "На даний момент роздає (видає):", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "ПКМ, щоб отримати", - - "create.linked_controller.bind_mode": "Режим прив'язки активовано", - "create.linked_controller.press_keybind": "Нажміть %1$s, %2$s, %3$s, %4$s, %5$s або %6$s, щоб прив'язати цю частоту до відповідної кнопки", - "create.linked_controller.key_bound": "Частота прив'язана до' %1$s", - "create.linked_controller.frequency_slot_1": "Клавіша: %1$s, Частота #1", - "create.linked_controller.frequency_slot_2": "Клавіша: %1$s, Частота #2", - - "create.crafting_blueprint.crafting_slot": "Слот для інгредієнтів", - "create.crafting_blueprint.filter_items_viable": "Розвинені фільтри предметів застосовні", - "create.crafting_blueprint.display_slot": "Відображувана комірка", - "create.crafting_blueprint.inferred": "Похідні від рецепту", - "create.crafting_blueprint.manually_assigned": "Призначений вручну", - "create.crafting_blueprint.secondary_display_slot": "Додаткова комірка, що відображається", - "create.crafting_blueprint.optional": "Опціональна", - - "create.potato_cannon.ammo.attack_damage": "%1$s Пошкодження від атаки", - "create.potato_cannon.ammo.reload_ticks": "%1$s тіків перезавантаження", - "create.potato_cannon.ammo.knockback": "%1$s відкидання", - - "create.hint.hose_pulley.title": "Безмежне постачання", - "create.hint.hose_pulley": "Цільовий водний резервуар вважається нескінченним.", - "create.hint.mechanical_arm_no_targets.title": "Немає цілей", - "create.hint.mechanical_arm_no_targets": "Здається ця _Механічна_ _Рука_ не має ніяких _цілей._ Виберіть конвеєр, депо, тунель або інші блоки, за допомогою _правою кнопкою миші_ утримуючи _Механічну_ _Руку_ в _руці_.", - "create.hint.empty_bearing.title": "Оновити підшипник", - "create.hint.empty_bearing": "_Права кнопка миші_ по підшипнику _пустою_ _рукою_ щоб _приєднати_ до нього структуру, яку ви щойно збудували перед ним.", - "create.hint.full_deployer.title": "Переполнение автономного активатора", - "create.hint.full_deployer": "Похоже цей _Автономний_ _активатор_ містить _лищні_ _предмети_ які необхідно _вилучити._ Використовуйте _воронку,_ или _інші способи_ to free it from its overflow.", - - "create.backtank.low": "UNLOCALIZED: Backtank pressure low", - "create.backtank.depleted": "UNLOCALIZED: Backtank pressure depleted", - - "create.hint.derailed_train.title": "UNLOCALIZED: Derailed Train", - "create.hint.derailed_train": "UNLOCALIZED: It appears this _Train_ is no longer sitting on a connected track piece. _Right-Click_ using a _wrench_ in order to relocate it to a nearby track.", - - "create.boiler.status": "UNLOCALIZED: Boiler Status: %1$s", - "create.boiler.status_short": "UNLOCALIZED: Boiler: %1$s", - "create.boiler.passive": "UNLOCALIZED: Passive", - "create.boiler.idle": "UNLOCALIZED: Idle", - "create.boiler.lvl": "UNLOCALIZED: Lvl %1$s", - "create.boiler.max_lvl": "UNLOCALIZED: Max", - "create.boiler.size": "UNLOCALIZED: Size", - "create.boiler.size_dots": "UNLOCALIZED: ....... ", - "create.boiler.water": "UNLOCALIZED: Water", - "create.boiler.water_dots": "UNLOCALIZED: ... ", - "create.boiler.heat": "UNLOCALIZED: Heat", - "create.boiler.heat_dots": "UNLOCALIZED: ...... ", - "create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine", - "create.boiler.via_engines": "UNLOCALIZED: via %1$s engines", - - "create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit", - "create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove", - "create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate", - "create.gui.schedule.remove_entry": "UNLOCALIZED: Remove Action", - "create.gui.schedule.add_entry": "UNLOCALIZED: Add Action", - "create.gui.schedule.move_up": "UNLOCALIZED: Move up", - "create.gui.schedule.move_down": "UNLOCALIZED: Move down", - "create.gui.schedule.add_condition": "UNLOCALIZED: Add Condition", - "create.gui.schedule.alternative_condition": "UNLOCALIZED: Alternative Condition", - - "create.schedule.instruction_type": "UNLOCALIZED: Next Action:", - "create.schedule.instruction.editor": "UNLOCALIZED: Instruction Editor", - "create.schedule.instruction.destination": "UNLOCALIZED: Travel to Station", - "create.schedule.instruction.destination.summary": "UNLOCALIZED: Next Stop:", - "create.schedule.instruction.filter_edit_box": "UNLOCALIZED: Station Name", - "create.schedule.instruction.filter_edit_box_1": "UNLOCALIZED: Use * as a text wildcard", - "create.schedule.instruction.filter_edit_box_2": "UNLOCALIZED: Example: 'My Station, Platform *'", - "create.schedule.instruction.filter_edit_box_3": "UNLOCALIZED: Train picks nearest unoccupied match", - "create.schedule.instruction.rename": "UNLOCALIZED: Update Schedule Title", - "create.schedule.instruction.rename.summary": "UNLOCALIZED: New Title:", - "create.schedule.instruction.name_edit_box": "UNLOCALIZED: Schedule Title", - "create.schedule.instruction.name_edit_box_1": "UNLOCALIZED: Affects text shown on displays", - "create.schedule.instruction.name_edit_box_2": "UNLOCALIZED: Defaults to next destination's name", - "create.schedule.instruction.throttle": "UNLOCALIZED: Limit Max Speed", - "create.schedule.instruction.throttle.summary": "UNLOCALIZED: Change Max Speed to %1$s", - "create.schedule.instruction.throttle_edit_box": "UNLOCALIZED: Throttle", - "create.schedule.instruction.throttle_edit_box_1": "UNLOCALIZED: Affects the top speed of the Train", - "create.schedule.condition_type": "UNLOCALIZED: Continue if/after:", - "create.schedule.condition.editor": "UNLOCALIZED: Condition Editor", - "create.schedule.condition.delay": "UNLOCALIZED: Scheduled Delay", - "create.schedule.condition.delay_short": "UNLOCALIZED: Wait: %1$s", - "create.schedule.condition.delay.status": "UNLOCALIZED: Departs in %1$s", - "create.schedule.condition.idle": "UNLOCALIZED: Cargo Inactivity", - "create.schedule.condition.idle_short": "UNLOCALIZED: Cargo Idle: %1$s", - "create.schedule.condition.idle.status": "UNLOCALIZED: Cargo Idle for %1$s", - "create.schedule.condition.for_x_time": "UNLOCALIZED: for %1$s", - "create.schedule.condition.unloaded": "UNLOCALIZED: Chunk Unloaded", - "create.schedule.condition.unloaded.status": "UNLOCALIZED: Waiting for chunk unload", - "create.schedule.condition.powered": "UNLOCALIZED: Station Powered", - "create.schedule.condition.powered.status": "UNLOCALIZED: Waiting for redstone", - "create.schedule.condition.time_of_day": "UNLOCALIZED: Time of Day", - "create.schedule.condition.time_of_day.scheduled": "UNLOCALIZED: Scheduled Time: %1$s", - "create.schedule.condition.time_of_day.digital_format": "UNLOCALIZED: %1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "UNLOCALIZED: Rotation", - "create.schedule.condition.time_of_day.rotation.every_24": "UNLOCALIZED: Every Day", - "create.schedule.condition.time_of_day.rotation.every_12": "UNLOCALIZED: Every 12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "UNLOCALIZED: Every 6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "UNLOCALIZED: Every 4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "UNLOCALIZED: Every 3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "UNLOCALIZED: Every 2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "UNLOCALIZED: Every 1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "UNLOCALIZED: Every 0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "UNLOCALIZED: Every 0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "UNLOCALIZED: Every 0:15", - "create.schedule.condition.time_of_day.status": "UNLOCALIZED: Departs at ", - "create.schedule.condition.threshold.train_holds": "UNLOCALIZED: Train holds %1$s", - "create.schedule.condition.threshold.greater": "UNLOCALIZED: more than", - "create.schedule.condition.threshold.less": "UNLOCALIZED: less than", - "create.schedule.condition.threshold.equal": "UNLOCALIZED: exactly", - "create.schedule.condition.threshold.x_units_of_item": "UNLOCALIZED: %1$s %2$s of %3$s", - "create.schedule.condition.threshold.matching_content": "UNLOCALIZED: Matching Content", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "UNLOCALIZED: Item Measure", - "create.schedule.condition.threshold.items": "UNLOCALIZED: Items", - "create.schedule.condition.threshold.stacks": "UNLOCALIZED: Stacks", - "create.schedule.condition.threshold.buckets": "UNLOCALIZED: Buckets", - "create.schedule.condition.threshold.status": "UNLOCALIZED: Cargo: %1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "UNLOCALIZED: Reference Item", - "create.schedule.condition.threshold.place_item_2": "UNLOCALIZED: Filters can be used", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "UNLOCALIZED: Fluid Cargo Condition", - "create.schedule.condition.item_threshold": "UNLOCALIZED: Item Cargo Condition", - "create.schedule.condition.redstone_link": "UNLOCALIZED: Redstone Link", - "create.schedule.condition.redstone_link.status": "UNLOCALIZED: Waiting for redstone link", - "create.schedule.condition.redstone_link_on": "UNLOCALIZED: Link On", - "create.schedule.condition.redstone_link_off": "UNLOCALIZED: Link Off", - "create.schedule.condition.redstone_link.powered": "UNLOCALIZED: Powered", - "create.schedule.condition.redstone_link.unpowered": "UNLOCALIZED: Not powered", - "create.schedule.condition.redstone_link.frequency_state": "UNLOCALIZED: Frequency state:", - "create.schedule.condition.redstone_link.frequency_powered": "UNLOCALIZED: Frequency powered:", - "create.schedule.condition.redstone_link.frequency_unpowered": "UNLOCALIZED: Frequency not powered:", - "create.schedule.condition.player_count": "UNLOCALIZED: Players Seated", - "create.schedule.condition.player_count.summary": "UNLOCALIZED: %1$s Player", - "create.schedule.condition.player_count.summary_plural": "UNLOCALIZED: %1$s Players", - "create.schedule.condition.player_count.seated": "UNLOCALIZED: %1$s seated", - "create.schedule.condition.player_count.players": "UNLOCALIZED: Players", - "create.schedule.condition.player_count.condition": "UNLOCALIZED: Conditional", - "create.schedule.condition.player_count.exactly": "UNLOCALIZED: Exactly", - "create.schedule.condition.player_count.or_above": "UNLOCALIZED: Or above", - "create.schedule.condition.player_count.status": "UNLOCALIZED: Passengers: %1$s/%2$s", - "create.schedule.loop": "UNLOCALIZED: Loop Forever", - "create.schedule.loop1": "UNLOCALIZED: Schedule starts over", - "create.schedule.loop2": "UNLOCALIZED: when completed", - "create.schedule.reset": "UNLOCALIZED: Reset Progress", - "create.schedule.skip": "UNLOCALIZED: Skip current Stop", - "create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule", - "create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block", - "create.schedule.remove_with_empty_hand": "UNLOCALIZED: Remove current Schedule with an Empty Hand", - "create.schedule.auto_removed_from_train": "UNLOCALIZED: Auto-Schedule discarded", - "create.schedule.removed_from_train": "UNLOCALIZED: Schedule retrieved from Train", - "create.schedule.no_stops": "UNLOCALIZED: This Schedule does not have any Stops yet", - "create.schedule.continued": "UNLOCALIZED: Schedule resumed", - - "create.track.selection_cleared": "UNLOCALIZED: Selection Cleared", - "create.track.valid_connection": "UNLOCALIZED: Can Connect ✔", - "create.track.second_point": "UNLOCALIZED: Place track or select a second point", - "create.track.too_far": "UNLOCALIZED: Too far away", - "create.track.original_missing": "UNLOCALIZED: Original block removed, Sneak-click to reset", - "create.track.perpendicular": "UNLOCALIZED: Cannot connect perpendicularly", - "create.track.ascending_s_curve": "UNLOCALIZED: Cannot create sloped S-Bends", - "create.track.too_sharp": "UNLOCALIZED: Turn too sharp", - "create.track.too_steep": "UNLOCALIZED: Slope too steep", - "create.track.slope_turn": "UNLOCALIZED: Cannot enter or leave slope on a turn", - "create.track.opposing_slopes": "UNLOCALIZED: Cannot connect opposing slopes", - "create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending", - "create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending", - "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", - "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", - "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", - "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", - "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", - - "create.portal_track.failed": "UNLOCALIZED: Cannot place portal track:", - "create.portal_track.missing": "UNLOCALIZED: Target portal not generated yet", - "create.portal_track.blocked": "UNLOCALIZED: Target location blocked (%1$s,%2$s,%3$s)", - - "create.station.idle": "UNLOCALIZED: Station is Idle", - "create.station.assembly_title": "UNLOCALIZED: Train Assembly", - "create.station.close": "UNLOCALIZED: Close Window", - "create.station.cancel": "UNLOCALIZED: Cancel Assembly", - "create.station.failed": "UNLOCALIZED: Assembly Failed", - "create.station.icon_type": "UNLOCALIZED: Icon Type", - "create.station.create_train": "UNLOCALIZED: Create new Train", - "create.station.assemble_train": "UNLOCALIZED: Assemble Train", - "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", - "create.station.remove_schedule": "UNLOCALIZED: Retrieve Schedule", - "create.station.remove_auto_schedule": "UNLOCALIZED: Discard Auto-Schedule", - "create.station.no_assembly_diagonal": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_diagonal_1": "UNLOCALIZED: on diagonal tracks", - "create.station.no_assembly_curve": "UNLOCALIZED: Cannot build trains", - "create.station.no_assembly_curve_1": "UNLOCALIZED: on curved tracks", - "create.station.train_not_aligned": "UNLOCALIZED: Cannot disassemble,", - "create.station.train_not_aligned_1": "UNLOCALIZED: not all carriages aligned", - "create.station.carriage_number": "UNLOCALIZED: Carriage %1$s:", - "create.station.retry": "UNLOCALIZED: Resolve this and retry", - "create.station.no_bogeys": "UNLOCALIZED: No Bogeys", - "create.station.one_bogey": "UNLOCALIZED: 1 Bogey", - "create.station.more_bogeys": "UNLOCALIZED: %1$s Bogeys", - "create.station.how_to": "UNLOCALIZED: Use Train Casing on highlighted Tracks to create bogeys.", - "create.station.how_to_1": "UNLOCALIZED: Remove bogeys by breaking the block on top.", - "create.station.how_to_2": "UNLOCALIZED: Build carriages attached to one or two bogeys each.", - - "create.train_assembly.too_many_bogeys": "UNLOCALIZED: Too many Bogeys attached: %1$s", - "create.train_assembly.frontmost_bogey_at_station": "UNLOCALIZED: Frontmost Bogey must be at Station Marker", - "create.train_assembly.no_bogeys": "UNLOCALIZED: No Bogeys Found", - "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", - "create.train_assembly.bogeys_too_close": "UNLOCALIZED: Bogeys %1$s and %2$s are too close to each other", - "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", - "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", - "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", - "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", - "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", - "create.train_assembly.requires_casing": "UNLOCALIZED: Use Railway Casing to create bogeys on tracks", - - "create.track_target.set": "UNLOCALIZED: Targeted track selected", - "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", - "create.track_target.clear": "UNLOCALIZED: Cleared track selection", - "create.track_target.missing": "UNLOCALIZED: Right-click the targeted train track first", - "create.track_target.too_far": "UNLOCALIZED: Targeted track is too far from here", - "create.track_target.no_junctions": "UNLOCALIZED: Targeted track cannot be an intersection", - "create.track_target.occupied": "UNLOCALIZED: Targeted track is occupied", - "create.track_target.invalid": "UNLOCALIZED: Cannot target this track here", - - "create.train.unnamed": "UNLOCALIZED: Unnamed Train", - "create.train.cannot_relocate_moving": "UNLOCALIZED: Cannot relocate a moving Train", - "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", - "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", - "create.train.relocate.success": "UNLOCALIZED: Relocation successful", - "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm", - "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", - "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", - "create.train.departing_from": "UNLOCALIZED: Departing from %1$s", - "create.train.arrived_at": "UNLOCALIZED: Arrived at %1$s", - "create.train.status": "UNLOCALIZED: Information about Train: %1$s", - "create.train.status.back_on_track": "UNLOCALIZED: Train is back on Track", - "create.train.status.collision": "UNLOCALIZED: Collision with other Train", - "create.train.status.end_of_track": "UNLOCALIZED: A Carriage has reached the end of its Track", - "create.train.status.double_portal": "UNLOCALIZED: A Carriage cannot enter a portal whilst leaving another", - "create.train.status.coupling_stress": "UNLOCALIZED: Forced stop due to Stress on Couplings", - "create.train.status.track_missing": "UNLOCALIZED: Tracks are missing beneath the Train", - "create.train.status.paused_for_manual": "UNLOCALIZED: Schedule paused for manual controls", - "create.train.status.opposite_driver": "UNLOCALIZED: Path requires a driver facing the opposite direction", - "create.train.status.missing_driver": "UNLOCALIZED: Driver has gone missing", - "create.train.status.found_driver": "UNLOCALIZED: A new driver has been found", - "create.train.status.navigation_success": "UNLOCALIZED: Navigation succeeded", - "create.train.status.no_match": "UNLOCALIZED: No station on graph matches '%1$s'", - "create.train.status.no_path": "UNLOCALIZED: No suitable path to the next Scheduled destination could be found", - - "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", - "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", - "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", - - "create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s", - "create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption", - "create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s", - - "create.display_link.set": "UNLOCALIZED: Targeted position selected", - "create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position", - "create.display_link.clear": "UNLOCALIZED: Cleared position selection", - "create.display_link.too_far": "UNLOCALIZED: Targeted position is too far from here", - "create.display_link.invalid": "UNLOCALIZED: Link has no valid target, try placing it again", - "create.display_link.title": "UNLOCALIZED: Display Link", - "create.display_link.no_source": "UNLOCALIZED: Not a Display Source", - "create.display_link.no_target": "UNLOCALIZED: Not a Display Target", - "create.display_link.reading_from": "UNLOCALIZED: Read from:", - "create.display_link.writing_to": "UNLOCALIZED: Send to:", - "create.display_link.attached_side": "UNLOCALIZED: Block on attached side", - "create.display_link.targeted_location": "UNLOCALIZED: Block in targeted location", - "create.display_link.view_compatible": "UNLOCALIZED: Click to view all Compatible", - "create.display_link.information_type": "UNLOCALIZED: Type of Information", - "create.display_link.display_on": "UNLOCALIZED: Write data to:", - "create.display_link.display_on_multiline": "UNLOCALIZED: Start writing at:", - - "create.display_source.label": "UNLOCALIZED: Attached Label", - "create.display_source.combine_item_names": "UNLOCALIZED: Combine Item Names", - "create.display_source.count_items": "UNLOCALIZED: Amount of matching Items", - "create.display_source.list_items": "UNLOCALIZED: List matching Items", - "create.display_source.fluid_amount": "UNLOCALIZED: Amount of matching Fluids", - "create.display_source.list_fluids": "UNLOCALIZED: List matching Fluids", - "create.display_source.nixie_tube": "UNLOCALIZED: Copy Nixie Tubes", - "create.display_source.fill_level": "UNLOCALIZED: Container Fill Level", - "create.display_source.fill_level.display": "UNLOCALIZED: Display Format", - "create.display_source.fill_level.percent": "UNLOCALIZED: Percent", - "create.display_source.fill_level.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.value_list.display": "UNLOCALIZED: Value Display", - "create.display_source.value_list.shortened": "UNLOCALIZED: Shortened", - "create.display_source.value_list.full_number": "UNLOCALIZED: Full Number", - "create.display_source.value_list.thousand": "UNLOCALIZED: k", - "create.display_source.value_list.million": "UNLOCALIZED: m", - "create.display_source.player_deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.scoreboard": "UNLOCALIZED: Scoreboard", - "create.display_source.scoreboard.objective": "UNLOCALIZED: Objective ID", - "create.display_source.scoreboard.objective_not_found": "UNLOCALIZED: '%1$s' not found", - "create.display_source.scoreboard.objective.deaths": "UNLOCALIZED: Player Deaths", - "create.display_source.time_of_day": "UNLOCALIZED: Time of Day", - "create.display_source.stop_watch": "UNLOCALIZED: Stopwatch", - "create.display_source.time.format": "UNLOCALIZED: Time Format", - "create.display_source.time.12_hour": "UNLOCALIZED: 12-hour", - "create.display_source.time.24_hour": "UNLOCALIZED: 24-hour", - "create.display_source.accumulate_items": "UNLOCALIZED: Accumulate Item Count", - "create.display_source.item_throughput": "UNLOCALIZED: Item Throughput", - "create.display_source.item_throughput.interval": "UNLOCALIZED: Interval", - "create.display_source.item_throughput.interval.second": "UNLOCALIZED: per Second", - "create.display_source.item_throughput.interval.minute": "UNLOCALIZED: per Minute", - "create.display_source.item_throughput.interval.hour": "UNLOCALIZED: per Hour", - "create.display_source.train_status": "UNLOCALIZED: Train Schedule Status", - "create.display_source.station_summary": "UNLOCALIZED: Train Station Summary", - "create.display_source.station_summary.filter": "UNLOCALIZED: Station name filter", - "create.display_source.station_summary.train_name_column": "UNLOCALIZED: Train column size", - "create.display_source.station_summary.platform_column": "UNLOCALIZED: Platform column size", - "create.display_source.station_summary.now": "UNLOCALIZED: now", - "create.display_source.station_summary.minutes": "UNLOCALIZED: min", - "create.display_source.station_summary.seconds": "UNLOCALIZED: %1$ss", - "create.display_source.observed_train_name": "UNLOCALIZED: Detected Train Name", - "create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost", - "create.display_source.boiler_status": "UNLOCALIZED: Boiler Status", - "create.display_source.entity_name": "UNLOCALIZED: Entity Name", - "create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)", - "create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction", - "create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction", - "create.display_source.kinetic_stress": "UNLOCALIZED: Network Stress", - "create.display_source.kinetic_stress.display": "UNLOCALIZED: Displayed Info", - "create.display_source.kinetic_stress.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.kinetic_stress.percent": "UNLOCALIZED: Percentage", - "create.display_source.kinetic_stress.current": "UNLOCALIZED: Stress in SU", - "create.display_source.kinetic_stress.max": "UNLOCALIZED: Total Capacity", - "create.display_source.kinetic_stress.remaining": "UNLOCALIZED: Remaining SU", - "create.display_source.redstone_power": "UNLOCALIZED: Redstone Power", - "create.display_source.redstone_power.display": "UNLOCALIZED: Display Format", - "create.display_source.redstone_power.number": "UNLOCALIZED: Number", - "create.display_source.redstone_power.progress_bar": "UNLOCALIZED: Progress Bar", - "create.display_source.boiler.not_enough_space": "UNLOCALIZED: Not enough space ", - "create.display_source.boiler.for_boiler_status": "UNLOCALIZED: for Boiler Status", - - "create.display_target.line": "UNLOCALIZED: Line %1$s", - "create.display_target.page": "UNLOCALIZED: Page %1$s", - "create.display_target.single_line": "UNLOCALIZED: Single Line", - - "create.flap_display.cycles.alphabet": "UNLOCALIZED: ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": "UNLOCALIZED: ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": "UNLOCALIZED: ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": "UNLOCALIZED: ;K;M", - "create.flap_display.cycles.fluid_units": "UNLOCALIZED: mB;B ", - "create.flap_display.cycles.instant": "UNLOCALIZED: ; ", - "create.flap_display.cycles.pixel": "UNLOCALIZED: █;▓;▒", - - "create.super_glue.too_far": "UNLOCALIZED: Selected area is too big", - "create.super_glue.cannot_reach": "UNLOCALIZED: Selected blocks must be connected", - "create.super_glue.click_to_confirm": "UNLOCALIZED: Click again to confirm", - "create.super_glue.click_to_discard": "UNLOCALIZED: Sneak-click to discard selection", - "create.super_glue.first_pos": "UNLOCALIZED: First position selected", - "create.super_glue.abort": "UNLOCALIZED: Selection discarded", - "create.super_glue.not_enough": "UNLOCALIZED: Not enough glue in inventory", - "create.super_glue.success": "UNLOCALIZED: Applying Glue...", - - "create.gui.config.overlay1": "Привіт :)", - "create.gui.config.overlay2": "Це зразок оверлея", - "create.gui.config.overlay3": "Клацніть та тягни за допомогою миші", - "create.gui.config.overlay4": "щоб перемістити його", - "create.gui.config.overlay5": "Нажіміть ESC щоб вийти", - "create.gui.config.overlay6": "або зберегти нову позицію", - "create.gui.config.overlay7": "Введи /create overlay reset", - "create.gui.config.overlay8": "щоб скинути позицію до стандартної", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Тіки сервера в даний час уповільнені на %s мс :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Тіки сервера тепер уповільнені на %s мс >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Тіки сервера повернулися в норму :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: використовуйте /killtps stop щоб повернути тик сервера на звичайну швидкість", - "create.command.killTPSCommand.status.usage.1": "[Create]: використовуйте /killtps start щоб штучно уповільнити тік сервера", - "create.command.killTPSCommand.argument.tickTime": "Час тіку", - - "create.contraption.minecart_contraption_too_big": "Ця вагонеткова штуковина здається занадто великою, щоб її можна було підняти", - "create.contraption.minecart_contraption_illegal_pickup": "Містична сила пов'язує цю вагонеткову штуковину зі світом", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "Штуковина зупиняється", - "create.subtitle.peculiar_bell_use": "Дивний дзвін дзвонить", - "create.subtitle.worldshaper_place": "Ручний редактор світу робить «Зап»", - "create.subtitle.whistle_train_manual": "UNLOCALIZED: Train honks", - "create.subtitle.steam": "UNLOCALIZED: Steam noises", - "create.subtitle.saw_activate_stone": "Активується механічна пила", - "create.subtitle.schematicannon_finish": "Схематична гармата закінчила роботу", - "create.subtitle.crafter_craft": "Крафтер створює", - "create.subtitle.wrench_remove": "Компонент ламається", - "create.subtitle.train3": "UNLOCALIZED: Bogey wheels rumble muffled", - "create.subtitle.whistle": "UNLOCALIZED: Whistling", - "create.subtitle.cogs": "Шестерні гуркочуть", - "create.subtitle.slime_added": "Намазування слизу", - "create.subtitle.whistle_train_low": "UNLOCALIZED: Low whistling", - "create.subtitle.schematicannon_launch_block": "Постріли схематичної гармати", - "create.subtitle.controller_take": "Кафедра спустошується", - "create.subtitle.crafter_click": "Крафтер клікає", - "create.subtitle.depot_plop": "Предмет падає", - "create.subtitle.confirm": "Стверджувальний «Дінь»", - "create.subtitle.mixing": "Шум змішування", - "create.subtitle.mechanical_press_activation_belt": "Механічний прес робить«боньк» ", - "create.subtitle.fwoomp": "Картопельна гармата робить «Свомп»»", - "create.subtitle.sanding_long": "UNLOCALIZED: Sanding noises", - "create.subtitle.crushing_1": "Шум руйнування", - "create.subtitle.depot_slide": "Шелест предметів", - "create.subtitle.blaze_munch": "Блейз радісно жує", - "create.subtitle.funnel_flap": "Фіранки воронок ляскають", - "create.subtitle.haunted_bell_use": "Примарний дзвін дзвонить", - "create.subtitle.scroll_value": "Клацання колеса прокручування", - "create.subtitle.controller_put": "Контролер стукає", - "create.subtitle.cranking": "Обертається рукоятка", - "create.subtitle.sanding_short": "UNLOCALIZED: Sanding noises", - "create.subtitle.wrench_rotate": "Використано гайковий ключ", - "create.subtitle.potato_hit": "Овочі врізаються", - "create.subtitle.saw_activate_wood": "Активується Механічна пила", - "create.subtitle.whistle_high": "UNLOCALIZED: High whistling", - "create.subtitle.whistle_train_manual_low": "UNLOCALIZED: Train honks", - "create.subtitle.whistle_train": "UNLOCALIZED: Whistling", - "create.subtitle.haunted_bell_convert": "Примарний дзвін прокидається", - "create.subtitle.train": "UNLOCALIZED: Bogey wheels rumble", - "create.subtitle.deny": "Від'ємний «Буп»", - "create.subtitle.controller_click": "Кліки контролера", - "create.subtitle.whistle_low": "UNLOCALIZED: Low whistling", - "create.subtitle.copper_armor_equip": "Дзвінкування спорядження для дайвінгу", - "create.subtitle.mechanical_press_activation": "Механічний прес активовано", - "create.subtitle.contraption_assemble": "Штуковина рухається", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "ПРИКЛАД ПРЕДМЕТА (лише маркер того, що ця підказка існує)", - "item.create.example_item.tooltip.summary": "Короткий опис предмета. _Підкреслення_ виділяють слово.", - "item.create.example_item.tooltip.condition1": "Коли це", - "item.create.example_item.tooltip.behaviour1": "Тоді цей предмет робить це. (поведінка показує на зміну)", - "item.create.example_item.tooltip.condition2": "І коли це", - "item.create.example_item.tooltip.behaviour2": "Ви можете додати скільки завгодно способів поведінки", - "item.create.example_item.tooltip.control1": "При натисканні Ctrl", - "item.create.example_item.tooltip.action1": "Відображаються ці елементи керування.", - - "block.create.wooden_bracket.tooltip": "ДЕРЕВ'ЯНА СКОБА", - "block.create.wooden_bracket.tooltip.summary": "_Прикраште_ ваші _вали, _шестерні_ і _труби_ використовуючи затишне дерев'яне укріплення.", - - "block.create.metal_bracket.tooltip": "МЕТАЛІЧНА СКОБА", - "block.create.metal_bracket.tooltip.summary": "_Прикраште_ your ваші _Вали, _Шестерні_ і _Труби_ використовуючи міцне індустріальне зміцнення.", - - "block.create.seat.tooltip": "СІДЛО", - "block.create.seat.tooltip.summary": "Сідайте і насолоджуйтеся поїздкою! Прив'язує гравців до зібраних _пристроям_. Відмінно виглядають як прості меблі! Можна пофарбувати у різні кольори.", - "block.create.seat.tooltip.condition1": "ПКМ по сидінню", - "block.create.seat.tooltip.behaviour1": "Садить гравця на _Сідло_. Нажміть L-shift щоб злізти з _Сідло_.", - - "item.create.blaze_cake.tooltip": "ТОРТ «ВОГНЯНИЙ»", - "item.create.blaze_cake.tooltip.summary": "Смачне частування для вашої трудяги _Пальник брейза_. Запалює їх усіх!", - - "item.create.wand_of_symmetry.tooltip": "ПАЛИЦЯ СИМЕТРІЇ", - "item.create.wand_of_symmetry.tooltip.summary": "Ідеально відзеркалює блоки, що розміщуються за налаштованими площинами.", - "item.create.wand_of_symmetry.tooltip.condition1": "На панелі щвидкого доступу", - "item.create.wand_of_symmetry.tooltip.behaviour1": "Залишається активним", - "item.create.wand_of_symmetry.tooltip.control1": "ПКМ по землі", - "item.create.wand_of_symmetry.tooltip.action1": "_Створює_ або _Передміщає_ зеркало", - "item.create.wand_of_symmetry.tooltip.control2": "ПКМ по повітрю", - "item.create.wand_of_symmetry.tooltip.action2": "_Забирає_ зеркало", - "item.create.wand_of_symmetry.tooltip.control3": "ПКМ крадькома", - "item.create.wand_of_symmetry.tooltip.action3": "Відкриває _Інтерфейс конфігурації_", - - "item.create.handheld_worldshaper.tooltip": "РУЧНИЙ РЕДАКТОР СВІТУ", - "item.create.handheld_worldshaper.tooltip.summary": "Зручний інструмент для створення _ландшафтів_ і _рельєфу місцевості_.", - "item.create.handheld_worldshaper.tooltip.control1": "ЛКМ по блоку", - "item.create.handheld_worldshaper.tooltip.action1": "Встановлює блоки, поміщені в інструмент, у цільовий блок.", - "item.create.handheld_worldshaper.tooltip.control2": "ПКМ по блоку", - "item.create.handheld_worldshaper.tooltip.action2": "Застосовує вибрану _Пензлик_ і _Інструмент_ в вибраному місці.", - "item.create.handheld_worldshaper.tooltip.control3": "ПКМ крадькома", - "item.create.handheld_worldshaper.tooltip.action3": "Відкриває _Інтерфейс конфігурації_", - - "item.create.tree_fertilizer.tooltip": "ПОДОБРЕННЯ ДЛЯ ДЕРЕВ", - "item.create.tree_fertilizer.tooltip.summary": "Потужна комбінація мінералів підходить для прискорення зростання поширених типів дерев.", - "item.create.tree_fertilizer.tooltip.condition1": "При використанні на Саджанці", - "item.create.tree_fertilizer.tooltip.behaviour1": "Вирощує дерева _rнезадежно_ від _умов розміщення_", - - "item.create.extendo_grip.tooltip": "ДОВГА РУКА", - "item.create.extendo_grip.tooltip.summary": "Бойойоїнг! Значно _збільшує досяжність_ власника. Може працювати за допомогою тиску повітря від _Мідного балону_", - "item.create.extendo_grip.tooltip.condition1": "Перебуваючи в іншій руці", - "item.create.extendo_grip.tooltip.behaviour1": "Збільшує _збільшує досяжність_ предметів, що використовуються в _Головній руці_.", - "item.create.extendo_grip.tooltip.condition2": "Коли одягнений Мідний балон", - "item.create.extendo_grip.tooltip.behaviour2": "_Не_ тратиться _Міцність_. Натомість буде витрачатися _Повітря_ з балону", - - "item.create.potato_cannon.tooltip": "КАРТОПЛЯНА ГРАМАТА", - "item.create.potato_cannon.tooltip.summary": "Свомп! Запускайте вирощені вами овочі у своїх ворогів. Може працювати від тиску повітря з _Мідного балону_", - "item.create.potato_cannon.tooltip.condition1": "Натискаючи ПКМ", - "item.create.potato_cannon.tooltip.behaviour1": "_Вистрілює_ відповідним предметом з вашого _інвентара_.", - "item.create.potato_cannon.tooltip.condition2": "Коли одягнений Мідний балон", - "item.create.potato_cannon.tooltip.behaviour2": "_Не_ тратиться _Міцність_. Натомість буде витрачатися _Повітря_ з балону", - - "item.create.filter.tooltip": "ФІЛЬТР", - "item.create.filter.tooltip.summary": "_Керує виходами_ і _входами_ логістичних пристроїв з _більшою точністю_, _зіставляючи_ їх зі _списком предметів_ або кількома _вкладеними фільтрами_.", - "item.create.filter.tooltip.condition1": "Коли в слоті фільтра", - "item.create.filter.tooltip.behaviour1": "_Керує_ потоком предметів відповідно до його _Конфігурації_.", - "item.create.filter.tooltip.condition2": "Коли ПКМ", - "item.create.filter.tooltip.behaviour2": "Відкриває _інтерфейс конфігурації_.", - - "item.create.attribute_filter.tooltip": "ФІЛЬТР АТРИБУТІВ", - "item.create.attribute_filter.tooltip.summary": "_Керує виходами_ і _входами_ логістичних пристроїв з більшою _точністю_, зіставлення їх із a _набором_ предметних _атрибутів_ і _категорій_.", - "item.create.attribute_filter.tooltip.condition1": "Коли в слоті фільтра", - "item.create.attribute_filter.tooltip.behaviour1": "_Керує_ потоком предметів відповідно до його _Конфігурації_.", - "item.create.attribute_filter.tooltip.condition2": "Коли ПКМ", - "item.create.attribute_filter.tooltip.behaviour2": "Відкриває _інтерфейс конфігурації_.", - - "item.create.empty_schematic.tooltip": "ПУСТА СХЕМАТИКА", - "item.create.empty_schematic.tooltip.summary": "Використовується як інгредієнт рецепту і для запису в _Схематичному столі_.", - - "item.create.schematic.tooltip": "СХЕМАТИКА", - "item.create.schematic.tooltip.summary": "Містить структуру, яка позиціонуватиметься і поміщатиметься у світ. Розташуйте голограму на свій розсуд і використовуйте _схематичну гармату_ для її побудови.", - "item.create.schematic.tooltip.condition1": "При утриманні", - "item.create.schematic.tooltip.behaviour1": "Може бути позиціонований за допомогою інструментів на екрані.", - "item.create.schematic.tooltip.control1": "ПКМ крадькома", - "item.create.schematic.tooltip.action1": "Відкриває _інтерфейс_ для введення _точних координат_.", - - "item.create.schematic_and_quill.tooltip": "СХЕМАТИКА І ПЕРО", - "item.create.schematic_and_quill.tooltip.summary": "Використовується для збереження структури у вашому світі у файл .nbt.", - "item.create.schematic_and_quill.tooltip.condition1": "Крок 1", - "item.create.schematic_and_quill.tooltip.behaviour1": "Виберіть дві кутові точки за допомогою ПКМ..", - "item.create.schematic_and_quill.tooltip.condition2": "Крок 2", - "item.create.schematic_and_quill.tooltip.behaviour2": "_Ctrl та прокручування_ на голограмі для зміни розміру. Натисніть ПКМ, щоб зберегти.", - "item.create.schematic_and_quill.tooltip.control1": "ПКМ", - "item.create.schematic_and_quill.tooltip.action1": "Виберіть кутові точки / підтвердіть збереження.", - "item.create.schematic_and_quill.tooltip.control2": "Утримуйте Ctrl", - "item.create.schematic_and_quill.tooltip.action2": "Виберіть точки в _повітрі_. _Прокрутка_ для настройки дистанції.", - "item.create.schematic_and_quill.tooltip.control3": "ПКМ крадькомаg", - "item.create.schematic_and_quill.tooltip.action3": "_Скидує_ і _видаляє_ виділення.", - - "block.create.schematicannon.tooltip": "СХЕМАТИЧНА ГАРРМАТА", - "block.create.schematicannon.tooltip.summary": "_Ставить блоки_ для відтворення _схематики_ у світі. Використовує предмети з _сусіднього інвентаря_ і _порох_ як _паливо_.", - "block.create.schematicannon.tooltip.condition1": "ПКМ", - "block.create.schematicannon.tooltip.behaviour1": "Відкриває _Інтерфейс_", - - "block.create.schematic_table.tooltip": "СХЕМАТИЧНИЙ СТІЛ", - "block.create.schematic_table.tooltip.summary": "Записує збережені схематики в _Пусті схематики_.", - "block.create.schematic_table.tooltip.condition1": "Коли дана схема порожня", - "block.create.schematic_table.tooltip.behaviour1": "Завантажує вибраний файл із папки Schematics.", - - "item.create.goggles.tooltip": "ІНЖЕНЕРНІ ОКУЛЯРИ", - "item.create.goggles.tooltip.summary": "Окуляри для покращення зору за допомогою корисної _кінетичної інформації_.", - "item.create.goggles.tooltip.condition1": "Коли одіто", - "item.create.goggles.tooltip.behaviour1": "Показує _кольорові індикатори_ відповідно _рівню швидкості_ розміщеного кінетичного компонента, а також _створюваному навантаженні_ і _потужності_ окремих компонентів.", - "item.create.goggles.tooltip.condition2": "При погляді на датчик", - "item.create.goggles.tooltip.behaviour2": "Показує детальну інформацію про _швидкість_ або _навантаження_ мережі, до якої підключено датчик.", - "item.create.goggles.tooltip.condition3": "При погляді на рідинні контейнери", - "item.create.goggles.tooltip.behaviour3": "Показує детальну інформацію про _МІсткість_ блоку і про _Рідини_ які в ньому зберігаються.", - - "item.create.wrench.tooltip": "ГАЙКОВИЙ КЛЮЧ", - "item.create.wrench.tooltip.summary": "Корисний інструмент для роботи з кінетичними пристосуваннями. Може використовуватись для _оберту_, _демонтажа_ та to _настройки_ каомпонентів.", - "item.create.wrench.tooltip.control1": "ПКМ по кінетичному блоку", - "item.create.wrench.tooltip.action1": "_Повертає компонент_ у бік або від обличчя, з яким ви взаємодіяли.", - "item.create.wrench.tooltip.control2": "ПКМ крадькома", - "item.create.wrench.tooltip.action2": "_Розбирає кінетичні компоненти_ і розміщує їх назад в _ваш інвентар_.", - - "block.create.nozzle.tooltip": "НАСАДКА", - "block.create.nozzle.tooltip.summary": "Прикріпіть до передньої частини _Вентилятора у корпусіn_щоб розподілити його вплив на Сутності в _всіх напрямах_.", - - "block.create.cuckoo_clock.tooltip": "ГОДИННИК З ЗОЗУЛЕЮ", - "block.create.cuckoo_clock.tooltip.summary": "Прекрасна майстерність для _дукорування_ простору і _відстеження часу_.", - "block.create.cuckoo_clock.tooltip.condition1": "При обертанні", - "block.create.cuckoo_clock.tooltip.behaviour1": "Показує _поточний час_ і грає мелодію двічі на день. _Активується_ один раз в _полудні_ і у сутінках, як тільки _гравець може спати_.", - - "block.create.turntable.tooltip": "ПОВОРОТНИЙ СТІЛ", - "block.create.turntable.tooltip.summary": "Повертає _силу обертання_ у вишукану морську хворобу.", - - "block.create.toolbox.tooltip": "ЯЩИК ДЛЯ ІНСТРУМЕНТІВ", - "block.create.toolbox.tooltip.summary": "Найдорожчий супутник кожного винахідника. Зручно _зберігає_ велику кількість _восьми різних_ типів предметів.", - "block.create.toolbox.tooltip.condition1": "Коли підібрано", - "block.create.toolbox.tooltip.behaviour1": "_Зберігає вміст_ Інвентарю.", - "block.create.toolbox.tooltip.condition2": "При розміщенні в діапазоні", - "block.create.toolbox.tooltip.behaviour2": "_Найближчі гравці_ можуть тримати _клавішу ящику для інструментів_, щоб отримати доступ до його вмісту _Дистанційно_.", - "block.create.toolbox.tooltip.condition3": "При клацанні ПКМ", - "block.create.toolbox.tooltip.behaviour3": "Відкриває _Інтерфейс контейнеру_.", - - "block.create.stockpile_switch.tooltip": "НАСТРОЄНИЙ КОМПАРАТОР", - "block.create.stockpile_switch.tooltip.summary": "Перемикає сигнал редстоуну залежно від кількості _Збережених предметів_ чи _Рідин_ у доданому контейнері. У комплект входить зручний фільтр. На відміну від a _Редстоунового Компаратора,_ _Настроєний компаратор_ дозволяє конфігурувати _поріг,_ при якому сигнали інвертуються.", - "block.create.stockpile_switch.tooltip.condition1": "При клацанні ПКМ", - "block.create.stockpile_switch.tooltip.behaviour1": "Відкриває _Інтерфейс конфігурації_.", - - "block.create.content_observer.tooltip": "CСПОСТЕРІГАЧ ВМІСТУ", - "block.create.content_observer.tooltip.summary": "_Розпізнає Предмети_ або _Рідини_ всередині _контейнерів_, _труб_ чи _конвеєрів_ відповідно налаштованому _фільтру_.", - "block.create.content_observer.tooltip.condition1": "При спостереженні за контейнером", - "block.create.content_observer.tooltip.behaviour1": "Випромінює _Редстоун сигнал_ коли спостережуваний контейнер має _відповідний вміст_.", - "block.create.content_observer.tooltip.condition2": "При спостереженні за Воронкою", - "block.create.content_observer.tooltip.behaviour2": "Випромінює _Імпульс редстоуну_ коли _відповідний_ предмет _передається_.", - - "block.create.creative_crate.tooltip": "ТВОРЧИЙ ЯЩИК", - "block.create.creative_crate.tooltip.summary": "Цей _Контейнер для зберігання_ дозволяє нескінченно копіювати будь-який елемент. Розмістіть поруч із _Схематичною гарматою_, щоб видалити будь-які вимоги до матеріалів.", - "block.create.creative_crate.tooltip.condition1": "Коли предмет в Слоті для Фільтра", - "block.create.creative_crate.tooltip.behaviour1": "Усе, що _витягується_ з цього контейнера, забезпечить _нескінченну поставку_ зазначеного елемента. Предмети, _вставлені_ в цей ящик, будуть _анульовані_.", - - "item.create.creative_blaze_cake.tooltip": "ТВОРЧИЙ «ВОГНЯНИЙ» ТОРТ", - "item.create.creative_blaze_cake.tooltip.summary": "Дуже особливе задоволення для _Пальника блейза_, котре дозволяє контролювати рівень їх нагріву. Після того, з’їдання цього пиріга, у _Пальника блейза_ _ніколи не закінчиться паливо_.", - "item.create.creative_blaze_cake.tooltip.condition1": "При клацанні ПКМ по Пальнику блейза", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_Блокує_ рівень нагрівання Пальника блейза. У разі повторного використання _циклує_ рівень нагрівання Пальника блейза.", - - "block.create.controller_rail.tooltip": "КОНТРОЛЕРНА РЕЙКА", - "block.create.controller_rail.tooltip.summary": "_Односпрямована рейка з електроприводом, здатна _точно контролювати швидкість руху вагонеток.", - "block.create.controller_rail.tooltip.condition1": "Коли живиться від Редстоуну", - "block.create.controller_rail.tooltip.behaviour1": "_Прискорює_ або _Сповільнює_ проходження _вагонеток_ відповідно до _потужності_ сигналу. Поширює потужність червоного каменю на сусідні рейки контролера. Живлення двох рейок контролера з різною потужністю призведе до інтерполяції сигналу на доріжках між ними.", - - "item.create.sand_paper.tooltip": "НАЖДАЧНИЙ ПАПІР", - "item.create.sand_paper.tooltip.summary": "Грубий папір, який можна використовувати для _полірування матеріалів_. Може застосовуватися автоматично за допомогою Автономний активатор.", - "item.create.sand_paper.tooltip.condition1": "При використанні", - "item.create.sand_paper.tooltip.behaviour1": "Полірує предмети у _другій руці_, або лежачі _на підлозі_, якщо _подивитися на них_", - - "item.create.builders_tea.tooltip": "ЧАЙ БУДІВЕЛТНИКА", - "item.create.builders_tea.tooltip.summary": "Ідеальний напіток для початку дня. _Мотивує_ і _Насищає_", - - "item.create.refined_radiance.tooltip": "ВИШУКАНЕ СЯЙВО", - "item.create.refined_radiance.tooltip.summary": "Хроматичний матеріал, _добутий з поглиненого світла_.", - "item.create.refined_radiance.tooltip.condition1": "Робота в процесі", - "item.create.refined_radiance.tooltip.behaviour1": "Використання цього матеріалу буде доступним у майбутніх оновленнях.", - - "item.create.shadow_steel.tooltip": "ТІНЬОВА СТАЛЬ", - "item.create.shadow_steel.tooltip.summary": "Хроматичний матеріал, _добутий в пустоті_.", - "item.create.shadow_steel.tooltip.condition1": "Робота в процесі", - "item.create.shadow_steel.tooltip.behaviour1": "Використання цього матеріалу буде доступним у майбутніх оновленнях.", - - "item.create.linked_controller.tooltip": "ПІДКЛЮЧЕНИЙ КОНТРОЛЕР", - "item.create.linked_controller.tooltip.summary": "Надає _ручний контроль_ над частотами _Бездротового передавача редстоун сигналу_, присвоєні його _шести_ кнопкам.", - "item.create.linked_controller.tooltip.condition1": "ПКМ", - "item.create.linked_controller.tooltip.behaviour1": "Вмикає контролер. _Управління рухом_ перехоплено, доки він активний.", - "item.create.linked_controller.tooltip.condition2": "ПКМ крадьдома", - "item.create.linked_controller.tooltip.behaviour2": "Відкриває ручний _Інтерфейс конфігурації_.", - "item.create.linked_controller.tooltip.condition3": "ПКМ по приймачеві сигналу редстоуна", - "item.create.linked_controller.tooltip.behaviour3": "Включає _режим прив'язки_, натисніть одну з _шести кнопок_, щоб прив'язати його до _частоти передавача_.", - "item.create.linked_controller.tooltip.condition4": "ПКМ по Аналою", - "item.create.linked_controller.tooltip.behaviour4": "Поміщає контролер на Аналой для зручності використання. (ПКМ крадучись, щоб забрати його)", - - "item.create.diving_helmet.tooltip": "ШОЛОМ ДЛЯ ДАЙВІНГУ", - "item.create.diving_helmet.tooltip.summary": "Разом з _Мідним балоном_, дозволяє володарю _дихати під водою_ протягом тривалого періоду часу.", - "item.create.diving_helmet.tooltip.condition1": "При носінні", - "item.create.diving_helmet.tooltip.behaviour1": "Дає ефект _Водяного Дихання_, повільно витрачаючи _повітря_ з балона.", - - "item.create.copper_backtank.tooltip": "МІДНИЙ БАЛОН", - "item.create.copper_backtank.tooltip.summary": "_Носити резервуар_ для транспортування повітря під тиском.", - "item.create.copper_backtank.tooltip.condition1": "При носінні", - "item.create.copper_backtank.tooltip.behaviour1": "Забезпечує подачу _повітря_ під _тиском_ до обладнання, яке цього потребує.", - "item.create.copper_backtank.tooltip.condition2": "При розміщенні та живленні від кінетичної енергії", - "item.create.copper_backtank.tooltip.behaviour2": "_Збирає та стискає повітря_ зі швидкістю, яка залежить від швидкості обертання_.", - - "block.create.placard.tooltip": "UNLOCALIZED: PLACARD", - "block.create.placard.tooltip.summary": "UNLOCALIZED: _Frame_ your _items_ in brass using this fancy wall panel. Safe for contraptions!", - "block.create.placard.tooltip.condition1": "UNLOCALIZED: When R-Clicked with Item", - "block.create.placard.tooltip.behaviour1": "UNLOCALIZED: _Adds_ the held _item_ to the Placard. _Emits_ a brief _Redstone_ signal if a matching item was present already.", - "block.create.placard.tooltip.condition2": "UNLOCALIZED: When Punched", - "block.create.placard.tooltip.behaviour2": "UNLOCALIZED: _Removes_ the current _item_ in the frame.", - - "block.create.flywheel.tooltip": "UNLOCALIZED: FLYWHEEL", - "block.create.flywheel.tooltip.summary": "UNLOCALIZED: _Embellish_ your _Machines_ with this imposing Wheel of Brass.", - "block.create.flywheel.tooltip.condition1": "UNLOCALIZED: When Powered by Kinetics", - "block.create.flywheel.tooltip.behaviour1": "UNLOCALIZED: Starts spinning.", - - "item.create.diving_boots.tooltip": "ЧОБОТИ ДЛЯ ДАЙВІНГУ", - "item.create.diving_boots.tooltip.summary": "Пара _важких черевиків_, дозволяючи краще проходити дно океану.", - "item.create.diving_boots.tooltip.condition1": "При носінні", - "item.create.diving_boots.tooltip.behaviour1": "Власник _тоне швидше_ і _не_ може _плавати_. Черевики дають можливість _ходити_ і _стрибати_ під водою. На власника також більше не впливають _Конвеєри_ (пересування конвеєром).", - - "item.create.crafting_blueprint.tooltip": "СТВОРЕННЯ КРУСЕННЯ", - "item.create.crafting_blueprint.tooltip.summary": "_Розмістивши_ на стіні, його можна використовувати для _визначення розташування компонентів_ (блоків) для більш простого ручного створення предметів. Кожен слот показує Рецепт.", - "item.create.crafting_blueprint.condition1": "ПКМ по пустому Слоту", - "item.create.crafting_blueprint.behaviour1": "Відкриває _Меню крафта_ дозволяючи вам _налаштувати рецепт_ і предмети для відображення.", - "item.create.crafting_blueprint.condition2": "ПКМ по налаштованому слоту", - "item.create.crafting_blueprint.behaviour2": "_Застосовує_ _заданий_ _рецепт_ з відповідними інгредієнтами, з вашого _інвентаря_. _Shift_, щоб створити цілого _стак_ предметів.", - - "item.create.minecart_coupling.tooltip": "З'ЄДНУВАЧ ВАГОНЕТОК", - "item.create.minecart_coupling.tooltip.summary": "_З'єднує_ всі ваші _Вагонетки_ або _Перевізні пристрої_ разом, щоб утворити величний поїзд.", - "item.create.minecart_coupling.tooltip.condition1": "При використанні на Вагонетці", - "item.create.minecart_coupling.tooltip.behaviour1": "_З'єднує_ дві Вагонетки разом, намагаючись утримати їх на _певній відстані_ під час руху.", - - "item.create.experience_nugget.tooltip": "UNLOCALIZED: NUGGET OF EXPERIENCE", - "item.create.experience_nugget.tooltip.summary": "UNLOCALIZED: _Ding!_ A speck of _inspiration_ from your fantastic inventions.", - "item.create.experience_nugget.tooltip.condition1": "UNLOCALIZED: When Used", - "item.create.experience_nugget.tooltip.behaviour1": "UNLOCALIZED: _Redeems_ _Experience_ points contained within.", - - "block.create.peculiar_bell.tooltip": "ДИВНИЙ ДЗВІН", - "block.create.peculiar_bell.tooltip.summary": "Декоративний _Латунний дзвін_. Розмістіть його прямо над відкритим _Вогнем душ_ може викликати побічні ефекти...", - - "block.create.haunted_bell.tooltip": "ПРИМАРНИЙ ДЗВІН", - "block.create.haunted_bell.tooltip.summary": "_Проклятий дзвін_ населений втраченими душами Нижнього світу.", - "block.create.haunted_bell.tooltip.condition1": "При носінні або при дзвоні", - "block.create.haunted_bell.tooltip.behaviour1": "Підсвічує найближчі місця _без світла_, на яких можуть з'являтися ворожі моби_", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 об./хв", - "create.ponder.shared.behaviour_modify_wrench": "Цю поведінку можна змінити за допомогою гайкового ключа", - "create.ponder.shared.storage_on_contraption": "Приєднані до штуковини інвентарі будуть підбирати речі автоматично", - "create.ponder.shared.rpm8": "8 об./хв", - "create.ponder.shared.rpm32": "32 об./хв", - "create.ponder.shared.rpm16_source": "Джерело: 16 об./хв", - "create.ponder.shared.movement_anchors": "З допомогою суперклея або шасі, великі структури можуть бути здвинуті.", - "create.ponder.tag.redstone": "Логічні компоненти", - "create.ponder.tag.redstone.description": "Компоненти, які допомагають з конструюванням редстоун схем", - "create.ponder.tag.contraption_assembly": "Пристосування для приєднання блоків", - "create.ponder.tag.contraption_assembly.description": "Інструменти та Компоненти використовуються для складання структур, що пересуваються як рухомі Штуковини", - "create.ponder.tag.fluids": "Рідинні маніпулятори", - "create.ponder.tag.fluids.description": "Компоненти, що допомагають переміщати та використовувати рідини", - "create.ponder.tag.decoration": "Естетика", - "create.ponder.tag.decoration.description": "Компоненти, які найчастіше використовуються для декоративних цілей", - "create.ponder.tag.windmill_sails": "Вітрила для Підшипників вітряка", - "create.ponder.tag.windmill_sails.description": "Блоки, кількість яких збільшує силу вітряка. Кожен із цих блоків має однакову ефективність у справі.", - "create.ponder.tag.arm_targets": "Цілі для Механічної руки", - "create.ponder.tag.arm_targets.description": "Компоненти, які можна вибрати входами або виходами для Механічної руки", - "create.ponder.tag.kinetic_appliances": "Кінетичні прилади", - "create.ponder.tag.kinetic_appliances.description": "Компоненти, які використовують силу обертання", - "create.ponder.tag.kinetic_sources": "Кінетичні джерела", - "create.ponder.tag.kinetic_sources.description": "Компоненти, які створюють обертальну силу", - "create.ponder.tag.movement_anchor": "Опори руху", - "create.ponder.tag.movement_anchor.description": "Компоненти, що дозволяють створювати штуковини, що рухаються, пожвавлюючи прикріплену структуру різними способами.", - "create.ponder.tag.kinetic_relays": "Кінетичні блоки", - "create.ponder.tag.kinetic_relays.description": "Компоненти, що допомагають передавати силу обертання будь-куди", - "create.ponder.tag.contraption_actor": "Компоненти штуковин", - "create.ponder.tag.contraption_actor.description": "Компоненти, що виявляють особливу поведінку, коли прикріплені до штуковини, що рухається.", - "create.ponder.tag.creative": "Творчий режим", - "create.ponder.tag.creative.description": "Компоненти зазвичай недоступні в режимі виживання", - "create.ponder.tag.display_sources": "UNLOCALIZED: Sources for Display Links", - "create.ponder.tag.display_sources.description": "UNLOCALIZED: Components or Blocks which offer some data that can be read with a Display Link", - "create.ponder.tag.logistics": "Транспортування предметів", - "create.ponder.tag.logistics.description": "Компоненти, що допомагають рухати предмети", - "create.ponder.tag.display_targets": "UNLOCALIZED: Targets for Display Links", - "create.ponder.tag.display_targets.description": "UNLOCALIZED: Components or Blocks which can process and display the data received from a Display Link", - "create.ponder.tag.train_related": "UNLOCALIZED: Railway Equipment", - "create.ponder.tag.train_related.description": "UNLOCALIZED: Components used in the construction or management of Train Contraptions", - - "create.ponder.analog_lever.header": "Управління сигналами використовуючи Аналоговий важіль", - "create.ponder.analog_lever.text_1": "Аналоговий важіль створений як компактне та точне джерело Редстоун сигналу", - "create.ponder.analog_lever.text_2": "ПКМ, щоб збільшити силу вихідного сигналу", - "create.ponder.analog_lever.text_3": "ПКМ крадучись, щоб зменшити силу вихідного сигналу знову", - - "create.ponder.andesite_tunnel.header": "Використання Андезитових тунелів", - "create.ponder.andesite_tunnel.text_1": "Андезитові тунелі можуть бути використані, щоб накривати конвеєри.", - "create.ponder.andesite_tunnel.text_2": "Завжди, коли у Андезитового тунелю є з'єднання збоку...", - "create.ponder.andesite_tunnel.text_3": "...він буде відокремлювати рівно один предмет з будь-яких стаків, що проходять повз.", - "create.ponder.andesite_tunnel.text_4": "Залишок продовжить свій шлях", - - "create.ponder.auto_schedule.header": "UNLOCALIZED: Stations & Scheduling", - "create.ponder.auto_schedule.text_1": "UNLOCALIZED: Schedules can be used to provide drivers with a destination", - "create.ponder.auto_schedule.text_2": "UNLOCALIZED: Comparators will receive a signal whenever a Train is present", - "create.ponder.auto_schedule.text_3": "UNLOCALIZED: Mind that a Station can only be approached from the indicated direction", - "create.ponder.auto_schedule.text_4": "UNLOCALIZED: Stations can also be used to assign new Schedules automatically", - "create.ponder.auto_schedule.text_5": "UNLOCALIZED: The Schedule placed on a station will automatically copy itself to present trains", - "create.ponder.auto_schedule.text_6": "UNLOCALIZED: As opposed to manual scheduling, drivers will not take the item with them", - - "create.ponder.basin.header": "Оброблення предметів у Чаші", - "create.ponder.basin.text_1": "Чаша може зберігати предмети та рідини для обробки", - "create.ponder.basin.text_2": "Після обробки, чаші намагаються вивести результат під будь-який з їхніх сторін", - "create.ponder.basin.text_3": "Коли надано відповідний компонент, у Чаші з'явиться кран, що виходить.", - "create.ponder.basin.text_4": "Декілька варіантів застосовні тут", - "create.ponder.basin.text_5": "Виведення чаші буде спіймано інвентарем нижче", - "create.ponder.basin.text_6": "Без виходу крана, Чаша залишатиме предмети, отримані в результаті обробки", - "create.ponder.basin.text_7": "Це може бути корисним, якщо продукт повинен бути використаний повторно як інгредієнт", - "create.ponder.basin.text_8": "Бажані продукти повинні бути в такому випадку вилучені із чаші", - "create.ponder.basin.text_9": "Фільтр може бути необхідний для уникнення вилучення необроблених предметів", - - "create.ponder.bearing_modes.header": "Режимах руху механічного підшипника", - "create.ponder.bearing_modes.text_1": "Коли зупинено, підшипник встановить структуру на найближчому вирівняному по сітці блоках куті.", - "create.ponder.bearing_modes.text_2": "Він може бути налаштований ніколи не повертати структуру в твердий стан, або лише біля початкового кута", - - "create.ponder.belt_casing.header": "Обрамлення ременів", - "create.ponder.belt_casing.text_1": "Латунний або Андезитовий корпус можна використовувати для декорації Механічних ременів (конвеєра)", - "create.ponder.belt_casing.text_2": "Використовуйте Ключ, щоб усунути обрамлення", - - "create.ponder.belt_connector.header": "Використання Механічних ременів", - "create.ponder.belt_connector.text_1": "ПКМ по двом валах предметом ременя з'єднає їх разом у конвеєр", - "create.ponder.belt_connector.text_2": "Випадкові виділення можуть бути скасовані натисканням ПКМ Крадучись", - "create.ponder.belt_connector.text_3": "Додаткові вали можуть бути додані по всій довжині конвеєра", - "create.ponder.belt_connector.text_4": "Вали, з'єднані через ремені, будуть обертатися з тією ж швидкістю та напрямком", - "create.ponder.belt_connector.text_5": "Додані Вали можуть бути прибрані Ключем", - "create.ponder.belt_connector.text_6": "Механічні ремені можуть бути пофарбовані з естетичною метою", - - "create.ponder.belt_directions.header": "Можливих розташувань Механічних ременів", - "create.ponder.belt_directions.text_1": "Ремені не можуть з'єднуватися у довільних напрямках", - "create.ponder.belt_directions.text_2": "1. Вони можуть з'єднуватися горизонтально", - "create.ponder.belt_directions.text_3": "2. Вони можуть з'єднуватись по діагоналі", - "create.ponder.belt_directions.text_4": "3. Вони можуть з'єднуватися вертикально", - "create.ponder.belt_directions.text_5": "4. І вони можуть з'єднувати вертикальні вали горизонтально", - "create.ponder.belt_directions.text_6": "Це все можливі напрямки. Ремені можуть досягати Довжини від 2 до 20 блоків", - - "create.ponder.belt_transport.header": "Використання Механічних ременів для логістики", - "create.ponder.belt_transport.text_1": "Ремені, що рухаються, переміщатимуть Предмети та інші Сутності", - "create.ponder.belt_transport.text_2": "ПКМ порожній рукою, щоб забрати предмети з ременя", - - "create.ponder.blaze_burner.header": "Годування пальників блейза", - "create.ponder.blaze_burner.text_1": "Пальники блейза дають тепло предметам, що обробляються в Чаші.", - "create.ponder.blaze_burner.text_2": "Для цього, Блейз повинен бути нагодований займистими предметами", - "create.ponder.blaze_burner.text_3": "З Тортом сполоху, пальник може досягати ще більшого рівня жару", - "create.ponder.blaze_burner.text_4": "Процес годування може бути автоматизований, використовуючи Автономний активатор або Механічну руку", - - "create.ponder.brass_funnel.header": "Латунній Воронці", - "create.ponder.brass_funnel.text_1": "Андезитова воронка може витягувати тільки одиночні предмети", - "create.ponder.brass_funnel.text_2": "Латунна воронка може витягувати до цілого стака", - "create.ponder.brass_funnel.text_3": "Прокручування на слоті фільтра дозволяє точно регулювати розмір стака, що витягується.", - "create.ponder.brass_funnel.text_4": "Використовуючи предмет на слоті фільтра, обмежить воронку до передачі тільки збігаючих стаків.", - - "create.ponder.brass_tunnel.header": "Використання Латунних тунелів", - "create.ponder.brass_tunnel.text_1": "Латунні тунелі можуть бути використані, щоб накривати конвеєри", - "create.ponder.brass_tunnel.text_2": "Латунні тунелі мають слот для фільтра на кожній відкритій стороні.", - "create.ponder.brass_tunnel.text_3": "Фільтр на вхідних з'єднаннях блокує невідповідні предмети", - "create.ponder.brass_tunnel.text_4": "Фільтр на вихідних з'єднаннях може бути використаний для сортування предметів типу", - "create.ponder.brass_tunnel.text_5": "Завжди, коли у предмета, що проходить, є кілька доступних виходів, режим розподілу вирішить що з ним робити", - "create.ponder.brass_tunnel.text_6": "Латунні тунелі на паралельних конвеєрах формують групи", - "create.ponder.brass_tunnel.text_7": "Вхідні предмети будуть розподілені між усіма з'єднаними виходами", - "create.ponder.brass_tunnel.text_8": "Для цього предмети можуть бути вкладені в блок тунелю безпосередньо", - - "create.ponder.brass_tunnel_modes.header": "Режимах розподілу Латунних тунелів", - "create.ponder.brass_tunnel_modes.text_1": "Використовуючи Ключ, ви можете налаштувати поведінку розподілу Латунного тунелю", - "create.ponder.brass_tunnel_modes.text_10": "«Синхронізувати входи» – унікальне налаштування для Латунних тунелів", - "create.ponder.brass_tunnel_modes.text_11": "Предмети можуть пройти тільки якщо у кожного тунелю в групі є предмет, що очікує біля входу", - "create.ponder.brass_tunnel_modes.text_12": "Це має на увазі, що всі конвеєри постачають предмети з рівною швидкістю", - "create.ponder.brass_tunnel_modes.text_2": "«Розділити» спробує розподілити так порівну між доступними виходами", - "create.ponder.brass_tunnel_modes.text_3": "Якщо вихід не може прийняти більше предметів, він буде пропущений", - "create.ponder.brass_tunnel_modes.text_4": "«Примусово розділити» ніколи не пропустить виходи і натомість чекатиме поки вони не звільняться", - "create.ponder.brass_tunnel_modes.text_5": "«По Кругу» зберігає цілісні стаки та віддає їх виходам по черзі", - "create.ponder.brass_tunnel_modes.text_6": "Знову ж таки, якщо вихід не може прийняти більше предметів, він буде пропущений", - "create.ponder.brass_tunnel_modes.text_7": "«Примусово по колу» ніколи не пропускає виходи", - "create.ponder.brass_tunnel_modes.text_8": "«Переважно найближче» пріоритизує найближчі виходи від місця подачі предметів", - "create.ponder.brass_tunnel_modes.text_9": "«Випадково» віддаватиме цілі стаки випадково вибраним виходам", - - "create.ponder.cart_assembler.header": "Рух структур за допомогою Складальника вагонеток", - "create.ponder.cart_assembler.text_1": "Активовані Збирачі вагонеток встановлюють прикріплені структури до вагонеток, що проходять повз.", - "create.ponder.cart_assembler.text_2": "Без редстоун сигналу вони розбирають вагонеткові штуковини назад у блоки.", - "create.ponder.cart_assembler.text_3": "Використання Ключа на вагонетці дозволить вам забрати Штуковину кудись ще", - - "create.ponder.cart_assembler_dual.header": "Складання Штуковин-екіпажів", - "create.ponder.cart_assembler_dual.text_1": "Завжди, коли два збирачі вагонеток мають загальну прикріплену структуру...", - "create.ponder.cart_assembler_dual.text_2": "активація будь-якого з них створить Штуковину-екіпаж", - "create.ponder.cart_assembler_dual.text_3": "Ці вагонетки будуть поводитися так, ніби вони з'єднані З'єднувачем вагонеток", - - "create.ponder.cart_assembler_modes.header": "Налаштування орієнтації Вагонеткових штуковин", - "create.ponder.cart_assembler_modes.text_1": "Вагонеткові штуковини повертатимуться у бік руху їх вагонеток.", - "create.ponder.cart_assembler_modes.text_2": "Стрілкою показано, яка сторона конструкції вважатиметься передньою", - "create.ponder.cart_assembler_modes.text_3": "Якщо збирач налаштований на блокування обертання, то орієнтація штуковин ніколи не зміниться", - - "create.ponder.cart_assembler_rails.header": "Інші типи вагонеток і рейок", - "create.ponder.cart_assembler_rails.text_1": "Складачі вагонеток на звичайних рейках не впливатимуть на рух вагонеток, що проходять.", - "create.ponder.cart_assembler_rails.text_2": "На активних Контролюючих рейках або Енергорельсах вагонетки стоятимуть на місці доти, доки Складальник не буде активований", - "create.ponder.cart_assembler_rails.text_3": "Інші типи вагонеток можуть бути використані як основа", - "create.ponder.cart_assembler_rails.text_4": "Самохідні вагонетки підтримуватимуть себе запитаними, використовуючи паливо із приєднаних інвентарів", - - "create.ponder.chain_drive.header": "Передачі сили обертання Ланцюгові приводи", - "create.ponder.chain_drive.text_1": "Ланцюгові приводи передають силу обертання один одному", - "create.ponder.chain_drive.text_2": "Всі вали з'єднані таким чином обертатимуться в одному напрямку", - "create.ponder.chain_drive.text_3": "Будь-яка частина в ряду може бути повернена на 90 градусів", - - "create.ponder.chain_gearshift.header": "Управління швидкістю обертання Регульованими ланцюговими механізмами", - "create.ponder.chain_gearshift.text_1": "Неактивні Ланцюгові механізми поводяться так само, як Ланцюгові приводи", - "create.ponder.chain_gearshift.text_2": "Коли активовано, швидкість, що передається іншим Ланцюговим механізмам у ряді подвоюється", - "create.ponder.chain_gearshift.text_3": "Коли активований Ланцюговий механізм не є джерелом, його швидкість буде знижена вдвічі", - "create.ponder.chain_gearshift.text_4": "В обох випадках Ланцюгові приводи в ряді завжди обертаються з 2x швидкістю активованого Ланцюгового механізму", - "create.ponder.chain_gearshift.text_5": "Використовуючи аналогові сигнали, це множення може бути точніше налаштовано між 1 і 2", - "create.ponder.chain_gearshift.text_6": "12 об./хв.", - - "create.ponder.chute.header": "Транспортування предметів вниз через Жолоба", - "create.ponder.chute.text_1": "Жолоби можуть транспортувати предмети вертикально з та в інвентарі", - "create.ponder.chute.text_2": "Використовуючи Ключ, ви можете створити вікно", - "create.ponder.chute.text_3": "Встановлення жолобів на сторони інших жолобів зробить їх діагональними", - - "create.ponder.chute_upward.header": "Транспортування предметів вгору через Жолоба", - "create.ponder.chute_upward.text_1": "Використовуючи Вентилятор у корпусі внизу або вгорі, Жолоб може переміщати предмети вгору", - "create.ponder.chute_upward.text_2": "Огляд ринв в Інженерних окулярах відкриває інформацію про напрямок руху", - "create.ponder.chute_upward.text_3": "На «заблокованому» кінці предмети мають бути введені/виведені збоку", - - "create.ponder.clockwork_bearing.header": "Пожвавлення структур Часовим механізмом", - "create.ponder.clockwork_bearing.text_1": "Годинникові механізми прикріплюються до блоків спереду", - "create.ponder.clockwork_bearing.text_2": "При отриманні сили обертання структура повернеться в залежності від поточної години", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "ПКМ по механізму, щоб зупинити або знову запустити структуру", - "create.ponder.clockwork_bearing.text_6": "Друга структура може бути додана спереду.", - "create.ponder.clockwork_bearing.text_7": "Переконайтеся, що дві структури не з'єднані між собою супер-клеєм чи чимось схожим", - "create.ponder.clockwork_bearing.text_8": "Друга структура обертатиметься як Хвилинна стрілка", - - "create.ponder.clutch.header": "Управління силою обертання за допомогою Зчеплення", - "create.ponder.clutch.text_1": "Зчеплення передає обертання прямою", - "create.ponder.clutch.text_2": "При активації Редстоуном воно розриває з'єднання", - - "create.ponder.cog_speedup.header": "Перемикання передач Шестернями", - "create.ponder.cog_speedup.text_1": "Великі та маленькі шестерні можуть з'єднуватися по діагоналі.", - "create.ponder.cog_speedup.text_2": "Переходячи з великих на маленькі шестерні, передана швидкість подвоїться", - "create.ponder.cog_speedup.text_3": "Переходячи у зворотному напрямку, передана швидкість скоротиться вдвічі", - - "create.ponder.cogwheel.header": "Передача сили обертання Шестернями", - "create.ponder.cogwheel.text_1": "Шестерні передають обертання іншим сусіднім шестерням", - "create.ponder.cogwheel.text_2": "Сусідні вали з'єднані таким чином обертатимуться у протилежних напрямках.", - - "create.ponder.cogwheel_casing.header": "UNLOCALIZED: Encasing Cogwheels", - "create.ponder.cogwheel_casing.text_1": "UNLOCALIZED: Brass or Andesite Casing can be used to decorate Cogwheels", - "create.ponder.cogwheel_casing.text_2": "UNLOCALIZED: Components added after encasing will not connect to the shaft outputs", - "create.ponder.cogwheel_casing.text_3": "UNLOCALIZED: The Wrench can be used to toggle connections", - - "create.ponder.creative_fluid_tank.header": "Творчому рідинному баку", - "create.ponder.creative_fluid_tank.text_1": "Творчий рідинний бак може використовуватись для забезпечення нескінченного запасу рідини", - "create.ponder.creative_fluid_tank.text_2": "Клацніть ПКМ предметом, який містить рідину, щоб налаштувати його", - "create.ponder.creative_fluid_tank.text_3": "Мережі труб можуть нескінченно витягувати задану рідину з резервуару.", - "create.ponder.creative_fluid_tank.text_4": "Будь-які рідини, закачані назад у творчий рідинний бак, будуть знищені.", - - "create.ponder.creative_motor.header": "Генерації сили обертання творчими двигунами", - "create.ponder.creative_motor.text_1": "Творчі мотори - це компактні та налаштовані джерела Сили Обертання", - "create.ponder.creative_motor.text_2": "Прокручування по задній панелі змінює кількість об./хв. у обертового валу мотора", - - "create.ponder.creative_motor_mojang.header": "UNLOCALIZED: Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "Оброблення предметів Колісами дроблення", - "create.ponder.crushing_wheels.text_1": "Пара Коліс дроблення може молоти предмети дуже ефективно", - "create.ponder.crushing_wheels.text_2": "Сила обертання повинна обертати їх одне в одного", - "create.ponder.crushing_wheels.text_3": "Предмети кинуті чи введені зверху будуть оброблені", - "create.ponder.crushing_wheels.text_4": "Предмети також можуть бути введені та підібрані автоматичним способом", - - "create.ponder.deployer.header": "Використання автономного активатора", - "create.ponder.deployer.text_1": "За наявності сили обертання автономний активатор може імітувати дії гравця", - "create.ponder.deployer.text_10": "ПКМ попереду, щоб дати йому предмет для використання", - "create.ponder.deployer.text_11": "Предмети також можуть бути введені автоматично", - "create.ponder.deployer.text_12": "Автономні активатори мають слот для фільтра", - "create.ponder.deployer.text_13": "Коли фільтр встановлений, Активатор працює тільки тримаючи відповідний предмет", - "create.ponder.deployer.text_14": "Тільки предмети, що підходять по фільтру, можуть бути введені...", - "create.ponder.deployer.text_15": "...і лише невідповідні предмети будуть виведені", - "create.ponder.deployer.text_2": "Він завжди буде взаємодіяти з місцем на два блоки перед ним", - "create.ponder.deployer.text_3": "Блоки прямо перед ним не заважатимуть йому", - "create.ponder.deployer.text_4": "Автономні активатори вміють:", - "create.ponder.deployer.text_5": "Ставити блоки,", - "create.ponder.deployer.text_6": "Використовувати предмети,", - "create.ponder.deployer.text_7": "Активувати блоки,", - "create.ponder.deployer.text_8": "Збирати блоки", - "create.ponder.deployer.text_9": "та Атакувати мобів", - - "create.ponder.deployer_contraption.header": "Використання автономних активаторів на штуковинах", - "create.ponder.deployer_contraption.text_1": "Завжди, коли автономні активатори рухаються як частина рухомої штуковини...", - "create.ponder.deployer_contraption.text_2": "Вони активуються на кожному відвідуваному місці, використовуючи предмети з будь-яких інвентарів на штуковині", - "create.ponder.deployer_contraption.text_3": "Слот для Фільтру може бути використаний для уточнення, які предмети йому брати", - - "create.ponder.deployer_modes.header": "Режимах автономного активатора", - "create.ponder.deployer_modes.text_1": "За замовчуванням активатор імітує ПКМ-взаємодія.", - "create.ponder.deployer_modes.text_2": "Використовуючи Ключ, ви можете встановити його на імітацію ЛКМ", - - "create.ponder.deployer_processing.header": "Обробка елементів за допомогою автономних активаторів", - "create.ponder.deployer_processing.text_1": "Тримаючи відповідний предмет/інструмент, автономні активатори можуть обробляти предмети під собою", - "create.ponder.deployer_processing.text_2": "Прийняті предмети можна кинути або покласти на депо під автономним активатором", - "create.ponder.deployer_processing.text_3": "Коли предмети знаходяться на конвеєрі...", - "create.ponder.deployer_processing.text_4": "автономний активатор буде утримувати та обробляти їх автоматично", - - "create.ponder.deployer_redstone.header": "Управління автономними активаторами редстоуном", - "create.ponder.deployer_redstone.text_1": "При активації Редстоуном активатор перестане працювати", - "create.ponder.deployer_redstone.text_2": "Перед зупинкою Активатор завершить всі розпочаті дії", - "create.ponder.deployer_redstone.text_3": "Таким чином, інвертований імпульс може бути використаний для виклику рівно одного спрацьовування", - - "create.ponder.depot.header": "Використання Депо", - "create.ponder.depot.text_1": "Депо можуть бути як «стаціонарний» елемент конвеєра", - "create.ponder.depot.text_2": "ПКМ, щоб самостійно покласти або забрати предмети з них", - "create.ponder.depot.text_3": "Так само, як Механічні ремені, воно може надавати предмети для обробки", - "create.ponder.depot.text_4": "...а також постачати предмети Механічним рукам", - - "create.ponder.display_board.header": "UNLOCALIZED: Using Display Boards", - "create.ponder.display_board.text_1": "UNLOCALIZED: Display Boards are a scalable alternative to the sign", - "create.ponder.display_board.text_2": "UNLOCALIZED: They require Rotational Force to operate", - "create.ponder.display_board.text_3": "UNLOCALIZED: Text can be displayed using Name Tags...", - "create.ponder.display_board.text_4": "UNLOCALIZED: ...or through the use of Display Links", - "create.ponder.display_board.text_5": "UNLOCALIZED: Dyes can be applied to individual lines of the board", - "create.ponder.display_board.text_6": "UNLOCALIZED: Lines can be reset by clicking them with an empty hand", - - "create.ponder.display_link.header": "UNLOCALIZED: Setting up Display Links", - "create.ponder.display_link.text_1": "UNLOCALIZED: Display Links can be used to visualise dynamic information", - "create.ponder.display_link.text_2": "UNLOCALIZED: First, right-click the target display...", - "create.ponder.display_link.text_3": "UNLOCALIZED: ...then attach it to the block to read from", - "create.ponder.display_link.text_4": "UNLOCALIZED: Open the Interface to select and configure what is sent", - "create.ponder.display_link.text_5": "UNLOCALIZED: The display will now receive information from the link", - "create.ponder.display_link.text_6": "UNLOCALIZED: Not every block can act as a source", - "create.ponder.display_link.text_7": "UNLOCALIZED: Each compatible block provides unique information", - "create.ponder.display_link.text_8": "UNLOCALIZED: The Display Link can work with several different displays", - - "create.ponder.display_link_redstone.header": "UNLOCALIZED: Redstone Control", - "create.ponder.display_link_redstone.text_1": "UNLOCALIZED: When powered by Redstone, Display Links stop sending updates", - "create.ponder.display_link_redstone.text_2": "UNLOCALIZED: Once unpowered, the Timer is reset and new info is sent immediately", - "create.ponder.display_link_redstone.text_3": "UNLOCALIZED: Signals emitted from the source do not affect the Link", - - "create.ponder.empty_blaze_burner.header": "Використання Порожніх пальників блейза", - "create.ponder.empty_blaze_burner.text_1": "ПКМ по Блейзу з порожнім пальником, щоб захопити його", - "create.ponder.empty_blaze_burner.text_2": "Також Блейзи можуть бути захоплені зі спавнера безпосередньо", - "create.ponder.empty_blaze_burner.text_3": "Тепер у вас є ідеальне джерело тепла для низки машин", - "create.ponder.empty_blaze_burner.text_4": "В естетичних цілях, Пусті пальники можуть бути запалені огнивом", - "create.ponder.empty_blaze_burner.text_5": "Полум'я можна трансформувати, використовуючи наповнений душею предмет.", - "create.ponder.empty_blaze_burner.text_6": "Однак вони не будуть підходити для промислового нагріву", - - "create.ponder.encased_fluid_pipe.header": "Обрамлення рідких труб", - "create.ponder.encased_fluid_pipe.text_1": "Мідний корпус можна використовувати для прикраси труб.", - "create.ponder.encased_fluid_pipe.text_2": "Крім того, що вони ховаються, ув'язнені в обрамлення труби блокуються в поточному стані", - "create.ponder.encased_fluid_pipe.text_3": "Вони більше не реагуватимуть на додавання чи видалення будь-яких сусідніх блоків", - - "create.ponder.fan_direction.header": "Повітряний потік Вентиляторів у корпусі", - "create.ponder.fan_direction.text_1": "Вентилятори в корпусі використовують силу обертання для створення повітряного потоку.", - "create.ponder.fan_direction.text_2": "Сила і напрямок потоку залежать від обертання, що подається.", - - "create.ponder.fan_processing.header": "Обробці предметів використовуючи Вентилятори в корпусі", - "create.ponder.fan_processing.text_1": "Проходячи через лаву, Повітряний потік стає Гарячим", - "create.ponder.fan_processing.text_2": "Предмети у цій області будуть переплавлені", - "create.ponder.fan_processing.text_3": "Їстівні предмети, кинуті сюди, будуть спалені", - "create.ponder.fan_processing.text_4": "Натомість, для них має бути використана установка для Копчення з вогнем.", - "create.ponder.fan_processing.text_5": "Потік, що проходить через Воду, створює установку, що промиває.", - "create.ponder.fan_processing.text_6": "Декілька нових варіантів обробки робляться з її допомогою", - "create.ponder.fan_processing.text_7": "Швидкість вентилятора не впливає на швидкість обробки, а лише на дальність", - "create.ponder.fan_processing.text_8": "Обробка Вентиляторами може бути застосована до предметів на конвеєрах або депо", - - "create.ponder.fluid_pipe_flow.header": "Переміщення рідин за допомогою мідних труб.", - "create.ponder.fluid_pipe_flow.text_1": "Рідинні труби можуть з'єднувати два або більше джерел та споживачів рідини", - "create.ponder.fluid_pipe_flow.text_2": "За допомогою гайкового ключа можна створити вікно прямому відрізку труби", - "create.ponder.fluid_pipe_flow.text_3": "Труби з вікнами не з'єднуватимуться ні з якими іншими трубами, що йдуть відрізками труб", - "create.ponder.fluid_pipe_flow.text_4": "Труби, що приводяться в дію механічними помпами, можуть транспортувати рідини.", - "create.ponder.fluid_pipe_flow.text_5": "Спочатку рідина не викачується", - "create.ponder.fluid_pipe_flow.text_6": "Як тільки потік з'єднає кінці, вони поступово перекачають свій вміст.", - "create.ponder.fluid_pipe_flow.text_7": "Таким чином, самі блоки труб ніколи «фізично» не містять жодної рідини.", - - "create.ponder.fluid_pipe_interaction.header": "Спустошення та наповнення рідинних контейнерів", - "create.ponder.fluid_pipe_interaction.text_1": "Кінці мережі труб можуть взаємодіяти з різними блоками", - "create.ponder.fluid_pipe_interaction.text_2": "Будь-який блок із можливістю зберігання рідини може бути заповнений або спустошений", - "create.ponder.fluid_pipe_interaction.text_3": "Джерела прямо перед відкритим кінцем можна відкачати...", - "create.ponder.fluid_pipe_interaction.text_4": "...тоді як виливання в незаповнений простір може створити джерела", - "create.ponder.fluid_pipe_interaction.text_5": "Труби також можуть витягувати рідини безпосередньо з кількох інших блоків", - - "create.ponder.fluid_tank_sizes.header": "Розміри рідинного бака", - "create.ponder.fluid_tank_sizes.text_1": "Рідинні баки можна поєднати для збільшення загальної місткості", - "create.ponder.fluid_tank_sizes.text_2": "Їх площа основи може становити до 3 блоків завширшки...", - "create.ponder.fluid_tank_sizes.text_3": "...та збільшуються у висоту більш ніж на 30 додаткових рівнів", - "create.ponder.fluid_tank_sizes.text_4": "За допомогою гайкового ключа можна створити вікно на резервуарі", - - "create.ponder.fluid_tank_storage.header": "Зберігання рідин у Резервуарах для рідини", - "create.ponder.fluid_tank_storage.text_1": "Резервуари для рідини можна використовувати для зберігання великої кількості рідини.", - "create.ponder.fluid_tank_storage.text_2": "Труби можуть закачувати та викачувати рідини з будь-якого боку", - "create.ponder.fluid_tank_storage.text_3": "Рідина, що міститься, може бути виміряна за допомогою компаратора", - "create.ponder.fluid_tank_storage.text_4": "Однак у режимі виживання рідину не можна додавати або виймати вручну.", - "create.ponder.fluid_tank_storage.text_5": "Ви можете використовувати чаші, предметні осушувачі і дозатори для спустошення або наповнення вмісту рідини предметів", - - "create.ponder.funnel_compat.header": "Сумісності Воронок", - "create.ponder.funnel_compat.text_1": "Вирви повинні добре взаємодіяти з багатьма компонентами:", - "create.ponder.funnel_compat.text_2": "Вертикальні пили", - "create.ponder.funnel_compat.text_3": "Депо", - "create.ponder.funnel_compat.text_4": "Предметні осушувачі", - - "create.ponder.funnel_direction.header": "Напрямок передачі", - "create.ponder.funnel_direction.text_1": "Поставлена звичайним чином вона забирає предмети з інвентарю", - "create.ponder.funnel_direction.text_2": "Поставлена крадькома, вона кладе предмети в інвентар", - "create.ponder.funnel_direction.text_3": "Використовуючи Ключ, ви можете змінити напрямок вирви", - "create.ponder.funnel_direction.text_4": "Ті ж правила застосовуються для більшості напрямків", - "create.ponder.funnel_direction.text_5": "Вирви на конвеєрах витягуватимуть/вводитимуть предмети в залежності від напрямку їх руху", - - "create.ponder.funnel_intro.header": "Використання Воронок", - "create.ponder.funnel_intro.text_1": "Вирви ідеально підходять для переміщення предметів з та в інвентарі", - - "create.ponder.funnel_redstone.header": "Редстоун управлінні", - "create.ponder.funnel_redstone.text_1": "Редстоун сигнал не дасть будь-якій воронці працювати", - - "create.ponder.funnel_transfer.header": "Передача безпосередньо", - "create.ponder.funnel_transfer.text_1": "Вирви не можуть переміщати предмети безпосередньо між закритими інвентарями", - "create.ponder.funnel_transfer.text_2": "Жолоби або Розумні жолоби можуть краще підходити для цих цілей", - "create.ponder.funnel_transfer.text_3": "Те саме стосується і горизонтального переміщення. Механічний ремінь має тут допомогти", - - "create.ponder.gantry_carriage.header": "Використання шасі портального крана", - "create.ponder.gantry_carriage.text_1": "Шасі портального крана можуть прикріплюватися і рухатися вздовж Валу портального крана", - "create.ponder.gantry_carriage.text_2": "Кранові установки можуть рухати приєднані блоки", - - "create.ponder.gantry_cascaded.header": "Багатоступінчастому портальному крані", - "create.ponder.gantry_cascaded.text_1": "Вали портального крана прикріплюються до шасі без потреби у супер-клеї.", - "create.ponder.gantry_cascaded.text_2": "Те саме стосується і шасі на Валах портального крана, що рухаються.", - "create.ponder.gantry_cascaded.text_3": "Таким чином, кранова система може покривати кілька осей руху.", - - "create.ponder.gantry_direction.header": "Напрямок руху крана", - "create.ponder.gantry_direction.text_1": "Вали портального крана можуть мати два протилежні напрямки", - "create.ponder.gantry_direction.text_2": "Напрямок руху шасі залежить від орієнтації їх валів.", - "create.ponder.gantry_direction.text_3": "...а також від напрямку обертання валу", - "create.ponder.gantry_direction.text_4": "Ті ж правила відносяться до обертання, що передається.", - - "create.ponder.gantry_redstone.header": "Подачі енергії на кран", - "create.ponder.gantry_redstone.text_1": "Активовані редстоуном вали крана перестають рухати шасі", - "create.ponder.gantry_redstone.text_2": "Натомість сила обертання передається вихідному валу шасі.", - - "create.ponder.gantry_shaft.header": "Використання валів портального крана", - "create.ponder.gantry_shaft.text_1": "Вали портального крана становлять основу кранової установки. По них рухатимуться приєднані шасі", - "create.ponder.gantry_shaft.text_2": "Кранові установки можуть рухати приєднані блоки", - - "create.ponder.gearbox.header": "Передача сили обертання за допомогою Коробок передач", - "create.ponder.gearbox.text_1": "Переходи між осями обертання можуть швидко стати громіздкими", - "create.ponder.gearbox.text_2": "Коробка Передач - це компактніший еквівалент цієї установки", - "create.ponder.gearbox.text_3": "Вали по кутах повертаються у дзеркальних напрямках", - "create.ponder.gearbox.text_4": "Прямі з'єднання будуть реверсовані", - - "create.ponder.gearshift.header": "Управління силою обертання за допомогою Реверсивного механізму", - "create.ponder.gearshift.text_1": "Реверсивні механізми передають обертання прямою", - "create.ponder.gearshift.text_2": "При активації редстоуном вони реверсують передачу", - - "create.ponder.hand_crank.header": "Генерації сили обертання за допомогою Рукояток", - "create.ponder.hand_crank.text_1": "Рукоятки можуть бути використані гравцями для застосування сили обертання вручну", - "create.ponder.hand_crank.text_2": "Тримайте ПКМ, щоб повернути їх проти Годинникової стрілки", - "create.ponder.hand_crank.text_3": "Їхня швидкість обертання відносно висока", - "create.ponder.hand_crank.text_4": "Тримайте ПКМ крадькома, щоб повернути її за годинниковою стрілкою", - - "create.ponder.hose_pulley.header": "Наповнення та осушення джерел за допомогою Шківу зі шлангом", - "create.ponder.hose_pulley.text_1": "Шківи зі шлангом можна використовувати для заповнення або осушення великих об'ємів рідини.", - "create.ponder.hose_pulley.text_2": "За допомогою кінетичної енергії можна регулювати довжину шлангу", - "create.ponder.hose_pulley.text_3": "Шків змотується, якщо звернути обертання", - "create.ponder.hose_pulley.text_4": "З протилежного боку можна підключати труби", - "create.ponder.hose_pulley.text_5": "Приєднані мережі труб можуть або подавати рідину в шланг...", - "create.ponder.hose_pulley.text_6": "...або витягувати її, осушуючи водойму", - "create.ponder.hose_pulley.text_7": "Швидкість заповнення та осушення шківом повністю залежить від пропускної спроможності рідинної мережі", - - "create.ponder.hose_pulley_infinite.header": "Пасивне заповнення та осушення великих об'ємів рідини", - "create.ponder.hose_pulley_infinite.text_1": "При розгортанні Шківу зі шлангом у досить великий океан...", - "create.ponder.hose_pulley_infinite.text_2": "Він надаватиме/поглинатиме рідини без впливу на джерело", - "create.ponder.hose_pulley_infinite.text_3": "Мережі труб можуть необмежено передавати рідини з/в такі шківи.", - - "create.ponder.hose_pulley_level.header": "Рівні заповнення та осушення Шківу зі шлангом", - "create.ponder.hose_pulley_level.text_1": "При повністю прибраному рукаві шланга - він не може працювати", - "create.ponder.hose_pulley_level.text_2": "Осушення відбувається зверху вниз", - "create.ponder.hose_pulley_level.text_3": "Рівень поверхні виявиться трохи нижче того місця, де закінчується шланг", - "create.ponder.hose_pulley_level.text_4": "Наповнення відбувається знизу нагору", - "create.ponder.hose_pulley_level.text_5": "Заповнюваний басейн не наповнюватиметься вище рівня кінця шлангу", - - "create.ponder.item_drain.header": "Спустошення рідинних резервуарів за допомогою предметних осушувачів", - "create.ponder.item_drain.text_1": "Предметні осушувачі можуть витягувати рідини з предметів", - "create.ponder.item_drain.text_2": "Клацніть на ПКМ по ньому, щоб перелити в нього рідину з предмета у ваших руках", - "create.ponder.item_drain.text_3": "Коли предмети подаються з боку...", - "create.ponder.item_drain.text_4": "...вони перевертаються, виливаючи рідину, що міститься в них.", - "create.ponder.item_drain.text_5": "Мережі труб тепер можуть витягувати рідину із внутрішнього сховища осушувачів.", - - "create.ponder.item_vault_sizes.header": "UNLOCALIZED: Dimensions of an Item Vault", - "create.ponder.item_vault_sizes.text_1": "UNLOCALIZED: Item Vaults can be combined to increase the total capacity", - "create.ponder.item_vault_sizes.text_2": "UNLOCALIZED: Their base square can be up to 3 blocks wide...", - "create.ponder.item_vault_sizes.text_3": "UNLOCALIZED: ...and grow in length up to 3x their diameter", - - "create.ponder.item_vault_storage.header": "UNLOCALIZED: Storing Items in Vaults", - "create.ponder.item_vault_storage.text_1": "UNLOCALIZED: Item Vaults can be used to store large amounts of items", - "create.ponder.item_vault_storage.text_2": "UNLOCALIZED: However, contents cannot be added or taken manually", - "create.ponder.item_vault_storage.text_3": "UNLOCALIZED: Any components for item transfer can both insert...", - "create.ponder.item_vault_storage.text_4": "UNLOCALIZED: ...and take contents from this container", - - "create.ponder.large_cogwheel.header": "Передача сили обертання за допомогою Великих шестерень", - "create.ponder.large_cogwheel.text_1": "Великі шестерні можуть з'єднуватися між собою під прямим кутом", - "create.ponder.large_cogwheel.text_2": "Це допоможе передавати швидкість на інші осі обертання", - - "create.ponder.linear_chassis_attachment.header": "Прикріплення блоків за допомогою Лінійних шасі", - "create.ponder.linear_chassis_attachment.text_1": "Відкриті грані Лінійних шасі можна зробити Липкими", - "create.ponder.linear_chassis_attachment.text_2": "Натисніть ще раз, щоб зробити протилежний бік липкою", - "create.ponder.linear_chassis_attachment.text_3": "ПКМ крадучись, порожньою рукою, щоб прибрати слиз", - "create.ponder.linear_chassis_attachment.text_4": "Липкі грані Лінійних шасі будуть прикріплювати ряд блоків перед ним", - "create.ponder.linear_chassis_attachment.text_5": "Використовуйте Ключ, щоб налаштувати радіус для цього шасі", - "create.ponder.linear_chassis_attachment.text_6": "Прокручування при утримуванні CTRL налаштовує радіус усіх приєднаних шасі", - "create.ponder.linear_chassis_attachment.text_7": "Прикріплення блоків на інші сторони потребує використання Супер-клею", - "create.ponder.linear_chassis_attachment.text_8": "За допомогою цих механік структури будь-якої форми можуть рухатися як Штуковина.", - - "create.ponder.linear_chassis_group.header": "Руху Лінійних шасі групами", - "create.ponder.linear_chassis_group.text_1": "Лінійні шасі з'єднуються з такими ж блоками Шасі поряд з ними", - "create.ponder.linear_chassis_group.text_2": "Коли один блок переміщається Штуковиною, інші рухаються з ним", - "create.ponder.linear_chassis_group.text_3": "Шасі інших типів або спрямовані в іншому напрямку не будуть прикріплюватися", - - "create.ponder.mechanical_arm.header": "Налаштування механічних рук", - "create.ponder.mechanical_arm.text_1": "Входи та виходи для Механічних рук повинні бути призначені перед їх встановленням", - "create.ponder.mechanical_arm.text_2": "ПКМ за інвентарями, тримаючи руку, щоб призначити їх цілями", - "create.ponder.mechanical_arm.text_3": "ПКМ ще раз, для перемикання між Входом (Синій) та Виходом (Помаранчевий)", - "create.ponder.mechanical_arm.text_4": "ЛКМ по компонентам, щоб усунути виділення з них", - "create.ponder.mechanical_arm.text_5": "Після встановлення, Механічні руки будуть націлені на раніше вибрані блоки", - "create.ponder.mechanical_arm.text_6": "У них може бути необмежену кількість входів і виходів у зоні їх досяжності", - "create.ponder.mechanical_arm.text_7": "Однак, не кожен вид Інвентар може взаємодіяти з ними безпосередньо", - "create.ponder.mechanical_arm.text_8": "Вирви та Депо можуть допомогти заповнити цю прогалину", - - "create.ponder.mechanical_arm_filtering.header": "Фільтрування виходів Механічної руки", - "create.ponder.mechanical_arm_filtering.text_1": "Входи", - "create.ponder.mechanical_arm_filtering.text_2": "Виходи", - "create.ponder.mechanical_arm_filtering.text_3": "Іноді бажано обмежити цілі руки фільтром", - "create.ponder.mechanical_arm_filtering.text_4": "Механічні руки не мають можливості фільтрації", - "create.ponder.mechanical_arm_filtering.text_5": "Однак, Латунні воронки як цілі повідомляють свій фільтр руці", - "create.ponder.mechanical_arm_filtering.text_6": "Рука досить розумна, щоб не підбирати предмети, які вона не зможе розподілити", - - "create.ponder.mechanical_arm_modes.header": "Режимах розподілу Механічної руки", - "create.ponder.mechanical_arm_modes.text_1": "Входи", - "create.ponder.mechanical_arm_modes.text_2": "Виходи", - "create.ponder.mechanical_arm_modes.text_3": "Коли рука вибирає між кількома доступними виходами...", - "create.ponder.mechanical_arm_modes.text_4": "...вона зробить вибір виходячи зі свого налаштування", - "create.ponder.mechanical_arm_modes.text_5": "Прокручування з Ключом дозволить вам налаштувати це", - "create.ponder.mechanical_arm_modes.text_6": "Режим «по Кругу» перемикається між усіма доступними виходами по черзі", - "create.ponder.mechanical_arm_modes.text_7": "Якщо вихід не може прийняти більше предметів, він буде пропущений", - "create.ponder.mechanical_arm_modes.text_8": "«Примусово по колу» ніколи не пропускає виходи, а чекає доки вони не звільняться", - "create.ponder.mechanical_arm_modes.text_9": "«Віддавати перевагу первинній цілі» пріоритизує виходи, вибрані раніше при налаштуванні цієї Руки", - - "create.ponder.mechanical_arm_redstone.header": "Управління Механічними руками редстоуном", - "create.ponder.mechanical_arm_redstone.text_1": "При активації редстоуном Механічні руки перестають працювати", - "create.ponder.mechanical_arm_redstone.text_2": "Перед зупинкою, вони завершать усі розпочаті дії", - "create.ponder.mechanical_arm_redstone.text_3": "Таким чином, інвертований імпульс може використовуватися для виклику рівно одного спрацьовування", - - "create.ponder.mechanical_bearing.header": "Пересування структур за допомогою механічного підшипника", - "create.ponder.mechanical_bearing.text_1": "Механічні підшипники прикріплюють блоки перед ними", - "create.ponder.mechanical_bearing.text_2": "При отриманні сили обертання, вони зберуться в штуковину, що обертається.", - - "create.ponder.mechanical_crafter.header": "Налаштування Механічних крафтерів", - "create.ponder.mechanical_crafter.text_1": "Масив з Механічних крафтерів можна використовувати для автоматизації створення будь-якого рецепту.", - "create.ponder.mechanical_crafter.text_2": "Можна налаштувати шляхи крафтерів за допомогою Ключа", - "create.ponder.mechanical_crafter.text_3": "Для правильної установки всі шляхи повинні сходитися в один вихід з будь-якої сторони", - "create.ponder.mechanical_crafter.text_4": "Продукти будуть поміщені в інвентар біля виходу", - "create.ponder.mechanical_crafter.text_5": "Механічним крафтерам потрібна сила обертання до роботи", - "create.ponder.mechanical_crafter.text_6": "ПКМ спереду, щоб вставити предмети вручну", - "create.ponder.mechanical_crafter.text_7": "Коли кожен слот на дорозі містить предмет, процес створення розпочнеться", - "create.ponder.mechanical_crafter.text_8": "Для рецептів, які не повністю займають крафтер-установку, старт можна спровокувати Редстоун імпульсом", - - "create.ponder.mechanical_crafter_connect.header": "Об'єднання інвентарів Механічних крафтерів", - "create.ponder.mechanical_crafter_connect.text_1": "Предмети можна помістити в крафтери автоматично", - "create.ponder.mechanical_crafter_connect.text_2": "За допомогою ключа позаду крафтерів їх інвентарі можна об'єднати", - "create.ponder.mechanical_crafter_connect.text_3": "Усі з'єднані крафтери тепер будуть доступні з одного місця введення", - - "create.ponder.mechanical_crafter_covers.header": "Закриття слотів Механічних крафтерів", - "create.ponder.mechanical_crafter_covers.text_1": "Деякі рецепти вимагають додаткових крафтерів, щоб закрити прогалини на дорозі", - "create.ponder.mechanical_crafter_covers.text_2": "За допомогою кришок на слоти, крафтери можуть грати роль порожніх слотів у схемі", - "create.ponder.mechanical_crafter_covers.text_3": "Загальні входи, створені ключем ззаду, також можуть бути доступні через закриті крафтери.", - - "create.ponder.mechanical_drill.header": "Ломанії блоків Механічним Дрилем", - "create.ponder.mechanical_drill.text_1": "При подачі обертання, Механічний дриль ламатиме блоки перед нею", - "create.ponder.mechanical_drill.text_2": "Швидкість видобутку залежить від швидкості, що подається", - - "create.ponder.mechanical_drill_contraption.header": "Використання Механічних дрилів на штуковинах", - "create.ponder.mechanical_drill_contraption.text_1": "Коли дрилі рухаються як частина рухомої штуковини...", - "create.ponder.mechanical_drill_contraption.text_2": "...вони будуть ламати блоки, на які вони натикаються", - - "create.ponder.mechanical_harvester.header": "Використання механічних комбайнів на штуковинах", - "create.ponder.mechanical_harvester.text_1": "Коли комбайни рухаються як частина рухомої штуковини...", - "create.ponder.mechanical_harvester.text_2": "Вони будуть прибирати зрілий урожай на своєму шляху і висаджувати його знову", - - "create.ponder.mechanical_mixer.header": "Обробка предметів Механічним міксером", - "create.ponder.mechanical_mixer.text_1": "За допомогою Міксера та Чаші можна автоматизувати деякі рецепти крафту.", - "create.ponder.mechanical_mixer.text_2": "Доступні рецепти включають будь-які безформні рецепти крафту плюс ще трохи", - "create.ponder.mechanical_mixer.text_3": "Деякі з них вимагають тепло від Пальника блейза", - "create.ponder.mechanical_mixer.text_4": "Слот для фільтра можна використовувати у разі конфлікту двох рецептів", - - "create.ponder.mechanical_piston.header": "Переміщення структур за допомогою Механічних поршнів", - "create.ponder.mechanical_piston.text_1": "Механічні поршні можуть рухати блоки перед ними", - "create.ponder.mechanical_piston.text_2": "Швидкість та Напрямок руху залежать від вихідного обертання", - "create.ponder.mechanical_piston.text_3": "Механічні поршні можуть тягнути назад приєднані блоки", - - "create.ponder.mechanical_piston_modes.header": "Режимах руху Механічного поршня", - "create.ponder.mechanical_piston_modes.text_1": "Коли поршень зупиняється, зрушена структура стає блоками", - "create.ponder.mechanical_piston_modes.text_2": "Можна налаштувати його так, щоб структура ніколи не ставала блоками або лише на початковій позиції", - - "create.ponder.mechanical_plough.header": "Використання Механічних плугів на штуковинах", - "create.ponder.mechanical_plough.text_1": "Коли плуги рухаються як частина рухомої штуковини...", - "create.ponder.mechanical_plough.text_2": "...вони будуть ламати блоки без твердого хітбоксу", - "create.ponder.mechanical_plough.text_3": "До того ж Плуги можуть створювати ріллю.", - "create.ponder.mechanical_plough.text_4": "....вони також можуть штовхати сутностей не завдаючи їм шкоди", - - "create.ponder.mechanical_press.header": "Обробка предметів Механічним пресом", - "create.ponder.mechanical_press.text_1": "Механічний прес може обробляти предмети під собою", - "create.ponder.mechanical_press.text_2": "Представлені предмети повинні бути кинуті або поміщені на Депо під Пресом", - "create.ponder.mechanical_press.text_3": "Коли предмети подаються на конвеєрі...", - "create.ponder.mechanical_press.text_4": "Прес буде затримувати та обробляти їх автоматично", - - "create.ponder.mechanical_press_compacting.header": "Упаковка предметів Механічним пресом", - "create.ponder.mechanical_press_compacting.text_1": "Спресування предметів у Чаші запакує їх", - "create.ponder.mechanical_press_compacting.text_2": "Упаковка включає будь-які заповнені 2x2 або 3x3 рецепти крафта плюс ще трохи", - "create.ponder.mechanical_press_compacting.text_3": "Деяким рецептам може знадобитися тепло від Пальнику блейза", - "create.ponder.mechanical_press_compacting.text_4": "Слот для фільтра можна використовувати у разі конфлікту двох рецептів", - - "create.ponder.mechanical_pump_flow.header": "Транспортування рідини за допомогою Механічних помп", - "create.ponder.mechanical_pump_flow.text_1": "Механічні помпи направляють потік у приєднані мережі із труб", - "create.ponder.mechanical_pump_flow.text_2": "Коли працює, стрілка вказує напрямок потоку", - "create.ponder.mechanical_pump_flow.text_3": "Частина мережі ззаду тепер качає рідину...", - "create.ponder.mechanical_pump_flow.text_4": "...у той час як частина мережі спереду передає їх назовні", - "create.ponder.mechanical_pump_flow.text_5": "Зміна напрямку обертання змінює напрямок потоку", - "create.ponder.mechanical_pump_flow.text_6": "Використовуйте гайковий ключ, щоб змінити напрямок помпи вручну", - - "create.ponder.mechanical_pump_speed.header": "Продуктивності механічних помп", - "create.ponder.mechanical_pump_speed.text_1": "Незалежно від швидкості, Механічні помпи впливають на труби в радіусі 16 блоків.", - "create.ponder.mechanical_pump_speed.text_2": "Прискорення обертання, що подається, змінює швидкість поширення потоків...", - "create.ponder.mechanical_pump_speed.text_3": "...так само, як і швидкість передачі рідин", - "create.ponder.mechanical_pump_speed.text_4": "Помпи можуть поєднувати свою продуктивність у загальних мережах труб", - "create.ponder.mechanical_pump_speed.text_5": "Зміна їхнього напрямку може допомогти спрямувати напрямок їх потоків", - - "create.ponder.mechanical_saw_breaker.header": "Різання дерев Механічною пилкою", - "create.ponder.mechanical_saw_breaker.text_1": "При подачі обертання, Механічна пилка пилятиме дерева прямо перед нею", - "create.ponder.mechanical_saw_breaker.text_2": "Для спилювання дерева повністю пилка повинна ламати останній блок дерева, з'єднаний із землею", - - "create.ponder.mechanical_saw_contraption.header": "Використання Механічних пилок на штуковинах", - "create.ponder.mechanical_saw_contraption.text_1": "Коли пилки рухаються як частина рухомої штуковини...", - "create.ponder.mechanical_saw_contraption.text_2": "...вони будуть ламати блоки, на які вони натикаються", - - "create.ponder.mechanical_saw_processing.header": "Обробка предметів на Механічній пилці", - "create.ponder.mechanical_saw_processing.text_1": "Механічні пили направлені вгору можуть обробляти безліч предметів", - "create.ponder.mechanical_saw_processing.text_2": "Оброблені предмети завжди рухаються проти обертання, що подається на пилу.", - "create.ponder.mechanical_saw_processing.text_3": "Пилки можуть працювати з Механічними ременями (конвеєром)", - "create.ponder.mechanical_saw_processing.text_4": "Коли з інгредієнта можна отримати кілька результатів, фільтр може уточнити його.", - "create.ponder.mechanical_saw_processing.text_5": "Без фільтра пила вибиратиме всі можливі результати по черзі", - - "create.ponder.millstone.header": "Оброблення предметів у Жорновах", - "create.ponder.millstone.text_1": "Жорнова обробляють предмети, перемелюючи їх", - "create.ponder.millstone.text_2": "Їх можна запустити за допомогою шестірні з будь-якого боку", - "create.ponder.millstone.text_3": "Киньте чи внесіть предмети зверху", - "create.ponder.millstone.text_4": "Після деякого часу результат можна забрати за допомогою ПКМ", - "create.ponder.millstone.text_5": "Продукти також можна вивести автоматично", - - "create.ponder.nixie_tube.header": "Використання Газорозрядних індикаторів", - "create.ponder.nixie_tube.text_1": "При подачі редстоуна сигналу, Газорозрядні індикатори відобразять його силу.", - "create.ponder.nixie_tube.text_2": "За допомогою бірок, відредагованих на ковадлі, ви можете відобразити будь-який текст.", - "create.ponder.nixie_tube.text_3": "Натисніть ПКМ з барвником, щоб змінити колір їх дисплея", - - "create.ponder.piston_pole.header": "Подовжувачі Поршня", - "create.ponder.piston_pole.text_1": "Без приєднаних Подовжувачів, Механічний поршень не може рухатися", - "create.ponder.piston_pole.text_2": "Довжина стрижня, доданого до задньої частини, визначає Діапазон висування.", - - "create.ponder.portable_fluid_interface.header": "Обмін рідини", - "create.ponder.portable_fluid_interface.text_1": "Рідинні баки на штуковинах, що рухаються, не можуть бути доступні жодним трубам", - "create.ponder.portable_fluid_interface.text_2": "Цей інтерфейс може взаємодіяти з рідинними баками без необхідності зупиняти штуковину.", - "create.ponder.portable_fluid_interface.text_3": "Встановіть другий із проміжком в 1 або 2 блоки між ними", - "create.ponder.portable_fluid_interface.text_4": "Вони встановлять з'єднання, коли зустрінуться", - "create.ponder.portable_fluid_interface.text_5": "Поки вони з'єднані, стаціонарний інтерфейс буде ВСІ баки на штуковині", - "create.ponder.portable_fluid_interface.text_6": "Тепер можна закачати рідини...", - "create.ponder.portable_fluid_interface.text_7": "...або викачати їх із штуковини", - "create.ponder.portable_fluid_interface.text_8": "Якщо на якийсь час припиниться обмін вмістом – штуковина продовжить свій шлях", - - "create.ponder.portable_storage_interface.header": "Портативний інтерфейс зберігання на штуковинах", - "create.ponder.portable_storage_interface.text_1": "Інвентари на штуковинах, що рухаються, не можуть бути відкриті гравцями", - "create.ponder.portable_storage_interface.text_2": "Цей компонент може взаємодіяти зі сховищем без необхідності зупиняти штуковину.", - "create.ponder.portable_storage_interface.text_3": "Встановіть другий із проміжком в 1 або 2 блоки між ними", - "create.ponder.portable_storage_interface.text_4": "Коли вони проходять повз один одного, вони з'єднаються", - "create.ponder.portable_storage_interface.text_5": "Поки вони з'єднані, стаціонарний інтерфейс буде представляти ВСІ інвентарі на штуковині", - "create.ponder.portable_storage_interface.text_6": "Тепер можна покласти предмети...", - "create.ponder.portable_storage_interface.text_7": "...або вивести їх із штуковини", - "create.ponder.portable_storage_interface.text_8": "Якщо на якийсь час припиниться обмін предметами – штуковина продовжить свій шлях", - - "create.ponder.portable_storage_interface_redstone.header": "Управління редстоуном", - "create.ponder.portable_storage_interface_redstone.text_1": "Редстоун сигнал запобігає включенню стаціонарного інтерфейсу", - - "create.ponder.powered_latch.header": "Управління сигналами за допомогою важеля живлення", - "create.ponder.powered_latch.text_1": "Живлюваний важіль - керований редстоуном важіль", - "create.ponder.powered_latch.text_2": "Сигнал позаду включає його", - "create.ponder.powered_latch.text_3": "Сигнали збоку назад вимикають його", - "create.ponder.powered_latch.text_4": "Живлені важелі можна перемикати і вручну", - - "create.ponder.powered_toggle_latch.header": "Управління сигналами за допомогою Важеля-перемикача.", - "create.ponder.powered_toggle_latch.text_1": "Живлюваний важіль-перемикач - важіль, що керується редстоуном", - "create.ponder.powered_toggle_latch.text_2": "Сигнали ззаду перемикають його стан", - "create.ponder.powered_toggle_latch.text_3": "...включають і знову вимикають", - "create.ponder.powered_toggle_latch.text_4": "Живлювані важелі-перемикачі також можна перемикати вручну", - - "create.ponder.pulse_extender.header": "UNLOCALIZED: Controlling signals using Pulse Extenders", - "create.ponder.pulse_extender.text_1": "UNLOCALIZED: Pulse Extenders can lengthen a signal passing through", - "create.ponder.pulse_extender.text_2": "UNLOCALIZED: They activate after a short delay...", - "create.ponder.pulse_extender.text_3": "UNLOCALIZED: ...and cool down for the configured duration", - "create.ponder.pulse_extender.text_4": "UNLOCALIZED: Using the mouse wheel, the discharge time can be configured", - "create.ponder.pulse_extender.text_5": "UNLOCALIZED: The configured duration can range up to 30 minutes", - - "create.ponder.pulse_repeater.header": "Управління сигналами за допомогою імпульсних повторювачів", - "create.ponder.pulse_repeater.text_1": "Імпульсні повторювачі вкоротять будь-який редстуон сигнал до одного імпульсу.", - "create.ponder.pulse_repeater.text_2": "UNLOCALIZED: Using the mouse wheel, the charge time can be configured", - "create.ponder.pulse_repeater.text_3": "UNLOCALIZED: Configured delays can range up to 30 minutes", - - "create.ponder.radial_chassis.header": "Приєднання блоків за допомогою Радіальних шасі", - "create.ponder.radial_chassis.text_1": "Радіальне шасі з'єднуються з ідентичними блоками шасі до ряду", - "create.ponder.radial_chassis.text_2": "Коли один блок переміщається штуковиною, решта рухається з ним", - "create.ponder.radial_chassis.text_3": "Бічні грані Радіального шасі можна зробити липкими", - "create.ponder.radial_chassis.text_4": "Натисніть ще раз, щоб зробити всі інші грані липкими", - "create.ponder.radial_chassis.text_5": "ПКМ порожній рукою крадучись, щоб прибрати слиз", - "create.ponder.radial_chassis.text_6": "Коли блок знаходиться поруч із липкою гранню...", - "create.ponder.radial_chassis.text_7": "...він приєднає всі доступні блоки в межах радіусу на цьому шарі", - "create.ponder.radial_chassis.text_8": "За допомогою ключа можна вказати точний радіус для цього шасі", - "create.ponder.radial_chassis.text_9": "Блоки не досягнуті жодною липкою гранню не прикріпляться", - - "create.ponder.redstone_contact.header": "Редстоун контакти", - "create.ponder.redstone_contact.text_1": "Контакти редстоун сигналу спрямовані один на одного випромінюватимуть редстоун сигнал", - "create.ponder.redstone_contact.text_2": "Також застосовно, коли один з них - частина штуковини, що рухається.", - - "create.ponder.redstone_link.header": "Використання бездротового передавача редстоун сигналу", - "create.ponder.redstone_link.text_1": "Бездротові передавачі редстоун сигналу можуть передавати редстоун сигнал без проводів", - "create.ponder.redstone_link.text_2": "ПКМ крадучись, щоб переключити режим приймача", - "create.ponder.redstone_link.text_3": "ПКМ ключем зробить те саме", - "create.ponder.redstone_link.text_4": "Приймачі випускають редстоун сигнал передавачів у 128 блоках", - "create.ponder.redstone_link.text_5": "Покладіть предмети у два слоти, щоб вказати частоту", - "create.ponder.redstone_link.text_6": "Передавачі лише однієї частоти можуть повідомлятись", - - "create.ponder.rope_pulley.header": "Переміщення структур за допомогою Лебідки", - "create.ponder.rope_pulley.text_1": "Лебідки можуть рухати блоки вертикально при подачі обертання", - "create.ponder.rope_pulley.text_2": "Напрямок та швидкість руху залежать від вихідного обертання", - - "create.ponder.rope_pulley_attachment.header": "Переміщення Лебідок, як частин штуковини", - "create.ponder.rope_pulley_attachment.text_1": "Коли лебідки переміщуються штуковиною...", - "create.ponder.rope_pulley_attachment.text_2": "...їхня приєднана структура рухається з ними", - "create.ponder.rope_pulley_attachment.text_3": "Враховуйте, що лебідки можна рухати тільки доки вони простоюють", - - "create.ponder.rope_pulley_modes.header": "Режими руху Лебідки", - "create.ponder.rope_pulley_modes.text_1": "Коли лебідка зупиняється, зрушена структура назад стає блоками", - "create.ponder.rope_pulley_modes.text_2": "Можна налаштувати її так, щоб структура ніколи не ставала блоками або лише на початковій позиції", - - "create.ponder.rose_quartz_lamp.header": "UNLOCALIZED: Rose Quartz Lamps", - "create.ponder.rose_quartz_lamp.text_1": "UNLOCALIZED: Rose Quartz Lamps activate on a Redstone signal", - "create.ponder.rose_quartz_lamp.text_2": "UNLOCALIZED: They will continue to emit redstone power afterwards", - "create.ponder.rose_quartz_lamp.text_3": "UNLOCALIZED: When multiple lamps are arranged in a group...", - "create.ponder.rose_quartz_lamp.text_4": "UNLOCALIZED: ...activating a Lamp will focus the signal to it, deactivating all others", - "create.ponder.rose_quartz_lamp.text_5": "UNLOCALIZED: Comparators output based on the distance to a powered lamp", - "create.ponder.rose_quartz_lamp.text_6": "UNLOCALIZED: The Lamps can also be toggled manually using a Wrench", - - "create.ponder.rotation_speed_controller.header": "Використання Регулятора швидкості обертання", - "create.ponder.rotation_speed_controller.text_1": "Регулятори шв. обертання передають обертання від своїх осей на Велику шестерню вище за них", - "create.ponder.rotation_speed_controller.text_2": "Можна налаштувати швидкість, що передається за допомогою прокручування по відповідному місцю збоку", - - "create.ponder.sail.header": "Складання Млинів за допомогою вітрил.", - "create.ponder.sail.text_1": "Вітрила - зручні блоки для створення млинів", - "create.ponder.sail.text_2": "Вони будуть прикріплюватися до блоків та один до одного без використання суперклею чи блоків шасі.", - "create.ponder.sail.text_3": "ПКМ барвником, щоб пофарбувати їх", - "create.ponder.sail.text_4": "ПКМ ножицями, щоб перетворити їх знову на раму", - - "create.ponder.sail_frame.header": "Складання Млинів за допомогою Рам вітрил.", - "create.ponder.sail_frame.text_1": "Рами вітрил - зручні блоки для створення млинів", - "create.ponder.sail_frame.text_2": "Вони будуть прикріплюватися до блоків та один до одного без використання суперклею чи блоків шасі.", - - "create.ponder.sequenced_gearshift.header": "Керування швидкістю обертання за допомогою Послідовного перемикача передач", - "create.ponder.sequenced_gearshift.text_1": "Посл. перем. передач передає обертання за тимчасовим списком інструкцій", - "create.ponder.sequenced_gearshift.text_2": "ПКМ, щоб відкрити інтерфейс налаштування", - "create.ponder.sequenced_gearshift.text_3": "При отриманні Редстоуна сигналу, він почне виконувати задані інструкції", - "create.ponder.sequenced_gearshift.text_4": "По завершенню він чекатиме наступного Редстоуна сигналу і почне спочатку", - "create.ponder.sequenced_gearshift.text_5": "Редстоун компаратор можна використовувати для зчитування прогресу", - - "create.ponder.shaft.header": "Передача обертання за допомогою Валів", - "create.ponder.shaft.text_1": "Вали передають обертання прямою", - - "create.ponder.shaft_casing.header": "Обрамлення Валів", - "create.ponder.shaft_casing.text_1": "Латунний або андезитовий корпус можна використовувати для декорації валів.", - - "create.ponder.smart_chute.header": "Фільтрації предметів за допомогою Розумних жолобів", - "create.ponder.smart_chute.text_1": "Розумні жолоби - вертикальні жолоби з додатковим контролем", - "create.ponder.smart_chute.text_2": "Предмети у слоті фільтра уточнюють, що вони можуть забирати та передавати", - "create.ponder.smart_chute.text_3": "Використовуйте Колесо Миші для уточнення розміру стака, що забирається.", - "create.ponder.smart_chute.text_4": "Редстоун сигнал вимикає їх", - - "create.ponder.smart_pipe.header": "Управління рідинним потоком за допомогою Розумних труб", - "create.ponder.smart_pipe.text_1": "Розумні труби можуть допомогти керувати потоками за типами рідин", - "create.ponder.smart_pipe.text_2": "Розміщені безпосередньо біля джерела, вони можуть вказувати тип видобутої рідини", - "create.ponder.smart_pipe.text_3": "Просто натисніть ПКМ на слоті фільтра з будь-яким предметом, що містить потрібну рідину", - "create.ponder.smart_pipe.text_4": "І при розміщенні глибше по мережі труб розумні труби пропускатимуть лише відповідні рідини.", - - "create.ponder.speedometer.header": "Моніторинг Кінетичної інформації за допомогою Спідометра", - "create.ponder.speedometer.text_1": "Спідометри відображають поточну швидкість приєднаних компонентів", - "create.ponder.speedometer.text_2": "При носінні Інженерних окулярів гравець може отримати більш повну інформацію від приладу", - "create.ponder.speedometer.text_3": "Компаратори можуть випромінювати аналоговий Редстоун сигнал щодо вимірювань спідометра", - - "create.ponder.spout_filling.header": "Наповнення предметів за допомогою дозатора", - "create.ponder.spout_filling.text_1": "Дозатор може заповнювати відповідні предмети, розташовані під ним.", - "create.ponder.spout_filling.text_2": "До вмісту дозатора неможливо отримати доступ вручну.", - "create.ponder.spout_filling.text_3": "Натомість можна використовувати труби для подачі в нього рідин", - "create.ponder.spout_filling.text_4": "Наповнювані предмети можуть бути розміщені на депо під дозатором", - "create.ponder.spout_filling.text_5": "Коли предмети подаються конвеєром...", - "create.ponder.spout_filling.text_6": "Дозатор буде утримувати та обробляти їх автоматично", - - "create.ponder.stabilized_bearings.header": "Стабілізація Штуковин", - "create.ponder.stabilized_bearings.text_1": "Коли Механічні підшипники є частиною структури, що рухається...", - "create.ponder.stabilized_bearings.text_2": "...вони намагатимуться триматися рівно", - "create.ponder.stabilized_bearings.text_3": "Знову ж таки, підшипники приєднують блоки перед ними", - "create.ponder.stabilized_bearings.text_4": "І в результаті ціла підструктура триматиметься рівно", - - "create.ponder.steam_engine.header": "UNLOCALIZED: Setting up Steam Engines", - "create.ponder.steam_engine.text_1": "UNLOCALIZED: Steam Engines can be placed on a Fluid Tank", - "create.ponder.steam_engine.text_10": "UNLOCALIZED: Lvl 4", - "create.ponder.steam_engine.text_11": "UNLOCALIZED: 4 Engines", - "create.ponder.steam_engine.text_12": "UNLOCALIZED: Lvl 8", - "create.ponder.steam_engine.text_13": "UNLOCALIZED: 8 Engines", - "create.ponder.steam_engine.text_2": "UNLOCALIZED: Clicking the engine with a Shaft creates the Kinetic Output", - "create.ponder.steam_engine.text_3": "UNLOCALIZED: With sufficient Heat, Water and Boiler space...", - "create.ponder.steam_engine.text_4": "UNLOCALIZED: ...they will generate Rotational Force", - "create.ponder.steam_engine.text_5": "UNLOCALIZED: The minimal setup requires 4 Fluid Tanks", - "create.ponder.steam_engine.text_6": "UNLOCALIZED: With the help of Blaze Burners, the power output can be increased", - "create.ponder.steam_engine.text_7": "UNLOCALIZED: Higher power levels require more Water, Size and Heat", - "create.ponder.steam_engine.text_8": "UNLOCALIZED: The boiler's current power level can be inspected with Engineer's Goggles", - "create.ponder.steam_engine.text_9": "UNLOCALIZED: With each added power level, an additional Engine can output at full capacity", - - "create.ponder.steam_whistle.header": "UNLOCALIZED: Setting up Steam Whistles", - "create.ponder.steam_whistle.text_1": "UNLOCALIZED: Steam Whistles can be placed on a Fluid Tank", - "create.ponder.steam_whistle.text_2": "UNLOCALIZED: If the tank receives sufficient heat...", - "create.ponder.steam_whistle.text_3": "UNLOCALIZED: ...the Whistle will play a note when activated", - "create.ponder.steam_whistle.text_4": "UNLOCALIZED: Use a Whistle item on the block to lower its pitch", - "create.ponder.steam_whistle.text_5": "UNLOCALIZED: Cycle between three different octaves using a Wrench", - "create.ponder.steam_whistle.text_6": "UNLOCALIZED: Engineer's Goggles can help to find out the current pitch of a Whistle", - - "create.ponder.sticker.header": "Прикріплення блоків за допомогою Липучки", - "create.ponder.sticker.text_1": "Липучки ідеально підходять для Редстоун-керованого приєднання блоків", - "create.ponder.sticker.text_2": "При отриманні сигналу вони перемикають свій стан", - "create.ponder.sticker.text_3": "Якщо він тепер рухається у штуковині, то блок рухатиметься з ним", - "create.ponder.sticker.text_4": "При повторному перемиканні блок більше не буде прикріплено", - - "create.ponder.stressometer.header": "Моніторинг кінетичної інформації за допомогою Стресометра", - "create.ponder.stressometer.text_1": "Стресометр відображає поточне допустиме навантаження приєднаної кінетичної мережі", - "create.ponder.stressometer.text_2": "При носінні Інженерних окулярів гравець може отримати більш повну інформацію від приладу", - "create.ponder.stressometer.text_3": "Компаратори можуть випускати аналоговий редстоун сигнал щодо вимірювань стресометра", - - "create.ponder.super_glue.header": "Приєднання блоків за допомогою Суперклею", - "create.ponder.super_glue.text_1": "Суперклей можна використовувати між двома будь-якими блоками", - "create.ponder.super_glue.text_2": "Скріплені блоки рухатимуться разом при складанні в штуковину", - "create.ponder.super_glue.text_3": "Коли ви тримаєте суперклей у другій руці...", - "create.ponder.super_glue.text_4": "...додані блоки будуть відразу приклеєні до грані, на яку вони були поставлені", - "create.ponder.super_glue.text_5": "Суперклей можна видалити лівим кліком", - "create.ponder.super_glue.text_6": "UNLOCALIZED: Blocks hanging on others usually do not require glue", - - "create.ponder.track_chunks.header": "UNLOCALIZED: Traversing unloaded Chunks", - "create.ponder.track_chunks.text_1": "UNLOCALIZED: Tracks stay functional outside of loaded chunks", - "create.ponder.track_chunks.text_2": "UNLOCALIZED: Trains will travel through inactive sections of the world without issue", - "create.ponder.track_chunks.text_3": "UNLOCALIZED: They will still stop at stations or red signals", - "create.ponder.track_chunks.text_4": "UNLOCALIZED: However, Drills and other on-board machines will not operate", - "create.ponder.track_chunks.text_5": "UNLOCALIZED: Once near a Player, the train will re-appear", - - "create.ponder.track_observer.header": "UNLOCALIZED: Detecting Trains", - "create.ponder.track_observer.text_1": "UNLOCALIZED: Select a Train Track then place the Observer nearby", - "create.ponder.track_observer.text_2": "UNLOCALIZED: The Observer will detect any Trains passing over the marker", - "create.ponder.track_observer.text_3": "UNLOCALIZED: Observers can be filtered to activate for matching cargo", - - "create.ponder.track_placement.header": "UNLOCALIZED: Placing Train Tracks", - "create.ponder.track_placement.text_1": "UNLOCALIZED: A new type of rail designed for Train Contraptions", - "create.ponder.track_placement.text_2": "UNLOCALIZED: To place rows of track in bulk, click on an existing track", - "create.ponder.track_placement.text_3": "UNLOCALIZED: Then place or select a second track", - "create.ponder.track_placement.text_4": "UNLOCALIZED: Tracks can also be placed as turns or slopes", - "create.ponder.track_placement.text_5": "UNLOCALIZED: When connecting, tracks will try to make each turn equally sized", - "create.ponder.track_placement.text_6": "UNLOCALIZED: Holding the sprint key while connecting...", - "create.ponder.track_placement.text_7": "UNLOCALIZED: ...will create the longest fitting bend instead", - "create.ponder.track_placement.text_8": "UNLOCALIZED: Materials in the off-hand will be paved under tracks automatically", - - "create.ponder.track_portal.header": "UNLOCALIZED: Tracks and the Nether", - "create.ponder.track_portal.text_1": "UNLOCALIZED: Tracks placed up against a nether portal...", - "create.ponder.track_portal.text_2": "UNLOCALIZED: ...will attempt to create a paired track on the other side", - "create.ponder.track_portal.text_3": "UNLOCALIZED: Trains on this track are now able to travel across dimensions", - - "create.ponder.train_assembly.header": "UNLOCALIZED: Assembling Trains", - "create.ponder.train_assembly.text_1": "UNLOCALIZED: Select a Train Track then place the Station nearby", - "create.ponder.train_assembly.text_10": "UNLOCALIZED: Every Train requires Train Controls on board", - "create.ponder.train_assembly.text_11": "UNLOCALIZED: An optional second one allows departure from Stations in both directions", - "create.ponder.train_assembly.text_12": "UNLOCALIZED: Open the Station UI and confirm the Assembly process", - "create.ponder.train_assembly.text_13": "UNLOCALIZED: Trains can be disassembled back into blocks at stations only", - "create.ponder.train_assembly.text_14": "UNLOCALIZED: When used on a station, maps will add a labeled marker at the location", - "create.ponder.train_assembly.text_15": "UNLOCALIZED: Assembled Trains can be relocated to nearby Tracks using the Wrench", - "create.ponder.train_assembly.text_2": "UNLOCALIZED: Stations are the Waypoints of your Track Network", - "create.ponder.train_assembly.text_3": "UNLOCALIZED: To create a new Train, open the UI and switch to Assembly Mode", - "create.ponder.train_assembly.text_4": "UNLOCALIZED: During Assembly no scheduled trains will approach this station", - "create.ponder.train_assembly.text_5": "UNLOCALIZED: Create new bogeys by using Train Casing on Tracks", - "create.ponder.train_assembly.text_6": "UNLOCALIZED: Click the track again to cycle between bogey designs", - "create.ponder.train_assembly.text_7": "UNLOCALIZED: Attach blocks with the help of Super Glue", - "create.ponder.train_assembly.text_8": "UNLOCALIZED: Assembled Trains will move faster if they can find fuel in assembled chests or barrels", - "create.ponder.train_assembly.text_9": "UNLOCALIZED: Fuel stored in Vaults will not be consumed by the train", - - "create.ponder.train_controls.header": "UNLOCALIZED: Controlling Trains", - "create.ponder.train_controls.text_1": "UNLOCALIZED: Train Controls are required on every train contraption", - "create.ponder.train_controls.text_2": "UNLOCALIZED: Once assembled, right-click the block to start driving", - "create.ponder.train_controls.text_3": "UNLOCALIZED: Accelerate and steer the Train using movement keybinds", - "create.ponder.train_controls.text_4": "UNLOCALIZED: If desired, the top speed can be fine-tuned using the mouse wheel", - "create.ponder.train_controls.text_5": "UNLOCALIZED: Hold space to approach a nearby Station", - "create.ponder.train_controls.text_6": "UNLOCALIZED: Trains can only be disassembled back into blocks at Stations", - "create.ponder.train_controls.text_7": "UNLOCALIZED: Assembled Whistles can be activated with the sprint key", - "create.ponder.train_controls.text_8": "UNLOCALIZED: Sneak or click again to stop controlling the Train", - - "create.ponder.train_schedule.header": "UNLOCALIZED: Using Train Schedules", - "create.ponder.train_schedule.text_1": "UNLOCALIZED: Schedules allow Trains to be controlled by other Drivers", - "create.ponder.train_schedule.text_2": "UNLOCALIZED: Right-click with the item in hand to open its Interface", - "create.ponder.train_schedule.text_3": "UNLOCALIZED: Once programmed, the Schedule can be handed off to a Train Driver", - "create.ponder.train_schedule.text_4": "UNLOCALIZED: Any mob or blaze burner sitting in front of Train Controls is an eligible conductor", - "create.ponder.train_schedule.text_5": "UNLOCALIZED: Creatures on a lead can be given their seat more conveniently", - "create.ponder.train_schedule.text_6": "UNLOCALIZED: Schedules can be retrieved from Drivers at any moment", - - "create.ponder.train_signal_placement.header": "UNLOCALIZED: Placing Train Signals", - "create.ponder.train_signal_placement.text_1": "UNLOCALIZED: Select a Train Track then place the Signal nearby", - "create.ponder.train_signal_placement.text_2": "UNLOCALIZED: Signals control the flow of Trains not driven by players", - "create.ponder.train_signal_placement.text_3": "UNLOCALIZED: Scheduled Trains will never cross signals in the opposite direction", - "create.ponder.train_signal_placement.text_4": "UNLOCALIZED: ...unless a second signal is added facing the opposite way.", - "create.ponder.train_signal_placement.text_5": "UNLOCALIZED: Nixie tubes can be attached to make a signal's lights more visible", - - "create.ponder.train_signal_redstone.header": "UNLOCALIZED: Signals & Redstone", - "create.ponder.train_signal_redstone.text_1": "UNLOCALIZED: Signals can be forced red by a redstone signal", - "create.ponder.train_signal_redstone.text_2": "UNLOCALIZED: Reversely, red signals emit a comparator output", - - "create.ponder.train_signal_signaling.header": "UNLOCALIZED: Collision Prevention with Signals", - "create.ponder.train_signal_signaling.text_1": "UNLOCALIZED: Train Signals divide a track into segments", - "create.ponder.train_signal_signaling.text_2": "UNLOCALIZED: If a Segment is occupied, no other Trains will be allowed entry", - "create.ponder.train_signal_signaling.text_3": "UNLOCALIZED: Thus, each Segment will contain only one Train at a time", - "create.ponder.train_signal_signaling.text_4": "UNLOCALIZED: A second Signal mode is available via the Wrench", - "create.ponder.train_signal_signaling.text_5": "UNLOCALIZED: Segments of a brass signal usually lead into standard signals", - "create.ponder.train_signal_signaling.text_6": "UNLOCALIZED: This special Signal can stop trains under a second condition", - "create.ponder.train_signal_signaling.text_7": "UNLOCALIZED: It will stop Trains, which, upon entering...", - "create.ponder.train_signal_signaling.text_8": "UNLOCALIZED: ...would not be able to leave the Segment immediately", - "create.ponder.train_signal_signaling.text_9": "UNLOCALIZED: This helps keeping queued Trains out of a busy Segment", - - "create.ponder.valve_handle.header": "Генерації сили обертання за допомогою Вентилів", - "create.ponder.valve_handle.text_1": "Гравці можуть використовувати вентилі для застосування сили обертання вручну", - "create.ponder.valve_handle.text_2": "Тримайте ПКМ для обертання його проти Годинникової стрілки", - "create.ponder.valve_handle.text_3": "Швидкість, що передається ними, повільна і точна", - "create.ponder.valve_handle.text_4": "Тримайте ПКМ крадькома для обертання його за Годинниковою стрілкою", - "create.ponder.valve_handle.text_5": "Вентилі можна фарбувати в естетичних цілях", - - "create.ponder.valve_pipe.header": "Управління потоком рідини за допомогою вентилів", - "create.ponder.valve_pipe.text_1": "Рідинні вентилі допомагають контролювати поширення рідин по мережах труб", - "create.ponder.valve_pipe.text_2": "Їх вхідний вал контролює, чи дозволено подачу рідини в даний момент.", - "create.ponder.valve_pipe.text_3": "При обертанні в напрямку відкриття клапан відкривається", - "create.ponder.valve_pipe.text_4": "Його можна знову закрити, змінивши напрямок вхідного обертання", - - "create.ponder.water_wheel.header": "Генерації сили обертання за допомогою Водяних коліс", - "create.ponder.water_wheel.text_1": "Водяні колеса беруть силу сусідніх потоків води", - "create.ponder.water_wheel.text_2": "Чим більше сторін запитано, тим швидше обертатиметься Водяне колесо", - "create.ponder.water_wheel.text_3": "Лопаті колеса повинні бути спрямовані проти течії", - "create.ponder.water_wheel.text_4": "Спрямована в протилежний бік, вона не буде такою ж ефективною", - - "create.ponder.weighted_ejector.header": "Використання Зважених катапульт", - "create.ponder.weighted_ejector.text_1": "ПКМ крадучись і тримаючи катапульту, щоб вибрати місце мети", - "create.ponder.weighted_ejector.text_10": "Тепер вона обмежена цим розміром стака і активуватиметься лише тоді, коли утримуваний стак досягне цієї кількості.", - "create.ponder.weighted_ejector.text_11": "Інші сутності, вставши на катапульту, завжди активуватимуть її", - "create.ponder.weighted_ejector.text_2": "Встановлена катапульта запускатиме об'єкти до зазначеного місця", - "create.ponder.weighted_ejector.text_3": "Відповідна мета може бути на будь-якій дистанції та висоті в радіусі", - "create.ponder.weighted_ejector.text_4": "Однак вони не можуть бути збоку", - "create.ponder.weighted_ejector.text_5": "Якщо не було вибрано відповідної мети, вона цілитиметься в блок перед нею", - "create.ponder.weighted_ejector.text_6": "Надайте силу обертання, щоб зарядити її", - "create.ponder.weighted_ejector.text_7": "Встановлення предметів на катапульту викликають її спрацювання", - "create.ponder.weighted_ejector.text_8": "Якщо інвентар обраний метою, то катапульта чекатиме, доки у ньому з'явиться місце.", - "create.ponder.weighted_ejector.text_9": "За допомогою ключа можна налаштувати необхідний розмір стака", - - "create.ponder.weighted_ejector_redstone.header": "Управління Зваженими катапультами редстоуном", - "create.ponder.weighted_ejector_redstone.text_1": "При подачі редстоун сигналу катапульти не активуватимуться", - "create.ponder.weighted_ejector_redstone.text_2": "Крім того, спостерігачі можуть визначити, коли катапульти спрацьовують", - - "create.ponder.weighted_ejector_tunnel.header": "Поділ стаків предметів за допомогою Зважених катапульт", - "create.ponder.weighted_ejector_tunnel.text_1": "Об'єднані з Латунними тунелями катапульти можуть ділити стаки предметів за певною кількістю.", - "create.ponder.weighted_ejector_tunnel.text_2": "Спочатку налаштуйте латунний тунель на «Переважно найближче», щоб пріоритизувати вихід збоку", - "create.ponder.weighted_ejector_tunnel.text_3": "Розмір стака, встановлений на катапульті, тепер визначає кількість, що відокремлюється.", - "create.ponder.weighted_ejector_tunnel.text_4": "Поки що новий стак потрібної кількості лежить на бічному виході...", - "create.ponder.weighted_ejector_tunnel.text_5": "...залишок продовжить свій шлях", - - "create.ponder.windmill_source.header": "Генерації сили обертання за допомогою Підшипників вітряка", - "create.ponder.windmill_source.text_1": "Підшипники вітряного млина прикріплюються до блоків перед ними", - "create.ponder.windmill_source.text_2": "Якщо прикріплено достатньо парусоподібних блоків, він може стати млином", - "create.ponder.windmill_source.text_3": "Активований за допомогою ПКМ, Підшипник вітряного млина почне виробляти силу обертання", - "create.ponder.windmill_source.text_4": "Кількість вітрил визначає швидкість обертання", - "create.ponder.windmill_source.text_5": "Використовуйте ключ, щоб налаштувати напрямок обертання", - "create.ponder.windmill_source.text_6": "ПКМ по підшипнику у будь-який час, щоб зупинити його та відредагувати структуру", - "create.ponder.windmill_source.text_7": "UNLOCALIZED: Right-click the Bearing anytime to stop and edit the Structure again", - - "create.ponder.windmill_structure.header": "Пристосування вітряка", - "create.ponder.windmill_structure.text_1": "Будь-яка споруда може вважатися дійсним вітряком, якщо вона містить принаймні 8 вітрильних блоків.", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json deleted file mode 100644 index cd5d6ab965..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 1", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "金合欢木窗户", - "block.create.acacia_window_pane": "金合欢木窗户板", - "block.create.adjustable_chain_gearshift": "可调节链式传动箱", - "block.create.analog_lever": "模拟拉杆", - "block.create.andesite_belt_funnel": "安山岩传送带漏斗", - "block.create.andesite_casing": "安山机壳", - "block.create.andesite_encased_cogwheel": "安山齿轮箱", - "block.create.andesite_encased_large_cogwheel": "安山大齿轮箱", - "block.create.andesite_encased_shaft": "安山传动杆箱", - "block.create.andesite_funnel": "安山岩漏斗", - "block.create.andesite_ladder": "安山梯子", - "block.create.andesite_pillar": "安山岩柱", - "block.create.andesite_tunnel": "安山岩隧道", - "block.create.asurine": "皓蓝石", - "block.create.asurine_pillar": "皓蓝石柱", - "block.create.basin": "工作盆", - "block.create.belt": "传送带", - "block.create.birch_window": "白桦木窗户", - "block.create.birch_window_pane": "白桦木窗户板", - "block.create.black_nixie_tube": "黑色辉光管", - "block.create.black_sail": "黑色风帆", - "block.create.black_seat": "黑色坐垫", - "block.create.black_toolbox": "黑色工具箱", - "block.create.black_valve_handle": "黑色阀门手轮", - "block.create.blaze_burner": "烈焰人燃烧室", - "block.create.blue_nixie_tube": "蓝色辉光管", - "block.create.blue_sail": "蓝色风帆", - "block.create.blue_seat": "蓝色坐垫", - "block.create.blue_toolbox": "蓝色工具箱", - "block.create.blue_valve_handle": "蓝色阀门手轮", - "block.create.brass_belt_funnel": "黄铜传送带漏斗", - "block.create.brass_block": "黄铜块", - "block.create.brass_casing": "黄铜机壳", - "block.create.brass_encased_cogwheel": "黄铜齿轮箱", - "block.create.brass_encased_large_cogwheel": "黄铜大齿轮箱", - "block.create.brass_encased_shaft": "黄铜传动杆箱", - "block.create.brass_funnel": "黄铜漏斗", - "block.create.brass_ladder": "黄铜梯子", - "block.create.brass_tunnel": "黄铜隧道", - "block.create.brown_nixie_tube": "棕色辉光管", - "block.create.brown_sail": "棕色风帆", - "block.create.brown_seat": "棕色坐垫", - "block.create.brown_toolbox": "棕色工具箱", - "block.create.brown_valve_handle": "棕色阀门手轮", - "block.create.calcite_pillar": "方解石柱", - "block.create.cart_assembler": "矿车装配站", - "block.create.chocolate": "巧克力", - "block.create.chute": "溜槽", - "block.create.clockwork_bearing": "发条轴承", - "block.create.clutch": "离合器", - "block.create.cogwheel": "齿轮", - "block.create.content_observer": "物品侦测器", - "block.create.controller_rail": "控制铁轨", - "block.create.controls": "列车驾驶台", - "block.create.copper_backtank": "铜背罐", - "block.create.copper_casing": "铜机壳", - "block.create.copper_ladder": "铜梯子", - "block.create.copper_shingle_slab": "铜砖瓦台阶", - "block.create.copper_shingle_stairs": "铜砖瓦楼梯", - "block.create.copper_shingles": "铜砖瓦", - "block.create.copper_tile_slab": "铜瓦台阶", - "block.create.copper_tile_stairs": "铜瓦楼梯", - "block.create.copper_tiles": "铜瓦", - "block.create.copper_valve_handle": "铜阀门手轮", - "block.create.creative_crate": "创造板条箱", - "block.create.creative_fluid_tank": "创造流体储罐", - "block.create.creative_motor": "创造马达", - "block.create.crimsite": "绯红岩", - "block.create.crimsite_pillar": "绯红岩柱", - "block.create.crimson_window": "绯红木窗户", - "block.create.crimson_window_pane": "绯红木窗户板", - "block.create.crushing_wheel": "粉碎轮", - "block.create.crushing_wheel_controller": "粉碎轮控制器", - "block.create.cuckoo_clock": "布谷鸟闹钟", - "block.create.cut_andesite": "切制安山岩", - "block.create.cut_andesite_brick_slab": "切制安山岩砖块台阶", - "block.create.cut_andesite_brick_stairs": "切制安山岩砖块楼梯", - "block.create.cut_andesite_brick_wall": "切制安山岩砖块墙", - "block.create.cut_andesite_bricks": "切制安山岩砖块", - "block.create.cut_andesite_slab": "切制安山岩台阶", - "block.create.cut_andesite_stairs": "切制安山岩楼梯", - "block.create.cut_andesite_wall": "切制安山岩墙", - "block.create.cut_asurine": "切制皓蓝石", - "block.create.cut_asurine_brick_slab": "切制皓蓝石砖块台阶", - "block.create.cut_asurine_brick_stairs": "切制皓蓝石砖块楼梯", - "block.create.cut_asurine_brick_wall": "切制皓蓝石砖块墙", - "block.create.cut_asurine_bricks": "切制皓蓝石砖块", - "block.create.cut_asurine_slab": "切制皓蓝石台阶", - "block.create.cut_asurine_stairs": "切制皓蓝石楼梯", - "block.create.cut_asurine_wall": "切制皓蓝石墙", - "block.create.cut_calcite": "切制方解石", - "block.create.cut_calcite_brick_slab": "切制方解石砖块台阶", - "block.create.cut_calcite_brick_stairs": "切制方解石砖块楼梯", - "block.create.cut_calcite_brick_wall": "切制方解石砖块墙", - "block.create.cut_calcite_bricks": "切制方解石砖块", - "block.create.cut_calcite_slab": "切制方解石台阶", - "block.create.cut_calcite_stairs": "切制方解石楼梯", - "block.create.cut_calcite_wall": "切制方解石墙", - "block.create.cut_crimsite": "切制绯红岩", - "block.create.cut_crimsite_brick_slab": "切制绯红岩砖块台阶", - "block.create.cut_crimsite_brick_stairs": "切制绯红岩砖块楼梯", - "block.create.cut_crimsite_brick_wall": "切制绯红岩砖块墙", - "block.create.cut_crimsite_bricks": "切制绯红岩砖块", - "block.create.cut_crimsite_slab": "切制绯红岩台阶", - "block.create.cut_crimsite_stairs": "切制绯红岩楼梯", - "block.create.cut_crimsite_wall": "切制绯红岩墙", - "block.create.cut_deepslate": "切制深板岩", - "block.create.cut_deepslate_brick_slab": "切制深板岩砖块台阶", - "block.create.cut_deepslate_brick_stairs": "切制深板岩砖块楼梯", - "block.create.cut_deepslate_brick_wall": "切制深板岩砖块墙", - "block.create.cut_deepslate_bricks": "切制深板岩砖块", - "block.create.cut_deepslate_slab": "切制深板岩台阶", - "block.create.cut_deepslate_stairs": "切制深板岩楼梯", - "block.create.cut_deepslate_wall": "切制深板岩墙", - "block.create.cut_diorite": "切制闪长岩", - "block.create.cut_diorite_brick_slab": "切制闪长岩砖块台阶", - "block.create.cut_diorite_brick_stairs": "切制闪长岩砖块楼梯", - "block.create.cut_diorite_brick_wall": "切制闪长岩砖块墙", - "block.create.cut_diorite_bricks": "切制闪长岩砖块", - "block.create.cut_diorite_slab": "切制闪长岩台阶", - "block.create.cut_diorite_stairs": "切制闪长岩楼梯", - "block.create.cut_diorite_wall": "切制闪长岩墙", - "block.create.cut_dripstone": "切制滴水石", - "block.create.cut_dripstone_brick_slab": "切制滴水石砖块台阶", - "block.create.cut_dripstone_brick_stairs": "切制滴水石砖块楼梯", - "block.create.cut_dripstone_brick_wall": "切制滴水石砖块墙", - "block.create.cut_dripstone_bricks": "切制滴水石砖块", - "block.create.cut_dripstone_slab": "切制滴水石台阶", - "block.create.cut_dripstone_stairs": "切制滴水石楼梯", - "block.create.cut_dripstone_wall": "切制滴水石墙", - "block.create.cut_granite": "切制花岗岩", - "block.create.cut_granite_brick_slab": "切制花岗岩砖块台阶", - "block.create.cut_granite_brick_stairs": "切制花岗岩砖块楼梯", - "block.create.cut_granite_brick_wall": "切制花岗岩砖块墙", - "block.create.cut_granite_bricks": "切制花岗岩砖块", - "block.create.cut_granite_slab": "切制花岗岩台阶", - "block.create.cut_granite_stairs": "切制花岗岩楼梯", - "block.create.cut_granite_wall": "切制花岗岩墙", - "block.create.cut_limestone": "切制石灰岩", - "block.create.cut_limestone_brick_slab": "切制石灰岩砖块台阶", - "block.create.cut_limestone_brick_stairs": "切制石灰岩砖块楼梯", - "block.create.cut_limestone_brick_wall": "切制石灰岩砖块墙", - "block.create.cut_limestone_bricks": "切制石灰岩砖块", - "block.create.cut_limestone_slab": "切制石灰岩台阶", - "block.create.cut_limestone_stairs": "切制石灰岩楼梯", - "block.create.cut_limestone_wall": "切制石灰岩墙", - "block.create.cut_ochrum": "切制赭金砂", - "block.create.cut_ochrum_brick_slab": "切制赭金砂砖块台阶", - "block.create.cut_ochrum_brick_stairs": "切制赭金砂砖块楼梯", - "block.create.cut_ochrum_brick_wall": "切制赭金砂砖块墙", - "block.create.cut_ochrum_bricks": "切制赭金砂砖块", - "block.create.cut_ochrum_slab": "切制赭金砂台阶", - "block.create.cut_ochrum_stairs": "切制赭金砂楼梯", - "block.create.cut_ochrum_wall": "切制赭金砂墙", - "block.create.cut_scorchia": "切制焦黑熔渣", - "block.create.cut_scorchia_brick_slab": "切制焦黑熔渣砖块台阶", - "block.create.cut_scorchia_brick_stairs": "切制焦黑熔渣砖块楼梯", - "block.create.cut_scorchia_brick_wall": "切制焦黑熔渣砖块墙", - "block.create.cut_scorchia_bricks": "切制焦黑熔渣砖块", - "block.create.cut_scorchia_slab": "切制焦黑熔渣台阶", - "block.create.cut_scorchia_stairs": "切制焦黑熔渣楼梯", - "block.create.cut_scorchia_wall": "切制焦黑熔渣墙", - "block.create.cut_scoria": "切制熔渣", - "block.create.cut_scoria_brick_slab": "切制熔渣砖块台阶", - "block.create.cut_scoria_brick_stairs": "切制熔渣砖块楼梯", - "block.create.cut_scoria_brick_wall": "切制熔渣砖块墙", - "block.create.cut_scoria_bricks": "切制熔渣砖块", - "block.create.cut_scoria_slab": "切制熔渣台阶", - "block.create.cut_scoria_stairs": "切制熔渣楼梯", - "block.create.cut_scoria_wall": "切制熔渣墙", - "block.create.cut_tuff": "切制凝灰岩", - "block.create.cut_tuff_brick_slab": "切制凝灰岩砖块台阶", - "block.create.cut_tuff_brick_stairs": "切制凝灰岩砖块楼梯", - "block.create.cut_tuff_brick_wall": "切制凝灰岩砖块墙", - "block.create.cut_tuff_bricks": "切制凝灰岩砖块", - "block.create.cut_tuff_slab": "切制凝灰岩台阶", - "block.create.cut_tuff_stairs": "切制凝灰岩楼梯", - "block.create.cut_tuff_wall": "切制凝灰岩墙", - "block.create.cut_veridium": "切制辉绿矿", - "block.create.cut_veridium_brick_slab": "切制辉绿矿砖块台阶", - "block.create.cut_veridium_brick_stairs": "切制辉绿矿砖块楼梯", - "block.create.cut_veridium_brick_wall": "切制辉绿矿砖块墙", - "block.create.cut_veridium_bricks": "切制辉绿矿砖块", - "block.create.cut_veridium_slab": "切制辉绿矿台阶", - "block.create.cut_veridium_stairs": "切制辉绿矿楼梯", - "block.create.cut_veridium_wall": "切制辉绿矿墙", - "block.create.cyan_nixie_tube": "青色辉光管", - "block.create.cyan_sail": "青色风帆", - "block.create.cyan_seat": "青色坐垫", - "block.create.cyan_toolbox": "青色工具箱", - "block.create.cyan_valve_handle": "青色阀门手轮", - "block.create.dark_oak_window": "深色橡木窗户", - "block.create.dark_oak_window_pane": "深色橡木窗户板", - "block.create.deepslate_pillar": "深板岩柱", - "block.create.deepslate_zinc_ore": "深层锌矿石", - "block.create.deployer": "机械手", - "block.create.depot": "置物台", - "block.create.diorite_pillar": "闪长岩柱", - "block.create.display_board": "翻牌显示器", - "block.create.display_link": "显示链接器", - "block.create.dripstone_pillar": "滴水石柱", - "block.create.encased_chain_drive": "链式传动箱", - "block.create.encased_fan": "鼓风机", - "block.create.encased_fluid_pipe": "流体管道箱", - "block.create.exposed_copper_shingle_slab": "斑驳的铜砖瓦台阶", - "block.create.exposed_copper_shingle_stairs": "斑驳的铜砖瓦楼梯", - "block.create.exposed_copper_shingles": "斑驳的铜砖瓦", - "block.create.exposed_copper_tile_slab": "斑驳的铜瓦台阶", - "block.create.exposed_copper_tile_stairs": "斑驳的铜瓦楼梯", - "block.create.exposed_copper_tiles": "斑驳的铜瓦", - "block.create.fake_track": "用于地图的轨道标记", - "block.create.fluid_pipe": "流体管道", - "block.create.fluid_tank": "流体储罐", - "block.create.fluid_valve": "流体阀门", - "block.create.flywheel": "飞轮", - "block.create.framed_glass": "边框玻璃", - "block.create.framed_glass_door": "边框玻璃门", - "block.create.framed_glass_pane": "边框玻璃板", - "block.create.framed_glass_trapdoor": "边框玻璃活板门", - "block.create.gantry_carriage": "起重机取物器", - "block.create.gantry_shaft": "起重机杆", - "block.create.gearbox": "十字齿轮箱", - "block.create.gearshift": "反转齿轮箱", - "block.create.glass_fluid_pipe": "玻璃流体管道", - "block.create.granite_pillar": "花岗岩柱", - "block.create.gray_nixie_tube": "灰色辉光管", - "block.create.gray_sail": "灰色风帆", - "block.create.gray_seat": "灰色坐垫", - "block.create.gray_toolbox": "灰色工具箱", - "block.create.gray_valve_handle": "灰色阀门手轮", - "block.create.green_nixie_tube": "绿色辉光管", - "block.create.green_sail": "绿色风帆", - "block.create.green_seat": "绿色坐垫", - "block.create.green_toolbox": "绿色工具箱", - "block.create.green_valve_handle": "绿色阀门手轮", - "block.create.hand_crank": "手摇曲柄", - "block.create.haunted_bell": "缠魂钟", - "block.create.honey": "蜂蜜", - "block.create.horizontal_framed_glass": "水平边框玻璃", - "block.create.horizontal_framed_glass_pane": "水平边框玻璃板", - "block.create.hose_pulley": "软管滑轮", - "block.create.item_drain": "分液池", - "block.create.item_vault": "物品保险库", - "block.create.jungle_window": "丛林木窗户", - "block.create.jungle_window_pane": "丛林木窗户板", - "block.create.large_bogey": "大转向架", - "block.create.large_cogwheel": "大齿轮", - "block.create.layered_andesite": "层叠安山岩", - "block.create.layered_asurine": "层叠皓蓝石", - "block.create.layered_calcite": "层叠方解石", - "block.create.layered_crimsite": "层叠绯红岩", - "block.create.layered_deepslate": "层叠深板岩", - "block.create.layered_diorite": "层叠闪长岩", - "block.create.layered_dripstone": "层叠滴水石", - "block.create.layered_granite": "层叠花岗岩", - "block.create.layered_limestone": "层叠石灰岩", - "block.create.layered_ochrum": "层叠赭金砂", - "block.create.layered_scorchia": "层叠焦黑熔渣", - "block.create.layered_scoria": "层叠熔渣", - "block.create.layered_tuff": "层叠凝灰岩", - "block.create.layered_veridium": "层叠辉绿矿", - "block.create.lectern_controller": "遥控器讲台", - "block.create.light_blue_nixie_tube": "淡蓝色辉光管", - "block.create.light_blue_sail": "淡蓝色风帆", - "block.create.light_blue_seat": "淡蓝色坐垫", - "block.create.light_blue_toolbox": "淡蓝色工具箱", - "block.create.light_blue_valve_handle": "淡蓝色阀门手轮", - "block.create.light_gray_nixie_tube": "淡灰色辉光管", - "block.create.light_gray_sail": "淡灰色风帆", - "block.create.light_gray_seat": "淡灰色坐垫", - "block.create.light_gray_toolbox": "淡灰色工具箱", - "block.create.light_gray_valve_handle": "淡灰色阀门手轮", - "block.create.lime_nixie_tube": "黄绿色辉光管", - "block.create.lime_sail": "黄绿色风帆", - "block.create.lime_seat": "黄绿色坐垫", - "block.create.lime_toolbox": "黄绿色工具箱", - "block.create.lime_valve_handle": "黄绿色阀门手轮", - "block.create.limestone": "石灰岩", - "block.create.limestone_pillar": "石灰岩柱", - "block.create.linear_chassis": "机壳底盘", - "block.create.lit_blaze_burner": "烈焰人燃烧室(已点燃)", - "block.create.magenta_nixie_tube": "品红色辉光管", - "block.create.magenta_sail": "品红色风帆", - "block.create.magenta_seat": "品红色坐垫", - "block.create.magenta_toolbox": "品红色工具箱", - "block.create.magenta_valve_handle": "品红色阀门手轮", - "block.create.mechanical_arm": "动力臂", - "block.create.mechanical_bearing": "动力轴承", - "block.create.mechanical_crafter": "动力合成器", - "block.create.mechanical_drill": "动力钻头", - "block.create.mechanical_harvester": "动力收割机", - "block.create.mechanical_mixer": "动力搅拌器", - "block.create.mechanical_piston": "动力活塞", - "block.create.mechanical_piston_head": "动力活塞头", - "block.create.mechanical_plough": "动力犁", - "block.create.mechanical_press": "动力辊压机", - "block.create.mechanical_pump": "动力泵", - "block.create.mechanical_saw": "动力锯", - "block.create.metal_bracket": "金属支架", - "block.create.metal_girder": "金属梁", - "block.create.metal_girder_encased_shaft": "金属梁包住的传动杆", - "block.create.millstone": "石磨", - "block.create.minecart_anchor": "矿车锚", - "block.create.mysterious_cuckoo_clock": "布谷鸟闹钟", - "block.create.nixie_tube": "辉光管", - "block.create.nozzle": "分散网", - "block.create.oak_window": "橡木窗户", - "block.create.oak_window_pane": "橡木窗户板", - "block.create.ochrum": "赭金砂", - "block.create.ochrum_pillar": "赭金砂柱", - "block.create.orange_sail": "橙色风帆", - "block.create.orange_seat": "橙色坐垫", - "block.create.orange_toolbox": "橙色工具箱", - "block.create.orange_valve_handle": "橙色阀门手轮", - "block.create.ornate_iron_window": "华丽铁窗户", - "block.create.ornate_iron_window_pane": "华丽铁窗户板", - "block.create.oxidized_copper_shingle_slab": "氧化的铜砖瓦台阶", - "block.create.oxidized_copper_shingle_stairs": "氧化的铜砖瓦楼梯", - "block.create.oxidized_copper_shingles": "氧化的铜砖瓦", - "block.create.oxidized_copper_tile_slab": "氧化的铜瓦台阶", - "block.create.oxidized_copper_tile_stairs": "氧化的铜瓦楼梯", - "block.create.oxidized_copper_tiles": "氧化的铜瓦", - "block.create.peculiar_bell": "奇异钟", - "block.create.pink_nixie_tube": "粉红色辉光管", - "block.create.pink_sail": "粉红色风帆", - "block.create.pink_seat": "粉红色坐垫", - "block.create.pink_toolbox": "粉红色工具箱", - "block.create.pink_valve_handle": "粉红色阀门手轮", - "block.create.piston_extension_pole": "活塞杆", - "block.create.placard": "置物板", - "block.create.polished_cut_andesite": "磨制切制安山岩", - "block.create.polished_cut_andesite_slab": "磨制切制安山岩台阶", - "block.create.polished_cut_andesite_stairs": "磨制切制安山岩楼梯", - "block.create.polished_cut_andesite_wall": "磨制切制安山岩墙", - "block.create.polished_cut_asurine": "磨制切制皓蓝石", - "block.create.polished_cut_asurine_slab": "磨制切制皓蓝石台阶", - "block.create.polished_cut_asurine_stairs": "磨制切制皓蓝石楼梯", - "block.create.polished_cut_asurine_wall": "磨制切制皓蓝石墙", - "block.create.polished_cut_calcite": "磨制切制方解石", - "block.create.polished_cut_calcite_slab": "磨制切制方解石台阶", - "block.create.polished_cut_calcite_stairs": "磨制切制方解石楼梯", - "block.create.polished_cut_calcite_wall": "磨制切制方解石墙", - "block.create.polished_cut_crimsite": "磨制切制绯红岩", - "block.create.polished_cut_crimsite_slab": "磨制切制绯红岩台阶", - "block.create.polished_cut_crimsite_stairs": "磨制切制绯红岩楼梯", - "block.create.polished_cut_crimsite_wall": "磨制切制绯红岩墙", - "block.create.polished_cut_deepslate": "磨制切制深板岩", - "block.create.polished_cut_deepslate_slab": "磨制切制深板岩台阶", - "block.create.polished_cut_deepslate_stairs": "磨制切制深板岩楼梯", - "block.create.polished_cut_deepslate_wall": "磨制切制深板岩墙", - "block.create.polished_cut_diorite": "磨制切制闪长岩", - "block.create.polished_cut_diorite_slab": "磨制切制闪长岩台阶", - "block.create.polished_cut_diorite_stairs": "磨制切制闪长岩楼梯", - "block.create.polished_cut_diorite_wall": "磨制切制闪长岩墙", - "block.create.polished_cut_dripstone": "磨制切制滴水石", - "block.create.polished_cut_dripstone_slab": "磨制切制滴水石台阶", - "block.create.polished_cut_dripstone_stairs": "磨制切制滴水石楼梯", - "block.create.polished_cut_dripstone_wall": "磨制切制滴水石墙", - "block.create.polished_cut_granite": "磨制切制花岗岩", - "block.create.polished_cut_granite_slab": "磨制切制花岗岩台阶", - "block.create.polished_cut_granite_stairs": "磨制切制花岗岩楼梯", - "block.create.polished_cut_granite_wall": "磨制切制花岗岩墙", - "block.create.polished_cut_limestone": "磨制切制石灰岩", - "block.create.polished_cut_limestone_slab": "磨制切制石灰岩台阶", - "block.create.polished_cut_limestone_stairs": "磨制切制石灰岩楼梯", - "block.create.polished_cut_limestone_wall": "磨制切制石灰岩墙", - "block.create.polished_cut_ochrum": "磨制切制赭金砂", - "block.create.polished_cut_ochrum_slab": "磨制切制赭金砂台阶", - "block.create.polished_cut_ochrum_stairs": "磨制切制赭金砂楼梯", - "block.create.polished_cut_ochrum_wall": "磨制切制赭金砂墙", - "block.create.polished_cut_scorchia": "磨制切制焦黑熔渣", - "block.create.polished_cut_scorchia_slab": "磨制切制焦黑熔渣台阶", - "block.create.polished_cut_scorchia_stairs": "磨制切制焦黑熔渣楼梯", - "block.create.polished_cut_scorchia_wall": "磨制切制焦黑熔渣墙", - "block.create.polished_cut_scoria": "磨制切制熔渣", - "block.create.polished_cut_scoria_slab": "磨制切制熔渣台阶", - "block.create.polished_cut_scoria_stairs": "磨制切制熔渣楼梯", - "block.create.polished_cut_scoria_wall": "磨制切制熔渣墙", - "block.create.polished_cut_tuff": "磨制切制凝灰岩", - "block.create.polished_cut_tuff_slab": "磨制切制凝灰岩台阶", - "block.create.polished_cut_tuff_stairs": "磨制切制凝灰岩楼梯", - "block.create.polished_cut_tuff_wall": "磨制切制凝灰岩墙", - "block.create.polished_cut_veridium": "磨制切制辉绿矿", - "block.create.polished_cut_veridium_slab": "磨制切制辉绿矿台阶", - "block.create.polished_cut_veridium_stairs": "磨制切制辉绿矿楼梯", - "block.create.polished_cut_veridium_wall": "磨制切制辉绿矿墙", - "block.create.portable_fluid_interface": "移动式流体接口", - "block.create.portable_storage_interface": "移动式存储接口", - "block.create.powered_latch": "锁存器", - "block.create.powered_shaft": "动力曲轴", - "block.create.powered_toggle_latch": "转换锁存器", - "block.create.pulley_magnet": "滑轮磁铁", - "block.create.pulse_extender": "脉冲延长器", - "block.create.pulse_repeater": "脉冲中继器", - "block.create.purple_nixie_tube": "紫色辉光管", - "block.create.purple_sail": "紫色风帆", - "block.create.purple_seat": "紫色坐垫", - "block.create.purple_toolbox": "紫色工具箱", - "block.create.purple_valve_handle": "紫色阀门手轮", - "block.create.radial_chassis": "旋转底盘", - "block.create.railway_casing": "列车机壳", - "block.create.raw_zinc_block": "粗锌块", - "block.create.red_nixie_tube": "红色辉光管", - "block.create.red_sail": "红色风帆", - "block.create.red_seat": "红色坐垫", - "block.create.red_toolbox": "红色工具箱", - "block.create.red_valve_handle": "红色阀门手轮", - "block.create.redstone_contact": "接触式红石信号发生器", - "block.create.redstone_link": "无线红石信号终端", - "block.create.refined_radiance_casing": "光辉机壳", - "block.create.rope": "绳索", - "block.create.rope_pulley": "绳索滑轮", - "block.create.rose_quartz_block": "玫瑰石英块", - "block.create.rose_quartz_lamp": "玫瑰石英灯", - "block.create.rose_quartz_tiles": "玫瑰石英砖块", - "block.create.rotation_speed_controller": "转速控制器", - "block.create.sail_frame": "风帆框架", - "block.create.schematic_table": "蓝图桌", - "block.create.schematicannon": "蓝图加农炮", - "block.create.scorchia": "焦黑熔渣", - "block.create.scorchia_pillar": "焦黑熔渣柱", - "block.create.scoria": "熔渣", - "block.create.scoria_pillar": "熔渣柱", - "block.create.secondary_linear_chassis": "机壳底盘 2 号", - "block.create.sequenced_gearshift": "可编程齿轮箱", - "block.create.shadow_steel_casing": "暗影机壳", - "block.create.shaft": "传动杆", - "block.create.small_andesite_brick_slab": "安山岩小砖块台阶", - "block.create.small_andesite_brick_stairs": "安山岩小砖块楼梯", - "block.create.small_andesite_brick_wall": "安山岩小砖块墙", - "block.create.small_andesite_bricks": "安山岩小砖块", - "block.create.small_asurine_brick_slab": "皓蓝石小砖块台阶", - "block.create.small_asurine_brick_stairs": "皓蓝石小砖块楼梯", - "block.create.small_asurine_brick_wall": "皓蓝石小砖块墙", - "block.create.small_asurine_bricks": "皓蓝石小砖块", - "block.create.small_bogey": "小转向架", - "block.create.small_calcite_brick_slab": "方解石小砖块台阶", - "block.create.small_calcite_brick_stairs": "方解石小砖块楼梯", - "block.create.small_calcite_brick_wall": "方解石小砖块墙", - "block.create.small_calcite_bricks": "方解石小砖块", - "block.create.small_crimsite_brick_slab": "绯红岩小砖块台阶", - "block.create.small_crimsite_brick_stairs": "绯红岩小砖块楼梯", - "block.create.small_crimsite_brick_wall": "绯红岩小砖块墙", - "block.create.small_crimsite_bricks": "绯红岩小砖块", - "block.create.small_deepslate_brick_slab": "深板岩小砖块台阶", - "block.create.small_deepslate_brick_stairs": "深板岩小砖块楼梯", - "block.create.small_deepslate_brick_wall": "深板岩小砖块墙", - "block.create.small_deepslate_bricks": "深板岩小砖块", - "block.create.small_diorite_brick_slab": "闪长岩小砖块台阶", - "block.create.small_diorite_brick_stairs": "闪长岩小砖块楼梯", - "block.create.small_diorite_brick_wall": "闪长岩小砖块墙", - "block.create.small_diorite_bricks": "闪长岩小砖块", - "block.create.small_dripstone_brick_slab": "滴水石小砖块台阶", - "block.create.small_dripstone_brick_stairs": "滴水石小砖块楼梯", - "block.create.small_dripstone_brick_wall": "滴水石小砖块墙", - "block.create.small_dripstone_bricks": "滴水石小砖块", - "block.create.small_granite_brick_slab": "花岗岩小砖块台阶", - "block.create.small_granite_brick_stairs": "花岗岩小砖块楼梯", - "block.create.small_granite_brick_wall": "花岗岩小砖块墙", - "block.create.small_granite_bricks": "花岗岩小砖块", - "block.create.small_limestone_brick_slab": "石灰岩小砖块台阶", - "block.create.small_limestone_brick_stairs": "石灰岩小砖块楼梯", - "block.create.small_limestone_brick_wall": "石灰岩小砖块墙", - "block.create.small_limestone_bricks": "石灰岩小砖块", - "block.create.small_ochrum_brick_slab": "赭金砂小砖块台阶", - "block.create.small_ochrum_brick_stairs": "赭金砂小砖块楼梯", - "block.create.small_ochrum_brick_wall": "赭金砂小砖块墙", - "block.create.small_ochrum_bricks": "赭金砂小砖块", - "block.create.small_rose_quartz_tiles": "玫瑰石英小砖块", - "block.create.small_scorchia_brick_slab": "焦黑熔渣小砖块台阶", - "block.create.small_scorchia_brick_stairs": "焦黑熔渣小砖块楼梯", - "block.create.small_scorchia_brick_wall": "焦黑熔渣小砖块墙", - "block.create.small_scorchia_bricks": "焦黑熔渣小砖块", - "block.create.small_scoria_brick_slab": "熔渣小砖块台阶", - "block.create.small_scoria_brick_stairs": "熔渣小砖块楼梯", - "block.create.small_scoria_brick_wall": "熔渣小砖块墙", - "block.create.small_scoria_bricks": "熔渣小砖块", - "block.create.small_tuff_brick_slab": "凝灰岩小砖块台阶", - "block.create.small_tuff_brick_stairs": "凝灰岩小砖块楼梯", - "block.create.small_tuff_brick_wall": "凝灰岩小砖块墙", - "block.create.small_tuff_bricks": "凝灰岩小砖块", - "block.create.small_veridium_brick_slab": "辉绿矿小砖块台阶", - "block.create.small_veridium_brick_stairs": "辉绿矿小砖块楼梯", - "block.create.small_veridium_brick_wall": "辉绿矿小砖块墙", - "block.create.small_veridium_bricks": "辉绿矿小砖块", - "block.create.smart_chute": "智能溜槽", - "block.create.smart_fluid_pipe": "智能流体管道", - "block.create.speedometer": "速度表", - "block.create.spout": "注液器", - "block.create.spruce_window": "云杉木窗户", - "block.create.spruce_window_pane": "云杉木窗户板", - "block.create.steam_engine": "蒸汽引擎", - "block.create.steam_whistle": "蒸汽笛", - "block.create.steam_whistle_extension": "蒸汽笛加长段", - "block.create.sticker": "黏着器", - "block.create.sticky_mechanical_piston": "黏性动力活塞", - "block.create.stockpile_switch": "存量转信器", - "block.create.stressometer": "应力表", - "block.create.tiled_glass": "十字玻璃窗", - "block.create.tiled_glass_pane": "十字玻璃窗户板", - "block.create.track": "列车轨道", - "block.create.track_observer": "列车侦测器", - "block.create.track_signal": "列车信号机", - "block.create.track_station": "列车站", - "block.create.train_door": "列车门", - "block.create.train_trapdoor": "列车活板门", - "block.create.tuff_pillar": "凝灰岩柱", - "block.create.turntable": "转盘", - "block.create.veridium": "辉绿矿", - "block.create.veridium_pillar": "辉绿矿柱", - "block.create.vertical_framed_glass": "竖直边框玻璃", - "block.create.vertical_framed_glass_pane": "竖直边框玻璃板", - "block.create.warped_window": "诡异木窗户", - "block.create.warped_window_pane": "诡异木窗户板", - "block.create.water_wheel": "水车", - "block.create.waxed_copper_shingle_slab": "涂蜡铜砖瓦台阶", - "block.create.waxed_copper_shingle_stairs": "涂蜡铜砖瓦楼梯", - "block.create.waxed_copper_shingles": "涂蜡铜砖瓦", - "block.create.waxed_copper_tile_slab": "涂蜡铜瓦台阶", - "block.create.waxed_copper_tile_stairs": "涂蜡铜瓦楼梯", - "block.create.waxed_copper_tiles": "涂蜡铜瓦", - "block.create.waxed_exposed_copper_shingle_slab": "斑驳的涂蜡铜砖瓦台阶", - "block.create.waxed_exposed_copper_shingle_stairs": "斑驳的涂蜡铜砖瓦楼梯", - "block.create.waxed_exposed_copper_shingles": "斑驳的涂蜡铜砖瓦", - "block.create.waxed_exposed_copper_tile_slab": "斑驳的涂蜡铜瓦台阶", - "block.create.waxed_exposed_copper_tile_stairs": "斑驳的涂蜡铜瓦楼梯", - "block.create.waxed_exposed_copper_tiles": "斑驳的涂蜡铜瓦", - "block.create.waxed_oxidized_copper_shingle_slab": "氧化的涂蜡铜砖瓦台阶", - "block.create.waxed_oxidized_copper_shingle_stairs": "氧化的涂蜡铜砖瓦楼梯", - "block.create.waxed_oxidized_copper_shingles": "氧化的涂蜡铜砖瓦", - "block.create.waxed_oxidized_copper_tile_slab": "氧化的涂蜡铜瓦台阶", - "block.create.waxed_oxidized_copper_tile_stairs": "氧化的涂蜡铜瓦楼梯", - "block.create.waxed_oxidized_copper_tiles": "氧化的涂蜡铜瓦", - "block.create.waxed_weathered_copper_shingle_slab": "锈蚀的涂蜡铜砖瓦台阶", - "block.create.waxed_weathered_copper_shingle_stairs": "锈蚀的涂蜡铜砖瓦楼梯", - "block.create.waxed_weathered_copper_shingles": "锈蚀的涂蜡铜砖瓦", - "block.create.waxed_weathered_copper_tile_slab": "锈蚀的涂蜡铜瓦台阶", - "block.create.waxed_weathered_copper_tile_stairs": "锈蚀的涂蜡铜瓦楼梯", - "block.create.waxed_weathered_copper_tiles": "锈蚀的涂蜡铜瓦", - "block.create.weathered_copper_shingle_slab": "锈蚀的铜砖瓦台阶", - "block.create.weathered_copper_shingle_stairs": "锈蚀的铜砖瓦楼梯", - "block.create.weathered_copper_shingles": "锈蚀的铜砖瓦", - "block.create.weathered_copper_tile_slab": "锈蚀的铜瓦台阶", - "block.create.weathered_copper_tile_stairs": "锈蚀的铜瓦楼梯", - "block.create.weathered_copper_tiles": "锈蚀的铜瓦", - "block.create.weighted_ejector": "弹射置物台", - "block.create.white_nixie_tube": "白色辉光管", - "block.create.white_sail": "白色风帆", - "block.create.white_seat": "白色坐垫", - "block.create.white_toolbox": "白色工具箱", - "block.create.white_valve_handle": "白色阀门手轮", - "block.create.windmill_bearing": "风车轴承", - "block.create.wooden_bracket": "木质支架", - "block.create.yellow_nixie_tube": "黄色辉光管", - "block.create.yellow_sail": "黄色风帆", - "block.create.yellow_seat": "黄色坐垫", - "block.create.yellow_toolbox": "黄色工具箱", - "block.create.yellow_valve_handle": "黄色阀门手轮", - "block.create.zinc_block": "锌块", - "block.create.zinc_ore": "锌矿石", - - "enchantment.create.capacity": "扩容", - "enchantment.create.potato_recovery": "土豆回收", - - "entity.create.carriage_contraption": "车厢装置", - "entity.create.contraption": "装置", - "entity.create.crafting_blueprint": "合成蓝图", - "entity.create.gantry_contraption": "起重机装置", - "entity.create.potato_projectile": "被发射的土豆", - "entity.create.seat": "坐垫", - "entity.create.stationary_contraption": "固定装置", - "entity.create.super_glue": "强力胶", - - "fluid.create.potion": "药水", - "fluid.create.tea": "建造工茶水", - - "item.create.andesite_alloy": "安山合金", - "item.create.attribute_filter": "属性过滤器", - "item.create.bar_of_chocolate": "巧克力棒", - "item.create.belt_connector": "传送带", - "item.create.blaze_cake": "烈焰蛋糕", - "item.create.blaze_cake_base": "烈焰蛋糕胚", - "item.create.brass_hand": "黄铜手部零件", - "item.create.brass_ingot": "黄铜锭", - "item.create.brass_nugget": "黄铜粒", - "item.create.brass_sheet": "黄铜板", - "item.create.builders_tea": "建造工茶饮", - "item.create.chest_minecart_contraption": "装配过的运输矿车", - "item.create.chocolate_bucket": "巧克力桶", - "item.create.chocolate_glazed_berries": "巧克力包层浆果", - "item.create.chromatic_compound": "异彩化合物", - "item.create.cinder_flour": "余烬面粉", - "item.create.copper_backtank": "铜背罐", - "item.create.copper_backtank_placeable": "可放置的铜背罐", - "item.create.copper_nugget": "铜粒", - "item.create.copper_sheet": "铜板", - "item.create.crafter_slot_cover": "合成槽盖板", - "item.create.crafting_blueprint": "合成蓝图", - "item.create.creative_blaze_cake": "创造烈焰蛋糕", - "item.create.crushed_aluminum_ore": "粉碎铝矿石", - "item.create.crushed_copper_ore": "粉碎铜矿石", - "item.create.crushed_gold_ore": "粉碎金矿石", - "item.create.crushed_iron_ore": "粉碎铁矿石", - "item.create.crushed_lead_ore": "粉碎铅矿石", - "item.create.crushed_nickel_ore": "粉碎镍矿石", - "item.create.crushed_osmium_ore": "粉碎锇矿石", - "item.create.crushed_platinum_ore": "粉碎铂矿石", - "item.create.crushed_quicksilver_ore": "粉碎水银矿石", - "item.create.crushed_silver_ore": "粉碎银矿石", - "item.create.crushed_tin_ore": "粉碎锡矿石", - "item.create.crushed_uranium_ore": "粉碎铀矿石", - "item.create.crushed_zinc_ore": "粉碎锌矿石", - "item.create.diving_boots": "潜水靴", - "item.create.diving_helmet": "潜水头盔", - "item.create.dough": "面团", - "item.create.electron_tube": "电子管", - "item.create.empty_blaze_burner": "空的烈焰人燃烧室", - "item.create.empty_schematic": "空白蓝图", - "item.create.experience_nugget": "经验颗粒", - "item.create.extendo_grip": "伸缩机械手", - "item.create.filter": "过滤器", - "item.create.furnace_minecart_contraption": "装配过的动力矿车", - "item.create.goggles": "工程师护目镜", - "item.create.golden_sheet": "金板", - "item.create.handheld_worldshaper": "手持式环境塑形器", - "item.create.honey_bucket": "蜂蜜桶", - "item.create.honeyed_apple": "蜜渍苹果", - "item.create.incomplete_precision_mechanism": "精密构件(半成品)", - "item.create.incomplete_track": "列车轨道(半成品)", - "item.create.iron_sheet": "铁板", - "item.create.linked_controller": "无线红石遥控器", - "item.create.minecart_contraption": "装配过的矿车", - "item.create.minecart_coupling": "矿车连轴器", - "item.create.polished_rose_quartz": "磨制玫瑰石英", - "item.create.potato_cannon": "土豆加农炮", - "item.create.powdered_obsidian": "黑曜石粉末", - "item.create.precision_mechanism": "精密构件", - "item.create.propeller": "扇叶", - "item.create.raw_zinc": "粗锌", - "item.create.red_sand_paper": "红沙砂纸", - "item.create.refined_radiance": "光辉石", - "item.create.rose_quartz": "玫瑰石英", - "item.create.sand_paper": "砂纸", - "item.create.schedule": "列车时刻表", - "item.create.schematic": "蓝图", - "item.create.schematic_and_quill": "蓝图与笔", - "item.create.shadow_steel": "暗影钢", - "item.create.sturdy_sheet": "坚固板", - "item.create.super_glue": "强力胶", - "item.create.sweet_roll": "甜甜卷", - "item.create.tree_fertilizer": "树木肥料", - "item.create.unprocessed_obsidian_sheet": "未加工的黑曜石板", - "item.create.vertical_gearbox": "竖直十字齿轮箱", - "item.create.wand_of_symmetry": "对称之杖", - "item.create.wheat_flour": "小麦粉", - "item.create.whisk": "搅拌器", - "item.create.wrench": "扳手", - "item.create.zinc_ingot": "锌锭", - "item.create.zinc_nugget": "锌粒", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "欢迎来到机械动力", - "advancement.create.root.desc": "精巧发明在此", - "advancement.create.andesite_alloy": "安如顽石", - "advancement.create.andesite_alloy.desc": "获取机械动力的最重要资源——安山合金", - "advancement.create.andesite_casing": "安山时代", - "advancement.create.andesite_casing.desc": "使用安山合金和去皮原木来制造一个安山机壳", - "advancement.create.mechanical_press": "铿!", - "advancement.create.mechanical_press.desc": "使用动力辊压机压扁物品制成板材", - "advancement.create.encased_fan": "御风者", - "advancement.create.encased_fan.desc": "放置一个鼓风机并且让它开始工作", - "advancement.create.fan_processing": "粒子加工", - "advancement.create.fan_processing.desc": "使用鼓风机去加工材料", - "advancement.create.saw_processing": "车间中的危险机械", - "advancement.create.saw_processing.desc": "使用动力锯来加工材料", - "advancement.create.compacting": "紧致化", - "advancement.create.compacting.desc": "使用动力辊压机与工作盆将多个物品压缩成一个", - "advancement.create.belt": "海带传动", - "advancement.create.belt.desc": "用传送带连接两个传动杆", - "advancement.create.funnel": "机场美学", - "advancement.create.funnel.desc": "用漏斗从容器输出或输入物品", - "advancement.create.chute": "垂直物流", - "advancement.create.chute.desc": "用溜槽传输一些物品", - "advancement.create.mechanical_mixer": "混合搅拌", - "advancement.create.mechanical_mixer.desc": "用动力搅拌器混合材料", - "advancement.create.burner": "活炉", - "advancement.create.burner.desc": "获得烈焰人燃烧室", - "advancement.create.water_wheel": "论水力学的运用", - "advancement.create.water_wheel.desc": "放置一个水车并且让它开始旋转!", - "advancement.create.windmill": "微风吹拂", - "advancement.create.windmill.desc": "组装风车并使其产生动力", - "advancement.create.shifting_gears": "换挡,加速,起飞!", - "advancement.create.shifting_gears.desc": "将大齿轮连接到小齿轮上,可以改变装置的转速", - "advancement.create.millstone": "怡人磨练", - "advancement.create.millstone.desc": "使用石磨将物品磨碎", - "advancement.create.super_glue": "衔接地带", - "advancement.create.super_glue.desc": "使用强力胶将多个方块连为一体", - "advancement.create.contraption_actors": "有目的地行动", - "advancement.create.contraption_actors.desc": "创建一个带有动力钻头、动力锯或者动力收割机的移动装置", - "advancement.create.portable_storage_interface": "顺道交换", - "advancement.create.portable_storage_interface.desc": "用移动式储存接口从移动装置中取出或输入物品", - "advancement.create.wrench_goggles": "一应俱全", - "advancement.create.wrench_goggles.desc": "同时装备工程师护目镜与扳手", - "advancement.create.stressometer": "应力数是给呆子看的", - "advancement.create.stressometer.desc": "在应力表和工程师护目镜的辅助下获取准确读数", - "advancement.create.cuckoo_clock": "到点了吗?", - "advancement.create.cuckoo_clock.desc": "目睹你的布谷鸟闹钟提醒你睡觉", - "advancement.create.windmill_maxed": "强风肆虐", - "advancement.create.windmill_maxed.desc": "组装最高强度的风车", - "advancement.create.ejector_maxed": "跳板冠军", - "advancement.create.ejector_maxed.desc": "被弹射置物台弹飞30格以外", - "advancement.create.pulley_maxed": "绳索遍地", - "advancement.create.pulley_maxed.desc": "使用绳索滑轮伸出超过200格长的绳索", - "advancement.create.cart_pickup": "铁腕儿", - "advancement.create.cart_pickup.desc": "捡起一个至少带有200个方块的矿车结构", - "advancement.create.anvil_plough": "锻匠大炮", - "advancement.create.anvil_plough.desc": "用动力犁发射铁砧", - "advancement.create.lava_wheel_00000": "风火轮", - "advancement.create.lava_wheel_00000.desc": "这也能行?§7\n(隐藏进度)", - "advancement.create.hand_crank_000": "锻炼时间", - "advancement.create.hand_crank_000.desc": "转动手摇曲柄直到耗尽饥饿值§7\n(隐藏进度)", - "advancement.create.belt_funnel_kiss": "鹦鹉和垂翼", - "advancement.create.belt_funnel_kiss.desc": "让两个安装在传送带上的漏斗深情相吻", - "advancement.create.stressometer_maxed": "完美消耗", - "advancement.create.stressometer_maxed.desc": "在应力表中得到100%的读数§7\n(隐藏进度)", - "advancement.create.copper": "更坚固的顽石", - "advancement.create.copper.desc": "为你的流体操控技术积累一点铜", - "advancement.create.copper_casing": "铜器时代", - "advancement.create.copper_casing.desc": "使用铜和木头制作一个铜机壳", - "advancement.create.spout": "哗啦啦", - "advancement.create.spout.desc": "观察注液器灌满物品", - "advancement.create.drain": "滚筒排液", - "advancement.create.drain.desc": "目睹物品被分液池排空", - "advancement.create.steam_engine": "动力强权", - "advancement.create.steam_engine.desc": "用蒸汽引擎产生动力", - "advancement.create.steam_whistle": "天籁之音", - "advancement.create.steam_whistle.desc": "激活一个蒸汽笛", - "advancement.create.backtank": "负重前行", - "advancement.create.backtank.desc": "制作一个铜背罐并对其积累气压", - "advancement.create.diving_suit": "准备深潜", - "advancement.create.diving_suit.desc": "装备潜水头盔和铜背罐,然后跳进水里", - "advancement.create.mechanical_pump_0": "面临压力", - "advancement.create.mechanical_pump_0.desc": "放置一个动力泵并为其供能", - "advancement.create.glass_pipe": "流之观察者", - "advancement.create.glass_pipe.desc": "透过带窗的流体管道观察流体在管道中流淌,使用扳手可打开直线流体管道的窗户", - "advancement.create.water_supply": "水洼收集者", - "advancement.create.water_supply.desc": "用流体管道的末端抽取水方块", - "advancement.create.hose_pulley": "工业泄漏", - "advancement.create.hose_pulley.desc": "放下一个软管滑轮,观察它排干或填充一大片流体", - "advancement.create.chocolate_bucket": "幻想世界", - "advancement.create.chocolate_bucket.desc": "获得一桶熔融巧克力", - "advancement.create.honey_drain": "自动养蜂场", - "advancement.create.honey_drain.desc": "用流体管道从蜂巢或蜂箱抽出蜂蜜", - "advancement.create.hose_pulley_lava": "流地幔的水龙头", - "advancement.create.hose_pulley_lava.desc": "从广阔的熔岩湖中抽出熔岩", - "advancement.create.steam_engine_maxed": "全速前进", - "advancement.create.steam_engine_maxed.desc": "运行最高功率等级的锅炉", - "advancement.create.foods": "均衡饮食", - "advancement.create.foods.desc": "用同一个注液器分别制作巧克力包层浆果、蜂蜜苹果和甜甜卷", - "advancement.create.diving_suit_lava": "与炽足兽共泳", - "advancement.create.diving_suit_lava.desc": "努力尝试用潜水装备在熔岩中潜水§7\n(隐藏进度)", - "advancement.create.chained_drain": "翻滚吧!", - "advancement.create.chained_drain.desc": "目睹一个物品滚过一串分液池§7\n(隐藏进度)", - "advancement.create.cross_streams": "不要混用!", - "advancement.create.cross_streams.desc": "目睹两种流体在你的管道网络中相交§7\n(隐藏进度)", - "advancement.create.pipe_organ": "管风琴", - "advancement.create.pipe_organ.desc": "在一个流体储罐上安装12个不同音高的蒸汽笛§7\n(隐藏进度)", - "advancement.create.brass": "真正的合金", - "advancement.create.brass.desc": "在烈焰加热的搅拌器中用铜锭和锌锭制作一些黄铜", - "advancement.create.brass_casing": "黄铜时代", - "advancement.create.brass_casing.desc": "用黄铜和木头制作一个黄铜机壳", - "advancement.create.rose_quartz": "粉色钻石", - "advancement.create.rose_quartz.desc": "用砂纸将玫瑰石英打磨至透明", - "advancement.create.deployer": "人工智能", - "advancement.create.deployer.desc": "放置并且启动一个机械手,这可是你右手的完美复制品", - "advancement.create.precision_mechanism": "高新技术", - "advancement.create.precision_mechanism.desc": "装配一个精密构件", - "advancement.create.speed_controller": "工程师的眼中钉", - "advancement.create.speed_controller.desc": "放置一个转速控制器,这是换档的终极装置", - "advancement.create.mechanical_arm": "飞转的手!", - "advancement.create.mechanical_arm.desc": "制作动力臂,选择输入和输出,放置并给予它动力,然后看着它为你完成所有工作", - "advancement.create.mechanical_crafter": "自动化装配", - "advancement.create.mechanical_crafter.desc": "放置一些动力合成器并为其供能", - "advancement.create.crushing_wheel": "一对大家伙", - "advancement.create.crushing_wheel.desc": "制作一些能更快粉碎物品的粉碎轮", - "advancement.create.haunted_bell": "黑暗感官", - "advancement.create.haunted_bell.desc": "敲响一个缠魂钟", - "advancement.create.clockwork_bearing": "巧械时钟", - "advancement.create.clockwork_bearing.desc": "组装安装在发条轴承上的装置", - "advancement.create.display_link": "大数据", - "advancement.create.display_link.desc": "用翻牌显示器可视化资讯", - "advancement.create.potato_cannon": "Fwoomp!", - "advancement.create.potato_cannon.desc": "用土豆加农炮击杀一个生物", - "advancement.create.extendo_grip": "Boioioing!", - "advancement.create.extendo_grip.desc": "获得一个伸缩机械手", - "advancement.create.linked_controller": "层层遥控", - "advancement.create.linked_controller.desc": "用无线红石遥控器激活无线红石终端", - "advancement.create.arm_blaze_burner": "熊熊燃烧", - "advancement.create.arm_blaze_burner.desc": "指导动力臂给烈焰人燃烧室投食", - "advancement.create.crusher_maxed_0000": "碾碎它", - "advancement.create.crusher_maxed_0000.desc": "让一对粉碎轮以最高速度运行", - "advancement.create.arm_many_targets": "掌控全局", - "advancement.create.arm_many_targets.desc": "配置一个有十个或更多输出位置的动力臂", - "advancement.create.potato_cannon_collide": "蔬菜烟花", - "advancement.create.potato_cannon_collide.desc": "让两种土豆发射器弹射物相撞", - "advancement.create.self_deploying": "自动驾驶矿车", - "advancement.create.self_deploying.desc": "让一个矿车装置在自己前方铺铁轨", - "advancement.create.fist_bump": "来碰个拳,哥们~", - "advancement.create.fist_bump.desc": "使两个机械手互相碰拳", - "advancement.create.crafter_lazy_000": "权宜之计", - "advancement.create.crafter_lazy_000.desc": "大幅度减慢动力合成器来延迟基本建设", - "advancement.create.extendo_grip_dual": "全图范围", - "advancement.create.extendo_grip_dual.desc": "用双重伸缩机械手获得超人般的触及距离§7\n(隐藏进度)", - "advancement.create.musical_arm": "机械人DJ", - "advancement.create.musical_arm.desc": "使用动力臂播放唱片", - "advancement.create.sturdy_sheet": "最顽固的磐石", - "advancement.create.sturdy_sheet.desc": "用精炼粉碎黑曜石装配坚固板", - "advancement.create.train_casing_00": "物流时代", - "advancement.create.train_casing_00.desc": "用坚固板制作列车组件的机壳", - "advancement.create.train": "各位请上车!", - "advancement.create.train.desc": "装配你的第一辆列车", - "advancement.create.conductor": "指挥者的指挥者", - "advancement.create.conductor.desc": "使用列车时刻表指挥列车司机", - "advancement.create.track_signal": "交通管制", - "advancement.create.track_signal.desc": "放置一个列车信号机", - "advancement.create.display_board_0": "动态时间表", - "advancement.create.display_board_0.desc": "利用显示链接器,在翻牌显示器上预报列车入站时间", - "advancement.create.track_0": "新轨距", - "advancement.create.track_0.desc": "获得一些列车轨道", - "advancement.create.train_whistle": "呜!呜!", - "advancement.create.train_whistle.desc": "在你的列车上安装一个蒸汽笛并在驾驶时激活它", - "advancement.create.train_portal": "跨维度通勤", - "advancement.create.train_portal.desc": "乘坐列车穿越下界传送门", - "advancement.create.track_crafting_factory": "轨道工厂", - "advancement.create.track_crafting_factory.desc": "用同一个动力辊压机制造1000个列车轨道", - "advancement.create.long_bend": "最长弯道", - "advancement.create.long_bend.desc": "建造一条长度超过30格的弯曲轨道", - "advancement.create.long_train": "雄心勃勃", - "advancement.create.long_train.desc": "建造至少带有六个车厢的列车", - "advancement.create.long_travel": "异地考察", - "advancement.create.long_travel.desc": "在距离起点5000格外的地方离开列车座位", - "advancement.create.train_roadkill": "泥头车,创创死", - "advancement.create.train_roadkill.desc": "用你的列车创死一名敌人§7\n(隐藏进度)", - "advancement.create.red_signal": "老司机", - "advancement.create.red_signal.desc": "驾驶列车闯红灯§7\n(隐藏进度)", - "advancement.create.train_crash": "劣质服务", - "advancement.create.train_crash.desc": "目睹自己乘坐的列车相撞§7\n(隐藏进度)", - "advancement.create.train_crash_backwards": "盲区", - "advancement.create.train_crash_backwards.desc": "在倒车时与另一辆列车相撞", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "机械动力", - "itemGroup.create.palettes": "机械动力丨建筑方块", - - "death.attack.create.crush": "%1$s被粉碎轮加工了", - "death.attack.create.crush.player": "%1$s被%2$s推进了粉碎轮", - "death.attack.create.fan_fire": "%1$s被鼓风机烟熏至死", - "death.attack.create.fan_fire.player": "%1$s被%2$s扔进了烟熏炉", - "death.attack.create.fan_lava": "%1$s被鼓风机火化了", - "death.attack.create.fan_lava.player": "%1$s被%2$s扔进了冶炼炉", - "death.attack.create.mechanical_drill": "%1$s被钻头刺穿了", - "death.attack.create.mechanical_drill.player": "%1$s被%2$s扔到钻头前", - "death.attack.create.mechanical_saw": "%1$s被动力锯切成了两截", - "death.attack.create.mechanical_saw.player": "%1$s被%2$s扔到动力锯上", - "death.attack.create.potato_cannon": "%1$s被%2$s的土豆加农炮射杀", - "death.attack.create.potato_cannon.item": "%1$s被%2$s发射的%3$s射杀", - "death.attack.create.cuckoo_clock_explosion": "%1$s被动过手脚的布谷鸟闹钟炸死了", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s被动过手脚的布谷鸟闹钟炸死了", - "death.attack.create.run_over": "%1$s被%2$s碾了过去", - - "create.block.deployer.damage_source_name": "机械手小坏蛋", - "create.block.cart_assembler.invalid": "请将矿车装配器放置在铁轨上", - - "create.menu.return": "返回上级菜单", - "create.menu.configure": "配置……", - "create.menu.ponder_index": "思索索引", - "create.menu.only_ingame": "仅在游戏内暂停菜单中可用", - "create.menu.report_bugs": "报告问题", - "create.menu.support": "支持我们", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "粉碎", - "create.recipe.milling": "研磨", - "create.recipe.fan_washing": "批量洗涤", - "create.recipe.fan_washing.fan": "在水后放置鼓风机", - "create.recipe.fan_smoking": "批量烟熏", - "create.recipe.fan_smoking.fan": "在火焰后放置鼓风机", - "create.recipe.fan_haunting": "批量缠魂", - "create.recipe.fan_haunting.fan": "在灵魂火后放置鼓风机", - "create.recipe.fan_blasting": "批量熔炼", - "create.recipe.fan_blasting.fan": "在熔岩后放置鼓风机", - "create.recipe.pressing": "金属压片", - "create.recipe.mixing": "混合搅拌", - "create.recipe.deploying": "使用", - "create.recipe.automatic_shapeless": "自动搅拌", - "create.recipe.automatic_brewing": "自动酿造", - "create.recipe.packing": "压块塑形", - "create.recipe.automatic_packing": "自动打包", - "create.recipe.sawing": "切割", - "create.recipe.mechanical_crafting": "动力合成", - "create.recipe.automatic_shaped": "自动合成", - "create.recipe.block_cutting": "方块切割", - "create.recipe.wood_cutting": "木材切割", - "create.recipe.sandpaper_polishing": "砂纸打磨", - "create.recipe.mystery_conversion": "神秘转化", - "create.recipe.spout_filling": "注液", - "create.recipe.draining": "分液", - "create.recipe.item_application": "手动物品使用", - "create.recipe.item_application.any_axe": "任意斧头", - "create.recipe.sequenced_assembly": "序列组装", - "create.recipe.assembly.next": "下一步:%1$s", - "create.recipe.assembly.step": "第%1$s步:", - "create.recipe.assembly.progress": "组装进度:%1$s/%2$s", - "create.recipe.assembly.pressing": "进行辊压", - "create.recipe.assembly.spout_filling_fluid": "注入%1$s", - "create.recipe.assembly.deploying_item": "安装%1$s", - "create.recipe.assembly.cutting": "用动力锯切割", - "create.recipe.assembly.repeat": "该序列需要重复 %1$s 次", - "create.recipe.assembly.junk": "随机废料", - "create.recipe.processing.chance": "%1$s%%概率", - "create.recipe.deploying.not_consumed": "不消耗", - "create.recipe.heat_requirement.none": "无需加热", - "create.recipe.heat_requirement.heated": "加热", - "create.recipe.heat_requirement.superheated": "超级加热", - - "create.generic.range": "范围", - "create.generic.radius": "半径", - "create.generic.width": "宽度", - "create.generic.height": "高度", - "create.generic.length": "长度", - "create.generic.speed": "速度", - "create.generic.delay": "延时", - "create.generic.duration": "持续时间", - "create.generic.timeUnit": "时间单位", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "秒", - "create.generic.unit.minutes": "分钟", - "create.generic.daytime.hour": "时", - "create.generic.daytime.minute": "分", - "create.generic.daytime.second": "秒", - "create.generic.daytime.pm": "pm", - "create.generic.daytime.am": "am", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "°", - "create.generic.unit.millibuckets": "%1$smB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "顺时针方向", - "create.generic.counter_clockwise": "逆时针方向", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "音高:%1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "滚轮", - "create.action.confirm": "确认", - "create.action.abort": "退出", - "create.action.saveToFile": "保存", - "create.action.discard": "放弃", - - "create.keyinfo.toolmenu": "蓝图工具菜单", - "create.keyinfo.toolbelt": "访问附近的工具箱", - "create.keyinfo.scrollup": "(游戏中)向上鼠标滚轮", - "create.keyinfo.scrolldown": "(游戏中)向下鼠标滚轮", - - "create.gui.scrollInput.defaultTitle": "选择一个选项:", - "create.gui.scrollInput.scrollToModify": "滚动修改", - "create.gui.scrollInput.scrollToAdjustAmount": "滚动修改数量", - "create.gui.scrollInput.scrollToSelect": "滚动选择", - "create.gui.scrollInput.shiftScrollsFaster": "按住 Shift 滚动更快", - "create.gui.toolmenu.focusKey": "按住 [%1$s] 鼠标滚轮选择", - "create.gui.toolmenu.cycle": "[SCROLL] 循环", - - "create.toolbox.unequip": "收回: %1$s", - "create.toolbox.outOfRange": "收纳物品的工具箱不在范围内", - "create.toolbox.detach": "停止追踪并保留物品", - "create.toolbox.depositAll": "把物品收回附近所有的工具箱", - "create.toolbox.depositBox": "把物品收回工具箱", - - "create.gui.symmetryWand.mirrorType": "镜子类型", - "create.gui.symmetryWand.orientation": "方向", - - "create.symmetry.mirror.plane": "镜像", - "create.symmetry.mirror.doublePlane": "矩形", - "create.symmetry.mirror.triplePlane": "八角", - - "create.orientation.orthogonal": "垂直", - "create.orientation.diagonal": "对角线", - "create.orientation.horizontal": "水平", - "create.orientation.alongZ": "以Z轴对齐", - "create.orientation.alongX": "以X轴对齐", - - "create.gui.terrainzapper.title": "手持式环境塑形器", - "create.gui.terrainzapper.searchDiagonal": "对角线延伸", - "create.gui.terrainzapper.searchFuzzy": "忽略材料分界", - "create.gui.terrainzapper.patternSection": "样式", - "create.gui.terrainzapper.pattern.solid": "填满", - "create.gui.terrainzapper.pattern.checkered": "棋盘格", - "create.gui.terrainzapper.pattern.inversecheckered": "反转棋盘格", - "create.gui.terrainzapper.pattern.chance25": "随机填充 25%", - "create.gui.terrainzapper.pattern.chance50": "随机填充 50%", - "create.gui.terrainzapper.pattern.chance75": "随机填充 75%", - "create.gui.terrainzapper.placement": "放置模式", - "create.gui.terrainzapper.placement.merged": "结合", - "create.gui.terrainzapper.placement.attached": "依附", - "create.gui.terrainzapper.placement.inserted": "插入", - "create.gui.terrainzapper.brush": "塑形类型", - "create.gui.terrainzapper.brush.cuboid": "矩形体", - "create.gui.terrainzapper.brush.sphere": "球体", - "create.gui.terrainzapper.brush.cylinder": "圆柱体", - "create.gui.terrainzapper.brush.surface": "表面", - "create.gui.terrainzapper.brush.cluster": "簇状", - "create.gui.terrainzapper.tool": "填充类型", - "create.gui.terrainzapper.tool.fill": "填充", - "create.gui.terrainzapper.tool.place": "放置", - "create.gui.terrainzapper.tool.replace": "替换", - "create.gui.terrainzapper.tool.clear": "清除", - "create.gui.terrainzapper.tool.overlay": "覆盖", - "create.gui.terrainzapper.tool.flatten": "平整", - - "create.terrainzapper.shiftRightClickToSet": "按住 Shift 右击以设置塑形类型", - "create.terrainzapper.usingBlock": "使用:%1$s", - "create.terrainzapper.leftClickToSet": "鼠标左击一个方块以设置填充材料", - - "create.minecart_coupling.two_couplings_max": "矿车无法被连接两个以上的矿车连轴器", - "create.minecart_coupling.unloaded": "有一部分列车存在于未加载区块中", - "create.minecart_coupling.no_loops": "矿车连轴器不能连成一个环", - "create.minecart_coupling.removed": "从矿车上移除所有矿车连轴器", - "create.minecart_coupling.too_far": "矿车距离你太远了", - - "create.contraptions.movement_mode": "运动模式", - "create.contraptions.movement_mode.move_place": "停止时总是将装置方块化", - "create.contraptions.movement_mode.move_place_returned": "停止时只在初始位置才将装置方块化", - "create.contraptions.movement_mode.move_never_place": "只有在动力方块摧毁后才将装置方块化", - "create.contraptions.movement_mode.rotate_place": "停止时总是将装置方块化", - "create.contraptions.movement_mode.rotate_place_returned": "停止时只在接近初始角度才将装置方块化", - "create.contraptions.movement_mode.rotate_never_place": "只有在旋转轴摧毁后才将装置方块化", - "create.contraptions.cart_movement_mode": "矿车运动模式", - "create.contraptions.cart_movement_mode.rotate": "始终面朝前进方向", - "create.contraptions.cart_movement_mode.rotate_paused": "矿车转向时机器停止工作", - "create.contraptions.cart_movement_mode.rotation_locked": "旋转锁定", - "create.contraptions.windmill.rotation_direction": "旋转方向", - "create.contraptions.clockwork.clock_hands": "钟表指针", - "create.contraptions.clockwork.hour_first": "时针优先", - "create.contraptions.clockwork.minute_first": "分针优先", - "create.contraptions.clockwork.hour_first_24": "24 小时制优先", - - "create.logistics.filter": "过滤器", - "create.logistics.recipe_filter": "配方过滤器", - "create.logistics.fluid_filter": "流体过滤器", - "create.logistics.firstFrequency": "频率 #1", - "create.logistics.secondFrequency": "频率 #2", - "create.logistics.filter.apply": "已将过滤应用于%1$s", - "create.logistics.filter.apply_click_again": "已将过滤应用于%1$s,再次点击可将手持物品数量复制到过滤器上", - "create.logistics.filter.apply_count": "已将提取数量应用至过滤器", - - "create.gui.goggles.generator_stats": "应力发生器状态:", - "create.gui.goggles.kinetic_stats": "动力学状态:", - "create.gui.goggles.at_current_speed": "当前速度应力值", - "create.gui.goggles.pole_length": "活塞杆长度:", - "create.gui.goggles.fluid_container": "流体容器信息:", - "create.gui.goggles.fluid_container.capacity": "容量:", - "create.gui.assembly.exception": "无法组装该装置:", - "create.gui.assembly.exception.unmovableBlock": "无法移动的方块:(%4$s)位于 [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "位于 [%1$s,%2$s,%3$s] 的方块未处于加载区块", - "create.gui.assembly.exception.structureTooLarge": "装置中的方块数量过多\n配置的最大值为:%1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "活塞加装的活塞杆数量过多\n配置的最大值为:%1$s", - "create.gui.assembly.exception.noPistonPoles": "活塞缺失部分活塞杆", - "create.gui.assembly.exception.not_enough_sails": "相接的结构所包含的类风帆方块的数量不足:%1$s\n至少需要 %2$s", - "create.gui.gauge.info_header": "仪表信息:", - "create.gui.speedometer.title": "旋转速度", - "create.gui.stressometer.title": "网络应力", - "create.gui.stressometer.capacity": "剩余应力量", - "create.gui.stressometer.overstressed": "应力过载", - "create.gui.stressometer.no_rotation": "无旋转", - "create.gui.contraptions.not_fast_enough": "显然%1$s_没有_达到_足够_的_工作转速_", - "create.gui.contraptions.network_overstressed": "显然装置_过载_,添加更多动力源或者_减慢_网络中高_应力影响_的组件", - "create.gui.adjustable_crate.title": "板条箱", - "create.gui.adjustable_crate.storageSpace": "储存空间", - "create.gui.stockpile_switch.title": "储存开关", - "create.gui.stockpile_switch.invert_signal": "反转信号", - "create.gui.stockpile_switch.move_to_lower_at": "移至下线%1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "移至上线%1$s%%", - "create.gui.sequenced_gearshift.title": "可编程齿轮箱", - "create.gui.sequenced_gearshift.instruction": "指令", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "以特定的角度进行旋转", - "create.gui.sequenced_gearshift.instruction.turn_angle": "旋转", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "角度", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "开始驱动活塞/软管滑轮/起重机", - "create.gui.sequenced_gearshift.instruction.turn_distance": "驱动活塞", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "距离", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "时间延迟", - "create.gui.sequenced_gearshift.instruction.delay": "延迟", - "create.gui.sequenced_gearshift.instruction.delay.duration": "时长", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "结束", - "create.gui.sequenced_gearshift.instruction.end": "停止", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "等待新的红石脉冲", - "create.gui.sequenced_gearshift.instruction.await": "等待", - "create.gui.sequenced_gearshift.speed": "速度,速度方向", - "create.gui.sequenced_gearshift.speed.forward": "一倍速,正向", - "create.gui.sequenced_gearshift.speed.forward_fast": "两倍速,正向", - "create.gui.sequenced_gearshift.speed.back": "一倍速,反向", - "create.gui.sequenced_gearshift.speed.back_fast": "两倍速,反向", - - "create.schematicAndQuill.dimensions": "蓝图尺寸:%1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "第一个位置", - "create.schematicAndQuill.secondPos": "第二个位置", - "create.schematicAndQuill.noTarget": "按住 [Ctrl] 选择空气方块", - "create.schematicAndQuill.abort": "删除选择", - "create.schematicAndQuill.title": "蓝图名:", - "create.schematicAndQuill.convert": "立即保存并部署", - "create.schematicAndQuill.fallbackName": "我的蓝图", - "create.schematicAndQuill.saved": "另存为%1$s", - - "create.schematic.invalid": "[!] 无效的物品 - 使用蓝图桌来替换", - "create.schematic.position": "位置", - "create.schematic.rotation": "旋转", - "create.schematic.rotation.none": "无", - "create.schematic.rotation.cw90": "顺时针90", - "create.schematic.rotation.cw180": "顺时针180", - "create.schematic.rotation.cw270": "顺时针270", - "create.schematic.mirror": "镜像", - "create.schematic.mirror.none": "无", - "create.schematic.mirror.frontBack": "前后", - "create.schematic.mirror.leftRight": "左右", - "create.schematic.tool.deploy": "部署", - "create.schematic.tool.move": "移动 XZ", - "create.schematic.tool.movey": "移动 Y", - "create.schematic.tool.rotate": "旋转", - "create.schematic.tool.print": "打印", - "create.schematic.tool.flip": "翻转", - "create.schematic.tool.deploy.description.0": "将结构移到某个位置", - "create.schematic.tool.deploy.description.1": "在地面上右击以放置", - "create.schematic.tool.deploy.description.2": "按住 [Ctrl] 以固定距离选择", - "create.schematic.tool.deploy.description.3": "按住 [Ctrl] 鼠标滚动更改距离", - "create.schematic.tool.move.description.0": "水平移动蓝图", - "create.schematic.tool.move.description.1": "选定蓝图,然后按住 [Ctrl] 鼠标滚动移动", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "垂直移动蓝图", - "create.schematic.tool.movey.description.1": "按住 [Ctrl] 鼠标滚动上下移动", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "围绕蓝图中心旋转蓝图", - "create.schematic.tool.rotate.description.1": "按住 [Ctrl] 鼠标滚动旋转90度", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "立即将结构放置在世界上", - "create.schematic.tool.print.description.1": "[右击] 确认当前位置", - "create.schematic.tool.print.description.2": "该工具仅适用于创造模式", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "沿你选择的面翻转蓝图", - "create.schematic.tool.flip.description.1": "指向蓝图,然后按住 [Ctrl] 鼠标滚动将其翻转", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "正在同步……", - "create.schematics.uploadTooLarge": "你的蓝图超出了服务器指定的限制", - "create.schematics.maxAllowedSize": "允许的最大蓝图文件大小为:", - - "create.gui.schematicTable.refresh": "刷新文件", - "create.gui.schematicTable.open_folder": "打开文件夹", - "create.gui.schematicTable.title": "蓝图桌", - "create.gui.schematicTable.availableSchematics": "可用蓝图", - "create.gui.schematicTable.noSchematics": "没有保存的蓝图", - "create.gui.schematicTable.uploading": "正在上传……", - "create.gui.schematicTable.finished": "上传完成!", - "create.gui.schematicannon.title": "蓝图加农炮", - "create.gui.schematicannon.listPrinter": "物品清单打印机", - "create.gui.schematicannon.gunpowderLevel": "火药%1$s%%", - "create.gui.schematicannon.shotsRemaining": "燃料余量:%1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "燃料储备:%1$s", - "create.gui.schematicannon.optionEnabled": "当前启用", - "create.gui.schematicannon.optionDisabled": "当前禁用", - "create.gui.schematicannon.showOptions": "显示蓝图加农炮设置", - "create.gui.schematicannon.option.dontReplaceSolid": "不要替换方块", - "create.gui.schematicannon.option.replaceWithSolid": "用固体方块替换工作区域内的方块", - "create.gui.schematicannon.option.replaceWithAny": "用任何方块替换工作区域内的方块", - "create.gui.schematicannon.option.replaceWithEmpty": "用空气替换工作区域内的方块", - "create.gui.schematicannon.option.skipMissing": "跳过缺少的方块", - "create.gui.schematicannon.option.skipTileEntities": "保护存储方块", - "create.gui.schematicannon.slot.gunpowder": "向蓝图加农炮添加火药以提供动力", - "create.gui.schematicannon.slot.listPrinter": "在此处放置书以打印蓝图所需的材料清单", - "create.gui.schematicannon.slot.schematic": "在此处添加你的蓝图,务必确保其已经被部署在特定位置", - "create.gui.schematicannon.option.skipMissing.description": "如果缺失材料,蓝图加农炮将忽略当前缺失材料并且使用其他已有材料继续工作", - "create.gui.schematicannon.option.skipTileEntities.description": "蓝图加农炮将避免替换存储数据的方块,如箱子", - "create.gui.schematicannon.option.dontReplaceSolid.description": "蓝图加农炮将不会替换工作范围内的任何固体方块", - "create.gui.schematicannon.option.replaceWithSolid.description": "蓝图加农炮会使用所提供的固体方块来替换工作区域内的其他固体方块", - "create.gui.schematicannon.option.replaceWithAny.description": "蓝图加农炮会使用任何所提供的方块来替换工作区域内的固体方块", - "create.gui.schematicannon.option.replaceWithEmpty.description": "蓝图加农炮将清理和替换工作区域内所有原本的方块", - - "create.schematicannon.status.idle": "闲置", - "create.schematicannon.status.ready": "就绪", - "create.schematicannon.status.running": "正在运作", - "create.schematicannon.status.finished": "已完成", - "create.schematicannon.status.paused": "已暂停", - "create.schematicannon.status.stopped": "已停止", - "create.schematicannon.status.noGunpowder": "火药已耗尽", - "create.schematicannon.status.targetNotLoaded": "目标未被加载", - "create.schematicannon.status.targetOutsideRange": "目标太远", - "create.schematicannon.status.searching": "正在搜索", - "create.schematicannon.status.skipping": "正在跳过", - "create.schematicannon.status.missingBlock": "缺少物品:", - "create.schematicannon.status.placing": "正在放置", - "create.schematicannon.status.clearing": "正在清除方块", - "create.schematicannon.status.schematicInvalid": "蓝图无效", - "create.schematicannon.status.schematicNotPlaced": "蓝图未部署", - "create.schematicannon.status.schematicExpired": "蓝图文件已过期", - - "create.materialChecklist": "材料清单", - "create.materialChecklist.blocksNotLoaded": "*免责声明*\n\n由于相关区块未被加载,材料清单可能不准确", - - "create.gui.filter.deny_list": "黑名单", - "create.gui.filter.deny_list.description": "只通过不在黑名单中的物品,如果黑名单为空,所有物品都可以通过", - "create.gui.filter.allow_list": "白名单", - "create.gui.filter.allow_list.description": "只通过在白名单中的物品,如果白名单为空,所有物品都无法通过", - "create.gui.filter.respect_data": "匹配物品属性", - "create.gui.filter.respect_data.description": "只有物品的耐久、附魔等其他属性相同时才可以匹配", - "create.gui.filter.ignore_data": "忽视物品属性", - "create.gui.filter.ignore_data.description": "匹配时忽视物品的耐久、附魔等其他属性", - - "create.item_attributes.placeable": "可放置", - "create.item_attributes.placeable.inverted": "不可放置", - "create.item_attributes.consumable": "可食用", - "create.item_attributes.consumable.inverted": "不可食用", - "create.item_attributes.fluid_container": "可储存流体", - "create.item_attributes.fluid_container.inverted": "不可储存流体", - "create.item_attributes.enchanted": "已被附魔", - "create.item_attributes.enchanted.inverted": "未被附魔", - "create.item_attributes.max_enchanted": "已达到最高附魔等级", - "create.item_attributes.max_enchanted.inverted": "并未达到最高附魔等级", - "create.item_attributes.renamed": "有自定义名称", - "create.item_attributes.renamed.inverted": "没有自定义名称", - "create.item_attributes.damaged": "已损坏", - "create.item_attributes.damaged.inverted": "未损坏", - "create.item_attributes.badly_damaged": "严重受损", - "create.item_attributes.badly_damaged.inverted": "未严重受损", - "create.item_attributes.not_stackable": "无法堆叠", - "create.item_attributes.not_stackable.inverted": "可堆叠", - "create.item_attributes.equipable": "可装备", - "create.item_attributes.equipable.inverted": "不可装备", - "create.item_attributes.furnace_fuel": "可作为燃料", - "create.item_attributes.furnace_fuel.inverted": "不可作为燃料", - "create.item_attributes.washable": "可被洗涤", - "create.item_attributes.washable.inverted": "不可被洗涤", - "create.item_attributes.hauntable": "可被缠魂", - "create.item_attributes.hauntable.inverted": "不可被缠魂", - "create.item_attributes.crushable": "可被粉碎", - "create.item_attributes.crushable.inverted": "不可被粉碎", - "create.item_attributes.smeltable": "可被熔炉烧制", - "create.item_attributes.smeltable.inverted": "不可被熔炉烧制", - "create.item_attributes.smokable": "可被烟熏", - "create.item_attributes.smokable.inverted": "不可被烟熏", - "create.item_attributes.blastable": "可被高炉冶炼", - "create.item_attributes.blastable.inverted": "不可被高炉冶炼", - "create.item_attributes.compostable": "可被堆肥", - "create.item_attributes.compostable.inverted": "不可被堆肥", - "create.item_attributes.shulker_level": "潜影盒是%1$s的", - "create.item_attributes.shulker_level.inverted": "潜影盒不是%1$s的", - "create.item_attributes.shulker_level.full": "满", - "create.item_attributes.shulker_level.empty": "空", - "create.item_attributes.shulker_level.partial": "部分填充", - "create.item_attributes.in_tag": "标签是%1$s", - "create.item_attributes.in_tag.inverted": "标签不是%1$s", - "create.item_attributes.in_item_group": "属于%1$s", - "create.item_attributes.in_item_group.inverted": "不属于%1$s", - "create.item_attributes.added_by": "由%1$s添加", - "create.item_attributes.added_by.inverted": "不由%1$s添加", - "create.item_attributes.has_enchant": "有附魔效果%1$s", - "create.item_attributes.has_enchant.inverted": "没有附魔效果%1$s", - "create.item_attributes.color": "染色为%1$s", - "create.item_attributes.color.inverted": "未被染成%1$s", - "create.item_attributes.has_fluid": "含有%1$s", - "create.item_attributes.has_fluid.inverted": "不含有%1$s", - "create.item_attributes.has_name": "有自定义名称%1$s", - "create.item_attributes.has_name.inverted": "没有自定义名称%1$s", - "create.item_attributes.book_author": "由%1$s编写", - "create.item_attributes.book_author.inverted": "不是由%1$s编写", - "create.item_attributes.book_copy_original": "是初版", - "create.item_attributes.book_copy_original.inverted": "不是初版", - "create.item_attributes.book_copy_first": "是第一代拷贝", - "create.item_attributes.book_copy_first.inverted": "不是第一代拷贝", - "create.item_attributes.book_copy_second": "是第二代拷贝", - "create.item_attributes.book_copy_second.inverted": "不是第二代拷贝", - "create.item_attributes.book_copy_tattered": "拷贝次数不可查", - "create.item_attributes.book_copy_tattered.inverted": "拷贝次数可查", - "create.item_attributes.astralsorcery_amulet": "璀璨棱镜增强%1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "璀璨棱镜未增强%1$s", - "create.item_attributes.astralsorcery_constellation": "与%1$s共鸣", - "create.item_attributes.astralsorcery_constellation.inverted": "不与%1$s共鸣", - "create.item_attributes.astralsorcery_crystal": "有水晶石属性%1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "没有水晶石属性%1$s", - "create.item_attributes.astralsorcery_perk_gem": "带有有星能力属性%1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "不带有星能力属性%1$s", - - "create.gui.attribute_filter.no_selected_attributes": "未选择任何属性", - "create.gui.attribute_filter.selected_attributes": "已选择的属性:", - "create.gui.attribute_filter.add_attribute": "向列表中添加属性", - "create.gui.attribute_filter.add_inverted_attribute": "向列表中添加相反属性", - "create.gui.attribute_filter.allow_list_disjunctive": "任意匹配白名单(任何)", - "create.gui.attribute_filter.allow_list_disjunctive.description": "只要有其中一项属性符合,就可以通过", - "create.gui.attribute_filter.allow_list_conjunctive": "全匹配白名单(全部)", - "create.gui.attribute_filter.allow_list_conjunctive.description": "只有所有属性都匹配才可以通过", - "create.gui.attribute_filter.deny_list": "黑名单", - "create.gui.attribute_filter.deny_list.description": "只要没有上述属性,就可以通过", - "create.gui.attribute_filter.add_reference_item": "添加参考物品", - - "create.tooltip.holdForDescription": "按住 [%1$s] 可查看概要", - "create.tooltip.holdForControls": "按住 [%1$s] 可查看控制方法", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "需求转速:%1$s", - "create.tooltip.speedRequirement.none": "无", - "create.tooltip.speedRequirement.slow": "慢", - "create.tooltip.speedRequirement.medium": "中", - "create.tooltip.speedRequirement.fast": "快", - "create.tooltip.stressImpact": "应力影响:%1$s", - "create.tooltip.stressImpact.low": "低", - "create.tooltip.stressImpact.medium": "中", - "create.tooltip.stressImpact.high": "高", - "create.tooltip.stressImpact.overstressed": "过载", - "create.tooltip.up_to": "最多%1$s", - "create.tooltip.capacityProvided": "应力量:%1$s", - "create.tooltip.capacityProvided.low": "小", - "create.tooltip.capacityProvided.medium": "中", - "create.tooltip.capacityProvided.high": "大", - "create.tooltip.generationSpeed": "产生于%1$s %2$s", - "create.tooltip.analogStrength": "模拟信号强度:%1$s/15", - - "create.mechanical_arm.extract_from": "从%1$s中拿取物品", - "create.mechanical_arm.deposit_to": "将物品存储至%1$s", - "create.mechanical_arm.summary": "动力臂当前有 %1$s 个输入,%2$s 个输出", - "create.mechanical_arm.points_outside_range": "由于距离限制,选定的交互点%1$s已被移除", - - "create.weighted_ejector.target_set": "目标已选取", - "create.weighted_ejector.target_not_valid": "弹射至临近方块(目标无效)", - "create.weighted_ejector.no_target": "弹射至临近方块(未选择目标)", - "create.weighted_ejector.targeting": "弹射至 [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "弹射物品堆数量", - - "create.logistics.when_multiple_outputs_available": "多个输出可用时", - - "create.mechanical_arm.selection_mode.round_robin": "轮询调度", - "create.mechanical_arm.selection_mode.forced_round_robin": "强制轮询调度", - "create.mechanical_arm.selection_mode.prefer_first": "第一目标优先", - - "create.tunnel.selection_mode.split": "分流", - "create.tunnel.selection_mode.forced_split": "强制分流", - "create.tunnel.selection_mode.round_robin": "轮询调度", - "create.tunnel.selection_mode.forced_round_robin": "强制轮询调度", - "create.tunnel.selection_mode.prefer_nearest": "最近优先", - "create.tunnel.selection_mode.randomize": "随机", - "create.tunnel.selection_mode.synchronize": "同步输入", - - "create.tooltip.chute.header": "溜槽信息", - "create.tooltip.chute.items_move_down": "物品下行", - "create.tooltip.chute.items_move_up": "物品上行", - "create.tooltip.chute.no_fans_attached": "未安装鼓风机", - "create.tooltip.chute.fans_push_up": "鼓风机从下方进行推动", - "create.tooltip.chute.fans_push_down": "鼓风机从上方进行推动", - "create.tooltip.chute.fans_pull_up": "鼓风机从上方进行吸引", - "create.tooltip.chute.fans_pull_down": "鼓风机从下方进行吸引", - "create.tooltip.chute.contains": "内含物品:%1$s x%2$s", - "create.tooltip.deployer.header": "机械手信息", - "create.tooltip.deployer.using": "模式:使用", - "create.tooltip.deployer.punching": "模式:攻击", - "create.tooltip.deployer.contains": "物品:%1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "目前分配:", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "右击取出", - - "create.linked_controller.bind_mode": "绑定模式激活", - "create.linked_controller.press_keybind": "按下%1$s、%2$s、%3$s、%4$s、%5$s或%6$s,可以将该频率绑定到按下的按键上", - "create.linked_controller.key_bound": "该频率已绑定到%1$s", - "create.linked_controller.frequency_slot_1": "按键绑定:%1$s, 频率 #1", - "create.linked_controller.frequency_slot_2": "按键绑定:%1$s, 频率 #2", - - "create.crafting_blueprint.crafting_slot": "原料槽", - "create.crafting_blueprint.filter_items_viable": "可以使用过滤器", - "create.crafting_blueprint.display_slot": "展示槽", - "create.crafting_blueprint.inferred": "已根据合成配方自动设定", - "create.crafting_blueprint.manually_assigned": "手动设定", - "create.crafting_blueprint.secondary_display_slot": "次要展示槽", - "create.crafting_blueprint.optional": "可选", - - "create.potato_cannon.ammo.attack_damage": "%1$s 攻击伤害", - "create.potato_cannon.ammo.reload_ticks": "%1$s 装弹时间(Ticks)", - "create.potato_cannon.ammo.knockback": "%1$s 击退", - - "create.hint.hose_pulley.title": "无限供应", - "create.hint.hose_pulley": "目标流体对象被视为无限量的", - "create.hint.mechanical_arm_no_targets.title": "没有目标", - "create.hint.mechanical_arm_no_targets": "看起来这个_动力臂_没有被分配给任何_目标_,在_手持动力臂_的同时,_右击_选取传送带、置物台、漏斗或其他设备来设置目标", - "create.hint.empty_bearing.title": "更新轴承", - "create.hint.empty_bearing": "_空手右击_轴承,可以将你新建造的结构_接到_轴承上", - "create.hint.full_deployer.title": "机械手物品溢出", - "create.hint.full_deployer": "_机械手_包含_过剩的物品_,需要被_提取_,使用_漏斗_或其他方法将其从溢出中释放出来", - - "create.backtank.low": "背罐压力低", - "create.backtank.depleted": "背罐压力耗尽", - - "create.hint.derailed_train.title": "出轨的列车", - "create.hint.derailed_train": "看起来该列车不再位于相连的轨道段上,使用_扳手__右击_可以将它重新安置到附近的轨道上", - - "create.boiler.status": "锅炉状态:%1$s", - "create.boiler.status_short": "锅炉:%1$s", - "create.boiler.passive": "被动", - "create.boiler.idle": "空闲", - "create.boiler.lvl": "等级%1$s", - "create.boiler.max_lvl": "最高等级", - "create.boiler.size": "尺寸", - "create.boiler.size_dots": "...... ", - "create.boiler.water": "水量", - "create.boiler.water_dots": "...... ", - "create.boiler.heat": "热量", - "create.boiler.heat_dots": "...... ", - "create.boiler.via_one_engine": "通过1个引擎", - "create.boiler.via_engines": "通过%1$s个引擎", - - "create.gui.schedule.lmb_edit": "左键点击编辑", - "create.gui.schedule.rmb_remove": "右键点击移除", - "create.gui.schedule.duplicate": "复制", - "create.gui.schedule.remove_entry": "移除动作", - "create.gui.schedule.add_entry": "添加动作", - "create.gui.schedule.move_up": "上移", - "create.gui.schedule.move_down": "下移", - "create.gui.schedule.add_condition": "添加条件", - "create.gui.schedule.alternative_condition": "备选条件", - - "create.schedule.instruction_type": "下一个动作:", - "create.schedule.instruction.editor": "指令编辑器", - "create.schedule.instruction.destination": "前往车站", - "create.schedule.instruction.destination.summary": "下一站:", - "create.schedule.instruction.filter_edit_box": "车站名称", - "create.schedule.instruction.filter_edit_box_1": "使用*作为文本通配符", - "create.schedule.instruction.filter_edit_box_2": "例如:“我的车站,站台*”", - "create.schedule.instruction.filter_edit_box_3": "列车会挑选并匹配至最近的未被占用的车站", - "create.schedule.instruction.rename": "更新时刻表标题", - "create.schedule.instruction.rename.summary": "新标题:", - "create.schedule.instruction.name_edit_box": "时刻表标题", - "create.schedule.instruction.name_edit_box_1": "影响显示器上显示的文本", - "create.schedule.instruction.name_edit_box_2": "默认为下一个目的地的名称", - "create.schedule.instruction.throttle": "限制最高速度", - "create.schedule.instruction.throttle.summary": "调整最高速度到%1$s", - "create.schedule.instruction.throttle_edit_box": "节流阀", - "create.schedule.instruction.throttle_edit_box_1": "影响列车的最高速度", - "create.schedule.condition_type": "如果满足/完成之后……则继续:", - "create.schedule.condition.editor": "条件编辑器", - "create.schedule.condition.delay": "调度延迟", - "create.schedule.condition.delay_short": "等待:%1$s", - "create.schedule.condition.delay.status": "发自%1$s", - "create.schedule.condition.idle": "装卸停止", - "create.schedule.condition.idle_short": "装卸停止:%1$s", - "create.schedule.condition.idle.status": "装卸停止:%1$s", - "create.schedule.condition.for_x_time": "%1$s", - "create.schedule.condition.unloaded": "区块卸载", - "create.schedule.condition.unloaded.status": "等待区块被卸载", - "create.schedule.condition.powered": "车站被充能", - "create.schedule.condition.powered.status": "等待红石信号", - "create.schedule.condition.time_of_day": "一天中的时间", - "create.schedule.condition.time_of_day.scheduled": "调度时间:%1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "轮换", - "create.schedule.condition.time_of_day.rotation.every_24": "每天", - "create.schedule.condition.time_of_day.rotation.every_12": "每12:00", - "create.schedule.condition.time_of_day.rotation.every_6": "每6:00", - "create.schedule.condition.time_of_day.rotation.every_4": "每4:00", - "create.schedule.condition.time_of_day.rotation.every_3": "每3:00", - "create.schedule.condition.time_of_day.rotation.every_2": "每2:00", - "create.schedule.condition.time_of_day.rotation.every_1": "每1:00", - "create.schedule.condition.time_of_day.rotation.every_0_45": "每0:45", - "create.schedule.condition.time_of_day.rotation.every_0_30": "每0:30", - "create.schedule.condition.time_of_day.rotation.every_0_15": "每0:15", - "create.schedule.condition.time_of_day.status": "出发于", - "create.schedule.condition.threshold.train_holds": "列车持有%1$s", - "create.schedule.condition.threshold.greater": "多于", - "create.schedule.condition.threshold.less": "少于", - "create.schedule.condition.threshold.equal": "恰好", - "create.schedule.condition.threshold.x_units_of_item": "%1$s%2$s%3$s", - "create.schedule.condition.threshold.matching_content": "匹配内容", - "create.schedule.condition.threshold.anything": "任意物品", - "create.schedule.condition.threshold.item_measure": "物品度量", - "create.schedule.condition.threshold.items": "个", - "create.schedule.condition.threshold.stacks": "组", - "create.schedule.condition.threshold.buckets": "桶", - "create.schedule.condition.threshold.status": "货物:%1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "参考物品", - "create.schedule.condition.threshold.place_item_2": "可以使用过滤器", - "create.schedule.condition.threshold.place_item_3": "留空以匹配任意物品", - "create.schedule.condition.fluid_threshold": "流体货物条件", - "create.schedule.condition.item_threshold": "物品货物条件", - "create.schedule.condition.redstone_link": "无线红石", - "create.schedule.condition.redstone_link.status": "等待无线红石", - "create.schedule.condition.redstone_link_on": "无线开启", - "create.schedule.condition.redstone_link_off": "无线关闭", - "create.schedule.condition.redstone_link.powered": "充能", - "create.schedule.condition.redstone_link.unpowered": "未充能", - "create.schedule.condition.redstone_link.frequency_state": "频率状态:", - "create.schedule.condition.redstone_link.frequency_powered": "频率充能:", - "create.schedule.condition.redstone_link.frequency_unpowered": "频率未充能:", - "create.schedule.condition.player_count": "玩家入座", - "create.schedule.condition.player_count.summary": "%1$s玩家", - "create.schedule.condition.player_count.summary_plural": "%1$s玩家", - "create.schedule.condition.player_count.seated": "%1$s入座", - "create.schedule.condition.player_count.players": "玩家", - "create.schedule.condition.player_count.condition": "条件", - "create.schedule.condition.player_count.exactly": "恰好", - "create.schedule.condition.player_count.or_above": "或以上", - "create.schedule.condition.player_count.status": "乘客:%1$s/%2$s", - "create.schedule.loop": "一直循环", - "create.schedule.loop1": "时刻表完成后", - "create.schedule.loop2": "重新开始", - "create.schedule.reset": "重置进度", - "create.schedule.skip": "跳过当前车站", - "create.schedule.applied_to_train": "列车现在遵循这个时刻表", - "create.schedule.non_controlling_seat": "列车长需要坐在驾驶台方块前面", - "create.schedule.remove_with_empty_hand": "用空手移除当前时刻表", - "create.schedule.auto_removed_from_train": "自动时刻表被废弃", - "create.schedule.removed_from_train": "从列车取回时刻表", - "create.schedule.no_stops": "该时刻表还没有任何停靠站", - "create.schedule.continued": "时刻表已恢复", - - "create.track.selection_cleared": "选区已清除", - "create.track.valid_connection": "可以连接✔", - "create.track.second_point": "放置轨道或选择第二个点", - "create.track.too_far": "太远了", - "create.track.original_missing": "原方块被移除,潜行点击重置", - "create.track.perpendicular": "无法垂直连接", - "create.track.ascending_s_curve": "无法创建有坡度的S型转弯", - "create.track.too_sharp": "转弯过急", - "create.track.too_steep": "坡度太陡", - "create.track.slope_turn": "不能在转弯时进入或离开斜坡", - "create.track.opposing_slopes": "不能连接相反的斜坡", - "create.track.leave_slope_ascending": "不能在上升时离开这个斜坡", - "create.track.leave_slope_descending": "不能在下降时离开这个斜坡", - "create.track.turn_90": "最多只能转90度", - "create.track.junction_start": "无法从路口开始连接", - "create.track.turn_start": "无法从转弯开始连接", - "create.track.not_enough_tracks": "没有足够的轨道", - "create.track.not_enough_pavement": "没有足够的路面方块", - - "create.portal_track.failed": "无法放置传送轨道:", - "create.portal_track.missing": "目标传送门还未生成", - "create.portal_track.blocked": "目标位置被封堵 (%1$s,%2$s,%3$s)", - - "create.station.idle": "车站空闲", - "create.station.assembly_title": "组装列车", - "create.station.close": "关闭窗口", - "create.station.cancel": "取消组装", - "create.station.failed": "组装失败", - "create.station.icon_type": "图标类型", - "create.station.create_train": "创建新列车", - "create.station.assemble_train": "组装列车", - "create.station.disassemble_train": "拆解列车", - "create.station.remove_schedule": "取回时刻表", - "create.station.remove_auto_schedule": "放弃自动时刻表", - "create.station.no_assembly_diagonal": "无法搭建列车", - "create.station.no_assembly_diagonal_1": "在对角的轨道上", - "create.station.no_assembly_curve": "无法搭建列车", - "create.station.no_assembly_curve_1": "在弧形的轨道上", - "create.station.train_not_aligned": "无法拆解,", - "create.station.train_not_aligned_1": "仍有车厢未对齐", - "create.station.carriage_number": "车厢%1$s:", - "create.station.retry": "解决此问题并重试", - "create.station.no_bogeys": "无转向架", - "create.station.one_bogey": "1个转向架", - "create.station.more_bogeys": "%1$s个转向架", - "create.station.how_to": "对着高亮的轨道使用列车机壳创建转向架。", - "create.station.how_to_1": "破坏转向架最上方的方块来移除它。", - "create.station.how_to_2": "搭建每个都连接了1个或2个转向架的车厢。", - - "create.train_assembly.too_many_bogeys": "连接的转向架太多:%1$s", - "create.train_assembly.frontmost_bogey_at_station": "最前面的转向架必须位于车站标记处", - "create.train_assembly.no_bogeys": "找不到转向架", - "create.train_assembly.not_connected_in_order": "转向架没有按顺序连接", - "create.train_assembly.bogeys_too_close": "转向架%1$s和%2$s距离太近", - "create.train_assembly.single_bogey_carriage": "这种转向架不能单独支撑一个车厢", - "create.train_assembly.nothing_attached": "没有结构连接到转向架%1$s", - "create.train_assembly.no_controls": "列车上至少需要安装一个面向前方的驾驶台方块", - "create.train_assembly.sideways_controls": "一个安装的驾驶台方块面向侧面", - "create.train_assembly.bogey_created": "转向架已创建,再次点击来循环修改类型", - "create.train_assembly.requires_casing": "在轨道上使用列车机壳来创建转向架", - - "create.track_target.set": "目标轨道已选择", - "create.track_target.success": "成功绑定到目标轨道", - "create.track_target.clear": "已清除选择的轨道", - "create.track_target.missing": "先右击目标列车轨道", - "create.track_target.too_far": "目标轨道离此处太远", - "create.track_target.no_junctions": "目标轨道不能是交叉口", - "create.track_target.occupied": "目标轨道被占用", - "create.track_target.invalid": "无法在此处定位该轨道", - - "create.train.unnamed": "未命名列车", - "create.train.cannot_relocate_moving": "无法重新安置移动中的列车", - "create.train.relocate": "点击一个轨道来重新安置%1$s,潜行点击取消", - "create.train.relocate.abort": "重新安置被取消", - "create.train.relocate.success": "重新安置成功", - "create.train.relocate.valid": "可以重新安置到此处,点击确认", - "create.train.relocate.invalid": "无法重新安置列车到此处", - "create.train.relocate.too_far": "无法重新安置列车到过远处", - "create.train.departing_from": "发自%1$s", - "create.train.arrived_at": "到达%1$s", - "create.train.status": " 关于列车的信息:%1$s", - "create.train.status.back_on_track": "列车回到了轨道上", - "create.train.status.collision": "和其他列车相撞", - "create.train.status.end_of_track": "一节车厢已到达轨道末端", - "create.train.status.double_portal": "一节车厢不能在离开传送门的同时进入另一个传送门", - "create.train.status.coupling_stress": "由于连轴器的压力强制停止", - "create.train.status.track_missing": "列车下方缺少轨道", - "create.train.status.paused_for_manual": "时刻表被暂停以进行手动控制", - "create.train.status.opposite_driver": "路线要求驾驶员面向相反方向", - "create.train.status.missing_driver": "驾驶员不知所踪", - "create.train.status.found_driver": "找到一个新的驾驶员", - "create.train.status.navigation_success": "导航成功", - "create.train.status.no_match": "在图表上没有匹配'%1$s'的车站", - "create.train.status.no_path": "找不到前往下一个目的地合适路线", - - "create.track_signal.cannot_change_mode": "无法切换该信号的模式", - "create.track_signal.mode_change.entry_signal": "-> 如果区间未闭塞则允许通行", - "create.track_signal.mode_change.cross_signal": "-> 如果区间可穿过则允许通行", - - "create.contraption.controls.start_controlling": "现在控制:%1$s", - "create.contraption.controls.stop_controlling": "停止控制装置", - "create.contraption.controls.approach_station": "按住%1$s以接近%2$s", - - "create.display_link.set": "已选择目标位置", - "create.display_link.success": "成功绑定到目标位置", - "create.display_link.clear": "选择的位置已清除", - "create.display_link.too_far": "目标位置离此处太远", - "create.display_link.invalid": "链接器没有有效的目标,尝试重新放置它", - "create.display_link.title": "显示链接器", - "create.display_link.no_source": "不是显示来源", - "create.display_link.no_target": "不是显示目标", - "create.display_link.reading_from": "读取自:", - "create.display_link.writing_to": "发送到:", - "create.display_link.attached_side": "连接到的方块", - "create.display_link.targeted_location": "目标位置的方块", - "create.display_link.view_compatible": "点击查看所有兼容的", - "create.display_link.information_type": "信息类型", - "create.display_link.display_on": "写入数据到:", - "create.display_link.display_on_multiline": "从此处开始写入:", - - "create.display_source.label": "附加标签", - "create.display_source.combine_item_names": "合并物品名称", - "create.display_source.count_items": "匹配的物品数量", - "create.display_source.list_items": "列出匹配的物品", - "create.display_source.fluid_amount": "匹配的流体储量", - "create.display_source.list_fluids": "列出匹配的流体", - "create.display_source.nixie_tube": "复制辉光管", - "create.display_source.fill_level": "容器存量", - "create.display_source.fill_level.display": "显示格式", - "create.display_source.fill_level.percent": "百分比", - "create.display_source.fill_level.progress_bar": "进度条", - "create.display_source.value_list.display": "数量显示", - "create.display_source.value_list.shortened": "近似值", - "create.display_source.value_list.full_number": "完整数值", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "玩家死亡次数", - "create.display_source.scoreboard": "计分板", - "create.display_source.scoreboard.objective": "记分项ID", - "create.display_source.scoreboard.objective_not_found": "找不到'%1$s'", - "create.display_source.scoreboard.objective.deaths": "玩家死亡次数", - "create.display_source.time_of_day": "时间", - "create.display_source.stop_watch": "秒表", - "create.display_source.time.format": "时间格式", - "create.display_source.time.12_hour": "12小时制", - "create.display_source.time.24_hour": "24小时制", - "create.display_source.accumulate_items": "累计物品数量", - "create.display_source.item_throughput": "物品吞吐量", - "create.display_source.item_throughput.interval": "间隔", - "create.display_source.item_throughput.interval.second": "每秒", - "create.display_source.item_throughput.interval.minute": "每分钟", - "create.display_source.item_throughput.interval.hour": "每小时", - "create.display_source.train_status": "列车行程状态", - "create.display_source.station_summary": "列车站状态总括", - "create.display_source.station_summary.filter": "站点名称过滤器", - "create.display_source.station_summary.train_name_column": "列车列数", - "create.display_source.station_summary.platform_column": "平台列数", - "create.display_source.station_summary.now": "现在", - "create.display_source.station_summary.minutes": "分钟", - "create.display_source.station_summary.seconds": "%1$s秒", - "create.display_source.observed_train_name": "测得的列车名称", - "create.display_source.max_enchant_level": "最大附魔花费", - "create.display_source.boiler_status": "锅炉状态", - "create.display_source.entity_name": "实体名称", - "create.display_source.kinetic_speed": "转速(RPM)", - "create.display_source.kinetic_speed.absolute": "无视转向", - "create.display_source.kinetic_speed.directional": "包含转向", - "create.display_source.kinetic_stress": "网络应力", - "create.display_source.kinetic_stress.display": "显示信息", - "create.display_source.kinetic_stress.progress_bar": "进度条", - "create.display_source.kinetic_stress.percent": "百分比", - "create.display_source.kinetic_stress.current": "应力(SU)", - "create.display_source.kinetic_stress.max": "总应力", - "create.display_source.kinetic_stress.remaining": "剩余应力", - "create.display_source.redstone_power": "红石信号", - "create.display_source.redstone_power.display": "显示格式", - "create.display_source.redstone_power.number": "数字", - "create.display_source.redstone_power.progress_bar": "进度条", - "create.display_source.boiler.not_enough_space": "没有足够空间", - "create.display_source.boiler.for_boiler_status": "来显示锅炉状态", - - "create.display_target.line": "第%1$s行", - "create.display_target.page": "第%1$s页", - "create.display_target.single_line": "单行", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;▒", - - "create.super_glue.too_far": "选择范围过大", - "create.super_glue.cannot_reach": "选择的方块必须是相连的", - "create.super_glue.click_to_confirm": "再次点击以确认", - "create.super_glue.click_to_discard": "潜行点击以取消选择", - "create.super_glue.first_pos": "已选择第一坐标", - "create.super_glue.abort": "选择已取消", - "create.super_glue.not_enough": "物品栏内强力胶不足", - "create.super_glue.success": "正在上胶……", - - "create.gui.config.overlay1": "Hi :)", - "create.gui.config.overlay2": "这是一个叠加层例子", - "create.gui.config.overlay3": "点击拖拽你的鼠标", - "create.gui.config.overlay4": "来移动这个预览", - "create.gui.config.overlay5": "ESC退出当前界面", - "create.gui.config.overlay6": "并保存新的位置", - "create.gui.config.overlay7": "输入 /create overlay reset", - "create.gui.config.overlay8": "重置到默认位置", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: 服务器现在的 TPS 速度被降低为 %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: 服务器现在的 TPS 速度被降低了 %s ms >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: 服务器恢复到正常的 TPS 速度 :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: 用 /killtps stop 来让服务器的 TPS 速度变回正常", - "create.command.killTPSCommand.status.usage.1": "[Create]: 用 /killtps start 来手动降低服务器 TPS 速度", - "create.command.killTPSCommand.argument.tickTime": "tickTime", - - "create.contraption.minecart_contraption_too_big": "这一矿车装置似乎太大了,无法变为拾捡状态", - "create.contraption.minecart_contraption_illegal_pickup": "一股神秘的力量将这一装置与世界牢牢绑定在了一起", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "结构:停止移动", - "create.subtitle.peculiar_bell_use": "奇异钟:鸣响", - "create.subtitle.worldshaper_place": "环境塑形器:放置方块", - "create.subtitle.whistle_train_manual": "列车:鸣笛", - "create.subtitle.steam": "蒸汽噪音", - "create.subtitle.saw_activate_stone": "动力锯:切割", - "create.subtitle.schematicannon_finish": "蓝图加农炮:叮", - "create.subtitle.crafter_craft": "动力合成器:合成中", - "create.subtitle.wrench_remove": "组件:被破坏", - "create.subtitle.train3": "列车:移动", - "create.subtitle.whistle": "蒸汽笛:鸣笛", - "create.subtitle.cogs": "齿轮:嘎吱作响", - "create.subtitle.slime_added": "黏液:压扁", - "create.subtitle.whistle_train_low": "列车:鸣笛", - "create.subtitle.schematicannon_launch_block": "蓝图加农炮:发射", - "create.subtitle.controller_take": "讲台:取走物品", - "create.subtitle.crafter_click": "动力合成器:咔哒声", - "create.subtitle.depot_plop": "物品:着地", - "create.subtitle.confirm": "提示声:接受", - "create.subtitle.mixing": "搅拌器:搅拌声", - "create.subtitle.mechanical_press_activation_belt": "辊压机:撞击传送带", - "create.subtitle.fwoomp": "土豆加农炮:发射", - "create.subtitle.sanding_long": "打磨噪音", - "create.subtitle.crushing_1": "粉碎噪音", - "create.subtitle.depot_slide": "物品:滑入", - "create.subtitle.blaze_munch": "烈焰人:咀嚼", - "create.subtitle.funnel_flap": "漏斗:垂帘碰撞", - "create.subtitle.haunted_bell_use": "缠魂钟:鸣响", - "create.subtitle.scroll_value": "拨码输入:咔哒", - "create.subtitle.controller_put": "遥控器:放进讲台", - "create.subtitle.cranking": "手摇曲柄:转动", - "create.subtitle.sanding_short": "打磨噪音", - "create.subtitle.wrench_rotate": "扳手:拧动", - "create.subtitle.potato_hit": "土豆:击中", - "create.subtitle.saw_activate_wood": "动力锯:切割", - "create.subtitle.whistle_high": "蒸汽笛:尖鸣", - "create.subtitle.whistle_train_manual_low": "列车:鸣笛", - "create.subtitle.whistle_train": "列车:鸣笛", - "create.subtitle.haunted_bell_convert": "奇异钟:转化", - "create.subtitle.train": "列车:移动", - "create.subtitle.deny": "提示声:出错", - "create.subtitle.controller_click": "遥控器:按下按钮", - "create.subtitle.whistle_low": "蒸汽笛:低鸣", - "create.subtitle.copper_armor_equip": "潜水装备:铿锵", - "create.subtitle.mechanical_press_activation": "辊压机:工作中", - "create.subtitle.contraption_assemble": "结构:开始移动", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "木质支架", - "block.create.wooden_bracket.tooltip.summary": "用这种给人温馨感的木质支架_装饰_你的_传动杆_,_齿轮_和_管道_吧。", - - "block.create.metal_bracket.tooltip": "金属支架", - "block.create.metal_bracket.tooltip.summary": "用这种工业风格的金属支架_装饰_你的_传动杆_,_齿轮_和_管道_吧。", - - "block.create.seat.tooltip": "坐垫", - "block.create.seat.tooltip.summary": "坐下来享受旅程吧!坐垫将会把玩家固定在一个移动_装置_上。也可以用来作为居家装饰,毕竟它有许多颜色。", - "block.create.seat.tooltip.condition1": "右击坐垫时", - "block.create.seat.tooltip.behaviour1": "会使得玩家坐在_坐垫_上,按下左 Shift 可离开_坐垫_", - - "item.create.blaze_cake.tooltip": "烈焰蛋糕", - "item.create.blaze_cake.tooltip.summary": "为辛勤劳作的_烈焰人_精心准备的美味。让他们兴奋起来吧!", - - "item.create.wand_of_symmetry.tooltip": "对称之杖", - "item.create.wand_of_symmetry.tooltip.summary": "完美地镜面复制工作区域内的方块到另一边。", - "item.create.wand_of_symmetry.tooltip.condition1": "在快捷栏时", - "item.create.wand_of_symmetry.tooltip.behaviour1": "持续进行镜面复制", - "item.create.wand_of_symmetry.tooltip.control1": "右击地面时", - "item.create.wand_of_symmetry.tooltip.action1": "_创建_或_移动_镜面", - "item.create.wand_of_symmetry.tooltip.control2": "右击空气时", - "item.create.wand_of_symmetry.tooltip.action2": "_删除_镜面", - "item.create.wand_of_symmetry.tooltip.control3": "潜行右击时", - "item.create.wand_of_symmetry.tooltip.action3": "打开_配置界面_", - - "item.create.handheld_worldshaper.tooltip": "手持式环境塑形器", - "item.create.handheld_worldshaper.tooltip.summary": "创造_大陆_和_山脉_的手持工具。", - "item.create.handheld_worldshaper.tooltip.control1": "左击方块时", - "item.create.handheld_worldshaper.tooltip.action1": "将工具放置的方块设置为该方块", - "item.create.handheld_worldshaper.tooltip.control2": "右击方块时", - "item.create.handheld_worldshaper.tooltip.action2": "_放置_或_替换_目标方块", - "item.create.handheld_worldshaper.tooltip.control3": "潜行右击时", - "item.create.handheld_worldshaper.tooltip.action3": "打开工具的_配置界面_", - - "item.create.tree_fertilizer.tooltip": "树木肥料", - "item.create.tree_fertilizer.tooltip.summary": "由多种矿物质复合而成的强大生长剂,能够加速普通树种的生长速度。", - "item.create.tree_fertilizer.tooltip.condition1": "在树苗上使用时", - "item.create.tree_fertilizer.tooltip.behaviour1": "使得该树_无视_它的_生长空间条件_,立刻长大", - - "item.create.extendo_grip.tooltip": "伸缩机械手", - "item.create.extendo_grip.tooltip.summary": "biubiubiu! 大幅度_增加_了使用者的_触及距离_。可以使用_铜背罐_供能。", - "item.create.extendo_grip.tooltip.condition1": "在副手时", - "item.create.extendo_grip.tooltip.behaviour1": "增加_主手_所使用物品的_触及距离_", - "item.create.extendo_grip.tooltip.condition2": "装备铜背罐时", - "item.create.extendo_grip.tooltip.behaviour2": "使用罐中_气压_来_抵消_伸缩机械手的_耐久_损耗", - - "item.create.potato_cannon.tooltip": "土豆加农炮", - "item.create.potato_cannon.tooltip.summary": "噗!把你亲手栽培的蔬菜砸向你的敌人。可以使用_铜背罐_供能。", - "item.create.potato_cannon.tooltip.condition1": "右击时", - "item.create.potato_cannon.tooltip.behaviour1": "_发射_你_物品栏_中任一可作为弹药的物品", - "item.create.potato_cannon.tooltip.condition2": "装备铜背罐时", - "item.create.potato_cannon.tooltip.behaviour2": "使用罐中_气压_来_抵消_土豆加农炮的_耐久_损耗", - - "item.create.filter.tooltip": "过滤器", - "item.create.filter.tooltip.summary": "可用于_精确控制_物流设备的_输出_以及_输入_,使得通过的物品流与_一组_物品或者数个_相嵌套的过滤器_相匹配。", - "item.create.filter.tooltip.condition1": "放置于过滤槽时", - "item.create.filter.tooltip.behaviour1": "根据过滤器的_配置_,来_决定_物品流是否能够通过", - "item.create.filter.tooltip.condition2": "右击时", - "item.create.filter.tooltip.behaviour2": "打开_配置界面_", - - "item.create.attribute_filter.tooltip": "属性过滤器", - "item.create.attribute_filter.tooltip.summary": "可用于_精确控制_物流设备的_输出_以及_输入_,使得通过的物品流与_一组_物品_属性_以及_分类_相匹配。", - "item.create.attribute_filter.tooltip.condition1": "放置于过滤槽时", - "item.create.attribute_filter.tooltip.behaviour1": "根据过滤器的_配置_,来_决定_物品流是否能够通过", - "item.create.attribute_filter.tooltip.condition2": "右击时", - "item.create.attribute_filter.tooltip.behaviour2": "打开_配置界面_", - - "item.create.empty_schematic.tooltip": "空白蓝图", - "item.create.empty_schematic.tooltip.summary": "可作为合成材料或在_蓝图桌_使用。", - - "item.create.schematic.tooltip": "蓝图", - "item.create.schematic.tooltip.summary": "可将结构部署并放置到世界中,将蓝图全息影像部署完毕后,使用_蓝图加农炮_进行结构建造。", - "item.create.schematic.tooltip.condition1": "手持时", - "item.create.schematic.tooltip.behaviour1": "可以使用屏幕上的工具调整位置", - "item.create.schematic.tooltip.control1": "潜行右击时", - "item.create.schematic.tooltip.action1": "打开一个用于输入_精确坐标_的_界面_", - - "item.create.schematic_and_quill.tooltip": "蓝图与笔", - "item.create.schematic_and_quill.tooltip.summary": "用于将世界中的结构保存到 .nbt 文件。", - "item.create.schematic_and_quill.tooltip.condition1": "第一步", - "item.create.schematic_and_quill.tooltip.behaviour1": "手持蓝图与笔右击选择两个对角点", - "item.create.schematic_and_quill.tooltip.condition2": "第二步", - "item.create.schematic_and_quill.tooltip.behaviour2": "对准选定区域,按住_Ctrl_并_滑动滚轮_,可以调整选区的大小,右击保存", - "item.create.schematic_and_quill.tooltip.control1": "右击时", - "item.create.schematic_and_quill.tooltip.action1": "选取一个对角点/确认保存", - "item.create.schematic_and_quill.tooltip.control2": "按住 Ctrl 时", - "item.create.schematic_and_quill.tooltip.action2": "可在_空中_选择点,_滑动滚轮_可调整距离", - "item.create.schematic_and_quill.tooltip.control3": "潜行右击时", - "item.create.schematic_and_quill.tooltip.action3": "_重置_并删除选区", - - "block.create.schematicannon.tooltip": "蓝图加农炮", - "block.create.schematicannon.tooltip.summary": "发射方块,重新构建已在世界中部署的_蓝图_,会使用相邻箱子中的物品进行填充,_火药_作为燃料。", - "block.create.schematicannon.tooltip.condition1": "右击时", - "block.create.schematicannon.tooltip.behaviour1": "打开_界面_", - - "block.create.schematic_table.tooltip": "蓝图桌", - "block.create.schematic_table.tooltip.summary": "将保存的蓝图写入_空白蓝图_。", - "block.create.schematic_table.tooltip.condition1": "放入空白蓝图时", - "block.create.schematic_table.tooltip.behaviour1": "可从 Schematics 文件夹中上传所选文件", - - "item.create.goggles.tooltip": "工程师护目镜", - "item.create.goggles.tooltip.summary": "一副可以扩增显示_动力学信息_的实用眼镜。", - "item.create.goggles.tooltip.condition1": "装备时", - "item.create.goggles.tooltip.behaviour1": "根据对应动力组件的_转速等级_,显示它的_颜色指示器_,也会显示这个组件的_应力影响_以及_应力量_", - "item.create.goggles.tooltip.condition2": "看向仪表时", - "item.create.goggles.tooltip.behaviour2": "会显示与仪表相连的网络的_转速_、_应力_等详细信息", - "item.create.goggles.tooltip.condition3": "看向流体容器时", - "item.create.goggles.tooltip.behaviour3": "会显示出方块的_容量_细节,以及其中包含的所有_流体_", - - "item.create.wrench.tooltip": "扳手", - "item.create.wrench.tooltip.summary": "操控动力组件的实用工具。可用于_旋转_、_拆除_以及_配置_组件。", - "item.create.wrench.tooltip.control1": "右击动力方块时", - "item.create.wrench.tooltip.action1": "以点击的面为轴心_旋转_点击的_组件_", - "item.create.wrench.tooltip.control2": "潜行右击时", - "item.create.wrench.tooltip.action2": "会_拆除动力组件_并将其放回_你的背包_", - - "block.create.nozzle.tooltip": "分散网", - "block.create.nozzle.tooltip.summary": "依附在鼓风机上,能够将鼓风机的效果分散到_各个方向_。", - - "block.create.cuckoo_clock.tooltip": "布谷鸟闹钟", - "block.create.cuckoo_clock.tooltip.summary": "精致的工艺品,能够_记录时间_。", - "block.create.cuckoo_clock.tooltip.condition1": "接入动力时", - "block.create.cuckoo_clock.tooltip.behaviour1": "显示_当前时间_并且一天会咕咕两次,_中午_咕咕一次,_黄昏可以睡觉_的时候咕咕一次", - - "block.create.turntable.tooltip": "转盘", - "block.create.turntable.tooltip.summary": "让_旋转力_给你带来一场刺激的旋转风车体验。", - - "block.create.toolbox.tooltip": "工具箱", - "block.create.toolbox.tooltip.summary": "每个发明家最亲爱的伙伴!可以方便地大量_收纳__8种_不同的物品类型。", - "block.create.toolbox.tooltip.condition1": "拾起时", - "block.create.toolbox.tooltip.behaviour1": "_保留_库存_内容_", - "block.create.toolbox.tooltip.condition2": "放置在一定范围内时", - "block.create.toolbox.tooltip.behaviour2": "_附近_的_玩家_可以按下_访问附近的工具箱__快捷键_来_远程_访问它的库存", - "block.create.toolbox.tooltip.condition3": "右击时", - "block.create.toolbox.tooltip.behaviour3": "打开_工具箱界面_", - - "block.create.stockpile_switch.tooltip": "存量转信器", - "block.create.stockpile_switch.tooltip.summary": "根据连接的容器中_已储存物品数_或_流体量_切换红石信号。自带有过滤槽,与_比较器_不同的是,你可以配置_存量转信器_信号反转的_阈值_。", - "block.create.stockpile_switch.tooltip.condition1": "右击时", - "block.create.stockpile_switch.tooltip.behaviour1": "打开_配置界面_", - - "block.create.content_observer.tooltip": "物品侦测器", - "block.create.content_observer.tooltip.summary": "_检测_与配置过的_过滤器_匹配的_容器_、_管道_或_传送带_中的_物品_或_流体_。", - "block.create.content_observer.tooltip.condition1": "检测容器时", - "block.create.content_observer.tooltip.behaviour1": "如果检测的容器内有_匹配_的_物品_,发出_红石信号_", - "block.create.content_observer.tooltip.condition2": "检测漏斗时 ", - "block.create.content_observer.tooltip.behaviour2": "如果一个_匹配_的_物品_通过,则发出一次_红石脉冲_", - - "block.create.creative_crate.tooltip": "创造板条箱", - "block.create.creative_crate.tooltip.summary": "这种_储存容器_可以无限地复制任何物品。它还可以移除相邻的_蓝图加农炮_的材料需求。", - "block.create.creative_crate.tooltip.condition1": "标记了物品时", - "block.create.creative_crate.tooltip.behaviour1": "任何从容器中_提取_的物品都是_无限量_的,而任何_放置_到容器中的物品都会被_清空_", - - "item.create.creative_blaze_cake.tooltip": "创造蛋糕", - "item.create.creative_blaze_cake.tooltip.summary": "为_烈焰人燃烧室_特制的小食,可以让你_控制燃烧室的热量等级_。吃下这个蛋糕之后,烈焰人燃烧室将_不再耗尽燃料_。", - "item.create.creative_blaze_cake.tooltip.condition1": "右击烈焰人燃烧室时", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_锁定_烈焰人燃烧室的热量等级,如果再次使用,会使得燃烧室的热量等级开始_循环_变化", - - "block.create.controller_rail.tooltip": "控制铁轨", - "block.create.controller_rail.tooltip.summary": "一种_单向动力铁轨_,能够_精细控制_经过的矿车的_移动速度_。", - "block.create.controller_rail.tooltip.condition1": "通入红石信号时", - "block.create.controller_rail.tooltip.behaviour1": "根据_信号强度__加速_或_减速_通过的_矿车_,还会将红石信号传递到相邻的控制铁轨,为两个控制铁轨提供不同强度的红石信号,将导致信号强度在它们之间的控制铁轨上过渡", - - "item.create.sand_paper.tooltip": "砂纸", - "item.create.sand_paper.tooltip.summary": "用来_打磨_物品的砂纸,可以用机械手来实现自动化。", - "item.create.sand_paper.tooltip.condition1": "使用时", - "item.create.sand_paper.tooltip.behaviour1": "打磨_副手_上或者_准心所指_的物品", - - "item.create.builders_tea.tooltip": "建造工茶饮", - "item.create.builders_tea.tooltip.summary": "饮下这杯完美茶饮,开启神清气爽的一天。可以恢复_饥饿值_并获得_急迫_效果。", - - "item.create.refined_radiance.tooltip": "光辉石", - "item.create.refined_radiance.tooltip.summary": "一种用_光辉_锻造的化合物材料。", - "item.create.refined_radiance.tooltip.condition1": "尚未完工", - "item.create.refined_radiance.tooltip.behaviour1": "该材料在未来可能会有更多的用途", - - "item.create.shadow_steel.tooltip": "暗影钢", - "item.create.shadow_steel.tooltip.summary": "一种用_虚空_锻造的化合物材料。", - "item.create.shadow_steel.tooltip.condition1": "尚未完工", - "item.create.shadow_steel.tooltip.behaviour1": "该材料在未来可能会有更多的用途", - - "item.create.linked_controller.tooltip": "无线红石遥控器", - "item.create.linked_controller.tooltip.summary": "提供_六个_可以绑定_无线红石_频率的按钮,用于_遥控_附近的_无线红石信号终端_。", - "item.create.linked_controller.tooltip.condition1": "右击时", - "item.create.linked_controller.tooltip.behaviour1": "_拿起_或_放下_遥控器,拿起遥控器时,_控制移动_将被用来_操作遥控器_,而不是移动玩家", - "item.create.linked_controller.tooltip.condition2": "潜行右击时", - "item.create.linked_controller.tooltip.behaviour2": "打开手动_配置界面_", - "item.create.linked_controller.tooltip.condition3": "右击无线红石信号终端时", - "item.create.linked_controller.tooltip.behaviour3": "启用_绑定模式_,按下_六个按键_中的一个,即可将此按键与_无线红石信号终端的频率_绑定", - "item.create.linked_controller.tooltip.condition4": "右击讲台时", - "item.create.linked_controller.tooltip.behaviour4": "将遥控器放在讲台上以便使用(潜行右击来取回遥控器)", - - "item.create.diving_helmet.tooltip": "潜水头盔", - "item.create.diving_helmet.tooltip.summary": "与_铜背罐_配合使用,为穿戴者提供在_水下_行动一段时间所需的_空气_。", - "item.create.diving_helmet.tooltip.condition1": "戴在头上时", - "item.create.diving_helmet.tooltip.behaviour1": "提供_水下呼吸_效果,缓慢消耗背罐中的_压缩空气_", - - "item.create.copper_backtank.tooltip": "铜背罐", - "item.create.copper_backtank.tooltip.summary": "一个可以_背在背上_的_铜罐_,用于携带一定量的压缩空气。", - "item.create.copper_backtank.tooltip.condition1": "背在背上时", - "item.create.copper_backtank.tooltip.behaviour1": "为其他需要_压缩空气_的装备提供所需的空气", - "item.create.copper_backtank.tooltip.condition2": "放下并接入动力时", - "item.create.copper_backtank.tooltip.behaviour2": "基于转速从周围环境中_收集_并_加压空气_", - - "block.create.placard.tooltip": "置物板", - "block.create.placard.tooltip.summary": "用这个漂亮的墙板把你的物品用黄铜框起来,支持移动装置!", - "block.create.placard.tooltip.condition1": "手持物品右击时", - "block.create.placard.tooltip.behaviour1": "将手持的_物品__放入_置物板,当内部已经有物品,且手持的物品与其匹配时,_发出_短暂的_红石_信号", - "block.create.placard.tooltip.condition2": "左击时", - "block.create.placard.tooltip.behaviour2": "_移除_内部的_物品_", - - "block.create.flywheel.tooltip": "飞轮", - "block.create.flywheel.tooltip.summary": "用壮观的黄铜轮子_装饰_你的_机器_。", - "block.create.flywheel.tooltip.condition1": "接入动力时", - "block.create.flywheel.tooltip.behaviour1": "开始旋转", - - "item.create.diving_boots.tooltip": "潜水靴", - "item.create.diving_boots.tooltip.summary": "一双_沉重的靴子_,让穿戴者可以更方便的探索海底。", - "item.create.diving_boots.tooltip.condition1": "穿在脚上时", - "item.create.diving_boots.tooltip.behaviour1": "穿戴者_下沉更快_且_无法游泳_,穿戴者可以在水下_行走_和_跳跃_,穿戴者不会被_传送带_移走", - - "item.create.crafting_blueprint.tooltip": "合成蓝图", - "item.create.crafting_blueprint.tooltip.summary": "_放在_墙上,便可用它来设置_特定的合成配方_,以便更快地制作物品。每个格子都可以设定一个配方。", - "item.create.crafting_blueprint.condition1": "右击空的格子时", - "item.create.crafting_blueprint.behaviour1": "打开一个_配方设置界面_,用于_设置_一个_合成配方_以及展示的物品", - "item.create.crafting_blueprint.condition2": "右击已设置好的格子时", - "item.create.crafting_blueprint.behaviour2": "使用_物品栏_中的物品制作_设置好的配方_,_潜行_可以一次合成_一组_", - - "item.create.minecart_coupling.tooltip": "矿车连轴器", - "item.create.minecart_coupling.tooltip.summary": "将多个_矿车装置_或_车厢装置_链接在一起,构成雄伟的列车。", - "item.create.minecart_coupling.tooltip.condition1": "在矿车上使用时", - "item.create.minecart_coupling.tooltip.behaviour1": "将两个矿车_链接_在一起,在移动时将它们保持_恒定的距离_", - - "item.create.experience_nugget.tooltip": "经验颗粒", - "item.create.experience_nugget.tooltip.summary": "_叮!_从你的奇妙发明中汲取_灵感_。", - "item.create.experience_nugget.tooltip.condition1": "使用时", - "item.create.experience_nugget.tooltip.behaviour1": "_吸收_其中包含的_经验值_", - - "block.create.peculiar_bell.tooltip": "奇异钟", - "block.create.peculiar_bell.tooltip.summary": "装饰用的_黄铜钟_。放在_灵魂火_的正上方可能会产生意料之外的后果……", - - "block.create.haunted_bell.tooltip": "缠魂钟", - "block.create.haunted_bell.tooltip.summary": "_被诅咒_的钟,来自下界的迷失的灵魂缠绕于其上。", - "block.create.haunted_bell.tooltip.condition1": "手持或鸣响时", - "block.create.haunted_bell.tooltip.behaviour1": "标识出附近可能生成_敌对生物_的_亮度不足_之处", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "可以用扳手调整它的行为", - "create.ponder.shared.storage_on_contraption": "与装置相接的容器,会自动拾取装置遇到的掉落物", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "动力源:16 RPM", - "create.ponder.shared.movement_anchors": "有了底盘和强力胶,移动起大型结构轻轻松松", - "create.ponder.tag.redstone": "逻辑组件", - "create.ponder.tag.redstone.description": "这些组件会在红石工程中发挥大用处", - "create.ponder.tag.contraption_assembly": "方块连接功能", - "create.ponder.tag.contraption_assembly.description": "将各个组件连接以便同时运动的工具以及组件", - "create.ponder.tag.fluids": "流体操纵器械", - "create.ponder.tag.fluids.description": "这些组件可以用于传递流体,以及利用流体进行工作", - "create.ponder.tag.decoration": "装饰", - "create.ponder.tag.decoration.description": "装饰是这些组件的常见用法", - "create.ponder.tag.windmill_sails": "用于风车轴承的帆", - "create.ponder.tag.windmill_sails.description": "在进行风车组装时会被算入风车强度的方块,这些方块的效能都是一样的", - "create.ponder.tag.arm_targets": "动力臂的工作目标", - "create.ponder.tag.arm_targets.description": "该组件可做为动力臂的输入或者输出点", - "create.ponder.tag.kinetic_appliances": "动力设备", - "create.ponder.tag.kinetic_appliances.description": "这些组件可以利用旋转力进行工作", - "create.ponder.tag.kinetic_sources": "动力源", - "create.ponder.tag.kinetic_sources.description": "能够产生旋转力的组件", - "create.ponder.tag.movement_anchor": "运动锚点", - "create.ponder.tag.movement_anchor.description": "允许创建移动装置的组件,它可以以数种方式使相接的结构运动起来", - "create.ponder.tag.kinetic_relays": "动力方块", - "create.ponder.tag.kinetic_relays.description": "用于传递旋转力的组件", - "create.ponder.tag.contraption_actor": "装置执行组件", - "create.ponder.tag.contraption_actor.description": "能在移动的装置上执行特殊功能的组件", - "create.ponder.tag.creative": "创造模式", - "create.ponder.tag.creative.description": "总有些东西是生存模式得不到的", - "create.ponder.tag.display_sources": "显示链接器的数据来源", - "create.ponder.tag.display_sources.description": "可以提供一些可被显示链接器读取的数据的组件或方块", - "create.ponder.tag.logistics": "物品运输", - "create.ponder.tag.logistics.description": "该组件可以协助物品运输", - "create.ponder.tag.display_targets": "显示链接器的输出目标", - "create.ponder.tag.display_targets.description": "可以处理和显示从显示链接器接收到的数据的组件或方块", - "create.ponder.tag.train_related": "铁路设备", - "create.ponder.tag.train_related.description": "用于建造或管理列车装置的组件", - - "create.ponder.analog_lever.header": "使用模拟拉杆控制红石信号", - "create.ponder.analog_lever.text_1": "模拟拉杆可提供紧凑而精确的红石信号源", - "create.ponder.analog_lever.text_2": "右击会提升输出的模拟信号的强度", - "create.ponder.analog_lever.text_3": "潜行右击会减少输出的模拟信号的强度", - - "create.ponder.andesite_tunnel.header": "安山隧道用法", - "create.ponder.andesite_tunnel.text_1": "安山隧道可用于遮掩传送带", - "create.ponder.andesite_tunnel.text_2": "当安山隧道与侧边有连接时……", - "create.ponder.andesite_tunnel.text_3": "……经过的所有物品堆都会被精准地分出一个物品", - "create.ponder.andesite_tunnel.text_4": "剩下的物品则不受影响,继续前进", - - "create.ponder.auto_schedule.header": "车站和调度", - "create.ponder.auto_schedule.text_1": "时刻表可用于为司机提供目的地", - "create.ponder.auto_schedule.text_2": "每当有列车出现时,比较器会收到一个信号", - "create.ponder.auto_schedule.text_3": "注意,只能从指示的方向接近车站", - "create.ponder.auto_schedule.text_4": "车站也可以用于自动分配新的时刻表", - "create.ponder.auto_schedule.text_5": "放置在车站上的时刻表会自动复制到当前列车上", - "create.ponder.auto_schedule.text_6": "与手动调度相反,司机不会携带物品在身上", - - "create.ponder.basin.header": "工作盆内物品处理", - "create.ponder.basin.text_1": "一个可以对放入的物品以及流体进行处理的盆", - "create.ponder.basin.text_2": "处理完毕后,工作盆会尝试从它下方的侧面输出", - "create.ponder.basin.text_3": "若在正确的位置上放置了有效的组件,工作盆会显示出一个输出龙头", - "create.ponder.basin.text_4": "有多种设备可以引发工作盆的这一行为", - "create.ponder.basin.text_5": "产物会被输出到盆下方的容器内", - "create.ponder.basin.text_6": "如果没有显示出输出龙头,那么盆内的产物将会一直留存在盆内", - "create.ponder.basin.text_7": "这在产物需要作为新一轮处理的原料时相当有用", - "create.ponder.basin.text_8": "需要输出的产物仍需从盆内取出", - "create.ponder.basin.text_9": "你可能需要过滤器避免未被处理的物品被抽取出来", - - "create.ponder.bearing_modes.header": "动力轴承的运动模式", - "create.ponder.bearing_modes.text_1": "停止时,轴承会控制结构以特定的角度停在最近的与网格相对齐之处", - "create.ponder.bearing_modes.text_2": "你可以调整使整个结构永不方块化,或者仅在结构的起始位置方块化", - - "create.ponder.belt_casing.header": "装壳传送带", - "create.ponder.belt_casing.text_1": "你可以用黄铜或者安山机壳装饰你的传送带", - "create.ponder.belt_casing.text_2": "使用扳手即可移除机壳", - - "create.ponder.belt_connector.header": "传送带用法", - "create.ponder.belt_connector.text_1": "手持传送带右击两根传动杆,可以将两根杆连接起来", - "create.ponder.belt_connector.text_2": "如果不小心选错了,潜行右击即可取消选择", - "create.ponder.belt_connector.text_3": "你也可以在传送带的中间加装额外的传动杆", - "create.ponder.belt_connector.text_4": "通过传送带连接的传动杆,会以相同的转速以及方向进行旋转", - "create.ponder.belt_connector.text_5": "加装的传动杆可以用扳手拆下来", - "create.ponder.belt_connector.text_6": "传送带亦可染色", - - "create.ponder.belt_directions.header": "传送带的有效连接方向", - "create.ponder.belt_directions.text_1": "传送带的连接方向并不是任意的", - "create.ponder.belt_directions.text_2": "1. 可以水平连接", - "create.ponder.belt_directions.text_3": "2. 可以对角连接", - "create.ponder.belt_directions.text_4": "3. 可以垂直连接", - "create.ponder.belt_directions.text_5": "4. 还可以水平连接竖直放置的传动杆", - "create.ponder.belt_directions.text_6": "以上为所有可能的连接方向,传送带的连接范围为 2 到 20 格", - - "create.ponder.belt_transport.header": "在物流中使用传送带", - "create.ponder.belt_transport.text_1": "运动的传送带可以运输物品以及其他实体", - "create.ponder.belt_transport.text_2": "空手右击传送带,即可将其上的物品拿下来", - - "create.ponder.blaze_burner.header": "烈焰人燃烧室补喂", - "create.ponder.blaze_burner.text_1": "烈焰人燃烧室可以为工作盆的物品处理提供热量", - "create.ponder.blaze_burner.text_2": "为此,你需要喂给烈焰人一些可燃物品", - "create.ponder.blaze_burner.text_3": "如果喂给它烈焰蛋糕,它还能达到更强的热量等级", - "create.ponder.blaze_burner.text_4": "你可以用机械手或者动力臂进行自动化补喂", - - "create.ponder.brass_funnel.header": "黄铜漏斗", - "create.ponder.brass_funnel.text_1": "安山岩漏斗一次只能提取出一个物品", - "create.ponder.brass_funnel.text_2": "黄铜漏斗可以一次提取一组物品", - "create.ponder.brass_funnel.text_3": "对着过滤槽滑动滚轮,还可以精确调节黄铜漏斗的提取数量", - "create.ponder.brass_funnel.text_4": "对着过滤槽使用某个物品,可以限制漏斗的行为,使其只传输匹配的物品", - - "create.ponder.brass_tunnel.header": "黄铜隧道用法", - "create.ponder.brass_tunnel.text_1": "黄铜隧道可以遮掩住你的传送带", - "create.ponder.brass_tunnel.text_2": "隧道的每一个开口面都有过滤槽", - "create.ponder.brass_tunnel.text_3": "在输入处的过滤槽仅会阻挡住不匹配的物品", - "create.ponder.brass_tunnel.text_4": "输出处的过滤槽可用于以种类为依据的物品整理", - "create.ponder.brass_tunnel.text_5": "当通过的物品有多个有效输出端时,那么隧道的分配模式将会决定这些物品何去何从", - "create.ponder.brass_tunnel.text_6": "连接了平行传送带的黄铜隧道,会将隧道、传送带组成一个组", - "create.ponder.brass_tunnel.text_7": "输入的物品现在会分配到所有连接的输出端", - "create.ponder.brass_tunnel.text_8": "在这一情况下,你也可以将物品直接输入到隧道方块中", - - "create.ponder.brass_tunnel_modes.header": "黄铜隧道的分配模式", - "create.ponder.brass_tunnel_modes.text_1": "使用扳手即可调节隧道的分配模式", - "create.ponder.brass_tunnel_modes.text_10": "“同步输入”是黄铜隧道的一种特殊设定", - "create.ponder.brass_tunnel_modes.text_11": "只有在组内全部的隧道都有一个等待通过的物品时,物品才能通过此隧道", - "create.ponder.brass_tunnel_modes.text_12": "这确保了所有受影响的传送带能够以相同的速率进行物品补给", - "create.ponder.brass_tunnel_modes.text_2": "“分流”会尝试在可用输出端之间均匀分配物品堆", - "create.ponder.brass_tunnel_modes.text_3": "如果某个输出端无法容纳更多的物品,那它会被跳过,不参与计算", - "create.ponder.brass_tunnel_modes.text_4": "“强制分流”不会跳过某个输出端,而是一直等待此输出端能够容纳更多物品,才会继续物品传输", - "create.ponder.brass_tunnel_modes.text_5": "“轮询调度”会保持物品堆完整,循环检索各个输出端,满足条件后分配整堆物品", - "create.ponder.brass_tunnel_modes.text_6": "与分流类似,如果某个输出端无法容纳更多物品,那它会被跳过", - "create.ponder.brass_tunnel_modes.text_7": "“强制轮询调度”不会跳过某个输出端", - "create.ponder.brass_tunnel_modes.text_8": "“最近优先”会将物品优先分配到距离输入端更近的输出端", - "create.ponder.brass_tunnel_modes.text_9": "“随机”会随机选择一个输出端,一次性分配整堆物品", - - "create.ponder.cart_assembler.header": "使用矿车装配站控制结构移动", - "create.ponder.cart_assembler.text_1": "矿车装配站会将它所连接的结构安装到矿车上", - "create.ponder.cart_assembler.text_2": "若没有通入红石信号,它会将矿车装置解散为方块的形式", - "create.ponder.cart_assembler.text_3": "对着矿车使用你的扳手,装置会变为可搬运的形式", - - "create.ponder.cart_assembler_dual.header": "组装车厢装置", - "create.ponder.cart_assembler_dual.text_1": "若两个矿车装配站分享了同一个结构", - "create.ponder.cart_assembler_dual.text_2": "给其中的任意一方的矿车装配站通入红石信号,都会创建出车厢装置", - "create.ponder.cart_assembler_dual.text_3": "两辆矿车此时的行为与用矿车连轴器连接在一起时十分相似", - - "create.ponder.cart_assembler_modes.header": "矿车装置的方向设定", - "create.ponder.cart_assembler_modes.text_1": "矿车装置会随着矿车的运动而发生转向", - "create.ponder.cart_assembler_modes.text_2": "该箭头指定结构的哪一侧将被视为“正面”", - "create.ponder.cart_assembler_modes.text_3": "如果装配站的配置为“旋转锁定”,那么装置的方向将不会改变", - - "create.ponder.cart_assembler_rails.header": "另外几种矿车以及铁轨", - "create.ponder.cart_assembler_rails.text_1": "放置在普通轨道上的矿车装配站并不会影响路过矿车装置的运动", - "create.ponder.cart_assembler_rails.text_2": "如果放置在动力铁轨或控制铁轨上且没有通入红石信号,矿车装置将停在此处,直到再次充能", - "create.ponder.cart_assembler_rails.text_3": "另外的几种矿车可以当作锚点来使用", - "create.ponder.cart_assembler_rails.text_4": "动力矿车会试图始终保持燃烧状态,并试图从任何连接的容器内提取燃料", - - "create.ponder.chain_drive.header": "使用链式传动箱传动旋转力", - "create.ponder.chain_drive.text_1": "同一行上的链式传动箱会相互间传递旋转", - "create.ponder.chain_drive.text_2": "所有以此种方式连接的传动杆都会以相同的方向进行旋转", - "create.ponder.chain_drive.text_3": "同一行的传动箱内的任意一个传动箱,旋转 90 度之后仍可以正常工作", - - "create.ponder.chain_gearshift.header": "利用可调节链式传动箱进行转速调节", - "create.ponder.chain_gearshift.text_1": "未充能的可调节链式传动箱与普通链式传动箱无异", - "create.ponder.chain_gearshift.text_2": "当被充能时,它将会把旋转力以双倍转速传动至其他链式传动箱", - "create.ponder.chain_gearshift.text_3": "若被充能的可调节传动箱并不是动力输入端,则它会把转速减半", - "create.ponder.chain_gearshift.text_4": "在这两种情况中,同一组的其他链式传动箱的转速都为被充能的可调节链式传动箱的两倍", - "create.ponder.chain_gearshift.text_5": "转速的倍率可在 x1 和 x2 间根据红石信号的强弱来精确调整", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "使用溜槽向下运输物品", - "create.ponder.chute.text_1": "溜槽可在两个容器之间垂直传输物品", - "create.ponder.chute.text_2": "使用扳手右击可以在溜槽上设置观察窗", - "create.ponder.chute.text_3": "对着另一个溜槽的侧面放置溜槽,将会放置下一个斜向的溜槽", - - "create.ponder.chute_upward.header": "使用溜槽向上运输物品", - "create.ponder.chute_upward.text_1": "在溜槽上或下方使用鼓风机时,物品会根据风的方向向上或下移动", - "create.ponder.chute_upward.text_2": "佩戴工程师护目镜时,你可以看见物品的移动方向", - "create.ponder.chute_upward.text_3": "在溜槽“被挡住的”末端,物品只能从侧边进行提取或输入", - - "create.ponder.clockwork_bearing.header": "使用发条轴承来使结构运动", - "create.ponder.clockwork_bearing.text_1": "发条轴承黏附其正前方的方块", - "create.ponder.clockwork_bearing.text_2": "当接受旋转力时,其附着结构会根据游戏内时间来进行旋转", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "右击可以激活/停止结构运动", - "create.ponder.clockwork_bearing.text_6": "在时针前方可添加第二个结构", - "create.ponder.clockwork_bearing.text_7": "请确保这两个结构没有互相被例如强力胶等方式黏附", - "create.ponder.clockwork_bearing.text_8": "第二个结构将会作为分针进行旋转", - - "create.ponder.clutch.header": "使用离合器控制旋转力", - "create.ponder.clutch.text_1": "离合器能将旋转力直线传递", - "create.ponder.clutch.text_2": "当被红石充能,离合器会断开动力传递", - - "create.ponder.cog_speedup.header": "使用齿轮来换挡变速", - "create.ponder.cog_speedup.text_1": "大齿轮与小齿轮可以斜向传递动力", - "create.ponder.cog_speedup.text_2": "从大齿轮传递动力至小齿轮时,转速翻倍", - "create.ponder.cog_speedup.text_3": "从小齿轮传递动力至大齿轮时,转速减半", - - "create.ponder.cogwheel.header": "使用齿轮来传递旋转力", - "create.ponder.cogwheel.text_1": "齿轮会将动力传递至临近的齿轮", - "create.ponder.cogwheel.text_2": "以此方式连接的齿轮,旋转方向相反", - - "create.ponder.cogwheel_casing.header": "装壳齿轮", - "create.ponder.cogwheel_casing.text_1": "黄铜机壳或安山机壳可用于装饰齿轮", - "create.ponder.cogwheel_casing.text_2": "在装壳后添加的组件将不会与传动轴相连", - "create.ponder.cogwheel_casing.text_3": "扳手可用于切换连接", - - "create.ponder.creative_fluid_tank.header": "创造流体储罐", - "create.ponder.creative_fluid_tank.text_1": "创造流体储罐可以提供无限量的流体", - "create.ponder.creative_fluid_tank.text_2": "使用一个含有流体的容器右击它,即可指定它提供特定的流体", - "create.ponder.creative_fluid_tank.text_3": "流体管道可以从中无限提取指定的流体", - "create.ponder.creative_fluid_tank.text_4": "任何被输入创造流体储罐的液体都将被销毁", - - "create.ponder.creative_motor.header": "使用创造马达产生旋转力", - "create.ponder.creative_motor.text_1": "创造马达是一种紧凑且可配置的旋转力源", - "create.ponder.creative_motor.text_2": "对其后面板滑动滚轮,可以改变马达的输出旋转转速", - - "create.ponder.creative_motor_mojang.header": "Mojang的神秘机械", - - "create.ponder.crushing_wheels.header": "使用粉碎轮处理物品", - "create.ponder.crushing_wheels.text_1": "一对粉碎轮,磨物快又准", - "create.ponder.crushing_wheels.text_2": "接入的旋转必须使得这两个轮子啮合转动", - "create.ponder.crushing_wheels.text_3": "扔入或者放入的物品都会被粉碎处理", - "create.ponder.crushing_wheels.text_4": "你也可以使用自动化方案进行物品的输入以及拾取", - - "create.ponder.deployer.header": "使用机械手", - "create.ponder.deployer.text_1": "接入旋转力,机械手便可以模仿玩家的交互行为", - "create.ponder.deployer.text_10": "对着机械手的前部右击,即可将手上的物品给予它使用", - "create.ponder.deployer.text_11": "物品也可以自动化输入到机械手内", - "create.ponder.deployer.text_12": "机械手附带一个过滤槽", - "create.ponder.deployer.text_13": "设定了过滤后,只有它手中的物品与过滤相匹配时,它才会工作", - "create.ponder.deployer.text_14": "只有与过滤匹配的物品才可输入……", - "create.ponder.deployer.text_15": "……只有不匹配的物品可被抽取出来", - "create.ponder.deployer.text_2": "它只会与它正前方第 2 格处的位置进行交互", - "create.ponder.deployer.text_3": "放在在它面前的方块不会阻拦它的工作", - "create.ponder.deployer.text_4": "机械手可以:", - "create.ponder.deployer.text_5": "放置方块", - "create.ponder.deployer.text_6": "使用物品", - "create.ponder.deployer.text_7": "激活方块", - "create.ponder.deployer.text_8": "采收方块", - "create.ponder.deployer.text_9": "以及攻击生物", - - "create.ponder.deployer_contraption.header": "在装置上使用机械手", - "create.ponder.deployer_contraption.text_1": "当机械手在移动的装置上时……", - "create.ponder.deployer_contraption.text_2": "机械手会对每一个经过的方块使用装置中任意容器内的物品", - "create.ponder.deployer_contraption.text_3": "过滤槽可用于指定要抽取的物品", - - "create.ponder.deployer_modes.header": "机械手的模式", - "create.ponder.deployer_modes.text_1": "在默认情况下,机械手模仿玩家的右击交互", - "create.ponder.deployer_modes.text_2": "使用扳手可以将模式调整为模仿玩家的左击交互", - - "create.ponder.deployer_processing.header": "使用机械手处理物品", - "create.ponder.deployer_processing.text_1": "当机械手持有合适的物品时,它可以自动处理下方的物品", - "create.ponder.deployer_processing.text_2": "物品可以被丢在机械手下方,或放在置物台上", - "create.ponder.deployer_processing.text_3": "当传送带上的物品经过机械手下方时……", - "create.ponder.deployer_processing.text_4": "……机械手会使物品停下,然后处理这个物品", - - "create.ponder.deployer_redstone.header": "使用红石控制机械手", - "create.ponder.deployer_redstone.text_1": "当被红石充能时,机械手会停止工作", - "create.ponder.deployer_redstone.text_2": "在停止工作前,机械手会完成当前正在进行的工作周期", - "create.ponder.deployer_redstone.text_3": "因此,通入单次负红石脉冲可以精确控制机械手,使其每次只进行单个周期的工作", - - "create.ponder.depot.header": "使用置物台", - "create.ponder.depot.text_1": "置物台可以被当成一个“静止的”传送带原件使用", - "create.ponder.depot.text_2": "右击可以手动放置或取下物品", - "create.ponder.depot.text_3": "与传送带一样,它也可以将其内的物品转送到其他设备中进行加工……", - "create.ponder.depot.text_4": "……同时物品也可以被机械手存取", - - "create.ponder.display_board.header": "使用翻牌显示器", - "create.ponder.display_board.text_1": "翻牌显示器是告示牌的可扩展替代品", - "create.ponder.display_board.text_2": "它们需要动力以运作", - "create.ponder.display_board.text_3": "可以对其使用命名牌来显示文字……", - "create.ponder.display_board.text_4": "……或通过使用显示链接器", - "create.ponder.display_board.text_5": "可以使用染料来改变单行的颜色", - "create.ponder.display_board.text_6": "可以通过空手点击来重置单行内容", - - "create.ponder.display_link.header": "配置显示链接器", - "create.ponder.display_link.text_1": "显示链接器可用于可视化动态信息", - "create.ponder.display_link.text_2": "首先,右击目标显示器……", - "create.ponder.display_link.text_3": "……然后将其连接到要读取的方块上", - "create.ponder.display_link.text_4": "打开界面选择和配置发送的内容", - "create.ponder.display_link.text_5": "显示器现在将从链接器接收信息", - "create.ponder.display_link.text_6": "不是所有方块都可以作为信息源", - "create.ponder.display_link.text_7": "每个兼容的方块都提供了独特的信息", - "create.ponder.display_link.text_8": "显示链接器可以用于多个不同的显示器", - - "create.ponder.display_link_redstone.header": "红石控制", - "create.ponder.display_link_redstone.text_1": "通入红石信号时,显示链接器停止发送新信息", - "create.ponder.display_link_redstone.text_2": "一旦红石信号断开,计时器就会重置,并立即发送新信息", - "create.ponder.display_link_redstone.text_3": "信息源方块发出的红石信号不会影响链接器", - - "create.ponder.empty_blaze_burner.header": "使用空的烈焰人燃烧室", - "create.ponder.empty_blaze_burner.text_1": "手持空的烈焰人燃烧室右击烈焰人来抓取烈焰人", - "create.ponder.empty_blaze_burner.text_2": "或者,可以直接从烈焰人刷怪笼中收集烈焰人", - "create.ponder.empty_blaze_burner.text_3": "这样,你便有了一个可供部分机器加工的热源", - "create.ponder.empty_blaze_burner.text_4": "如果是为了美观,空的烈焰人燃烧室也可以被打火石点燃", - "create.ponder.empty_blaze_burner.text_5": "你可以使用注入了灵魂的物品转化这种火焰", - "create.ponder.empty_blaze_burner.text_6": "但是,没有烈焰人,这样的火焰并不足以用于工业级加热工作", - - "create.ponder.encased_fluid_pipe.header": "装壳流体管道", - "create.ponder.encased_fluid_pipe.text_1": "铜机壳可以用于装饰流体管道", - "create.ponder.encased_fluid_pipe.text_2": "除了遮掩流体管道之外,装壳的流体管道将不会改变其连接状态", - "create.ponder.encased_fluid_pipe.text_3": "它将不会对旁边新增加或移除的管道做出反应", - - "create.ponder.fan_direction.header": "鼓风机的气流", - "create.ponder.fan_direction.text_1": "鼓风机使用旋转力来制造气流", - "create.ponder.fan_direction.text_2": "流速以及方向由所接受旋转力的强弱以及方向而定", - - "create.ponder.fan_processing.header": "使用鼓风机加工物品", - "create.ponder.fan_processing.text_1": "当气流吹过熔岩时,气流会被加热", - "create.ponder.fan_processing.text_2": "热气流中的物品会被冶炼", - "create.ponder.fan_processing.text_3": "但在气流中的食物会被直接烧成灰", - "create.ponder.fan_processing.text_4": "而想要烹饪食物,必须要通过吹过火焰的气流来烟熏食物", - "create.ponder.fan_processing.text_5": "当气流吹过水后,便可用于洗涤物品", - "create.ponder.fan_processing.text_6": "这种加工方法可以做到不少有趣的事情", - "create.ponder.fan_processing.text_7": "鼓风机的转速对加工的速度没有影响,只影响气流的吹拂距离", - "create.ponder.fan_processing.text_8": "而那些放置在置物台或者传送带上的物品,鼓风机也是可以处理的", - - "create.ponder.fluid_pipe_flow.header": "使用管道运输流体", - "create.ponder.fluid_pipe_flow.text_1": "流体管道可以用于连接两个或多个流体容器", - "create.ponder.fluid_pipe_flow.text_2": "使用扳手,可以为直管道安装观察窗", - "create.ponder.fluid_pipe_flow.text_3": "带有观察窗的管道不会建立侧向管道连接", - "create.ponder.fluid_pipe_flow.text_4": "使用动力泵,流体管道可以传输流体", - "create.ponder.fluid_pipe_flow.text_5": "一开始,流体不会真正地被抽出", - "create.ponder.fluid_pipe_flow.text_6": "只有当管道内的流体流彻底连通之后,流体才会开始逐渐从一个容器中转移到另一个中", - "create.ponder.fluid_pipe_flow.text_7": "这意味着流体管道本身并不真正存储任何流体", - - "create.ponder.fluid_pipe_interaction.header": "抽取和填充流体容器", - "create.ponder.fluid_pipe_interaction.text_1": "流体管道的末端可以与许多种容器连接", - "create.ponder.fluid_pipe_interaction.text_2": "任何可以容纳流体的容器都可以被填充或从中抽取", - "create.ponder.fluid_pipe_interaction.text_3": "开放的管道口可以吸走流体源方块……", - "create.ponder.fluid_pipe_interaction.text_4": "……或者将流体源排放出来", - "create.ponder.fluid_pipe_interaction.text_5": "管道也可以从许多种其他方块中直接抽取流体", - - "create.ponder.fluid_tank_sizes.header": "流体储罐的大小", - "create.ponder.fluid_tank_sizes.text_1": "流体储罐可以多格连接,提供更大的存储量", - "create.ponder.fluid_tank_sizes.text_2": "流体储罐最大横截面为 3x3……", - "create.ponder.fluid_tank_sizes.text_3": "……并且可以超过 30 格高", - "create.ponder.fluid_tank_sizes.text_4": "使用扳手可以打开或关闭观察窗", - - "create.ponder.fluid_tank_storage.header": "使用流体储罐存储流体", - "create.ponder.fluid_tank_storage.text_1": "流体储罐可以存储大量的流体", - "create.ponder.fluid_tank_storage.text_2": "流体管道可以在流体储罐的任何一面将流体输入/输出", - "create.ponder.fluid_tank_storage.text_3": "使用比较器可以检测储罐中的流体储量", - "create.ponder.fluid_tank_storage.text_4": "在生存模式中,无法直接用容器向储罐中存入流体,或是取出流体", - "create.ponder.fluid_tank_storage.text_5": "要装满/倒空流体容器,可以使用工作盆,分液池或注液器", - - "create.ponder.funnel_compat.header": "漏斗的兼容性", - "create.ponder.funnel_compat.text_1": "漏斗可以与一些其他组件互动", - "create.ponder.funnel_compat.text_2": "动力锯", - "create.ponder.funnel_compat.text_3": "置物台", - "create.ponder.funnel_compat.text_4": "分液池", - - "create.ponder.funnel_direction.header": "物流方向", - "create.ponder.funnel_direction.text_1": "直接放置时,漏斗会将物品从容器中取出", - "create.ponder.funnel_direction.text_2": "潜行放置时,漏斗会将物品置入容器中", - "create.ponder.funnel_direction.text_3": "使用扳手可以改变漏斗的存/取模式", - "create.ponder.funnel_direction.text_4": "相同的规则适用于大多数朝向", - "create.ponder.funnel_direction.text_5": "在传送带末端放置的漏斗会根据传送带的传动方向存/取物品", - - "create.ponder.funnel_intro.header": "使用漏斗", - "create.ponder.funnel_intro.text_1": "用漏斗来存取容器内的物品,可谓又快又好", - - "create.ponder.funnel_redstone.header": "红石信号控制", - "create.ponder.funnel_redstone.text_1": "红石信号会使漏斗停止工作", - - "create.ponder.funnel_transfer.header": "直接运输", - "create.ponder.funnel_transfer.text_1": "漏斗不能在闭合容器之间直接传输物品", - "create.ponder.funnel_transfer.text_2": "溜槽和智能溜槽更适用于这样的场景", - "create.ponder.funnel_transfer.text_3": "水平传输也是如此,也许传送带更方便快捷", - - "create.ponder.gantry_carriage.header": "使用起重机取物器", - "create.ponder.gantry_carriage.text_1": "起重机取物器可以被放置在起重机杆上,并且可以沿着起重机杆运动", - "create.ponder.gantry_carriage.text_2": "起重机可以移动其黏附的方块", - - "create.ponder.gantry_cascaded.header": "串联起重机", - "create.ponder.gantry_cascaded.text_1": "无需强力胶,起重机取物器便可与起重机杆相连", - "create.ponder.gantry_cascaded.text_2": "即使是在移动的起重机杆上也是如此", - "create.ponder.gantry_cascaded.text_3": "因此,起重机系统可以串联起来,如此可以影响到多轴向的运动", - - "create.ponder.gantry_direction.header": "起重机移动方向", - "create.ponder.gantry_direction.text_1": "起重机杆可以有相反的方向", - "create.ponder.gantry_direction.text_2": "起重机取物器的移动方向取决于起重机杆的方向", - "create.ponder.gantry_direction.text_3": "……以及起重机杆的旋转方向", - "create.ponder.gantry_direction.text_4": "在旋转传递中,此规则同样适用", - - "create.ponder.gantry_redstone.header": "起重机的力传递", - "create.ponder.gantry_redstone.text_1": "被红石信号激活的起重机杆,将不会移动其上的取物器", - "create.ponder.gantry_redstone.text_2": "作为替代,杆上的旋转力会传递到取物器的输出杆上", - - "create.ponder.gantry_shaft.header": "使用起重机杆", - "create.ponder.gantry_shaft.text_1": "起重机杆组成了起重机系统的基础,与其相接的取物器可以沿着杆进行移动", - "create.ponder.gantry_shaft.text_2": "起重机系统可以移动与其相接的方块", - - "create.ponder.gearbox.header": "使用十字齿轮箱传递旋转力", - "create.ponder.gearbox.text_1": "更改旋转轴向,很容易使得整个旋转体系变得臃肿不堪", - "create.ponder.gearbox.text_2": "十字齿轮箱则是替代方案,它的体积更为小巧紧凑", - "create.ponder.gearbox.text_3": "垂直相邻的传动杆,旋转方向呈镜像", - "create.ponder.gearbox.text_4": "直线连接的传动杆,旋转方向相反", - - "create.ponder.gearshift.header": "使用反转齿轮箱控制旋转力", - "create.ponder.gearshift.text_1": "反转齿轮箱可以直线传输旋转", - "create.ponder.gearshift.text_2": "通入红石信号后,输出端的旋转方向会被反转", - - "create.ponder.hand_crank.header": "使用手摇曲柄产生旋转力", - "create.ponder.hand_crank.text_1": "玩家可以使用手摇曲柄来手动产生旋转力", - "create.ponder.hand_crank.text_2": "按住右键可以逆时针旋转它", - "create.ponder.hand_crank.text_3": "它产生的转速相对较高", - "create.ponder.hand_crank.text_4": "潜行按住右键可以顺时针旋转它", - - "create.ponder.hose_pulley.header": "使用软管滑轮抽取或排放流体", - "create.ponder.hose_pulley.text_1": "软管滑轮可以用于方便地对一个较大区域进行抽取流体或填满流体的操作", - "create.ponder.hose_pulley.text_2": "通过输入动力可以调节软管末端的高度", - "create.ponder.hose_pulley.text_3": "反转动力输入的方向可以收起软管", - "create.ponder.hose_pulley.text_4": "管道可以连接在另一侧", - "create.ponder.hose_pulley.text_5": "连接的管道可以将流体输入到软管滑轮中,软管会在下方排出口处放置流体源……", - "create.ponder.hose_pulley.text_6": "……或者提供吸力来抽取世界中的流体", - "create.ponder.hose_pulley.text_7": "软管滑轮的抽取/排放速度取决于连接管道中流体的流速", - - "create.ponder.hose_pulley_infinite.header": "被动抽取和排放大体量流体", - "create.ponder.hose_pulley_infinite.text_1": "当软管被放进足够大的流体中时……", - "create.ponder.hose_pulley_infinite.text_2": "……它在抽取或排放流体时将不会影响流体源", - "create.ponder.hose_pulley_infinite.text_3": "可以从这些软管滑轮中无限量地抽取或向其排放流体", - - "create.ponder.hose_pulley_level.header": "软管滑轮的排水/抽水机制", - "create.ponder.hose_pulley_level.text_1": "当软管彻底收回时,软管滑轮无法工作", - "create.ponder.hose_pulley_level.text_2": "抽取流体的顺序为从上到下", - "create.ponder.hose_pulley_level.text_3": "流体表面最终将会被抽取到刚好低于软管开口", - "create.ponder.hose_pulley_level.text_4": "填充流体的顺序为从下到上", - "create.ponder.hose_pulley_level.text_5": "流体最多只能被填充至软管开口所在的高度", - - "create.ponder.item_drain.header": "使用分液池提取物品中的流体", - "create.ponder.item_drain.text_1": "分液池可以提取物品中的流体", - "create.ponder.item_drain.text_2": "右击可以将手持物品中的流体倒入分液池中", - "create.ponder.item_drain.text_3": "当物品从侧面输入时……", - "create.ponder.item_drain.text_4": "……物品将会滚过分液池顶部,并在此过程中将其包含的流体排入分液池内", - "create.ponder.item_drain.text_5": "流体管道可以从分液池中抽取流体", - - "create.ponder.item_vault_sizes.header": "物品保险库的尺寸", - "create.ponder.item_vault_sizes.text_1": "可以组合物品保险库以增加总容量", - "create.ponder.item_vault_sizes.text_2": "它们的直径最多可以有 3 个方块宽……", - "create.ponder.item_vault_sizes.text_3": "……长度最多为直径的 3 倍", - - "create.ponder.item_vault_storage.header": "在保险库中存储物品", - "create.ponder.item_vault_storage.text_1": "物品保险库可用于存储大量物品", - "create.ponder.item_vault_storage.text_2": "但是,不能手动添加或获取物品", - "create.ponder.item_vault_storage.text_3": "任何用于物品传输的组件都可以用于添加……", - "create.ponder.item_vault_storage.text_4": "……和从该容器中取出物品", - - "create.ponder.large_cogwheel.header": "使用大齿轮传递旋转力", - "create.ponder.large_cogwheel.text_1": "大齿轮可以以特定的角度相互连接", - "create.ponder.large_cogwheel.text_2": "可以利用大齿轮变更旋转轴向", - - "create.ponder.linear_chassis_attachment.header": "使用机壳底盘黏合方块", - "create.ponder.linear_chassis_attachment.text_1": "它的外露面可以变为黏性面", - "create.ponder.linear_chassis_attachment.text_2": "再次点击黏性面,可以将它的对面也变得具有黏性", - "create.ponder.linear_chassis_attachment.text_3": "空手潜行右击可以移除此面的黏性物", - "create.ponder.linear_chassis_attachment.text_4": "黏性面可以将此面前方的一长条方块黏住", - "create.ponder.linear_chassis_attachment.text_5": "使用扳手可以精确控制底盘的影响范围", - "create.ponder.linear_chassis_attachment.text_6": "按住 Ctrl 滑动滚轮,你可以一次性调节所有底盘的影响范围", - "create.ponder.linear_chassis_attachment.text_7": "若想让底盘的其他面也能粘方块,你需要用到强力胶", - "create.ponder.linear_chassis_attachment.text_8": "利用这些机制,任何形状的结构都可以作为装置移动", - - "create.ponder.linear_chassis_group.header": "成组移动机壳底盘", - "create.ponder.linear_chassis_group.text_1": "相邻的机壳底盘可以相互连接在一起", - "create.ponder.linear_chassis_group.text_2": "其中的一个底盘若被移动,其余的底盘也会跟着移动", - "create.ponder.linear_chassis_group.text_3": "不同种类的底盘,或者是朝向不一致的底盘,将不会相连", - - "create.ponder.mechanical_arm.header": "配置动力臂", - "create.ponder.mechanical_arm.text_1": "你得在放置动力臂之前就配置好它的输入以及输出端", - "create.ponder.mechanical_arm.text_2": "手持动力臂右击某个容器,可以将其指定为目标", - "create.ponder.mechanical_arm.text_3": "再次右击可以将其在输入端(蓝色)以及输出端(橙色)之间切换", - "create.ponder.mechanical_arm.text_4": "左击此组件可以移除选择", - "create.ponder.mechanical_arm.text_5": "将动力臂放下来后,它会将此前选择的方块作为目标", - "create.ponder.mechanical_arm.text_6": "在有效范围内,动力臂可以有任意数量的输出以及输入端", - "create.ponder.mechanical_arm.text_7": "然而,并不是所有的容器可以被直接交互", - "create.ponder.mechanical_arm.text_8": "在此情况下,漏斗和置物台可以解决此问题", - - "create.ponder.mechanical_arm_filtering.header": "过滤动力臂的输出端", - "create.ponder.mechanical_arm_filtering.text_1": "输入", - "create.ponder.mechanical_arm_filtering.text_2": "输出", - "create.ponder.mechanical_arm_filtering.text_3": "有时,你会想着利用某种过滤限制动力臂的目标", - "create.ponder.mechanical_arm_filtering.text_4": "动力臂自身并不提供任何过滤选项", - "create.ponder.mechanical_arm_filtering.text_5": "然而,若将黄铜漏斗作为目标,则漏斗的过滤槽可以应用至动力臂上", - "create.ponder.mechanical_arm_filtering.text_6": "动力臂足够智能,它不会去拿取那些它无法分配的物品", - - "create.ponder.mechanical_arm_modes.header": "动力臂的分配模式", - "create.ponder.mechanical_arm_modes.text_1": "输入", - "create.ponder.mechanical_arm_modes.text_2": "输出", - "create.ponder.mechanical_arm_modes.text_3": "若动力臂必须在数个有效的输出端之间作出选择……", - "create.ponder.mechanical_arm_modes.text_4": "……它会依照自己的设定选择特定的行为", - "create.ponder.mechanical_arm_modes.text_5": "手持扳手对其滑动滚轮,可以改变其配置", - "create.ponder.mechanical_arm_modes.text_6": "“轮询调度”模式很好理解,即循环输出至所有有效的输出端", - "create.ponder.mechanical_arm_modes.text_7": "如果某个输出端无法容纳更多物品,则它会被跳过", - "create.ponder.mechanical_arm_modes.text_8": "“强制轮询调度”不会跳过任何输出端,动力臂会一直等待,直到输出端有空位容纳物品输入", - "create.ponder.mechanical_arm_modes.text_9": "“第一目标优先”模式会使得动力臂先将物品输出至更早被选择的输出端", - - "create.ponder.mechanical_arm_redstone.header": "利用红石信号控制动力臂", - "create.ponder.mechanical_arm_redstone.text_1": "通入红石信号后,动力臂会停止工作", - "create.ponder.mechanical_arm_redstone.text_2": "在停止工作前,它会完成当前正在进行的工作周期", - "create.ponder.mechanical_arm_redstone.text_3": "因此,通入单次负红石脉冲可以精确控制动力臂,使其每次只进行单个周期的工作", - - "create.ponder.mechanical_bearing.header": "使用动力轴承移动结构", - "create.ponder.mechanical_bearing.text_1": "动力轴承会与其前方的方块黏合在一起", - "create.ponder.mechanical_bearing.text_2": "接收到旋转力后,它会将这一黏合结构组装为旋转装置", - - "create.ponder.mechanical_crafter.header": "设置动力合成器", - "create.ponder.mechanical_crafter.text_1": "动力合成器阵列可用于自动化任何合成配方的制作", - "create.ponder.mechanical_crafter.text_2": "使用扳手可以调控合成器的合成通路", - "create.ponder.mechanical_crafter.text_3": "所有的合成通路必须汇集到任意一侧的一个出口,整套合成器方可算是设置正确", - "create.ponder.mechanical_crafter.text_4": "输出产物会被放入位于出口的容器中", - "create.ponder.mechanical_crafter.text_5": "动力合成器的运转需要旋转力的供应", - "create.ponder.mechanical_crafter.text_6": "右击合成器正面,可以手动放入物品", - "create.ponder.mechanical_crafter.text_7": "一旦合成通路上的所有合成槽位都有了物品,合成就会开始", - "create.ponder.mechanical_crafter.text_8": "而对于那些没有完全占满所有合成器槽位的配方,你可以通入红石信号强制开启合成", - - "create.ponder.mechanical_crafter_connect.header": "连接动力合成器的容器", - "create.ponder.mechanical_crafter_connect.text_1": "合成器可以自动接受向其输入的物品", - "create.ponder.mechanical_crafter_connect.text_2": "对其背面使用扳手,可以连接合成器", - "create.ponder.mechanical_crafter_connect.text_3": "所有相连的合成器可以访问同一个位置的输入", - - "create.ponder.mechanical_crafter_covers.header": "盖住动力合成器的合成槽", - "create.ponder.mechanical_crafter_covers.text_1": "有些配方需要额外的合成器,来补足合成通路上的间隙", - "create.ponder.mechanical_crafter_covers.text_2": "使用合成槽盖板,合成器在合成时的行为就如同一个空的合成槽位", - "create.ponder.mechanical_crafter_covers.text_3": "使用扳手在背面创建的的共享输入也可以跨越有盖的合成器", - - "create.ponder.mechanical_drill.header": "使用动力钻头破坏方块", - "create.ponder.mechanical_drill.text_1": "向其通入旋转力后,动力钻头会破坏它面前的方块", - "create.ponder.mechanical_drill.text_2": "它的挖掘速度取决于通入的旋转速度", - - "create.ponder.mechanical_drill_contraption.header": "在装置中使用动力钻头", - "create.ponder.mechanical_drill_contraption.text_1": "当钻头作为运动装置一部分移动时……", - "create.ponder.mechanical_drill_contraption.text_2": "……它会破坏掉它撞上的方块", - - "create.ponder.mechanical_harvester.header": "在装置中使用动力收割机", - "create.ponder.mechanical_harvester.text_1": "当收割机作为运动装置一部分移动时……", - "create.ponder.mechanical_harvester.text_2": "它会采收其路径上的作物,并重置这些作物的生长进度", - - "create.ponder.mechanical_mixer.header": "使用动力搅拌器处理物品", - "create.ponder.mechanical_mixer.text_1": "使用搅拌器和工作盆,你可以自动化某些合成配方", - "create.ponder.mechanical_mixer.text_2": "有效配方包括各种无序合成配方,以及一些额外的配方", - "create.ponder.mechanical_mixer.text_3": "一些配方可能需要使用烈焰人燃烧室提供热量", - "create.ponder.mechanical_mixer.text_4": "过滤槽可用于解决两个配方相互冲突的情况", - - "create.ponder.mechanical_piston.header": "使用动力活塞移动结构", - "create.ponder.mechanical_piston.text_1": "动力活塞可以移动它前方的方块", - "create.ponder.mechanical_piston.text_2": "移动速度和方向取决于通入活塞的旋转力", - "create.ponder.mechanical_piston.text_3": "黏性动力活塞可以将连接的方块拉回来", - - "create.ponder.mechanical_piston_modes.header": "动力活塞的移动模式", - "create.ponder.mechanical_piston_modes.text_1": "一旦活塞停下,被移动的结构就会恢复到方块状态", - "create.ponder.mechanical_piston_modes.text_2": "你也可以将其配置为从不方块化,或者只在起始位置方块化", - - "create.ponder.mechanical_plough.header": "在装置中使用动力犁", - "create.ponder.mechanical_plough.text_1": "当动力犁作为运动装置一部分移动时……", - "create.ponder.mechanical_plough.text_2": "……它会破坏掉那些不具有固体碰撞箱的方块", - "create.ponder.mechanical_plough.text_3": "此外,动力犁可以耕地", - "create.ponder.mechanical_plough.text_4": "……它也可以在不伤害实体的情况下推动它们", - - "create.ponder.mechanical_press.header": "使用动力辊压机处理物品", - "create.ponder.mechanical_press.text_1": "动力辊压机可以处理位于其下方的物品", - "create.ponder.mechanical_press.text_2": "在其下方丢入物品,或者将物品放在置物台上,都算作有效的物品输入", - "create.ponder.mechanical_press.text_3": "若物品位于传送带上……", - "create.ponder.mechanical_press.text_4": "辊压机会使物品停下,然后自动处理这一物品", - - "create.ponder.mechanical_press_compacting.header": "使用动力辊压机压缩物品", - "create.ponder.mechanical_press_compacting.text_1": "对放置于工作盆内的物品进行辊压,可以将这些物品压缩在一起", - "create.ponder.mechanical_press_compacting.text_2": "压缩意指任何同种物品填满了 2x2 或者 3x3 网格的配方,以及一些额外的配方", - "create.ponder.mechanical_press_compacting.text_3": "一些配方可能需要烈焰人燃烧室提供热量", - "create.ponder.mechanical_press_compacting.text_4": "过滤槽可用于解决两个配方相互冲突的情况", - - "create.ponder.mechanical_pump_flow.header": "使用动力泵传输流体", - "create.ponder.mechanical_pump_flow.text_1": "动力泵可以控制管道网络中的流体", - "create.ponder.mechanical_pump_flow.text_2": "当接入动力时,其上的箭头指示流体流向", - "create.ponder.mechanical_pump_flow.text_3": "泵后的管道网络正在抽取流体……", - "create.ponder.mechanical_pump_flow.text_4": "……而泵前的网络则在排放流体", - "create.ponder.mechanical_pump_flow.text_5": "反转动力方向将会改变流体流向", - "create.ponder.mechanical_pump_flow.text_6": "使用扳手可以手动改变动力泵的朝向", - - "create.ponder.mechanical_pump_speed.header": "动力泵的传输机制", - "create.ponder.mechanical_pump_speed.text_1": "动力泵的压力最多沿管线传递 16 格,与输入动力无关", - "create.ponder.mechanical_pump_speed.text_2": "提高输入转速,可以加快流体的蔓延速度……", - "create.ponder.mechanical_pump_speed.text_3": "……以及流体的传输速度", - "create.ponder.mechanical_pump_speed.text_4": "同一管道网络中的多个并联动力泵,它们的传输量可以叠加", - "create.ponder.mechanical_pump_speed.text_5": "使泵的朝向相互交替,可以方便地对齐流体流向", - - "create.ponder.mechanical_saw_breaker.header": "使用动力锯伐木", - "create.ponder.mechanical_saw_breaker.text_1": "向其通入旋转力后,动力锯可以直接砍伐掉它面前的树木", - "create.ponder.mechanical_saw_breaker.text_2": "想要一次性砍掉整棵树,锯子必须破坏掉树与地面连接的最后一个方块", - - "create.ponder.mechanical_saw_contraption.header": "在装置中使用动力锯", - "create.ponder.mechanical_saw_contraption.text_1": "当动力锯作为运动装置一部分移动时……", - "create.ponder.mechanical_saw_contraption.text_2": "……它会将撞到它的树木破坏掉", - - "create.ponder.mechanical_saw_processing.header": "使用动力锯处理物品", - "create.ponder.mechanical_saw_processing.text_1": "面朝上的动力锯可以处理各种物品", - "create.ponder.mechanical_saw_processing.text_2": "处理过后的物品的弹出方向始终与通入锯中的旋转转向相反", - "create.ponder.mechanical_saw_processing.text_3": "锯子可以与传送带放置在一条直线上,相互配合工作", - "create.ponder.mechanical_saw_processing.text_4": "若输入原料有多种可能产物,你可以用动力锯上的过滤槽指定只产出某种产物", - "create.ponder.mechanical_saw_processing.text_5": "若没有使用过滤槽,动力锯会在各产物中按顺序循环输出", - - "create.ponder.millstone.header": "使用石磨处理物品", - "create.ponder.millstone.text_1": "石磨会对输入的物品进行研磨", - "create.ponder.millstone.text_2": "在其侧边使用齿轮与其相耦合,方可为其通入动力", - "create.ponder.millstone.text_3": "顶部可以丢入或者塞入物品", - "create.ponder.millstone.text_4": "一段时间过后,右击石磨可以拿出其中的产物", - "create.ponder.millstone.text_5": "产物的提取也是可以自动化的", - - "create.ponder.nixie_tube.header": "使用辉光管", - "create.ponder.nixie_tube.text_1": "通入红石信号后,辉光管会显示出红石信号的强度", - "create.ponder.nixie_tube.text_2": "对着它使用更改过名称的命名牌,可以自定义它的显示文本", - "create.ponder.nixie_tube.text_3": "使用染料右击,便可更改辉光管的显示颜色", - - "create.ponder.piston_pole.header": "活塞延长杆", - "create.ponder.piston_pole.text_1": "若无相接的活塞杆,动力活塞无法移动其他方块", - "create.ponder.piston_pole.text_2": "在其背面安装的活塞杆长度,决定了活塞的推动范围", - - "create.ponder.portable_fluid_interface.header": "装置流体交换", - "create.ponder.portable_fluid_interface.text_1": "管道无法与运动装置内的流体储罐直接交互", - "create.ponder.portable_fluid_interface.text_2": "这一组件可以在不停止装置的情况下与装置内的流体存储进行交互", - "create.ponder.portable_fluid_interface.text_3": "放置第二个接口时,记得要与装置接口相隔 1 格或者 2 格的距离", - "create.ponder.portable_fluid_interface.text_4": "当它们彼此经过时,它们会连接在一起", - "create.ponder.portable_fluid_interface.text_5": "连接状态下,固定侧接口便会作为整个装置的流体存储代理", - "create.ponder.portable_fluid_interface.text_6": "流体可被泵入到装置内……", - "create.ponder.portable_fluid_interface.text_7": "……或是从装置中抽取出来", - "create.ponder.portable_fluid_interface.text_8": "如果一小段时间内没有流体交换,接口将会断开连接,然后装置重新开始运动", - - "create.ponder.portable_storage_interface.header": "装置存储交换", - "create.ponder.portable_storage_interface.text_1": "玩家无法与运动装置内的容器进行交互", - "create.ponder.portable_storage_interface.text_2": "这一组件可以在不停止装置的情况下与装置内的容器进行交互", - "create.ponder.portable_storage_interface.text_3": "放置第二个接口时,记得要与装置接口相隔 1 格或者 2 格的距离", - "create.ponder.portable_storage_interface.text_4": "当它们彼此经过时,它们会连接在一起", - "create.ponder.portable_storage_interface.text_5": "连接状态下,固定侧接口便会作为整个装置的存储空间代理", - "create.ponder.portable_storage_interface.text_6": "物品可被输入到装置内……", - "create.ponder.portable_storage_interface.text_7": "……或是从装置中提取出来", - "create.ponder.portable_storage_interface.text_8": "如果一小段时间内没有物品交换,接口将会断开连接,然后装置重新开始运动", - - "create.ponder.portable_storage_interface_redstone.header": "红石控制", - "create.ponder.portable_storage_interface_redstone.text_1": "通入红石信号可以阻止固定侧接口的连接行为", - - "create.ponder.powered_latch.header": "使用锁存器控制信号", - "create.ponder.powered_latch.text_1": "锁存器是一种可以用红石信号控制的拉杆", - "create.ponder.powered_latch.text_2": "后方输入的信号会将其设为开启状态", - "create.ponder.powered_latch.text_3": "侧边输入的信号会将其设为关闭状态", - "create.ponder.powered_latch.text_4": "你也可以手动切换其状态", - - "create.ponder.powered_toggle_latch.header": "使用转换锁存器控制信号", - "create.ponder.powered_toggle_latch.text_1": "转换锁存器是一种可以用红石信号控制的拉杆", - "create.ponder.powered_toggle_latch.text_2": "后方信号输入可以将其更改为", - "create.ponder.powered_toggle_latch.text_3": "……开启或者是关闭状态", - "create.ponder.powered_toggle_latch.text_4": "你也可以手动切换其状态", - - "create.ponder.pulse_extender.header": "使用脉冲延长器控制信号", - "create.ponder.pulse_extender.text_1": "脉冲延长器可以延长通过的信号", - "create.ponder.pulse_extender.text_2": "它会在短暂延迟后激活……", - "create.ponder.pulse_extender.text_3": "……并在配置的持续时间后取消激活", - "create.ponder.pulse_extender.text_4": "通过鼠标滚轮,可以配置持续时间", - "create.ponder.pulse_extender.text_5": "配置的持续时间最长可达 30 分钟", - - "create.ponder.pulse_repeater.header": "使用脉冲中继器控制信号", - "create.ponder.pulse_repeater.text_1": "脉冲中继器会将所有通入的红石信号缩减为一次脉冲", - "create.ponder.pulse_repeater.text_2": "通过鼠标滚轮,可以配置充能时间", - "create.ponder.pulse_repeater.text_3": "配置的延迟范围最长可达 30 分钟", - - "create.ponder.radial_chassis.header": "使用旋转底盘黏着方块", - "create.ponder.radial_chassis.text_1": "相同的旋转底盘会连续连接成一排", - "create.ponder.radial_chassis.text_2": "当其中的一个底盘被装置带动时,其余的底盘也会被带动", - "create.ponder.radial_chassis.text_3": "底盘的侧边可以变为黏性面", - "create.ponder.radial_chassis.text_4": "再次点击黏性面,可以让其所有面都变得带黏性", - "create.ponder.radial_chassis.text_5": "空手潜行右击可以移除其上的黏性物", - "create.ponder.radial_chassis.text_6": "若有物品与底盘的黏性面相接触……", - "create.ponder.radial_chassis.text_7": "……底盘便会与同层且位于半径内的所有可到达方块黏着在一起", - "create.ponder.radial_chassis.text_8": "使用扳手可以精确指定底盘的影响半径", - "create.ponder.radial_chassis.text_9": "任何黏性面都不可到达的方块不会被黏着", - - "create.ponder.redstone_contact.header": "接触式红石信号发生器", - "create.ponder.redstone_contact.text_1": "当两个接触式红石信号发生器面对面时,它们会发出红石信号", - "create.ponder.redstone_contact.text_2": "并且,若有一方位于运动装置上,此特性也能正常生效", - - "create.ponder.redstone_link.header": "使用无线红石信号终端", - "create.ponder.redstone_link.text_1": "无线红石信号终端可以无线传输红石信号", - "create.ponder.redstone_link.text_2": "潜行右击可以切换接收模式", - "create.ponder.redstone_link.text_3": "手持扳手右击也可以", - "create.ponder.redstone_link.text_4": "接收端会发出由传输端发来的信号,有效距离为 128 格", - "create.ponder.redstone_link.text_5": "在它们所带的槽位中放上物品,可以为它们指定频率", - "create.ponder.redstone_link.text_6": "只有频率相互匹配的终端方可互通", - - "create.ponder.rope_pulley.header": "使用绳索滑轮移动结构", - "create.ponder.rope_pulley.text_1": "绳索滑轮在接受旋转力时可以垂直移动方块结构", - "create.ponder.rope_pulley.text_2": "移动的方向及速度取决于提供的转速", - - "create.ponder.rope_pulley_attachment.header": "绳索滑轮与装置一同运动", - "create.ponder.rope_pulley_attachment.text_1": "当绳索滑轮本身在装置中被带动时……", - "create.ponder.rope_pulley_attachment.text_2": "……附着在滑轮上的结构会被滑轮拉着一同移动", - "create.ponder.rope_pulley_attachment.text_3": "注意,只有绳索滑轮停止工作时才能被移动", - - "create.ponder.rope_pulley_modes.header": "绳索滑轮的运动模式", - "create.ponder.rope_pulley_modes.text_1": "当绳索滑轮停止运动时,它所附着的移动结构便会方块化", - "create.ponder.rope_pulley_modes.text_2": "你可以调整使整个结构永不方块化,或者仅在结构的初始位置方块化", - - "create.ponder.rose_quartz_lamp.header": "玫瑰石英灯", - "create.ponder.rose_quartz_lamp.text_1": "玫瑰石英灯通入红石信号后会处于激活状态", - "create.ponder.rose_quartz_lamp.text_2": "它们之后会继续产生红石信号", - "create.ponder.rose_quartz_lamp.text_3": "当多盏灯排成一组时……", - "create.ponder.rose_quartz_lamp.text_4": "……激活一盏灯会集中信号给它,并取消激活其他所有的灯", - "create.ponder.rose_quartz_lamp.text_5": "比较器根据到激活的灯的距离产生输出", - "create.ponder.rose_quartz_lamp.text_6": "灯也可以用扳手手动开关", - - "create.ponder.rotation_speed_controller.header": "使用转速控制器", - "create.ponder.rotation_speed_controller.text_1": "转速控制器将旋转力从其转轴传递至它上方的大齿轮", - "create.ponder.rotation_speed_controller.text_2": "在其侧面滚动鼠标滚轮,可以调节输出转速", - - "create.ponder.sail.header": "使用风帆来组装风车", - "create.ponder.sail.text_1": "风帆是制作风车的趁手材料", - "create.ponder.sail.text_2": "无需强力胶等黏附手段,它们便可自行互相连结", - "create.ponder.sail.text_3": "手持染料右击可对其染色", - "create.ponder.sail.text_4": "手持剪刀右击可剪除帆布,使其变回风帆框架", - - "create.ponder.sail_frame.header": "使用风帆框架来组装风车", - "create.ponder.sail_frame.text_1": "风帆框架是制作风车的趁手材料", - "create.ponder.sail_frame.text_2": "无需强力胶等黏附手段,它们便可自行互相连结", - - "create.ponder.sequenced_gearshift.header": "使用可编程齿轮箱来控制转速", - "create.ponder.sequenced_gearshift.text_1": "可编程齿轮箱能够根据玩家设置的预设时序表来传递旋转", - "create.ponder.sequenced_gearshift.text_2": "对其右击可以打开设置面板", - "create.ponder.sequenced_gearshift.text_3": "接受红石信号时,它会开始执行其内部已配置好的时序指令表", - "create.ponder.sequenced_gearshift.text_4": "当完成时序指令表后,它会进入待机状态,再次接受红石信号后,它才会再次执行时序指令表内容", - "create.ponder.sequenced_gearshift.text_5": "红石比较器可以读取当前时序指令表完成进度", - - "create.ponder.shaft.header": "使用传动杆传递旋转力", - "create.ponder.shaft.text_1": "传动杆能直线传递旋转力", - - "create.ponder.shaft_casing.header": "装壳传动杆", - "create.ponder.shaft_casing.text_1": "安山或黄铜机壳,装饰传动杆的好伙伴", - - "create.ponder.smart_chute.header": "使用智能溜槽过滤物品", - "create.ponder.smart_chute.text_1": "智能溜槽是垂直溜槽的升级控制版", - "create.ponder.smart_chute.text_2": "当在其过滤槽内指定了物品后,溜槽只会传输这一指定标记的物品", - "create.ponder.smart_chute.text_3": "使用鼠标滚轮可以指定被过滤的物品数量", - "create.ponder.smart_chute.text_4": "通入红石信号可以使智能溜槽停止工作", - - "create.ponder.smart_pipe.header": "使用智能流体管道控制流体流动", - "create.ponder.smart_pipe.text_1": "智能流体管道可以限制通过它的流体种类", - "create.ponder.smart_pipe.text_2": "当紧邻流体源放置时,管道只会抽取设置的流体种类", - "create.ponder.smart_pipe.text_3": "使用任何包含流体的容器右击过滤槽,可以标记过滤的流体", - "create.ponder.smart_pipe.text_4": "当放在管道网络中时,只有匹配过滤器的流体才能通过此管道", - - "create.ponder.speedometer.header": "使用速度表来监测转速", - "create.ponder.speedometer.text_1": "速度表能显示相接组件的转速", - "create.ponder.speedometer.text_2": "当佩戴工程师护目镜时,可以看到仪表所显示的更详细的数据", - "create.ponder.speedometer.text_3": "红石比较器可以根据速度表的数值输出不同强弱的红石信号", - - "create.ponder.spout_filling.header": "使用注液器填充物品", - "create.ponder.spout_filling.text_1": "注液器可以将流体装入下方经过且可以接受该流体的物品", - "create.ponder.spout_filling.text_2": "注液器的流体容器无法直接手动交互", - "create.ponder.spout_filling.text_3": "使用管道可以将流体输入到注液器内", - "create.ponder.spout_filling.text_4": "输入的物品可以被放置在其下方的置物台上", - "create.ponder.spout_filling.text_5": "当传送带上的物品经过注液器下方时……", - "create.ponder.spout_filling.text_6": "注液器会使物品停下,然后自动处理这一物品", - - "create.ponder.stabilized_bearings.header": "装置固定朝向", - "create.ponder.stabilized_bearings.text_1": "当动力轴承在结构被带动时……", - "create.ponder.stabilized_bearings.text_2": "……它会确保它转盘的垂直朝向不变", - "create.ponder.stabilized_bearings.text_3": "跟默认的一样,动力轴承会黏着它前方的方块", - "create.ponder.stabilized_bearings.text_4": "这种情况下,它所黏着的子装置的垂直朝向也不会改变", - - "create.ponder.steam_engine.header": "安装蒸汽引擎", - "create.ponder.steam_engine.text_1": "蒸汽引擎可以放置在流体储罐上", - "create.ponder.steam_engine.text_10": "等级4", - "create.ponder.steam_engine.text_11": "4个引擎", - "create.ponder.steam_engine.text_12": "等级8", - "create.ponder.steam_engine.text_13": "8个引擎", - "create.ponder.steam_engine.text_2": "手持传动杆点击引擎创建动力输出", - "create.ponder.steam_engine.text_3": "有充足的热量、水和锅炉空间……", - "create.ponder.steam_engine.text_4": "……它们就会产生旋转力", - "create.ponder.steam_engine.text_5": "最低配置需要4个流体储罐", - "create.ponder.steam_engine.text_6": "在烈焰人燃烧室的帮助下,可以增加输出功率", - "create.ponder.steam_engine.text_7": "更高的功率等级需要更多水、空间和热量", - "create.ponder.steam_engine.text_8": "可以用工程师护目镜检查当前锅炉的功率等级", - "create.ponder.steam_engine.text_9": "每提升一个功率等级,就可以多装一个满功率输出的蒸汽引擎", - - "create.ponder.steam_whistle.header": "安装蒸汽笛", - "create.ponder.steam_whistle.text_1": "蒸汽笛能够被放置在流体储罐上", - "create.ponder.steam_whistle.text_2": "若流体储罐达到足够的温度……", - "create.ponder.steam_whistle.text_3": "……此时,用红石信号激活蒸汽笛,它便会演奏单个音符", - "create.ponder.steam_whistle.text_4": "对蒸汽笛使用蒸汽笛物品来降低它的音高", - "create.ponder.steam_whistle.text_5": "使用扳手来在三个八度之间切换", - "create.ponder.steam_whistle.text_6": "工程师护目镜能够帮你查看蒸汽笛的音高", - - "create.ponder.sticker.header": "使用黏着器来黏附方块", - "create.ponder.sticker.text_1": "你可以用红石信号来控制黏着器的行为", - "create.ponder.sticker.text_2": "当接受红石信号时,黏着器会黏着前方的方块", - "create.ponder.sticker.text_3": "如果黏着器以装置的形式移动,那么被黏着的方块也会一同移动", - "create.ponder.sticker.text_4": "再次接受红石信号时,它会断开与方块的黏连", - - "create.ponder.stressometer.header": "使用应力表来监测应力", - "create.ponder.stressometer.text_1": "应力表能显示当前动力网络内的应力信息", - "create.ponder.stressometer.text_2": "当佩戴工程师护目镜时,可以看到仪表所显示的更详细的数据", - "create.ponder.stressometer.text_3": "红石比较器可以根据应力表的数值输出不同强弱的红石信号", - - "create.ponder.super_glue.header": "使用强力胶来黏附方块", - "create.ponder.super_glue.text_1": "强力胶用于将方块组合成移动装置", - "create.ponder.super_glue.text_2": "右击两个端点来创建一个新的“胶合”区域", - "create.ponder.super_glue.text_3": "手持强力胶左击可以移除选区", - "create.ponder.super_glue.text_4": "同一个选区内相邻的方块会互相拉动对方", - "create.ponder.super_glue.text_5": "互相重叠的选区会一起移动", - "create.ponder.super_glue.text_6": "悬挂在其它方块上的方块通常不需要强力胶", - - "create.ponder.track_chunks.header": "横穿卸载的区块", - "create.ponder.track_chunks.text_1": "轨道在加载的区块之外仍然保持运作", - "create.ponder.track_chunks.text_2": "列车可以横穿世界上未加载的区块,这点可以放心", - "create.ponder.track_chunks.text_3": "它们仍然会停在车站或红灯处", - "create.ponder.track_chunks.text_4": "但是,钻头和其他机载机器将无法运行", - "create.ponder.track_chunks.text_5": "一旦靠近玩家,列车将重新出现", - - "create.ponder.track_observer.header": "侦测列车", - "create.ponder.track_observer.text_1": "选择一个列车轨道,然后将侦测器放在附近", - "create.ponder.track_observer.text_2": "侦测器将检测任何经过标记的列车", - "create.ponder.track_observer.text_3": "侦测器可以设置过滤为仅给匹配的货物激活", - - "create.ponder.track_placement.header": "放置列车轨道", - "create.ponder.track_placement.text_1": "一种专为列车装置设计的新型轨道", - "create.ponder.track_placement.text_2": "要批量放置多排轨道,单击现有轨道", - "create.ponder.track_placement.text_3": "然后选择或放置第二个轨道", - "create.ponder.track_placement.text_4": "轨道也可以放置为转弯或斜坡", - "create.ponder.track_placement.text_5": "连接时,轨道将尝试使每个转弯的大小相等", - "create.ponder.track_placement.text_6": "连接时按住疾跑键……", - "create.ponder.track_placement.text_7": "……将创建最长的适合的弯道", - "create.ponder.track_placement.text_8": "副手的材料会自动铺在轨道下", - - "create.ponder.track_portal.header": "轨道与下界", - "create.ponder.track_portal.text_1": "对着下界传送门放置的轨道……", - "create.ponder.track_portal.text_2": "……将尝试在另一侧创建成对的轨道", - "create.ponder.track_portal.text_3": "这条轨道上的列车现在可以跨维度旅行", - - "create.ponder.train_assembly.header": "组装列车", - "create.ponder.train_assembly.text_1": "选择列车轨道,然后将车站放置在附近", - "create.ponder.train_assembly.text_10": "每列列车都需要装上列车驾驶台", - "create.ponder.train_assembly.text_11": "可选的第二个允许从车站往两个方向出发", - "create.ponder.train_assembly.text_12": "打开车站UI并确认组装过程", - "create.ponder.train_assembly.text_13": "列车只能在车站被拆解为方块", - "create.ponder.train_assembly.text_14": "对着车站使用时,地图会在该位置添加一个带标签的标记", - "create.ponder.train_assembly.text_15": "组装好的列车可以使用扳手重新安置到相邻的轨道", - "create.ponder.train_assembly.text_2": "车站是你的轨道网络的路径点", - "create.ponder.train_assembly.text_3": "要创建新列车,打开UI并切换到组装模式", - "create.ponder.train_assembly.text_4": "在组装期间,时刻表上的列车不会接近这个车站", - "create.ponder.train_assembly.text_5": "在轨道上使用列车机壳创建新的转向架", - "create.ponder.train_assembly.text_6": "再次单击轨道,便可以在转向架类型之间循环", - "create.ponder.train_assembly.text_7": "在强力胶的帮助下连接方块", - "create.ponder.train_assembly.text_8": "如果组装好的列车能在其内的箱子或桶中找到燃料,它们会移动得更快", - "create.ponder.train_assembly.text_9": "储存在保险库中的燃料不会被列车消耗", - - "create.ponder.train_controls.header": "控制列车", - "create.ponder.train_controls.text_1": "每个列车装置都需要列车驾驶台", - "create.ponder.train_controls.text_2": "组装好后,右击方块开始驾驶", - "create.ponder.train_controls.text_3": "使用移动键加速和引导列车", - "create.ponder.train_controls.text_4": "如果需要,可以使用鼠标滚轮微调最高速度", - "create.ponder.train_controls.text_5": "按住空格键来接近最近的车站", - "create.ponder.train_controls.text_6": "列车只能在车站被拆解为方块", - "create.ponder.train_controls.text_7": "组装的蒸汽笛可以用疾跑键激活", - "create.ponder.train_controls.text_8": "潜行或再次点击可以停止控制列车", - - "create.ponder.train_schedule.header": "使用列车时刻表", - "create.ponder.train_schedule.text_1": "时刻表让列车可以被其他司机控制", - "create.ponder.train_schedule.text_2": "将物品拿在手上右击打开界面", - "create.ponder.train_schedule.text_3": "一旦规划好,时刻表就可以交给列车司机", - "create.ponder.train_schedule.text_4": "任何坐在列车驾驶台前面的生物,或者烈焰人燃烧室,都能成为一名合格的列车长", - "create.ponder.train_schedule.text_5": "用拴绳拴住生物可以更方便地使它们坐上座位", - "create.ponder.train_schedule.text_6": "可以随时从司机那里取回时刻表", - - "create.ponder.train_signal_placement.header": "放置列车信号机", - "create.ponder.train_signal_placement.text_1": "选择一个列车轨道,然后将信号机放置在附近", - "create.ponder.train_signal_placement.text_2": "信号机控制不由玩家驾驶的列车的行驶", - "create.ponder.train_signal_placement.text_3": "被调度的列车绝不会以相反方向穿过信号", - "create.ponder.train_signal_placement.text_4": "……除非添加第二个面向相反方向的信号", - "create.ponder.train_signal_placement.text_5": "可以连接辉光管让信号灯更加显眼", - - "create.ponder.train_signal_redstone.header": "信号机和红石", - "create.ponder.train_signal_redstone.text_1": "信号机通入红石信号后可以保持为红色", - "create.ponder.train_signal_redstone.text_2": "相反,红色信号产生比较器输出", - - "create.ponder.train_signal_signaling.header": "用信号机避免相撞", - "create.ponder.train_signal_signaling.text_1": "列车信号机将轨道分成多个区间", - "create.ponder.train_signal_signaling.text_2": "如果一个区间被占用,则不允许其他列车进入", - "create.ponder.train_signal_signaling.text_3": "因此,每个区间同时只能容纳一列列车", - "create.ponder.train_signal_signaling.text_4": "通过扳手可以使用第二种信号模式", - "create.ponder.train_signal_signaling.text_5": "黄铜信号区间通常会产生标准信号", - "create.ponder.train_signal_signaling.text_6": "这种特殊的信号可以在第二种情况下停止列车", - "create.ponder.train_signal_signaling.text_7": "它会停止列车,该列车在进入时……", - "create.ponder.train_signal_signaling.text_8": "……将无法立即离开该区间", - "create.ponder.train_signal_signaling.text_9": "这有助于排队等候的列车远离繁忙的区间", - - "create.ponder.valve_handle.header": "使用阀门手轮产生旋转力", - "create.ponder.valve_handle.text_1": "玩家可以手动使用阀门手轮来产生旋转力", - "create.ponder.valve_handle.text_2": "右击可使它逆时针旋转", - "create.ponder.valve_handle.text_3": "它的转速慢而精确", - "create.ponder.valve_handle.text_4": "潜行右击可使它顺时针旋转", - "create.ponder.valve_handle.text_5": "可以通过染色来美化阀门手轮", - - "create.ponder.valve_pipe.header": "使用流体阀门控制液体流", - "create.ponder.valve_pipe.text_1": "流体阀门可以控制管道网络中流体的蔓延", - "create.ponder.valve_pipe.text_2": "通过其上的传动杆输入动力可以控制它的开关", - "create.ponder.valve_pipe.text_3": "提供向“打开”方向的旋转力会打开阀门,使得流体可以通过", - "create.ponder.valve_pipe.text_4": "提供另一方向的旋转力可以关闭阀门,阻止流体通过", - - "create.ponder.water_wheel.header": "使用水车产生旋转力", - "create.ponder.water_wheel.text_1": "水车利用相邻的水流来产生应力", - "create.ponder.water_wheel.text_2": "水车接触水流的面越多,它的转速越高", - "create.ponder.water_wheel.text_3": "水车叶片应逆着水流方向摆放", - "create.ponder.water_wheel.text_4": "如果顺着水流摆放,它的效率则会降低", - - "create.ponder.weighted_ejector.header": "使用弹射置物台", - "create.ponder.weighted_ejector.text_1": "手持弹射置物台时,潜行右击可以设置弹射目标位置", - "create.ponder.weighted_ejector.text_10": "现在,只有等被放置的物品数量等于所设定数量时,弹射置物台才会弹射物品", - "create.ponder.weighted_ejector.text_11": "当其他实体站在弹射置物台上时会被直接弹射", - "create.ponder.weighted_ejector.text_2": "现在,放置下的弹射置物台会将物品弹射至目标位置", - "create.ponder.weighted_ejector.text_3": "限制范围内的任意距离和高度均可作为有效目标地点", - "create.ponder.weighted_ejector.text_4": "但是,目标位置与置物台的连线,必须垂直于置物台的侧面", - "create.ponder.weighted_ejector.text_5": "如果没有设置有效目标位置,弹射置物台会直接将其前方一格设为默认目标位置", - "create.ponder.weighted_ejector.text_6": "提供旋转力可为其蓄力", - "create.ponder.weighted_ejector.text_7": "蓄力完毕后,放置在它上方的物品会被立刻弹射出去", - "create.ponder.weighted_ejector.text_8": "如果目标为容器,则弹射置物台会等待容器有位置后再弹射物品", - "create.ponder.weighted_ejector.text_9": "使用扳手可以调整弹射所要求的物品数量", - - "create.ponder.weighted_ejector_redstone.header": "使用红石控制弹射置物台", - "create.ponder.weighted_ejector_redstone.text_1": "当被红石充能时,弹射置物台停止工作", - "create.ponder.weighted_ejector_redstone.text_2": "此外,置物台弹射的瞬间可以被侦测器侦测", - - "create.ponder.weighted_ejector_tunnel.header": "使用弹射置物台来分流物品", - "create.ponder.weighted_ejector_tunnel.text_1": "与黄铜隧道搭配使用时,弹射置物台可以将物品以特定数量进行分流", - "create.ponder.weighted_ejector_tunnel.text_2": "首先,将黄铜隧道调整为“最近优先”模式,从而让它优先侧面输出", - "create.ponder.weighted_ejector_tunnel.text_3": "置物台上所设置的物品数量则为被分流出去的物品数量", - "create.ponder.weighted_ejector_tunnel.text_4": "当所设置的物品数量被分流出去后……", - "create.ponder.weighted_ejector_tunnel.text_5": "……剩余的物品则会继续前进", - - "create.ponder.windmill_source.header": "使用风车轴承产生旋转力", - "create.ponder.windmill_source.text_1": "风车轴承会黏附它前方的方块", - "create.ponder.windmill_source.text_2": "在强力胶的帮助下创建一个可移动结构", - "create.ponder.windmill_source.text_3": "如果有足够多的类风帆方块黏附于其上,那么整体结构便可被视为风车", - "create.ponder.windmill_source.text_4": "右击启动后,风车轴承会开始产生旋转力", - "create.ponder.windmill_source.text_5": "风帆方块的数量决定了它的旋转速度", - "create.ponder.windmill_source.text_6": "使用扳手可以调整风车的旋转方向", - "create.ponder.windmill_source.text_7": "任何时候右击轴承,都可以将其停止,这样你就能再次修改风车的结构", - - "create.ponder.windmill_structure.header": "风车装置", - "create.ponder.windmill_structure.text_1": "任何有至少 8 个类风帆方块的结构,都被视为一个有效的风车", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json deleted file mode 100644 index 092966a62f..0000000000 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ /dev/null @@ -1,3013 +0,0 @@ -{ - "_": "Missing Localizations: 9", - - "_": "->------------------------] Game Elements [------------------------<-", - - "block.create.acacia_window": "相思木窗戶", - "block.create.acacia_window_pane": "相思木窗戶片", - "block.create.adjustable_chain_gearshift": "可調式鏈式變速箱", - "block.create.analog_lever": "可調式拉桿", - "block.create.andesite_belt_funnel": "安山岩輸送帶漏斗", - "block.create.andesite_casing": "安山岩機殼", - "block.create.andesite_encased_cogwheel": "安山齒輪箱", - "block.create.andesite_encased_large_cogwheel": "安山大齒輪箱", - "block.create.andesite_encased_shaft": "安山傳動軸箱", - "block.create.andesite_funnel": "安山岩漏斗", - "block.create.andesite_ladder": "安山岩梯子", - "block.create.andesite_pillar": "安山岩柱", - "block.create.andesite_tunnel": "安山岩物品隧道", - "block.create.asurine": "皓藍石", - "block.create.asurine_pillar": "皓藍石柱", - "block.create.basin": "作業盆", - "block.create.belt": "輸送帶", - "block.create.birch_window": "白樺木窗戶", - "block.create.birch_window_pane": "白樺木窗戶片", - "block.create.black_nixie_tube": "黑色真空管", - "block.create.black_sail": "黑色風帆", - "block.create.black_seat": "黑色坐墊", - "block.create.black_toolbox": "黑色工具箱", - "block.create.black_valve_handle": "黑色閥門開關", - "block.create.blaze_burner": "烈焰使者動力爐", - "block.create.blue_nixie_tube": "藍色真空管", - "block.create.blue_sail": "藍色風帆", - "block.create.blue_seat": "藍色坐墊", - "block.create.blue_toolbox": "藍色工具箱", - "block.create.blue_valve_handle": "藍色閥門開關", - "block.create.brass_belt_funnel": "黃銅輸送帶漏斗", - "block.create.brass_block": "黃銅方塊", - "block.create.brass_casing": "黃銅機殼", - "block.create.brass_encased_cogwheel": "黃銅齒輪箱", - "block.create.brass_encased_large_cogwheel": "黃銅大齒輪箱", - "block.create.brass_encased_shaft": "黃銅傳動軸箱", - "block.create.brass_funnel": "黃銅漏斗", - "block.create.brass_ladder": "黃銅梯子", - "block.create.brass_tunnel": "黃銅物品隧道", - "block.create.brown_nixie_tube": "棕色真空管", - "block.create.brown_sail": "棕色風帆", - "block.create.brown_seat": "棕色坐墊", - "block.create.brown_toolbox": "棕色工具箱", - "block.create.brown_valve_handle": "棕色閥門開關", - "block.create.calcite_pillar": "方解石柱", - "block.create.cart_assembler": "礦車裝修站", - "block.create.chocolate": "巧克力", - "block.create.chute": "滑槽", - "block.create.clockwork_bearing": "時鐘軸承", - "block.create.clutch": "離合器", - "block.create.cogwheel": "齒輪", - "block.create.content_observer": "物品偵測器", - "block.create.controller_rail": "控制軌道", - "block.create.controls": "火車控制台", - "block.create.copper_backtank": "銅製後背包", - "block.create.copper_casing": "銅機殼", - "block.create.copper_ladder": "銅製梯子", - "block.create.copper_shingle_slab": "銅屋瓦半磚", - "block.create.copper_shingle_stairs": "銅屋瓦階梯", - "block.create.copper_shingles": "銅屋瓦", - "block.create.copper_tile_slab": "銅磚瓦半磚", - "block.create.copper_tile_stairs": "銅磚瓦階梯", - "block.create.copper_tiles": "銅磚瓦", - "block.create.copper_valve_handle": "銅製閥門開關", - "block.create.creative_crate": "創造板條箱", - "block.create.creative_fluid_tank": "創造流體儲存罐", - "block.create.creative_motor": "創造馬達", - "block.create.crimsite": "緋紅岩", - "block.create.crimsite_pillar": "緋紅岩柱", - "block.create.crimson_window": "緋紅窗戶", - "block.create.crimson_window_pane": "緋紅窗戶片", - "block.create.crushing_wheel": "粉碎輪", - "block.create.crushing_wheel_controller": "粉碎輪控制器", - "block.create.cuckoo_clock": "布穀鳥鐘", - "block.create.cut_andesite": "切製安山岩", - "block.create.cut_andesite_brick_slab": "切製安山岩磚半磚", - "block.create.cut_andesite_brick_stairs": "切製安山岩磚階梯", - "block.create.cut_andesite_brick_wall": "切製安山岩磚牆", - "block.create.cut_andesite_bricks": "切製安山岩磚", - "block.create.cut_andesite_slab": "切製安山岩半磚", - "block.create.cut_andesite_stairs": "切製安山岩階梯", - "block.create.cut_andesite_wall": "切製安山岩牆", - "block.create.cut_asurine": "切製皓藍石", - "block.create.cut_asurine_brick_slab": "切製皓藍石磚半磚", - "block.create.cut_asurine_brick_stairs": "切製皓藍石磚階梯", - "block.create.cut_asurine_brick_wall": "切製皓藍石磚牆", - "block.create.cut_asurine_bricks": "切製皓藍石磚", - "block.create.cut_asurine_slab": "切製皓藍石半磚", - "block.create.cut_asurine_stairs": "切製皓藍石階梯", - "block.create.cut_asurine_wall": "切製皓藍石牆", - "block.create.cut_calcite": "切製方解石", - "block.create.cut_calcite_brick_slab": "切製方解石磚半磚", - "block.create.cut_calcite_brick_stairs": "切製方解石磚階梯", - "block.create.cut_calcite_brick_wall": "切製方解石磚牆", - "block.create.cut_calcite_bricks": "切製方解石磚", - "block.create.cut_calcite_slab": "切製方解石半磚", - "block.create.cut_calcite_stairs": "切製方解石階梯", - "block.create.cut_calcite_wall": "切製方解石牆", - "block.create.cut_crimsite": "切製緋紅岩", - "block.create.cut_crimsite_brick_slab": "切製緋紅岩磚半磚", - "block.create.cut_crimsite_brick_stairs": "切製緋紅岩磚階梯", - "block.create.cut_crimsite_brick_wall": "切製緋紅岩磚牆", - "block.create.cut_crimsite_bricks": "切製緋紅岩磚", - "block.create.cut_crimsite_slab": "切製緋紅岩半磚", - "block.create.cut_crimsite_stairs": "切製緋紅岩階梯", - "block.create.cut_crimsite_wall": "切製緋紅岩牆", - "block.create.cut_deepslate": "切製深板岩", - "block.create.cut_deepslate_brick_slab": "切製深板岩磚半磚", - "block.create.cut_deepslate_brick_stairs": "切製深板岩磚階梯", - "block.create.cut_deepslate_brick_wall": "切製深板岩磚牆", - "block.create.cut_deepslate_bricks": "切製深板岩磚", - "block.create.cut_deepslate_slab": "切製深板岩半磚", - "block.create.cut_deepslate_stairs": "切製深板岩階梯", - "block.create.cut_deepslate_wall": "切製深板岩牆", - "block.create.cut_diorite": "切製閃長岩", - "block.create.cut_diorite_brick_slab": "切製閃長岩磚半磚", - "block.create.cut_diorite_brick_stairs": "切製閃長岩磚階梯", - "block.create.cut_diorite_brick_wall": "切製閃長岩磚牆", - "block.create.cut_diorite_bricks": "切製閃長岩磚", - "block.create.cut_diorite_slab": "切製閃長岩半磚", - "block.create.cut_diorite_stairs": "切製閃長岩階梯", - "block.create.cut_diorite_wall": "切製閃長岩牆", - "block.create.cut_dripstone": "切製鐘乳石", - "block.create.cut_dripstone_brick_slab": "切製鐘乳石磚半磚", - "block.create.cut_dripstone_brick_stairs": "切製鐘乳石磚階梯", - "block.create.cut_dripstone_brick_wall": "切製鐘乳石磚牆", - "block.create.cut_dripstone_bricks": "切製鐘乳石磚", - "block.create.cut_dripstone_slab": "切製鐘乳石半磚", - "block.create.cut_dripstone_stairs": "切製鐘乳石階梯", - "block.create.cut_dripstone_wall": "切製鐘乳石牆", - "block.create.cut_granite": "切製花崗岩", - "block.create.cut_granite_brick_slab": "切製花崗岩磚半磚", - "block.create.cut_granite_brick_stairs": "切製花崗岩磚階梯", - "block.create.cut_granite_brick_wall": "切製花崗岩磚牆", - "block.create.cut_granite_bricks": "切製花崗岩磚", - "block.create.cut_granite_slab": "切製花崗岩半磚", - "block.create.cut_granite_stairs": "切製花崗岩階梯", - "block.create.cut_granite_wall": "切製花崗岩牆", - "block.create.cut_limestone": "切製石灰岩", - "block.create.cut_limestone_brick_slab": "切製石灰岩磚半磚", - "block.create.cut_limestone_brick_stairs": "切製石灰岩磚階梯", - "block.create.cut_limestone_brick_wall": "切製石灰岩磚牆", - "block.create.cut_limestone_bricks": "切製石灰岩磚", - "block.create.cut_limestone_slab": "切製石灰岩半磚", - "block.create.cut_limestone_stairs": "切製石灰岩階梯", - "block.create.cut_limestone_wall": "切製石灰岩牆", - "block.create.cut_ochrum": "切製赭金石", - "block.create.cut_ochrum_brick_slab": "切製赭金石磚半磚", - "block.create.cut_ochrum_brick_stairs": "切製赭金石磚階梯", - "block.create.cut_ochrum_brick_wall": "切製赭金石磚牆", - "block.create.cut_ochrum_bricks": "切製赭金石磚", - "block.create.cut_ochrum_slab": "切製赭金石半磚", - "block.create.cut_ochrum_stairs": "切製赭金石階梯", - "block.create.cut_ochrum_wall": "切製赭金石牆", - "block.create.cut_scorchia": "切製焦熔渣", - "block.create.cut_scorchia_brick_slab": "切製焦熔渣磚半磚", - "block.create.cut_scorchia_brick_stairs": "切製焦熔渣磚階梯", - "block.create.cut_scorchia_brick_wall": "切製焦熔渣磚牆", - "block.create.cut_scorchia_bricks": "切製焦熔渣磚", - "block.create.cut_scorchia_slab": "切製焦熔渣半磚", - "block.create.cut_scorchia_stairs": "切製焦熔渣階梯", - "block.create.cut_scorchia_wall": "切製焦熔渣牆", - "block.create.cut_scoria": "切製熔渣", - "block.create.cut_scoria_brick_slab": "切製熔渣磚半磚", - "block.create.cut_scoria_brick_stairs": "切製熔渣磚階梯", - "block.create.cut_scoria_brick_wall": "切製熔渣磚牆", - "block.create.cut_scoria_bricks": "切製熔渣磚", - "block.create.cut_scoria_slab": "切製熔渣半磚", - "block.create.cut_scoria_stairs": "切製熔渣階梯", - "block.create.cut_scoria_wall": "切製熔渣牆", - "block.create.cut_tuff": "切製凝灰岩", - "block.create.cut_tuff_brick_slab": "切製凝灰岩磚半磚", - "block.create.cut_tuff_brick_stairs": "切製凝灰岩磚階梯", - "block.create.cut_tuff_brick_wall": "切製凝灰岩磚牆", - "block.create.cut_tuff_bricks": "切製凝灰岩磚", - "block.create.cut_tuff_slab": "切製凝灰岩半磚", - "block.create.cut_tuff_stairs": "切製凝灰岩階梯", - "block.create.cut_tuff_wall": "切製凝灰岩牆", - "block.create.cut_veridium": "切製輝綠岩", - "block.create.cut_veridium_brick_slab": "切製輝綠岩磚半磚", - "block.create.cut_veridium_brick_stairs": "切製輝綠岩磚階梯", - "block.create.cut_veridium_brick_wall": "切製輝綠岩磚牆", - "block.create.cut_veridium_bricks": "切製輝綠岩磚", - "block.create.cut_veridium_slab": "切製輝綠岩半磚", - "block.create.cut_veridium_stairs": "切製輝綠岩階梯", - "block.create.cut_veridium_wall": "切製輝綠岩牆", - "block.create.cyan_nixie_tube": "青色真空管", - "block.create.cyan_sail": "藍綠色風帆", - "block.create.cyan_seat": "藍綠色坐墊", - "block.create.cyan_toolbox": "藍綠色工具箱", - "block.create.cyan_valve_handle": "藍綠色閥門開關", - "block.create.dark_oak_window": "黑橡木窗戶", - "block.create.dark_oak_window_pane": "黑橡木窗戶片", - "block.create.deepslate_pillar": "深板岩柱", - "block.create.deepslate_zinc_ore": "深板岩鋅礦", - "block.create.deployer": "機械手", - "block.create.depot": "置物臺", - "block.create.diorite_pillar": "閃長岩柱", - "block.create.display_board": "顯示板", - "block.create.display_link": "顯示鏈路", - "block.create.dripstone_pillar": "鐘乳石柱", - "block.create.encased_chain_drive": "鏈式傳動箱", - "block.create.encased_fan": "鼓風機", - "block.create.encased_fluid_pipe": "流體管道箱", - "block.create.exposed_copper_shingle_slab": "斑駁的銅屋瓦半磚", - "block.create.exposed_copper_shingle_stairs": "斑駁的銅屋瓦階梯", - "block.create.exposed_copper_shingles": "斑駁的銅屋瓦", - "block.create.exposed_copper_tile_slab": "斑駁的銅磚瓦半磚", - "block.create.exposed_copper_tile_stairs": "斑駁的銅磚瓦階梯", - "block.create.exposed_copper_tiles": "斑駁的銅磚瓦", - "block.create.fake_track": "地圖軌道標記", - "block.create.fluid_pipe": "流體管道", - "block.create.fluid_tank": "流體儲存罐", - "block.create.fluid_valve": "流體閥門", - "block.create.flywheel": "飛輪", - "block.create.framed_glass": "邊框玻璃", - "block.create.framed_glass_door": "邊框玻璃門", - "block.create.framed_glass_pane": "邊框玻璃片", - "block.create.framed_glass_trapdoor": "邊框玻璃地板門", - "block.create.gantry_carriage": "橋式起重機", - "block.create.gantry_shaft": "橋式起重機導軌", - "block.create.gearbox": "齒輪箱", - "block.create.gearshift": "變速箱", - "block.create.glass_fluid_pipe": "玻璃流體管道", - "block.create.granite_pillar": "花崗岩柱", - "block.create.gray_nixie_tube": "灰色真空管", - "block.create.gray_sail": "灰色風帆", - "block.create.gray_seat": "灰色坐墊", - "block.create.gray_toolbox": "灰色工具箱", - "block.create.gray_valve_handle": "灰色閥門開關", - "block.create.green_nixie_tube": "綠色真空管", - "block.create.green_sail": "綠色風帆", - "block.create.green_seat": "綠色坐墊", - "block.create.green_toolbox": "綠色工具箱", - "block.create.green_valve_handle": "綠色閥門開關", - "block.create.hand_crank": "手搖把手", - "block.create.haunted_bell": "靈魂鐘", - "block.create.honey": "蜂蜜", - "block.create.horizontal_framed_glass": "豎直邊框玻璃", - "block.create.horizontal_framed_glass_pane": "豎直邊框玻璃片", - "block.create.hose_pulley": "軟管滑輪", - "block.create.item_drain": "分液池", - "block.create.item_vault": "倉儲", - "block.create.jungle_window": "叢林木窗戶", - "block.create.jungle_window_pane": "叢林木窗戶片", - "block.create.large_bogey": "大轉向架", - "block.create.large_cogwheel": "大齒輪", - "block.create.layered_andesite": "疊層安山岩", - "block.create.layered_asurine": "疊層皓藍石", - "block.create.layered_calcite": "疊層方解石", - "block.create.layered_crimsite": "疊層緋紅岩", - "block.create.layered_deepslate": "疊層深板岩", - "block.create.layered_diorite": "疊層閃長岩", - "block.create.layered_dripstone": "疊層鐘乳石", - "block.create.layered_granite": "疊層花崗岩", - "block.create.layered_limestone": "疊層石灰岩", - "block.create.layered_ochrum": "疊層赭金石", - "block.create.layered_scorchia": "疊層焦熔渣", - "block.create.layered_scoria": "疊層熔渣", - "block.create.layered_tuff": "疊層凝灰岩", - "block.create.layered_veridium": "疊層輝綠岩", - "block.create.lectern_controller": "講台遙控器", - "block.create.light_blue_nixie_tube": "亮藍色真空管", - "block.create.light_blue_sail": "淡藍色風帆", - "block.create.light_blue_seat": "淡藍色坐墊", - "block.create.light_blue_toolbox": "淡藍色工具箱", - "block.create.light_blue_valve_handle": "淡藍色閥門開關", - "block.create.light_gray_nixie_tube": "亮灰色真空管", - "block.create.light_gray_sail": "淡灰色風帆", - "block.create.light_gray_seat": "淡灰色坐墊", - "block.create.light_gray_toolbox": "淺灰色工具箱", - "block.create.light_gray_valve_handle": "淡灰色閥門開關", - "block.create.lime_nixie_tube": "淺綠色真空管", - "block.create.lime_sail": "黃綠色風帆", - "block.create.lime_seat": "黃綠色坐墊", - "block.create.lime_toolbox": "黃綠色工具箱", - "block.create.lime_valve_handle": "黃綠色閥門開關", - "block.create.limestone": "石灰岩", - "block.create.limestone_pillar": "石灰岩柱", - "block.create.linear_chassis": "機殼底盤", - "block.create.lit_blaze_burner": "烈焰使者動力爐 (已啟動) ", - "block.create.magenta_nixie_tube": "洋紅色真空管", - "block.create.magenta_sail": "洋紅色風帆", - "block.create.magenta_seat": "洋紅色坐墊", - "block.create.magenta_toolbox": "洋紅色工具箱", - "block.create.magenta_valve_handle": "洋紅色閥門開關", - "block.create.mechanical_arm": "機械臂", - "block.create.mechanical_bearing": "機械軸承", - "block.create.mechanical_crafter": "機械合成器", - "block.create.mechanical_drill": "機械鑽頭", - "block.create.mechanical_harvester": "機械收割機", - "block.create.mechanical_mixer": "機械攪拌器", - "block.create.mechanical_piston": "機械活塞", - "block.create.mechanical_piston_head": "機械活塞頭", - "block.create.mechanical_plough": "機械犁", - "block.create.mechanical_press": "機械鍛壓機", - "block.create.mechanical_pump": "機械幫浦", - "block.create.mechanical_saw": "機械圓鋸機", - "block.create.metal_bracket": "金屬支架", - "block.create.metal_girder": "金屬樑", - "block.create.metal_girder_encased_shaft": "金屬傳動軸樑", - "block.create.millstone": "石磨", - "block.create.minecart_anchor": "礦車錨", - "block.create.mysterious_cuckoo_clock": "神秘布穀鳥鐘", - "block.create.nixie_tube": "真空管顯示器", - "block.create.nozzle": "鼓風機噴嘴", - "block.create.oak_window": "橡木窗戶", - "block.create.oak_window_pane": "橡木窗戶片", - "block.create.ochrum": "赭金石", - "block.create.ochrum_pillar": "赭金石柱", - "block.create.orange_sail": "橙色風帆", - "block.create.orange_seat": "橙色坐墊", - "block.create.orange_toolbox": "橙色工具箱", - "block.create.orange_valve_handle": "橙色閥門開關", - "block.create.ornate_iron_window": "華麗鐵窗戶", - "block.create.ornate_iron_window_pane": "華麗鐵窗戶片", - "block.create.oxidized_copper_shingle_slab": "氧化的銅屋瓦半磚", - "block.create.oxidized_copper_shingle_stairs": "氧化的銅屋瓦階梯", - "block.create.oxidized_copper_shingles": "氧化的銅屋瓦", - "block.create.oxidized_copper_tile_slab": "氧化的銅磚瓦半磚", - "block.create.oxidized_copper_tile_stairs": "氧化的銅磚瓦階梯", - "block.create.oxidized_copper_tiles": "氧化的銅磚瓦", - "block.create.peculiar_bell": "黃銅鐘", - "block.create.pink_nixie_tube": "粉紅色真空管", - "block.create.pink_sail": "粉紅色風帆", - "block.create.pink_seat": "粉紅色坐墊", - "block.create.pink_toolbox": "粉紅色工具箱", - "block.create.pink_valve_handle": "粉紅色閥門開關", - "block.create.piston_extension_pole": "活塞桿", - "block.create.placard": "標示牌", - "block.create.polished_cut_andesite": "拋光切製安山岩", - "block.create.polished_cut_andesite_slab": "拋光切製安山岩半磚", - "block.create.polished_cut_andesite_stairs": "拋光切製安山岩階梯", - "block.create.polished_cut_andesite_wall": "拋光切製安山岩牆", - "block.create.polished_cut_asurine": "拋光切製皓藍石", - "block.create.polished_cut_asurine_slab": "拋光切製皓藍石半磚", - "block.create.polished_cut_asurine_stairs": "拋光切製皓藍石階梯", - "block.create.polished_cut_asurine_wall": "拋光切製皓藍石牆", - "block.create.polished_cut_calcite": "拋光切製方解石", - "block.create.polished_cut_calcite_slab": "拋光切製方解石半磚", - "block.create.polished_cut_calcite_stairs": "拋光切製方解石階梯", - "block.create.polished_cut_calcite_wall": "拋光切製方解石牆", - "block.create.polished_cut_crimsite": "拋光切製緋紅岩", - "block.create.polished_cut_crimsite_slab": "拋光切製緋紅岩半磚", - "block.create.polished_cut_crimsite_stairs": "拋光切製緋紅岩階梯", - "block.create.polished_cut_crimsite_wall": "拋光切製緋紅岩牆", - "block.create.polished_cut_deepslate": "拋光切製深板岩", - "block.create.polished_cut_deepslate_slab": "拋光切製深板岩半磚", - "block.create.polished_cut_deepslate_stairs": "拋光切製深板岩階梯", - "block.create.polished_cut_deepslate_wall": "拋光切製深板岩牆", - "block.create.polished_cut_diorite": "拋光切製閃長岩", - "block.create.polished_cut_diorite_slab": "拋光切製閃長岩半磚", - "block.create.polished_cut_diorite_stairs": "拋光切製閃長岩階梯", - "block.create.polished_cut_diorite_wall": "拋光切製閃長岩牆", - "block.create.polished_cut_dripstone": "拋光切製鐘乳石", - "block.create.polished_cut_dripstone_slab": "拋光切製鐘乳石半磚", - "block.create.polished_cut_dripstone_stairs": "拋光切製鐘乳石階梯", - "block.create.polished_cut_dripstone_wall": "拋光切製鐘乳石牆", - "block.create.polished_cut_granite": "拋光切製花崗岩", - "block.create.polished_cut_granite_slab": "拋光切製花崗岩半磚", - "block.create.polished_cut_granite_stairs": "拋光切製花崗岩階梯", - "block.create.polished_cut_granite_wall": "拋光切製花崗岩牆", - "block.create.polished_cut_limestone": "拋光切製石灰岩", - "block.create.polished_cut_limestone_slab": "拋光切製石灰岩半磚", - "block.create.polished_cut_limestone_stairs": "拋光切製石灰岩階梯", - "block.create.polished_cut_limestone_wall": "拋光切製石灰岩牆", - "block.create.polished_cut_ochrum": "拋光切製赭金石", - "block.create.polished_cut_ochrum_slab": "拋光切製赭金石半磚", - "block.create.polished_cut_ochrum_stairs": "拋光切製赭金石階梯", - "block.create.polished_cut_ochrum_wall": "拋光切製赭金石牆", - "block.create.polished_cut_scorchia": "拋光切製焦熔渣", - "block.create.polished_cut_scorchia_slab": "拋光切製焦熔渣半磚", - "block.create.polished_cut_scorchia_stairs": "拋光切製焦熔渣階梯", - "block.create.polished_cut_scorchia_wall": "拋光切製焦熔渣牆", - "block.create.polished_cut_scoria": "拋光切製熔渣", - "block.create.polished_cut_scoria_slab": "拋光切製熔渣半磚", - "block.create.polished_cut_scoria_stairs": "拋光切製熔渣階梯", - "block.create.polished_cut_scoria_wall": "拋光切製熔渣牆", - "block.create.polished_cut_tuff": "拋光切製凝灰岩", - "block.create.polished_cut_tuff_slab": "拋光切製凝灰岩半磚", - "block.create.polished_cut_tuff_stairs": "拋光切製凝灰岩階梯", - "block.create.polished_cut_tuff_wall": "拋光切製凝灰岩牆", - "block.create.polished_cut_veridium": "拋光切製輝綠岩", - "block.create.polished_cut_veridium_slab": "拋光切製輝綠岩半磚", - "block.create.polished_cut_veridium_stairs": "拋光切製輝綠岩階梯", - "block.create.polished_cut_veridium_wall": "拋光切製輝綠岩牆", - "block.create.portable_fluid_interface": "移動式流體口", - "block.create.portable_storage_interface": "移動式物品口", - "block.create.powered_latch": "閂鎖器", - "block.create.powered_shaft": "動力傳動軸", - "block.create.powered_toggle_latch": "T型正反器", - "block.create.pulley_magnet": "滑輪磁鐵", - "block.create.pulse_extender": "脈衝延長器", - "block.create.pulse_repeater": "脈衝中繼器", - "block.create.purple_nixie_tube": "紫色真空管", - "block.create.purple_sail": "紫色風帆", - "block.create.purple_seat": "紫色坐墊", - "block.create.purple_toolbox": "紫色工具箱", - "block.create.purple_valve_handle": "紫色閥門開關", - "block.create.radial_chassis": "旋轉底盤", - "block.create.railway_casing": "火車機殼", - "block.create.raw_zinc_block": "鋅原礦方塊", - "block.create.red_nixie_tube": "紅色真空管", - "block.create.red_sail": "紅色風帆", - "block.create.red_seat": "紅色坐墊", - "block.create.red_toolbox": "紅色工具箱", - "block.create.red_valve_handle": "紅色閥門開關", - "block.create.redstone_contact": "接觸式偵測器", - "block.create.redstone_link": "無線紅石鏈路", - "block.create.refined_radiance_casing": "光輝機殼", - "block.create.rope": "繩索", - "block.create.rope_pulley": "滑輪繩索", - "block.create.rose_quartz_block": "玫瑰石英方塊", - "block.create.rose_quartz_lamp": "玫瑰石英燈", - "block.create.rose_quartz_tiles": "玫瑰石英磚瓦", - "block.create.rotation_speed_controller": "轉速控制器", - "block.create.sail_frame": "風帆框架", - "block.create.schematic_table": "藍圖桌", - "block.create.schematicannon": "藍圖加農炮", - "block.create.scorchia": "焦熔渣", - "block.create.scorchia_pillar": "焦熔渣柱", - "block.create.scoria": "熔渣", - "block.create.scoria_pillar": "熔渣柱", - "block.create.secondary_linear_chassis": "機殼底盤二號", - "block.create.sequenced_gearshift": "可程式化齒輪箱", - "block.create.shadow_steel_casing": "暗影機殼", - "block.create.shaft": "傳動軸", - "block.create.small_andesite_brick_slab": "小安山岩磚半磚", - "block.create.small_andesite_brick_stairs": "小安山岩磚階梯", - "block.create.small_andesite_brick_wall": "小安山岩磚牆", - "block.create.small_andesite_bricks": "小安山岩磚", - "block.create.small_asurine_brick_slab": "小皓藍石磚半磚", - "block.create.small_asurine_brick_stairs": "小皓藍石磚階梯", - "block.create.small_asurine_brick_wall": "小皓藍石磚牆", - "block.create.small_asurine_bricks": "小皓藍石磚", - "block.create.small_bogey": "小轉向架", - "block.create.small_calcite_brick_slab": "小方解石磚半磚", - "block.create.small_calcite_brick_stairs": "小方解石磚階梯", - "block.create.small_calcite_brick_wall": "小方解石磚牆", - "block.create.small_calcite_bricks": "小方解石磚", - "block.create.small_crimsite_brick_slab": "小緋紅岩磚半磚", - "block.create.small_crimsite_brick_stairs": "小緋紅岩磚階梯", - "block.create.small_crimsite_brick_wall": "小緋紅岩磚牆", - "block.create.small_crimsite_bricks": "小緋紅岩磚", - "block.create.small_deepslate_brick_slab": "小深板岩磚半磚", - "block.create.small_deepslate_brick_stairs": "小深板岩磚階梯", - "block.create.small_deepslate_brick_wall": "小深板岩磚牆", - "block.create.small_deepslate_bricks": "小深板岩磚", - "block.create.small_diorite_brick_slab": "小閃長岩磚半磚", - "block.create.small_diorite_brick_stairs": "小閃長岩磚階梯", - "block.create.small_diorite_brick_wall": "小閃長岩磚牆", - "block.create.small_diorite_bricks": "小閃長岩磚", - "block.create.small_dripstone_brick_slab": "小鐘乳石磚半磚", - "block.create.small_dripstone_brick_stairs": "小鐘乳石磚階梯", - "block.create.small_dripstone_brick_wall": "小鐘乳石磚牆", - "block.create.small_dripstone_bricks": "小鐘乳石磚", - "block.create.small_granite_brick_slab": "小花崗岩磚半磚", - "block.create.small_granite_brick_stairs": "小花崗岩磚階梯", - "block.create.small_granite_brick_wall": "小花崗岩磚牆", - "block.create.small_granite_bricks": "小花崗岩磚", - "block.create.small_limestone_brick_slab": "小石灰岩磚半磚", - "block.create.small_limestone_brick_stairs": "小石灰岩磚階梯", - "block.create.small_limestone_brick_wall": "小石灰岩磚牆", - "block.create.small_limestone_bricks": "小石灰岩磚", - "block.create.small_ochrum_brick_slab": "小赭金石磚半磚", - "block.create.small_ochrum_brick_stairs": "小赭金石磚階梯", - "block.create.small_ochrum_brick_wall": "小赭金石磚牆", - "block.create.small_ochrum_bricks": "小赭金石磚", - "block.create.small_rose_quartz_tiles": "小玫瑰石英磚瓦", - "block.create.small_scorchia_brick_slab": "小焦熔渣磚半磚", - "block.create.small_scorchia_brick_stairs": "小焦熔渣磚階梯", - "block.create.small_scorchia_brick_wall": "小焦熔渣磚牆", - "block.create.small_scorchia_bricks": "小焦熔渣磚", - "block.create.small_scoria_brick_slab": "小熔渣磚半磚", - "block.create.small_scoria_brick_stairs": "小熔渣磚階梯", - "block.create.small_scoria_brick_wall": "小熔渣磚牆", - "block.create.small_scoria_bricks": "小熔渣磚", - "block.create.small_tuff_brick_slab": "小凝灰岩磚半磚", - "block.create.small_tuff_brick_stairs": "小凝灰岩磚階梯", - "block.create.small_tuff_brick_wall": "小凝灰岩磚牆", - "block.create.small_tuff_bricks": "小凝灰岩磚", - "block.create.small_veridium_brick_slab": "小輝綠岩磚半磚", - "block.create.small_veridium_brick_stairs": "小輝綠岩磚階梯", - "block.create.small_veridium_brick_wall": "小輝綠岩磚牆", - "block.create.small_veridium_bricks": "小輝綠岩磚", - "block.create.smart_chute": "智慧滑槽", - "block.create.smart_fluid_pipe": "智慧流體管道", - "block.create.speedometer": "轉速計", - "block.create.spout": "流體灌注器", - "block.create.spruce_window": "雲杉木窗戶", - "block.create.spruce_window_pane": "雲杉木窗戶片", - "block.create.steam_engine": "蒸汽機", - "block.create.steam_whistle": "汽笛", - "block.create.steam_whistle_extension": "汽笛管", - "block.create.sticker": "方塊黏著器", - "block.create.sticky_mechanical_piston": "黏性機械活塞", - "block.create.stockpile_switch": "存量偵測器", - "block.create.stressometer": "動力計", - "block.create.tiled_glass": "十字玻璃窗", - "block.create.tiled_glass_pane": "十字玻璃窗戶片", - "block.create.track": "火車軌道", - "block.create.track_observer": "火車感測器", - "block.create.track_signal": "火車訊號機", - "block.create.track_station": "火車站點", - "block.create.train_door": "火車車門", - "block.create.train_trapdoor": "火車地板門", - "block.create.tuff_pillar": "凝灰岩柱", - "block.create.turntable": "轉盤", - "block.create.veridium": "輝綠岩", - "block.create.veridium_pillar": "輝綠岩柱", - "block.create.vertical_framed_glass": "豎直邊框玻璃", - "block.create.vertical_framed_glass_pane": "豎直邊框玻璃片", - "block.create.warped_window": "扭曲蕈木窗戶", - "block.create.warped_window_pane": "扭曲蕈木窗戶片", - "block.create.water_wheel": "水車", - "block.create.waxed_copper_shingle_slab": "上蠟的銅屋瓦半磚", - "block.create.waxed_copper_shingle_stairs": "上蠟的銅屋瓦階梯", - "block.create.waxed_copper_shingles": "上蠟的銅屋瓦", - "block.create.waxed_copper_tile_slab": "上蠟的銅磚瓦半磚", - "block.create.waxed_copper_tile_stairs": "上蠟的銅磚瓦階梯", - "block.create.waxed_copper_tiles": "上蠟的銅磚瓦", - "block.create.waxed_exposed_copper_shingle_slab": "上蠟的斑駁銅屋瓦半磚", - "block.create.waxed_exposed_copper_shingle_stairs": "上蠟的斑駁銅屋瓦階梯", - "block.create.waxed_exposed_copper_shingles": "上蠟的斑駁銅屋瓦", - "block.create.waxed_exposed_copper_tile_slab": "上蠟的斑駁銅磚瓦半磚", - "block.create.waxed_exposed_copper_tile_stairs": "上蠟的斑駁銅磚瓦階梯", - "block.create.waxed_exposed_copper_tiles": "上蠟的斑駁銅磚瓦", - "block.create.waxed_oxidized_copper_shingle_slab": "上蠟的氧化銅屋瓦半磚", - "block.create.waxed_oxidized_copper_shingle_stairs": "上蠟的氧化銅屋瓦階梯", - "block.create.waxed_oxidized_copper_shingles": "上蠟的氧化銅屋瓦", - "block.create.waxed_oxidized_copper_tile_slab": "上蠟的氧化銅磚瓦半磚", - "block.create.waxed_oxidized_copper_tile_stairs": "上蠟的氧化銅磚瓦階梯", - "block.create.waxed_oxidized_copper_tiles": "上蠟的氧化銅磚瓦", - "block.create.waxed_weathered_copper_shingle_slab": "上蠟的風化銅屋瓦半磚", - "block.create.waxed_weathered_copper_shingle_stairs": "上蠟的風化銅屋瓦階梯", - "block.create.waxed_weathered_copper_shingles": "上蠟的風化銅屋瓦", - "block.create.waxed_weathered_copper_tile_slab": "上蠟的風化銅磚瓦半磚", - "block.create.waxed_weathered_copper_tile_stairs": "上蠟的風化銅磚瓦階梯", - "block.create.waxed_weathered_copper_tiles": "上蠟的風化銅磚瓦", - "block.create.weathered_copper_shingle_slab": "風化的銅屋瓦半磚", - "block.create.weathered_copper_shingle_stairs": "風化的銅屋瓦階梯", - "block.create.weathered_copper_shingles": "風化的銅屋瓦", - "block.create.weathered_copper_tile_slab": "風化的銅磚瓦半磚", - "block.create.weathered_copper_tile_stairs": "風化的銅磚瓦階梯", - "block.create.weathered_copper_tiles": "風化的銅磚瓦", - "block.create.weighted_ejector": "彈射置物台", - "block.create.white_nixie_tube": "白色真空管", - "block.create.white_sail": "白色風帆", - "block.create.white_seat": "白色坐墊", - "block.create.white_toolbox": "白色工具箱", - "block.create.white_valve_handle": "白色閥門開關", - "block.create.windmill_bearing": "風車軸承", - "block.create.wooden_bracket": "木製支架", - "block.create.yellow_nixie_tube": "黃色真空管", - "block.create.yellow_sail": "黃色風帆", - "block.create.yellow_seat": "黃色坐墊", - "block.create.yellow_toolbox": "黃色工具箱", - "block.create.yellow_valve_handle": "黃色閥門開關", - "block.create.zinc_block": "鋅方塊", - "block.create.zinc_ore": "鋅礦石", - - "enchantment.create.capacity": "容量", - "enchantment.create.potato_recovery": "回收馬鈴薯", - - "entity.create.carriage_contraption": "運輸結構", - "entity.create.contraption": "結構", - "entity.create.crafting_blueprint": "合成藍圖", - "entity.create.gantry_contraption": "橋式結構", - "entity.create.potato_projectile": "馬鈴薯彈藥", - "entity.create.seat": "坐墊", - "entity.create.stationary_contraption": "固定結構", - "entity.create.super_glue": "強力膠", - - "fluid.create.potion": "藥水", - "fluid.create.tea": "茶", - - "item.create.andesite_alloy": "安山合金", - "item.create.attribute_filter": "屬性過濾器", - "item.create.bar_of_chocolate": "巧克力棒", - "item.create.belt_connector": "輸送帶", - "item.create.blaze_cake": "熔岩蛋糕", - "item.create.blaze_cake_base": "熔岩蛋糕胚", - "item.create.brass_hand": "黃銅手部零件", - "item.create.brass_ingot": "黃銅錠", - "item.create.brass_nugget": "黃銅粒", - "item.create.brass_sheet": "黃銅板", - "item.create.builders_tea": "建築工的茶", - "item.create.chest_minecart_contraption": "裝修過的機械礦車", - "item.create.chocolate_bucket": "巧克力桶", - "item.create.chocolate_glazed_berries": "巧克力甜莓", - "item.create.chromatic_compound": "異彩化合物", - "item.create.cinder_flour": "地獄麵粉", - "item.create.copper_backtank": "銅製後背包", - "item.create.copper_backtank_placeable": "可放置的銅製後背包", - "item.create.copper_nugget": "銅粒", - "item.create.copper_sheet": "銅板", - "item.create.crafter_slot_cover": "合成器蓋板", - "item.create.crafting_blueprint": "合成藍圖", - "item.create.creative_blaze_cake": "創造熔岩蛋糕", - "item.create.crushed_aluminum_ore": "碎狀鋁礦石", - "item.create.crushed_copper_ore": "碎狀銅礦石", - "item.create.crushed_gold_ore": "碎狀金礦石", - "item.create.crushed_iron_ore": "碎狀鐵礦石", - "item.create.crushed_lead_ore": "碎狀鉛礦石", - "item.create.crushed_nickel_ore": "碎狀鎳礦石", - "item.create.crushed_osmium_ore": "碎狀鋨礦石", - "item.create.crushed_platinum_ore": "碎狀白金礦石", - "item.create.crushed_quicksilver_ore": "碎狀水銀礦石", - "item.create.crushed_silver_ore": "碎狀銀礦石", - "item.create.crushed_tin_ore": "碎狀錫礦石", - "item.create.crushed_uranium_ore": "碎狀鈾礦石", - "item.create.crushed_zinc_ore": "碎狀鋅礦石", - "item.create.diving_boots": "潛水鞋", - "item.create.diving_helmet": "潛水頭盔", - "item.create.dough": "麵團", - "item.create.electron_tube": "真空管", - "item.create.empty_blaze_burner": "空的烈焰使者動力爐", - "item.create.empty_schematic": "空白藍圖", - "item.create.experience_nugget": "經驗金塊", - "item.create.extendo_grip": "伸縮機械手", - "item.create.filter": "過濾器", - "item.create.furnace_minecart_contraption": "裝配過的機械礦車", - "item.create.goggles": "工程師護目鏡", - "item.create.golden_sheet": "金板", - "item.create.handheld_worldshaper": "地形雕塑器", - "item.create.honey_bucket": "蜂蜜桶", - "item.create.honeyed_apple": "蜂蜜蘋果", - "item.create.incomplete_precision_mechanism": "未完成的精密機構", - "item.create.incomplete_track": "未完成的軌道", - "item.create.iron_sheet": "鐵板", - "item.create.linked_controller": "遙控器", - "item.create.minecart_contraption": "裝修過的礦車", - "item.create.minecart_coupling": "礦車連結器", - "item.create.polished_rose_quartz": "拋光玫瑰石英", - "item.create.potato_cannon": "馬鈴薯大砲", - "item.create.powdered_obsidian": "黑曜石粉末", - "item.create.precision_mechanism": "精密機構", - "item.create.propeller": "扇葉", - "item.create.raw_zinc": "鋅原礦", - "item.create.red_sand_paper": "紅砂紙", - "item.create.refined_radiance": "光輝石", - "item.create.rose_quartz": "玫瑰石英", - "item.create.sand_paper": "砂紙", - "item.create.schedule": "火車時刻表", - "item.create.schematic": "藍圖", - "item.create.schematic_and_quill": "藍圖與筆", - "item.create.shadow_steel": "暗影鋼", - "item.create.sturdy_sheet": "高強度板", - "item.create.super_glue": "強力膠", - "item.create.sweet_roll": "蛋糕捲", - "item.create.tree_fertilizer": "樹木肥料", - "item.create.unprocessed_obsidian_sheet": "未加工的黑曜石板", - "item.create.vertical_gearbox": "豎直齒輪箱", - "item.create.wand_of_symmetry": "對稱杖", - "item.create.wheat_flour": "小麥粉", - "item.create.whisk": "攪拌器", - "item.create.wrench": "扳手", - "item.create.zinc_ingot": "鋅錠", - "item.create.zinc_nugget": "鋅粒", - - - "_": "->------------------------] Advancements [------------------------<-", - - "advancement.create.root": "歡迎來到機械動力的世界", - "advancement.create.root.desc": "是製造機械的時候了", - "advancement.create.andesite_alloy": "更堅硬的岩石", - "advancement.create.andesite_alloy.desc": "獲得安山合金,機械動力最重要的資源", - "advancement.create.andesite_casing": "安山時代", - "advancement.create.andesite_casing.desc": "結合安山合金和木頭,製作機械的基本外殼", - "advancement.create.mechanical_press": "Bonk", - "advancement.create.mechanical_press.desc": "以機械鍛壓機鍛造板金", - "advancement.create.encased_fan": "吹風機", - "advancement.create.encased_fan.desc": "啟動鼓風機", - "advancement.create.fan_processing": "粒子技術", - "advancement.create.fan_processing.desc": "以鼓風機進行材料加工", - "advancement.create.saw_processing": "作坊中最深的恐懼", - "advancement.create.saw_processing.desc": "以面向上的機械圓鋸機進行材料加工", - "advancement.create.compacting": "緊緻的", - "advancement.create.compacting.desc": "以機械鍛壓機與作業盆將多個物品壓縮在一塊", - "advancement.create.belt": "流水線作業", - "advancement.create.belt.desc": "將輸送帶連接兩個傳動軸", - "advancement.create.funnel": "航站美學", - "advancement.create.funnel.desc": "透過漏斗,自容器中輸入或輸出物品", - "advancement.create.chute": "垂直物流", - "advancement.create.chute.desc": "透過滑槽運輸物品", - "advancement.create.mechanical_mixer": "混和攪拌", - "advancement.create.mechanical_mixer.desc": "以機械攪拌器混和材料", - "advancement.create.burner": "活生生的壁爐", - "advancement.create.burner.desc": "獲得烈焰使者動力爐", - "advancement.create.water_wheel": "水力學", - "advancement.create.water_wheel.desc": "放置水車並讓它開始旋轉", - "advancement.create.windmill": "微風拂過", - "advancement.create.windmill.desc": "組裝風車以產生扭矩", - "advancement.create.shifting_gears": "換檔", - "advancement.create.shifting_gears.desc": "將大齒輪連接到小齒輪上,改變轉軸的速度", - "advancement.create.millstone": "石磨轉起", - "advancement.create.millstone.desc": "使用石磨研磨材料", - "advancement.create.super_glue": "將空間黏合", - "advancement.create.super_glue.desc": "用強力膠將多個方塊黏成一團", - "advancement.create.contraption_actors": "奉命出行", - "advancement.create.contraption_actors.desc": "製造帶有機械鑽頭、機械圓鋸機或機械收割機的移動裝置", - "advancement.create.portable_storage_interface": "得來速", - "advancement.create.portable_storage_interface.desc": "透過移動式物品口,自移動裝置中輸入或輸出物品", - "advancement.create.wrench_goggles": "裝備齊全", - "advancement.create.wrench_goggles.desc": "同時裝備工程師護目鏡及扳手", - "advancement.create.stressometer": "精密的動能控制", - "advancement.create.stressometer.desc": "透過工程師護目鏡和動力計讀取精確數值", - "advancement.create.cuckoo_clock": "到時間了嗎?", - "advancement.create.cuckoo_clock.desc": "目睹布穀鳥鐘提醒你睡覺", - "advancement.create.windmill_maxed": "強烈風暴", - "advancement.create.windmill_maxed.desc": "組裝出最高強度的風車", - "advancement.create.ejector_maxed": "跳板冠軍", - "advancement.create.ejector_maxed.desc": "被彈射置物台扔到 30 格以外", - "advancement.create.pulley_maxed": "深入虛空", - "advancement.create.pulley_maxed.desc": "用滑輪繩索延伸超過 200 格", - "advancement.create.cart_pickup": "壯碩的胳膊", - "advancement.create.cart_pickup.desc": "撿起至少含有 200 個方塊的礦車結構", - "advancement.create.anvil_plough": "鍛工的重砲", - "advancement.create.anvil_plough.desc": "用機械犁發射鐵砧", - "advancement.create.lava_wheel_00000": "風火輪", - "advancement.create.lava_wheel_00000.desc": "這不該奏效§7\n(隱藏成就)", - "advancement.create.hand_crank_000": "健身課程", - "advancement.create.hand_crank_000.desc": "轉動手搖把手直到挨餓§7\n(隱藏成就)", - "advancement.create.belt_funnel_kiss": "比翼雙飛", - "advancement.create.belt_funnel_kiss.desc": "使安裝在輸送帶上的兩個漏斗相吻§7\n(隱藏成就)", - "advancement.create.stressometer_maxed": "完美的負荷", - "advancement.create.stressometer_maxed.desc": "在動力計目睹負荷滿載§7\n(隱藏成就)", - "advancement.create.copper": "更加堅硬的岩石", - "advancement.create.copper.desc": "為開發流體控制技術積攢一些銅", - "advancement.create.copper_casing": "銅時代", - "advancement.create.copper_casing.desc": "結合銅錠與木頭,為您的機械打造防水外殼", - "advancement.create.spout": "水花四濺", - "advancement.create.spout.desc": "看著流體灌注器注滿容器", - "advancement.create.drain": "細水慢流", - "advancement.create.drain.desc": "看著容器被分液池排空", - "advancement.create.steam_engine": "發電站", - "advancement.create.steam_engine.desc": "以蒸汽機產生動力", - "advancement.create.steam_whistle": "天籟之音", - "advancement.create.steam_whistle.desc": "鳴笛", - "advancement.create.backtank": "蓄勢待發", - "advancement.create.backtank.desc": "製造銅製後背包並加壓", - "advancement.create.diving_suit": "深潛準備", - "advancement.create.diving_suit.desc": "裝備潛水頭盔和銅製後背包,跳入水中", - "advancement.create.mechanical_pump_0": "施壓", - "advancement.create.mechanical_pump_0.desc": "驅動機械幫浦", - "advancement.create.glass_pipe": "窺視波流", - "advancement.create.glass_pipe.desc": "在液體流過的管道上使用扳手", - "advancement.create.water_supply": "取自水窪", - "advancement.create.water_supply.desc": "使用機械幫浦或軟管滑輪抽水", - "advancement.create.hose_pulley": "工業排放", - "advancement.create.hose_pulley.desc": "放下軟管滑輪,觀察它排出或抽取流體", - "advancement.create.chocolate_bucket": "幻想世界", - "advancement.create.chocolate_bucket.desc": "獲得一桶融化的巧克力", - "advancement.create.honey_drain": "自動養蜂場", - "advancement.create.honey_drain.desc": "使用流體管道從蜂巢或蜂屋中抽取蜂蜜", - "advancement.create.hose_pulley_lava": "迫近地函", - "advancement.create.hose_pulley_lava.desc": "從可被認定為無限容量的熔岩體抽出岩漿", - "advancement.create.steam_engine_maxed": "蒸氣充沛", - "advancement.create.steam_engine_maxed.desc": "以最大功率運行鍋爐", - "advancement.create.foods": "均衡飲食", - "advancement.create.foods.desc": "自同一個流體灌注器生產巧克力甜莓、蜂蜜蘋果和蛋糕捲", - "advancement.create.diving_suit_lava": "與熾足獸游泳", - "advancement.create.diving_suit_lava.desc": "嘗試使用您的銅製潛水裝備在熔岩中潛水§7\n(隱藏成就)", - "advancement.create.chained_drain": "走運了", - "advancement.create.chained_drain.desc": "看著物品滾過一整排分液池§7\n(隱藏成就)", - "advancement.create.cross_streams": "別混流", - "advancement.create.cross_streams.desc": "目睹兩種液體在管道中相遇§7\n(隱藏成就)", - "advancement.create.pipe_organ": "管風琴", - "advancement.create.pipe_organ.desc": "在一個流體儲存罐上裝設 12 個不同音高的汽笛§7\n(隱藏成就)", - "advancement.create.brass": "真正的合金", - "advancement.create.brass.desc": "以烈焰使者動力爐加熱機械攪拌器,加入銅錠和鋅錠以製作黃銅", - "advancement.create.brass_casing": "黃銅時代", - "advancement.create.brass_casing.desc": "結合黃銅錠與木頭,為更複雜的機器製造外殼", - "advancement.create.rose_quartz": "粉色鑽石", - "advancement.create.rose_quartz.desc": "將玫瑰石英拋光", - "advancement.create.deployer": "人工智慧", - "advancement.create.deployer.desc": "放置並且啟動一個機械手。這可是你右手的完美複製品", - "advancement.create.precision_mechanism": "關鍵工藝", - "advancement.create.precision_mechanism.desc": "組裝一個精密機構", - "advancement.create.speed_controller": "工程師的惡夢", - "advancement.create.speed_controller.desc": "放置一個轉速控制器,這是換檔的終極裝置", - "advancement.create.mechanical_arm": "忙碌的雙手", - "advancement.create.mechanical_arm.desc": "看著機械臂完成你所交代的任務", - "advancement.create.mechanical_crafter": "自動化產線", - "advancement.create.mechanical_crafter.desc": "為機械合成器提供動力", - "advancement.create.crushing_wheel": "一對巨匠", - "advancement.create.crushing_wheel.desc": "為一對粉碎輪提供動力", - "advancement.create.haunted_bell": "鬼影幢幢", - "advancement.create.haunted_bell.desc": "敲響靈魂鐘", - "advancement.create.clockwork_bearing": "時差", - "advancement.create.clockwork_bearing.desc": "組裝安裝在發條軸承上的結構", - "advancement.create.display_link": "大數據", - "advancement.create.display_link.desc": "使用顯示鏈路可視化訊息", - "advancement.create.potato_cannon": "噗~碰", - "advancement.create.potato_cannon.desc": "用馬鈴薯大砲擊殺一隻怪物", - "advancement.create.extendo_grip": "彈性極佳", - "advancement.create.extendo_grip.desc": "拿到一個伸縮機械手", - "advancement.create.linked_controller": "遠端遙控", - "advancement.create.linked_controller.desc": "以遙控器開啟無線紅石鏈路", - "advancement.create.arm_blaze_burner": "補給燃料", - "advancement.create.arm_blaze_burner.desc": "吩咐機械臂餵食你的烈焰使者", - "advancement.create.crusher_maxed_0000": "粉碎一切", - "advancement.create.crusher_maxed_0000.desc": "讓一對粉碎輪以極速運作", - "advancement.create.arm_many_targets": "手忙手亂", - "advancement.create.arm_many_targets.desc": "讓機械臂擁有十個或更多的輸出位置", - "advancement.create.potato_cannon_collide": "蔬果花火", - "advancement.create.potato_cannon_collide.desc": "使兩座馬鈴薯大砲的砲彈相互碰撞", - "advancement.create.self_deploying": "自動駕駛", - "advancement.create.self_deploying.desc": "讓一個礦車結構為自己鋪設鐵軌", - "advancement.create.fist_bump": "朋友,擊拳吧", - "advancement.create.fist_bump.desc": "使兩個機械手互相碰拳§7\n(隱藏成就)", - "advancement.create.crafter_lazy_000": "鋌而走險", - "advancement.create.crafter_lazy_000.desc": "使機械合成器大幅減速,適當的延遲基礎建設§7\n(隱藏成就)", - "advancement.create.extendo_grip_dual": "面面俱到", - "advancement.create.extendo_grip_dual.desc": "使用兩支伸縮機械手,以達到超人般的接觸距離§7\n(隱藏成就)", - "advancement.create.musical_arm": "DJ:機械師", - "advancement.create.musical_arm.desc": "目睹機械臂跳舞§7\n(隱藏成就)", - "advancement.create.sturdy_sheet": "堅不可摧", - "advancement.create.sturdy_sheet.desc": "以黑曜石粉末打造高強度板", - "advancement.create.train_casing_00": "物流時代", - "advancement.create.train_casing_00.desc": "以高強度板製作火車部件的機殼", - "advancement.create.train": "盡速上車", - "advancement.create.train.desc": "組裝你的第一列火車", - "advancement.create.conductor": "命令司機員", - "advancement.create.conductor.desc": "透過火車時刻表給予司機員指示", - "advancement.create.track_signal": "交通管制", - "advancement.create.track_signal.desc": "設置火車訊號機", - "advancement.create.display_board_0": "動態時刻表", - "advancement.create.display_board_0.desc": "在顯示鏈路的幫助下,透過顯示板預測火車的抵達時間", - "advancement.create.track_0": "新軌距", - "advancement.create.track_0.desc": "獲得一些火車軌道", - "advancement.create.train_whistle": "Choo Choo", - "advancement.create.train_whistle.desc": "將汽笛裝到火車上並在行駛時觸發", - "advancement.create.train_portal": "次元旅行者", - "advancement.create.train_portal.desc": "駕駛火車通過地獄門", - "advancement.create.track_crafting_factory": "軌道工廠", - "advancement.create.track_crafting_factory.desc": "在一台機械鍛壓機中製造超過 1000 條軌道", - "advancement.create.long_bend": "無際彎道", - "advancement.create.long_bend.desc": "鋪設長度超過 30 格的曲線軌道", - "advancement.create.long_train": "雄心勃勃", - "advancement.create.long_train.desc": "建造一列至少有六節車廂的火車", - "advancement.create.long_travel": "遠足", - "advancement.create.long_travel.desc": "從距離旅行起始點超過 5000 格的火車座位起身", - "advancement.create.train_roadkill": "路殺", - "advancement.create.train_roadkill.desc": "用火車輾死敵人§7\n(隱藏成就)", - "advancement.create.red_signal": "合格司機員", - "advancement.create.red_signal.desc": "駛過紅色訊號§7\n(隱藏成就)", - "advancement.create.train_crash": "服務爛透了", - "advancement.create.train_crash.desc": "乘車時目睹火車事故§7\n(隱藏成就)", - "advancement.create.train_crash_backwards": "盲點", - "advancement.create.train_crash_backwards.desc": "倒車時撞上另一列火車§7\n(隱藏成就)", - - - "_": "->------------------------] UI & Messages [------------------------<-", - - "itemGroup.create.base": "動力機械", - "itemGroup.create.palettes": "動力機械建築與裝飾方塊", - - "death.attack.create.crush": "%1$s 被壓扁了", - "death.attack.create.crush.player": "%1$s 被 %2$s 打包丟進粉碎輪", - "death.attack.create.fan_fire": "%1$s 想接受熱風的洗禮", - "death.attack.create.fan_fire.player": "%1$s 被 %2$s 推入火坑", - "death.attack.create.fan_lava": "%1$s 想接受熱風的洗禮但走火入魔", - "death.attack.create.fan_lava.player": "%1$s 被 %2$s 推進岩漿", - "death.attack.create.mechanical_drill": "%1$s 被鑽頭鑽爆腦袋", - "death.attack.create.mechanical_drill.player": "%1$s 被 %2$s 當成礦物放在鑽頭前面而死", - "death.attack.create.mechanical_saw": "%1$s 被鋸切成了兩半", - "death.attack.create.mechanical_saw.player": "%1$s 被 %2$s 鋸掉了", - "death.attack.create.potato_cannon": "%1$s 被 %2$s 的馬鈴薯大砲餵飽了", - "death.attack.create.potato_cannon.item": "%1$s 被 %2$s 用馬鈴薯大砲塞了滿肚子 %3$s", - "death.attack.create.cuckoo_clock_explosion": "%1$s 被布穀鳥鐘炸得粉身碎骨", - "death.attack.create.cuckoo_clock_explosion.player": "%1$s 被布穀鳥鐘炸得粉身碎骨", - "death.attack.create.run_over": "%1$s 被 %2$s 輾過", - - "create.block.deployer.damage_source_name": "機械手", - "create.block.cart_assembler.invalid": "將你的礦車裝修站放在鐵軌上", - - "create.menu.return": "回到選單", - "create.menu.configure": "設定", - "create.menu.ponder_index": "示範目錄", - "create.menu.only_ingame": "僅適用於暫停選單", - "create.menu.report_bugs": "回報問題", - "create.menu.support": "支持我們", - - "create.ponder.mod_name": "UNLOCALIZED: Create", - - "create.recipe.crushing": "粉碎", - "create.recipe.milling": "研磨", - "create.recipe.fan_washing": "批次洗滌", - "create.recipe.fan_washing.fan": "在水後放置鼓風機", - "create.recipe.fan_smoking": "批次煙燻", - "create.recipe.fan_smoking.fan": "在火焰後放置鼓風機", - "create.recipe.fan_haunting": "批次喚魂", - "create.recipe.fan_haunting.fan": "在靈魂火後放置鼓風機", - "create.recipe.fan_blasting": "批次融煉", - "create.recipe.fan_blasting.fan": "在熔岩後放置鼓風機", - "create.recipe.pressing": "金屬鍛造", - "create.recipe.mixing": "混合攪拌", - "create.recipe.deploying": "使用", - "create.recipe.automatic_shapeless": "自動攪拌", - "create.recipe.automatic_brewing": "自動釀造", - "create.recipe.packing": "壓塑", - "create.recipe.automatic_packing": "自動壓塑", - "create.recipe.sawing": "切割", - "create.recipe.mechanical_crafting": "機械製造", - "create.recipe.automatic_shaped": "自動成型", - "create.recipe.block_cutting": "切割方塊", - "create.recipe.wood_cutting": "切割木材", - "create.recipe.sandpaper_polishing": "砂紙打磨", - "create.recipe.mystery_conversion": "奧秘", - "create.recipe.spout_filling": "灌注", - "create.recipe.draining": "分液", - "create.recipe.item_application": "手動使用物品", - "create.recipe.item_application.any_axe": "任意的斧", - "create.recipe.sequenced_assembly": "步驟", - "create.recipe.assembly.next": "下一步:%1$s", - "create.recipe.assembly.step": "步驟 %1$s", - "create.recipe.assembly.progress": "進度:%1$s/%2$s", - "create.recipe.assembly.pressing": "鍛造過程", - "create.recipe.assembly.spout_filling_fluid": "注入 %1$s", - "create.recipe.assembly.deploying_item": "使用 %1$s", - "create.recipe.assembly.cutting": "用鋸子切", - "create.recipe.assembly.repeat": "重複 %1$s 次", - "create.recipe.assembly.junk": "有機率得到垃圾", - "create.recipe.processing.chance": "%1$s%% 概率", - "create.recipe.deploying.not_consumed": "不消耗", - "create.recipe.heat_requirement.none": "不需要加熱", - "create.recipe.heat_requirement.heated": "一般加熱", - "create.recipe.heat_requirement.superheated": "超級加熱", - - "create.generic.range": "範圍", - "create.generic.radius": "半徑", - "create.generic.width": "寬", - "create.generic.height": "高", - "create.generic.length": "長", - "create.generic.speed": "速度", - "create.generic.delay": "延時", - "create.generic.duration": "間隔", - "create.generic.timeUnit": "時間單位", - "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "秒", - "create.generic.unit.minutes": "分", - "create.generic.daytime.hour": "時", - "create.generic.daytime.minute": "分", - "create.generic.daytime.second": "秒", - "create.generic.daytime.pm": "PM", - "create.generic.daytime.am": "AM", - "create.generic.unit.rpm": "RPM", - "create.generic.unit.stress": "su", - "create.generic.unit.degrees": "度", - "create.generic.unit.millibuckets": "mB", - "create.generic.unit.buckets": "B", - "create.generic.clockwise": "順時鐘方向", - "create.generic.counter_clockwise": "逆時鐘方向", - "create.generic.in_quotes": "\"%1$s\"", - "create.generic.pitch": "音高:%1$s", - "create.generic.notes": "F#;F;E;D#;D;C#;C;B;A#;A;G#;G", - - "create.action.scroll": "滾輪", - "create.action.confirm": "確認", - "create.action.abort": "退出", - "create.action.saveToFile": "離開", - "create.action.discard": "放棄", - - "create.keyinfo.toolmenu": "選單", - "create.keyinfo.toolbelt": "使用附近的工具箱", - "create.keyinfo.scrollup": "(遊戲中) 向上滑鼠滾輪", - "create.keyinfo.scrolldown": "(遊戲中) 向下滑鼠滾輪", - - "create.gui.scrollInput.defaultTitle": "選擇一個選項:", - "create.gui.scrollInput.scrollToModify": "滾動修改", - "create.gui.scrollInput.scrollToAdjustAmount": "滾動修改數量", - "create.gui.scrollInput.scrollToSelect": "滾動選擇", - "create.gui.scrollInput.shiftScrollsFaster": "按住 Shift 滾動更快", - "create.gui.toolmenu.focusKey": "按住 [%1$s] 滑鼠滾輪選擇", - "create.gui.toolmenu.cycle": "[SCROLL] 循環", - - "create.toolbox.unequip": "解除: %1$s", - "create.toolbox.outOfRange": "手持的物品不在工具箱的範圍內", - "create.toolbox.detach": "停止追蹤工具箱,並保留物品", - "create.toolbox.depositAll": "歸還物品至附近所有的工具箱", - "create.toolbox.depositBox": "歸還物品至工具箱", - - "create.gui.symmetryWand.mirrorType": "鏡子類型", - "create.gui.symmetryWand.orientation": "方向", - - "create.symmetry.mirror.plane": "鏡像", - "create.symmetry.mirror.doublePlane": "矩形", - "create.symmetry.mirror.triplePlane": "八角", - - "create.orientation.orthogonal": "垂直", - "create.orientation.diagonal": "對角線", - "create.orientation.horizontal": "水平", - "create.orientation.alongZ": "以 z軸 對齊", - "create.orientation.alongX": "以 x軸 對齊", - - "create.gui.terrainzapper.title": "地形雕塑器", - "create.gui.terrainzapper.searchDiagonal": "跟隨對角線", - "create.gui.terrainzapper.searchFuzzy": "忽略材質邊界", - "create.gui.terrainzapper.patternSection": "樣式", - "create.gui.terrainzapper.pattern.solid": "填滿", - "create.gui.terrainzapper.pattern.checkered": "棋盤狀", - "create.gui.terrainzapper.pattern.inversecheckered": "反轉棋盤狀", - "create.gui.terrainzapper.pattern.chance25": "隨機填滿 25% 的面積", - "create.gui.terrainzapper.pattern.chance50": "隨機填滿 50% 的面積", - "create.gui.terrainzapper.pattern.chance75": "隨機填滿 75% 的面積", - "create.gui.terrainzapper.placement": "放置模式", - "create.gui.terrainzapper.placement.merged": "結合", - "create.gui.terrainzapper.placement.attached": "依附", - "create.gui.terrainzapper.placement.inserted": "插入", - "create.gui.terrainzapper.brush": "雕塑類型", - "create.gui.terrainzapper.brush.cuboid": "矩形體", - "create.gui.terrainzapper.brush.sphere": "球體", - "create.gui.terrainzapper.brush.cylinder": "圓柱體", - "create.gui.terrainzapper.brush.surface": "表面", - "create.gui.terrainzapper.brush.cluster": "群組", - "create.gui.terrainzapper.tool": "填充類型", - "create.gui.terrainzapper.tool.fill": "填充", - "create.gui.terrainzapper.tool.place": "覆寫", - "create.gui.terrainzapper.tool.replace": "替換", - "create.gui.terrainzapper.tool.clear": "清除", - "create.gui.terrainzapper.tool.overlay": "覆蓋", - "create.gui.terrainzapper.tool.flatten": "平整", - - "create.terrainzapper.shiftRightClickToSet": "Shift + 滑鼠右鍵 以設定雕塑類型", - "create.terrainzapper.usingBlock": "使用:%1$s", - "create.terrainzapper.leftClickToSet": "左鍵點擊方塊可以設定材質", - - "create.minecart_coupling.two_couplings_max": "礦車無法被連接兩個以上的礦車連結器", - "create.minecart_coupling.unloaded": "有一部份礦車存在於未讀取區塊中", - "create.minecart_coupling.no_loops": "礦車連結器不能連成一個環", - "create.minecart_coupling.removed": "從礦車上移除所有礦車連結器", - "create.minecart_coupling.too_far": "礦車距離你太遠了", - - "create.contraptions.movement_mode": "運動模式", - "create.contraptions.movement_mode.move_place": "停止時實體化方塊", - "create.contraptions.movement_mode.move_place_returned": "只在初始位置實體化方塊", - "create.contraptions.movement_mode.move_never_place": "只有在機械方塊摧毀後才實體化方塊", - "create.contraptions.movement_mode.rotate_place": "停止時實體化方塊", - "create.contraptions.movement_mode.rotate_place_returned": "只在接近初始角度實體化方塊", - "create.contraptions.movement_mode.rotate_never_place": "只有在旋轉軸摧毀後才實體化方塊", - "create.contraptions.cart_movement_mode": "礦車運動模式", - "create.contraptions.cart_movement_mode.rotate": "結構與礦車保持相同方向", - "create.contraptions.cart_movement_mode.rotate_paused": "礦車轉向時機器停止工作", - "create.contraptions.cart_movement_mode.rotation_locked": "結構方向保持不變", - "create.contraptions.windmill.rotation_direction": "旋轉方向", - "create.contraptions.clockwork.clock_hands": "鐘錶指針", - "create.contraptions.clockwork.hour_first": "時針優先", - "create.contraptions.clockwork.minute_first": "分針優先", - "create.contraptions.clockwork.hour_first_24": "24小時制優先", - - "create.logistics.filter": "過濾器", - "create.logistics.recipe_filter": "配方過濾器", - "create.logistics.fluid_filter": "流體過濾器", - "create.logistics.firstFrequency": "頻道. #1", - "create.logistics.secondFrequency": "頻道. #2", - "create.logistics.filter.apply": "將過濾器應用來 %1$s", - "create.logistics.filter.apply_click_again": "將過濾器應用來 %1$s,再次點擊以複製數量", - "create.logistics.filter.apply_count": "使用提取計數過濾", - - "create.gui.goggles.generator_stats": "發動機狀態:", - "create.gui.goggles.kinetic_stats": "動力學狀態:", - "create.gui.goggles.at_current_speed": "目前動能值", - "create.gui.goggles.pole_length": "活塞桿長度:", - "create.gui.goggles.fluid_container": "流體容器資訊:", - "create.gui.goggles.fluid_container.capacity": "容量:", - "create.gui.assembly.exception": "該結構無法組合:", - "create.gui.assembly.exception.unmovableBlock": "無法移動的方塊 (%4$s) 位於 [%1$s,%2$s,%3$s]", - "create.gui.assembly.exception.chunkNotLoaded": "位於 [%1$s,%2$s,%3$s] 方塊屬未載入區塊", - "create.gui.assembly.exception.structureTooLarge": "結構中的方塊數量過多\n可放置的數量最大為:%1$s", - "create.gui.assembly.exception.tooManyPistonPoles": "活塞的活塞桿數量過多\n可放置的數量最大為:%1$s", - "create.gui.assembly.exception.noPistonPoles": "這個活塞遺失了一些活塞桿", - "create.gui.assembly.exception.not_enough_sails": "結構中所需的風帆類方塊數量不足:%1$s\n最少需要的數量為:%2$s", - "create.gui.gauge.info_header": "儀表訊息:", - "create.gui.speedometer.title": "旋轉速度", - "create.gui.stressometer.title": "網路負荷", - "create.gui.stressometer.capacity": "剩餘能量", - "create.gui.stressometer.overstressed": "動能過載", - "create.gui.stressometer.no_rotation": "無旋轉", - "create.gui.contraptions.not_fast_enough": "看起來 %1$s 沒有達到足夠的工作轉速", - "create.gui.contraptions.network_overstressed": "裝置似乎過載,減少高動能消耗的裝置或者增加更多更多動能", - "create.gui.adjustable_crate.title": "板條箱", - "create.gui.adjustable_crate.storageSpace": "儲存空間", - "create.gui.stockpile_switch.title": "儲存開關", - "create.gui.stockpile_switch.invert_signal": "反轉訊號", - "create.gui.stockpile_switch.move_to_lower_at": "移至下限 %1$s%%", - "create.gui.stockpile_switch.move_to_upper_at": "移至上限 %1$s%%", - "create.gui.sequenced_gearshift.title": "可程式化齒輪箱", - "create.gui.sequenced_gearshift.instruction": "指令", - "create.gui.sequenced_gearshift.instruction.turn_angle.descriptive": "以特定角度旋轉", - "create.gui.sequenced_gearshift.instruction.turn_angle": "旋轉", - "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "角度", - "create.gui.sequenced_gearshift.instruction.turn_distance.descriptive": "帶動 活塞/滑輪/橋式起重機", - "create.gui.sequenced_gearshift.instruction.turn_distance": "驅動活塞", - "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "距離", - "create.gui.sequenced_gearshift.instruction.delay.descriptive": "延遲時間", - "create.gui.sequenced_gearshift.instruction.delay": "延遲", - "create.gui.sequenced_gearshift.instruction.delay.duration": "間隔", - "create.gui.sequenced_gearshift.instruction.end.descriptive": "結束", - "create.gui.sequenced_gearshift.instruction.end": "停止", - "create.gui.sequenced_gearshift.instruction.await.descriptive": "等待新的紅石脈衝", - "create.gui.sequenced_gearshift.instruction.await": "等待", - "create.gui.sequenced_gearshift.speed": "速度,速度方向", - "create.gui.sequenced_gearshift.speed.forward": "一倍速,正向", - "create.gui.sequenced_gearshift.speed.forward_fast": "兩倍速,正向", - "create.gui.sequenced_gearshift.speed.back": "一倍速,反向", - "create.gui.sequenced_gearshift.speed.back_fast": "兩倍速,反向", - - "create.schematicAndQuill.dimensions": "藍圖尺寸:%1$sx%2$sx%3$s", - "create.schematicAndQuill.firstPos": "第一個位置", - "create.schematicAndQuill.secondPos": "第二個位置", - "create.schematicAndQuill.noTarget": "按住Ctrl選擇空氣方塊", - "create.schematicAndQuill.abort": "刪除選擇", - "create.schematicAndQuill.title": "藍圖名:", - "create.schematicAndQuill.convert": "立即存檔並發佈", - "create.schematicAndQuill.fallbackName": "我的藍圖", - "create.schematicAndQuill.saved": "另存為 %1$s", - - "create.schematic.invalid": "[!] 無效的項目", - "create.schematic.position": "位置", - "create.schematic.rotation": "旋轉", - "create.schematic.rotation.none": "無", - "create.schematic.rotation.cw90": "順時鐘 90", - "create.schematic.rotation.cw180": "順時鐘 180", - "create.schematic.rotation.cw270": "順時鐘 270", - "create.schematic.mirror": "鏡像", - "create.schematic.mirror.none": "無", - "create.schematic.mirror.frontBack": "前後", - "create.schematic.mirror.leftRight": "左右", - "create.schematic.tool.deploy": "發佈", - "create.schematic.tool.move": "移動 XZ", - "create.schematic.tool.movey": "移動 Y", - "create.schematic.tool.rotate": "旋轉", - "create.schematic.tool.print": "列印", - "create.schematic.tool.flip": "翻轉", - "create.schematic.tool.deploy.description.0": "將結構移到某個位置", - "create.schematic.tool.deploy.description.1": "在地面上點擊滑鼠右鍵以放置", - "create.schematic.tool.deploy.description.2": "按住 Ctrl 以固定距離選擇", - "create.schematic.tool.deploy.description.3": "按住 Ctrl 滑鼠滾動更改距離", - "create.schematic.tool.move.description.0": "水平移動藍圖", - "create.schematic.tool.move.description.1": "選定藍圖,然後按住 Ctrl 滑鼠滾動", - "create.schematic.tool.move.description.2": "", - "create.schematic.tool.move.description.3": "", - "create.schematic.tool.movey.description.0": "垂直移動藍圖", - "create.schematic.tool.movey.description.1": "按住 Ctrl 滑鼠滾動上下移動", - "create.schematic.tool.movey.description.2": "", - "create.schematic.tool.movey.description.3": "", - "create.schematic.tool.rotate.description.0": "圍繞藍圖中心旋轉藍圖", - "create.schematic.tool.rotate.description.1": "按住 Ctrl 滑鼠滾動旋轉 90 度", - "create.schematic.tool.rotate.description.2": "", - "create.schematic.tool.rotate.description.3": "", - "create.schematic.tool.print.description.0": "立即將結構放置在世界上", - "create.schematic.tool.print.description.1": "右鍵點擊確認目前位置", - "create.schematic.tool.print.description.2": "該工具僅能用於創造模式", - "create.schematic.tool.print.description.3": "", - "create.schematic.tool.flip.description.0": "沿你選擇的面翻轉藍圖", - "create.schematic.tool.flip.description.1": "指向藍圖,然後按住 Ctrl 滑鼠滾動將其翻轉", - "create.schematic.tool.flip.description.2": "", - "create.schematic.tool.flip.description.3": "", - - "create.schematics.synchronizing": "正在同步…", - "create.schematics.uploadTooLarge": "你的藍圖太大", - "create.schematics.maxAllowedSize": "允許的最大藍圖文件大小為:", - - "create.gui.schematicTable.refresh": "重新整理文件", - "create.gui.schematicTable.open_folder": "打開資料夾", - "create.gui.schematicTable.title": "藍圖桌", - "create.gui.schematicTable.availableSchematics": "可用藍圖", - "create.gui.schematicTable.noSchematics": "沒有存檔的藍圖", - "create.gui.schematicTable.uploading": "正在上傳…", - "create.gui.schematicTable.finished": "上傳完成!", - "create.gui.schematicannon.title": "藍圖加農炮", - "create.gui.schematicannon.listPrinter": "物品清單列印機", - "create.gui.schematicannon.gunpowderLevel": "火藥 %1$s%%", - "create.gui.schematicannon.shotsRemaining": "發射進度:%1$s", - "create.gui.schematicannon.shotsRemainingWithBackup": "備份:%1$s", - "create.gui.schematicannon.optionEnabled": "目前啟用", - "create.gui.schematicannon.optionDisabled": "目前停用", - "create.gui.schematicannon.showOptions": "顯示藍圖加農炮設定", - "create.gui.schematicannon.option.dontReplaceSolid": "不要替換方塊", - "create.gui.schematicannon.option.replaceWithSolid": "用固體方塊替換工作區域內的方塊", - "create.gui.schematicannon.option.replaceWithAny": "用任何方塊替換工作區域內的方塊", - "create.gui.schematicannon.option.replaceWithEmpty": "用空氣替換工作區域內的方塊", - "create.gui.schematicannon.option.skipMissing": "繞過缺少的方塊", - "create.gui.schematicannon.option.skipTileEntities": "保護儲存方塊", - "create.gui.schematicannon.slot.gunpowder": "向藍圖加農炮添加火藥以提供動能", - "create.gui.schematicannon.slot.listPrinter": "在此處放置書以列印藍圖所需的材料清單", - "create.gui.schematicannon.slot.schematic": "在此處添加你的藍圖,務必確保其已被部放置在特定位置", - "create.gui.schematicannon.option.skipMissing.description": "如果材料不夠,藍圖大炮將忽略目前不夠的材料並且使用其他已有材料繼續工作", - "create.gui.schematicannon.option.skipTileEntities.description": "藍圖將避免更換儲存方塊,如箱子", - "create.gui.schematicannon.option.dontReplaceSolid.description": "藍圖加農炮將不會替換工作範圍內的任何固體方塊", - "create.gui.schematicannon.option.replaceWithSolid.description": "藍圖加農炮會使用所提供的固體方塊來替換工作區域內的其他固體方塊", - "create.gui.schematicannon.option.replaceWithAny.description": "藍圖加農炮會使用任何所提供的方塊來替換工作區域內的固體方塊", - "create.gui.schematicannon.option.replaceWithEmpty.description": "藍圖加農炮將清理和替換工作區域內所有原本的方塊", - - "create.schematicannon.status.idle": "閒置", - "create.schematicannon.status.ready": "準備", - "create.schematicannon.status.running": "啟動", - "create.schematicannon.status.finished": "完成", - "create.schematicannon.status.paused": "已暫停", - "create.schematicannon.status.stopped": "停止", - "create.schematicannon.status.noGunpowder": "火藥消耗完畢", - "create.schematicannon.status.targetNotLoaded": "方塊未讀取", - "create.schematicannon.status.targetOutsideRange": "定位目標太遠", - "create.schematicannon.status.searching": "搜尋", - "create.schematicannon.status.skipping": "跳過", - "create.schematicannon.status.missingBlock": "缺少方塊:", - "create.schematicannon.status.placing": "建築中", - "create.schematicannon.status.clearing": "清除方塊中", - "create.schematicannon.status.schematicInvalid": "藍圖無效", - "create.schematicannon.status.schematicNotPlaced": "藍圖未發佈", - "create.schematicannon.status.schematicExpired": "藍圖文件已過期", - - "create.materialChecklist": "材料清單", - "create.materialChecklist.blocksNotLoaded": "*免責聲明* \n\n由於未讀取相關區塊,材料清單可能不正確", - - "create.gui.filter.deny_list": "黑名單", - "create.gui.filter.deny_list.description": "只通過不在黑名單中的物品,如果黑名單為空,所有物品都可以通過", - "create.gui.filter.allow_list": "白名單", - "create.gui.filter.allow_list.description": "只通過在白名單中的物品,如果白名單為空,所有物品都無法通過", - "create.gui.filter.respect_data": "比對物品屬性", - "create.gui.filter.respect_data.description": "只有物品的耐久、附魔等其他屬性相同時才可以比對", - "create.gui.filter.ignore_data": "忽略物品屬性", - "create.gui.filter.ignore_data.description": "配對時忽略物品的耐久、附魔等其他屬性", - - "create.item_attributes.placeable": "可放置", - "create.item_attributes.placeable.inverted": "不可放置", - "create.item_attributes.consumable": "可食用", - "create.item_attributes.consumable.inverted": "不可食用", - "create.item_attributes.fluid_container": "可儲存流體", - "create.item_attributes.fluid_container.inverted": "不可儲存流體", - "create.item_attributes.enchanted": "已被附魔", - "create.item_attributes.enchanted.inverted": "未被附魔", - "create.item_attributes.max_enchanted": "已達到最高附魔等級", - "create.item_attributes.max_enchanted.inverted": "未達到最高附魔等級", - "create.item_attributes.renamed": "有自訂名稱", - "create.item_attributes.renamed.inverted": "沒有自訂名稱", - "create.item_attributes.damaged": "已損壞", - "create.item_attributes.damaged.inverted": "未損壞", - "create.item_attributes.badly_damaged": "嚴重受損", - "create.item_attributes.badly_damaged.inverted": "未嚴重受損", - "create.item_attributes.not_stackable": "無法堆疊", - "create.item_attributes.not_stackable.inverted": "可堆疊", - "create.item_attributes.equipable": "可裝備", - "create.item_attributes.equipable.inverted": "不可裝備", - "create.item_attributes.furnace_fuel": "是燃料", - "create.item_attributes.furnace_fuel.inverted": "不是燃料", - "create.item_attributes.washable": "可被篩洗", - "create.item_attributes.washable.inverted": "不可被篩洗", - "create.item_attributes.hauntable": "可被喚魂", - "create.item_attributes.hauntable.inverted": "不可被喚魂", - "create.item_attributes.crushable": "可被粉碎", - "create.item_attributes.crushable.inverted": "不可被粉碎", - "create.item_attributes.smeltable": "可被熔爐融煉", - "create.item_attributes.smeltable.inverted": "不可被熔爐融煉", - "create.item_attributes.smokable": "可被煙熏", - "create.item_attributes.smokable.inverted": "不可被煙熏", - "create.item_attributes.blastable": "可被高爐融煉", - "create.item_attributes.blastable.inverted": "不可被高爐融煉", - "create.item_attributes.compostable": "UNLOCALIZED: can be composted", - "create.item_attributes.compostable.inverted": "UNLOCALIZED: cannot be composted", - "create.item_attributes.shulker_level": "界伏盒是 %1$s", - "create.item_attributes.shulker_level.inverted": "界伏盒不是 %1$s", - "create.item_attributes.shulker_level.full": "滿的", - "create.item_attributes.shulker_level.empty": "空的", - "create.item_attributes.shulker_level.partial": "有裝東西但沒滿", - "create.item_attributes.in_tag": "標籤是 %1$s", - "create.item_attributes.in_tag.inverted": "標籤不是 %1$s", - "create.item_attributes.in_item_group": "屬於 %1$s", - "create.item_attributes.in_item_group.inverted": "不屬於 %1$s", - "create.item_attributes.added_by": "由 %1$s 添加", - "create.item_attributes.added_by.inverted": "不是由 %1$s 添加", - "create.item_attributes.has_enchant": "有附魔效果 %1$s", - "create.item_attributes.has_enchant.inverted": "沒有附魔效果 %1$s", - "create.item_attributes.color": "已被染色成 %1$s", - "create.item_attributes.color.inverted": "未被染色成 %1$s", - "create.item_attributes.has_fluid": "包含 %1$s", - "create.item_attributes.has_fluid.inverted": "不包含 %1$s", - "create.item_attributes.has_name": "有自定義名稱 %1$s", - "create.item_attributes.has_name.inverted": "沒有自定義名稱 %1$s", - "create.item_attributes.book_author": "由 %1$s 編寫", - "create.item_attributes.book_author.inverted": "未由 %1$s 編寫", - "create.item_attributes.book_copy_original": "是原創的", - "create.item_attributes.book_copy_original.inverted": "不是原創的", - "create.item_attributes.book_copy_first": "是第一份複製", - "create.item_attributes.book_copy_first.inverted": "不是第一份複製", - "create.item_attributes.book_copy_second": "是第二份複製", - "create.item_attributes.book_copy_second.inverted": "不是第二份複製", - "create.item_attributes.book_copy_tattered": "是第三份複製", - "create.item_attributes.book_copy_tattered.inverted": "不是第三份複製", - "create.item_attributes.astralsorcery_amulet": "提升 %1$s", - "create.item_attributes.astralsorcery_amulet.inverted": "不提升 %1$s", - "create.item_attributes.astralsorcery_constellation": "與 %1$s 調和", - "create.item_attributes.astralsorcery_constellation.inverted": "未與 %1$s 調和", - "create.item_attributes.astralsorcery_crystal": "具有晶體屬性 %1$s", - "create.item_attributes.astralsorcery_crystal.inverted": "不具有晶體屬性 %1$s", - "create.item_attributes.astralsorcery_perk_gem": "具有特殊屬性 %1$s", - "create.item_attributes.astralsorcery_perk_gem.inverted": "不具有特殊屬性 %1$s", - - "create.gui.attribute_filter.no_selected_attributes": "沒有標記任何屬性", - "create.gui.attribute_filter.selected_attributes": "已選擇的屬性:", - "create.gui.attribute_filter.add_attribute": "向列表中添加屬性", - "create.gui.attribute_filter.add_inverted_attribute": "向列表中添加相反屬性", - "create.gui.attribute_filter.allow_list_disjunctive": "任意比對白名單 (任何) ", - "create.gui.attribute_filter.allow_list_disjunctive.description": "只要有其中一項屬性符合,就可以通過", - "create.gui.attribute_filter.allow_list_conjunctive": "全部比對白名單 (全部) ", - "create.gui.attribute_filter.allow_list_conjunctive.description": "只有所有屬性都相符才可以通過", - "create.gui.attribute_filter.deny_list": "黑名單", - "create.gui.attribute_filter.deny_list.description": "只要沒有上述屬性,就可以通過", - "create.gui.attribute_filter.add_reference_item": "添加參考物品", - - "create.tooltip.holdForDescription": "按住 [%1$s] 來讀取物品概要", - "create.tooltip.holdForControls": "按住 [%1$s] 來讀取控制方法", - "create.tooltip.keyShift": "Shift", - "create.tooltip.keyCtrl": "Ctrl", - "create.tooltip.speedRequirement": "需求速度:%1$s", - "create.tooltip.speedRequirement.none": "無", - "create.tooltip.speedRequirement.slow": "慢", - "create.tooltip.speedRequirement.medium": "適當", - "create.tooltip.speedRequirement.fast": "快", - "create.tooltip.stressImpact": "動能消耗:%1$s", - "create.tooltip.stressImpact.low": "低", - "create.tooltip.stressImpact.medium": "中", - "create.tooltip.stressImpact.high": "高", - "create.tooltip.stressImpact.overstressed": "過載", - "create.tooltip.up_to": "最高 %1$s", - "create.tooltip.capacityProvided": "動能輸出:%1$s", - "create.tooltip.capacityProvided.low": "小", - "create.tooltip.capacityProvided.medium": "中", - "create.tooltip.capacityProvided.high": "大", - "create.tooltip.generationSpeed": "產生 %1$s %2$s", - "create.tooltip.analogStrength": "訊號強度:%1$s/15", - - "create.mechanical_arm.extract_from": "從 %1$s 拿取物品", - "create.mechanical_arm.deposit_to": "向 %1$s 儲存物品", - "create.mechanical_arm.summary": "機械臂有 %1$s 輸入以及 %2$s 輸出", - "create.mechanical_arm.points_outside_range": "%1$s 由於距離限制,選定的交互點被移除", - - "create.weighted_ejector.target_set": "已選取目的地", - "create.weighted_ejector.target_not_valid": "彈射到鄰近的方塊 (目的地無效)", - "create.weighted_ejector.no_target": "彈射到鄰近的方塊 (未選取目的地)", - "create.weighted_ejector.targeting": "彈射到 [%1$s,%2$s,%3$s]", - "create.weighted_ejector.stack_size": "彈射物品數量", - - "create.logistics.when_multiple_outputs_available": "當多個輸出可用時", - - "create.mechanical_arm.selection_mode.round_robin": "輪詢調度", - "create.mechanical_arm.selection_mode.forced_round_robin": "強制輪詢調度", - "create.mechanical_arm.selection_mode.prefer_first": "第一目標優先", - - "create.tunnel.selection_mode.split": "分攤", - "create.tunnel.selection_mode.forced_split": "強制分攤", - "create.tunnel.selection_mode.round_robin": "輪詢調度", - "create.tunnel.selection_mode.forced_round_robin": "強制輪詢調度", - "create.tunnel.selection_mode.prefer_nearest": "最近優先", - "create.tunnel.selection_mode.randomize": "隨機", - "create.tunnel.selection_mode.synchronize": "同步輸入", - - "create.tooltip.chute.header": "滑槽訊息", - "create.tooltip.chute.items_move_down": "物品向下移動", - "create.tooltip.chute.items_move_up": "物品向上移動", - "create.tooltip.chute.no_fans_attached": "未安裝鼓風機", - "create.tooltip.chute.fans_push_up": "鼓風機從下方進行推動", - "create.tooltip.chute.fans_push_down": "鼓風機從上方進行推動", - "create.tooltip.chute.fans_pull_up": "鼓風機從下方進行吸引", - "create.tooltip.chute.fans_pull_down": "鼓風機從上方進行吸引", - "create.tooltip.chute.contains": "物品: %1$s x%2$s", - "create.tooltip.deployer.header": "UNLOCALIZED: Deployer Information", - "create.tooltip.deployer.using": "UNLOCALIZED: Mode: Use", - "create.tooltip.deployer.punching": "UNLOCALIZED: Mode: Attack", - "create.tooltip.deployer.contains": "UNLOCALIZED: Item: %1$s x%2$s", - "create.tooltip.brass_tunnel.contains": "正在處理", - "create.tooltip.brass_tunnel.contains_entry": "> %1$s x%2$s", - "create.tooltip.brass_tunnel.retrieve": "右鍵取回", - - "create.linked_controller.bind_mode": "綁定模式", - "create.linked_controller.press_keybind": "按 %1$s, %2$s, %3$s, %4$s, %5$s 或 %6$s 來綁定這個頻率到對應按鍵上", - "create.linked_controller.key_bound": "頻率綁定到 %1$s 鍵", - "create.linked_controller.frequency_slot_1": "按鍵:%1$s 頻道 #1", - "create.linked_controller.frequency_slot_2": "按鍵:%1$s 頻道 #2", - - "create.crafting_blueprint.crafting_slot": "材料格", - "create.crafting_blueprint.filter_items_viable": "可使用進階物品過濾", - "create.crafting_blueprint.display_slot": "顯示格", - "create.crafting_blueprint.inferred": "根據配方推論", - "create.crafting_blueprint.manually_assigned": "手動設定", - "create.crafting_blueprint.secondary_display_slot": "次要顯示格", - "create.crafting_blueprint.optional": "可選的", - - "create.potato_cannon.ammo.attack_damage": "%1$s 攻擊傷害", - "create.potato_cannon.ammo.reload_ticks": "%1$s 攻擊速度", - "create.potato_cannon.ammo.knockback": "%1$s 擊退", - - "create.hint.hose_pulley.title": "無限供應", - "create.hint.hose_pulley": "目標流體為無限供應", - "create.hint.mechanical_arm_no_targets.title": "沒有目標", - "create.hint.mechanical_arm_no_targets": "看起來這個_機械臂_沒有被分配任何_目標_。在手持機械臂的同時,右鍵選取輸送帶、置物臺、漏斗或其他設備來設定目標", - "create.hint.empty_bearing.title": "更新軸承", - "create.hint.empty_bearing": "_空手右鍵_軸承來_添加_你新建造的結構", - "create.hint.full_deployer.title": "機械手物品溢出", - "create.hint.full_deployer": "_機械手_包含_過剩的物品_需要被_取出._使用漏斗_或其他方法將溢出解決", - - "create.backtank.low": "後背包壓力不足", - "create.backtank.depleted": "後背包壓力耗盡", - - "create.hint.derailed_train.title": "出軌的火車", - "create.hint.derailed_train": "這列_火車_不在軌道上,用扳手_左鍵點擊_它以重置到附近的軌道", - - "create.boiler.status": "鍋爐狀態:%1$s", - "create.boiler.status_short": "鍋爐:%1$s", - "create.boiler.passive": "運作中", - "create.boiler.idle": "閒置", - "create.boiler.lvl": "Lvl %1$s", - "create.boiler.max_lvl": "Max", - "create.boiler.size": "尺寸", - "create.boiler.size_dots": "....... ", - "create.boiler.water": "水", - "create.boiler.water_dots": "... ", - "create.boiler.heat": "熱量", - "create.boiler.heat_dots": "...... ", - "create.boiler.via_one_engine": "透過 1 個引擎", - "create.boiler.via_engines": "透過 %1$s 個引擎", - - "create.gui.schedule.lmb_edit": "左鍵點擊編輯", - "create.gui.schedule.rmb_remove": "右鍵點擊移除", - "create.gui.schedule.duplicate": "複製", - "create.gui.schedule.remove_entry": "移除動作", - "create.gui.schedule.add_entry": "增加動作", - "create.gui.schedule.move_up": "上移", - "create.gui.schedule.move_down": "下移", - "create.gui.schedule.add_condition": "增加條件", - "create.gui.schedule.alternative_condition": "增加替代條件", - - "create.schedule.instruction_type": "下一步:", - "create.schedule.instruction.editor": "指令編輯器", - "create.schedule.instruction.destination": "駛至車站", - "create.schedule.instruction.destination.summary": "下一站:", - "create.schedule.instruction.filter_edit_box": "站名", - "create.schedule.instruction.filter_edit_box_1": "使用「*」做為萬用字元", - "create.schedule.instruction.filter_edit_box_2": "例如:「我的車站,月台*」", - "create.schedule.instruction.filter_edit_box_3": "火車會選擇最近且未被使用的月台", - "create.schedule.instruction.rename": "更新時刻表標題", - "create.schedule.instruction.rename.summary": "新標題:", - "create.schedule.instruction.name_edit_box": "時刻表標題", - "create.schedule.instruction.name_edit_box_1": "影響顯示板上的文字", - "create.schedule.instruction.name_edit_box_2": "預設為下一個目的地的名稱", - "create.schedule.instruction.throttle": "極速限制", - "create.schedule.instruction.throttle.summary": "調整極速為 %1$s", - "create.schedule.instruction.throttle_edit_box": "油門", - "create.schedule.instruction.throttle_edit_box_1": "影響火車的極速", - "create.schedule.condition_type": "如果/之後…繼續", - "create.schedule.condition.editor": "條件編輯器", - "create.schedule.condition.delay": "延遲", - "create.schedule.condition.delay_short": "等待:%1$s", - "create.schedule.condition.delay.status": "%1$s 後出發", - "create.schedule.condition.idle": "閒置貨物", - "create.schedule.condition.idle_short": "貨物閒置:%1$s", - "create.schedule.condition.idle.status": "貨物閒置 %1$s", - "create.schedule.condition.for_x_time": "%1$s", - "create.schedule.condition.unloaded": "區塊卸載", - "create.schedule.condition.unloaded.status": "等待區塊卸載", - "create.schedule.condition.powered": "車站充能", - "create.schedule.condition.powered.status": "等待紅石訊號", - "create.schedule.condition.time_of_day": "日中時刻", - "create.schedule.condition.time_of_day.scheduled": "規劃時間:%1$s", - "create.schedule.condition.time_of_day.digital_format": "%1$s:%3$s %4$s", - "create.schedule.condition.time_of_day.rotation": "重複", - "create.schedule.condition.time_of_day.rotation.every_24": "每日", - "create.schedule.condition.time_of_day.rotation.every_12": "每 12 小時", - "create.schedule.condition.time_of_day.rotation.every_6": "每 6 小時", - "create.schedule.condition.time_of_day.rotation.every_4": "每 4 小時", - "create.schedule.condition.time_of_day.rotation.every_3": "每 3 小時", - "create.schedule.condition.time_of_day.rotation.every_2": "每 2 小時", - "create.schedule.condition.time_of_day.rotation.every_1": "每 1 小時", - "create.schedule.condition.time_of_day.rotation.every_0_45": "每 45 分鐘", - "create.schedule.condition.time_of_day.rotation.every_0_30": "每 30 分鐘", - "create.schedule.condition.time_of_day.rotation.every_0_15": "每 15 分鐘", - "create.schedule.condition.time_of_day.status": "發車於", - "create.schedule.condition.threshold.train_holds": "火車上有 %1$s", - "create.schedule.condition.threshold.greater": "多於", - "create.schedule.condition.threshold.less": "少於", - "create.schedule.condition.threshold.equal": "剛好", - "create.schedule.condition.threshold.x_units_of_item": "%1$s%2$s %3$s", - "create.schedule.condition.threshold.matching_content": "比對內容", - "create.schedule.condition.threshold.anything": "UNLOCALIZED: Anything", - "create.schedule.condition.threshold.item_measure": "物品單位", - "create.schedule.condition.threshold.items": "個", - "create.schedule.condition.threshold.stacks": "組", - "create.schedule.condition.threshold.buckets": "桶", - "create.schedule.condition.threshold.status": "貨物:%1$s/%2$s %3$s", - "create.schedule.condition.threshold.place_item": "參考物品", - "create.schedule.condition.threshold.place_item_2": "可以使用過濾器", - "create.schedule.condition.threshold.place_item_3": "UNLOCALIZED: Leave empty to match any", - "create.schedule.condition.fluid_threshold": "流體貨物條件", - "create.schedule.condition.item_threshold": "物品貨物條件", - "create.schedule.condition.redstone_link": "無線紅石連接", - "create.schedule.condition.redstone_link.status": "等待無線紅石連接", - "create.schedule.condition.redstone_link_on": "連線開啟", - "create.schedule.condition.redstone_link_off": "連線關閉", - "create.schedule.condition.redstone_link.powered": "開啟", - "create.schedule.condition.redstone_link.unpowered": "關閉", - "create.schedule.condition.redstone_link.frequency_state": "頻道狀態:", - "create.schedule.condition.redstone_link.frequency_powered": "頻道開啟:", - "create.schedule.condition.redstone_link.frequency_unpowered": "頻道關閉:", - "create.schedule.condition.player_count": "玩家入座", - "create.schedule.condition.player_count.summary": "%1$s玩家", - "create.schedule.condition.player_count.summary_plural": "%1$s玩家", - "create.schedule.condition.player_count.seated": "%1$s入座", - "create.schedule.condition.player_count.players": "玩家", - "create.schedule.condition.player_count.condition": "條件", - "create.schedule.condition.player_count.exactly": "剛好", - "create.schedule.condition.player_count.or_above": "或以上", - "create.schedule.condition.player_count.status": "乘客:%1$s/%2$s", - "create.schedule.loop": "持續循環", - "create.schedule.loop1": "時刻表結束後", - "create.schedule.loop2": "重新開始", - "create.schedule.reset": "重置進程", - "create.schedule.skip": "跳過現在的步驟", - "create.schedule.applied_to_train": "火車現在正照表操課", - "create.schedule.non_controlling_seat": "司機員必須坐在火車控制台前", - "create.schedule.remove_with_empty_hand": "空手移除現在的時刻表", - "create.schedule.auto_removed_from_train": "自動時刻表被棄置", - "create.schedule.removed_from_train": "從火車回收時刻表", - "create.schedule.no_stops": "這份時刻表沒有設定任何停靠站", - "create.schedule.continued": "時刻表已重新開始", - - "create.track.selection_cleared": "已清除選擇區域", - "create.track.valid_connection": "可以連接", - "create.track.second_point": "鋪設火車軌道或選擇第二處", - "create.track.too_far": "距離過遠", - "create.track.original_missing": "原方塊已被移除,潛行點擊以重置", - "create.track.perpendicular": "無法垂直連接軌道", - "create.track.ascending_s_curve": "無法鋪設有坡度的S形彎", - "create.track.too_sharp": "曲率過高", - "create.track.too_steep": "斜率過高", - "create.track.slope_turn": "轉彎時無法進入或離開斜坡", - "create.track.opposing_slopes": "無法連接下斜方向相反的斜坡", - "create.track.leave_slope_ascending": "無法在上升時離開這個斜坡", - "create.track.leave_slope_descending": "無法在下降時離開這個斜坡", - "create.track.turn_90": "單個彎最多只能轉 90 度", - "create.track.junction_start": "無法從道岔開始連接", - "create.track.turn_start": "無法從彎道開始連結", - "create.track.not_enough_tracks": "火車軌道不足", - "create.track.not_enough_pavement": "基座方塊不足", - - "create.portal_track.failed": "無法鋪設傳送門軌道:", - "create.portal_track.missing": "對向傳送門尚未生成", - "create.portal_track.blocked": "對向位址被堵塞 (%1$s,%2$s,%3$s)", - - "create.station.idle": "車站閒置中", - "create.station.assembly_title": "組裝火車", - "create.station.close": "關閉視窗", - "create.station.cancel": "取消組裝", - "create.station.failed": "組裝失敗", - "create.station.icon_type": "圖樣類型", - "create.station.create_train": "創建新火車", - "create.station.assemble_train": "組裝火車", - "create.station.disassemble_train": "拆解火車", - "create.station.remove_schedule": "回收時刻表", - "create.station.remove_auto_schedule": "棄置自動時刻表", - "create.station.no_assembly_diagonal": "無法在對角線軌道上", - "create.station.no_assembly_diagonal_1": "組裝火車", - "create.station.no_assembly_curve": "無法在彎道上", - "create.station.no_assembly_curve_1": "組裝火車", - "create.station.train_not_aligned": "仍有車廂未對齊", - "create.station.train_not_aligned_1": "無法拆解", - "create.station.carriage_number": "車廂 %1$s:", - "create.station.retry": "解決問題並重新嘗試", - "create.station.no_bogeys": "無轉向架", - "create.station.one_bogey": "一座轉向架", - "create.station.more_bogeys": "%1$s 座轉向架", - "create.station.how_to": "在加亮軌道上放置火車機殼以創建轉向架", - "create.station.how_to_1": "破壞轉向架上方的方塊以移除轉向架", - "create.station.how_to_2": "搭建車廂時每個車廂都須與一或二座轉向架連接", - - "create.train_assembly.too_many_bogeys": "轉向架連接過多:%1$s", - "create.train_assembly.frontmost_bogey_at_station": "最前方的轉向架需位於車站標記處", - "create.train_assembly.no_bogeys": "找無轉向架", - "create.train_assembly.not_connected_in_order": "轉向架未按順序連接", - "create.train_assembly.bogeys_too_close": "轉向架 %1$s 及 %2$s 距離過近", - "create.train_assembly.single_bogey_carriage": "這類轉向架無法單獨支撐一個車廂", - "create.train_assembly.nothing_attached": "沒有任何結構連接到轉向架 %1$s", - "create.train_assembly.no_controls": "火車上需安裝至少一個面向前方的火車控制台", - "create.train_assembly.sideways_controls": "某個已安裝的火車控制台面向火車側面", - "create.train_assembly.bogey_created": "已創建轉向架,再度點擊以循環改變種類", - "create.train_assembly.requires_casing": "在軌道上放置火車機殼以創建轉向架", - - "create.track_target.set": "已選擇目標軌道", - "create.track_target.success": "成功綁定目標軌道", - "create.track_target.clear": "已清除選擇的軌道", - "create.track_target.missing": "先對目標火車軌道點擊右鍵", - "create.track_target.too_far": "目標軌道距離此處過遠", - "create.track_target.no_junctions": "目標軌道不能是道岔", - "create.track_target.occupied": "目標軌道被占用", - "create.track_target.invalid": "無法在此定位該軌道", - - "create.train.unnamed": "未命名火車", - "create.train.cannot_relocate_moving": "無法重新設置移動中的火車", - "create.train.relocate": "點擊軌道以重新設置 %1$s,潛行點擊則取消", - "create.train.relocate.abort": "重新設置被取消", - "create.train.relocate.success": "重新設置成功", - "create.train.relocate.valid": "火車可重新設置於此,點擊確認", - "create.train.relocate.invalid": "無法重新設置火車於此", - "create.train.relocate.too_far": "無法重新設置火車於過遠的位置", - "create.train.departing_from": "自 %1$s 發車", - "create.train.arrived_at": "抵達 %1$s", - "create.train.status": " 火車資訊:%1$s", - "create.train.status.back_on_track": "火車已回到軌道上", - "create.train.status.collision": "與其他火車相撞", - "create.train.status.end_of_track": "車廂已至軌道末端", - "create.train.status.double_portal": "車廂不能同時進入與離開傳送門", - "create.train.status.coupling_stress": "因連結器受壓,火車已被強制停止", - "create.train.status.track_missing": "火車下方無軌道", - "create.train.status.paused_for_manual": "時刻表暫停運作,手動控制中", - "create.train.status.opposite_driver": "路線需要司機員面向反方向", - "create.train.status.missing_driver": "司機員失蹤", - "create.train.status.found_driver": "已找到新的司機員", - "create.train.status.navigation_success": "導航成功", - "create.train.status.no_match": "圖上無符合「%1$s」的車站", - "create.train.status.no_path": "找無通往下個目的地的路線", - - "create.track_signal.cannot_change_mode": "無法切換訊號模式", - "create.track_signal.mode_change.entry_signal": "-> 若區間未被占用則允許通行", - "create.track_signal.mode_change.cross_signal": "-> 若區間可穿越則允許通行", - - "create.contraption.controls.start_controlling": "正在控制:%1$s", - "create.contraption.controls.stop_controlling": "停止控制裝置", - "create.contraption.controls.approach_station": "按住 %1$s 以接近 %2$s", - - "create.display_link.set": "已選定目標位置", - "create.display_link.success": "成功綁定到目標位置", - "create.display_link.clear": "清除位置選擇", - "create.display_link.too_far": "目標位置離這裡太遠", - "create.display_link.invalid": "鏈路沒有有效的目標,請嘗試重新放置", - "create.display_link.title": "連接鏈路", - "create.display_link.no_source": "非訊號源", - "create.display_link.no_target": "非訊號目標", - "create.display_link.reading_from": "讀取自:", - "create.display_link.writing_to": "發送到:", - "create.display_link.attached_side": "在接收側的方塊", - "create.display_link.targeted_location": "在目標位置的方塊", - "create.display_link.view_compatible": "點擊查看所有相容項目", - "create.display_link.information_type": "訊息類型", - "create.display_link.display_on": "將數據寫入:", - "create.display_link.display_on_multiline": "首行發送到:", - - "create.display_source.label": "添加標籤", - "create.display_source.combine_item_names": "內含的物件名稱", - "create.display_source.count_items": "匹配的物品總量", - "create.display_source.list_items": "匹配的物品清單", - "create.display_source.fluid_amount": "匹配的流體總量", - "create.display_source.list_fluids": "匹配的流體清單", - "create.display_source.nixie_tube": "複製文字", - "create.display_source.fill_level": "容器充填程度", - "create.display_source.fill_level.display": "顯示格式", - "create.display_source.fill_level.percent": "百分比", - "create.display_source.fill_level.progress_bar": "進度條", - "create.display_source.value_list.display": "數值格式", - "create.display_source.value_list.shortened": "精簡", - "create.display_source.value_list.full_number": "完整", - "create.display_source.value_list.thousand": "k", - "create.display_source.value_list.million": "m", - "create.display_source.player_deaths": "玩家死亡次數", - "create.display_source.scoreboard": "計分板", - "create.display_source.scoreboard.objective": "計分項 ID", - "create.display_source.scoreboard.objective_not_found": "找不到 「%1$s」", - "create.display_source.scoreboard.objective.deaths": "玩家死亡次數", - "create.display_source.time_of_day": "當日時間", - "create.display_source.stop_watch": "碼表", - "create.display_source.time.format": "時間格式", - "create.display_source.time.12_hour": "12小時制", - "create.display_source.time.24_hour": "24小時制", - "create.display_source.accumulate_items": "累積物品數量", - "create.display_source.item_throughput": "物品吞吐量", - "create.display_source.item_throughput.interval": "間隔", - "create.display_source.item_throughput.interval.second": "每秒", - "create.display_source.item_throughput.interval.minute": "每分鐘", - "create.display_source.item_throughput.interval.hour": "每小時", - "create.display_source.train_status": "火車時刻表資訊", - "create.display_source.station_summary": "火車站點概要", - "create.display_source.station_summary.filter": "站名過濾器", - "create.display_source.station_summary.train_name_column": "火車判定尺寸", - "create.display_source.station_summary.platform_column": "月台判定尺寸", - "create.display_source.station_summary.now": "到站", - "create.display_source.station_summary.minutes": " 分鐘", - "create.display_source.station_summary.seconds": "%1$s 秒", - "create.display_source.observed_train_name": "檢測到的火車名稱", - "create.display_source.max_enchant_level": "最大附魔費用", - "create.display_source.boiler_status": "鍋爐狀態", - "create.display_source.entity_name": "實體名稱", - "create.display_source.kinetic_speed": "轉速 (RPM)", - "create.display_source.kinetic_speed.absolute": "無視轉向", - "create.display_source.kinetic_speed.directional": "顯示轉向", - "create.display_source.kinetic_stress": "網路負荷", - "create.display_source.kinetic_stress.display": "顯示訊息", - "create.display_source.kinetic_stress.progress_bar": "進度條", - "create.display_source.kinetic_stress.percent": "百分比", - "create.display_source.kinetic_stress.current": "動能負荷", - "create.display_source.kinetic_stress.max": "總能量", - "create.display_source.kinetic_stress.remaining": "剩餘動能", - "create.display_source.redstone_power": "紅石訊號強度", - "create.display_source.redstone_power.display": "顯示格式", - "create.display_source.redstone_power.number": "數值", - "create.display_source.redstone_power.progress_bar": "進度條", - "create.display_source.boiler.not_enough_space": "空間不足", - "create.display_source.boiler.for_boiler_status": "以顯示鍋爐狀態", - - "create.display_target.line": "第 %1$s 行", - "create.display_target.page": "第 %1$s 頁", - "create.display_target.single_line": "單行", - - "create.flap_display.cycles.alphabet": " ;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;X;Y;Z", - "create.flap_display.cycles.numeric": " ;0;1;2;3;4;5;6;7;8;9", - "create.flap_display.cycles.arrival_time": " ; min;now;15s;30s;45s", - "create.flap_display.cycles.shortened_numbers": " ;K;M", - "create.flap_display.cycles.fluid_units": "mB;B ", - "create.flap_display.cycles.instant": " ; ", - "create.flap_display.cycles.pixel": "█;▓;?", - - "create.super_glue.too_far": "選取的區域過大", - "create.super_glue.cannot_reach": "選取的方塊必須連通", - "create.super_glue.click_to_confirm": "再度點擊以確認", - "create.super_glue.click_to_discard": "潛行右鍵以放棄選取", - "create.super_glue.first_pos": "已選取第一個位置", - "create.super_glue.abort": "放棄選取", - "create.super_glue.not_enough": "庫存中沒有足夠的強力膠", - "create.super_glue.success": "塗抹強力膠…", - - "create.gui.config.overlay1": "嗨 :)", - "create.gui.config.overlay2": "這是一個實例層", - "create.gui.config.overlay3": "點擊拖拽你的滑鼠", - "create.gui.config.overlay4": "來將它移動到前方", - "create.gui.config.overlay5": "ESC 退出目前介面", - "create.gui.config.overlay6": "並儲存新的位置", - "create.gui.config.overlay7": "輸入 /create overlay reset", - "create.gui.config.overlay8": "重設到預設位置", - - "create.command.killTPSCommand": "killtps", - "create.command.killTPSCommand.status.slowed_by.0": "[Create]: 伺服器每秒 tick 被降為 %s ms :o", - "create.command.killTPSCommand.status.slowed_by.1": "[Create]: 伺服器現在每秒 tick 被降為 >:)", - "create.command.killTPSCommand.status.slowed_by.2": "[Create]: 伺服器現在不延遲了,fps 正常 :D", - "create.command.killTPSCommand.status.usage.0": "[Create]: 用 /killtps stop 來讓伺服器的 fps 速度恢復正常", - "create.command.killTPSCommand.status.usage.1": "[Create]: 用 /killtps start 來手動降低伺服器 fps", - "create.command.killTPSCommand.argument.tickTime": "TickTime", - - "create.contraption.minecart_contraption_too_big": "這個礦車結構太大了而無法撿取", - "create.contraption.minecart_contraption_illegal_pickup": "一股神秘的力量將這個礦車結構與世界綁在一起", - - - "_": "->------------------------] Subtitles [------------------------<-", - - "create.subtitle.contraption_disassemble": "結構停止", - "create.subtitle.peculiar_bell_use": "黃銅鐘聲", - "create.subtitle.worldshaper_place": "地形塑造器發射聲", - "create.subtitle.whistle_train_manual": "火車汽笛聲", - "create.subtitle.steam": "蒸氣聲", - "create.subtitle.saw_activate_stone": "機械圓鋸機聲", - "create.subtitle.schematicannon_finish": "藍圖大炮完成任務", - "create.subtitle.crafter_craft": "機械合成器合成聲", - "create.subtitle.wrench_remove": "零件移除聲", - "create.subtitle.train3": "轉向架的車輪隆隆作響", - "create.subtitle.whistle": "汽笛聲", - "create.subtitle.cogs": "齒輪隆隆聲", - "create.subtitle.slime_added": "黏液擠壓", - "create.subtitle.whistle_train_low": "汽笛低嘯", - "create.subtitle.schematicannon_launch_block": "藍圖大炮發射", - "create.subtitle.controller_take": "拿下遙控器", - "create.subtitle.crafter_click": "機械合成器工作聲", - "create.subtitle.depot_plop": "物品著地", - "create.subtitle.confirm": "接受提示聲", - "create.subtitle.mixing": "攪拌機噪音", - "create.subtitle.mechanical_press_activation_belt": "液壓機工作", - "create.subtitle.fwoomp": "馬鈴薯大砲發射", - "create.subtitle.sanding_long": "打磨的聲響", - "create.subtitle.crushing_1": "粉碎的聲響", - "create.subtitle.depot_slide": "物品滑動聲", - "create.subtitle.blaze_munch": "烈焰使者咀嚼聲", - "create.subtitle.funnel_flap": "垂簾拍打", - "create.subtitle.haunted_bell_use": "靈魂鐘敲響", - "create.subtitle.scroll_value": "滾動輸入聲", - "create.subtitle.controller_put": "遙控器放置聲", - "create.subtitle.cranking": "手搖把手轉動聲", - "create.subtitle.sanding_short": "打磨的聲響", - "create.subtitle.wrench_rotate": "使用扳手", - "create.subtitle.potato_hit": "食物撞擊聲", - "create.subtitle.saw_activate_wood": "機械圓鋸機運作聲", - "create.subtitle.whistle_high": "汽笛高嘯", - "create.subtitle.whistle_train_manual_low": "火車汽笛聲", - "create.subtitle.whistle_train": "汽笛聲", - "create.subtitle.haunted_bell_convert": "靈魂鐘轉化聲", - "create.subtitle.train": "轉向架的車輪隆隆作響", - "create.subtitle.deny": "故障聲", - "create.subtitle.controller_click": "遙控器按鍵聲", - "create.subtitle.whistle_low": "汽笛低嘯", - "create.subtitle.copper_armor_equip": "潛水裝裝備聲", - "create.subtitle.mechanical_press_activation": "液壓機工作", - "create.subtitle.contraption_assemble": "結構移動", - - - "_": "->------------------------] Item Descriptions [------------------------<-", - - "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", - "item.create.example_item.tooltip.summary": "A brief description of the item._Underscores_highlight a term.", - "item.create.example_item.tooltip.condition1": "When this", - "item.create.example_item.tooltip.behaviour1": "Then this item does this(behaviours show on shift)", - "item.create.example_item.tooltip.condition2": "And When this", - "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", - "item.create.example_item.tooltip.control1": "When Ctrl pressed", - "item.create.example_item.tooltip.action1": "These controls are displayed.", - - "block.create.wooden_bracket.tooltip": "木製支架", - "block.create.wooden_bracket.tooltip.summary": "用來裝飾_傳動軸_,_齒輪_和_管道_", - - "block.create.metal_bracket.tooltip": "金屬支架", - "block.create.metal_bracket.tooltip.summary": "用來裝飾_傳動軸_,_齒輪_和_管道_", - - "block.create.seat.tooltip": "坐墊", - "block.create.seat.tooltip.summary": "坐下來享受旅程吧!坐墊將會把玩家固定在一個移動裝置上,也可以用來作為居家裝飾,畢竟他有許多顏色", - "block.create.seat.tooltip.condition1": "對坐墊右鍵", - "block.create.seat.tooltip.behaviour1": "玩家將坐在_坐墊_上,按左側 Shift 可離開_坐墊_", - - "item.create.blaze_cake.tooltip": "熔岩蛋糕", - "item.create.blaze_cake.tooltip.summary": "為您辛勤工作的_烈焰使者_提供美味佳餚。讓牠們興奮起來吧!", - - "item.create.wand_of_symmetry.tooltip": "對稱杖", - "item.create.wand_of_symmetry.tooltip.summary": "完美地鏡面複製工作區域內的方塊放置於破壞", - "item.create.wand_of_symmetry.tooltip.condition1": "當在快捷欄時", - "item.create.wand_of_symmetry.tooltip.behaviour1": "持續進行鏡面複製", - "item.create.wand_of_symmetry.tooltip.control1": "當右鍵地面時", - "item.create.wand_of_symmetry.tooltip.action1": "_創建_或_移動_鏡子", - "item.create.wand_of_symmetry.tooltip.control2": "當右鍵空氣時", - "item.create.wand_of_symmetry.tooltip.action2": "_刪除_鏡子", - "item.create.wand_of_symmetry.tooltip.control3": "當潛行右鍵時", - "item.create.wand_of_symmetry.tooltip.action3": "打開_gui介面_", - - "item.create.handheld_worldshaper.tooltip": "地形雕塑器", - "item.create.handheld_worldshaper.tooltip.summary": "用於創造_景觀_和_地形特徵_的便利工具", - "item.create.handheld_worldshaper.tooltip.control1": "當左鍵方塊時", - "item.create.handheld_worldshaper.tooltip.action1": "將地形雕塑器放置的方塊設定為所選的方塊", - "item.create.handheld_worldshaper.tooltip.control2": "當右鍵方塊時", - "item.create.handheld_worldshaper.tooltip.action2": "_放置_或_替換_所選的方塊", - "item.create.handheld_worldshaper.tooltip.control3": "當潛行右鍵時", - "item.create.handheld_worldshaper.tooltip.action3": "打開_操作介面_", - - "item.create.tree_fertilizer.tooltip": "樹木肥料", - "item.create.tree_fertilizer.tooltip.summary": "適用來常見樹木的快速肥料", - "item.create.tree_fertilizer.tooltip.condition1": "對樹苗使用時", - "item.create.tree_fertilizer.tooltip.behaviour1": "無論_生長時間_多少,直接長大", - - "item.create.extendo_grip.tooltip": "伸縮機械手", - "item.create.extendo_grip.tooltip.summary": "biubiubiu! 大幅度_增加了_使用者的_觸碰距離_", - "item.create.extendo_grip.tooltip.condition1": "放置於副手欄時", - "item.create.extendo_grip.tooltip.behaviour1": "大幅增加_主手_的觸碰距離,與_主手_的伸縮機械手攜同使用,可進一步增加_觸碰距離_", - "item.create.extendo_grip.tooltip.condition2": "當裝備銅製後背包時", - "item.create.extendo_grip.tooltip.behaviour2": "_不會消耗耐久_,但是會抽取銅製後背包裡的_壓縮空氣_", - - "item.create.potato_cannon.tooltip": "馬鈴薯大砲", - "item.create.potato_cannon.tooltip.summary": "噗~碰!用你種的蔬菜來攻擊敵人。可以用_銅製後背包_的壓縮空氣驅動", - "item.create.potato_cannon.tooltip.condition1": "當點擊右鍵時", - "item.create.potato_cannon.tooltip.behaviour1": "從_物品欄_中_發射_一顆彈藥", - "item.create.potato_cannon.tooltip.condition2": "當裝備銅製後背包時", - "item.create.potato_cannon.tooltip.behaviour2": "_不會消耗耐久_ 但是會抽取銅製後背包裡的_壓縮空氣_", - - "item.create.filter.tooltip": "過濾器", - "item.create.filter.tooltip.summary": "將物品更精確地進行_篩選分類_,可以同時_篩選_多個物品或者將已標記的_過濾器_放在另一個_過濾器_里_嵌套_使用", - "item.create.filter.tooltip.condition1": "當放置於過濾插槽中時", - "item.create.filter.tooltip.behaviour1": "根據_過濾器_的設定,來_決定_物品是否能夠通過", - "item.create.filter.tooltip.condition2": "當點擊右鍵時", - "item.create.filter.tooltip.behaviour2": "打開_設定面板_", - - "item.create.attribute_filter.tooltip": "屬性過濾器", - "item.create.attribute_filter.tooltip.summary": "比起普通過濾器,_屬性過濾器_可以根據不同物品的_屬性_來進行過濾", - "item.create.attribute_filter.tooltip.condition1": "當放置於過濾插槽中時", - "item.create.attribute_filter.tooltip.behaviour1": "根據_過濾器_的配置,來_決定_物品是否能夠通過", - "item.create.attribute_filter.tooltip.condition2": "當點擊右鍵時", - "item.create.attribute_filter.tooltip.behaviour2": "打開_配置面板_", - - "item.create.empty_schematic.tooltip": "空白藍圖", - "item.create.empty_schematic.tooltip.summary": "可作為合成材料或在_藍圖桌_使用", - - "item.create.schematic.tooltip": "藍圖", - "item.create.schematic.tooltip.summary": "將工程結構的_設計圖_放置於_世界中_,並使用_藍圖加農炮_進行構建", - "item.create.schematic.tooltip.condition1": "當設計圖存在時", - "item.create.schematic.tooltip.behaviour1": "可以使用屏幕上的工具調整位置", - "item.create.schematic.tooltip.control1": "當潛行右鍵時", - "item.create.schematic.tooltip.action1": "打開一個用來輸入_精確坐標_的介面", - - "item.create.schematic_and_quill.tooltip": "藍圖與筆", - "item.create.schematic_and_quill.tooltip.summary": "用來將世界中的結構存到 .nbt 文件", - "item.create.schematic_and_quill.tooltip.condition1": "第一步", - "item.create.schematic_and_quill.tooltip.behaviour1": "手持藍圖與右鍵旋轉兩個點", - "item.create.schematic_and_quill.tooltip.condition2": "第二步", - "item.create.schematic_and_quill.tooltip.behaviour2": "按住 Ctrl 滑鼠滾輪選擇選區大小,右鍵空白處存檔", - "item.create.schematic_and_quill.tooltip.control1": "右鍵", - "item.create.schematic_and_quill.tooltip.action1": "選取點 / 確認存檔", - "item.create.schematic_and_quill.tooltip.control2": "按住 Ctrl 滑鼠滾輪", - "item.create.schematic_and_quill.tooltip.action2": "在_空中_選擇點滾動以調整距離", - "item.create.schematic_and_quill.tooltip.control3": "當潛行右鍵時", - "item.create.schematic_and_quill.tooltip.action3": "_重設_並刪除選區", - - "block.create.schematicannon.tooltip": "藍圖加農炮", - "block.create.schematicannon.tooltip.summary": "通過發射方塊以在世界中重新構建已部署的_全息圖_,使用相鄰箱子中的物品及_火藥_作為燃料", - "block.create.schematicannon.tooltip.condition1": "當你對加農砲右鍵時", - "block.create.schematicannon.tooltip.behaviour1": "打開加農砲的設定介面", - - "block.create.schematic_table.tooltip": "藍圖桌", - "block.create.schematic_table.tooltip.summary": "將保存的藍圖圖寫入_空白藍圖_", - "block.create.schematic_table.tooltip.condition1": "放入空白藍圖時", - "block.create.schematic_table.tooltip.behaviour1": "從 Schematics 文件夾上傳所選文件", - - "item.create.goggles.tooltip": "工程師護目鏡", - "item.create.goggles.tooltip.summary": "一副特殊的眼鏡,能夠讓你看見_動能_的訊息", - "item.create.goggles.tooltip.condition1": "當裝備後", - "item.create.goggles.tooltip.behaviour1": "將會顯示該機械元件的_速度_、_動能_等數值", - "item.create.goggles.tooltip.condition2": "當裝備後看向儀表時", - "item.create.goggles.tooltip.behaviour2": "將會顯示該儀表所連接網路的_速度_、_動能_等數值", - "item.create.goggles.tooltip.condition3": "當裝備後看向流體容器時", - "item.create.goggles.tooltip.behaviour3": "將會顯示儲存在該容器內的 _流體_ 以及其 _容量_ 等資訊", - - "item.create.wrench.tooltip": "扳手", - "item.create.wrench.tooltip.summary": "一種常用的工具,能夠調整_動能_的_方向_、_配置_等", - "item.create.wrench.tooltip.control1": "右鍵動力元件時", - "item.create.wrench.tooltip.action1": "以點擊的面為軸心_旋轉_點擊的方塊", - "item.create.wrench.tooltip.control2": "當潛行右鍵時", - "item.create.wrench.tooltip.action2": "將物品_取下_並移動到你的背包中", - - "block.create.nozzle.tooltip": "分散網", - "block.create.nozzle.tooltip.summary": "依附在鼓風機上,能夠將鼓風機的效果_分散_各個方向", - - "block.create.cuckoo_clock.tooltip": "布穀鳥鐘", - "block.create.cuckoo_clock.tooltip.summary": "精美的布穀鳥鐘,能夠報時", - "block.create.cuckoo_clock.tooltip.condition1": "輸入動力時", - "block.create.cuckoo_clock.tooltip.behaviour1": "顯示_現在時間_且一天會報時_兩次_;中午一次,黃昏可以睡覺時一次 ", - - "block.create.turntable.tooltip": "轉盤", - "block.create.turntable.tooltip.summary": "讓旋轉機械給你帶來一場刺激的旋轉風車體驗", - - "block.create.toolbox.tooltip": "工具箱", - "block.create.toolbox.tooltip.summary": "發明家的好夥伴。便利且大量的_容納八種_物品", - "block.create.toolbox.tooltip.condition1": "拾取時", - "block.create.toolbox.tooltip.behaviour1": "_保留內容物_", - "block.create.toolbox.tooltip.condition2": "放置於一定範圍內時", - "block.create.toolbox.tooltip.behaviour2": "_附近玩家_可以按對應的_快捷鍵_ (預設ALT) _遠程_訪問內容物", - "block.create.toolbox.tooltip.condition3": "當點擊右鍵時", - "block.create.toolbox.tooltip.behaviour3": "開啟_工具箱介面_", - - "block.create.stockpile_switch.tooltip": "存量偵測器", - "block.create.stockpile_switch.tooltip.summary": "根據連接的容器_儲存空間_的占用情況切換紅石訊號強度", - "block.create.stockpile_switch.tooltip.condition1": "低於下限或高於上限時", - "block.create.stockpile_switch.tooltip.behaviour1": "提供紅石訊號", - - "block.create.content_observer.tooltip": "物品偵測器", - "block.create.content_observer.tooltip.summary": "偵測_容器_、_管道_或_輸送帶_中,與_過濾器_設定相匹配的_物品_或_流體_", - "block.create.content_observer.tooltip.condition1": "偵測容器時", - "block.create.content_observer.tooltip.behaviour1": "偵測到容器內含_匹配的內容物_時,發出_紅石訊號_", - "block.create.content_observer.tooltip.condition2": "偵測漏斗時", - "block.create.content_observer.tooltip.behaviour2": "偵測到_匹配的物品_被_轉移_時,發出_紅石脈衝_", - - "block.create.creative_crate.tooltip": "創造板條箱", - "block.create.creative_crate.tooltip.summary": "這個容器可以給臨近的_藍圖大炮_提供無限物品以及燃料 (創造模式專屬) ", - "block.create.creative_crate.tooltip.condition1": "當標記了物品時", - "block.create.creative_crate.tooltip.behaviour1": "容器將會從虛空中提供_無限量_的標記物品,並且任何放置到容器中的物品都會被_送入虛空_", - - "item.create.creative_blaze_cake.tooltip": "創造熔岩蛋糕", - "item.create.creative_blaze_cake.tooltip.summary": "為您的_烈焰使者_提供特別款待。吃完這個蛋糕後,烈焰使者將_永不耗盡燃料_", - "item.create.creative_blaze_cake.tooltip.condition1": "使用時", - "item.create.creative_blaze_cake.tooltip.behaviour1": "_循環地_更改烈焰使者的燃燒模式", - - "block.create.controller_rail.tooltip": "控制鐵軌", - "block.create.controller_rail.tooltip.summary": "單向電動導軌,能夠精細控制礦車的移動速度", - "block.create.controller_rail.tooltip.condition1": "輸入紅石訊號時", - "block.create.controller_rail.tooltip.behaviour1": "根據訊號強度_加速_或_減速_經過的礦車,並將紅石強度傳播到相鄰的控制鐵軌", - - "item.create.sand_paper.tooltip": "紅砂紙", - "item.create.sand_paper.tooltip.summary": "用來_打磨_物品的砂紙,可以用_機械手_來實現自動化", - "item.create.sand_paper.tooltip.condition1": "使用時", - "item.create.sand_paper.tooltip.behaviour1": "打磨_副手_上或者_準心所指_的物品", - - "item.create.builders_tea.tooltip": "建築工的茶", - "item.create.builders_tea.tooltip.summary": "神清氣爽的一天,從這杯完美茶飲開始。恢復_饑餓值_並獲得_加速_效果", - - "item.create.refined_radiance.tooltip": "光輝石", - "item.create.refined_radiance.tooltip.summary": "一種用_光輝_鍛造的化合物材料", - "item.create.refined_radiance.tooltip.condition1": "工作進度", - "item.create.refined_radiance.tooltip.behaviour1": "在未來的更新中會更新更多用途", - - "item.create.shadow_steel.tooltip": "暗影鋼", - "item.create.shadow_steel.tooltip.summary": "一種用_虛空_鍛造的化合物材料", - "item.create.shadow_steel.tooltip.condition1": "工作進度", - "item.create.shadow_steel.tooltip.behaviour1": "在未來的更新中會更新更多用途", - - "item.create.linked_controller.tooltip": "遙控器", - "item.create.linked_controller.tooltip.summary": "提供_六個_連接到對應_無線紅石鏈路頻道_的_遙控按鈕_", - "item.create.linked_controller.tooltip.condition1": "當點擊右鍵時", - "item.create.linked_controller.tooltip.behaviour1": "_切換_模式;遙控器啟動時會接管_移動控制_", - "item.create.linked_controller.tooltip.condition2": "當潛行右鍵時", - "item.create.linked_controller.tooltip.behaviour2": "打開_設定面板_", - "item.create.linked_controller.tooltip.condition3": "當右鍵無線紅石鏈路時", - "item.create.linked_controller.tooltip.behaviour3": "開啟_綁定模式_,按下_六個控制鍵_之一以綁定_頻率_", - "item.create.linked_controller.tooltip.condition4": "當右鍵講台時", - "item.create.linked_controller.tooltip.behaviour4": "把遙控器放到講台上,可以更方便的控制它 (潛行右鍵取回) ", - - "item.create.diving_helmet.tooltip": "潛水頭盔", - "item.create.diving_helmet.tooltip.summary": "和_銅製後背包_一起裝備時可以延長在_水下呼吸_的時間", - "item.create.diving_helmet.tooltip.condition1": "當裝備時", - "item.create.diving_helmet.tooltip.behaviour1": "提昇_水下呼吸效果_,會緩慢的抽取銅製後背包中的_壓縮空氣_", - - "item.create.copper_backtank.tooltip": "銅製後背包", - "item.create.copper_backtank.tooltip.summary": "可裝備的氣罐,用來攜帶壓縮空氣", - "item.create.copper_backtank.tooltip.condition1": "當裝備時", - "item.create.copper_backtank.tooltip.behaviour1": "提供_壓縮空氣_給需要的裝備", - "item.create.copper_backtank.tooltip.condition2": "當放置時,由轉動來補充驅動", - "item.create.copper_backtank.tooltip.behaviour2": "旋轉的速度決定收集_壓縮空氣_的速率", - - "block.create.placard.tooltip": "標示牌", - "block.create.placard.tooltip.summary": "用這個精美的牆板將你的_物品_用黃銅_框起來_。對器械安全!", - "block.create.placard.tooltip.condition1": "手持物品右鍵時", - "block.create.placard.tooltip.behaviour1": "_放入_手持的_物品_。若該物品已經存在,則_發出紅石脈衝_", - "block.create.placard.tooltip.condition2": "當點擊左鍵時", - "block.create.placard.tooltip.behaviour2": "_移除_標示牌當前的_物品_", - - "block.create.flywheel.tooltip": "飛輪", - "block.create.flywheel.tooltip.summary": "用雄偉的黃銅飛輪_裝飾_你的_機械_", - "block.create.flywheel.tooltip.condition1": "以動力驅動時", - "block.create.flywheel.tooltip.behaviour1": "開始轉動", - - "item.create.diving_boots.tooltip": "潛水鞋", - "item.create.diving_boots.tooltip.summary": "一雙_沈重的鞋子_,可以更順暢地穿越海底", - "item.create.diving_boots.tooltip.condition1": "當裝備時", - "item.create.diving_boots.tooltip.behaviour1": "你可以在水下走得更快而且可以跳躍,但是不能游泳。穿著者不會被輸送帶移動", - - "item.create.crafting_blueprint.tooltip": "合成藍圖", - "item.create.crafting_blueprint.tooltip.summary": "可以被放置在牆上、地上和天花板。指定一個合成配方,你可以更快速的合成物品;每一格代表一個合成配方", - "item.create.crafting_blueprint.condition1": "右鍵點擊空格", - "item.create.crafting_blueprint.behaviour1": "打開_合成界面_讓你_指定配方_和要顯示的物品", - "item.create.crafting_blueprint.condition2": "右鍵點擊編輯過的格子", - "item.create.crafting_blueprint.behaviour2": "根據_物品欄_內的物品_使用_這個_配方_合成。_潛行右鍵_可以一次合成_一組_的物品", - - "item.create.minecart_coupling.tooltip": "礦車連軸器", - "item.create.minecart_coupling.tooltip.summary": "將多個_礦車_或運輸結構鏈接在一起,構成雄偉的火車", - "item.create.minecart_coupling.tooltip.condition1": "作用於礦車時", - "item.create.minecart_coupling.tooltip.behaviour1": "將兩個礦車耦合在一起,在移動時將它們保持_恆定的距離_", - - "item.create.experience_nugget.tooltip": "經驗金塊", - "item.create.experience_nugget.tooltip.summary": "_叮!_來自奇妙發明的一點_靈感_", - "item.create.experience_nugget.tooltip.condition1": "使用時", - "item.create.experience_nugget.tooltip.behaviour1": "得到其中包含的_經驗值_", - - "block.create.peculiar_bell.tooltip": "黃銅鐘", - "block.create.peculiar_bell.tooltip.summary": "一個裝飾性的_鐘_,放在_靈魂火_正上方會有意想不到的副作用", - - "block.create.haunted_bell.tooltip": "靈魂鐘", - "block.create.haunted_bell.tooltip.summary": "一個受到地獄亡魂_詛咒的鐘_", - "block.create.haunted_bell.tooltip.condition1": "當拿者或是被敲響時", - "block.create.haunted_bell.tooltip.behaviour1": "標示附近_不夠亮_、會生成_敵對生物_的地方", - - - "_": "->------------------------] Ponder Content [------------------------<-", - - "create.ponder.shared.rpm16": "16 RPM", - "create.ponder.shared.behaviour_modify_wrench": "使用扳手來調整這個動作", - "create.ponder.shared.storage_on_contraption": "與結構相連的儲物空間會自動撿取物品", - "create.ponder.shared.rpm8": "8 RPM", - "create.ponder.shared.rpm32": "32 RPM", - "create.ponder.shared.rpm16_source": "轉速:16 RPM", - "create.ponder.shared.movement_anchors": "有了機殼底盤和強力膠就可以移動大型結構", - "create.ponder.tag.redstone": "邏輯控制裝置", - "create.ponder.tag.redstone.description": "這些裝置會在紅石電路中發揮用處", - "create.ponder.tag.contraption_assembly": "方塊連接物件", - "create.ponder.tag.contraption_assembly.description": "此物件用於連接各個零件以便組成一個成品", - "create.ponder.tag.fluids": "流體控制裝置", - "create.ponder.tag.fluids.description": "這些裝置可傳輸並利用流體", - "create.ponder.tag.decoration": "裝飾", - "create.ponder.tag.decoration.description": "這些零件通常用於裝飾", - "create.ponder.tag.windmill_sails": "風車軸承的帆", - "create.ponder.tag.windmill_sails.description": "建造風車時用於產生動能的帆,每個帆對風車產生的效果都是同等的", - "create.ponder.tag.arm_targets": "機械臂的目標物", - "create.ponder.tag.arm_targets.description": "該裝置可作為機械臂的工作目標", - "create.ponder.tag.kinetic_appliances": "動力器械", - "create.ponder.tag.kinetic_appliances.description": "該部件透過動力運作", - "create.ponder.tag.kinetic_sources": "動力源", - "create.ponder.tag.kinetic_sources.description": "該部件能夠產生動力", - "create.ponder.tag.movement_anchor": "運動錨點", - "create.ponder.tag.movement_anchor.description": "允許建立移動裝置的部件,以各種方式為連接的結構設置動畫", - "create.ponder.tag.kinetic_relays": "動力傳輸方塊", - "create.ponder.tag.kinetic_relays.description": "該部件用於傳輸動力", - "create.ponder.tag.contraption_actor": "特殊行為裝置", - "create.ponder.tag.contraption_actor.description": "裝置在移動裝置時表現出特殊行為的方塊", - "create.ponder.tag.creative": "創造模式", - "create.ponder.tag.creative.description": "該裝置無法在生存模式中獲得", - "create.ponder.tag.display_sources": "顯示鏈路的訊號源", - "create.ponder.tag.display_sources.description": "可發送訊號供顯示鏈路讀取的部件或方塊", - "create.ponder.tag.logistics": "傳輸物品", - "create.ponder.tag.logistics.description": "該裝置用於物品的傳輸", - "create.ponder.tag.display_targets": "顯示鏈路的目標", - "create.ponder.tag.display_targets.description": "可接收顯示鏈路的訊號,並處理或顯示訊息的部件或方塊", - "create.ponder.tag.train_related": "鐵道設備", - "create.ponder.tag.train_related.description": "製造或管理火車裝置的零件", - - "create.ponder.analog_lever.header": "使用可調式拉桿來控制訊號", - "create.ponder.analog_lever.text_1": "可調式拉桿是一種小巧而輕準的紅石能源", - "create.ponder.analog_lever.text_2": "右鍵以增加紅石訊號強度", - "create.ponder.analog_lever.text_3": "潛行右鍵以降低紅石訊號強度", - - "create.ponder.andesite_tunnel.header": "使用安山岩物品隧道", - "create.ponder.andesite_tunnel.text_1": "安山岩物品隧道可以覆蓋在輸送帶上", - "create.ponder.andesite_tunnel.text_2": "當安山岩物品隧道側邊連接到另一條輸送帶時…", - "create.ponder.andesite_tunnel.text_3": "…隧道將會從經過的整組物品中拿出一個丟到另一條輸送帶上", - "create.ponder.andesite_tunnel.text_4": "剩餘物品則按照原路輸出", - - "create.ponder.auto_schedule.header": "車站與火車調度", - "create.ponder.auto_schedule.text_1": "時刻表可以提供司機員目的地", - "create.ponder.auto_schedule.text_2": "紅石比較器會在有火車時收到訊號", - "create.ponder.auto_schedule.text_3": "火車只能從指定的方向進入車站", - "create.ponder.auto_schedule.text_4": "車站也可以自動分配新的時刻表給司機員", - "create.ponder.auto_schedule.text_5": "置於車站上的時刻表會自動複製給當前的火車", - "create.ponder.auto_schedule.text_6": "與手動調度不同,自動調度並不會使司機員攜帶時刻表在身上", - - "create.ponder.basin.header": "在作業盆中處理物品", - "create.ponder.basin.text_1": "作業盆可以放入物品或流體來進行處理", - "create.ponder.basin.text_2": "在每次的處理完成後,作業盆會試著輸出成品到他的側面下方", - "create.ponder.basin.text_3": "當側面下方有一個有效的容器或設備,作業盆側面會出現一個輸出嘴", - "create.ponder.basin.text_4": "有很多的容器或設備可以觸發上述現象", - "create.ponder.basin.text_5": "作業盆輸出的成品會被儲存到該容器或設備內", - "create.ponder.basin.text_6": "如果側面沒有出現輸出嘴,則作業盆內的成品則不會輸出", - "create.ponder.basin.text_7": "這個原理用在產生的成品為下一輪處理的原料時相當有用", - "create.ponder.basin.text_8": "期望的成品將會從作業盆中輸出", - "create.ponder.basin.text_9": "加裝過濾器可防止未被處理的物品輸出", - - "create.ponder.bearing_modes.header": "機械軸承的工作模式", - "create.ponder.bearing_modes.text_1": "當機械軸承停止時,它會控制整個結構停在最近的垂直線上並實體化", - "create.ponder.bearing_modes.text_2": "你可以控制它不要實體化,或是在結構起始位置才實體化", - - "create.ponder.belt_casing.header": "包裹住輸送帶", - "create.ponder.belt_casing.text_1": "安山岩機殼或黃銅機殼可以用來裝飾輸送帶", - "create.ponder.belt_casing.text_2": "使用扳手可以移除機殼", - - "create.ponder.belt_connector.header": "使用輸送帶", - "create.ponder.belt_connector.text_1": "手持輸送帶對兩根傳動軸右鍵以安裝輸送帶", - "create.ponder.belt_connector.text_2": "不小心點到傳動軸的話可以潛行右鍵來取消選取", - "create.ponder.belt_connector.text_3": "輸送帶間只要有空間就能安裝額外的傳動軸", - "create.ponder.belt_connector.text_4": "相同輸送帶接出來的傳動軸轉速及轉向會相同", - "create.ponder.belt_connector.text_5": "使用扳手可以移除已安裝的傳動軸", - "create.ponder.belt_connector.text_6": "輸送帶可以被各種染料染色", - - "create.ponder.belt_directions.header": "輸送帶正確的安裝方向", - "create.ponder.belt_directions.text_1": "輸送帶不可以隨意聯結", - "create.ponder.belt_directions.text_2": "1. 輸送帶可以水平連結", - "create.ponder.belt_directions.text_3": "2. 輸送帶可以對角連結", - "create.ponder.belt_directions.text_4": "3. 輸送帶可以垂直連結", - "create.ponder.belt_directions.text_5": "4. 也可以連結在垂直的傳動軸上", - "create.ponder.belt_directions.text_6": "這些都是可以使用的連接方式,輸送帶可以放置的長度為 2 至 20 格", - - "create.ponder.belt_transport.header": "將輸送帶用於後勤", - "create.ponder.belt_transport.text_1": "被啟動的輸送帶能運送物品及實體", - "create.ponder.belt_transport.text_2": "空手對輸送帶上的物品右鍵即可從輸送帶上取下物品", - - "create.ponder.blaze_burner.header": "餵食烈焰使者動力爐", - "create.ponder.blaze_burner.text_1": "烈焰使者動力爐可以用來加熱作業盆", - "create.ponder.blaze_burner.text_2": "你需要餵食可以燃燒的物品來加熱作業盆", - "create.ponder.blaze_burner.text_3": "餵食熔岩蛋糕可以讓烈焰使者動力爐加熱到另一個更高的境界", - "create.ponder.blaze_burner.text_4": "使用機械手或機械臂來將餵食自動化", - - "create.ponder.brass_funnel.header": "黃銅漏斗", - "create.ponder.brass_funnel.text_1": "安山岩漏斗每次只能傳輸一個物品", - "create.ponder.brass_funnel.text_2": "但黃銅漏斗每次可以傳輸整組物品", - "create.ponder.brass_funnel.text_3": "對漏斗上的過濾格使用滾輪可以調整每次輸出物品的數量", - "create.ponder.brass_funnel.text_4": "手持物品對漏斗上的過濾格右鍵可以限制漏斗只輸出該物品", - - "create.ponder.brass_tunnel.header": "使用黃銅隧道", - "create.ponder.brass_tunnel.text_1": "黃銅隧道必須裝設在輸送帶上", - "create.ponder.brass_tunnel.text_2": "黃銅隧道輸出入口上都有過濾格", - "create.ponder.brass_tunnel.text_3": "在輸入口上的過濾器會阻擋不相符的物品", - "create.ponder.brass_tunnel.text_4": "在輸出口上的過濾器可依種類整理排列物品", - "create.ponder.brass_tunnel.text_5": "如果數種與過濾相符的物品通過隧道,隧道的分配模式將決定如何處理這些物品", - "create.ponder.brass_tunnel.text_6": "在平行相鄰的輸送帶上,相鄰的黃銅隧道將會成為一組", - "create.ponder.brass_tunnel.text_7": "輸入該組內的物品將會採用該組隧道的分配模式輸送", - "create.ponder.brass_tunnel.text_8": "在這個情況下,物品也能被直接輸入到隧道方塊", - - "create.ponder.brass_tunnel_modes.header": "黃銅隧道的分配模式", - "create.ponder.brass_tunnel_modes.text_1": "使用扳手來調整隧道的分配模式", - "create.ponder.brass_tunnel_modes.text_10": "「同步輸入」 是一種黃銅隧道的特殊設定", - "create.ponder.brass_tunnel_modes.text_11": "當同組內的所有隧道都有一個可通過的物品時,所有隧道才可輸出物品", - "create.ponder.brass_tunnel_modes.text_12": "這確保了同組隧道所在的輸送帶都能以同一速率輸出物品", - "create.ponder.brass_tunnel_modes.text_2": "「分流輸出」 此模式會將物品輸出到該組隧道可用的輸出口", - "create.ponder.brass_tunnel_modes.text_3": "如果該組隧道內某個輸出口無法再輸出物品,則該輸出口會被跳過", - "create.ponder.brass_tunnel_modes.text_4": "「強制分流輸出」 模式不會跳過某個無法輸出物品的輸出口,直到該輸出口可以輸出物品", - "create.ponder.brass_tunnel_modes.text_5": "「輪詢輸入」 模式將會保持整組物品完整性,然後在有輸出口可以輸出時才輸入物品", - "create.ponder.brass_tunnel_modes.text_6": "如果該組隧道內某個輸出口無法再輸出物品,則該輸出口會被跳過", - "create.ponder.brass_tunnel_modes.text_7": "「強制輪詢輸入」 模式不會跳過某個無法輸出物品的輸出口,直到該輸出口可以輸出物品", - "create.ponder.brass_tunnel_modes.text_8": "「鄰近優先」 模式會將物品輸出到該組隧道離物品輸入口最近的出口", - "create.ponder.brass_tunnel_modes.text_9": "「隨機輸出」 模式會隨機選擇同組隧道的一個輸出口輸出", - - "create.ponder.cart_assembler.header": "使用礦車裝修站裝修礦車來移動結構", - "create.ponder.cart_assembler.text_1": "礦車裝修站會將所有連接到礦車的結構裝在礦車上", - "create.ponder.cart_assembler.text_2": "如果沒有紅時訊號,它會將礦車結構分解成方塊", - "create.ponder.cart_assembler.text_3": "對礦車結構使用扳手可以將礦車變成物品", - - "create.ponder.cart_assembler_dual.header": "雙礦車結構", - "create.ponder.cart_assembler_dual.text_1": "當兩台礦車在同一礦車結構上", - "create.ponder.cart_assembler_dual.text_2": "任一礦車裝修站收到紅石訊號時,會形成完整的一個礦車結構", - "create.ponder.cart_assembler_dual.text_3": "整個礦車結構會類似於用礦車連結器連接兩個礦車結構", - - "create.ponder.cart_assembler_modes.header": "礦車結構的方向設定", - "create.ponder.cart_assembler_modes.text_1": "礦車結構會隨著礦車方向改變", - "create.ponder.cart_assembler_modes.text_2": "如果在裝修站鎖定其方向,則結構方向不會隨礦車方向改變", - "create.ponder.cart_assembler_modes.text_3": "如果在裝修站鎖定其方向,則結構方向不會隨礦車方向改變", - - "create.ponder.cart_assembler_rails.header": "其他種類的礦車和鐵軌", - "create.ponder.cart_assembler_rails.text_1": "放在普通鐵軌上的礦車裝修站不會影響礦車的動作", - "create.ponder.cart_assembler_rails.text_2": "如果裝修站在沒有紅石訊號的動力鐵軌或控制鐵軌上,則礦車會停下直到鐵軌收到紅石訊號", - "create.ponder.cart_assembler_rails.text_3": "有幾種礦車可以當作錨來使用", - "create.ponder.cart_assembler_rails.text_4": "熔爐礦車會盡可能維持熔煉狀態,並會拿取鄰近儲存結構上的燃料", - - "create.ponder.chain_drive.header": "使用鏈式傳動箱傳輸動力", - "create.ponder.chain_drive.text_1": "同一排上的鏈式傳動箱會互相傳輸動力", - "create.ponder.chain_drive.text_2": "所有傳動軸此時會朝相同方向旋轉", - "create.ponder.chain_drive.text_3": "任一個鏈式傳動箱被旋轉 90 度時所有鏈式傳動箱仍可正常運作", - - "create.ponder.chain_gearshift.header": "使用可調式鏈式變速箱來調整轉速", - "create.ponder.chain_gearshift.text_1": "未被控制的可調式鏈式變速箱與鏈式傳動箱無異", - "create.ponder.chain_gearshift.text_2": "當可調式鏈式變速箱被啟動後,它會把轉速提升兩倍傳至其他鏈式傳動箱", - "create.ponder.chain_gearshift.text_3": "當被啟動的可調式鏈式變速箱並不是動能輸入端,則它會把轉速減半", - "create.ponder.chain_gearshift.text_4": "上述兩種狀況中,其他鏈式傳動箱都會被可調式鏈式變速箱提升兩倍的轉速", - "create.ponder.chain_gearshift.text_5": "利用紅石訊號的強度,轉速倍率可以在 1 至 2 倍之間調整", - "create.ponder.chain_gearshift.text_6": "12 RPM", - - "create.ponder.chute.header": "使用滑槽向下輸送物品", - "create.ponder.chute.text_1": "滑槽可以在兩個垂直的儲物空間中輸送物品", - "create.ponder.chute.text_2": "使用扳手可以讓它產生一個觀景窗", - "create.ponder.chute.text_3": "在滑槽的側面放置另一個滑槽,會產生一個斜狀的滑槽", - - "create.ponder.chute_upward.header": "使用滑槽向上輸送物品", - "create.ponder.chute_upward.text_1": "在滑槽上方或下方使用鼓風機時,物品會根據被向上或向下吹", - "create.ponder.chute_upward.text_2": "裝備工程師護目鏡以觀測物品的傳輸方向", - "create.ponder.chute_upward.text_3": "如滑槽底端被擋住,則物品只能由側邊進行輸出入", - - "create.ponder.clockwork_bearing.header": "使用時鐘軸承來建造時鐘結構", - "create.ponder.clockwork_bearing.text_1": "時鐘軸承會黏住其前方方塊產生一個時針結構", - "create.ponder.clockwork_bearing.text_2": "在輸入動力後,該結構會依照遊戲時間來旋轉", - "create.ponder.clockwork_bearing.text_3": "3:00", - "create.ponder.clockwork_bearing.text_4": "4:00", - "create.ponder.clockwork_bearing.text_5": "對軸承右鍵會使結構啟動或停止", - "create.ponder.clockwork_bearing.text_6": "在時針結構的前方可再增加一組分針結構", - "create.ponder.clockwork_bearing.text_7": "你必須確保時針分針結構間未被使用強力膠之類的相連零件", - "create.ponder.clockwork_bearing.text_8": "分針結構此時將正常運作", - - "create.ponder.clutch.header": "使用離合器控制動力", - "create.ponder.clutch.text_1": "離合器能將動力沿直線傳輸", - "create.ponder.clutch.text_2": "當離合器被啟動,離合器會中斷動力傳輸", - - "create.ponder.cog_speedup.header": "使用大小齒輪來變速", - "create.ponder.cog_speedup.text_1": "大齒輪與小齒輪可以斜向連接", - "create.ponder.cog_speedup.text_2": "大齒輪帶動小齒輪旋轉時,轉速加倍", - "create.ponder.cog_speedup.text_3": "小齒輪帶動大齒輪旋轉時,轉速減半", - - "create.ponder.cogwheel.header": "使用齒輪來傳輸動力", - "create.ponder.cogwheel.text_1": "齒輪會將動力傳輸至臨近的齒輪", - "create.ponder.cogwheel.text_2": "以此方式連接的齒輪,旋轉方向相反", - - "create.ponder.cogwheel_casing.header": "齒輪裝殼", - "create.ponder.cogwheel_casing.text_1": "黃銅或安山岩機殼可用於裝飾齒輪", - "create.ponder.cogwheel_casing.text_2": "裝殼後添加的組件不會與傳動軸相連", - "create.ponder.cogwheel_casing.text_3": "扳手可用於切換連接", - - "create.ponder.creative_fluid_tank.header": "創造流體儲存罐", - "create.ponder.creative_fluid_tank.text_1": "創造流體儲存罐可以提供無限的流體", - "create.ponder.creative_fluid_tank.text_2": "拿著一個流體物品點擊可以設定它", - "create.ponder.creative_fluid_tank.text_3": "現在管線網路可以無限制的從它抽取流體", - "create.ponder.creative_fluid_tank.text_4": "任何被抽進創造流體儲存罐的流體都會消失", - - "create.ponder.creative_motor.header": "使用創造馬達產生動力", - "create.ponder.creative_motor.text_1": "創造馬達不僅能夠手動設定輸出動力,而且體積相當小巧", - "create.ponder.creative_motor.text_2": "對其背後面板滑動滾輪,可以改變馬達的轉速", - - "create.ponder.creative_motor_mojang.header": "Mojang's Enigma", - - "create.ponder.crushing_wheels.header": "使用粉碎輪處理物品", - "create.ponder.crushing_wheels.text_1": "一對粉碎輪,可以有效地進行研磨", - "create.ponder.crushing_wheels.text_2": "它們的輸入軸必須使兩個輪子契合的轉動", - "create.ponder.crushing_wheels.text_3": "扔入或者放入的物品都會被粉碎處理", - "create.ponder.crushing_wheels.text_4": "你也可以使用自動化進行物品的輸入以及撿取", - - "create.ponder.deployer.header": "使用機械手", - "create.ponder.deployer.text_1": "在機械手獲得動力後能夠模仿玩家的各種行為", - "create.ponder.deployer.text_10": "對機械手手部右鍵,即可將手上的物品給它使用", - "create.ponder.deployer.text_11": "物品也可以自動化輸入到機械手內", - "create.ponder.deployer.text_12": "機械手附帶一個過濾格", - "create.ponder.deployer.text_13": "當設定了過濾後,只有當它的手中物品與過濾格相符時,它才會工作", - "create.ponder.deployer.text_14": "只有與過濾格相符的物品才可輸入…", - "create.ponder.deployer.text_15": "…不符的物品可被取出來", - "create.ponder.deployer.text_2": "它只會與它正前方兩格處的位置進行互動", - "create.ponder.deployer.text_3": "放在在它面前的方塊不會阻攔它的工作", - "create.ponder.deployer.text_4": "機械手可以:", - "create.ponder.deployer.text_5": "放置方塊", - "create.ponder.deployer.text_6": "使用物品", - "create.ponder.deployer.text_7": "啟動方塊", - "create.ponder.deployer.text_8": "採收方塊", - "create.ponder.deployer.text_9": "以及攻擊生物", - - "create.ponder.deployer_contraption.header": "在裝置上使用機械手", - "create.ponder.deployer_contraption.text_1": "當機械手在移動的結構上時…", - "create.ponder.deployer_contraption.text_2": "機械手會對每一個經過的方塊使用裝置中任意容器內的物品", - "create.ponder.deployer_contraption.text_3": "可以透過過濾格來指定其從存儲空間中抽取的物品", - - "create.ponder.deployer_modes.header": "機械手的工作模式", - "create.ponder.deployer_modes.text_1": "在設設情況下,機械手模仿玩家的右鍵", - "create.ponder.deployer_modes.text_2": "使用扳手可以將模式調整為模仿玩家的左鍵", - - "create.ponder.deployer_processing.header": "用機械手處理物品", - "create.ponder.deployer_processing.text_1": "拿著適當物品的機械手可以處理下面的物品", - "create.ponder.deployer_processing.text_2": "待處理的物品可以是掉落狀態或是被放在置物台上", - "create.ponder.deployer_processing.text_3": "當物品被放在輸送帶上時…", - "create.ponder.deployer_processing.text_4": "機械手會抓住他並且自動處理", - - "create.ponder.deployer_redstone.header": "使用紅石控制機械手", - "create.ponder.deployer_redstone.text_1": "當機械手收到紅時訊號時會停止工作", - "create.ponder.deployer_redstone.text_2": "在停止工作前,機械手會完成目前手頭上的工作", - "create.ponder.deployer_redstone.text_3": "因此,輸入脈衝訊號可以使其每次只進行一個週期的工作", - - "create.ponder.depot.header": "使用置物台", - "create.ponder.depot.text_1": "置物台可以被當成一個「靜止的」傳送帶原件使用", - "create.ponder.depot.text_2": "右鍵可以手動放置或取下物品", - "create.ponder.depot.text_3": "與傳送帶一樣,它也可以將其內的物品轉送到其他設備中進行加工…", - "create.ponder.depot.text_4": "…同時物品也可以被機械手存取", - - "create.ponder.display_board.header": "使用顯示板", - "create.ponder.display_board.text_1": "顯示板是可選擇性擴充的標誌", - "create.ponder.display_board.text_2": "它們需要動力才能運作", - "create.ponder.display_board.text_3": "可以透過命名牌顯示文字…", - "create.ponder.display_board.text_4": "…或透過顯示鏈路", - "create.ponder.display_board.text_5": "染料可以應用於顯示板的各行", - "create.ponder.display_board.text_6": "空手點擊可以重設", - - "create.ponder.display_link.header": "設置顯示鏈路", - "create.ponder.display_link.text_1": "顯示鏈路用於可視化動態訊息", - "create.ponder.display_link.text_2": "首先,右鍵目標顯示器…", - "create.ponder.display_link.text_3": "…然後將其放到想要讀取的方塊上", - "create.ponder.display_link.text_4": "打開界面,以選擇和配置想發送的內容", - "create.ponder.display_link.text_5": "顯示器將從鏈路接收訊息", - "create.ponder.display_link.text_6": "並非所有方塊都可以作為訊號源", - "create.ponder.display_link.text_7": "每種相容的方塊都提供獨特的訊息", - "create.ponder.display_link.text_8": "顯示鏈路可以在多種不同的顯示器上運作", - - "create.ponder.display_link_redstone.header": "以紅石控制", - "create.ponder.display_link_redstone.text_1": "接收紅石訊號時,顯示鏈路將停止更新訊息", - "create.ponder.display_link_redstone.text_2": "紅石訊號一旦消失,計時器會重置並立即發送訊息", - "create.ponder.display_link_redstone.text_3": "從訊號源發出的紅石訊號不會造成影響", - - "create.ponder.empty_blaze_burner.header": "使用空的烈焰使者動力爐", - "create.ponder.empty_blaze_burner.text_1": "手持空的烈焰使者動力爐右鍵烈焰使者來抓取烈焰使者", - "create.ponder.empty_blaze_burner.text_2": "或者,也可以透過右鍵烈焰使者刷怪籠來填充啟動烈焰使者動力爐", - "create.ponder.empty_blaze_burner.text_3": "這樣,你便有了一個可供部分機器加工的熱源", - "create.ponder.empty_blaze_burner.text_4": "如果是為了美觀,空的烈焰使者動力爐也可以被打火石點燃", - "create.ponder.empty_blaze_burner.text_5": "可以放入靈魂物品將火焰轉化成靈魂火", - "create.ponder.empty_blaze_burner.text_6": "但是,這樣的熱源不足以給機器加工提供足夠的熱量", - - "create.ponder.encased_fluid_pipe.header": "流體管道箱", - "create.ponder.encased_fluid_pipe.text_1": "銅製機殼可以裝飾流體管道", - "create.ponder.encased_fluid_pipe.text_2": "除了遮蔽流體管道以外,流體管道箱並不會改變管道的連接狀態", - "create.ponder.encased_fluid_pipe.text_3": "流體管道箱不會因旁邊新增或移除管道而產生反應", - - "create.ponder.fan_direction.header": "鼓風機的氣流", - "create.ponder.fan_direction.text_1": "鼓風機藉由動力製造氣流", - "create.ponder.fan_direction.text_2": "流速以及方向由輸入軸的強弱以及方向而定", - - "create.ponder.fan_processing.header": "使用鼓風機加工物品", - "create.ponder.fan_processing.text_1": "當氣流吹過熔岩時,氣流會被加熱", - "create.ponder.fan_processing.text_2": "熱氣流中的物品會被冶煉", - "create.ponder.fan_processing.text_3": "但在氣流中的食物會被直接燒成灰", - "create.ponder.fan_processing.text_4": "而想要烹飪食物,必須要透過吹過火焰的氣流來煙燻食物", - "create.ponder.fan_processing.text_5": "當氣流吹過水後,便可用於洗滌物品", - "create.ponder.fan_processing.text_6": "這種加工方法可以做到不少有趣的事情", - "create.ponder.fan_processing.text_7": "鼓風機的轉速對加工的速度沒有影響,只影響氣流的吹拂距離", - "create.ponder.fan_processing.text_8": "而那些放置在置物台或者傳送帶上的物品,鼓風機也是可以處理的", - - "create.ponder.fluid_pipe_flow.header": "始用銅製管道來移動流體", - "create.ponder.fluid_pipe_flow.text_1": "流體管可以連接兩個或更多的流體來源與目標", - "create.ponder.fluid_pipe_flow.text_2": "使用扳手可以在一段直管線上開窗戶", - "create.ponder.fluid_pipe_flow.text_3": "有窗戶的管線側面不會連接到其他管線", - "create.ponder.fluid_pipe_flow.text_4": "機械幫浦可以讓管線運輸流體", - "create.ponder.fluid_pipe_flow.text_5": "一開始不會有流體被抽出來", - "create.ponder.fluid_pipe_flow.text_6": "直到兩端被連接起來,才會有流體被抽過去", - "create.ponder.fluid_pipe_flow.text_7": "因此,管線裡不會「物理上的」含有流體", - - "create.ponder.fluid_pipe_interaction.header": "抽取並填滿流體罐", - "create.ponder.fluid_pipe_interaction.text_1": "管線網路的終端可以和很多東西互動", - "create.ponder.fluid_pipe_interaction.text_2": "任何有意體容量的方塊都可以被抽取和填滿", - "create.ponder.fluid_pipe_interaction.text_3": "在開放端口前的流體源方塊可以被抽走", - "create.ponder.fluid_pipe_interaction.text_4": "當流體被排放出來時會產生新的流體源方塊", - "create.ponder.fluid_pipe_interaction.text_5": "管線也可以直接從其他方塊中抽取流體", - - "create.ponder.fluid_tank_sizes.header": "流體罐的尺寸", - "create.ponder.fluid_tank_sizes.text_1": "可以組合流體罐以增加總容量", - "create.ponder.fluid_tank_sizes.text_2": "底部最多可以是 3x3 的正方形…", - "create.ponder.fluid_tank_sizes.text_3": "…最多可以堆疊 30 層", - "create.ponder.fluid_tank_sizes.text_4": "扳手可以用來開關窗戶", - - "create.ponder.fluid_tank_storage.header": "在流體罐中儲存流體", - "create.ponder.fluid_tank_storage.text_1": "流體罐中可儲存大量的流體", - "create.ponder.fluid_tank_storage.text_2": "管線體網路可以從任何一邊抽取或是輸入流體", - "create.ponder.fluid_tank_storage.text_3": "紅石比較器可以輸出流體容量", - "create.ponder.fluid_tank_storage.text_4": "但是,在生存模式你不能直接存入、取出流體", - "create.ponder.fluid_tank_storage.text_5": "你可以用作業盆、分液池或流體灌注器和管線網路互動", - - "create.ponder.funnel_compat.header": "漏斗的相容性", - "create.ponder.funnel_compat.text_1": "漏斗可以與一些其他組件互動", - "create.ponder.funnel_compat.text_2": "機械圓鋸機", - "create.ponder.funnel_compat.text_3": "置物台", - "create.ponder.funnel_compat.text_4": "分液池", - - "create.ponder.funnel_direction.header": "物流方向", - "create.ponder.funnel_direction.text_1": "直接放置時,漏斗會將物品從容器中取出", - "create.ponder.funnel_direction.text_2": "潛行放置時,漏斗會將物品置入容器中", - "create.ponder.funnel_direction.text_3": "使用扳手可以改變漏斗的存取模式", - "create.ponder.funnel_direction.text_4": "對大多數朝向放置的漏斗都具有此特性", - "create.ponder.funnel_direction.text_5": "在傳送帶末端放置的漏斗會根據傳送帶的傳動方向存/取物品", - - "create.ponder.funnel_intro.header": "使用漏斗", - "create.ponder.funnel_intro.text_1": "用漏斗來存取物品欄內的物品,可謂又快又好", - - "create.ponder.funnel_redstone.header": "紅石訊號控制", - "create.ponder.funnel_redstone.text_1": "紅石訊號會使漏斗停止工作", - - "create.ponder.funnel_transfer.header": "直接運輸", - "create.ponder.funnel_transfer.text_1": "漏斗無法將物品傳輸到非開放式的物品欄中", - "create.ponder.funnel_transfer.text_2": "滑槽和智慧滑槽更適用於這樣的場景", - "create.ponder.funnel_transfer.text_3": "水平傳輸也是如此,也許傳送帶更方便快捷", - - "create.ponder.gantry_carriage.header": "使用起重機", - "create.ponder.gantry_carriage.text_1": "起重機可以被放置在起重機導軌上,並且可以沿著起重機導軌運動", - "create.ponder.gantry_carriage.text_2": "起重機可以移動其黏附的方塊", - - "create.ponder.gantry_cascaded.header": "串聯起重機", - "create.ponder.gantry_cascaded.text_1": "無需強力膠,起重機便可與導軌相連", - "create.ponder.gantry_cascaded.text_2": "即使是在移動的起重機導軌上也是如此", - "create.ponder.gantry_cascaded.text_3": "因此,起重機系統可以串聯起來,以在多個軸上運動", - - "create.ponder.gantry_direction.header": "起重機移動方向", - "create.ponder.gantry_direction.text_1": "導軌可以以相反的方向運作", - "create.ponder.gantry_direction.text_2": "起重機的移動方向取決於導軌的朝向", - "create.ponder.gantry_direction.text_3": "…以及導軌的轉向", - "create.ponder.gantry_direction.text_4": "規則同樣適用於起重機的動力傳輸", - - "create.ponder.gantry_redstone.header": "起重機的動力傳輸", - "create.ponder.gantry_redstone.text_1": "以紅石訊號充能導軌,可以讓起重機停止移動", - "create.ponder.gantry_redstone.text_2": "作為替代,導軌上的動力會傳輸到起重機的輸出軸上", - - "create.ponder.gantry_shaft.header": "使用起重機導軌", - "create.ponder.gantry_shaft.text_1": "起重機導軌組成了起重機結構的基礎,與其相接的起重機可以沿著杆進行移動", - "create.ponder.gantry_shaft.text_2": "起重機結構可以移動與其相接的方塊", - - "create.ponder.gearbox.header": "使用十字齒輪箱傳輸動力", - "create.ponder.gearbox.text_1": "更改旋轉軸,很容易使得整個旋轉體系變得臃腫不堪", - "create.ponder.gearbox.text_2": "十字齒輪箱則是替代方案,它的體積更為小巧緊", - "create.ponder.gearbox.text_3": "側邊連接的傳動桿,旋轉方向與輸入端一致", - "create.ponder.gearbox.text_4": "直線連接的傳動桿,旋轉方向會被反轉", - - "create.ponder.gearshift.header": "使用反轉齒輪箱控制動力", - "create.ponder.gearshift.text_1": "反轉齒輪箱可以直線傳輸旋轉", - "create.ponder.gearshift.text_2": "輸入紅石訊號後,輸出端的旋轉方向會被反轉", - - "create.ponder.hand_crank.header": "使用手搖把手產生動力", - "create.ponder.hand_crank.text_1": "玩家可以使用手搖把手來手動產生動力", - "create.ponder.hand_crank.text_2": "按住右鍵可以逆時針旋轉它", - "create.ponder.hand_crank.text_3": "它產生的轉速相對較高", - "create.ponder.hand_crank.text_4": "潛行長按右鍵可以順時針旋轉它", - - "create.ponder.hose_pulley.header": "使用軟管滑輪抽取、填滿流體", - "create.ponder.hose_pulley.text_1": "軟管滑輪可以用來抽取、填滿大量的流體", - "create.ponder.hose_pulley.text_2": "你可以透過輸入轉動來控制軟管的高度", - "create.ponder.hose_pulley.text_3": "反轉時可以收回軟管", - "create.ponder.hose_pulley.text_4": "另一邊可以連接管線", - "create.ponder.hose_pulley.text_5": "相連的管線網路可以提供流體…", - "create.ponder.hose_pulley.text_6": "…或是從池子裡抽取流體", - "create.ponder.hose_pulley.text_7": "抽取或填滿的速度取決於管線系統的吞吐量", - - "create.ponder.hose_pulley_infinite.header": "被動填充和排放大量流體", - "create.ponder.hose_pulley_infinite.text_1": "將軟管滑輪接觸到足夠大的海洋中時…", - "create.ponder.hose_pulley_infinite.text_2": "海洋會被視為無限流體源", - "create.ponder.hose_pulley_infinite.text_3": "管線網路可以無限的抽取、排放流體到海洋中而不影響海洋", - - "create.ponder.hose_pulley_level.header": "軟管滑輪抽取、填滿水平面", - "create.ponder.hose_pulley_level.text_1": "完全縮回時,軟管滑輪無法操作", - "create.ponder.hose_pulley_level.text_2": "抽取工作將由上而下進行", - "create.ponder.hose_pulley_level.text_3": "水平面將停在軟管末端的正下方", - "create.ponder.hose_pulley_level.text_4": "而填充工作將由下而上進行將由上而下進行", - "create.ponder.hose_pulley_level.text_5": "水平面不會超過軟管末端", - - "create.ponder.item_drain.header": "使用分液池清空流體容器", - "create.ponder.item_drain.text_1": "分液池可以從流體容器中清空抽取流體", - "create.ponder.item_drain.text_2": "點擊右鍵可以把你手上的流體倒進去", - "create.ponder.item_drain.text_3": "當從旁邊輸入物品…", - "create.ponder.item_drain.text_4": "…他會從上方滑過,並清空裡面的流體", - "create.ponder.item_drain.text_5": "現在流體網路可以抽取分液池中的流體了", - - "create.ponder.item_vault_sizes.header": "倉儲的尺寸", - "create.ponder.item_vault_sizes.text_1": "倉儲可以合併,以增加容量", - "create.ponder.item_vault_sizes.text_2": "它們的直徑可達 3 個方塊寬…", - "create.ponder.item_vault_sizes.text_3": "…而長度可以增長到直徑的 3 倍", - - "create.ponder.item_vault_storage.header": "儲存物品至倉儲", - "create.ponder.item_vault_storage.text_1": "倉儲可用於存儲大量物品", - "create.ponder.item_vault_storage.text_2": "但是,不能手動存放或提取內容物", - "create.ponder.item_vault_storage.text_3": "任何用於物品傳輸的部件都可以嵌入…", - "create.ponder.item_vault_storage.text_4": "…並從該容器中提取內容物", - - "create.ponder.large_cogwheel.header": "使用大齒輪傳輸動力", - "create.ponder.large_cogwheel.text_1": "大齒輪可以以特定的角度相互連接", - "create.ponder.large_cogwheel.text_2": "可以利用大齒輪變更旋轉軸向", - - "create.ponder.linear_chassis_attachment.header": "使用機殼底盤黏合方塊", - "create.ponder.linear_chassis_attachment.text_1": "它的開放面可以變為黏性面", - "create.ponder.linear_chassis_attachment.text_2": "再度點擊黏性面,可以將它的相反面也變得具有黏性", - "create.ponder.linear_chassis_attachment.text_3": "空手潛行右鍵可以移除此面的黏性物", - "create.ponder.linear_chassis_attachment.text_4": "黏性面可以將此面前方的一長條方塊黏住", - "create.ponder.linear_chassis_attachment.text_5": "使用扳手可以精確控制底盤的影響範圍", - "create.ponder.linear_chassis_attachment.text_6": "按住 Ctrl 滑動滾輪,你可以一次性調節所有底盤的影響範圍", - "create.ponder.linear_chassis_attachment.text_7": "若想讓底盤的其他面也能黏方塊,你需要用到強力膠", - "create.ponder.linear_chassis_attachment.text_8": "利用這些機制,任何形狀的機制都可以像裝置那樣移動", - - "create.ponder.linear_chassis_group.header": "成組移動機殼底盤", - "create.ponder.linear_chassis_group.text_1": "相鄰的機殼底盤可以相互連接在一起", - "create.ponder.linear_chassis_group.text_2": "其中的一個底盤若被移動,其餘的底盤也會跟著移動", - "create.ponder.linear_chassis_group.text_3": "不同種類的底盤,或者是朝向不一致的底盤,將不會相連", - - "create.ponder.mechanical_arm.header": "設置機械臂", - "create.ponder.mechanical_arm.text_1": "你得在放置機械臂之前就設定好它的輸入以及輸出端", - "create.ponder.mechanical_arm.text_2": "手持機械臂右鍵某個存儲空間,可以將其指定為目標", - "create.ponder.mechanical_arm.text_3": "再度右鍵可以將其在輸入端 (藍色) 以及輸出端 (橙色) 之間切換", - "create.ponder.mechanical_arm.text_4": "左鍵組件可以移除選擇", - "create.ponder.mechanical_arm.text_5": "將機械臂放下來後,它會將此前選擇的方塊作為目標", - "create.ponder.mechanical_arm.text_6": "在有效範圍內,機械臂可以有任意數量的輸出以及輸入端", - "create.ponder.mechanical_arm.text_7": "然而,並不是所有的存儲空間可以被直接互動", - "create.ponder.mechanical_arm.text_8": "在此情況下,漏斗和置物台可以解決此問題", - - "create.ponder.mechanical_arm_filtering.header": "過濾機械臂的輸出端", - "create.ponder.mechanical_arm_filtering.text_1": "輸入", - "create.ponder.mechanical_arm_filtering.text_2": "輸出", - "create.ponder.mechanical_arm_filtering.text_3": "有時,你會想著利用某種過濾限煞車力臂的目標", - "create.ponder.mechanical_arm_filtering.text_4": "機械臂自身並不提供任何過濾選項", - "create.ponder.mechanical_arm_filtering.text_5": "然而,若將黃銅漏斗作為目標,則漏斗的過濾槽則可以應用至機械臂上", - "create.ponder.mechanical_arm_filtering.text_6": "機械臂足夠聰明,它不會去拿取那些它無法分配的物品", - - "create.ponder.mechanical_arm_modes.header": "機械臂的分配模式", - "create.ponder.mechanical_arm_modes.text_1": "輸入", - "create.ponder.mechanical_arm_modes.text_2": "輸出", - "create.ponder.mechanical_arm_modes.text_3": "若機械臂必須在數個有效的輸出端之間作出選擇…", - "create.ponder.mechanical_arm_modes.text_4": "…它會依照自己的設定選擇特定的行為", - "create.ponder.mechanical_arm_modes.text_5": "手持扳手對其滑動滾輪,可以改變其設定", - "create.ponder.mechanical_arm_modes.text_6": "輪詢調度模式很好理解,即循環輸出至所有有效的輸出端", - "create.ponder.mechanical_arm_modes.text_7": "如果某個輸出端無法容納更多物品,則它會被跳過", - "create.ponder.mechanical_arm_modes.text_8": "強制輪詢調度不會跳過任何輸出端,機械臂會一直等待,直到輸出端有空位容納物品輸入", - "create.ponder.mechanical_arm_modes.text_9": "最近優先模式會使得機械臂先將物品輸出至更早被選擇的輸出端", - - "create.ponder.mechanical_arm_redstone.header": "利用紅石訊號控制機械臂", - "create.ponder.mechanical_arm_redstone.text_1": "輸入紅石訊號後,機械臂會停止工作", - "create.ponder.mechanical_arm_redstone.text_2": "在停止工作前,它會完成目前正在進行的工作週期", - "create.ponder.mechanical_arm_redstone.text_3": "因此,輸入單次負紅石脈衝可以精確控制機械臂,使其每次只進行單個週期的工作", - - "create.ponder.mechanical_bearing.header": "使用機械軸承移動結構", - "create.ponder.mechanical_bearing.text_1": "機械軸承會與其前方的方塊黏合在一起", - "create.ponder.mechanical_bearing.text_2": "接收到動力後,它會將這一黏合結構組裝為旋轉裝置", - - "create.ponder.mechanical_crafter.header": "設置機械合成器", - "create.ponder.mechanical_crafter.text_1": "機械合成器陣列可用於自動化任何合成配方的製作", - "create.ponder.mechanical_crafter.text_2": "使用扳手可以調控合成器的合成通路", - "create.ponder.mechanical_crafter.text_3": "所有的合成通路必須匯集到任意一側的一個出口,整套合成器方可算是設置正確", - "create.ponder.mechanical_crafter.text_4": "輸出產物會被放入位於出口的存儲空間中", - "create.ponder.mechanical_crafter.text_5": "機械合成器的運轉需要動力的供應", - "create.ponder.mechanical_crafter.text_6": "右鍵合成器正面,可以手動放入物品", - "create.ponder.mechanical_crafter.text_7": "一旦合成通路上的所有合成槽位都有了物品,合成就會開始", - "create.ponder.mechanical_crafter.text_8": "而對於那些沒有完全占滿所有合成器槽位的配方,你可以輸入紅石訊號強制啟動合成", - - "create.ponder.mechanical_crafter_connect.header": "為合成器連接物品欄", - "create.ponder.mechanical_crafter_connect.text_1": "合成器可以自動接受向其輸入的物品", - "create.ponder.mechanical_crafter_connect.text_2": "對其背面使用扳手,可以連接合成器", - "create.ponder.mechanical_crafter_connect.text_3": "所有相連的合成器可以訪問同一個位置的輸入", - - "create.ponder.mechanical_crafter_covers.header": "蓋住機械合成器的合成槽", - "create.ponder.mechanical_crafter_covers.text_1": "有些配方需要額外的合成器,來補足合成通路上的間隙", - "create.ponder.mechanical_crafter_covers.text_2": "使用合成槽蓋板,合成器會在合成進行時的行為就如同一個空的合成槽位", - "create.ponder.mechanical_crafter_covers.text_3": "被蓋住的合成器並不會阻斷共享輸入端的影響", - - "create.ponder.mechanical_drill.header": "使用機械鑽頭破壞方塊", - "create.ponder.mechanical_drill.text_1": "當向其輸入動力後,機械鑽頭會破壞它面前的方塊", - "create.ponder.mechanical_drill.text_2": "它的挖掘速度取決於輸入軸的轉速", - - "create.ponder.mechanical_drill_contraption.header": "在裝置中使用機械鑽頭", - "create.ponder.mechanical_drill_contraption.text_1": "在運動裝置中使用機械鑽頭時…", - "create.ponder.mechanical_drill_contraption.text_2": "…它會破壞掉它撞上的方塊", - - "create.ponder.mechanical_harvester.header": "在裝置中使用機械收割機", - "create.ponder.mechanical_harvester.text_1": "在運動裝置中使用機械收割機時…", - "create.ponder.mechanical_harvester.text_2": "它會採收其路徑上的作物,並重設這些作物的生長進度", - - "create.ponder.mechanical_mixer.header": "使用機械攪拌器處理物品", - "create.ponder.mechanical_mixer.text_1": "使用攪拌器和工作盆,你可以自動化某些合成配方", - "create.ponder.mechanical_mixer.text_2": "有效配方包括各種無序合成配方,以及一些額外的配方", - "create.ponder.mechanical_mixer.text_3": "一些配方可能需要使用烈焰使者動力爐提供熱量", - "create.ponder.mechanical_mixer.text_4": "過濾槽可用於解決兩個配方相互衝突的情況", - - "create.ponder.mechanical_piston.header": "使用機械活塞移動結構", - "create.ponder.mechanical_piston.text_1": "機械活塞可以移動它前方的方塊", - "create.ponder.mechanical_piston.text_2": "移動速度和方向取決於輸入軸", - "create.ponder.mechanical_piston.text_3": "黏性機械活塞可以將相接的方塊拉回來", - - "create.ponder.mechanical_piston_modes.header": "機械活塞的移動模式", - "create.ponder.mechanical_piston_modes.text_1": "一旦活塞停下,被移動的結構就會回退到方塊狀態", - "create.ponder.mechanical_piston_modes.text_2": "你也可以將其設定為從不方塊化,或者只在起始位置方塊化", - - "create.ponder.mechanical_plough.header": "在裝置中使用機械犁", - "create.ponder.mechanical_plough.text_1": "在運動裝置中使用機械犁時…", - "create.ponder.mechanical_plough.text_2": "…它會破壞掉那些不具有固體碰撞箱的方塊", - "create.ponder.mechanical_plough.text_3": "此外,機械犁可以耕地", - "create.ponder.mechanical_plough.text_4": "…它也可以在不傷害實體的情況下推動它們", - - "create.ponder.mechanical_press.header": "使用機械鍛壓機處理物品", - "create.ponder.mechanical_press.text_1": "機械鍛壓機可以處理位於其下方的物品", - "create.ponder.mechanical_press.text_2": "在其下方丟入物品,或者將物品放在置物台上,都算作有效的物品輸入", - "create.ponder.mechanical_press.text_3": "若物品被輸入時正位於傳送帶上…", - "create.ponder.mechanical_press.text_4": "輥軋機會使物品停下,然後自動處理這一物品", - - "create.ponder.mechanical_press_compacting.header": "使用機械鍛壓機壓縮物品", - "create.ponder.mechanical_press_compacting.text_1": "對放置於工作盆內的物品進行輥軋,可以將這些物品壓縮在一起", - "create.ponder.mechanical_press_compacting.text_2": "壓縮意指任何同種物品填滿了 2x2 或者 3x3 網格的配方,以及一些額外的配方", - "create.ponder.mechanical_press_compacting.text_3": "一些配方可能需要烈焰使者動力爐提供熱量", - "create.ponder.mechanical_press_compacting.text_4": "過濾槽可用於解決兩個配方相互衝突的情況", - - "create.ponder.mechanical_pump_flow.header": "使用機械幫浦抽運送流體", - "create.ponder.mechanical_pump_flow.text_1": "機械幫浦為與其連接的管線提供動力", - "create.ponder.mechanical_pump_flow.text_2": "轉動時,箭頭指向流體的方向", - "create.ponder.mechanical_pump_flow.text_3": "在他後面的網路現在可以抽取流體…", - "create.ponder.mechanical_pump_flow.text_4": "…當前面的網路向外傳輸時", - "create.ponder.mechanical_pump_flow.text_5": "反轉輸入的動力可以反轉流體的方向", - "create.ponder.mechanical_pump_flow.text_6": "扳手可以手動調整方向", - - "create.ponder.mechanical_pump_speed.header": "機械幫浦的吞吐量", - "create.ponder.mechanical_pump_speed.text_1": "無論轉速如何,機械幫浦都只能影響相連的 16 個方塊以內的管線", - "create.ponder.mechanical_pump_speed.text_2": "加快旋轉速度會改變液動傳播的速度…", - "create.ponder.mechanical_pump_speed.text_3": "…以及流體轉移的速度", - "create.ponder.mechanical_pump_speed.text_4": "在同一個管線網路中機械幫浦可以結合他們的吞吐量", - "create.ponder.mechanical_pump_speed.text_5": "改變它們的方向可以對齊它們的流動方向", - - "create.ponder.mechanical_saw_breaker.header": "使用機械圓鋸機伐木", - "create.ponder.mechanical_saw_breaker.text_1": "向其輸入動力後,機械圓鋸機可以直接砍伐掉它面前的樹木", - "create.ponder.mechanical_saw_breaker.text_2": "想要一次性砍掉整棵樹,鋸子必須破壞掉樹與地面連接的最後一個方塊", - - "create.ponder.mechanical_saw_contraption.header": "在裝置中使用機械圓鋸機", - "create.ponder.mechanical_saw_contraption.text_1": "若在運動裝置中使用機械圓鋸機…", - "create.ponder.mechanical_saw_contraption.text_2": "…它會將撞到它的樹木破壞掉", - - "create.ponder.mechanical_saw_processing.header": "使用機械圓鋸機處理物品", - "create.ponder.mechanical_saw_processing.text_1": "面朝上方的機械圓鋸機可以加工各種物品", - "create.ponder.mechanical_saw_processing.text_2": "處理後的物品總是逆著機械圓鋸機的轉向移動", - "create.ponder.mechanical_saw_processing.text_3": "機械圓鋸機可以配合輸送帶運駔", - "create.ponder.mechanical_saw_processing.text_4": "當原料有多種可產出的產品時,過濾槽可以指定產品的種類", - "create.ponder.mechanical_saw_processing.text_5": "若沒有使用過濾槽,機械圓鋸機循環的生產可產出的產品", - - "create.ponder.millstone.header": "使用石磨處理物品", - "create.ponder.millstone.text_1": "石磨會對輸入的物品進行磨製", - "create.ponder.millstone.text_2": "在其側邊使用齒輪與其相耦合,方可為其輸入動力", - "create.ponder.millstone.text_3": "頂部可以丟入或者塞入物品", - "create.ponder.millstone.text_4": "一段時間過後,右鍵石磨可以拿出其中的產物", - "create.ponder.millstone.text_5": "產物的提取也是可以自動化的", - - "create.ponder.nixie_tube.header": "使用真空管顯示器", - "create.ponder.nixie_tube.text_1": "輸入紅石訊號後,真空管顯示器會顯示出紅石訊號的強度", - "create.ponder.nixie_tube.text_2": "使用命名牌在鐵砧上為其命名,可以自訂它的顯示文字", - "create.ponder.nixie_tube.text_3": "使用染料右鍵點擊可以上色", - - "create.ponder.piston_pole.header": "活塞延長杆", - "create.ponder.piston_pole.text_1": "若無相接的延長杆,機械活塞無法移動其他方塊", - "create.ponder.piston_pole.text_2": "在其背面安裝的延長杆長度,決定了活塞的推動範圍", - - "create.ponder.portable_fluid_interface.header": "移動式流體口", - "create.ponder.portable_fluid_interface.text_1": "任何管道線都無法與移動裝置上的流體罐連接", - "create.ponder.portable_fluid_interface.text_2": "該元件可以與流體罐相互作用,而無需停止裝置", - "create.ponder.portable_fluid_interface.text_3": "放置第二個,中間間隔 1 或 2 個方塊", - "create.ponder.portable_fluid_interface.text_4": "每當它們擦身而過時,它們就會建立聯繫", - "create.ponder.portable_fluid_interface.text_5": "啟用時,移動式流體口將代表裝置上的「所有」水箱", - "create.ponder.portable_fluid_interface.text_6": "現在可以輸入流體…", - "create.ponder.portable_fluid_interface.text_7": "…或從裝置中抽取", - "create.ponder.portable_fluid_interface.text_8": "一段時間沒有流體交換後,裝置將繼續前進", - - "create.ponder.portable_storage_interface.header": "裝置存儲交換", - "create.ponder.portable_storage_interface.text_1": "玩家無法與運動裝置內的存儲空間進行互動", - "create.ponder.portable_storage_interface.text_2": "這一組件可以在不停止裝置的情況下與裝置內的存儲空間進行互動", - "create.ponder.portable_storage_interface.text_3": "放置第二個介面時,記得要與裝置介面相隔 1 格或者 2 格的距離", - "create.ponder.portable_storage_interface.text_4": "當它們彼此經過時,它們會連接在一起", - "create.ponder.portable_storage_interface.text_5": "連接狀態下,固定側介面便會作為整個裝置的存儲空間代理", - "create.ponder.portable_storage_interface.text_6": "物品會被輸入到裝置內…", - "create.ponder.portable_storage_interface.text_7": "…或是從裝置中提取出來", - "create.ponder.portable_storage_interface.text_8": "物品交換完畢後,裝置仍然會停留在原地一小會,然後才會繼續前行", - - "create.ponder.portable_storage_interface_redstone.header": "紅石控制", - "create.ponder.portable_storage_interface_redstone.text_1": "輸入紅石訊號可以阻止固定側介面的連接行為", - - "create.ponder.powered_latch.header": "使用閂鎖器控制訊號", - "create.ponder.powered_latch.text_1": "閂鎖器是一種可以用紅石訊號控制的拉杆", - "create.ponder.powered_latch.text_2": "後方輸入的訊號會將其設為開啟狀態", - "create.ponder.powered_latch.text_3": "側邊輸入的訊號會將其設為關閉狀態", - "create.ponder.powered_latch.text_4": "你也可以手動切換其狀態", - - "create.ponder.powered_toggle_latch.header": "使用T型正反器控制訊號", - "create.ponder.powered_toggle_latch.text_1": "T型正反器是一種可以用紅石訊號控制的拉杆", - "create.ponder.powered_toggle_latch.text_2": "後方訊號輸入可以改變它的狀態", - "create.ponder.powered_toggle_latch.text_3": "…開啟或者是關閉", - "create.ponder.powered_toggle_latch.text_4": "你也可以手動切換其狀態", - - "create.ponder.pulse_extender.header": "使用脈衝延長器控制訊號", - "create.ponder.pulse_extender.text_1": "脈衝延長器可以延長通過的訊號", - "create.ponder.pulse_extender.text_2": "它們會在短暫延遲後被開啟…", - "create.ponder.pulse_extender.text_3": "…並於設定的延遲過後關閉", - "create.ponder.pulse_extender.text_4": "使用滑鼠滾輪可以設定延遲", - "create.ponder.pulse_extender.text_5": "延遲最長可達 30 分鐘", - - "create.ponder.pulse_repeater.header": "使用脈衝中繼器控制訊號", - "create.ponder.pulse_repeater.text_1": "脈衝中繼器會在延遲後發出一個短脈衝", - "create.ponder.pulse_repeater.text_2": "使用滑鼠滾輪可以設定延遲", - "create.ponder.pulse_repeater.text_3": "延遲最長可達 30 分鐘", - - "create.ponder.radial_chassis.header": "使用旋轉底盤黏著方塊", - "create.ponder.radial_chassis.text_1": "同一行上的旋轉底盤會相互連接在一起", - "create.ponder.radial_chassis.text_2": "當其中的一個底盤被裝置帶動時,其餘的底盤也會被帶動", - "create.ponder.radial_chassis.text_3": "底盤的側邊可以變為黏性面", - "create.ponder.radial_chassis.text_4": "再度點擊黏性面,可以讓其所有面都變得帶黏性", - "create.ponder.radial_chassis.text_5": "空手潛行右鍵可以移除其上的黏性物", - "create.ponder.radial_chassis.text_6": "若有物品與底盤的黏性面相接觸…", - "create.ponder.radial_chassis.text_7": "…底盤便會與同層且位於半徑內的所有可及方塊黏著在一起", - "create.ponder.radial_chassis.text_8": "使用扳手可以精確指定底盤的影響範圍", - "create.ponder.radial_chassis.text_9": "黏性面一側的不可及方塊不會被黏著", - - "create.ponder.redstone_contact.header": "接觸式偵測器", - "create.ponder.redstone_contact.text_1": "當兩個接觸式偵測器面對面時,它們會發出紅石訊號", - "create.ponder.redstone_contact.text_2": "若其中一方位於運動裝置上,它們仍正常生效", - - "create.ponder.redstone_link.header": "使用無線紅石鏈路", - "create.ponder.redstone_link.text_1": "無線紅石鏈路可以無線傳輸紅石訊號", - "create.ponder.redstone_link.text_2": "潛行右鍵可以改變其接收模式", - "create.ponder.redstone_link.text_3": "手持扳手右鍵也可以", - "create.ponder.redstone_link.text_4": "接收端會發出由傳輸端發來的訊號,有效距離為 128 格", - "create.ponder.redstone_link.text_5": "在它們所帶的槽位中放上物品,可以為它們指定頻道", - "create.ponder.redstone_link.text_6": "只有頻道相互匹配的機方可互通", - - "create.ponder.rope_pulley.header": "使用繩索滑輪移動結構", - "create.ponder.rope_pulley.text_1": "繩索滑輪在輸入動力時可以垂直移動方塊結構", - "create.ponder.rope_pulley.text_2": "移動的方向及速度取決於輸入軸", - - "create.ponder.rope_pulley_attachment.header": "繩索滑輪與裝置一同運動", - "create.ponder.rope_pulley_attachment.text_1": "當繩索滑輪本身在裝置中被帶動時…", - "create.ponder.rope_pulley_attachment.text_2": "…它附著在滑輪上的結構會被滑輪拉著一同移動", - "create.ponder.rope_pulley_attachment.text_3": "注意,只有繩索滑輪停止工作時才能被移動", - - "create.ponder.rope_pulley_modes.header": "繩索滑輪的運動模式", - "create.ponder.rope_pulley_modes.text_1": "當繩索滑輪停止運動時,它所附屬的移動結構便會方塊化", - "create.ponder.rope_pulley_modes.text_2": "你可以調整整個結構永不方塊化,或者僅在結構的初始位置方塊化", - - "create.ponder.rose_quartz_lamp.header": "玫瑰石英燈", - "create.ponder.rose_quartz_lamp.text_1": "玫瑰石英燈由紅石訊號開啟", - "create.ponder.rose_quartz_lamp.text_2": "之後它們會持續發出紅石能量", - "create.ponder.rose_quartz_lamp.text_3": "當多個燈排列成一組…", - "create.ponder.rose_quartz_lamp.text_4": "…訊號會集中到新開啟的燈,其餘的將熄滅", - "create.ponder.rose_quartz_lamp.text_5": "比較器的輸出強度,取決於開啟的燈的距離", - "create.ponder.rose_quartz_lamp.text_6": "也可以透過扳手手動切換", - - "create.ponder.rotation_speed_controller.header": "使用轉速控制器", - "create.ponder.rotation_speed_controller.text_1": "轉速控制器將動能從其轉軸傳輸至它上方的大齒輪", - "create.ponder.rotation_speed_controller.text_2": "在其側面滾動滑鼠滾輪,可以調節輸出轉速", - - "create.ponder.sail.header": "使用風帆來組裝風車", - "create.ponder.sail.text_1": "風帆是製作風車的趁手材料", - "create.ponder.sail.text_2": "無需強力膠等黏附手段,它們便可自行互相連結", - "create.ponder.sail.text_3": "手持染料右鍵可對其染色", - "create.ponder.sail.text_4": "手持剪刀右鍵可剪除帆布,使其變迴風帆框架", - - "create.ponder.sail_frame.header": "使用風帆框架來組裝風車", - "create.ponder.sail_frame.text_1": "風帆框架是製作風車的趁手材料", - "create.ponder.sail_frame.text_2": "無需強力膠等黏附手段,它們便可自行互相連結", - - "create.ponder.sequenced_gearshift.header": "使用可編程齒輪箱來控制轉速", - "create.ponder.sequenced_gearshift.text_1": "可編程齒輪箱能夠根據玩家設置的預設時序表來傳輸動力", - "create.ponder.sequenced_gearshift.text_2": "右鍵可以打開設置面板", - "create.ponder.sequenced_gearshift.text_3": "接受紅石訊號時,它會開始執行其內部已設定好的時序指令表", - "create.ponder.sequenced_gearshift.text_4": "當完成時序指令表後,它會進入待機狀態,再度接受紅石訊號後,它才會再度執行時序指令表內容", - "create.ponder.sequenced_gearshift.text_5": "紅石比較器可以讀取目前時序指令表完成進度", - - "create.ponder.shaft.header": "使用傳動軸來傳輸動力", - "create.ponder.shaft.text_1": "傳動軸可以直線傳輸動力", - - "create.ponder.shaft_casing.header": "包裹傳動軸", - "create.ponder.shaft_casing.text_1": "黃銅及安山岩機殼可以用來裝飾傳動軸", - - "create.ponder.smart_chute.header": "使用智慧滑槽來過濾物品", - "create.ponder.smart_chute.text_1": "智慧滑槽是一種可以被控制的滑槽", - "create.ponder.smart_chute.text_2": "當在其過濾槽內指定了物品後,滑槽只會傳輸這一指定標記的物品", - "create.ponder.smart_chute.text_3": "使用滑鼠滾輪可以指定被過濾的物品數量", - "create.ponder.smart_chute.text_4": "輸入紅石訊號,智慧滑槽將會完全暫停工作", - - "create.ponder.smart_pipe.header": "使用智慧流體管道控制流體", - "create.ponder.smart_pipe.text_1": "智慧流體管道可以按照流體類型控制流體流", - "create.ponder.smart_pipe.text_2": "當直接放置在源頭時,它們可以指定要提取的流體類型", - "create.ponder.smart_pipe.text_3": "只需用包含所需流體的任何項目右鍵點擊其過濾槽", - "create.ponder.smart_pipe.text_4": "在管網裡時,智慧流體管道只會讓匹配的流體經過", - - "create.ponder.speedometer.header": "使用轉速計來監測轉速", - "create.ponder.speedometer.text_1": "轉速計能顯示相接組件的轉速", - "create.ponder.speedometer.text_2": "當佩戴工程師護目鏡時,可以看到儀表所顯示的更詳細的數據", - "create.ponder.speedometer.text_3": "紅石比較器可以根據轉速計的數值輸出不同強弱的紅石訊號", - - "create.ponder.spout_filling.header": "使用流體灌注器填充物品", - "create.ponder.spout_filling.text_1": "流體灌注器可以填充下方的流體容器", - "create.ponder.spout_filling.text_2": "無法手動接觸流體灌注器中的流體", - "create.ponder.spout_filling.text_3": "管道可用於為其提供流體", - "create.ponder.spout_filling.text_4": "輸入物品可以是掉落狀態或是被放在置物台上", - "create.ponder.spout_filling.text_5": "當物品放在輸送帶上時…", - "create.ponder.spout_filling.text_6": "流體灌注器會停下他並且自動填滿", - - "create.ponder.stabilized_bearings.header": "裝置固定朝向", - "create.ponder.stabilized_bearings.text_1": "當機械軸承在結構被帶動時…", - "create.ponder.stabilized_bearings.text_2": "…它會確保它轉盤的垂直朝向不變", - "create.ponder.stabilized_bearings.text_3": "跟預設的一樣,機械軸承會黏著它前方的方塊", - "create.ponder.stabilized_bearings.text_4": "這種情況下,它所黏著的子結構的垂直朝向也不會改變", - - "create.ponder.steam_engine.header": "設置蒸汽機", - "create.ponder.steam_engine.text_1": "蒸汽機可以放置在流體儲存罐上", - "create.ponder.steam_engine.text_10": "Lvl 4", - "create.ponder.steam_engine.text_11": "4 個引擎", - "create.ponder.steam_engine.text_12": "Lvl 8", - "create.ponder.steam_engine.text_13": "8 個引擎", - "create.ponder.steam_engine.text_2": "手持傳動軸右鍵以輸出動力", - "create.ponder.steam_engine.text_3": "給予足夠的熱量、水和鍋爐空間…", - "create.ponder.steam_engine.text_4": "…它們會產生動力", - "create.ponder.steam_engine.text_5": "最低配備為 4 個流體儲存罐", - "create.ponder.steam_engine.text_6": "在烈焰使者動力爐的幫助下,功率可以得到提升", - "create.ponder.steam_engine.text_7": "更高的功率需要更多的熱量、水和空間", - "create.ponder.steam_engine.text_8": "可以使用工程師護目鏡檢查鍋爐的當前功率", - "create.ponder.steam_engine.text_9": "每提升一級功率,可以額外使一個蒸汽機滿負荷輸出", - - "create.ponder.steam_whistle.header": "設置汽笛", - "create.ponder.steam_whistle.text_1": "汽笛可以放置在流體儲存罐上", - "create.ponder.steam_whistle.text_2": "當儲存罐的熱量足夠…", - "create.ponder.steam_whistle.text_3": "…汽笛將被觸發並發出一個音", - "create.ponder.steam_whistle.text_4": "增加汽笛以降低音高", - "create.ponder.steam_whistle.text_5": "使用扳手可以設置音調在三個八度間切換", - "create.ponder.steam_whistle.text_6": "工程師護目鏡可以查看汽笛的音高", - - "create.ponder.sticker.header": "使用方塊黏著器來黏取方塊", - "create.ponder.sticker.text_1": "方塊黏著器是一個很棒的裝置,他受控於紅石訊號", - "create.ponder.sticker.text_2": "當接收到訊號時,他會黏起面前的一個方塊", - "create.ponder.sticker.text_3": "如果此時方塊黏著器被移動,被黏到的方塊會跟著移動", - "create.ponder.sticker.text_4": "再度接收到訊號後,黏著器會放下它面前的方塊", - - "create.ponder.stressometer.header": "使用動力計來監測動力", - "create.ponder.stressometer.text_1": "動力計能顯示目前動能網路內的動力訊息", - "create.ponder.stressometer.text_2": "當佩戴工程師護目鏡時,可以看到儀表所顯示的更詳細的數據", - "create.ponder.stressometer.text_3": "紅石比較器可以根據動力計的數值輸出不同強弱的紅石訊號", - - "create.ponder.super_glue.header": "使用強力膠來黏附方塊", - "create.ponder.super_glue.text_1": "強力膠可以在任意兩個方塊間使用", - "create.ponder.super_glue.text_2": "當被黏合的方塊被組裝為裝置時,它們會一起運動", - "create.ponder.super_glue.text_3": "當強力膠在副手時…", - "create.ponder.super_glue.text_4": "…新放置的方塊會自動被黏附在所放置方塊的面上", - "create.ponder.super_glue.text_5": "左鍵可以清除強力膠", - "create.ponder.super_glue.text_6": "附掛在其他方塊之上的方塊通常不需要使用強力膠", - - "create.ponder.track_chunks.header": "通過未加載的區塊", - "create.ponder.track_chunks.text_1": "軌道在未加載的區塊仍會運作", - "create.ponder.track_chunks.text_2": "火車可以順利的通過未被加載的區域", - "create.ponder.track_chunks.text_3": "它們仍會在車站及紅色信號處停止", - "create.ponder.track_chunks.text_4": "但是機械鑽頭與其他車載機器會停止運作", - "create.ponder.track_chunks.text_5": "一旦接近玩家火車將重新出現", - - "create.ponder.track_observer.header": "偵測火車", - "create.ponder.track_observer.text_1": "選取一個火車軌道並將火車感測器放在旁邊", - "create.ponder.track_observer.text_2": "感測器會檢測所有經過標記的火車", - "create.ponder.track_observer.text_3": "感測器可以設定為當比對到特定貨物時才啟動", - - "create.ponder.track_placement.header": "鋪設火車軌道", - "create.ponder.track_placement.text_1": "一種專為火車裝置設計的新型鐵軌", - "create.ponder.track_placement.text_2": "若要同時鋪設多條軌道,右鍵點擊已鋪設的軌道", - "create.ponder.track_placement.text_3": "然後選擇或放置第二個軌道", - "create.ponder.track_placement.text_4": "軌道也可以鋪設成彎道或斜坡", - "create.ponder.track_placement.text_5": "軌道在連接時會嘗試讓每個彎道的大小相等", - "create.ponder.track_placement.text_6": "連接時按住衝刺鍵…", - "create.ponder.track_placement.text_7": "…將創建最長且適合的彎道", - "create.ponder.track_placement.text_8": "副手持有的材料會自動鋪設在軌道下方", - - "create.ponder.track_portal.header": "軌道與地獄", - "create.ponder.track_portal.text_1": "對著地獄傳送門鋪設軌道…", - "create.ponder.track_portal.text_2": "…將嘗試在另一邊的傳送門鋪設成對的軌道", - "create.ponder.track_portal.text_3": "現在這條軌道上的火車可以跨次元旅行", - - "create.ponder.train_assembly.header": "組裝火車", - "create.ponder.train_assembly.text_1": "選擇一截軌道並在旁邊設置車站", - "create.ponder.train_assembly.text_10": "每列火車都需要安裝火車控制台", - "create.ponder.train_assembly.text_11": "可選擇安裝第二個控制台讓火車從車站的兩個方向出發", - "create.ponder.train_assembly.text_12": "開啟車站介面並確認組裝", - "create.ponder.train_assembly.text_13": "火車只能在車站拆解成方塊", - "create.ponder.train_assembly.text_14": "地圖會在車站的位置畫上標記", - "create.ponder.train_assembly.text_15": "組裝好的火車可以用扳手重新設置到相鄰的軌道", - "create.ponder.train_assembly.text_2": "車站是軌道網的路徑點", - "create.ponder.train_assembly.text_3": "開啟UI並切換到組裝模式以打造新火車", - "create.ponder.train_assembly.text_4": "在組裝時,時刻表上的火車不會接近此車站", - "create.ponder.train_assembly.text_5": "在軌道上設置火車機殼以創建新的轉向架", - "create.ponder.train_assembly.text_6": "再度點擊軌道以循環改變轉向架種類", - "create.ponder.train_assembly.text_7": "用強力膠連接方塊", - "create.ponder.train_assembly.text_8": "若組裝好的火車可在安裝於上的箱子或桶子中找到燃料,可以移動得更快速", - "create.ponder.train_assembly.text_9": "保險庫中的燃料不會被火車消耗", - - "create.ponder.train_controls.header": "控制火車", - "create.ponder.train_controls.text_1": "每列火車都需要火車控制台", - "create.ponder.train_controls.text_2": "組裝好後右鍵點擊控制台開始駕駛", - "create.ponder.train_controls.text_3": "使用移動鍵加速及導引火車方向", - "create.ponder.train_controls.text_4": "可以用滑鼠滾輪微調極速", - "create.ponder.train_controls.text_5": "按住空白鍵以接近最近的車站", - "create.ponder.train_controls.text_6": "火車只能在車站被拆解成方塊", - "create.ponder.train_controls.text_7": "安裝的汽笛可以按衝刺鍵觸發", - "create.ponder.train_controls.text_8": "潛行或再度點擊可以停止控制火車", - - "create.ponder.train_schedule.header": "使用火車時刻表", - "create.ponder.train_schedule.text_1": "時刻表讓其他司機員可以控制列車", - "create.ponder.train_schedule.text_2": "將時刻表拿在手上右鍵開啟介面", - "create.ponder.train_schedule.text_3": "計畫完成後就可以將時刻表給司機員", - "create.ponder.train_schedule.text_4": "任何坐在火車控制台前的生物及烈焰使者動力爐,都是合格的司機員", - "create.ponder.train_schedule.text_5": "用栓繩拴住生物可以使牠們更方便地坐上座位", - "create.ponder.train_schedule.text_6": "時刻表可以隨時從司機員身上回收", - - "create.ponder.train_signal_placement.header": "設置火車訊號機", - "create.ponder.train_signal_placement.text_1": "選擇一截軌道並在旁邊設置訊號機", - "create.ponder.train_signal_placement.text_2": "訊號機會控制非玩家駕駛的火車", - "create.ponder.train_signal_placement.text_3": "被調度的火車不會以反方向穿越訊號", - "create.ponder.train_signal_placement.text_4": "…除非添加第二個反方向的訊號", - "create.ponder.train_signal_placement.text_5": "連接真空管顯示器可以讓訊號燈更顯眼", - - "create.ponder.train_signal_redstone.header": "訊號與紅石", - "create.ponder.train_signal_redstone.text_1": "紅石訊號會使訊號機保持紅色", - "create.ponder.train_signal_redstone.text_2": "相反地,紅色訊號會使紅石比較器輸出紅石訊號", - - "create.ponder.train_signal_signaling.header": "使用訊號避免相撞", - "create.ponder.train_signal_signaling.text_1": "火車訊號機將一條軌道分成許多區間", - "create.ponder.train_signal_signaling.text_2": "若一個區間被占用,則不允許其他火車進入該區間", - "create.ponder.train_signal_signaling.text_3": "因此每個區間只能同時有一列火車", - "create.ponder.train_signal_signaling.text_4": "扳手可以設定第二種訊號模式", - "create.ponder.train_signal_signaling.text_5": "黃銅訊號區間通常會產生標準訊號", - "create.ponder.train_signal_signaling.text_6": "這種特殊訊號會讓火車在第二種情形下停止", - "create.ponder.train_signal_signaling.text_7": "它會使火車在進入區間時停止…", - "create.ponder.train_signal_signaling.text_8": "…讓火車無法離開這個區間", - "create.ponder.train_signal_signaling.text_9": "這協助排隊等候的火車遠離繁忙的區間", - - "create.ponder.valve_handle.header": "使用閥門手輪產生動力", - "create.ponder.valve_handle.text_1": "玩家可以手動使用閥門手輪以產生動力", - "create.ponder.valve_handle.text_2": "右鍵可使它逆時針旋轉", - "create.ponder.valve_handle.text_3": "它的轉速慢而精確", - "create.ponder.valve_handle.text_4": "潛行右鍵可使它順時針旋轉", - "create.ponder.valve_handle.text_5": "可以透過染色來美化閥門手輪", - - "create.ponder.valve_pipe.header": "使用流體閥門控制流體流量", - "create.ponder.valve_pipe.text_1": "閥門管道有助於控制通過管線網路傳輸的流體", - "create.ponder.valve_pipe.text_2": "它們的轉軸控制了流體是否允許通過", - "create.ponder.valve_pipe.text_3": "沿開啟的方向旋轉,流體閥門將會打開", - "create.ponder.valve_pipe.text_4": "反方向的旋轉會關閉閥門", - - "create.ponder.water_wheel.header": "使用水車產生動力", - "create.ponder.water_wheel.text_1": "水車利用臨近的水流產生動力", - "create.ponder.water_wheel.text_2": "水車接觸水流的面越多,它的轉速越高", - "create.ponder.water_wheel.text_3": "水車葉片應逆著水流方向擺放", - "create.ponder.water_wheel.text_4": "如果順著水流擺放,它的效率則會降低", - - "create.ponder.weighted_ejector.header": "使用彈射置物台", - "create.ponder.weighted_ejector.text_1": "手持彈射置物台時,潛行右鍵可以設置彈射目標位置", - "create.ponder.weighted_ejector.text_10": "現在,只有等被放置的物品數量等於所設定數量時,彈射置物台才會彈射物品", - "create.ponder.weighted_ejector.text_11": "當其他實體站在彈射置物台上時會被直接彈射", - "create.ponder.weighted_ejector.text_2": "現在,放置下的彈射置物台會將物品彈射至目標位置", - "create.ponder.weighted_ejector.text_3": "限制範圍內的任意距離和高度均可作為有效目標地點", - "create.ponder.weighted_ejector.text_4": "但是,目標位置與置物台的連線,必須垂直於置物台的側面", - "create.ponder.weighted_ejector.text_5": "如果沒有設置有效目標位置,彈射置物台會直接將其前方一格設為默認目標位置", - "create.ponder.weighted_ejector.text_6": "提供動力可為其蓄力", - "create.ponder.weighted_ejector.text_7": "蓄力完畢後,放置在它上方的物品會被立刻彈射出去", - "create.ponder.weighted_ejector.text_8": "如果目標為容器,則彈射置物台會等待容器有位置後再彈射物品", - "create.ponder.weighted_ejector.text_9": "使用扳手可以調整彈射所要求的物品數量", - - "create.ponder.weighted_ejector_redstone.header": "使用紅石控制彈射置物台", - "create.ponder.weighted_ejector_redstone.text_1": "當被紅石充能時,彈射置物台停止工作", - "create.ponder.weighted_ejector_redstone.text_2": "此外,置物台彈射的瞬間可以被偵測器偵測", - - "create.ponder.weighted_ejector_tunnel.header": "使用彈射置物台來分流物品", - "create.ponder.weighted_ejector_tunnel.text_1": "與黃銅隧道搭配使用時,彈射置物台可以將物品以特定數量進行分流", - "create.ponder.weighted_ejector_tunnel.text_2": "首先,將黃銅隧道調整為「最近優先」模式,從而讓它優先側面輸出", - "create.ponder.weighted_ejector_tunnel.text_3": "置物台上所設置的物品數量則為被分流出去的物品數量", - "create.ponder.weighted_ejector_tunnel.text_4": "當所設置的物品數量被分流出去後…", - "create.ponder.weighted_ejector_tunnel.text_5": "…剩餘的物品則會繼續前進", - - "create.ponder.windmill_source.header": "使用風車軸承產生動力", - "create.ponder.windmill_source.text_1": "風車軸承會黏住它面前的結構", - "create.ponder.windmill_source.text_2": "藉由強力膠建造可動結構", - "create.ponder.windmill_source.text_3": "如果該結構包含足夠多的風帆,他能作為風車運作", - "create.ponder.windmill_source.text_4": "右鍵啟動風車後,風車軸承將提供動力", - "create.ponder.windmill_source.text_5": "風帆的數量決定了旋轉的轉速", - "create.ponder.windmill_source.text_6": "使用扳手來調整其旋轉方向", - "create.ponder.windmill_source.text_7": "對風車軸承右鍵可使其停止,方便你維修風車", - - "create.ponder.windmill_structure.header": "風車結構", - "create.ponder.windmill_structure.text_1": "任一包含至少 8 個風帆方塊的結構即為有效的風車", - - "_": "Thank you for translating Create!" - -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_alloy_block.json b/src/generated/resources/assets/create/models/block/andesite_alloy_block.json new file mode 100644 index 0000000000..10e0cb6b80 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_alloy_block.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/andesite_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended.json deleted file mode 100644 index 5036d51eb8..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_extended", - "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall", - "6": "create:block/andesite_funnel", - "7": "create:block/andesite_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_powered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_powered.json index d4d5598d26..9d10ca3513 100644 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_powered.json @@ -1,13 +1,10 @@ { "parent": "create:block/belt_funnel/block_extended", "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall_powered", - "6": "create:block/andesite_funnel_powered", - "7": "create:block/andesite_funnel_plating" + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_neutral", + "redstone": "create:block/funnel/andesite_funnel_powered", + "base": "create:block/funnel/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_unpowered.json new file mode 100644 index 0000000000..37387e3e77 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_extended_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_extended", + "textures": { + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_neutral", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "base": "create:block/funnel/andesite_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling.json deleted file mode 100644 index 5a4fd73dae..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_pulling", - "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall", - "6": "create:block/andesite_funnel", - "7": "create:block/andesite_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_powered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_powered.json index a43488f11c..624713368c 100644 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_powered.json @@ -1,13 +1,10 @@ { "parent": "create:block/belt_funnel/block_pulling", "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall_powered", - "6": "create:block/andesite_funnel_powered", - "7": "create:block/andesite_funnel_plating" + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_pull", + "redstone": "create:block/funnel/andesite_funnel_powered", + "base": "create:block/funnel/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_unpowered.json new file mode 100644 index 0000000000..e2098131c0 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pulling_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_pulling", + "textures": { + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_pull", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "base": "create:block/funnel/andesite_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing.json deleted file mode 100644 index 47130f0052..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_pushing", - "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall", - "6": "create:block/andesite_funnel", - "7": "create:block/andesite_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_powered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_powered.json index 6513821737..4d852fabda 100644 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_powered.json @@ -1,13 +1,10 @@ { "parent": "create:block/belt_funnel/block_pushing", "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall_powered", - "6": "create:block/andesite_funnel_powered", - "7": "create:block/andesite_funnel_plating" + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_push", + "redstone": "create:block/funnel/andesite_funnel_powered", + "base": "create:block/funnel/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_unpowered.json new file mode 100644 index 0000000000..3fdaa36d22 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_pushing_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_pushing", + "textures": { + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_push", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "base": "create:block/funnel/andesite_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted.json deleted file mode 100644 index 4b272eeee3..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_retracted", - "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall", - "6": "create:block/andesite_funnel", - "7": "create:block/andesite_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_powered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_powered.json index 5552e989d4..45a34cceb3 100644 --- a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_powered.json @@ -1,13 +1,10 @@ { "parent": "create:block/belt_funnel/block_retracted", "textures": { - "particle": "minecraft:block/polished_andesite", - "2": "create:block/andesite_funnel_neutral", - "2_1": "create:block/andesite_funnel_push", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "5": "create:block/andesite_funnel_tall_powered", - "6": "create:block/andesite_funnel_powered", - "7": "create:block/andesite_funnel_plating" + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_neutral", + "redstone": "create:block/funnel/andesite_funnel_powered", + "base": "create:block/funnel/andesite_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_unpowered.json new file mode 100644 index 0000000000..9d61dfef3e --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_belt_funnel_retracted_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_retracted", + "textures": { + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "direction": "create:block/funnel/andesite_funnel_neutral", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "base": "create:block/funnel/andesite_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_cap.json b/src/generated/resources/assets/create/models/block/andesite_cap.json new file mode 100644 index 0000000000..10e6febcdd --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_cap.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_cap_alt.json b/src/generated/resources/assets/create/models/block/andesite_cap_alt.json new file mode 100644 index 0000000000..f23a3bf279 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_cap_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap_alt", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel.json b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel.json index a7a19bcddf..1b254a4fdd 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_bottom.json b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_bottom.json index ecfe574aca..b98901fc69 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_bottom.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_bottom", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top.json b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top.json index bf9533df32..0aef0307b3 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_top", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top_bottom.json b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top_bottom.json index f3523aaea8..488c355403 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top_bottom.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_cogwheel_top_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_top_bottom", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel.json b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel.json index dbabfdca60..1776aeef24 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_bottom.json b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_bottom.json index e29b6d37ad..a0734bf1fc 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_bottom.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_bottom", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top.json b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top.json index 3115674e77..632b5afd1b 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_top", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top_bottom.json b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top_bottom.json index 45aa717ca8..3c90be1d7b 100644 --- a/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top_bottom.json +++ b/src/generated/resources/assets/create/models/block/andesite_encased_large_cogwheel_top_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_top_bottom", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", + "4": "create:block/gearbox", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json deleted file mode 100644 index 4ca78f3abc..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_horizontal", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "6": "create:block/andesite_funnel" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json index f30214bd63..b985ddc8c9 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_powered.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/block_horizontal", "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "6": "create:block/andesite_funnel_powered" + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_powered", + "direction": "create:block/funnel/andesite_funnel_pull", + "block": "create:block/andesite_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_unpowered.json new file mode 100644 index 0000000000..f815e4bb1e --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_pull_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/funnel/block_horizontal", + "textures": { + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "direction": "create:block/funnel/andesite_funnel_pull", + "block": "create:block/andesite_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json deleted file mode 100644 index 090a3e9645..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_horizontal", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back", - "6": "create:block/andesite_funnel" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json index 3907df971b..fdafa100ac 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_powered.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/block_horizontal", "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back", - "6": "create:block/andesite_funnel_powered" + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_powered", + "direction": "create:block/funnel/andesite_funnel_push", + "block": "create:block/andesite_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_unpowered.json new file mode 100644 index 0000000000..27a70e7bbc --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_horizontal_push_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/funnel/block_horizontal", + "textures": { + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "direction": "create:block/funnel/andesite_funnel_push", + "block": "create:block/andesite_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json deleted file mode 100644 index a05b1954a2..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/funnel/block_vertical_filterless", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "8": "create:block/andesite_casing", - "9": "create:block/andesite_funnel_slope", - "10": "create:block/funnel_open" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json index 979f71145b..24b1f8300b 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_powered.json @@ -1,13 +1,11 @@ { "parent": "create:block/funnel/block_vertical_filterless", "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_pull", - "3": "create:block/andesite_funnel_back", - "8": "create:block/andesite_casing", - "9": "create:block/andesite_funnel_slope", - "10": "create:block/funnel_closed" + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_powered", + "direction": "create:block/funnel/andesite_funnel_pull", + "frame": "create:block/funnel/andesite_funnel_frame", + "open": "create:block/funnel/funnel_closed" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_unpowered.json new file mode 100644 index 0000000000..6a8ad6c1ea --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_pull_unpowered.json @@ -0,0 +1,11 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "direction": "create:block/funnel/andesite_funnel_pull", + "frame": "create:block/funnel/andesite_funnel_frame", + "open": "create:block/funnel/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json deleted file mode 100644 index ef3fe44319..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/funnel/block_vertical_filterless", - "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back", - "8": "create:block/andesite_casing", - "9": "create:block/andesite_funnel_slope", - "10": "create:block/funnel_open" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json index 4afdf8a20c..d81ac8ed25 100644 --- a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_powered.json @@ -1,13 +1,11 @@ { "parent": "create:block/funnel/block_vertical_filterless", "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "5": "create:block/andesite_funnel_tall_powered", - "2_2": "create:block/andesite_funnel_push", - "3": "create:block/andesite_funnel_back", - "8": "create:block/andesite_casing", - "9": "create:block/andesite_funnel_slope", - "10": "create:block/funnel_closed" + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_powered", + "direction": "create:block/funnel/andesite_funnel_push", + "frame": "create:block/funnel/andesite_funnel_frame", + "open": "create:block/funnel/funnel_closed" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_unpowered.json b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_unpowered.json new file mode 100644 index 0000000000..2b56302db9 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_funnel_vertical_filterless_push_unpowered.json @@ -0,0 +1,11 @@ +{ + "parent": "create:block/funnel/block_vertical_filterless", + "textures": { + "particle": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "redstone": "create:block/funnel/andesite_funnel_unpowered", + "direction": "create:block/funnel/andesite_funnel_push", + "frame": "create:block/funnel/andesite_funnel_frame", + "open": "create:block/funnel/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_post.json b/src/generated/resources/assets/create/models/block/andesite_post.json new file mode 100644 index 0000000000..b511a3363f --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_post.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_post_ends.json b/src/generated/resources/assets/create/models/block/andesite_post_ends.json new file mode 100644 index 0000000000..ea8088fa44 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_post_ends.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post_ends", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_scaffolding.json b/src/generated/resources/assets/create/models/block/andesite_scaffolding.json new file mode 100644 index 0000000000..8ecbf0691d --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_scaffolding.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block", + "textures": { + "top": "create:block/funnel/andesite_funnel_frame", + "inside": "create:block/scaffold/andesite_scaffold_inside", + "side": "create:block/scaffold/andesite_scaffold", + "casing": "create:block/andesite_casing", + "particle": "create:block/scaffold/andesite_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_scaffolding_horizontal.json b/src/generated/resources/assets/create/models/block/andesite_scaffolding_horizontal.json new file mode 100644 index 0000000000..3e5f979795 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_scaffolding_horizontal.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block_horizontal", + "textures": { + "top": "create:block/funnel/andesite_funnel_frame", + "inside": "create:block/scaffold/andesite_scaffold_inside", + "side": "create:block/scaffold/andesite_scaffold", + "casing": "create:block/andesite_casing", + "particle": "create:block/scaffold/andesite_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_side.json b/src/generated/resources/assets/create/models/block/andesite_side.json new file mode 100644 index 0000000000..069b74e654 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_side.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_side_alt.json b/src/generated/resources/assets/create/models/block/andesite_side_alt.json new file mode 100644 index 0000000000..1349daa077 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/andesite_side_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side_alt", + "textures": { + "bars": "create:block/bars/andesite_bars", + "particle": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_tunnel/cross.json b/src/generated/resources/assets/create/models/block/andesite_tunnel/cross.json deleted file mode 100644 index 26d9a16a27..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_tunnel/cross.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/cross", - "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", - "3": "create:block/andesite_tunnel_top_window", - "particle": "minecraft:block/polished_andesite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_tunnel/straight.json b/src/generated/resources/assets/create/models/block/andesite_tunnel/straight.json deleted file mode 100644 index c09b277408..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_tunnel/straight.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/straight", - "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", - "3": "create:block/andesite_tunnel_top_window", - "particle": "minecraft:block/polished_andesite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_tunnel/t_left.json b/src/generated/resources/assets/create/models/block/andesite_tunnel/t_left.json deleted file mode 100644 index 2f3779c2da..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_tunnel/t_left.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/t_left", - "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", - "3": "create:block/andesite_tunnel_top_window", - "particle": "minecraft:block/polished_andesite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_tunnel/t_right.json b/src/generated/resources/assets/create/models/block/andesite_tunnel/t_right.json deleted file mode 100644 index 52212c4a70..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_tunnel/t_right.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/t_right", - "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", - "3": "create:block/andesite_tunnel_top_window", - "particle": "minecraft:block/polished_andesite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/andesite_tunnel/window.json b/src/generated/resources/assets/create/models/block/andesite_tunnel/window.json deleted file mode 100644 index 71fd705dc8..0000000000 --- a/src/generated/resources/assets/create/models/block/andesite_tunnel/window.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/window", - "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", - "3": "create:block/andesite_tunnel_top_window", - "particle": "minecraft:block/polished_andesite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/asurine.json b/src/generated/resources/assets/create/models/block/asurine.json deleted file mode 100644 index 800055e27b..0000000000 --- a/src/generated/resources/assets/create/models/block/asurine.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "create:block/palettes/stone_types/asurine" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/asurine_natural_0.json b/src/generated/resources/assets/create/models/block/asurine_natural_0.json new file mode 100644 index 0000000000..215bad507d --- /dev/null +++ b/src/generated/resources/assets/create/models/block/asurine_natural_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/asurine_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/asurine_natural_1.json b/src/generated/resources/assets/create/models/block/asurine_natural_1.json new file mode 100644 index 0000000000..1075b117c1 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/asurine_natural_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/asurine_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/asurine_natural_2.json b/src/generated/resources/assets/create/models/block/asurine_natural_2.json new file mode 100644 index 0000000000..0dc373e4c8 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/asurine_natural_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/asurine_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/asurine_natural_3.json b/src/generated/resources/assets/create/models/block/asurine_natural_3.json new file mode 100644 index 0000000000..ac3daef705 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/asurine_natural_3.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/asurine_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended.json deleted file mode 100644 index 0fce1a25af..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_extended", - "textures": { - "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_powered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_powered.json index ff664c508b..9693650e42 100644 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_powered.json @@ -2,12 +2,9 @@ "parent": "create:block/belt_funnel/block_extended", "textures": { "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall_powered", - "6": "create:block/brass_funnel_powered", - "7": "create:block/brass_funnel_plating" + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_neutral", + "redstone": "create:block/funnel/brass_funnel_powered", + "base": "create:block/funnel/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_unpowered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_unpowered.json new file mode 100644 index 0000000000..6dcc3453fb --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_extended_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_extended", + "textures": { + "particle": "create:block/brass_block", + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_neutral", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "base": "create:block/funnel/brass_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling.json deleted file mode 100644 index 2975e7830b..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_pulling", - "textures": { - "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_powered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_powered.json index b2afb7d4ea..9cdb6c6933 100644 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_powered.json @@ -2,12 +2,9 @@ "parent": "create:block/belt_funnel/block_pulling", "textures": { "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall_powered", - "6": "create:block/brass_funnel_powered", - "7": "create:block/brass_funnel_plating" + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_pull", + "redstone": "create:block/funnel/brass_funnel_powered", + "base": "create:block/funnel/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_unpowered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_unpowered.json new file mode 100644 index 0000000000..b99062b8b7 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pulling_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_pulling", + "textures": { + "particle": "create:block/brass_block", + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_pull", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "base": "create:block/funnel/brass_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing.json deleted file mode 100644 index a1130fb8e1..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_pushing", - "textures": { - "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_powered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_powered.json index 99b7337752..b6b5df184d 100644 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_powered.json @@ -2,12 +2,9 @@ "parent": "create:block/belt_funnel/block_pushing", "textures": { "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall_powered", - "6": "create:block/brass_funnel_powered", - "7": "create:block/brass_funnel_plating" + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_push", + "redstone": "create:block/funnel/brass_funnel_powered", + "base": "create:block/funnel/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_unpowered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_unpowered.json new file mode 100644 index 0000000000..1057b96af1 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_pushing_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_pushing", + "textures": { + "particle": "create:block/brass_block", + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_push", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "base": "create:block/funnel/brass_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted.json deleted file mode 100644 index 693ec38e69..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/belt_funnel/block_retracted", - "textures": { - "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall", - "6": "create:block/brass_funnel", - "7": "create:block/brass_funnel_plating" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_powered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_powered.json index 60060dfb5a..c4355d82b8 100644 --- a/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_powered.json @@ -2,12 +2,9 @@ "parent": "create:block/belt_funnel/block_retracted", "textures": { "particle": "create:block/brass_block", - "2": "create:block/brass_funnel_neutral", - "2_1": "create:block/brass_funnel_push", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "5": "create:block/brass_funnel_tall_powered", - "6": "create:block/brass_funnel_powered", - "7": "create:block/brass_funnel_plating" + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_neutral", + "redstone": "create:block/funnel/brass_funnel_powered", + "base": "create:block/funnel/brass_funnel" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_unpowered.json b/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_unpowered.json new file mode 100644 index 0000000000..e910fd46ba --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_belt_funnel_retracted_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_funnel/block_retracted", + "textures": { + "particle": "create:block/brass_block", + "block": "create:block/brass_block", + "direction": "create:block/funnel/brass_funnel_neutral", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "base": "create:block/funnel/brass_funnel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_block.json b/src/generated/resources/assets/create/models/block/brass_block.json index c3d4b94f45..124827f00c 100644 --- a/src/generated/resources/assets/create/models/block/brass_block.json +++ b/src/generated/resources/assets/create/models/block/brass_block.json @@ -1,6 +1,6 @@ { "parent": "minecraft:block/cube_all", "textures": { - "all": "create:block/brass_storage_block" + "all": "create:block/brass_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_cap.json b/src/generated/resources/assets/create/models/block/brass_cap.json new file mode 100644 index 0000000000..b9270e6901 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_cap.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_cap_alt.json b/src/generated/resources/assets/create/models/block/brass_cap_alt.json new file mode 100644 index 0000000000..f5b3d71b4d --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_cap_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap_alt", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel.json b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel.json index ac524fa201..75b323ca9e 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_bottom.json b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_bottom.json index f539444af1..1860843693 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_bottom.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_bottom", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top.json b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top.json index bd1e4ee971..9280d9b5d0 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_top", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top_bottom.json b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top_bottom.json index 4a79cf7a90..4b713187e3 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top_bottom.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_cogwheel_top_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_cogwheel/block_top_bottom", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel.json b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel.json index b3a3f5ea7a..b7737d1426 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_bottom.json b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_bottom.json index d6cf2a4644..68401dd46e 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_bottom.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_bottom", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top.json b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top.json index 0ea8439415..dc83b552d0 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_top", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top_bottom.json b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top_bottom.json index 2250120e88..1703adbc89 100644 --- a/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top_bottom.json +++ b/src/generated/resources/assets/create/models/block/brass_encased_large_cogwheel_top_bottom.json @@ -2,6 +2,8 @@ "parent": "create:block/encased_large_cogwheel/block_top_bottom", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", + "4": "create:block/brass_gearbox", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json deleted file mode 100644 index a971472b42..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_horizontal", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "6": "create:block/brass_funnel" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json index 38c8a7e7af..5aa87848c0 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_powered.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/block_horizontal", "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "6": "create:block/brass_funnel_powered" + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_powered", + "direction": "create:block/funnel/brass_funnel_pull", + "block": "create:block/brass_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_unpowered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_unpowered.json new file mode 100644 index 0000000000..b90f575ce5 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_pull_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/funnel/block_horizontal", + "textures": { + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "direction": "create:block/funnel/brass_funnel_pull", + "block": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json deleted file mode 100644 index 85321b0318..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "parent": "create:block/funnel/block_horizontal", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back", - "6": "create:block/brass_funnel" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json index 83a796536d..4a9a5b9a0d 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_powered.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/block_horizontal", "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back", - "6": "create:block/brass_funnel_powered" + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_powered", + "direction": "create:block/funnel/brass_funnel_push", + "block": "create:block/brass_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_unpowered.json b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_unpowered.json new file mode 100644 index 0000000000..480a9e30d0 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_horizontal_push_unpowered.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/funnel/block_horizontal", + "textures": { + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "direction": "create:block/funnel/brass_funnel_push", + "block": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json deleted file mode 100644 index d2a1c61598..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/funnel/block_vertical", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "8": "create:block/brass_casing", - "9": "create:block/brass_funnel_slope", - "10": "create:block/funnel_open" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json index e319cf39d9..5695ef6632 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_powered.json @@ -1,13 +1,11 @@ { "parent": "create:block/funnel/block_vertical", "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_pull", - "3": "create:block/brass_funnel_back", - "8": "create:block/brass_casing", - "9": "create:block/brass_funnel_slope", - "10": "create:block/funnel_closed" + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_powered", + "direction": "create:block/funnel/brass_funnel_pull", + "frame": "create:block/funnel/brass_funnel_frame", + "open": "create:block/funnel/funnel_closed" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_unpowered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_unpowered.json new file mode 100644 index 0000000000..6c320b02f9 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_pull_unpowered.json @@ -0,0 +1,11 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "direction": "create:block/funnel/brass_funnel_pull", + "frame": "create:block/funnel/brass_funnel_frame", + "open": "create:block/funnel/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json deleted file mode 100644 index f95cdf3915..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "parent": "create:block/funnel/block_vertical", - "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back", - "8": "create:block/brass_casing", - "9": "create:block/brass_funnel_slope", - "10": "create:block/funnel_open" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json index 45ac7f48fa..3fa002b8b5 100644 --- a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_powered.json @@ -1,13 +1,11 @@ { "parent": "create:block/funnel/block_vertical", "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "5": "create:block/brass_funnel_tall_powered", - "2_2": "create:block/brass_funnel_push", - "3": "create:block/brass_funnel_back", - "8": "create:block/brass_casing", - "9": "create:block/brass_funnel_slope", - "10": "create:block/funnel_closed" + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_powered", + "direction": "create:block/funnel/brass_funnel_push", + "frame": "create:block/funnel/brass_funnel_frame", + "open": "create:block/funnel/funnel_closed" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_unpowered.json b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_unpowered.json new file mode 100644 index 0000000000..1180fdd003 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_funnel_vertical_push_unpowered.json @@ -0,0 +1,11 @@ +{ + "parent": "create:block/funnel/block_vertical", + "textures": { + "particle": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "redstone": "create:block/funnel/brass_funnel_unpowered", + "direction": "create:block/funnel/brass_funnel_push", + "frame": "create:block/funnel/brass_funnel_frame", + "open": "create:block/funnel/funnel_open" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_post.json b/src/generated/resources/assets/create/models/block/brass_post.json new file mode 100644 index 0000000000..75de082586 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_post.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_post_ends.json b/src/generated/resources/assets/create/models/block/brass_post_ends.json new file mode 100644 index 0000000000..c50e80d163 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_post_ends.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post_ends", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_scaffolding.json b/src/generated/resources/assets/create/models/block/brass_scaffolding.json new file mode 100644 index 0000000000..e7a305dd3e --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_scaffolding.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block", + "textures": { + "top": "create:block/funnel/brass_funnel_frame", + "inside": "create:block/scaffold/brass_scaffold_inside", + "side": "create:block/scaffold/brass_scaffold", + "casing": "create:block/brass_casing", + "particle": "create:block/scaffold/brass_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_scaffolding_horizontal.json b/src/generated/resources/assets/create/models/block/brass_scaffolding_horizontal.json new file mode 100644 index 0000000000..6e614692c2 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_scaffolding_horizontal.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block_horizontal", + "textures": { + "top": "create:block/funnel/brass_funnel_frame", + "inside": "create:block/scaffold/brass_scaffold_inside", + "side": "create:block/scaffold/brass_scaffold", + "casing": "create:block/brass_casing", + "particle": "create:block/scaffold/brass_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_side.json b/src/generated/resources/assets/create/models/block/brass_side.json new file mode 100644 index 0000000000..10b81c8493 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_side.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_side_alt.json b/src/generated/resources/assets/create/models/block/brass_side_alt.json new file mode 100644 index 0000000000..160ae7e217 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/brass_side_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side_alt", + "textures": { + "bars": "create:block/bars/brass_bars", + "particle": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_tunnel/cross.json b/src/generated/resources/assets/create/models/block/brass_tunnel/cross.json deleted file mode 100644 index 35f563cc3b..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_tunnel/cross.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/cross", - "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", - "3": "create:block/brass_tunnel_top_window", - "particle": "create:block/brass_block" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_tunnel/straight.json b/src/generated/resources/assets/create/models/block/brass_tunnel/straight.json deleted file mode 100644 index 219f222577..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_tunnel/straight.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/straight", - "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", - "3": "create:block/brass_tunnel_top_window", - "particle": "create:block/brass_block" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_tunnel/t_left.json b/src/generated/resources/assets/create/models/block/brass_tunnel/t_left.json deleted file mode 100644 index 62165f5330..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_tunnel/t_left.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/t_left", - "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", - "3": "create:block/brass_tunnel_top_window", - "particle": "create:block/brass_block" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_tunnel/t_right.json b/src/generated/resources/assets/create/models/block/brass_tunnel/t_right.json deleted file mode 100644 index a9da1c54af..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_tunnel/t_right.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/t_right", - "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", - "3": "create:block/brass_tunnel_top_window", - "particle": "create:block/brass_block" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/brass_tunnel/window.json b/src/generated/resources/assets/create/models/block/brass_tunnel/window.json deleted file mode 100644 index 0c62dcab8e..0000000000 --- a/src/generated/resources/assets/create/models/block/brass_tunnel/window.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "parent": "create:block/belt_tunnel/window", - "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", - "3": "create:block/brass_tunnel_top_window", - "particle": "create:block/brass_block" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/clockwork_bearing.json b/src/generated/resources/assets/create/models/block/clockwork_bearing.json index 918f089a7c..144a26a781 100644 --- a/src/generated/resources/assets/create/models/block/clockwork_bearing.json +++ b/src/generated/resources/assets/create/models/block/clockwork_bearing.json @@ -2,7 +2,6 @@ "parent": "create:block/bearing/block", "textures": { "side": "create:block/clockwork_bearing_side", - "nook": "create:block/brass_casing", "back": "create:block/brass_gearbox" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_cap.json b/src/generated/resources/assets/create/models/block/copper_cap.json new file mode 100644 index 0000000000..38dd67bfa2 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_cap.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_cap_alt.json b/src/generated/resources/assets/create/models/block/copper_cap_alt.json new file mode 100644 index 0000000000..e01cd860a8 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_cap_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/cap_alt", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_post.json b/src/generated/resources/assets/create/models/block/copper_post.json new file mode 100644 index 0000000000..befb6f49ba --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_post.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_post_ends.json b/src/generated/resources/assets/create/models/block/copper_post_ends.json new file mode 100644 index 0000000000..293984fb1a --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_post_ends.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/post_ends", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_scaffolding.json b/src/generated/resources/assets/create/models/block/copper_scaffolding.json new file mode 100644 index 0000000000..7aa498957b --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_scaffolding.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block", + "textures": { + "top": "create:block/funnel/copper_funnel_frame", + "inside": "create:block/scaffold/copper_scaffold_inside", + "side": "create:block/scaffold/copper_scaffold", + "casing": "create:block/copper_casing", + "particle": "create:block/scaffold/copper_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_scaffolding_horizontal.json b/src/generated/resources/assets/create/models/block/copper_scaffolding_horizontal.json new file mode 100644 index 0000000000..053a64d2dc --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_scaffolding_horizontal.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/scaffold/block_horizontal", + "textures": { + "top": "create:block/funnel/copper_funnel_frame", + "inside": "create:block/scaffold/copper_scaffold_inside", + "side": "create:block/scaffold/copper_scaffold", + "casing": "create:block/copper_casing", + "particle": "create:block/scaffold/copper_scaffold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_side.json b/src/generated/resources/assets/create/models/block/copper_side.json new file mode 100644 index 0000000000..81c632b02e --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_side.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/copper_side_alt.json b/src/generated/resources/assets/create/models/block/copper_side_alt.json new file mode 100644 index 0000000000..28987f702f --- /dev/null +++ b/src/generated/resources/assets/create/models/block/copper_side_alt.json @@ -0,0 +1,8 @@ +{ + "parent": "create:block/bars/side_alt", + "textures": { + "bars": "create:block/bars/copper_bars", + "particle": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/crimsite.json b/src/generated/resources/assets/create/models/block/crimsite.json deleted file mode 100644 index a7c02eec1a..0000000000 --- a/src/generated/resources/assets/create/models/block/crimsite.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "create:block/palettes/stone_types/crimsite" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/crimsite_natural_0.json b/src/generated/resources/assets/create/models/block/crimsite_natural_0.json new file mode 100644 index 0000000000..7199eff111 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/crimsite_natural_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/crimsite_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/crimsite_natural_1.json b/src/generated/resources/assets/create/models/block/crimsite_natural_1.json new file mode 100644 index 0000000000..c006ddbf64 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/crimsite_natural_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/crimsite_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/crimsite_natural_2.json b/src/generated/resources/assets/create/models/block/crimsite_natural_2.json new file mode 100644 index 0000000000..55208b5a0c --- /dev/null +++ b/src/generated/resources/assets/create/models/block/crimsite_natural_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/crimsite_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/crimsite_natural_3.json b/src/generated/resources/assets/create/models/block/crimsite_natural_3.json new file mode 100644 index 0000000000..a76aabcbec --- /dev/null +++ b/src/generated/resources/assets/create/models/block/crimsite_natural_3.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/crimsite_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/industrial_iron_block.json b/src/generated/resources/assets/create/models/block/industrial_iron_block.json new file mode 100644 index 0000000000..6b62aa6ff5 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/industrial_iron_block.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/cube_column", + "textures": { + "side": "create:block/industrial_iron_block", + "end": "create:block/industrial_iron_block_top" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/mechanical_bearing.json b/src/generated/resources/assets/create/models/block/mechanical_bearing.json index 74a704e576..9e50b2ade9 100644 --- a/src/generated/resources/assets/create/models/block/mechanical_bearing.json +++ b/src/generated/resources/assets/create/models/block/mechanical_bearing.json @@ -2,7 +2,6 @@ "parent": "create:block/bearing/block", "textures": { "side": "create:block/mechanical_bearing_side", - "nook": "create:block/brass_casing", "back": "create:block/gearbox" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/ochrum.json b/src/generated/resources/assets/create/models/block/ochrum.json deleted file mode 100644 index aa1b78ea5f..0000000000 --- a/src/generated/resources/assets/create/models/block/ochrum.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "create:block/palettes/stone_types/ochrum" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/ochrum_natural_0.json b/src/generated/resources/assets/create/models/block/ochrum_natural_0.json new file mode 100644 index 0000000000..a09dbd318e --- /dev/null +++ b/src/generated/resources/assets/create/models/block/ochrum_natural_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/ochrum_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/ochrum_natural_1.json b/src/generated/resources/assets/create/models/block/ochrum_natural_1.json new file mode 100644 index 0000000000..c765a7db25 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/ochrum_natural_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/ochrum_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/ochrum_natural_2.json b/src/generated/resources/assets/create/models/block/ochrum_natural_2.json new file mode 100644 index 0000000000..31a26ea709 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/ochrum_natural_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/ochrum_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/ochrum_natural_3.json b/src/generated/resources/assets/create/models/block/ochrum_natural_3.json new file mode 100644 index 0000000000..366b54a887 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/ochrum_natural_3.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/ochrum_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_0.json b/src/generated/resources/assets/create/models/block/stockpile_switch_0.json deleted file mode 100644 index 4d1b9b70e7..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_0.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/0" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_1.json b/src/generated/resources/assets/create/models/block/stockpile_switch_1.json deleted file mode 100644 index 288dc2927b..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/1" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_2.json b/src/generated/resources/assets/create/models/block/stockpile_switch_2.json deleted file mode 100644 index 8b0da8a215..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_2.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/2" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_3.json b/src/generated/resources/assets/create/models/block/stockpile_switch_3.json deleted file mode 100644 index fc3e401322..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_3.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/3" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_4.json b/src/generated/resources/assets/create/models/block/stockpile_switch_4.json deleted file mode 100644 index 2194e2c692..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_4.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/4" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_5.json b/src/generated/resources/assets/create/models/block/stockpile_switch_5.json deleted file mode 100644 index eb0f8298ce..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_5.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/5" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/stockpile_switch_6.json b/src/generated/resources/assets/create/models/block/stockpile_switch_6.json deleted file mode 100644 index 58a83e6467..0000000000 --- a/src/generated/resources/assets/create/models/block/stockpile_switch_6.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "create:block/stockpile_switch", - "textures": { - "indicator": "create:block/indicator/6" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/cross.json b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/cross.json new file mode 100644 index 0000000000..af761a56e3 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/cross.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/cross", + "textures": { + "top": "create:block/tunnel/andesite_tunnel_top", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", + "particle": "minecraft:block/polished_andesite" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/straight.json b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/straight.json new file mode 100644 index 0000000000..673cdfd5c6 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/straight.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/straight", + "textures": { + "top": "create:block/tunnel/andesite_tunnel_top", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", + "particle": "minecraft:block/polished_andesite" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_left.json b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_left.json new file mode 100644 index 0000000000..d017afa30c --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_left.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/t_left", + "textures": { + "top": "create:block/tunnel/andesite_tunnel_top", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", + "particle": "minecraft:block/polished_andesite" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_right.json b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_right.json new file mode 100644 index 0000000000..c3de582423 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/t_right.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/t_right", + "textures": { + "top": "create:block/tunnel/andesite_tunnel_top", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", + "particle": "minecraft:block/polished_andesite" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/window.json b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/window.json new file mode 100644 index 0000000000..8813af82e8 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/andesite_tunnel/window.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/window", + "textures": { + "top": "create:block/tunnel/andesite_tunnel_top_window", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", + "particle": "minecraft:block/polished_andesite" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/cross.json b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/cross.json new file mode 100644 index 0000000000..0368020e03 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/cross.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/cross", + "textures": { + "top": "create:block/tunnel/brass_tunnel_top", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", + "particle": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/straight.json b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/straight.json new file mode 100644 index 0000000000..c9a870d81b --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/straight.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/straight", + "textures": { + "top": "create:block/tunnel/brass_tunnel_top", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", + "particle": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_left.json b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_left.json new file mode 100644 index 0000000000..bf210e93b7 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_left.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/t_left", + "textures": { + "top": "create:block/tunnel/brass_tunnel_top", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", + "particle": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_right.json b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_right.json new file mode 100644 index 0000000000..c9ce280610 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/t_right.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/t_right", + "textures": { + "top": "create:block/tunnel/brass_tunnel_top", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", + "particle": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/window.json b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/window.json new file mode 100644 index 0000000000..5efd8ccaa6 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/tunnel/brass_tunnel/window.json @@ -0,0 +1,10 @@ +{ + "parent": "create:block/belt_tunnel/window", + "textures": { + "top": "create:block/tunnel/brass_tunnel_top_window", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", + "particle": "create:block/brass_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/veridium.json b/src/generated/resources/assets/create/models/block/veridium.json deleted file mode 100644 index fe23b9d7a9..0000000000 --- a/src/generated/resources/assets/create/models/block/veridium.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "create:block/palettes/stone_types/veridium" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/veridium_natural_0.json b/src/generated/resources/assets/create/models/block/veridium_natural_0.json new file mode 100644 index 0000000000..ec6d946300 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/veridium_natural_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/veridium_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/veridium_natural_1.json b/src/generated/resources/assets/create/models/block/veridium_natural_1.json new file mode 100644 index 0000000000..52e7c814df --- /dev/null +++ b/src/generated/resources/assets/create/models/block/veridium_natural_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/veridium_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/veridium_natural_2.json b/src/generated/resources/assets/create/models/block/veridium_natural_2.json new file mode 100644 index 0000000000..75f8fd7c39 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/veridium_natural_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/veridium_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/veridium_natural_3.json b/src/generated/resources/assets/create/models/block/veridium_natural_3.json new file mode 100644 index 0000000000..d8f40fe314 --- /dev/null +++ b/src/generated/resources/assets/create/models/block/veridium_natural_3.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/veridium_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/block/windmill_bearing.json b/src/generated/resources/assets/create/models/block/windmill_bearing.json index 1af6d60598..fb370406e5 100644 --- a/src/generated/resources/assets/create/models/block/windmill_bearing.json +++ b/src/generated/resources/assets/create/models/block/windmill_bearing.json @@ -2,7 +2,6 @@ "parent": "create:block/bearing/block", "textures": { "side": "create:block/windmill_bearing_side", - "nook": "create:block/andesite_casing", "back": "create:block/gearbox" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_alloy_block.json b/src/generated/resources/assets/create/models/item/andesite_alloy_block.json new file mode 100644 index 0000000000..177e920a35 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/andesite_alloy_block.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/andesite_alloy_block" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_bars.json b/src/generated/resources/assets/create/models/item/andesite_bars.json new file mode 100644 index 0000000000..a881e12f6b --- /dev/null +++ b/src/generated/resources/assets/create/models/item/andesite_bars.json @@ -0,0 +1,7 @@ +{ + "parent": "create:item/bars", + "textures": { + "bars": "create:block/bars/andesite_bars", + "edge": "create:block/bars/andesite_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_door.json b/src/generated/resources/assets/create/models/item/andesite_door.json new file mode 100644 index 0000000000..644fdf227d --- /dev/null +++ b/src/generated/resources/assets/create/models/item/andesite_door.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/andesite_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_encased_cogwheel.json b/src/generated/resources/assets/create/models/item/andesite_encased_cogwheel.json index 7912bbab9c..2c8048e5b5 100644 --- a/src/generated/resources/assets/create/models/item/andesite_encased_cogwheel.json +++ b/src/generated/resources/assets/create/models/item/andesite_encased_cogwheel.json @@ -2,6 +2,7 @@ "parent": "create:block/encased_cogwheel/item", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/item/andesite_encased_large_cogwheel.json b/src/generated/resources/assets/create/models/item/andesite_encased_large_cogwheel.json index 14396af11b..3344649115 100644 --- a/src/generated/resources/assets/create/models/item/andesite_encased_large_cogwheel.json +++ b/src/generated/resources/assets/create/models/item/andesite_encased_large_cogwheel.json @@ -2,6 +2,7 @@ "parent": "create:block/encased_large_cogwheel/item", "textures": { "casing": "create:block/andesite_casing", + "particle": "create:block/andesite_casing", "1": "minecraft:block/stripped_spruce_log_top", "side": "create:block/andesite_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/item/andesite_funnel.json b/src/generated/resources/assets/create/models/item/andesite_funnel.json index 6cb095db37..5aa85e5b5b 100644 --- a/src/generated/resources/assets/create/models/item/andesite_funnel.json +++ b/src/generated/resources/assets/create/models/item/andesite_funnel.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/item", "textures": { - "particle": "create:block/andesite_casing", - "7": "create:block/andesite_funnel_plating", - "2": "create:block/andesite_funnel_neutral", - "6": "create:block/andesite_funnel", - "5": "create:block/andesite_funnel_tall", - "3": "create:block/andesite_funnel_back" + "particle": "create:block/andesite_block", + "block": "create:block/andesite_block", + "base": "create:block/funnel/andesite_funnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "redstone": "create:block/funnel/andesite_funnel_unpowered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_scaffolding.json b/src/generated/resources/assets/create/models/item/andesite_scaffolding.json new file mode 100644 index 0000000000..1178fb151e --- /dev/null +++ b/src/generated/resources/assets/create/models/item/andesite_scaffolding.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/andesite_scaffolding" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/andesite_tunnel.json b/src/generated/resources/assets/create/models/item/andesite_tunnel.json index b8a1aa70a3..99233d0e78 100644 --- a/src/generated/resources/assets/create/models/item/andesite_tunnel.json +++ b/src/generated/resources/assets/create/models/item/andesite_tunnel.json @@ -1,8 +1,10 @@ { "parent": "create:block/belt_tunnel/item", "textures": { - "1": "create:block/andesite_tunnel_top", - "2": "create:block/andesite_tunnel", + "top": "create:block/tunnel/andesite_tunnel_top", + "tunnel": "create:block/tunnel/andesite_tunnel", + "direction": "create:block/funnel/andesite_funnel_neutral", + "frame": "create:block/funnel/andesite_funnel_frame", "particle": "minecraft:block/polished_andesite" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/asurine.json b/src/generated/resources/assets/create/models/item/asurine.json index 777afa9190..1075b117c1 100644 --- a/src/generated/resources/assets/create/models/item/asurine.json +++ b/src/generated/resources/assets/create/models/item/asurine.json @@ -1,3 +1,6 @@ { - "parent": "create:block/asurine" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/asurine_1" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/attribute_filter.json b/src/generated/resources/assets/create/models/item/attribute_filter.json new file mode 100644 index 0000000000..e20fe2e5f6 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/attribute_filter.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/attribute_filter" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/brass_bars.json b/src/generated/resources/assets/create/models/item/brass_bars.json new file mode 100644 index 0000000000..e1b32edd80 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/brass_bars.json @@ -0,0 +1,7 @@ +{ + "parent": "create:item/bars", + "textures": { + "bars": "create:block/bars/brass_bars", + "edge": "create:block/bars/brass_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/brass_door.json b/src/generated/resources/assets/create/models/item/brass_door.json new file mode 100644 index 0000000000..814256ba64 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/brass_door.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/brass_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/brass_encased_cogwheel.json b/src/generated/resources/assets/create/models/item/brass_encased_cogwheel.json index ca72d6475c..1f5296ec8e 100644 --- a/src/generated/resources/assets/create/models/item/brass_encased_cogwheel.json +++ b/src/generated/resources/assets/create/models/item/brass_encased_cogwheel.json @@ -2,6 +2,7 @@ "parent": "create:block/encased_cogwheel/item", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side" } diff --git a/src/generated/resources/assets/create/models/item/brass_encased_large_cogwheel.json b/src/generated/resources/assets/create/models/item/brass_encased_large_cogwheel.json index 0f81deda2a..24da645e78 100644 --- a/src/generated/resources/assets/create/models/item/brass_encased_large_cogwheel.json +++ b/src/generated/resources/assets/create/models/item/brass_encased_large_cogwheel.json @@ -2,6 +2,7 @@ "parent": "create:block/encased_large_cogwheel/item", "textures": { "casing": "create:block/brass_casing", + "particle": "create:block/brass_casing", "1": "minecraft:block/stripped_dark_oak_log_top", "side": "create:block/brass_encased_cogwheel_side_connected" } diff --git a/src/generated/resources/assets/create/models/item/brass_funnel.json b/src/generated/resources/assets/create/models/item/brass_funnel.json index 5a1542acb7..2450d2d131 100644 --- a/src/generated/resources/assets/create/models/item/brass_funnel.json +++ b/src/generated/resources/assets/create/models/item/brass_funnel.json @@ -1,11 +1,10 @@ { "parent": "create:block/funnel/item", "textures": { - "particle": "create:block/brass_casing", - "7": "create:block/brass_funnel_plating", - "2": "create:block/brass_funnel_neutral", - "6": "create:block/brass_funnel", - "5": "create:block/brass_funnel_tall", - "3": "create:block/brass_funnel_back" + "particle": "create:block/brass_block", + "block": "create:block/brass_block", + "base": "create:block/funnel/brass_funnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "redstone": "create:block/funnel/brass_funnel_unpowered" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/brass_scaffolding.json b/src/generated/resources/assets/create/models/item/brass_scaffolding.json new file mode 100644 index 0000000000..94a4c5a958 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/brass_scaffolding.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/brass_scaffolding" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/brass_tunnel.json b/src/generated/resources/assets/create/models/item/brass_tunnel.json index b78dea50b4..57ef723a13 100644 --- a/src/generated/resources/assets/create/models/item/brass_tunnel.json +++ b/src/generated/resources/assets/create/models/item/brass_tunnel.json @@ -1,8 +1,10 @@ { "parent": "create:block/belt_tunnel/item", "textures": { - "1": "create:block/brass_tunnel_top", - "2": "create:block/brass_tunnel", + "top": "create:block/tunnel/brass_tunnel_top", + "tunnel": "create:block/tunnel/brass_tunnel", + "direction": "create:block/funnel/brass_funnel_neutral", + "frame": "create:block/funnel/brass_funnel_frame", "particle": "create:block/brass_block" } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/clipboard.json b/src/generated/resources/assets/create/models/item/clipboard.json new file mode 100644 index 0000000000..07fd628205 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/clipboard.json @@ -0,0 +1,26 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/clipboard" + }, + "overrides": [ + { + "predicate": { + "create:clipboard_type": 0.0 + }, + "model": "create:item/clipboard_0" + }, + { + "predicate": { + "create:clipboard_type": 1.0 + }, + "model": "create:item/clipboard_1" + }, + { + "predicate": { + "create:clipboard_type": 2.0 + }, + "model": "create:item/clipboard_2" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/clipboard_0.json b/src/generated/resources/assets/create/models/item/clipboard_0.json new file mode 100644 index 0000000000..46f7226fa4 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/clipboard_0.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/empty_clipboard" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/clipboard_1.json b/src/generated/resources/assets/create/models/item/clipboard_1.json new file mode 100644 index 0000000000..ee59b74f7b --- /dev/null +++ b/src/generated/resources/assets/create/models/item/clipboard_1.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/clipboard" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/clipboard_2.json b/src/generated/resources/assets/create/models/item/clipboard_2.json new file mode 100644 index 0000000000..a51972bbcc --- /dev/null +++ b/src/generated/resources/assets/create/models/item/clipboard_2.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/clipboard_and_quill" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/contraption_controls.json b/src/generated/resources/assets/create/models/item/contraption_controls.json new file mode 100644 index 0000000000..07a722d362 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/contraption_controls.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/contraption_controls/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copper_bars.json b/src/generated/resources/assets/create/models/item/copper_bars.json new file mode 100644 index 0000000000..66553f12e1 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copper_bars.json @@ -0,0 +1,7 @@ +{ + "parent": "create:item/bars", + "textures": { + "bars": "create:block/bars/copper_bars", + "edge": "create:block/bars/copper_bars_edge" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copper_diving_boots.json b/src/generated/resources/assets/create/models/item/copper_diving_boots.json new file mode 100644 index 0000000000..fab121e042 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copper_diving_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/copper_diving_boots" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copper_diving_helmet.json b/src/generated/resources/assets/create/models/item/copper_diving_helmet.json new file mode 100644 index 0000000000..e21e9b4eec --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copper_diving_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/copper_diving_helmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copper_door.json b/src/generated/resources/assets/create/models/item/copper_door.json new file mode 100644 index 0000000000..8e2e20d3e8 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copper_door.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/copper_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copper_scaffolding.json b/src/generated/resources/assets/create/models/item/copper_scaffolding.json new file mode 100644 index 0000000000..6908ad3675 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copper_scaffolding.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/copper_scaffolding" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copycat_panel.json b/src/generated/resources/assets/create/models/item/copycat_panel.json new file mode 100644 index 0000000000..5772b8c882 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copycat_panel.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/copycat_base/panel" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copycat_step.json b/src/generated/resources/assets/create/models/item/copycat_step.json new file mode 100644 index 0000000000..dd2286908b --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copycat_step.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/copycat_base/step" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crimsite.json b/src/generated/resources/assets/create/models/item/crimsite.json index a555488746..c006ddbf64 100644 --- a/src/generated/resources/assets/create/models/item/crimsite.json +++ b/src/generated/resources/assets/create/models/item/crimsite.json @@ -1,3 +1,6 @@ { - "parent": "create:block/crimsite" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/crimsite_1" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_aluminum_ore.json b/src/generated/resources/assets/create/models/item/crushed_aluminum_ore.json deleted file mode 100644 index 662060f98d..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_aluminum_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_aluminum_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_copper_ore.json b/src/generated/resources/assets/create/models/item/crushed_copper_ore.json deleted file mode 100644 index 500b001244..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_copper_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_copper_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_gold_ore.json b/src/generated/resources/assets/create/models/item/crushed_gold_ore.json deleted file mode 100644 index dc00a36118..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_gold_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_gold_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_iron_ore.json b/src/generated/resources/assets/create/models/item/crushed_iron_ore.json deleted file mode 100644 index 9ac971ece3..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_iron_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_iron_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_lead_ore.json b/src/generated/resources/assets/create/models/item/crushed_lead_ore.json deleted file mode 100644 index 1c2c6911bd..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_lead_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_lead_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_nickel_ore.json b/src/generated/resources/assets/create/models/item/crushed_nickel_ore.json deleted file mode 100644 index 4a47620f79..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_nickel_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_nickel_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_osmium_ore.json b/src/generated/resources/assets/create/models/item/crushed_osmium_ore.json deleted file mode 100644 index bffaad165b..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_osmium_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_osmium_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_platinum_ore.json b/src/generated/resources/assets/create/models/item/crushed_platinum_ore.json deleted file mode 100644 index 6b2d3a4a1f..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_platinum_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_platinum_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_quicksilver_ore.json b/src/generated/resources/assets/create/models/item/crushed_quicksilver_ore.json deleted file mode 100644 index 755ae5489b..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_quicksilver_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_quicksilver_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_aluminum.json b/src/generated/resources/assets/create/models/item/crushed_raw_aluminum.json new file mode 100644 index 0000000000..f5e02b9dca --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_aluminum.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_aluminum" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_copper.json b/src/generated/resources/assets/create/models/item/crushed_raw_copper.json new file mode 100644 index 0000000000..e5d40a25d4 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_copper.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_copper" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_gold.json b/src/generated/resources/assets/create/models/item/crushed_raw_gold.json new file mode 100644 index 0000000000..fe99490a1b --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_gold.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_gold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_iron.json b/src/generated/resources/assets/create/models/item/crushed_raw_iron.json new file mode 100644 index 0000000000..a8daf7cd1b --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_iron.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_iron" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_lead.json b/src/generated/resources/assets/create/models/item/crushed_raw_lead.json new file mode 100644 index 0000000000..320d9ffe25 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_lead.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_lead" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_nickel.json b/src/generated/resources/assets/create/models/item/crushed_raw_nickel.json new file mode 100644 index 0000000000..ef46ce7346 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_nickel.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_nickel" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_osmium.json b/src/generated/resources/assets/create/models/item/crushed_raw_osmium.json new file mode 100644 index 0000000000..e763e37945 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_osmium.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_osmium" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_platinum.json b/src/generated/resources/assets/create/models/item/crushed_raw_platinum.json new file mode 100644 index 0000000000..ce40617e96 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_platinum.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_platinum" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_quicksilver.json b/src/generated/resources/assets/create/models/item/crushed_raw_quicksilver.json new file mode 100644 index 0000000000..2898054765 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_quicksilver.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_quicksilver" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_silver.json b/src/generated/resources/assets/create/models/item/crushed_raw_silver.json new file mode 100644 index 0000000000..a7e28cfbce --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_silver.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_silver" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_tin.json b/src/generated/resources/assets/create/models/item/crushed_raw_tin.json new file mode 100644 index 0000000000..de7e794551 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_tin.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_tin" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_uranium.json b/src/generated/resources/assets/create/models/item/crushed_raw_uranium.json new file mode 100644 index 0000000000..d1e4707430 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_uranium.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_uranium" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_raw_zinc.json b/src/generated/resources/assets/create/models/item/crushed_raw_zinc.json new file mode 100644 index 0000000000..97a98e7e62 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/crushed_raw_zinc.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/crushed_raw_zinc" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_silver_ore.json b/src/generated/resources/assets/create/models/item/crushed_silver_ore.json deleted file mode 100644 index 98054fe180..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_silver_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_silver_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_tin_ore.json b/src/generated/resources/assets/create/models/item/crushed_tin_ore.json deleted file mode 100644 index 6e0bb6e653..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_tin_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_tin_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_uranium_ore.json b/src/generated/resources/assets/create/models/item/crushed_uranium_ore.json deleted file mode 100644 index b377d5915a..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_uranium_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_uranium_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushed_zinc_ore.json b/src/generated/resources/assets/create/models/item/crushed_zinc_ore.json deleted file mode 100644 index ee85115fcc..0000000000 --- a/src/generated/resources/assets/create/models/item/crushed_zinc_ore.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/crushed_zinc_ore" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/crushing_wheel.json b/src/generated/resources/assets/create/models/item/crushing_wheel.json index 5a8ad33624..872fef2b00 100644 --- a/src/generated/resources/assets/create/models/item/crushing_wheel.json +++ b/src/generated/resources/assets/create/models/item/crushing_wheel.json @@ -1,3 +1,3 @@ { - "parent": "create:block/crushing_wheel" + "parent": "create:block/crushing_wheel/item" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/diving_boots.json b/src/generated/resources/assets/create/models/item/diving_boots.json deleted file mode 100644 index 88c9dccb58..0000000000 --- a/src/generated/resources/assets/create/models/item/diving_boots.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/diving_boots" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/diving_helmet.json b/src/generated/resources/assets/create/models/item/diving_helmet.json deleted file mode 100644 index f287c2ca8b..0000000000 --- a/src/generated/resources/assets/create/models/item/diving_helmet.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "create:item/diving_helmet" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/elevator_contact.json b/src/generated/resources/assets/create/models/item/elevator_contact.json new file mode 100644 index 0000000000..50fc0dfa99 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/elevator_contact.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/elevator_contact/block" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/elevator_pulley.json b/src/generated/resources/assets/create/models/item/elevator_pulley.json new file mode 100644 index 0000000000..df00e5656e --- /dev/null +++ b/src/generated/resources/assets/create/models/item/elevator_pulley.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/elevator_pulley/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/experience_block.json b/src/generated/resources/assets/create/models/item/experience_block.json new file mode 100644 index 0000000000..450f5d371c --- /dev/null +++ b/src/generated/resources/assets/create/models/item/experience_block.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/experience_block" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/filter.json b/src/generated/resources/assets/create/models/item/filter.json new file mode 100644 index 0000000000..584b3303f1 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/filter.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/filter" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/industrial_iron_block.json b/src/generated/resources/assets/create/models/item/industrial_iron_block.json new file mode 100644 index 0000000000..5938f808ec --- /dev/null +++ b/src/generated/resources/assets/create/models/item/industrial_iron_block.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/industrial_iron_block" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/large_water_wheel.json b/src/generated/resources/assets/create/models/item/large_water_wheel.json new file mode 100644 index 0000000000..e4beac8d75 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/large_water_wheel.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/large_water_wheel/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/limestone.json b/src/generated/resources/assets/create/models/item/limestone.json index 450a981f7c..4e8cd81fa3 100644 --- a/src/generated/resources/assets/create/models/item/limestone.json +++ b/src/generated/resources/assets/create/models/item/limestone.json @@ -1,3 +1,6 @@ { - "parent": "create:block/limestone" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/limestone" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/mechanical_roller.json b/src/generated/resources/assets/create/models/item/mechanical_roller.json new file mode 100644 index 0000000000..fc689e02a9 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/mechanical_roller.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/mechanical_roller/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/netherite_backtank.json b/src/generated/resources/assets/create/models/item/netherite_backtank.json new file mode 100644 index 0000000000..267a98e101 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/netherite_backtank.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/netherite_backtank/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/netherite_backtank_placeable.json b/src/generated/resources/assets/create/models/item/netherite_backtank_placeable.json new file mode 100644 index 0000000000..ff77c281bd --- /dev/null +++ b/src/generated/resources/assets/create/models/item/netherite_backtank_placeable.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/barrier" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/netherite_diving_boots.json b/src/generated/resources/assets/create/models/item/netherite_diving_boots.json new file mode 100644 index 0000000000..ed1728d3f6 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/netherite_diving_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/netherite_diving_boots" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/netherite_diving_helmet.json b/src/generated/resources/assets/create/models/item/netherite_diving_helmet.json new file mode 100644 index 0000000000..fde66a4b63 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/netherite_diving_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "create:item/netherite_diving_helmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/ochrum.json b/src/generated/resources/assets/create/models/item/ochrum.json index 9d6f5b134a..c765a7db25 100644 --- a/src/generated/resources/assets/create/models/item/ochrum.json +++ b/src/generated/resources/assets/create/models/item/ochrum.json @@ -1,3 +1,6 @@ { - "parent": "create:block/ochrum" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/ochrum_1" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/scorchia.json b/src/generated/resources/assets/create/models/item/scorchia.json index b4fee0dd1e..29730b192b 100644 --- a/src/generated/resources/assets/create/models/item/scorchia.json +++ b/src/generated/resources/assets/create/models/item/scorchia.json @@ -1,3 +1,6 @@ { - "parent": "create:block/scorchia" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/scorchia" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/scoria.json b/src/generated/resources/assets/create/models/item/scoria.json index f1fc1af406..cf031beeda 100644 --- a/src/generated/resources/assets/create/models/item/scoria.json +++ b/src/generated/resources/assets/create/models/item/scoria.json @@ -1,3 +1,6 @@ { - "parent": "create:block/scoria" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/scoria" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/stockpile_switch.json b/src/generated/resources/assets/create/models/item/stockpile_switch.json index 3e623a7d5e..8455dde8be 100644 --- a/src/generated/resources/assets/create/models/item/stockpile_switch.json +++ b/src/generated/resources/assets/create/models/item/stockpile_switch.json @@ -1,3 +1,3 @@ { - "parent": "create:block/stockpile_switch" + "parent": "create:block/threshold_switch/block_wall" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/veridium.json b/src/generated/resources/assets/create/models/item/veridium.json index 5391052db7..52e7c814df 100644 --- a/src/generated/resources/assets/create/models/item/veridium.json +++ b/src/generated/resources/assets/create/models/item/veridium.json @@ -1,3 +1,6 @@ { - "parent": "create:block/veridium" + "parent": "minecraft:block/cube_all", + "textures": { + "all": "create:block/palettes/stone_types/natural/veridium_1" + } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/water_wheel.json b/src/generated/resources/assets/create/models/item/water_wheel.json index 1fe80c21b2..5b83b2a7e2 100644 --- a/src/generated/resources/assets/create/models/item/water_wheel.json +++ b/src/generated/resources/assets/create/models/item/water_wheel.json @@ -1,3 +1,3 @@ { - "parent": "create:block/water_wheel" + "parent": "create:block/water_wheel/item" } \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/windmill_bearing.json b/src/generated/resources/assets/create/models/item/windmill_bearing.json index 434880d44d..f9365a5a64 100644 --- a/src/generated/resources/assets/create/models/item/windmill_bearing.json +++ b/src/generated/resources/assets/create/models/item/windmill_bearing.json @@ -1,7 +1,7 @@ { "parent": "create:block/bearing/item", "textures": { - "top": "create:block/bearing_top_wooden", + "top": "create:block/bearing_top", "side": "create:block/windmill_bearing_side", "back": "create:block/gearbox" } diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_0.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_0.json new file mode 100644 index 0000000000..f5da60e995 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_0.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_1.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_1.json new file mode 100644 index 0000000000..77d321740c --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_1.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_2.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_2.json new file mode 100644 index 0000000000..041c46a2d6 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_2.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_3.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_3.json new file mode 100644 index 0000000000..8ccaf704a8 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_3.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_4.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_4.json new file mode 100644 index 0000000000..fc36e6d52d --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_4.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_4" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_5.json b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_5.json new file mode 100644 index 0000000000..b708eae938 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_ceiling_5.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_ceiling", + "textures": { + "level": "create:block/threshold_switch/level_5" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_0.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_0.json new file mode 100644 index 0000000000..2fff31978d --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_0.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_1.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_1.json new file mode 100644 index 0000000000..9ecd2edad1 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_1.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_2.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_2.json new file mode 100644 index 0000000000..f9fa8d1375 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_2.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_3.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_3.json new file mode 100644 index 0000000000..1166633589 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_3.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_4.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_4.json new file mode 100644 index 0000000000..b2e82e522d --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_4.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_4" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_floor_5.json b/src/generated/resources/assets/create/models/threshold_switch/block_floor_5.json new file mode 100644 index 0000000000..7a8bc7ac33 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_floor_5.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_floor", + "textures": { + "level": "create:block/threshold_switch/level_5" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_0.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_0.json new file mode 100644 index 0000000000..e602f46ef8 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_0.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_0" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_1.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_1.json new file mode 100644 index 0000000000..f4fa237f59 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_1.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_1" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_2.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_2.json new file mode 100644 index 0000000000..7c489af9ca --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_2.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_2" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_3.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_3.json new file mode 100644 index 0000000000..1ac6d64dd9 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_3.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_3" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_4.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_4.json new file mode 100644 index 0000000000..79047ddc64 --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_4.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_4" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/threshold_switch/block_wall_5.json b/src/generated/resources/assets/create/models/threshold_switch/block_wall_5.json new file mode 100644 index 0000000000..8e5ea3d59a --- /dev/null +++ b/src/generated/resources/assets/create/models/threshold_switch/block_wall_5.json @@ -0,0 +1,6 @@ +{ + "parent": "create:block/threshold_switch/block_wall", + "textures": { + "level": "create:block/threshold_switch/level_5" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/diving_suit.json b/src/generated/resources/data/create/advancements/diving_suit.json index 94db68db5e..aec7ce96e5 100644 --- a/src/generated/resources/data/create/advancements/diving_suit.json +++ b/src/generated/resources/data/create/advancements/diving_suit.json @@ -2,7 +2,7 @@ "parent": "create:backtank", "display": { "icon": { - "item": "create:diving_helmet", + "item": "create:copper_diving_helmet", "nbt": "{Damage:0}" }, "title": { diff --git a/src/generated/resources/data/create/advancements/diving_suit_lava.json b/src/generated/resources/data/create/advancements/diving_suit_lava.json index 9f8b1630e8..0c888be2c2 100644 --- a/src/generated/resources/data/create/advancements/diving_suit_lava.json +++ b/src/generated/resources/data/create/advancements/diving_suit_lava.json @@ -2,7 +2,7 @@ "parent": "create:backtank", "display": { "icon": { - "item": "create:diving_helmet", + "item": "create:copper_diving_helmet", "nbt": "{Damage:0}" }, "title": { diff --git a/src/generated/resources/data/create/advancements/long_bend.json b/src/generated/resources/data/create/advancements/long_bend.json deleted file mode 100644 index 5b6f5f5138..0000000000 --- a/src/generated/resources/data/create/advancements/long_bend.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "parent": "create:track_crafting_factory", - "display": { - "icon": { - "item": "create:track" - }, - "title": { - "translate": "advancement.create.long_bend" - }, - "description": { - "color": "#DBA213", - "translate": "advancement.create.long_bend.desc" - }, - "frame": "goal", - "show_toast": true, - "announce_to_chat": true, - "hidden": false - }, - "criteria": { - "0": { - "trigger": "create:long_bend_builtin", - "conditions": {} - } - }, - "requirements": [ - [ - "0" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/long_train.json b/src/generated/resources/data/create/advancements/long_train.json index e72513d0a9..83ff7a6611 100644 --- a/src/generated/resources/data/create/advancements/long_train.json +++ b/src/generated/resources/data/create/advancements/long_train.json @@ -1,5 +1,5 @@ { - "parent": "create:long_bend", + "parent": "create:track_crafting_factory", "display": { "icon": { "item": "minecraft:minecart" diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/andesite_from_stone_types_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/andesite_from_stone_types_andesite_stonecutting.json new file mode 100644 index 0000000000..e5a74ac795 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/andesite_from_stone_types_andesite_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:andesite_from_stone_types_andesite_stonecutting" + ] + }, + "criteria": { + "has_stone_types_andesite": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/andesite" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:andesite_from_stone_types_andesite_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_andesite", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_aluminum_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_aluminum_compat_immersiveengineering.json index 6f521810f7..2d96f3f540 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_aluminum_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_aluminum_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_aluminum_ore" + "create:crushed_raw_aluminum" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_immersiveengineering.json index 48d676edc9..c449b144f0 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_mekanism.json index fb079e8224..19e0e7a37a 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_lead_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_nickel_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_nickel_compat_immersiveengineering.json index bee8d616e4..8c57da8b1c 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_nickel_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_nickel_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_nickel_ore" + "create:crushed_raw_nickel" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_osmium_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_osmium_compat_mekanism.json index 7b6dd7a2ce..3f85547eb3 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_osmium_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_osmium_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_osmium_ore" + "create:crushed_raw_osmium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_silver_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_silver_compat_immersiveengineering.json index 3027c62e89..c71f9e73c4 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_silver_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_silver_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_silver_ore" + "create:crushed_raw_silver" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_tin_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_tin_compat_mekanism.json index 7ba1b16a10..687e360041 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_tin_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_tin_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_tin_ore" + "create:crushed_raw_tin" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_immersiveengineering.json index 1a19aba036..12ad305c00 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_uranium_ore" + "create:crushed_raw_uranium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_mekanism.json index fb4c40a54e..d6c9377f22 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/ingot_uranium_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_uranium_ore" + "create:crushed_raw_uranium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_thermal.json index 192da7c444..4d6f44d6b7 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/lead_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/nickel_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/nickel_ingot_compat_thermal.json index e2b7f8675c..a7e397cbec 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/nickel_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/nickel_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_nickel_ore" + "create:crushed_raw_nickel" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/silver_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/silver_ingot_compat_thermal.json index 3d4c891511..c032257ff9 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/silver_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/silver_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_silver_ore" + "create:crushed_raw_silver" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/tin_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/tin_ingot_compat_thermal.json index e78a4efcb9..222f5c7546 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/tin_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/blasting/tin_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_tin_ore" + "create:crushed_raw_tin" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/calcite_from_stone_types_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/calcite_from_stone_types_calcite_stonecutting.json new file mode 100644 index 0000000000..4209196e2a --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/calcite_from_stone_types_calcite_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:calcite_from_stone_types_calcite_stonecutting" + ] + }, + "criteria": { + "has_stone_types_calcite": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/calcite" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:calcite_from_stone_types_calcite_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_calcite", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/deepslate_from_stone_types_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/deepslate_from_stone_types_deepslate_stonecutting.json new file mode 100644 index 0000000000..0156209b93 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/deepslate_from_stone_types_deepslate_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:deepslate_from_stone_types_deepslate_stonecutting" + ] + }, + "criteria": { + "has_stone_types_deepslate": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/deepslate" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:deepslate_from_stone_types_deepslate_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_deepslate", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/diorite_from_stone_types_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/diorite_from_stone_types_diorite_stonecutting.json new file mode 100644 index 0000000000..1868b2520e --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/diorite_from_stone_types_diorite_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:diorite_from_stone_types_diorite_stonecutting" + ] + }, + "criteria": { + "has_stone_types_diorite": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/diorite" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:diorite_from_stone_types_diorite_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_diorite", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/dripstone_block_from_stone_types_dripstone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/dripstone_block_from_stone_types_dripstone_stonecutting.json new file mode 100644 index 0000000000..fa1fa6473c --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/dripstone_block_from_stone_types_dripstone_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:dripstone_block_from_stone_types_dripstone_stonecutting" + ] + }, + "criteria": { + "has_stone_types_dripstone": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/dripstone" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:dripstone_block_from_stone_types_dripstone_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_dripstone", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/granite_from_stone_types_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/granite_from_stone_types_granite_stonecutting.json new file mode 100644 index 0000000000..d8a912cbe2 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/granite_from_stone_types_granite_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:granite_from_stone_types_granite_stonecutting" + ] + }, + "criteria": { + "has_stone_types_granite": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/granite" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:granite_from_stone_types_granite_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_granite", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_aluminum_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_aluminum_compat_immersiveengineering.json index 7cb734e7eb..700f02dd46 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_aluminum_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_aluminum_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_aluminum_ore" + "create:crushed_raw_aluminum" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_immersiveengineering.json index 333607787d..07c0187ad9 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_mekanism.json index 97b3d81c6f..a1361014ef 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_lead_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_nickel_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_nickel_compat_immersiveengineering.json index 71f3b1364c..71e8533d6c 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_nickel_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_nickel_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_nickel_ore" + "create:crushed_raw_nickel" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_osmium_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_osmium_compat_mekanism.json index 45ba4cfeba..9a3d3c66de 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_osmium_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_osmium_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_osmium_ore" + "create:crushed_raw_osmium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_silver_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_silver_compat_immersiveengineering.json index f62583777f..af5b762e2b 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_silver_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_silver_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_silver_ore" + "create:crushed_raw_silver" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_tin_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_tin_compat_mekanism.json index 8d70b59fcb..a566036002 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_tin_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_tin_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_tin_ore" + "create:crushed_raw_tin" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_immersiveengineering.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_immersiveengineering.json index b19eb08706..a354caa5d3 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_immersiveengineering.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_uranium_ore" + "create:crushed_raw_uranium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_mekanism.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_mekanism.json index d298d23466..2c35aabd0a 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_mekanism.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/ingot_uranium_compat_mekanism.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_uranium_ore" + "create:crushed_raw_uranium" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_thermal.json index d3b5bb2e56..f42553df93 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/lead_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_lead_ore" + "create:crushed_raw_lead" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/nickel_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/nickel_ingot_compat_thermal.json index 2e64a986c6..21067c14d7 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/nickel_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/nickel_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_nickel_ore" + "create:crushed_raw_nickel" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/silver_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/silver_ingot_compat_thermal.json index 8afd81c735..0be1a29d25 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/silver_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/silver_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_silver_ore" + "create:crushed_raw_silver" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/tin_ingot_compat_thermal.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/tin_ingot_compat_thermal.json index e986d06ee9..2217438cd6 100644 --- a/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/tin_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/smelting/tin_ingot_compat_thermal.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_tin_ore" + "create:crushed_raw_tin" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/building_blocks/tuff_from_stone_types_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/building_blocks/tuff_from_stone_types_tuff_stonecutting.json new file mode 100644 index 0000000000..36b9b22731 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/building_blocks/tuff_from_stone_types_tuff_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:tuff_from_stone_types_tuff_stonecutting" + ] + }, + "criteria": { + "has_stone_types_tuff": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/tuff" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:tuff_from_stone_types_tuff_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_tuff", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/blasting/zinc_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/create.base/blasting/zinc_ingot_from_crushed.json index 5a6615cea4..dc05126598 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/blasting/zinc_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/create.base/blasting/zinc_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_zinc_ore" + "create:crushed_raw_zinc" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/brass_ladder_from_plates_brass_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.base/brass_ladder_from_plates_brass_stonecutting.json deleted file mode 100644 index ddc2829a2e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/brass_ladder_from_plates_brass_stonecutting.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:brass_ladder_from_plates_brass_stonecutting" - ] - }, - "criteria": { - "has_plates_brass": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "forge:plates/brass" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:brass_ladder_from_plates_brass_stonecutting" - } - } - }, - "requirements": [ - [ - "has_plates_brass", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_ladder_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.base/copper_ladder_from_plates_copper_stonecutting.json deleted file mode 100644 index 800bc8e650..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/copper_ladder_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:copper_ladder_from_plates_copper_stonecutting" - ] - }, - "criteria": { - "has_plates_copper": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "forge:plates/copper" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:copper_ladder_from_plates_copper_stonecutting" - } - } - }, - "requirements": [ - [ - "has_plates_copper", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingles_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingles_from_plates_copper_stonecutting.json deleted file mode 100644 index 64d071eb2b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingles_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:copper_shingles_from_plates_copper_stonecutting" - ] - }, - "criteria": { - "has_plates_copper": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "forge:plates/copper" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:copper_shingles_from_plates_copper_stonecutting" - } - } - }, - "requirements": [ - [ - "has_plates_copper", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tiles_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.base/copper_tiles_from_plates_copper_stonecutting.json deleted file mode 100644 index 2f9c65d0d9..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tiles_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:copper_tiles_from_plates_copper_stonecutting" - ] - }, - "criteria": { - "has_plates_copper": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "tag": "forge:plates/copper" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:copper_tiles_from_plates_copper_stonecutting" - } - } - }, - "requirements": [ - [ - "has_plates_copper", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/attribute_filter_clear.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/attribute_filter_clear.json new file mode 100644 index 0000000000..810c51962f --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/attribute_filter_clear.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/attribute_filter_clear" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:attribute_filter" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/attribute_filter_clear" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json new file mode 100644 index 0000000000..98fd323616 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/clipboard" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/clipboard" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json new file mode 100644 index 0000000000..39d0e338d5 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/clipboard_clear" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:clipboard" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/clipboard_clear" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_boots.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_boots.json new file mode 100644 index 0000000000..d2a401732c --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_boots.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/copper_diving_boots" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:copper_ingot" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/copper_diving_boots" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_helmet.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_helmet.json new file mode 100644 index 0000000000..36cadac5d9 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_helmet.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/copper_diving_helmet" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:copper_ingot" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/copper_diving_helmet" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_boots.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_boots.json deleted file mode 100644 index d0d7f07e10..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_boots.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/appliances/diving_boots" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:copper_ingot" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/appliances/diving_boots" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_helmet.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_helmet.json deleted file mode 100644 index 5491317c85..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/diving_helmet.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/appliances/diving_helmet" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:copper_ingot" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/appliances/diving_helmet" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/filter_clear.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/filter_clear.json new file mode 100644 index 0000000000..0eb037350d --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/filter_clear.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/filter_clear" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:filter" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/filter_clear" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank.json new file mode 100644 index 0000000000..ebb5d2ee65 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_backtank" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:copper_backtank" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_backtank" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank_from_netherite.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank_from_netherite.json new file mode 100644 index 0000000000..b65a4ed695 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_backtank_from_netherite.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_backtank_from_netherite" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:netherite_chestplate" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_backtank_from_netherite" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots.json new file mode 100644 index 0000000000..c6e3aec852 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_diving_boots" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:copper_diving_boots" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_diving_boots" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots_from_netherite.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots_from_netherite.json new file mode 100644 index 0000000000..0a74df9797 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_boots_from_netherite.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_diving_boots_from_netherite" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:netherite_boots" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_diving_boots_from_netherite" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet.json new file mode 100644 index 0000000000..450a9ca49e --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_diving_helmet" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:copper_diving_helmet" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_diving_helmet" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet_from_netherite.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet_from_netherite.json new file mode 100644 index 0000000000..ec5ee2750f --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/netherite_diving_helmet_from_netherite.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/netherite_diving_helmet_from_netherite" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "minecraft:netherite_helmet" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/netherite_diving_helmet_from_netherite" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/schedule_clear.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/schedule_clear.json new file mode 100644 index 0000000000..dbb5fe2fb4 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/schedule_clear.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/schedule_clear" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:schedule" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/schedule_clear" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/andesite_ladder.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/andesite_ladder.json deleted file mode 100644 index 12c07d7006..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/andesite_ladder.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/kinetics/andesite_ladder" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:andesite_alloy" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/kinetics/andesite_ladder" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/contraption_controls.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/contraption_controls.json new file mode 100644 index 0000000000..69e0835f18 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/contraption_controls.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/contraption_controls" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/contraption_controls" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/elevator_pulley.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/elevator_pulley.json new file mode 100644 index 0000000000..d6d780eed6 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/elevator_pulley.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/elevator_pulley" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/brass" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/elevator_pulley" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheel_from_little.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheel_from_little.json new file mode 100644 index 0000000000..f0735db631 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheel_from_little.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/large_cogwheel_from_little" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/large_cogwheel_from_little" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheelfrom_little.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheelfrom_little.json deleted file mode 100644 index d711440e9e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_cogwheelfrom_little.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/kinetics/large_cogwheelfrom_little" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:andesite_alloy" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/kinetics/large_cogwheelfrom_little" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_water_wheel.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_water_wheel.json new file mode 100644 index 0000000000..76a30dec6b --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/large_water_wheel.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/large_water_wheel" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:water_wheel" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/large_water_wheel" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/mechanical_roller.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/mechanical_roller.json new file mode 100644 index 0000000000..f7cbf0bc2e --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/mechanical_roller.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/mechanical_roller" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_casing" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/mechanical_roller" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observer.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observer.json index 0d7b867479..3d2320e595 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observer.json +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observer.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:belt_connector" + "create:brass_casing" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observerfrom_conversion.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observerfrom_conversion.json deleted file mode 100644 index 69c294f671..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/content_observerfrom_conversion.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/logistics/content_observerfrom_conversion" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:stockpile_switch" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/logistics/content_observerfrom_conversion" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switch.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switch.json new file mode 100644 index 0000000000..ad1c6d7a22 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switch.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/logistics/stockpile_switch" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:brass_casing" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/logistics/stockpile_switch" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switchfrom_conversion.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switchfrom_conversion.json deleted file mode 100644 index 47a6612158..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/logistics/stockpile_switchfrom_conversion.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crafting/logistics/stockpile_switchfrom_conversion" - ] - }, - "criteria": { - "has_item": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:content_observer" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crafting/logistics/stockpile_switchfrom_conversion" - } - } - }, - "requirements": [ - [ - "has_item", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/andesite_alloy_from_block.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/andesite_alloy_from_block.json new file mode 100644 index 0000000000..572469d388 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/andesite_alloy_from_block.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/materials/andesite_alloy_from_block" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/materials/andesite_alloy_from_block" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/experience_nugget_from_block.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/experience_nugget_from_block.json new file mode 100644 index 0000000000..cd7cdb595f --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/experience_nugget_from_block.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/materials/experience_nugget_from_block" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:experience_nugget" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/materials/experience_nugget_from_block" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/smelting/zinc_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/create.base/smelting/zinc_ingot_from_crushed.json index 928af90e11..d6050bfda9 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/smelting/zinc_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/create.base/smelting/zinc_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_zinc_ore" + "create:crushed_raw_zinc" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_bars_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_bars_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..e523f3ecfe --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_bars_from_andesite_alloy_stonecutting.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:andesite_bars_from_andesite_alloy_stonecutting" + ] + }, + "criteria": { + "has_andesite_alloy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:andesite_bars_from_andesite_alloy_stonecutting" + } + } + }, + "requirements": [ + [ + "has_andesite_alloy", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_ladder_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_ladder_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..be1be477bf --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_ladder_from_andesite_alloy_stonecutting.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:andesite_ladder_from_andesite_alloy_stonecutting" + ] + }, + "criteria": { + "has_andesite_alloy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:andesite_ladder_from_andesite_alloy_stonecutting" + } + } + }, + "requirements": [ + [ + "has_andesite_alloy", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_pillar_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_pillar_from_andesite_stonecutting.json deleted file mode 100644 index a4f9d9172d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_pillar_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:andesite_pillar_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:andesite_pillar_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_scaffolding_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_scaffolding_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..8950f06208 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/andesite_scaffolding_from_andesite_alloy_stonecutting.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:andesite_scaffolding_from_andesite_alloy_stonecutting" + ] + }, + "criteria": { + "has_andesite_alloy": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:andesite_scaffolding_from_andesite_alloy_stonecutting" + } + } + }, + "requirements": [ + [ + "has_andesite_alloy", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_from_stone_types_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_from_stone_types_asurine_stonecutting.json new file mode 100644 index 0000000000..5e47532c27 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_from_stone_types_asurine_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:asurine_from_stone_types_asurine_stonecutting" + ] + }, + "criteria": { + "has_stone_types_asurine": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/asurine" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:asurine_from_stone_types_asurine_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_asurine", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_pillar_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_pillar_from_asurine_stonecutting.json deleted file mode 100644 index 8be2182f93..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/asurine_pillar_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:asurine_pillar_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:asurine_pillar_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_bars_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_bars_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..deabf22a22 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_bars_from_ingots_brass_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:brass_bars_from_ingots_brass_stonecutting" + ] + }, + "criteria": { + "has_ingots_brass": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/brass" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:brass_bars_from_ingots_brass_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_brass", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_ladder_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_ladder_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..f72b210a46 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_ladder_from_ingots_brass_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:brass_ladder_from_ingots_brass_stonecutting" + ] + }, + "criteria": { + "has_ingots_brass": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/brass" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:brass_ladder_from_ingots_brass_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_brass", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_scaffolding_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_scaffolding_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..ed3d4c252f --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/brass_scaffolding_from_ingots_brass_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:brass_scaffolding_from_ingots_brass_stonecutting" + ] + }, + "criteria": { + "has_ingots_brass": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/brass" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:brass_scaffolding_from_ingots_brass_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_brass", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/calcite_pillar_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/calcite_pillar_from_calcite_stonecutting.json deleted file mode 100644 index 84a79a6510..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/calcite_pillar_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:calcite_pillar_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:calcite_pillar_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_bars_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_bars_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..15ba528899 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_bars_from_ingots_copper_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copper_bars_from_ingots_copper_stonecutting" + ] + }, + "criteria": { + "has_ingots_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copper_bars_from_ingots_copper_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_ladder_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_ladder_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..9c1dc3f96e --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_ladder_from_ingots_copper_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copper_ladder_from_ingots_copper_stonecutting" + ] + }, + "criteria": { + "has_ingots_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copper_ladder_from_ingots_copper_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_scaffolding_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_scaffolding_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..6c18ef0321 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_scaffolding_from_ingots_copper_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copper_scaffolding_from_ingots_copper_stonecutting" + ] + }, + "criteria": { + "has_ingots_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copper_scaffolding_from_ingots_copper_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_slab_from_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_slab_from_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_slab_from_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_slab_from_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_stairs_from_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_stairs_from_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_shingle_stairs_from_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingle_stairs_from_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingles_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingles_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..993ffab95b --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_shingles_from_ingots_copper_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copper_shingles_from_ingots_copper_stonecutting" + ] + }, + "criteria": { + "has_ingots_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copper_shingles_from_ingots_copper_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_slab_from_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_slab_from_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_slab_from_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_slab_from_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_stairs_from_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_stairs_from_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/copper_tile_stairs_from_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tile_stairs_from_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tiles_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tiles_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..bd3b1c94ff --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copper_tiles_from_ingots_copper_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copper_tiles_from_ingots_copper_stonecutting" + ] + }, + "criteria": { + "has_ingots_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copper_tiles_from_ingots_copper_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_panel_from_ingots_zinc_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_panel_from_ingots_zinc_stonecutting.json new file mode 100644 index 0000000000..7ffe13c45c --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_panel_from_ingots_zinc_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copycat_panel_from_ingots_zinc_stonecutting" + ] + }, + "criteria": { + "has_ingots_zinc": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/zinc" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copycat_panel_from_ingots_zinc_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_zinc", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_step_from_ingots_zinc_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_step_from_ingots_zinc_stonecutting.json new file mode 100644 index 0000000000..6c9fca18a7 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/copycat_step_from_ingots_zinc_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:copycat_step_from_ingots_zinc_stonecutting" + ] + }, + "criteria": { + "has_ingots_zinc": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/zinc" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:copycat_step_from_ingots_zinc_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_zinc", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingle_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingle_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingle_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingle_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingle_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingle_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingle_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingle_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_shingles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_shingles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tile_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tile_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tile_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tile_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tile_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tile_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tile_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tile_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tiles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tiles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_copper_tiles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_copper_tiles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingle_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingle_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingle_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingle_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingle_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingle_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingle_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingle_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_shingles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_shingles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tile_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tile_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tile_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tile_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tile_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tile_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tile_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tile_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tiles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tiles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_exposed_copper_tiles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_exposed_copper_tiles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingle_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingle_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingle_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingle_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingle_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingle_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingle_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingle_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_shingles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_shingles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tile_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tile_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tile_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tile_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tile_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tile_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tile_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tile_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tiles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tiles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_oxidized_copper_tiles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_oxidized_copper_tiles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingle_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingle_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingle_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingle_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingle_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingle_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingle_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingle_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_shingles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_shingles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tile_slab_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tile_slab_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tile_slab_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tile_slab_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tile_stairs_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tile_stairs_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tile_stairs_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tile_stairs_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tiles_from_honeycomb.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tiles_from_honeycomb.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/copper/waxed_weathered_copper_tiles_from_honeycomb.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/copper/waxed_weathered_copper_tiles_from_honeycomb.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/andesite_door.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/andesite_door.json new file mode 100644 index 0000000000..788f511756 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/andesite_door.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/andesite_door" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_casing" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/andesite_door" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/black_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/black_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/black_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/black_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/black_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/black_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/black_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/black_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/blue_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/blue_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/blue_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/blue_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/blue_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/blue_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/blue_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/blue_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brass_door.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brass_door.json new file mode 100644 index 0000000000..a035e3d3ab --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brass_door.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/brass_door" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:brass_casing" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/brass_door" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/brown_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brown_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/brown_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brown_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/brown_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brown_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/brown_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/brown_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/copper_door.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/copper_door.json new file mode 100644 index 0000000000..4ab980502a --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/copper_door.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/kinetics/copper_door" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:copper_casing" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/kinetics/copper_door" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/cyan_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/cyan_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/cyan_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/cyan_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/cyan_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/cyan_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/cyan_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/cyan_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/framed_glass_door.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/framed_glass_door.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/framed_glass_door.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/framed_glass_door.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/framed_glass_trapdoor.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/framed_glass_trapdoor.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/framed_glass_trapdoor.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/framed_glass_trapdoor.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gray_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/gray_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gray_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/gray_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gray_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/gray_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/gray_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/gray_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/green_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/green_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/green_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/green_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/green_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/green_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/green_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/green_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_blue_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_blue_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_blue_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_blue_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_blue_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_blue_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_blue_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_blue_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_gray_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_gray_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_gray_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_gray_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_gray_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_gray_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/light_gray_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/light_gray_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/lime_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/lime_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/lime_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/lime_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/lime_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/lime_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/lime_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/lime_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/magenta_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/magenta_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/magenta_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/magenta_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/magenta_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/magenta_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/magenta_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/magenta_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/metal_girder.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/metal_girder.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/metal_girder.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/metal_girder.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/orange_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/orange_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/orange_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/orange_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/orange_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/orange_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/orange_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/orange_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/pink_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/pink_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/pink_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/pink_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/pink_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/pink_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/pink_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/pink_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/purple_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/purple_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/purple_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/purple_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/purple_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/purple_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/purple_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/purple_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/red_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/red_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/red_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/red_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/red_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/red_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/red_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/red_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_door.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_door.json similarity index 87% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_door.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_door.json index 05cc6e7ee2..fba5220b63 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_door.json +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_door.json @@ -11,7 +11,9 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": [ + "create:railway_casing" + ] } ] } diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_trapdoor.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_trapdoor.json similarity index 88% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_trapdoor.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_trapdoor.json index 92ffc3e355..fd9965815f 100644 --- a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/train_trapdoor.json +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/train_trapdoor.json @@ -11,7 +11,9 @@ "conditions": { "items": [ { - "tag": "forge:ingots/brass" + "items": [ + "create:railway_casing" + ] } ] } diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/white_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/white_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/white_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/white_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/white_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/white_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/white_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/white_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/yellow_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/yellow_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/yellow_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/yellow_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/yellow_seat_from_other_seat.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/yellow_seat_from_other_seat.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/kinetics/yellow_seat_from_other_seat.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/kinetics/yellow_seat_from_other_seat.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/andesite_alloy_block.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/andesite_alloy_block.json new file mode 100644 index 0000000000..697029168d --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/andesite_alloy_block.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/materials/andesite_alloy_block" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/materials/andesite_alloy_block" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/brass_block_from_compacting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/brass_block_from_compacting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/brass_block_from_compacting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/brass_block_from_compacting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/experience_block.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/experience_block.json new file mode 100644 index 0000000000..41d286ae4e --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/experience_block.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/materials/experience_block" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:experience_nugget" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/materials/experience_block" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/raw_zinc_block.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/raw_zinc_block.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/raw_zinc_block.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/raw_zinc_block.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/rose_quartz_tilesfrom_conversion.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/rose_quartz_tilesfrom_conversion.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/rose_quartz_tilesfrom_conversion.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/rose_quartz_tilesfrom_conversion.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/small_rose_quartz_tilesfrom_conversion.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/small_rose_quartz_tilesfrom_conversion.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/small_rose_quartz_tilesfrom_conversion.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/small_rose_quartz_tilesfrom_conversion.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/zinc_block_from_compacting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/zinc_block_from_compacting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/crafting/materials/zinc_block_from_compacting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/crafting/materials/zinc_block_from_compacting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_from_stone_types_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_from_stone_types_crimsite_stonecutting.json new file mode 100644 index 0000000000..5b1f4e2cdd --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_from_stone_types_crimsite_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crimsite_from_stone_types_crimsite_stonecutting" + ] + }, + "criteria": { + "has_stone_types_crimsite": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/crimsite" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crimsite_from_stone_types_crimsite_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_crimsite", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_pillar_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_pillar_from_crimsite_stonecutting.json deleted file mode 100644 index 6a01356b1d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/crimsite_pillar_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:crimsite_pillar_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:crimsite_pillar_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_slab_from_andesite_stonecutting.json deleted file mode 100644 index 0949343015..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_brick_slab_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_brick_slab_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_stairs_from_andesite_stonecutting.json deleted file mode 100644 index 208c6d444f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_brick_stairs_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_brick_stairs_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_wall_from_andesite_stonecutting.json deleted file mode 100644 index 7b68b59a59..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_brick_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_brick_wall_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_brick_wall_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_bricks_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_bricks_from_andesite_stonecutting.json deleted file mode 100644 index abf56affe3..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_bricks_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_bricks_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_bricks_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_from_andesite_stonecutting.json deleted file mode 100644 index 220a7fac5f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_slab_from_andesite_stonecutting.json deleted file mode 100644 index cb19842be5..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_slab_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_slab_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_stairs_from_andesite_stonecutting.json deleted file mode 100644 index edbb6af145..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_stairs_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_stairs_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_wall_from_andesite_stonecutting.json deleted file mode 100644 index fbe3c478c8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_andesite_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_andesite_wall_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_andesite_wall_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_slab_from_asurine_stonecutting.json deleted file mode 100644 index 05d36a6717..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_brick_slab_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_brick_slab_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_stairs_from_asurine_stonecutting.json deleted file mode 100644 index cd7f26cef4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_brick_stairs_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_brick_stairs_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_wall_from_asurine_stonecutting.json deleted file mode 100644 index 2bc73db5d0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_brick_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_brick_wall_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_brick_wall_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_bricks_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_bricks_from_asurine_stonecutting.json deleted file mode 100644 index 2f412e1c96..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_bricks_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_bricks_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_bricks_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_from_asurine_stonecutting.json deleted file mode 100644 index 72b7bf93c2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_slab_from_asurine_stonecutting.json deleted file mode 100644 index c688db959a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_slab_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_slab_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_stairs_from_asurine_stonecutting.json deleted file mode 100644 index 1d527f78b8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_stairs_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_stairs_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_wall_from_asurine_stonecutting.json deleted file mode 100644 index 24894adb7a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_asurine_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_asurine_wall_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_asurine_wall_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_slab_from_calcite_stonecutting.json deleted file mode 100644 index 53cab3c7d6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_brick_slab_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_brick_slab_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 3f876b5c46..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_brick_stairs_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_brick_stairs_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_wall_from_calcite_stonecutting.json deleted file mode 100644 index 74342d5db4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_brick_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_brick_wall_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_brick_wall_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_bricks_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_bricks_from_calcite_stonecutting.json deleted file mode 100644 index 9c6cb8b76f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_bricks_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_bricks_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_bricks_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_from_calcite_stonecutting.json deleted file mode 100644 index d4ac877a90..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_slab_from_calcite_stonecutting.json deleted file mode 100644 index a2e68e6123..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_slab_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_slab_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 4d8cdbd4ea..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_stairs_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_stairs_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_wall_from_calcite_stonecutting.json deleted file mode 100644 index b10d80de72..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_calcite_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_calcite_wall_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_calcite_wall_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json deleted file mode 100644 index e6b5f0699d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_brick_slab_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_brick_slab_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index 5b2543642b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_brick_stairs_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_brick_stairs_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json deleted file mode 100644 index df9e0e0c3f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_brick_wall_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_brick_wall_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_bricks_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_bricks_from_crimsite_stonecutting.json deleted file mode 100644 index 1acde8a292..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_bricks_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_bricks_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_bricks_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index 9afecc71a2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_slab_from_crimsite_stonecutting.json deleted file mode 100644 index 252eb6220e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_slab_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_slab_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index e7d5dec3ec..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_stairs_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_stairs_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_wall_from_crimsite_stonecutting.json deleted file mode 100644 index 45beacec04..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_crimsite_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_crimsite_wall_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_crimsite_wall_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 8f444eeeb4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_brick_slab_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_brick_slab_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index e768d7aebe..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_brick_stairs_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_brick_stairs_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json deleted file mode 100644 index 35a4b27b31..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_brick_wall_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_brick_wall_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_bricks_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_bricks_from_deepslate_stonecutting.json deleted file mode 100644 index 7acdb528c5..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_bricks_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_bricks_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_bricks_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index dd447a8760..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_slab_from_deepslate_stonecutting.json deleted file mode 100644 index d0e2af559e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_slab_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_slab_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index 522aba1436..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_stairs_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_stairs_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_wall_from_deepslate_stonecutting.json deleted file mode 100644 index 280b623657..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_deepslate_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_deepslate_wall_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_deepslate_wall_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_slab_from_diorite_stonecutting.json deleted file mode 100644 index b4f9ff683e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_brick_slab_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_brick_slab_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_stairs_from_diorite_stonecutting.json deleted file mode 100644 index 583a7003ab..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_brick_stairs_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_brick_stairs_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_wall_from_diorite_stonecutting.json deleted file mode 100644 index 360c4cb3fe..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_brick_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_brick_wall_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_brick_wall_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_bricks_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_bricks_from_diorite_stonecutting.json deleted file mode 100644 index 889a63760d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_bricks_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_bricks_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_bricks_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_from_diorite_stonecutting.json deleted file mode 100644 index 7f59bc5c26..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_slab_from_diorite_stonecutting.json deleted file mode 100644 index 46583eae51..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_slab_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_slab_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_stairs_from_diorite_stonecutting.json deleted file mode 100644 index d96d2f5f2a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_stairs_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_stairs_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_wall_from_diorite_stonecutting.json deleted file mode 100644 index 53a1c4335e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_diorite_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_diorite_wall_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_diorite_wall_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index b74720e084..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_brick_slab_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_brick_slab_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 78791c3a38..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_brick_stairs_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_brick_stairs_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index b0ce97485e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_brick_wall_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_brick_wall_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json deleted file mode 100644 index 44d76a70b6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_bricks_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_bricks_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index 01e79ef278..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 41941d9b22..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_slab_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_slab_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 929ab3e58e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_stairs_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_stairs_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 22dca90c24..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_dripstone_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_dripstone_wall_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_dripstone_wall_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_slab_from_granite_stonecutting.json deleted file mode 100644 index 4babd88f59..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_brick_slab_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_brick_slab_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_stairs_from_granite_stonecutting.json deleted file mode 100644 index e9e94d20ec..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_brick_stairs_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_brick_stairs_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_wall_from_granite_stonecutting.json deleted file mode 100644 index 6b875b323a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_brick_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_brick_wall_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_brick_wall_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_bricks_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_bricks_from_granite_stonecutting.json deleted file mode 100644 index d1b9976651..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_bricks_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_bricks_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_bricks_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_from_granite_stonecutting.json deleted file mode 100644 index c7bb64f927..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_slab_from_granite_stonecutting.json deleted file mode 100644 index 9c1638d400..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_slab_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_slab_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_stairs_from_granite_stonecutting.json deleted file mode 100644 index 33289253f1..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_stairs_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_stairs_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_wall_from_granite_stonecutting.json deleted file mode 100644 index eafec08b47..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_granite_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_granite_wall_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_granite_wall_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_slab_from_limestone_stonecutting.json deleted file mode 100644 index a520e929a2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_brick_slab_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_brick_slab_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_stairs_from_limestone_stonecutting.json deleted file mode 100644 index ad29f86818..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_brick_stairs_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_brick_stairs_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_wall_from_limestone_stonecutting.json deleted file mode 100644 index 5a149f6ff4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_brick_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_brick_wall_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_brick_wall_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_bricks_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_bricks_from_limestone_stonecutting.json deleted file mode 100644 index 9513454a2b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_bricks_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_bricks_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_bricks_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_from_limestone_stonecutting.json deleted file mode 100644 index dcaac28811..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_slab_from_limestone_stonecutting.json deleted file mode 100644 index 3cba1d9c8b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_slab_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_slab_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_stairs_from_limestone_stonecutting.json deleted file mode 100644 index e119fb372b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_stairs_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_stairs_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_wall_from_limestone_stonecutting.json deleted file mode 100644 index 1f61024c98..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_limestone_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_limestone_wall_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_limestone_wall_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json deleted file mode 100644 index c3050f4657..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_brick_slab_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_brick_slab_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index cca046fe29..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_brick_stairs_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_brick_stairs_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json deleted file mode 100644 index 7c615e08bb..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_brick_wall_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_brick_wall_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_bricks_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_bricks_from_ochrum_stonecutting.json deleted file mode 100644 index 0f7af819f2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_bricks_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_bricks_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_bricks_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index 0b8d11ac02..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_slab_from_ochrum_stonecutting.json deleted file mode 100644 index aeb7629c81..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_slab_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_slab_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index 5a80f24c49..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_stairs_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_stairs_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_wall_from_ochrum_stonecutting.json deleted file mode 100644 index 9692e6bc78..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_ochrum_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_ochrum_wall_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_ochrum_wall_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json deleted file mode 100644 index 88465cda0b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_brick_slab_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_brick_slab_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index a54cb74b20..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_brick_stairs_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_brick_stairs_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 805ea2c070..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_brick_wall_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_brick_wall_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_bricks_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_bricks_from_scorchia_stonecutting.json deleted file mode 100644 index e8262ca7bf..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_bricks_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_bricks_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_bricks_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index 24af46b932..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_slab_from_scorchia_stonecutting.json deleted file mode 100644 index e0d4059d24..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_slab_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_slab_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 952fa9370f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_stairs_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_stairs_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 38ed60cb84..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scorchia_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scorchia_wall_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scorchia_wall_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_slab_from_scoria_stonecutting.json deleted file mode 100644 index 93fa0f6d27..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_brick_slab_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_brick_slab_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_stairs_from_scoria_stonecutting.json deleted file mode 100644 index 040dc36fd0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_brick_stairs_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_brick_stairs_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_wall_from_scoria_stonecutting.json deleted file mode 100644 index 5e69150d7d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_brick_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_brick_wall_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_brick_wall_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_bricks_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_bricks_from_scoria_stonecutting.json deleted file mode 100644 index 132f936523..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_bricks_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_bricks_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_bricks_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_from_scoria_stonecutting.json deleted file mode 100644 index 6006518570..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_slab_from_scoria_stonecutting.json deleted file mode 100644 index 3deda71ded..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_slab_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_slab_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_stairs_from_scoria_stonecutting.json deleted file mode 100644 index ff2547c8cc..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_stairs_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_stairs_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_wall_from_scoria_stonecutting.json deleted file mode 100644 index 23a3643315..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_scoria_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_scoria_wall_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_scoria_wall_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_slab_from_tuff_stonecutting.json deleted file mode 100644 index 9a98892436..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_brick_slab_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_brick_slab_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_stairs_from_tuff_stonecutting.json deleted file mode 100644 index 59fc13f054..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_brick_stairs_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_brick_stairs_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_wall_from_tuff_stonecutting.json deleted file mode 100644 index 57698d86d7..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_brick_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_brick_wall_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_brick_wall_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_bricks_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_bricks_from_tuff_stonecutting.json deleted file mode 100644 index 81dc00d890..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_bricks_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_bricks_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_bricks_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_from_tuff_stonecutting.json deleted file mode 100644 index eb3982c81f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_slab_from_tuff_stonecutting.json deleted file mode 100644 index 5c760a3586..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_slab_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_slab_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_stairs_from_tuff_stonecutting.json deleted file mode 100644 index 1267eb0b2e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_stairs_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_stairs_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_wall_from_tuff_stonecutting.json deleted file mode 100644 index 6f9a0e5adc..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_tuff_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_tuff_wall_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_tuff_wall_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_slab_from_veridium_stonecutting.json deleted file mode 100644 index a014591283..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_brick_slab_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_brick_slab_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_stairs_from_veridium_stonecutting.json deleted file mode 100644 index e1bdfba6aa..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_brick_stairs_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_brick_stairs_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_wall_from_veridium_stonecutting.json deleted file mode 100644 index 7bfa4583f6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_brick_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_brick_wall_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_brick_wall_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_bricks_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_bricks_from_veridium_stonecutting.json deleted file mode 100644 index f341998915..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_bricks_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_bricks_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_bricks_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 4d659430c9..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_slab_from_veridium_stonecutting.json deleted file mode 100644 index 2ae77157f6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_slab_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_slab_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_stairs_from_veridium_stonecutting.json deleted file mode 100644 index 7636c43806..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_stairs_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_stairs_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_wall_from_veridium_stonecutting.json deleted file mode 100644 index 18231b30f4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/cut_veridium_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:cut_veridium_wall_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:cut_veridium_wall_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/deepslate_pillar_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/deepslate_pillar_from_deepslate_stonecutting.json deleted file mode 100644 index a4f2b67ff0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/deepslate_pillar_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:deepslate_pillar_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:deepslate_pillar_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/diorite_pillar_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/diorite_pillar_from_diorite_stonecutting.json deleted file mode 100644 index b877d76957..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/diorite_pillar_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:diorite_pillar_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:diorite_pillar_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/dripstone_pillar_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/dripstone_pillar_from_dripstone_block_stonecutting.json deleted file mode 100644 index f6e7f1a918..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/dripstone_pillar_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:dripstone_pillar_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:dripstone_pillar_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_slab_from_exposed_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_slab_from_exposed_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_slab_from_exposed_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_slab_from_exposed_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_stairs_from_exposed_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_stairs_from_exposed_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_shingle_stairs_from_exposed_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_shingle_stairs_from_exposed_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_slab_from_exposed_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_slab_from_exposed_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_slab_from_exposed_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_slab_from_exposed_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_stairs_from_exposed_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_stairs_from_exposed_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/exposed_copper_tile_stairs_from_exposed_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/exposed_copper_tile_stairs_from_exposed_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/granite_pillar_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/granite_pillar_from_granite_stonecutting.json deleted file mode 100644 index 1f642455fd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/granite_pillar_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:granite_pillar_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:granite_pillar_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/industrial_iron_block_from_ingots_iron_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/industrial_iron_block_from_ingots_iron_stonecutting.json new file mode 100644 index 0000000000..642513ff02 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/industrial_iron_block_from_ingots_iron_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:industrial_iron_block_from_ingots_iron_stonecutting" + ] + }, + "criteria": { + "has_ingots_iron": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/iron" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:industrial_iron_block_from_ingots_iron_stonecutting" + } + } + }, + "requirements": [ + [ + "has_ingots_iron", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_andesite_from_andesite_stonecutting.json deleted file mode 100644 index 789772e552..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_andesite_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_andesite_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_asurine_from_asurine_stonecutting.json deleted file mode 100644 index 11bef8018c..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_asurine_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_asurine_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_calcite_from_calcite_stonecutting.json deleted file mode 100644 index 57f947a930..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_calcite_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_calcite_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index 5277e69bcf..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_crimsite_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_crimsite_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index 08d0e13aa0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_deepslate_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_deepslate_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_diorite_from_diorite_stonecutting.json deleted file mode 100644 index 4ec75b65a4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_diorite_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_diorite_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index 121758f704..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_dripstone_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_dripstone_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_granite_from_granite_stonecutting.json deleted file mode 100644 index ce7f5fbf5f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_granite_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_granite_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_limestone_from_limestone_stonecutting.json deleted file mode 100644 index edc38bbb52..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_limestone_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_limestone_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index b14f4a6940..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_ochrum_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_ochrum_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index 3b368b77aa..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_scorchia_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_scorchia_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scoria_from_scoria_stonecutting.json deleted file mode 100644 index 3ffabe6a81..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_scoria_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_scoria_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_tuff_from_tuff_stonecutting.json deleted file mode 100644 index 20a0c792a9..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_tuff_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_tuff_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 0832e7591c..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/layered_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:layered_veridium_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:layered_veridium_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_from_stone_types_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_from_stone_types_limestone_stonecutting.json new file mode 100644 index 0000000000..0a77e0a6cd --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_from_stone_types_limestone_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:limestone_from_stone_types_limestone_stonecutting" + ] + }, + "criteria": { + "has_stone_types_limestone": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/limestone" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:limestone_from_stone_types_limestone_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_limestone", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_pillar_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_pillar_from_limestone_stonecutting.json deleted file mode 100644 index a44df03394..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/limestone_pillar_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:limestone_pillar_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:limestone_pillar_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_from_stone_types_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_from_stone_types_ochrum_stonecutting.json new file mode 100644 index 0000000000..361d8de6b1 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_from_stone_types_ochrum_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:ochrum_from_stone_types_ochrum_stonecutting" + ] + }, + "criteria": { + "has_stone_types_ochrum": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/ochrum" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:ochrum_from_stone_types_ochrum_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_ochrum", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_pillar_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_pillar_from_ochrum_stonecutting.json deleted file mode 100644 index f8bc77356c..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/ochrum_pillar_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:ochrum_pillar_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:ochrum_pillar_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_slab_from_oxidized_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_slab_from_oxidized_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_slab_from_oxidized_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_slab_from_oxidized_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_stairs_from_oxidized_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_stairs_from_oxidized_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_shingle_stairs_from_oxidized_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_shingle_stairs_from_oxidized_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_slab_from_oxidized_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_slab_from_oxidized_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_slab_from_oxidized_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_slab_from_oxidized_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_stairs_from_oxidized_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_stairs_from_oxidized_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/oxidized_copper_tile_stairs_from_oxidized_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/oxidized_copper_tile_stairs_from_oxidized_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_from_andesite_stonecutting.json deleted file mode 100644 index ea9aff3e12..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_andesite_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_andesite_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_slab_from_andesite_stonecutting.json deleted file mode 100644 index cf4802c6b8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_andesite_slab_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_andesite_slab_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_stairs_from_andesite_stonecutting.json deleted file mode 100644 index f3b3c4b64d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_andesite_stairs_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_andesite_stairs_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_wall_from_andesite_stonecutting.json deleted file mode 100644 index 63b071b714..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_andesite_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_andesite_wall_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_andesite_wall_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_from_asurine_stonecutting.json deleted file mode 100644 index cb5da4e4f7..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_asurine_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_asurine_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_slab_from_asurine_stonecutting.json deleted file mode 100644 index 3c2b0f9254..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_asurine_slab_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_asurine_slab_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_stairs_from_asurine_stonecutting.json deleted file mode 100644 index 599cf193e6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_asurine_stairs_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_asurine_stairs_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_wall_from_asurine_stonecutting.json deleted file mode 100644 index 08af2c8ded..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_asurine_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_asurine_wall_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_asurine_wall_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_from_calcite_stonecutting.json deleted file mode 100644 index 1077d2f778..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_calcite_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_calcite_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_slab_from_calcite_stonecutting.json deleted file mode 100644 index 331fce65dd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_calcite_slab_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_calcite_slab_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 233f000182..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_calcite_stairs_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_calcite_stairs_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_wall_from_calcite_stonecutting.json deleted file mode 100644 index 42569f37d7..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_calcite_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_calcite_wall_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_calcite_wall_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index f161bfc845..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_crimsite_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_crimsite_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json deleted file mode 100644 index 90222aafd8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_crimsite_slab_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_crimsite_slab_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index fdea741be2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_crimsite_stairs_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_crimsite_stairs_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json deleted file mode 100644 index be5ef977bc..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_crimsite_wall_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_crimsite_wall_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index 22a8afd2bd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_deepslate_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_deepslate_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 3f71eb85d9..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_deepslate_slab_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_deepslate_slab_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index 37bca81176..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_deepslate_stairs_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_deepslate_stairs_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json deleted file mode 100644 index 8de38d8210..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_deepslate_wall_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_deepslate_wall_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_from_diorite_stonecutting.json deleted file mode 100644 index 981f9e986d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_diorite_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_diorite_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_slab_from_diorite_stonecutting.json deleted file mode 100644 index e03db2ea54..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_diorite_slab_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_diorite_slab_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_stairs_from_diorite_stonecutting.json deleted file mode 100644 index f7166d8067..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_diorite_stairs_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_diorite_stairs_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_wall_from_diorite_stonecutting.json deleted file mode 100644 index 8d300039c1..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_diorite_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_diorite_wall_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_diorite_wall_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index 735de46b41..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_dripstone_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_dripstone_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 0502e9f5f7..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_dripstone_slab_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_dripstone_slab_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 41d573fa5f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_dripstone_stairs_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_dripstone_stairs_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 0991098b1d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_dripstone_wall_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_dripstone_wall_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_from_granite_stonecutting.json deleted file mode 100644 index b672949756..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_granite_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_granite_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_slab_from_granite_stonecutting.json deleted file mode 100644 index 432eb458dc..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_granite_slab_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_granite_slab_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_stairs_from_granite_stonecutting.json deleted file mode 100644 index 3d8565b535..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_granite_stairs_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_granite_stairs_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_wall_from_granite_stonecutting.json deleted file mode 100644 index 8032bc1cbe..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_granite_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_granite_wall_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_granite_wall_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_from_limestone_stonecutting.json deleted file mode 100644 index 5a668cfc25..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_limestone_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_limestone_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_slab_from_limestone_stonecutting.json deleted file mode 100644 index d9c02a88bd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_limestone_slab_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_limestone_slab_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_stairs_from_limestone_stonecutting.json deleted file mode 100644 index 53b0c712af..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_limestone_stairs_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_limestone_stairs_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_wall_from_limestone_stonecutting.json deleted file mode 100644 index b72b04ae16..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_limestone_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_limestone_wall_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_limestone_wall_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index bf0d48b3bf..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_ochrum_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_ochrum_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json deleted file mode 100644 index 086164b873..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_ochrum_slab_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_ochrum_slab_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index 0518050bff..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_ochrum_stairs_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_ochrum_stairs_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json deleted file mode 100644 index ede44d5a56..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_ochrum_wall_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_ochrum_wall_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index a97b3935c5..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scorchia_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scorchia_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json deleted file mode 100644 index 67d80340e4..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scorchia_slab_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scorchia_slab_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 39fd9ef38e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scorchia_stairs_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scorchia_stairs_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 9a4267bc8d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scorchia_wall_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scorchia_wall_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_from_scoria_stonecutting.json deleted file mode 100644 index 80ba3e063f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scoria_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scoria_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_slab_from_scoria_stonecutting.json deleted file mode 100644 index f0f3db1734..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scoria_slab_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scoria_slab_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_stairs_from_scoria_stonecutting.json deleted file mode 100644 index 4b9d143200..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scoria_stairs_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scoria_stairs_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_wall_from_scoria_stonecutting.json deleted file mode 100644 index 2c8302353a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_scoria_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_scoria_wall_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_scoria_wall_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_from_tuff_stonecutting.json deleted file mode 100644 index b9b878f262..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_tuff_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_tuff_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_slab_from_tuff_stonecutting.json deleted file mode 100644 index d03ac6230b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_tuff_slab_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_tuff_slab_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_stairs_from_tuff_stonecutting.json deleted file mode 100644 index f27fb779ac..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_tuff_stairs_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_tuff_stairs_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_wall_from_tuff_stonecutting.json deleted file mode 100644 index 9e62c38f52..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_tuff_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_tuff_wall_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_tuff_wall_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 0a47a6596b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_veridium_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_veridium_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_slab_from_veridium_stonecutting.json deleted file mode 100644 index 6b79272405..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_veridium_slab_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_veridium_slab_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_stairs_from_veridium_stonecutting.json deleted file mode 100644 index bc292d8627..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_veridium_stairs_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_veridium_stairs_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_wall_from_veridium_stonecutting.json deleted file mode 100644 index 9b3196d868..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/polished_cut_veridium_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:polished_cut_veridium_wall_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:polished_cut_veridium_wall_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/rose_quartz_block_from_rose_quartz_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/rose_quartz_block_from_rose_quartz_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/rose_quartz_block_from_rose_quartz_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/rose_quartz_block_from_rose_quartz_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_from_stone_types_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_from_stone_types_scorchia_stonecutting.json new file mode 100644 index 0000000000..890e681f41 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_from_stone_types_scorchia_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:scorchia_from_stone_types_scorchia_stonecutting" + ] + }, + "criteria": { + "has_stone_types_scorchia": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/scorchia" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:scorchia_from_stone_types_scorchia_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_scorchia", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_pillar_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_pillar_from_scorchia_stonecutting.json deleted file mode 100644 index 6b31a2cf36..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/scorchia_pillar_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:scorchia_pillar_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:scorchia_pillar_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_from_stone_types_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_from_stone_types_scoria_stonecutting.json new file mode 100644 index 0000000000..be2edf2eca --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_from_stone_types_scoria_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:scoria_from_stone_types_scoria_stonecutting" + ] + }, + "criteria": { + "has_stone_types_scoria": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/scoria" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:scoria_from_stone_types_scoria_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_scoria", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_pillar_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_pillar_from_scoria_stonecutting.json deleted file mode 100644 index 6a262a2930..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/scoria_pillar_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:scoria_pillar_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:scoria_pillar_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_slab_from_andesite_stonecutting.json deleted file mode 100644 index feaa082e7e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_andesite_brick_slab_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_andesite_brick_slab_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_stairs_from_andesite_stonecutting.json deleted file mode 100644 index 9aebaaaaf0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_andesite_brick_stairs_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_andesite_brick_stairs_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_wall_from_andesite_stonecutting.json deleted file mode 100644 index 2788f52e03..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_brick_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_andesite_brick_wall_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_andesite_brick_wall_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_bricks_from_andesite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_bricks_from_andesite_stonecutting.json deleted file mode 100644 index 7cd184cf0d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_andesite_bricks_from_andesite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_andesite_bricks_from_andesite_stonecutting" - ] - }, - "criteria": { - "has_andesite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:andesite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_andesite_bricks_from_andesite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_andesite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_slab_from_asurine_stonecutting.json deleted file mode 100644 index 701a77baf0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_asurine_brick_slab_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_asurine_brick_slab_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_stairs_from_asurine_stonecutting.json deleted file mode 100644 index a8caac7dce..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_asurine_brick_stairs_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_asurine_brick_stairs_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_wall_from_asurine_stonecutting.json deleted file mode 100644 index 4596c0d26b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_brick_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_asurine_brick_wall_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_asurine_brick_wall_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_bricks_from_asurine_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_bricks_from_asurine_stonecutting.json deleted file mode 100644 index cbc5609603..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_asurine_bricks_from_asurine_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_asurine_bricks_from_asurine_stonecutting" - ] - }, - "criteria": { - "has_asurine": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:asurine" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_asurine_bricks_from_asurine_stonecutting" - } - } - }, - "requirements": [ - [ - "has_asurine", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_slab_from_calcite_stonecutting.json deleted file mode 100644 index e52d7c3d30..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_calcite_brick_slab_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_calcite_brick_slab_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 9ec834dc94..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_calcite_brick_stairs_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_calcite_brick_stairs_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_wall_from_calcite_stonecutting.json deleted file mode 100644 index 96bf88393b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_brick_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_calcite_brick_wall_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_calcite_brick_wall_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_bricks_from_calcite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_bricks_from_calcite_stonecutting.json deleted file mode 100644 index e49d4ffbe1..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_calcite_bricks_from_calcite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_calcite_bricks_from_calcite_stonecutting" - ] - }, - "criteria": { - "has_calcite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:calcite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_calcite_bricks_from_calcite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_calcite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_slab_from_crimsite_stonecutting.json deleted file mode 100644 index 49cf8ff572..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_crimsite_brick_slab_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_crimsite_brick_slab_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index f4faec4384..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_crimsite_brick_stairs_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_crimsite_brick_stairs_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_wall_from_crimsite_stonecutting.json deleted file mode 100644 index e038a8d46c..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_brick_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_crimsite_brick_wall_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_crimsite_brick_wall_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_bricks_from_crimsite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_bricks_from_crimsite_stonecutting.json deleted file mode 100644 index b9f70fab70..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_crimsite_bricks_from_crimsite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_crimsite_bricks_from_crimsite_stonecutting" - ] - }, - "criteria": { - "has_crimsite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:crimsite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_crimsite_bricks_from_crimsite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_crimsite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_slab_from_deepslate_stonecutting.json deleted file mode 100644 index b99e39c653..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_deepslate_brick_slab_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_deepslate_brick_slab_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index f85c41b108..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_deepslate_brick_stairs_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_deepslate_brick_stairs_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_wall_from_deepslate_stonecutting.json deleted file mode 100644 index c10de08767..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_brick_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_deepslate_brick_wall_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_deepslate_brick_wall_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_bricks_from_deepslate_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_bricks_from_deepslate_stonecutting.json deleted file mode 100644 index 7f05d39814..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_deepslate_bricks_from_deepslate_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_deepslate_bricks_from_deepslate_stonecutting" - ] - }, - "criteria": { - "has_deepslate": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:deepslate" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_deepslate_bricks_from_deepslate_stonecutting" - } - } - }, - "requirements": [ - [ - "has_deepslate", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_slab_from_diorite_stonecutting.json deleted file mode 100644 index a2ae56672f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_diorite_brick_slab_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_diorite_brick_slab_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_stairs_from_diorite_stonecutting.json deleted file mode 100644 index 8ac40e7fbb..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_diorite_brick_stairs_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_diorite_brick_stairs_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_wall_from_diorite_stonecutting.json deleted file mode 100644 index 25216a3a6b..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_brick_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_diorite_brick_wall_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_diorite_brick_wall_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_bricks_from_diorite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_bricks_from_diorite_stonecutting.json deleted file mode 100644 index 2c41cb1ffc..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_diorite_bricks_from_diorite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_diorite_bricks_from_diorite_stonecutting" - ] - }, - "criteria": { - "has_diorite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:diorite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_diorite_bricks_from_diorite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_diorite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 123b2a1c3c..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_dripstone_brick_slab_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_dripstone_brick_slab_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 196d7e83fd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_dripstone_brick_stairs_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_dripstone_brick_stairs_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index f56f88e87a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_dripstone_brick_wall_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_dripstone_brick_wall_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_bricks_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_bricks_from_dripstone_block_stonecutting.json deleted file mode 100644 index b25bc0273a..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_dripstone_bricks_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_dripstone_bricks_from_dripstone_block_stonecutting" - ] - }, - "criteria": { - "has_dripstone_block": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:dripstone_block" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_dripstone_bricks_from_dripstone_block_stonecutting" - } - } - }, - "requirements": [ - [ - "has_dripstone_block", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_slab_from_granite_stonecutting.json deleted file mode 100644 index 448a1281c8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_granite_brick_slab_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_granite_brick_slab_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_stairs_from_granite_stonecutting.json deleted file mode 100644 index b94dee5d13..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_granite_brick_stairs_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_granite_brick_stairs_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_wall_from_granite_stonecutting.json deleted file mode 100644 index 1a21db1fba..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_brick_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_granite_brick_wall_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_granite_brick_wall_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_bricks_from_granite_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_bricks_from_granite_stonecutting.json deleted file mode 100644 index 3516f8901e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_granite_bricks_from_granite_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_granite_bricks_from_granite_stonecutting" - ] - }, - "criteria": { - "has_granite": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:granite" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_granite_bricks_from_granite_stonecutting" - } - } - }, - "requirements": [ - [ - "has_granite", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_slab_from_limestone_stonecutting.json deleted file mode 100644 index 0334cd87af..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_limestone_brick_slab_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_limestone_brick_slab_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_stairs_from_limestone_stonecutting.json deleted file mode 100644 index 81614ac7c0..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_limestone_brick_stairs_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_limestone_brick_stairs_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_wall_from_limestone_stonecutting.json deleted file mode 100644 index 32849e4584..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_brick_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_limestone_brick_wall_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_limestone_brick_wall_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_bricks_from_limestone_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_bricks_from_limestone_stonecutting.json deleted file mode 100644 index c26c260bc2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_limestone_bricks_from_limestone_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_limestone_bricks_from_limestone_stonecutting" - ] - }, - "criteria": { - "has_limestone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:limestone" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_limestone_bricks_from_limestone_stonecutting" - } - } - }, - "requirements": [ - [ - "has_limestone", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_slab_from_ochrum_stonecutting.json deleted file mode 100644 index 26ce8727bb..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_ochrum_brick_slab_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_ochrum_brick_slab_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index 720edfbd87..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_ochrum_brick_stairs_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_ochrum_brick_stairs_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_wall_from_ochrum_stonecutting.json deleted file mode 100644 index 3d82c26705..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_brick_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_ochrum_brick_wall_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_ochrum_brick_wall_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_bricks_from_ochrum_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_bricks_from_ochrum_stonecutting.json deleted file mode 100644 index 6faac45975..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_ochrum_bricks_from_ochrum_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_ochrum_bricks_from_ochrum_stonecutting" - ] - }, - "criteria": { - "has_ochrum": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:ochrum" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_ochrum_bricks_from_ochrum_stonecutting" - } - } - }, - "requirements": [ - [ - "has_ochrum", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/small_rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/small_rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/small_rose_quartz_tiles_from_polished_rose_quartz_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_slab_from_scorchia_stonecutting.json deleted file mode 100644 index 8af10ef4a2..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scorchia_brick_slab_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scorchia_brick_slab_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 2f827bd09e..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scorchia_brick_stairs_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scorchia_brick_stairs_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_wall_from_scorchia_stonecutting.json deleted file mode 100644 index ea64aff984..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_brick_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scorchia_brick_wall_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scorchia_brick_wall_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_bricks_from_scorchia_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_bricks_from_scorchia_stonecutting.json deleted file mode 100644 index 6f906cffb9..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scorchia_bricks_from_scorchia_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scorchia_bricks_from_scorchia_stonecutting" - ] - }, - "criteria": { - "has_scorchia": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scorchia" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scorchia_bricks_from_scorchia_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scorchia", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_slab_from_scoria_stonecutting.json deleted file mode 100644 index 5a018c6d0f..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scoria_brick_slab_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scoria_brick_slab_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_stairs_from_scoria_stonecutting.json deleted file mode 100644 index 5fdfa995fb..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scoria_brick_stairs_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scoria_brick_stairs_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_wall_from_scoria_stonecutting.json deleted file mode 100644 index 61aa8b0f26..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_brick_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scoria_brick_wall_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scoria_brick_wall_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_bricks_from_scoria_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_bricks_from_scoria_stonecutting.json deleted file mode 100644 index 9398cf4fc8..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_scoria_bricks_from_scoria_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_scoria_bricks_from_scoria_stonecutting" - ] - }, - "criteria": { - "has_scoria": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:scoria" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_scoria_bricks_from_scoria_stonecutting" - } - } - }, - "requirements": [ - [ - "has_scoria", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_slab_from_tuff_stonecutting.json deleted file mode 100644 index d9499e4062..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_tuff_brick_slab_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_tuff_brick_slab_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_stairs_from_tuff_stonecutting.json deleted file mode 100644 index 1cc30e2ffd..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_tuff_brick_stairs_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_tuff_brick_stairs_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_wall_from_tuff_stonecutting.json deleted file mode 100644 index 6930cc6193..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_brick_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_tuff_brick_wall_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_tuff_brick_wall_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_bricks_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_bricks_from_tuff_stonecutting.json deleted file mode 100644 index e7898bd8c6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_tuff_bricks_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_tuff_bricks_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_tuff_bricks_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_slab_from_veridium_stonecutting.json deleted file mode 100644 index 9222560289..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_veridium_brick_slab_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_veridium_brick_slab_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_stairs_from_veridium_stonecutting.json deleted file mode 100644 index 9a1f27fbd6..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_veridium_brick_stairs_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_veridium_brick_stairs_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_wall_from_veridium_stonecutting.json deleted file mode 100644 index 87dce1fe5d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_brick_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_veridium_brick_wall_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_veridium_brick_wall_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_bricks_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_bricks_from_veridium_stonecutting.json deleted file mode 100644 index 04cdbefb16..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/small_veridium_bricks_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:small_veridium_bricks_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:small_veridium_bricks_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/tuff_pillar_from_tuff_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/tuff_pillar_from_tuff_stonecutting.json deleted file mode 100644 index 36e1535baf..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/tuff_pillar_from_tuff_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:tuff_pillar_from_tuff_stonecutting" - ] - }, - "criteria": { - "has_tuff": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "minecraft:tuff" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:tuff_pillar_from_tuff_stonecutting" - } - } - }, - "requirements": [ - [ - "has_tuff", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_from_stone_types_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_from_stone_types_veridium_stonecutting.json new file mode 100644 index 0000000000..85f39eb259 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_from_stone_types_veridium_stonecutting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:veridium_from_stone_types_veridium_stonecutting" + ] + }, + "criteria": { + "has_stone_types_veridium": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "create:stone_types/veridium" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:veridium_from_stone_types_veridium_stonecutting" + } + } + }, + "requirements": [ + [ + "has_stone_types_veridium", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_pillar_from_veridium_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_pillar_from_veridium_stonecutting.json deleted file mode 100644 index cac898c96d..0000000000 --- a/src/generated/resources/data/create/advancements/recipes/create.palettes/veridium_pillar_from_veridium_stonecutting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "create:veridium_pillar_from_veridium_stonecutting" - ] - }, - "criteria": { - "has_veridium": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "create:veridium" - ] - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "create:veridium_pillar_from_veridium_stonecutting" - } - } - }, - "requirements": [ - [ - "has_veridium", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_slab_from_weathered_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_slab_from_weathered_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_slab_from_weathered_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_slab_from_weathered_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_stairs_from_weathered_copper_shingles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_stairs_from_weathered_copper_shingles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_shingle_stairs_from_weathered_copper_shingles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_shingle_stairs_from_weathered_copper_shingles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_slab.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_slab.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_slab.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_slab.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_slab_from_weathered_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_slab_from_weathered_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_slab_from_weathered_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_slab_from_weathered_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_stairs.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_stairs.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_stairs.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_stairs.json diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json b/src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json similarity index 100% rename from src/generated/resources/data/create/advancements/recipes/create.base/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json rename to src/generated/resources/data/create/advancements/recipes/create.palettes/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json diff --git a/src/generated/resources/data/create/advancements/recipes/misc/blasting/copper_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/blasting/copper_ingot_from_crushed.json index a0bc54c8a1..09f877883d 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/blasting/copper_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/blasting/copper_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_copper_ore" + "create:crushed_raw_copper" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/misc/blasting/gold_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/blasting/gold_ingot_from_crushed.json index 48c26f0c13..69d8816da1 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/blasting/gold_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/blasting/gold_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_gold_ore" + "create:crushed_raw_gold" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/misc/blasting/iron_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/blasting/iron_ingot_from_crushed.json index 784ded85f3..e76b967dd5 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/blasting/iron_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/blasting/iron_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_iron_ore" + "create:crushed_raw_iron" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/misc/smelting/copper_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/smelting/copper_ingot_from_crushed.json index ce73863740..a73ecd0d76 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/smelting/copper_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/smelting/copper_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_copper_ore" + "create:crushed_raw_copper" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/misc/smelting/gold_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/smelting/gold_ingot_from_crushed.json index fcdcd01cde..a8a4376b33 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/smelting/gold_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/smelting/gold_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_gold_ore" + "create:crushed_raw_gold" ] } ] diff --git a/src/generated/resources/data/create/advancements/recipes/misc/smelting/iron_ingot_from_crushed.json b/src/generated/resources/data/create/advancements/recipes/misc/smelting/iron_ingot_from_crushed.json index 500eee1e9b..7a239a0730 100644 --- a/src/generated/resources/data/create/advancements/recipes/misc/smelting/iron_ingot_from_crushed.json +++ b/src/generated/resources/data/create/advancements/recipes/misc/smelting/iron_ingot_from_crushed.json @@ -12,7 +12,7 @@ "items": [ { "items": [ - "create:crushed_iron_ore" + "create:crushed_raw_iron" ] } ] diff --git a/src/generated/resources/data/create/loot_tables/blocks/andesite_alloy_block.json b/src/generated/resources/data/create/loot_tables/blocks/andesite_alloy_block.json new file mode 100644 index 0000000000..5fb5603d2d --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/andesite_alloy_block.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:andesite_alloy_block" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/andesite_bars.json b/src/generated/resources/data/create/loot_tables/blocks/andesite_bars.json new file mode 100644 index 0000000000..c978dd88fd --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/andesite_bars.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:andesite_bars" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/andesite_door.json b/src/generated/resources/data/create/loot_tables/blocks/andesite_door.json new file mode 100644 index 0000000000..49cf670f7a --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/andesite_door.json @@ -0,0 +1,29 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "create:andesite_door", + "properties": { + "half": "lower" + } + } + ], + "name": "create:andesite_door" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/andesite_scaffolding.json b/src/generated/resources/data/create/loot_tables/blocks/andesite_scaffolding.json new file mode 100644 index 0000000000..ec4bc449d9 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/andesite_scaffolding.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:andesite_scaffolding" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/brass_bars.json b/src/generated/resources/data/create/loot_tables/blocks/brass_bars.json new file mode 100644 index 0000000000..4bad9d3d94 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/brass_bars.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:brass_bars" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/brass_door.json b/src/generated/resources/data/create/loot_tables/blocks/brass_door.json new file mode 100644 index 0000000000..b783b61453 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/brass_door.json @@ -0,0 +1,29 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "create:brass_door", + "properties": { + "half": "lower" + } + } + ], + "name": "create:brass_door" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/brass_scaffolding.json b/src/generated/resources/data/create/loot_tables/blocks/brass_scaffolding.json new file mode 100644 index 0000000000..5020434ca8 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/brass_scaffolding.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:brass_scaffolding" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/clipboard.json b/src/generated/resources/data/create/loot_tables/blocks/clipboard.json new file mode 100644 index 0000000000..68701f9f6e --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/clipboard.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:block" +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/contraption_controls.json b/src/generated/resources/data/create/loot_tables/blocks/contraption_controls.json new file mode 100644 index 0000000000..69cece5200 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/contraption_controls.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:contraption_controls" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copper_bars.json b/src/generated/resources/data/create/loot_tables/blocks/copper_bars.json new file mode 100644 index 0000000000..dd69e65783 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copper_bars.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:copper_bars" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copper_door.json b/src/generated/resources/data/create/loot_tables/blocks/copper_door.json new file mode 100644 index 0000000000..0f1a745f1d --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copper_door.json @@ -0,0 +1,29 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:block_state_property", + "block": "create:copper_door", + "properties": { + "half": "lower" + } + } + ], + "name": "create:copper_door" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copper_scaffolding.json b/src/generated/resources/data/create/loot_tables/blocks/copper_scaffolding.json new file mode 100644 index 0000000000..27bace0b46 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copper_scaffolding.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:copper_scaffolding" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_bars.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_bars.json new file mode 100644 index 0000000000..3da3a59b4e --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_bars.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:air" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json new file mode 100644 index 0000000000..3da3a59b4e --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:air" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json new file mode 100644 index 0000000000..920edaf466 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:copycat_panel" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json new file mode 100644 index 0000000000..880a818c12 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:copycat_step" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/elevator_contact.json b/src/generated/resources/data/create/loot_tables/blocks/elevator_contact.json new file mode 100644 index 0000000000..da0d76bbdb --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/elevator_contact.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:redstone_contact" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/elevator_pulley.json b/src/generated/resources/data/create/loot_tables/blocks/elevator_pulley.json new file mode 100644 index 0000000000..f73be002f7 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/elevator_pulley.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:elevator_pulley" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/experience_block.json b/src/generated/resources/data/create/loot_tables/blocks/experience_block.json new file mode 100644 index 0000000000..4460120de9 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/experience_block.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:experience_block" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/industrial_iron_block.json b/src/generated/resources/data/create/loot_tables/blocks/industrial_iron_block.json new file mode 100644 index 0000000000..be76eafc86 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/industrial_iron_block.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:industrial_iron_block" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/large_water_wheel.json b/src/generated/resources/data/create/loot_tables/blocks/large_water_wheel.json new file mode 100644 index 0000000000..bfbf1c3a0d --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/large_water_wheel.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:large_water_wheel" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/mechanical_roller.json b/src/generated/resources/data/create/loot_tables/blocks/mechanical_roller.json new file mode 100644 index 0000000000..b45d5c150f --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/mechanical_roller.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "create:mechanical_roller" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/netherite_backtank.json b/src/generated/resources/data/create/loot_tables/blocks/netherite_backtank.json new file mode 100644 index 0000000000..4418da818f --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/netherite_backtank.json @@ -0,0 +1,48 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + }, + { + "function": "minecraft:copy_nbt", + "source": "block_entity", + "ops": [ + { + "source": "Air", + "target": "Air", + "op": "replace" + } + ] + }, + { + "function": "minecraft:copy_nbt", + "source": "block_entity", + "ops": [ + { + "source": "Enchantments", + "target": "Enchantments", + "op": "replace" + } + ] + } + ], + "name": "create:netherite_backtank" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/water_wheel_structure.json b/src/generated/resources/data/create/loot_tables/blocks/water_wheel_structure.json new file mode 100644 index 0000000000..3da3a59b4e --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/water_wheel_structure.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:air" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/andesite_bars_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/recipes/andesite_bars_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..a9946a88ad --- /dev/null +++ b/src/generated/resources/data/create/recipes/andesite_bars_from_andesite_alloy_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "item": "create:andesite_alloy" + }, + "result": "create:andesite_bars", + "count": 4 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/andesite_from_stone_types_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/andesite_from_stone_types_andesite_stonecutting.json new file mode 100644 index 0000000000..3a3cd6b7c0 --- /dev/null +++ b/src/generated/resources/data/create/recipes/andesite_from_stone_types_andesite_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/andesite" + }, + "result": "minecraft:andesite", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/andesite_ladder_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/recipes/andesite_ladder_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..e7339d2f4f --- /dev/null +++ b/src/generated/resources/data/create/recipes/andesite_ladder_from_andesite_alloy_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "item": "create:andesite_alloy" + }, + "result": "create:andesite_ladder", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/andesite_pillar_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/andesite_pillar_from_andesite_stonecutting.json deleted file mode 100644 index 44da5f5609..0000000000 --- a/src/generated/resources/data/create/recipes/andesite_pillar_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:andesite_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/andesite_scaffolding_from_andesite_alloy_stonecutting.json b/src/generated/resources/data/create/recipes/andesite_scaffolding_from_andesite_alloy_stonecutting.json new file mode 100644 index 0000000000..0ddcaf13fe --- /dev/null +++ b/src/generated/resources/data/create/recipes/andesite_scaffolding_from_andesite_alloy_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "item": "create:andesite_alloy" + }, + "result": "create:andesite_scaffolding", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/asurine_from_stone_types_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/asurine_from_stone_types_asurine_stonecutting.json new file mode 100644 index 0000000000..285c6f2002 --- /dev/null +++ b/src/generated/resources/data/create/recipes/asurine_from_stone_types_asurine_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/asurine" + }, + "result": "create:asurine", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/asurine_pillar_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/asurine_pillar_from_asurine_stonecutting.json deleted file mode 100644 index 0473a80d31..0000000000 --- a/src/generated/resources/data/create/recipes/asurine_pillar_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:asurine_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/blasting/copper_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/blasting/copper_ingot_from_crushed.json index dd803ed810..2d7258affd 100644 --- a/src/generated/resources/data/create/recipes/blasting/copper_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/blasting/copper_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_copper_ore" + "item": "create:crushed_raw_copper" }, "result": "minecraft:copper_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/gold_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/blasting/gold_ingot_from_crushed.json index 32f1a5e9e6..a3d23b0cb4 100644 --- a/src/generated/resources/data/create/recipes/blasting/gold_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/blasting/gold_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_gold_ore" + "item": "create:crushed_raw_gold" }, "result": "minecraft:gold_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json index df88850d4e..ce60539fd2 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_aluminum_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_aluminum_ore" + "item": "create:crushed_raw_aluminum" }, "result": "immersiveengineering:ingot_aluminum", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json index 74f359db2d..59353634aa 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "immersiveengineering:ingot_lead", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_mekanism.json b/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_mekanism.json index 077eb05123..3084e0248c 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_lead_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "mekanism:ingot_lead", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_nickel_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/blasting/ingot_nickel_compat_immersiveengineering.json index 8ad2bf41b1..43dc378953 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_nickel_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_nickel_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, "result": "immersiveengineering:ingot_nickel", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_osmium_compat_mekanism.json b/src/generated/resources/data/create/recipes/blasting/ingot_osmium_compat_mekanism.json index f191d5906c..3e0d99760d 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_osmium_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_osmium_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_osmium_ore" + "item": "create:crushed_raw_osmium" }, "result": "mekanism:ingot_osmium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_silver_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/blasting/ingot_silver_compat_immersiveengineering.json index 4b0fac0c85..b460dc6095 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_silver_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_silver_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, "result": "immersiveengineering:ingot_silver", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_tin_compat_mekanism.json b/src/generated/resources/data/create/recipes/blasting/ingot_tin_compat_mekanism.json index 0bc4fe4f74..bd11d969c1 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_tin_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_tin_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, "result": "mekanism:ingot_tin", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_immersiveengineering.json index 52c435ebfe..a8fbf1408d 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, "result": "immersiveengineering:ingot_uranium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_mekanism.json b/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_mekanism.json index fb51bfaf88..6f9e7b1612 100644 --- a/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/blasting/ingot_uranium_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, "result": "mekanism:ingot_uranium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/iron_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/blasting/iron_ingot_from_crushed.json index 43c60447d7..9cc4cff583 100644 --- a/src/generated/resources/data/create/recipes/blasting/iron_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/blasting/iron_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_iron_ore" + "item": "create:crushed_raw_iron" }, "result": "minecraft:iron_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/lead_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/blasting/lead_ingot_compat_thermal.json index e6b05e422f..7a47d44070 100644 --- a/src/generated/resources/data/create/recipes/blasting/lead_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/blasting/lead_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "thermal:lead_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/nickel_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/blasting/nickel_ingot_compat_thermal.json index 377dde1b9a..5c490c0ed8 100644 --- a/src/generated/resources/data/create/recipes/blasting/nickel_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/blasting/nickel_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, "result": "thermal:nickel_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/silver_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/blasting/silver_ingot_compat_thermal.json index 94079c9124..e3428d61d3 100644 --- a/src/generated/resources/data/create/recipes/blasting/silver_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/blasting/silver_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, "result": "thermal:silver_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/tin_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/blasting/tin_ingot_compat_thermal.json index bda6c13ff1..dc7962468d 100644 --- a/src/generated/resources/data/create/recipes/blasting/tin_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/blasting/tin_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, "result": "thermal:tin_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/blasting/zinc_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/blasting/zinc_ingot_from_crushed.json index e23b0e03b6..9a113255f8 100644 --- a/src/generated/resources/data/create/recipes/blasting/zinc_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/blasting/zinc_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:blasting", "ingredient": { - "item": "create:crushed_zinc_ore" + "item": "create:crushed_raw_zinc" }, "result": "create:zinc_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/brass_bars_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/recipes/brass_bars_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..b1632c97c1 --- /dev/null +++ b/src/generated/resources/data/create/recipes/brass_bars_from_ingots_brass_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/brass" + }, + "result": "create:brass_bars", + "count": 4 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/brass_ladder_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/recipes/brass_ladder_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..123c06af91 --- /dev/null +++ b/src/generated/resources/data/create/recipes/brass_ladder_from_ingots_brass_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/brass" + }, + "result": "create:brass_ladder", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/brass_ladder_from_plates_brass_stonecutting.json b/src/generated/resources/data/create/recipes/brass_ladder_from_plates_brass_stonecutting.json deleted file mode 100644 index d9671970aa..0000000000 --- a/src/generated/resources/data/create/recipes/brass_ladder_from_plates_brass_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "tag": "forge:plates/brass" - }, - "result": "create:brass_ladder", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/brass_scaffolding_from_ingots_brass_stonecutting.json b/src/generated/resources/data/create/recipes/brass_scaffolding_from_ingots_brass_stonecutting.json new file mode 100644 index 0000000000..12f9c2ae37 --- /dev/null +++ b/src/generated/resources/data/create/recipes/brass_scaffolding_from_ingots_brass_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/brass" + }, + "result": "create:brass_scaffolding", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/calcite_from_stone_types_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/calcite_from_stone_types_calcite_stonecutting.json new file mode 100644 index 0000000000..055191019e --- /dev/null +++ b/src/generated/resources/data/create/recipes/calcite_from_stone_types_calcite_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/calcite" + }, + "result": "minecraft:calcite", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/calcite_pillar_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/calcite_pillar_from_calcite_stonecutting.json deleted file mode 100644 index 8e187e3254..0000000000 --- a/src/generated/resources/data/create/recipes/calcite_pillar_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:calcite_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_bars_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_bars_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..d62f0163cc --- /dev/null +++ b/src/generated/resources/data/create/recipes/copper_bars_from_ingots_copper_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/copper" + }, + "result": "create:copper_bars", + "count": 4 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_ladder_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_ladder_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..131bfa4b60 --- /dev/null +++ b/src/generated/resources/data/create/recipes/copper_ladder_from_ingots_copper_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/copper" + }, + "result": "create:copper_ladder", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_ladder_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_ladder_from_plates_copper_stonecutting.json deleted file mode 100644 index 336285d51c..0000000000 --- a/src/generated/resources/data/create/recipes/copper_ladder_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "tag": "forge:plates/copper" - }, - "result": "create:copper_ladder", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_scaffolding_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_scaffolding_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..f10c9b2756 --- /dev/null +++ b/src/generated/resources/data/create/recipes/copper_scaffolding_from_ingots_copper_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/copper" + }, + "result": "create:copper_scaffolding", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_shingles_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_shingles_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..da223e215b --- /dev/null +++ b/src/generated/resources/data/create/recipes/copper_shingles_from_ingots_copper_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/copper" + }, + "result": "create:copper_shingles", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_shingles_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_shingles_from_plates_copper_stonecutting.json deleted file mode 100644 index 7d56f6076b..0000000000 --- a/src/generated/resources/data/create/recipes/copper_shingles_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "tag": "forge:plates/copper" - }, - "result": "create:copper_shingles", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_tiles_from_ingots_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_tiles_from_ingots_copper_stonecutting.json new file mode 100644 index 0000000000..654e61e9ed --- /dev/null +++ b/src/generated/resources/data/create/recipes/copper_tiles_from_ingots_copper_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/copper" + }, + "result": "create:copper_tiles", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copper_tiles_from_plates_copper_stonecutting.json b/src/generated/resources/data/create/recipes/copper_tiles_from_plates_copper_stonecutting.json deleted file mode 100644 index 44c0bbc397..0000000000 --- a/src/generated/resources/data/create/recipes/copper_tiles_from_plates_copper_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "tag": "forge:plates/copper" - }, - "result": "create:copper_tiles", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copycat_panel_from_ingots_zinc_stonecutting.json b/src/generated/resources/data/create/recipes/copycat_panel_from_ingots_zinc_stonecutting.json new file mode 100644 index 0000000000..1e4a87c476 --- /dev/null +++ b/src/generated/resources/data/create/recipes/copycat_panel_from_ingots_zinc_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/zinc" + }, + "result": "create:copycat_panel", + "count": 4 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/copycat_step_from_ingots_zinc_stonecutting.json b/src/generated/resources/data/create/recipes/copycat_step_from_ingots_zinc_stonecutting.json new file mode 100644 index 0000000000..5fa62e6f2a --- /dev/null +++ b/src/generated/resources/data/create/recipes/copycat_step_from_ingots_zinc_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/zinc" + }, + "result": "create:copycat_step", + "count": 4 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/attribute_filter_clear.json b/src/generated/resources/data/create/recipes/crafting/appliances/attribute_filter_clear.json new file mode 100644 index 0000000000..9f09e14cda --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/attribute_filter_clear.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:attribute_filter" + } + ], + "result": { + "item": "create:attribute_filter" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json new file mode 100644 index 0000000000..c32ad15528 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "A", + "P", + "G" + ], + "key": { + "G": { + "tag": "minecraft:planks" + }, + "P": { + "item": "minecraft:paper" + }, + "A": { + "item": "create:andesite_alloy" + } + }, + "result": { + "item": "create:clipboard" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json new file mode 100644 index 0000000000..de19409bd1 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:clipboard" + } + ], + "result": { + "item": "create:clipboard" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_boots.json b/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_boots.json new file mode 100644 index 0000000000..76059a7971 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_boots.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "P P", + "P P", + "G G" + ], + "key": { + "G": { + "item": "create:andesite_alloy" + }, + "P": { + "item": "minecraft:copper_ingot" + } + }, + "result": { + "item": "create:copper_diving_boots" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_helmet.json b/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_helmet.json new file mode 100644 index 0000000000..68e63efc2c --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/copper_diving_helmet.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "PPP", + "PGP" + ], + "key": { + "G": { + "tag": "forge:glass" + }, + "P": { + "item": "minecraft:copper_ingot" + } + }, + "result": { + "item": "create:copper_diving_helmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/diving_boots.json b/src/generated/resources/data/create/recipes/crafting/appliances/diving_boots.json deleted file mode 100644 index 8ea573d109..0000000000 --- a/src/generated/resources/data/create/recipes/crafting/appliances/diving_boots.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "P P", - "P P", - "G G" - ], - "key": { - "G": { - "item": "create:andesite_alloy" - }, - "P": { - "item": "minecraft:copper_ingot" - } - }, - "result": { - "item": "create:diving_boots" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/diving_helmet.json b/src/generated/resources/data/create/recipes/crafting/appliances/diving_helmet.json deleted file mode 100644 index c2434ae437..0000000000 --- a/src/generated/resources/data/create/recipes/crafting/appliances/diving_helmet.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "PPP", - "PGP" - ], - "key": { - "G": { - "tag": "forge:glass" - }, - "P": { - "item": "minecraft:copper_ingot" - } - }, - "result": { - "item": "create:diving_helmet" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/filter_clear.json b/src/generated/resources/data/create/recipes/crafting/appliances/filter_clear.json new file mode 100644 index 0000000000..19fb93579f --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/filter_clear.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:filter" + } + ], + "result": { + "item": "create:filter" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank.json new file mode 100644 index 0000000000..ab3830a3c2 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "create:copper_backtank" + }, + "addition": { + "tag": "forge:ingots/netherite" + }, + "result": { + "item": "create:netherite_backtank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank_from_netherite.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank_from_netherite.json new file mode 100644 index 0000000000..eb05b36177 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_backtank_from_netherite.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "minecraft:netherite_chestplate" + }, + "addition": { + "item": "create:copper_backtank" + }, + "result": { + "item": "create:netherite_backtank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots.json new file mode 100644 index 0000000000..82e8c91284 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "create:copper_diving_boots" + }, + "addition": { + "tag": "forge:ingots/netherite" + }, + "result": { + "item": "create:netherite_diving_boots" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots_from_netherite.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots_from_netherite.json new file mode 100644 index 0000000000..f1d242feba --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_boots_from_netherite.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "minecraft:netherite_boots" + }, + "addition": { + "item": "create:copper_diving_boots" + }, + "result": { + "item": "create:netherite_diving_boots" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet.json new file mode 100644 index 0000000000..7d8cae6d46 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "create:copper_diving_helmet" + }, + "addition": { + "tag": "forge:ingots/netherite" + }, + "result": { + "item": "create:netherite_diving_helmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet_from_netherite.json b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet_from_netherite.json new file mode 100644 index 0000000000..bc034e266c --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/netherite_diving_helmet_from_netherite.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:smithing", + "base": { + "item": "minecraft:netherite_helmet" + }, + "addition": { + "item": "create:copper_diving_helmet" + }, + "result": { + "item": "create:netherite_diving_helmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/schedule_clear.json b/src/generated/resources/data/create/recipes/crafting/appliances/schedule_clear.json new file mode 100644 index 0000000000..a34b2868b7 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/schedule_clear.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:schedule" + } + ], + "result": { + "item": "create:schedule" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_door.json b/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_door.json new file mode 100644 index 0000000000..f8870c5fce --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_door.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "minecraft:wooden_doors" + }, + { + "item": "create:andesite_casing" + } + ], + "result": { + "item": "create:andesite_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_ladder.json b/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_ladder.json deleted file mode 100644 index 9b2e5918a3..0000000000 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/andesite_ladder.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "pattern": [ - "A A", - "AAA", - "A A" - ], - "key": { - "A": { - "item": "create:andesite_alloy" - } - }, - "result": { - "item": "create:andesite_ladder", - "count": 4 - } -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/brass_door.json b/src/generated/resources/data/create/recipes/crafting/kinetics/brass_door.json new file mode 100644 index 0000000000..1ff8c45ee2 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/brass_door.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "minecraft:wooden_doors" + }, + { + "item": "create:brass_casing" + } + ], + "result": { + "item": "create:brass_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/contraption_controls.json b/src/generated/resources/data/create/recipes/crafting/kinetics/contraption_controls.json new file mode 100644 index 0000000000..7ef868c4c1 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/contraption_controls.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "B", + "C", + "I" + ], + "key": { + "B": { + "tag": "minecraft:buttons" + }, + "C": { + "item": "create:andesite_casing" + }, + "I": { + "item": "create:electron_tube" + } + }, + "result": { + "item": "create:contraption_controls" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/copper_door.json b/src/generated/resources/data/create/recipes/crafting/kinetics/copper_door.json new file mode 100644 index 0000000000..98cb8e3534 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/copper_door.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "tag": "minecraft:wooden_doors" + }, + { + "item": "create:copper_casing" + } + ], + "result": { + "item": "create:copper_door" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/elevator_pulley.json b/src/generated/resources/data/create/recipes/crafting/kinetics/elevator_pulley.json new file mode 100644 index 0000000000..b60facd729 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/elevator_pulley.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "B", + "C", + "I" + ], + "key": { + "B": { + "item": "create:brass_casing" + }, + "C": { + "item": "minecraft:dried_kelp_block" + }, + "I": { + "tag": "forge:plates/iron" + } + }, + "result": { + "item": "create:elevator_pulley" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/large_cogwheelfrom_little.json b/src/generated/resources/data/create/recipes/crafting/kinetics/large_cogwheel_from_little.json similarity index 100% rename from src/generated/resources/data/create/recipes/crafting/kinetics/large_cogwheelfrom_little.json rename to src/generated/resources/data/create/recipes/crafting/kinetics/large_cogwheel_from_little.json diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/large_water_wheel.json b/src/generated/resources/data/create/recipes/crafting/kinetics/large_water_wheel.json new file mode 100644 index 0000000000..e82322b2b2 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/large_water_wheel.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SSS", + "SCS", + "SSS" + ], + "key": { + "S": { + "tag": "minecraft:planks" + }, + "C": { + "item": "create:water_wheel" + } + }, + "result": { + "item": "create:large_water_wheel" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/mechanical_roller.json b/src/generated/resources/data/create/recipes/crafting/kinetics/mechanical_roller.json new file mode 100644 index 0000000000..f6d780efd8 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/mechanical_roller.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "A", + "C", + "I" + ], + "key": { + "C": { + "item": "create:andesite_casing" + }, + "A": { + "item": "create:electron_tube" + }, + "I": { + "item": "create:crushing_wheel" + } + }, + "result": { + "item": "create:mechanical_roller" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/train_door.json b/src/generated/resources/data/create/recipes/crafting/kinetics/train_door.json index 7751dd7ef8..558c8734f6 100644 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/train_door.json +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/train_door.json @@ -5,7 +5,7 @@ "tag": "minecraft:wooden_doors" }, { - "tag": "forge:plates/brass" + "item": "create:railway_casing" } ], "result": { diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/train_trapdoor.json b/src/generated/resources/data/create/recipes/crafting/kinetics/train_trapdoor.json index 6b37bcb5cf..82b668a524 100644 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/train_trapdoor.json +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/train_trapdoor.json @@ -5,7 +5,7 @@ "tag": "minecraft:wooden_trapdoors" }, { - "tag": "forge:plates/brass" + "item": "create:railway_casing" } ], "result": { diff --git a/src/generated/resources/data/create/recipes/crafting/kinetics/water_wheel.json b/src/generated/resources/data/create/recipes/crafting/kinetics/water_wheel.json index 9fa6560ee7..97550a965a 100644 --- a/src/generated/resources/data/create/recipes/crafting/kinetics/water_wheel.json +++ b/src/generated/resources/data/create/recipes/crafting/kinetics/water_wheel.json @@ -7,10 +7,10 @@ ], "key": { "S": { - "tag": "minecraft:wooden_slabs" + "tag": "minecraft:planks" }, "C": { - "item": "create:large_cogwheel" + "item": "create:shaft" } }, "result": { diff --git a/src/generated/resources/data/create/recipes/crafting/logistics/content_observer.json b/src/generated/resources/data/create/recipes/crafting/logistics/content_observer.json index 6e21a750f9..ab4e7a50c7 100644 --- a/src/generated/resources/data/create/recipes/crafting/logistics/content_observer.json +++ b/src/generated/resources/data/create/recipes/crafting/logistics/content_observer.json @@ -1,9 +1,9 @@ { "type": "minecraft:crafting_shaped", "pattern": [ - "I", + "R", "B", - "R" + "I" ], "key": { "B": { @@ -13,7 +13,7 @@ "item": "create:electron_tube" }, "I": { - "item": "minecraft:comparator" + "item": "minecraft:observer" } }, "result": { diff --git a/src/generated/resources/data/create/recipes/crafting/logistics/content_observerfrom_conversion.json b/src/generated/resources/data/create/recipes/crafting/logistics/content_observerfrom_conversion.json deleted file mode 100644 index d6d5582365..0000000000 --- a/src/generated/resources/data/create/recipes/crafting/logistics/content_observerfrom_conversion.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:crafting_shapeless", - "ingredients": [ - { - "item": "create:stockpile_switch" - } - ], - "result": { - "item": "create:content_observer" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switch.json b/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switch.json new file mode 100644 index 0000000000..00f52e58e4 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switch.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "R", + "B", + "I" + ], + "key": { + "B": { + "item": "create:brass_casing" + }, + "R": { + "item": "create:electron_tube" + }, + "I": { + "item": "minecraft:comparator" + } + }, + "result": { + "item": "create:stockpile_switch" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switchfrom_conversion.json b/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switchfrom_conversion.json deleted file mode 100644 index 34cb0c2774..0000000000 --- a/src/generated/resources/data/create/recipes/crafting/logistics/stockpile_switchfrom_conversion.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:crafting_shapeless", - "ingredients": [ - { - "item": "create:content_observer" - } - ], - "result": { - "item": "create:stockpile_switch" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_block.json b/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_block.json new file mode 100644 index 0000000000..791418b90c --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_block.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "CCC", + "CCC", + "CCC" + ], + "key": { + "C": { + "item": "create:andesite_alloy" + } + }, + "result": { + "item": "create:andesite_alloy_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_from_block.json b/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_from_block.json new file mode 100644 index 0000000000..807d6836a3 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/materials/andesite_alloy_from_block.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:andesite_alloy_block" + } + ], + "result": { + "item": "create:andesite_alloy", + "count": 9 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/materials/experience_block.json b/src/generated/resources/data/create/recipes/crafting/materials/experience_block.json new file mode 100644 index 0000000000..be3191b6d3 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/materials/experience_block.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "CCC", + "CCC", + "CCC" + ], + "key": { + "C": { + "item": "create:experience_nugget" + } + }, + "result": { + "item": "create:experience_block" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/materials/experience_nugget_from_block.json b/src/generated/resources/data/create/recipes/crafting/materials/experience_nugget_from_block.json new file mode 100644 index 0000000000..adc3f4b57d --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/materials/experience_nugget_from_block.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:experience_block" + } + ], + "result": { + "item": "create:experience_nugget", + "count": 9 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crimsite_from_stone_types_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/crimsite_from_stone_types_crimsite_stonecutting.json new file mode 100644 index 0000000000..540e5e5bc0 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crimsite_from_stone_types_crimsite_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/crimsite" + }, + "result": "create:crimsite", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crimsite_pillar_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/crimsite_pillar_from_crimsite_stonecutting.json deleted file mode 100644 index e1ed186dd3..0000000000 --- a/src/generated/resources/data/create/recipes/crimsite_pillar_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:crimsite_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crushing/aluminum_ore.json b/src/generated/resources/data/create/recipes/crushing/aluminum_ore.json index 7b02ab2453..b5eabe8ee6 100644 --- a/src/generated/resources/data/create/recipes/crushing/aluminum_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/aluminum_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_aluminum_ore" + "item": "create:crushed_raw_aluminum" }, { - "item": "create:crushed_aluminum_ore", + "item": "create:crushed_raw_aluminum", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/asurine.json b/src/generated/resources/data/create/recipes/crushing/asurine.json index de7e6204e8..21b7a95352 100644 --- a/src/generated/resources/data/create/recipes/crushing/asurine.json +++ b/src/generated/resources/data/create/recipes/crushing/asurine.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "chance": 0.3 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/asurine_recycling.json b/src/generated/resources/data/create/recipes/crushing/asurine_recycling.json index a80f3d65f6..57819eb326 100644 --- a/src/generated/resources/data/create/recipes/crushing/asurine_recycling.json +++ b/src/generated/resources/data/create/recipes/crushing/asurine_recycling.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "chance": 0.3 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/copper_ore.json b/src/generated/resources/data/create/recipes/crushing/copper_ore.json index a7b4f903f8..1ee7a3c866 100644 --- a/src/generated/resources/data/create/recipes/crushing/copper_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/copper_ore.json @@ -7,11 +7,11 @@ ], "results": [ { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "count": 5 }, { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "chance": 0.25 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/crimsite.json b/src/generated/resources/data/create/recipes/crushing/crimsite.json index 6634023932..e627b51cf5 100644 --- a/src/generated/resources/data/create/recipes/crushing/crimsite.json +++ b/src/generated/resources/data/create/recipes/crushing/crimsite.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "chance": 0.4 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/crimsite_recycling.json b/src/generated/resources/data/create/recipes/crushing/crimsite_recycling.json index d479e6a033..5b94b7b831 100644 --- a/src/generated/resources/data/create/recipes/crushing/crimsite_recycling.json +++ b/src/generated/resources/data/create/recipes/crushing/crimsite_recycling.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "chance": 0.4 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/deepslate_copper_ore.json b/src/generated/resources/data/create/recipes/crushing/deepslate_copper_ore.json index 683025dbff..38fdaa3a24 100644 --- a/src/generated/resources/data/create/recipes/crushing/deepslate_copper_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/deepslate_copper_ore.json @@ -7,11 +7,11 @@ ], "results": [ { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "count": 7 }, { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "chance": 0.25 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/deepslate_gold_ore.json b/src/generated/resources/data/create/recipes/crushing/deepslate_gold_ore.json index 40b2f1b527..ed3c876566 100644 --- a/src/generated/resources/data/create/recipes/crushing/deepslate_gold_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/deepslate_gold_ore.json @@ -7,15 +7,16 @@ ], "results": [ { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "count": 2 }, { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "chance": 0.25 }, { "item": "create:experience_nugget", + "count": 2, "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/deepslate_iron_ore.json b/src/generated/resources/data/create/recipes/crushing/deepslate_iron_ore.json index ed9bbc058a..91f34e8dc0 100644 --- a/src/generated/resources/data/create/recipes/crushing/deepslate_iron_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/deepslate_iron_ore.json @@ -7,11 +7,11 @@ ], "results": [ { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "count": 2 }, { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "chance": 0.25 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/deepslate_zinc_ore.json b/src/generated/resources/data/create/recipes/crushing/deepslate_zinc_ore.json index cddbf59d78..71aed1015a 100644 --- a/src/generated/resources/data/create/recipes/crushing/deepslate_zinc_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/deepslate_zinc_ore.json @@ -7,11 +7,11 @@ ], "results": [ { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "count": 2 }, { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "chance": 0.25 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/gold_ore.json b/src/generated/resources/data/create/recipes/crushing/gold_ore.json index 1208634d84..2ce9d0a6fd 100644 --- a/src/generated/resources/data/create/recipes/crushing/gold_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/gold_ore.json @@ -7,14 +7,15 @@ ], "results": [ { - "item": "create:crushed_gold_ore" + "item": "create:crushed_raw_gold" }, { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "chance": 0.75 }, { "item": "create:experience_nugget", + "count": 2, "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/iron_ore.json b/src/generated/resources/data/create/recipes/crushing/iron_ore.json index 658ffe0bf0..d6b478e6b5 100644 --- a/src/generated/resources/data/create/recipes/crushing/iron_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/iron_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_iron_ore" + "item": "create:crushed_raw_iron" }, { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/lead_ore.json b/src/generated/resources/data/create/recipes/crushing/lead_ore.json index d9eec31d9b..83d1be3acf 100644 --- a/src/generated/resources/data/create/recipes/crushing/lead_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/lead_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, { - "item": "create:crushed_lead_ore", + "item": "create:crushed_raw_lead", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/nickel_ore.json b/src/generated/resources/data/create/recipes/crushing/nickel_ore.json index d54c82dfcf..705a85a082 100644 --- a/src/generated/resources/data/create/recipes/crushing/nickel_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/nickel_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, { - "item": "create:crushed_nickel_ore", + "item": "create:crushed_raw_nickel", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/ochrum.json b/src/generated/resources/data/create/recipes/crushing/ochrum.json index a98df1e28a..6e723c99fb 100644 --- a/src/generated/resources/data/create/recipes/crushing/ochrum.json +++ b/src/generated/resources/data/create/recipes/crushing/ochrum.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "chance": 0.2 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/ochrum_recycling.json b/src/generated/resources/data/create/recipes/crushing/ochrum_recycling.json index 64adbdb984..3cbaf7ce58 100644 --- a/src/generated/resources/data/create/recipes/crushing/ochrum_recycling.json +++ b/src/generated/resources/data/create/recipes/crushing/ochrum_recycling.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "chance": 0.2 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/osmium_ore.json b/src/generated/resources/data/create/recipes/crushing/osmium_ore.json index d13cd9df4b..605b6ea97d 100644 --- a/src/generated/resources/data/create/recipes/crushing/osmium_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/osmium_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_osmium_ore" + "item": "create:crushed_raw_osmium" }, { - "item": "create:crushed_osmium_ore", + "item": "create:crushed_raw_osmium", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/platinum_ore.json b/src/generated/resources/data/create/recipes/crushing/platinum_ore.json index e651ac5c9b..78b99ea677 100644 --- a/src/generated/resources/data/create/recipes/crushing/platinum_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/platinum_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_platinum_ore" + "item": "create:crushed_raw_platinum" }, { - "item": "create:crushed_platinum_ore", + "item": "create:crushed_raw_platinum", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/quicksilver_ore.json b/src/generated/resources/data/create/recipes/crushing/quicksilver_ore.json index 228561c07a..1b09210474 100644 --- a/src/generated/resources/data/create/recipes/crushing/quicksilver_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/quicksilver_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_quicksilver_ore" + "item": "create:crushed_raw_quicksilver" }, { - "item": "create:crushed_quicksilver_ore", + "item": "create:crushed_raw_quicksilver", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_aluminum_block.json b/src/generated/resources/data/create/recipes/crushing/raw_aluminum_block.json index 85b39f9070..014d9cf49c 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_aluminum_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_aluminum_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_aluminum_ore", + "item": "create:crushed_raw_aluminum", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_aluminum_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_aluminum_ore.json index 854c47b0b9..03905d762b 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_aluminum_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_aluminum_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_aluminum_ore" + "item": "create:crushed_raw_aluminum" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_copper.json b/src/generated/resources/data/create/recipes/crushing/raw_copper.json index 81e99ec47c..c96a96dda2 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_copper.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_copper.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_copper_ore" + "item": "create:crushed_raw_copper" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_copper_block.json b/src/generated/resources/data/create/recipes/crushing/raw_copper_block.json index 00f83d3296..ee6d6269dc 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_copper_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_copper_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_gold.json b/src/generated/resources/data/create/recipes/crushing/raw_gold.json index caf7b3f35b..fd6f852430 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_gold.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_gold.json @@ -7,10 +7,11 @@ ], "results": [ { - "item": "create:crushed_gold_ore" + "item": "create:crushed_raw_gold" }, { "item": "create:experience_nugget", + "count": 2, "chance": 0.75 } ], diff --git a/src/generated/resources/data/create/recipes/crushing/raw_gold_block.json b/src/generated/resources/data/create/recipes/crushing/raw_gold_block.json index 90942d3c6c..f978987443 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_gold_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_gold_block.json @@ -7,12 +7,12 @@ ], "results": [ { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "count": 9 }, { "item": "create:experience_nugget", - "count": 9, + "count": 18, "chance": 0.75 } ], diff --git a/src/generated/resources/data/create/recipes/crushing/raw_iron.json b/src/generated/resources/data/create/recipes/crushing/raw_iron.json index cd044b642a..b044167e8b 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_iron.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_iron.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_iron_ore" + "item": "create:crushed_raw_iron" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_iron_block.json b/src/generated/resources/data/create/recipes/crushing/raw_iron_block.json index 3e45d75c6d..664b0cfcd4 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_iron_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_iron_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_iron_ore", + "item": "create:crushed_raw_iron", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_lead_block.json b/src/generated/resources/data/create/recipes/crushing/raw_lead_block.json index f8ee5bd7b0..57c1f742c5 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_lead_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_lead_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_lead_ore", + "item": "create:crushed_raw_lead", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_lead_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_lead_ore.json index cce5d9eeed..8e3e80e34a 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_lead_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_lead_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_nickel_block.json b/src/generated/resources/data/create/recipes/crushing/raw_nickel_block.json index 1eb2048c2c..330e2b506a 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_nickel_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_nickel_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_nickel_ore", + "item": "create:crushed_raw_nickel", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_nickel_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_nickel_ore.json index b1d5a0661c..5c364129b2 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_nickel_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_nickel_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_osmium_block.json b/src/generated/resources/data/create/recipes/crushing/raw_osmium_block.json index a5c805e43b..6db3c770c6 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_osmium_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_osmium_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_osmium_ore", + "item": "create:crushed_raw_osmium", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_osmium_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_osmium_ore.json index 6f4461f99d..3b5e30f509 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_osmium_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_osmium_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_osmium_ore" + "item": "create:crushed_raw_osmium" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_platinum_block.json b/src/generated/resources/data/create/recipes/crushing/raw_platinum_block.json index e7654edd60..617d664b82 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_platinum_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_platinum_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_platinum_ore", + "item": "create:crushed_raw_platinum", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_platinum_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_platinum_ore.json index 387ce13e77..e08bbfa4e5 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_platinum_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_platinum_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_platinum_ore" + "item": "create:crushed_raw_platinum" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_block.json b/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_block.json index 75f86ebb1d..f9741a504b 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_quicksilver_ore", + "item": "create:crushed_raw_quicksilver", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_ore.json index 2f3b851c3a..1c920ec4d9 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_quicksilver_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_quicksilver_ore" + "item": "create:crushed_raw_quicksilver" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_silver_block.json b/src/generated/resources/data/create/recipes/crushing/raw_silver_block.json index 76a124f577..71a33fbd22 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_silver_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_silver_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_silver_ore", + "item": "create:crushed_raw_silver", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_silver_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_silver_ore.json index 825a0e52bb..fd0ddc610b 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_silver_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_silver_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_tin_block.json b/src/generated/resources/data/create/recipes/crushing/raw_tin_block.json index 8b4b3c9b95..ae4c5b36da 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_tin_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_tin_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_tin_ore", + "item": "create:crushed_raw_tin", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_tin_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_tin_ore.json index 2457ef4461..06bf62e92a 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_tin_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_tin_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_uranium_block.json b/src/generated/resources/data/create/recipes/crushing/raw_uranium_block.json index 77a7f28e52..bd9afbd137 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_uranium_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_uranium_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_uranium_ore", + "item": "create:crushed_raw_uranium", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/raw_uranium_ore.json b/src/generated/resources/data/create/recipes/crushing/raw_uranium_ore.json index f2497f6f8a..3a25ad2077 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_uranium_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_uranium_ore.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_zinc.json b/src/generated/resources/data/create/recipes/crushing/raw_zinc.json index 59f163c235..662ecd80bb 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_zinc.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_zinc.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_zinc_ore" + "item": "create:crushed_raw_zinc" }, { "item": "create:experience_nugget", diff --git a/src/generated/resources/data/create/recipes/crushing/raw_zinc_block.json b/src/generated/resources/data/create/recipes/crushing/raw_zinc_block.json index 997e066d03..938b401f06 100644 --- a/src/generated/resources/data/create/recipes/crushing/raw_zinc_block.json +++ b/src/generated/resources/data/create/recipes/crushing/raw_zinc_block.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "count": 9 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/silver_ore.json b/src/generated/resources/data/create/recipes/crushing/silver_ore.json index 9b690f13e1..d11c74ba70 100644 --- a/src/generated/resources/data/create/recipes/crushing/silver_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/silver_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, { - "item": "create:crushed_silver_ore", + "item": "create:crushed_raw_silver", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/tin_ore.json b/src/generated/resources/data/create/recipes/crushing/tin_ore.json index c6d7e1968c..3cc4d2cc02 100644 --- a/src/generated/resources/data/create/recipes/crushing/tin_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/tin_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, { - "item": "create:crushed_tin_ore", + "item": "create:crushed_raw_tin", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/uranium_ore.json b/src/generated/resources/data/create/recipes/crushing/uranium_ore.json index a64647845a..cacf9ee8e9 100644 --- a/src/generated/resources/data/create/recipes/crushing/uranium_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/uranium_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, { - "item": "create:crushed_uranium_ore", + "item": "create:crushed_raw_uranium", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/veridium.json b/src/generated/resources/data/create/recipes/crushing/veridium.json index 1859c92475..05a1bd1ecb 100644 --- a/src/generated/resources/data/create/recipes/crushing/veridium.json +++ b/src/generated/resources/data/create/recipes/crushing/veridium.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "chance": 0.8 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/veridium_recycling.json b/src/generated/resources/data/create/recipes/crushing/veridium_recycling.json index da4b529ddc..8939d44e00 100644 --- a/src/generated/resources/data/create/recipes/crushing/veridium_recycling.json +++ b/src/generated/resources/data/create/recipes/crushing/veridium_recycling.json @@ -7,7 +7,7 @@ ], "results": [ { - "item": "create:crushed_copper_ore", + "item": "create:crushed_raw_copper", "chance": 0.8 }, { diff --git a/src/generated/resources/data/create/recipes/crushing/zinc_ore.json b/src/generated/resources/data/create/recipes/crushing/zinc_ore.json index 6034fe124c..d55e1efd3a 100644 --- a/src/generated/resources/data/create/recipes/crushing/zinc_ore.json +++ b/src/generated/resources/data/create/recipes/crushing/zinc_ore.json @@ -7,10 +7,10 @@ ], "results": [ { - "item": "create:crushed_zinc_ore" + "item": "create:crushed_raw_zinc" }, { - "item": "create:crushed_zinc_ore", + "item": "create:crushed_raw_zinc", "chance": 0.75 }, { diff --git a/src/generated/resources/data/create/recipes/cut_andesite_brick_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_brick_slab_from_andesite_stonecutting.json deleted file mode 100644 index c4f7bbb370..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_brick_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_brick_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_brick_stairs_from_andesite_stonecutting.json deleted file mode 100644 index 12adb3c5ed..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_brick_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_brick_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_brick_wall_from_andesite_stonecutting.json deleted file mode 100644 index fb3b97ab66..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_brick_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_bricks_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_bricks_from_andesite_stonecutting.json deleted file mode 100644 index f51b38098a..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_bricks_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_from_andesite_stonecutting.json deleted file mode 100644 index a189185b80..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_slab_from_andesite_stonecutting.json deleted file mode 100644 index ea5722ed18..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_stairs_from_andesite_stonecutting.json deleted file mode 100644 index f9082bde7f..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_andesite_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_andesite_wall_from_andesite_stonecutting.json deleted file mode 100644 index e1873c45b9..0000000000 --- a/src/generated/resources/data/create/recipes/cut_andesite_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:cut_andesite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_brick_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_brick_slab_from_asurine_stonecutting.json deleted file mode 100644 index 4f619e26bf..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_brick_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_brick_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_brick_stairs_from_asurine_stonecutting.json deleted file mode 100644 index b1bab7db9b..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_brick_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_brick_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_brick_wall_from_asurine_stonecutting.json deleted file mode 100644 index d43b085d32..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_brick_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_bricks_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_bricks_from_asurine_stonecutting.json deleted file mode 100644 index 89e2fa4933..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_bricks_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_from_asurine_stonecutting.json deleted file mode 100644 index fdee584f7e..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_slab_from_asurine_stonecutting.json deleted file mode 100644 index ad2c438ade..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_stairs_from_asurine_stonecutting.json deleted file mode 100644 index 2653b7ab02..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_asurine_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/cut_asurine_wall_from_asurine_stonecutting.json deleted file mode 100644 index c98cecccf7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_asurine_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:cut_asurine_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_brick_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_brick_slab_from_calcite_stonecutting.json deleted file mode 100644 index df106f5d47..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_brick_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_brick_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_brick_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 1d7a942800..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_brick_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_brick_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_brick_wall_from_calcite_stonecutting.json deleted file mode 100644 index 76b5c6aa19..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_brick_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_bricks_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_bricks_from_calcite_stonecutting.json deleted file mode 100644 index 7a8de612b7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_bricks_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_from_calcite_stonecutting.json deleted file mode 100644 index 50989274f7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_slab_from_calcite_stonecutting.json deleted file mode 100644 index b7a50ca967..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 1ba40696c8..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_calcite_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_calcite_wall_from_calcite_stonecutting.json deleted file mode 100644 index 8baafaeab3..0000000000 --- a/src/generated/resources/data/create/recipes/cut_calcite_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:cut_calcite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json deleted file mode 100644 index 944b3d8352..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_brick_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index 92d0586505..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_brick_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json deleted file mode 100644 index 588cf46f2e..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_brick_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_bricks_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_bricks_from_crimsite_stonecutting.json deleted file mode 100644 index c78042ab57..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_bricks_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index c2a20100de..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_slab_from_crimsite_stonecutting.json deleted file mode 100644 index cd393df9c3..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index bf63cf76a8..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_crimsite_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_crimsite_wall_from_crimsite_stonecutting.json deleted file mode 100644 index 12c9c0c5ce..0000000000 --- a/src/generated/resources/data/create/recipes/cut_crimsite_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:cut_crimsite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 78f5b45add..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_brick_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index 322fbfe736..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_brick_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json deleted file mode 100644 index c6aab86394..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_brick_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_bricks_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_bricks_from_deepslate_stonecutting.json deleted file mode 100644 index d3bcca6369..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_bricks_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index 7cf47a9550..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 4e6b17b1d4..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index 2d71b28dfb..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_deepslate_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/cut_deepslate_wall_from_deepslate_stonecutting.json deleted file mode 100644 index bb981f9cf1..0000000000 --- a/src/generated/resources/data/create/recipes/cut_deepslate_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:cut_deepslate_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_brick_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_brick_slab_from_diorite_stonecutting.json deleted file mode 100644 index 92a3e5e889..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_brick_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_brick_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_brick_stairs_from_diorite_stonecutting.json deleted file mode 100644 index 16f98adbbc..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_brick_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_brick_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_brick_wall_from_diorite_stonecutting.json deleted file mode 100644 index a732432aa7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_brick_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_bricks_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_bricks_from_diorite_stonecutting.json deleted file mode 100644 index ca58ac8bf7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_bricks_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_from_diorite_stonecutting.json deleted file mode 100644 index b846e47a87..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_slab_from_diorite_stonecutting.json deleted file mode 100644 index ba2d193e37..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_stairs_from_diorite_stonecutting.json deleted file mode 100644 index 8640a362d3..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_diorite_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_diorite_wall_from_diorite_stonecutting.json deleted file mode 100644 index 5f93e79b25..0000000000 --- a/src/generated/resources/data/create/recipes/cut_diorite_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:cut_diorite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 5d312f6aec..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_brick_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 0b5e5425bf..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_brick_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 0baf61719c..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_brick_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json deleted file mode 100644 index 3f4472f419..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_bricks_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index b336999b59..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 09235fa730..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index abd2d38ff3..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_dripstone_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/cut_dripstone_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 84bb1c2ac2..0000000000 --- a/src/generated/resources/data/create/recipes/cut_dripstone_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:cut_dripstone_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_brick_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_brick_slab_from_granite_stonecutting.json deleted file mode 100644 index 96a5d39b74..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_brick_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_brick_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_brick_stairs_from_granite_stonecutting.json deleted file mode 100644 index b2a58072f1..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_brick_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_brick_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_brick_wall_from_granite_stonecutting.json deleted file mode 100644 index 95fda3972c..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_brick_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_bricks_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_bricks_from_granite_stonecutting.json deleted file mode 100644 index f220122ed7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_bricks_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_from_granite_stonecutting.json deleted file mode 100644 index 428c786ad5..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_slab_from_granite_stonecutting.json deleted file mode 100644 index 6a8549a321..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_stairs_from_granite_stonecutting.json deleted file mode 100644 index 633eabad54..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_granite_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/cut_granite_wall_from_granite_stonecutting.json deleted file mode 100644 index 4b23d1d8e0..0000000000 --- a/src/generated/resources/data/create/recipes/cut_granite_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:cut_granite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_brick_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_brick_slab_from_limestone_stonecutting.json deleted file mode 100644 index 85464f5570..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_brick_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_brick_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_brick_stairs_from_limestone_stonecutting.json deleted file mode 100644 index 2bd442cb1c..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_brick_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_brick_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_brick_wall_from_limestone_stonecutting.json deleted file mode 100644 index f7f3f82e55..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_brick_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_bricks_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_bricks_from_limestone_stonecutting.json deleted file mode 100644 index 4b7a46e02a..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_bricks_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_from_limestone_stonecutting.json deleted file mode 100644 index 54cacd25d7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_slab_from_limestone_stonecutting.json deleted file mode 100644 index eb933fe43a..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_stairs_from_limestone_stonecutting.json deleted file mode 100644 index bf74242280..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_limestone_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/cut_limestone_wall_from_limestone_stonecutting.json deleted file mode 100644 index 641c7a3220..0000000000 --- a/src/generated/resources/data/create/recipes/cut_limestone_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:cut_limestone_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json deleted file mode 100644 index fdfc4cb587..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_brick_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index c30adcd8b7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_brick_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json deleted file mode 100644 index bc2fb08a3e..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_brick_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_bricks_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_bricks_from_ochrum_stonecutting.json deleted file mode 100644 index fbe3b0c422..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_bricks_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index e71ff1de92..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_slab_from_ochrum_stonecutting.json deleted file mode 100644 index 3144a3a706..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index b0560202e1..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_ochrum_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/cut_ochrum_wall_from_ochrum_stonecutting.json deleted file mode 100644 index de1b5154a6..0000000000 --- a/src/generated/resources/data/create/recipes/cut_ochrum_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:cut_ochrum_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json deleted file mode 100644 index c000ad5c37..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_brick_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index bfeb5c6088..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_brick_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 53a9d45957..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_brick_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_bricks_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_bricks_from_scorchia_stonecutting.json deleted file mode 100644 index 1034f3b613..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_bricks_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index fba16329d7..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_slab_from_scorchia_stonecutting.json deleted file mode 100644 index 59e29292c6..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 12d23a164d..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scorchia_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scorchia_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 4be94b90d2..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scorchia_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:cut_scorchia_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_brick_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_brick_slab_from_scoria_stonecutting.json deleted file mode 100644 index e3511ca2a6..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_brick_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_brick_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_brick_stairs_from_scoria_stonecutting.json deleted file mode 100644 index f88949d3a8..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_brick_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_brick_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_brick_wall_from_scoria_stonecutting.json deleted file mode 100644 index 2938482161..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_brick_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_bricks_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_bricks_from_scoria_stonecutting.json deleted file mode 100644 index 411528683c..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_bricks_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_from_scoria_stonecutting.json deleted file mode 100644 index 2217b57757..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_slab_from_scoria_stonecutting.json deleted file mode 100644 index 5be3baa942..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_stairs_from_scoria_stonecutting.json deleted file mode 100644 index c85eb0510a..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_scoria_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/cut_scoria_wall_from_scoria_stonecutting.json deleted file mode 100644 index 5aee65ad4e..0000000000 --- a/src/generated/resources/data/create/recipes/cut_scoria_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:cut_scoria_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_brick_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_brick_slab_from_tuff_stonecutting.json deleted file mode 100644 index e8034a0c31..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_brick_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_brick_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_brick_stairs_from_tuff_stonecutting.json deleted file mode 100644 index 20ac6d7364..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_brick_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_brick_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_brick_wall_from_tuff_stonecutting.json deleted file mode 100644 index f00e156fe0..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_brick_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_bricks_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_bricks_from_tuff_stonecutting.json deleted file mode 100644 index c95e4af73d..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_bricks_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_from_tuff_stonecutting.json deleted file mode 100644 index 09032f0b4f..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_slab_from_tuff_stonecutting.json deleted file mode 100644 index e05b276e7a..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_stairs_from_tuff_stonecutting.json deleted file mode 100644 index 66fe1fa2c1..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_tuff_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/cut_tuff_wall_from_tuff_stonecutting.json deleted file mode 100644 index e4e2bee9a6..0000000000 --- a/src/generated/resources/data/create/recipes/cut_tuff_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:cut_tuff_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_brick_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_brick_slab_from_veridium_stonecutting.json deleted file mode 100644 index f2ac0276a2..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_brick_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_brick_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_brick_stairs_from_veridium_stonecutting.json deleted file mode 100644 index 4d318a47ec..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_brick_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_brick_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_brick_wall_from_veridium_stonecutting.json deleted file mode 100644 index a7b8f9fb80..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_brick_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_bricks_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_bricks_from_veridium_stonecutting.json deleted file mode 100644 index 96985ae8b9..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_bricks_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 9e0f2dbd6f..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_slab_from_veridium_stonecutting.json deleted file mode 100644 index 812f69f40d..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_stairs_from_veridium_stonecutting.json deleted file mode 100644 index 1cbd1aeded..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/cut_veridium_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/cut_veridium_wall_from_veridium_stonecutting.json deleted file mode 100644 index 5bca497759..0000000000 --- a/src/generated/resources/data/create/recipes/cut_veridium_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:cut_veridium_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/deepslate_from_stone_types_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/deepslate_from_stone_types_deepslate_stonecutting.json new file mode 100644 index 0000000000..4bfbcca4a3 --- /dev/null +++ b/src/generated/resources/data/create/recipes/deepslate_from_stone_types_deepslate_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/deepslate" + }, + "result": "minecraft:deepslate", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/deepslate_pillar_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/deepslate_pillar_from_deepslate_stonecutting.json deleted file mode 100644 index 9b521347f4..0000000000 --- a/src/generated/resources/data/create/recipes/deepslate_pillar_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:deepslate_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/diorite_from_stone_types_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/diorite_from_stone_types_diorite_stonecutting.json new file mode 100644 index 0000000000..dae28ec6cc --- /dev/null +++ b/src/generated/resources/data/create/recipes/diorite_from_stone_types_diorite_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/diorite" + }, + "result": "minecraft:diorite", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/diorite_pillar_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/diorite_pillar_from_diorite_stonecutting.json deleted file mode 100644 index 081b88e5c3..0000000000 --- a/src/generated/resources/data/create/recipes/diorite_pillar_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:diorite_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/dripstone_block_from_stone_types_dripstone_stonecutting.json b/src/generated/resources/data/create/recipes/dripstone_block_from_stone_types_dripstone_stonecutting.json new file mode 100644 index 0000000000..d9fc9483f5 --- /dev/null +++ b/src/generated/resources/data/create/recipes/dripstone_block_from_stone_types_dripstone_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/dripstone" + }, + "result": "minecraft:dripstone_block", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/dripstone_pillar_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/dripstone_pillar_from_dripstone_block_stonecutting.json deleted file mode 100644 index 9b7cd8e7cc..0000000000 --- a/src/generated/resources/data/create/recipes/dripstone_pillar_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:dripstone_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/granite_from_stone_types_granite_stonecutting.json b/src/generated/resources/data/create/recipes/granite_from_stone_types_granite_stonecutting.json new file mode 100644 index 0000000000..4a00abb834 --- /dev/null +++ b/src/generated/resources/data/create/recipes/granite_from_stone_types_granite_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/granite" + }, + "result": "minecraft:granite", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/granite_pillar_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/granite_pillar_from_granite_stonecutting.json deleted file mode 100644 index 7df1313ef7..0000000000 --- a/src/generated/resources/data/create/recipes/granite_pillar_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:granite_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/industrial_iron_block_from_ingots_iron_stonecutting.json b/src/generated/resources/data/create/recipes/industrial_iron_block_from_ingots_iron_stonecutting.json new file mode 100644 index 0000000000..a811a2aa5c --- /dev/null +++ b/src/generated/resources/data/create/recipes/industrial_iron_block_from_ingots_iron_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "forge:ingots/iron" + }, + "result": "create:industrial_iron_block", + "count": 2 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/layered_andesite_from_andesite_stonecutting.json deleted file mode 100644 index c7fefccfcc..0000000000 --- a/src/generated/resources/data/create/recipes/layered_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:layered_andesite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/layered_asurine_from_asurine_stonecutting.json deleted file mode 100644 index c70d98ec5d..0000000000 --- a/src/generated/resources/data/create/recipes/layered_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:layered_asurine", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/layered_calcite_from_calcite_stonecutting.json deleted file mode 100644 index 9d893e95f5..0000000000 --- a/src/generated/resources/data/create/recipes/layered_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:layered_calcite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/layered_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index c83c1eead7..0000000000 --- a/src/generated/resources/data/create/recipes/layered_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:layered_crimsite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/layered_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index 5316e62d5b..0000000000 --- a/src/generated/resources/data/create/recipes/layered_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:layered_deepslate", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/layered_diorite_from_diorite_stonecutting.json deleted file mode 100644 index 9f290ccc51..0000000000 --- a/src/generated/resources/data/create/recipes/layered_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:layered_diorite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/layered_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index b602f12b58..0000000000 --- a/src/generated/resources/data/create/recipes/layered_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:layered_dripstone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/layered_granite_from_granite_stonecutting.json deleted file mode 100644 index 384c7912eb..0000000000 --- a/src/generated/resources/data/create/recipes/layered_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:layered_granite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/layered_limestone_from_limestone_stonecutting.json deleted file mode 100644 index bfec0ef447..0000000000 --- a/src/generated/resources/data/create/recipes/layered_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:layered_limestone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/layered_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index 3112ae4d70..0000000000 --- a/src/generated/resources/data/create/recipes/layered_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:layered_ochrum", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/layered_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index 37c1cab08f..0000000000 --- a/src/generated/resources/data/create/recipes/layered_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:layered_scorchia", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/layered_scoria_from_scoria_stonecutting.json deleted file mode 100644 index e6b6c0e567..0000000000 --- a/src/generated/resources/data/create/recipes/layered_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:layered_scoria", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/layered_tuff_from_tuff_stonecutting.json deleted file mode 100644 index 5cf19409cc..0000000000 --- a/src/generated/resources/data/create/recipes/layered_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:layered_tuff", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/layered_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/layered_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 2c863952a8..0000000000 --- a/src/generated/resources/data/create/recipes/layered_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:layered_veridium", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/limestone_from_stone_types_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/limestone_from_stone_types_limestone_stonecutting.json new file mode 100644 index 0000000000..de24e5fb57 --- /dev/null +++ b/src/generated/resources/data/create/recipes/limestone_from_stone_types_limestone_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/limestone" + }, + "result": "create:limestone", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/limestone_pillar_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/limestone_pillar_from_limestone_stonecutting.json deleted file mode 100644 index b1bb3e8775..0000000000 --- a/src/generated/resources/data/create/recipes/limestone_pillar_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:limestone_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/ochrum_from_stone_types_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/ochrum_from_stone_types_ochrum_stonecutting.json new file mode 100644 index 0000000000..85c2c92591 --- /dev/null +++ b/src/generated/resources/data/create/recipes/ochrum_from_stone_types_ochrum_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/ochrum" + }, + "result": "create:ochrum", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/ochrum_pillar_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/ochrum_pillar_from_ochrum_stonecutting.json deleted file mode 100644 index de3d3c8c27..0000000000 --- a/src/generated/resources/data/create/recipes/ochrum_pillar_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:ochrum_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_andesite_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_andesite_from_andesite_stonecutting.json deleted file mode 100644 index 53249f792e..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_andesite_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:polished_cut_andesite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_andesite_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_andesite_slab_from_andesite_stonecutting.json deleted file mode 100644 index 7b791b2526..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_andesite_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:polished_cut_andesite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_andesite_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_andesite_stairs_from_andesite_stonecutting.json deleted file mode 100644 index 27af6d8bb3..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_andesite_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:polished_cut_andesite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_andesite_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_andesite_wall_from_andesite_stonecutting.json deleted file mode 100644 index f1c7eaa00f..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_andesite_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:polished_cut_andesite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_asurine_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_asurine_from_asurine_stonecutting.json deleted file mode 100644 index 2f0e3cb1c6..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_asurine_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:polished_cut_asurine", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_asurine_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_asurine_slab_from_asurine_stonecutting.json deleted file mode 100644 index 79c031a50d..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_asurine_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:polished_cut_asurine_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_asurine_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_asurine_stairs_from_asurine_stonecutting.json deleted file mode 100644 index decbcb3e63..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_asurine_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:polished_cut_asurine_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_asurine_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_asurine_wall_from_asurine_stonecutting.json deleted file mode 100644 index e5c5b111ff..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_asurine_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:polished_cut_asurine_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_calcite_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_calcite_from_calcite_stonecutting.json deleted file mode 100644 index 604019c74e..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_calcite_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:polished_cut_calcite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_calcite_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_calcite_slab_from_calcite_stonecutting.json deleted file mode 100644 index 709b18a4eb..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_calcite_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:polished_cut_calcite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_calcite_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_calcite_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 511d3f99b1..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_calcite_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:polished_cut_calcite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_calcite_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_calcite_wall_from_calcite_stonecutting.json deleted file mode 100644 index 7ba2d02b96..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_calcite_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:polished_cut_calcite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_crimsite_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_crimsite_from_crimsite_stonecutting.json deleted file mode 100644 index 88578ffb11..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_crimsite_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:polished_cut_crimsite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json deleted file mode 100644 index 3be734fb15..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_crimsite_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:polished_cut_crimsite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index 4dcef5004b..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_crimsite_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:polished_cut_crimsite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json deleted file mode 100644 index 3a70c67e3b..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_crimsite_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:polished_cut_crimsite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_deepslate_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_deepslate_from_deepslate_stonecutting.json deleted file mode 100644 index 28ce710103..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_deepslate_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:polished_cut_deepslate", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 7b5833aa87..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_deepslate_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:polished_cut_deepslate_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index 674953e81b..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_deepslate_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:polished_cut_deepslate_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json deleted file mode 100644 index a336343094..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_deepslate_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:polished_cut_deepslate_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_diorite_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_diorite_from_diorite_stonecutting.json deleted file mode 100644 index 828d997c07..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_diorite_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:polished_cut_diorite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_diorite_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_diorite_slab_from_diorite_stonecutting.json deleted file mode 100644 index b9f9478515..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_diorite_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:polished_cut_diorite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_diorite_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_diorite_stairs_from_diorite_stonecutting.json deleted file mode 100644 index cb271a5167..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_diorite_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:polished_cut_diorite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_diorite_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_diorite_wall_from_diorite_stonecutting.json deleted file mode 100644 index 3bf5e9937a..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_diorite_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:polished_cut_diorite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_dripstone_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_dripstone_from_dripstone_block_stonecutting.json deleted file mode 100644 index f3d7ba8788..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_dripstone_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:polished_cut_dripstone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index 6829d80dbf..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_dripstone_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:polished_cut_dripstone_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 3ea93e1b9c..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_dripstone_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:polished_cut_dripstone_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 39a6586b9e..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_dripstone_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:polished_cut_dripstone_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_granite_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_granite_from_granite_stonecutting.json deleted file mode 100644 index 58612c9e61..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_granite_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:polished_cut_granite", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_granite_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_granite_slab_from_granite_stonecutting.json deleted file mode 100644 index b3f5b2f9f7..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_granite_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:polished_cut_granite_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_granite_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_granite_stairs_from_granite_stonecutting.json deleted file mode 100644 index 71e414bdf6..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_granite_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:polished_cut_granite_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_granite_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_granite_wall_from_granite_stonecutting.json deleted file mode 100644 index 7413437119..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_granite_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:polished_cut_granite_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_limestone_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_limestone_from_limestone_stonecutting.json deleted file mode 100644 index 274cefa2c3..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_limestone_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:polished_cut_limestone", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_limestone_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_limestone_slab_from_limestone_stonecutting.json deleted file mode 100644 index 2b149708c5..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_limestone_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:polished_cut_limestone_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_limestone_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_limestone_stairs_from_limestone_stonecutting.json deleted file mode 100644 index 06ffafe132..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_limestone_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:polished_cut_limestone_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_limestone_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_limestone_wall_from_limestone_stonecutting.json deleted file mode 100644 index 7ff25fd9a5..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_limestone_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:polished_cut_limestone_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_ochrum_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_ochrum_from_ochrum_stonecutting.json deleted file mode 100644 index ff851fef95..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_ochrum_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:polished_cut_ochrum", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json deleted file mode 100644 index 1ea2a4ea81..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_ochrum_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:polished_cut_ochrum_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index 51834c41b6..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_ochrum_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:polished_cut_ochrum_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json deleted file mode 100644 index 2886d40f72..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_ochrum_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:polished_cut_ochrum_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scorchia_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scorchia_from_scorchia_stonecutting.json deleted file mode 100644 index 169e35165b..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scorchia_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:polished_cut_scorchia", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json deleted file mode 100644 index bc009d55d3..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scorchia_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:polished_cut_scorchia_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 2fb4ead570..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scorchia_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:polished_cut_scorchia_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json deleted file mode 100644 index 8e1148b0c5..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scorchia_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:polished_cut_scorchia_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scoria_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scoria_from_scoria_stonecutting.json deleted file mode 100644 index 4cfb705a70..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scoria_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:polished_cut_scoria", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scoria_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scoria_slab_from_scoria_stonecutting.json deleted file mode 100644 index 1003cdb787..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scoria_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:polished_cut_scoria_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scoria_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scoria_stairs_from_scoria_stonecutting.json deleted file mode 100644 index c63976afef..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scoria_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:polished_cut_scoria_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_scoria_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_scoria_wall_from_scoria_stonecutting.json deleted file mode 100644 index b0e06af959..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_scoria_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:polished_cut_scoria_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_tuff_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_tuff_from_tuff_stonecutting.json deleted file mode 100644 index a4ac8327fd..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_tuff_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:polished_cut_tuff", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_tuff_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_tuff_slab_from_tuff_stonecutting.json deleted file mode 100644 index 44bdbf3a33..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_tuff_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:polished_cut_tuff_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_tuff_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_tuff_stairs_from_tuff_stonecutting.json deleted file mode 100644 index e1119f9709..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_tuff_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:polished_cut_tuff_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_tuff_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_tuff_wall_from_tuff_stonecutting.json deleted file mode 100644 index ee7e81be5a..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_tuff_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:polished_cut_tuff_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_veridium_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_veridium_from_veridium_stonecutting.json deleted file mode 100644 index 607010f9ab..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_veridium_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:polished_cut_veridium", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_veridium_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_veridium_slab_from_veridium_stonecutting.json deleted file mode 100644 index b0af66cf6d..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_veridium_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:polished_cut_veridium_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_veridium_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_veridium_stairs_from_veridium_stonecutting.json deleted file mode 100644 index de35709c8b..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_veridium_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:polished_cut_veridium_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/polished_cut_veridium_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/polished_cut_veridium_wall_from_veridium_stonecutting.json deleted file mode 100644 index cfb67813d8..0000000000 --- a/src/generated/resources/data/create/recipes/polished_cut_veridium_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:polished_cut_veridium_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/scorchia_from_stone_types_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/scorchia_from_stone_types_scorchia_stonecutting.json new file mode 100644 index 0000000000..6daab9da79 --- /dev/null +++ b/src/generated/resources/data/create/recipes/scorchia_from_stone_types_scorchia_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/scorchia" + }, + "result": "create:scorchia", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/scorchia_pillar_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/scorchia_pillar_from_scorchia_stonecutting.json deleted file mode 100644 index af299139b5..0000000000 --- a/src/generated/resources/data/create/recipes/scorchia_pillar_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:scorchia_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/scoria_from_stone_types_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/scoria_from_stone_types_scoria_stonecutting.json new file mode 100644 index 0000000000..bf0b2aca43 --- /dev/null +++ b/src/generated/resources/data/create/recipes/scoria_from_stone_types_scoria_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/scoria" + }, + "result": "create:scoria", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/scoria_pillar_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/scoria_pillar_from_scoria_stonecutting.json deleted file mode 100644 index 4e25cf1d89..0000000000 --- a/src/generated/resources/data/create/recipes/scoria_pillar_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:scoria_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/sequenced_assembly/precision_mechanism.json b/src/generated/resources/data/create/recipes/sequenced_assembly/precision_mechanism.json index 581708a726..2f025dc8a9 100644 --- a/src/generated/resources/data/create/recipes/sequenced_assembly/precision_mechanism.json +++ b/src/generated/resources/data/create/recipes/sequenced_assembly/precision_mechanism.json @@ -82,7 +82,7 @@ "chance": 2.0 }, { - "item": "create:crushed_gold_ore", + "item": "create:crushed_raw_gold", "chance": 2.0 }, { diff --git a/src/generated/resources/data/create/recipes/small_andesite_brick_slab_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/small_andesite_brick_slab_from_andesite_stonecutting.json deleted file mode 100644 index e5be2955ee..0000000000 --- a/src/generated/resources/data/create/recipes/small_andesite_brick_slab_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:small_andesite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_andesite_brick_stairs_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/small_andesite_brick_stairs_from_andesite_stonecutting.json deleted file mode 100644 index 52d9f2b2c9..0000000000 --- a/src/generated/resources/data/create/recipes/small_andesite_brick_stairs_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:small_andesite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_andesite_brick_wall_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/small_andesite_brick_wall_from_andesite_stonecutting.json deleted file mode 100644 index 48703ea743..0000000000 --- a/src/generated/resources/data/create/recipes/small_andesite_brick_wall_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:small_andesite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_andesite_bricks_from_andesite_stonecutting.json b/src/generated/resources/data/create/recipes/small_andesite_bricks_from_andesite_stonecutting.json deleted file mode 100644 index ec5d6c50c8..0000000000 --- a/src/generated/resources/data/create/recipes/small_andesite_bricks_from_andesite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:andesite" - }, - "result": "create:small_andesite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_asurine_brick_slab_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/small_asurine_brick_slab_from_asurine_stonecutting.json deleted file mode 100644 index 75602a95ba..0000000000 --- a/src/generated/resources/data/create/recipes/small_asurine_brick_slab_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:small_asurine_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_asurine_brick_stairs_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/small_asurine_brick_stairs_from_asurine_stonecutting.json deleted file mode 100644 index 22b6beea2e..0000000000 --- a/src/generated/resources/data/create/recipes/small_asurine_brick_stairs_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:small_asurine_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_asurine_brick_wall_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/small_asurine_brick_wall_from_asurine_stonecutting.json deleted file mode 100644 index 552ce44d61..0000000000 --- a/src/generated/resources/data/create/recipes/small_asurine_brick_wall_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:small_asurine_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_asurine_bricks_from_asurine_stonecutting.json b/src/generated/resources/data/create/recipes/small_asurine_bricks_from_asurine_stonecutting.json deleted file mode 100644 index 2a291a1731..0000000000 --- a/src/generated/resources/data/create/recipes/small_asurine_bricks_from_asurine_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:asurine" - }, - "result": "create:small_asurine_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_calcite_brick_slab_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/small_calcite_brick_slab_from_calcite_stonecutting.json deleted file mode 100644 index 34b2f9d9d7..0000000000 --- a/src/generated/resources/data/create/recipes/small_calcite_brick_slab_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:small_calcite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_calcite_brick_stairs_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/small_calcite_brick_stairs_from_calcite_stonecutting.json deleted file mode 100644 index 20f9bbbf55..0000000000 --- a/src/generated/resources/data/create/recipes/small_calcite_brick_stairs_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:small_calcite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_calcite_brick_wall_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/small_calcite_brick_wall_from_calcite_stonecutting.json deleted file mode 100644 index ef324aa739..0000000000 --- a/src/generated/resources/data/create/recipes/small_calcite_brick_wall_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:small_calcite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_calcite_bricks_from_calcite_stonecutting.json b/src/generated/resources/data/create/recipes/small_calcite_bricks_from_calcite_stonecutting.json deleted file mode 100644 index e9fbb9d974..0000000000 --- a/src/generated/resources/data/create/recipes/small_calcite_bricks_from_calcite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:calcite" - }, - "result": "create:small_calcite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_crimsite_brick_slab_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/small_crimsite_brick_slab_from_crimsite_stonecutting.json deleted file mode 100644 index c1f8ea305a..0000000000 --- a/src/generated/resources/data/create/recipes/small_crimsite_brick_slab_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:small_crimsite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json deleted file mode 100644 index 35c5793931..0000000000 --- a/src/generated/resources/data/create/recipes/small_crimsite_brick_stairs_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:small_crimsite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_crimsite_brick_wall_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/small_crimsite_brick_wall_from_crimsite_stonecutting.json deleted file mode 100644 index c3467a82bd..0000000000 --- a/src/generated/resources/data/create/recipes/small_crimsite_brick_wall_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:small_crimsite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_crimsite_bricks_from_crimsite_stonecutting.json b/src/generated/resources/data/create/recipes/small_crimsite_bricks_from_crimsite_stonecutting.json deleted file mode 100644 index ee3a10246e..0000000000 --- a/src/generated/resources/data/create/recipes/small_crimsite_bricks_from_crimsite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:crimsite" - }, - "result": "create:small_crimsite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_deepslate_brick_slab_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/small_deepslate_brick_slab_from_deepslate_stonecutting.json deleted file mode 100644 index 6d5b703204..0000000000 --- a/src/generated/resources/data/create/recipes/small_deepslate_brick_slab_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:small_deepslate_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json deleted file mode 100644 index d8ca482a63..0000000000 --- a/src/generated/resources/data/create/recipes/small_deepslate_brick_stairs_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:small_deepslate_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_deepslate_brick_wall_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/small_deepslate_brick_wall_from_deepslate_stonecutting.json deleted file mode 100644 index 57b002aa6d..0000000000 --- a/src/generated/resources/data/create/recipes/small_deepslate_brick_wall_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:small_deepslate_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_deepslate_bricks_from_deepslate_stonecutting.json b/src/generated/resources/data/create/recipes/small_deepslate_bricks_from_deepslate_stonecutting.json deleted file mode 100644 index 0f0f106701..0000000000 --- a/src/generated/resources/data/create/recipes/small_deepslate_bricks_from_deepslate_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:deepslate" - }, - "result": "create:small_deepslate_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_diorite_brick_slab_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/small_diorite_brick_slab_from_diorite_stonecutting.json deleted file mode 100644 index e799a935e6..0000000000 --- a/src/generated/resources/data/create/recipes/small_diorite_brick_slab_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:small_diorite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_diorite_brick_stairs_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/small_diorite_brick_stairs_from_diorite_stonecutting.json deleted file mode 100644 index ea257c0da6..0000000000 --- a/src/generated/resources/data/create/recipes/small_diorite_brick_stairs_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:small_diorite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_diorite_brick_wall_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/small_diorite_brick_wall_from_diorite_stonecutting.json deleted file mode 100644 index 5d80dc85b5..0000000000 --- a/src/generated/resources/data/create/recipes/small_diorite_brick_wall_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:small_diorite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_diorite_bricks_from_diorite_stonecutting.json b/src/generated/resources/data/create/recipes/small_diorite_bricks_from_diorite_stonecutting.json deleted file mode 100644 index ee48ce9e96..0000000000 --- a/src/generated/resources/data/create/recipes/small_diorite_bricks_from_diorite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:diorite" - }, - "result": "create:small_diorite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json deleted file mode 100644 index f6916143a8..0000000000 --- a/src/generated/resources/data/create/recipes/small_dripstone_brick_slab_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:small_dripstone_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json deleted file mode 100644 index 58717fa3f0..0000000000 --- a/src/generated/resources/data/create/recipes/small_dripstone_brick_stairs_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:small_dripstone_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json deleted file mode 100644 index 9eaba011c6..0000000000 --- a/src/generated/resources/data/create/recipes/small_dripstone_brick_wall_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:small_dripstone_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_dripstone_bricks_from_dripstone_block_stonecutting.json b/src/generated/resources/data/create/recipes/small_dripstone_bricks_from_dripstone_block_stonecutting.json deleted file mode 100644 index 4a901aae4f..0000000000 --- a/src/generated/resources/data/create/recipes/small_dripstone_bricks_from_dripstone_block_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:dripstone_block" - }, - "result": "create:small_dripstone_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_granite_brick_slab_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/small_granite_brick_slab_from_granite_stonecutting.json deleted file mode 100644 index 0107936cb4..0000000000 --- a/src/generated/resources/data/create/recipes/small_granite_brick_slab_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:small_granite_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_granite_brick_stairs_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/small_granite_brick_stairs_from_granite_stonecutting.json deleted file mode 100644 index 0e57b8884b..0000000000 --- a/src/generated/resources/data/create/recipes/small_granite_brick_stairs_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:small_granite_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_granite_brick_wall_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/small_granite_brick_wall_from_granite_stonecutting.json deleted file mode 100644 index 83d1b94ddf..0000000000 --- a/src/generated/resources/data/create/recipes/small_granite_brick_wall_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:small_granite_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_granite_bricks_from_granite_stonecutting.json b/src/generated/resources/data/create/recipes/small_granite_bricks_from_granite_stonecutting.json deleted file mode 100644 index 7aff8dff48..0000000000 --- a/src/generated/resources/data/create/recipes/small_granite_bricks_from_granite_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:granite" - }, - "result": "create:small_granite_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_limestone_brick_slab_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/small_limestone_brick_slab_from_limestone_stonecutting.json deleted file mode 100644 index 2ca1dab8fb..0000000000 --- a/src/generated/resources/data/create/recipes/small_limestone_brick_slab_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:small_limestone_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_limestone_brick_stairs_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/small_limestone_brick_stairs_from_limestone_stonecutting.json deleted file mode 100644 index f494e4b99a..0000000000 --- a/src/generated/resources/data/create/recipes/small_limestone_brick_stairs_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:small_limestone_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_limestone_brick_wall_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/small_limestone_brick_wall_from_limestone_stonecutting.json deleted file mode 100644 index 25954f0f06..0000000000 --- a/src/generated/resources/data/create/recipes/small_limestone_brick_wall_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:small_limestone_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_limestone_bricks_from_limestone_stonecutting.json b/src/generated/resources/data/create/recipes/small_limestone_bricks_from_limestone_stonecutting.json deleted file mode 100644 index 2060663e97..0000000000 --- a/src/generated/resources/data/create/recipes/small_limestone_bricks_from_limestone_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:limestone" - }, - "result": "create:small_limestone_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_ochrum_brick_slab_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/small_ochrum_brick_slab_from_ochrum_stonecutting.json deleted file mode 100644 index 60102742ac..0000000000 --- a/src/generated/resources/data/create/recipes/small_ochrum_brick_slab_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:small_ochrum_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json deleted file mode 100644 index 661193b819..0000000000 --- a/src/generated/resources/data/create/recipes/small_ochrum_brick_stairs_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:small_ochrum_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_ochrum_brick_wall_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/small_ochrum_brick_wall_from_ochrum_stonecutting.json deleted file mode 100644 index cd8cca5d1c..0000000000 --- a/src/generated/resources/data/create/recipes/small_ochrum_brick_wall_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:small_ochrum_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_ochrum_bricks_from_ochrum_stonecutting.json b/src/generated/resources/data/create/recipes/small_ochrum_bricks_from_ochrum_stonecutting.json deleted file mode 100644 index c87615a4cc..0000000000 --- a/src/generated/resources/data/create/recipes/small_ochrum_bricks_from_ochrum_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:ochrum" - }, - "result": "create:small_ochrum_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scorchia_brick_slab_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/small_scorchia_brick_slab_from_scorchia_stonecutting.json deleted file mode 100644 index f75c040cee..0000000000 --- a/src/generated/resources/data/create/recipes/small_scorchia_brick_slab_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:small_scorchia_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json deleted file mode 100644 index 97baa5c4d2..0000000000 --- a/src/generated/resources/data/create/recipes/small_scorchia_brick_stairs_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:small_scorchia_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scorchia_brick_wall_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/small_scorchia_brick_wall_from_scorchia_stonecutting.json deleted file mode 100644 index d1fcb853cb..0000000000 --- a/src/generated/resources/data/create/recipes/small_scorchia_brick_wall_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:small_scorchia_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scorchia_bricks_from_scorchia_stonecutting.json b/src/generated/resources/data/create/recipes/small_scorchia_bricks_from_scorchia_stonecutting.json deleted file mode 100644 index e93f5ed3ed..0000000000 --- a/src/generated/resources/data/create/recipes/small_scorchia_bricks_from_scorchia_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scorchia" - }, - "result": "create:small_scorchia_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scoria_brick_slab_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/small_scoria_brick_slab_from_scoria_stonecutting.json deleted file mode 100644 index 1fe7341fb7..0000000000 --- a/src/generated/resources/data/create/recipes/small_scoria_brick_slab_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:small_scoria_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scoria_brick_stairs_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/small_scoria_brick_stairs_from_scoria_stonecutting.json deleted file mode 100644 index 0259202cbf..0000000000 --- a/src/generated/resources/data/create/recipes/small_scoria_brick_stairs_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:small_scoria_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scoria_brick_wall_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/small_scoria_brick_wall_from_scoria_stonecutting.json deleted file mode 100644 index 6db64baf99..0000000000 --- a/src/generated/resources/data/create/recipes/small_scoria_brick_wall_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:small_scoria_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_scoria_bricks_from_scoria_stonecutting.json b/src/generated/resources/data/create/recipes/small_scoria_bricks_from_scoria_stonecutting.json deleted file mode 100644 index e4a667b391..0000000000 --- a/src/generated/resources/data/create/recipes/small_scoria_bricks_from_scoria_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:scoria" - }, - "result": "create:small_scoria_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_tuff_brick_slab_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/small_tuff_brick_slab_from_tuff_stonecutting.json deleted file mode 100644 index db6e520db3..0000000000 --- a/src/generated/resources/data/create/recipes/small_tuff_brick_slab_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:small_tuff_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_tuff_brick_stairs_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/small_tuff_brick_stairs_from_tuff_stonecutting.json deleted file mode 100644 index e6e5df595a..0000000000 --- a/src/generated/resources/data/create/recipes/small_tuff_brick_stairs_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:small_tuff_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_tuff_brick_wall_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/small_tuff_brick_wall_from_tuff_stonecutting.json deleted file mode 100644 index ebcb5fe6af..0000000000 --- a/src/generated/resources/data/create/recipes/small_tuff_brick_wall_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:small_tuff_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_tuff_bricks_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/small_tuff_bricks_from_tuff_stonecutting.json deleted file mode 100644 index 268a3519b4..0000000000 --- a/src/generated/resources/data/create/recipes/small_tuff_bricks_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:small_tuff_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_veridium_brick_slab_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/small_veridium_brick_slab_from_veridium_stonecutting.json deleted file mode 100644 index 8bfc43bbd5..0000000000 --- a/src/generated/resources/data/create/recipes/small_veridium_brick_slab_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:small_veridium_brick_slab", - "count": 2 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_veridium_brick_stairs_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/small_veridium_brick_stairs_from_veridium_stonecutting.json deleted file mode 100644 index 40dc666c48..0000000000 --- a/src/generated/resources/data/create/recipes/small_veridium_brick_stairs_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:small_veridium_brick_stairs", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_veridium_brick_wall_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/small_veridium_brick_wall_from_veridium_stonecutting.json deleted file mode 100644 index 7ad18f781c..0000000000 --- a/src/generated/resources/data/create/recipes/small_veridium_brick_wall_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:small_veridium_brick_wall", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/small_veridium_bricks_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/small_veridium_bricks_from_veridium_stonecutting.json deleted file mode 100644 index 934416a300..0000000000 --- a/src/generated/resources/data/create/recipes/small_veridium_bricks_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:small_veridium_bricks", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/smelting/copper_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/smelting/copper_ingot_from_crushed.json index 3ce7bf74a1..805373c586 100644 --- a/src/generated/resources/data/create/recipes/smelting/copper_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/smelting/copper_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_copper_ore" + "item": "create:crushed_raw_copper" }, "result": "minecraft:copper_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/gold_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/smelting/gold_ingot_from_crushed.json index 6bf7613bb6..0c551e13d5 100644 --- a/src/generated/resources/data/create/recipes/smelting/gold_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/smelting/gold_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_gold_ore" + "item": "create:crushed_raw_gold" }, "result": "minecraft:gold_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json index e76df0c7d1..32d4379a59 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_aluminum_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_aluminum_ore" + "item": "create:crushed_raw_aluminum" }, "result": "immersiveengineering:ingot_aluminum", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json index c204213ef3..3902f4aef8 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "immersiveengineering:ingot_lead", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_mekanism.json b/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_mekanism.json index 58622c15c6..7ef5505f4d 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_lead_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "mekanism:ingot_lead", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_nickel_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/smelting/ingot_nickel_compat_immersiveengineering.json index 1beebd3554..ff73071c57 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_nickel_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_nickel_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, "result": "immersiveengineering:ingot_nickel", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_osmium_compat_mekanism.json b/src/generated/resources/data/create/recipes/smelting/ingot_osmium_compat_mekanism.json index 56f95d5f3d..0b080c1566 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_osmium_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_osmium_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_osmium_ore" + "item": "create:crushed_raw_osmium" }, "result": "mekanism:ingot_osmium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_silver_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/smelting/ingot_silver_compat_immersiveengineering.json index 02570ae93f..cb76eb8e8e 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_silver_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_silver_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, "result": "immersiveengineering:ingot_silver", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_tin_compat_mekanism.json b/src/generated/resources/data/create/recipes/smelting/ingot_tin_compat_mekanism.json index 476cd49424..a8902699a4 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_tin_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_tin_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, "result": "mekanism:ingot_tin", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_immersiveengineering.json b/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_immersiveengineering.json index a036fdfa25..d1dddad5c3 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_immersiveengineering.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_immersiveengineering.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, "result": "immersiveengineering:ingot_uranium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_mekanism.json b/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_mekanism.json index de12e07e3e..2244bad906 100644 --- a/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_mekanism.json +++ b/src/generated/resources/data/create/recipes/smelting/ingot_uranium_compat_mekanism.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_uranium_ore" + "item": "create:crushed_raw_uranium" }, "result": "mekanism:ingot_uranium", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/iron_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/smelting/iron_ingot_from_crushed.json index f2d3dfc51f..efef20b761 100644 --- a/src/generated/resources/data/create/recipes/smelting/iron_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/smelting/iron_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_iron_ore" + "item": "create:crushed_raw_iron" }, "result": "minecraft:iron_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/lead_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/smelting/lead_ingot_compat_thermal.json index 0a6ead4f69..54f9f37ea7 100644 --- a/src/generated/resources/data/create/recipes/smelting/lead_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/smelting/lead_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_lead_ore" + "item": "create:crushed_raw_lead" }, "result": "thermal:lead_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/nickel_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/smelting/nickel_ingot_compat_thermal.json index 03c534ae3c..3a63a973f7 100644 --- a/src/generated/resources/data/create/recipes/smelting/nickel_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/smelting/nickel_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_nickel_ore" + "item": "create:crushed_raw_nickel" }, "result": "thermal:nickel_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/silver_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/smelting/silver_ingot_compat_thermal.json index 6d5039376f..2525f899af 100644 --- a/src/generated/resources/data/create/recipes/smelting/silver_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/smelting/silver_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_silver_ore" + "item": "create:crushed_raw_silver" }, "result": "thermal:silver_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/tin_ingot_compat_thermal.json b/src/generated/resources/data/create/recipes/smelting/tin_ingot_compat_thermal.json index e70aac3006..8a6d0c6129 100644 --- a/src/generated/resources/data/create/recipes/smelting/tin_ingot_compat_thermal.json +++ b/src/generated/resources/data/create/recipes/smelting/tin_ingot_compat_thermal.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_tin_ore" + "item": "create:crushed_raw_tin" }, "result": "thermal:tin_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/smelting/zinc_ingot_from_crushed.json b/src/generated/resources/data/create/recipes/smelting/zinc_ingot_from_crushed.json index 5ccc6df6e4..c030b33737 100644 --- a/src/generated/resources/data/create/recipes/smelting/zinc_ingot_from_crushed.json +++ b/src/generated/resources/data/create/recipes/smelting/zinc_ingot_from_crushed.json @@ -1,7 +1,7 @@ { "type": "minecraft:smelting", "ingredient": { - "item": "create:crushed_zinc_ore" + "item": "create:crushed_raw_zinc" }, "result": "create:zinc_ingot", "experience": 0.1, diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_copper_ore.json b/src/generated/resources/data/create/recipes/splashing/crushed_copper_ore.json deleted file mode 100644 index 18ab1116c8..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/crushed_copper_ore.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_copper_ore" - } - ], - "results": [ - { - "item": "create:copper_nugget", - "count": 9 - }, - { - "item": "minecraft:clay_ball", - "chance": 0.5 - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_gold_ore.json b/src/generated/resources/data/create/recipes/splashing/crushed_gold_ore.json deleted file mode 100644 index 19bef6491a..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/crushed_gold_ore.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_gold_ore" - } - ], - "results": [ - { - "item": "minecraft:gold_nugget", - "count": 9 - }, - { - "item": "minecraft:quartz", - "chance": 0.5 - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_iron_ore.json b/src/generated/resources/data/create/recipes/splashing/crushed_iron_ore.json deleted file mode 100644 index 5e37b20cf6..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/crushed_iron_ore.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_iron_ore" - } - ], - "results": [ - { - "item": "minecraft:iron_nugget", - "count": 9 - }, - { - "item": "minecraft:redstone", - "chance": 0.75 - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_raw_copper.json b/src/generated/resources/data/create/recipes/splashing/crushed_raw_copper.json new file mode 100644 index 0000000000..d2a077a382 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/crushed_raw_copper.json @@ -0,0 +1,18 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_copper" + } + ], + "results": [ + { + "item": "create:copper_nugget", + "count": 9 + }, + { + "item": "minecraft:clay_ball", + "chance": 0.5 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_raw_gold.json b/src/generated/resources/data/create/recipes/splashing/crushed_raw_gold.json new file mode 100644 index 0000000000..3ee701ffc1 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/crushed_raw_gold.json @@ -0,0 +1,18 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_gold" + } + ], + "results": [ + { + "item": "minecraft:gold_nugget", + "count": 9 + }, + { + "item": "minecraft:quartz", + "chance": 0.5 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_raw_iron.json b/src/generated/resources/data/create/recipes/splashing/crushed_raw_iron.json new file mode 100644 index 0000000000..c06bd49f73 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/crushed_raw_iron.json @@ -0,0 +1,18 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_iron" + } + ], + "results": [ + { + "item": "minecraft:iron_nugget", + "count": 9 + }, + { + "item": "minecraft:redstone", + "chance": 0.75 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_raw_zinc.json b/src/generated/resources/data/create/recipes/splashing/crushed_raw_zinc.json new file mode 100644 index 0000000000..8607029160 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/crushed_raw_zinc.json @@ -0,0 +1,18 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_zinc" + } + ], + "results": [ + { + "item": "create:zinc_nugget", + "count": 9 + }, + { + "item": "minecraft:gunpowder", + "chance": 0.25 + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/crushed_zinc_ore.json b/src/generated/resources/data/create/recipes/splashing/crushed_zinc_ore.json deleted file mode 100644 index b147f25fdc..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/crushed_zinc_ore.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_zinc_ore" - } - ], - "results": [ - { - "item": "create:zinc_nugget", - "count": 9 - }, - { - "item": "minecraft:gunpowder", - "chance": 0.25 - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_aluminum_ore.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_aluminum_ore.json deleted file mode 100644 index 167f6c5aa9..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_aluminum_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_aluminum_ore" - } - ], - "results": [ - { - "item": "immersiveengineering:nugget_aluminum", - "count": 9 - } - ], - "conditions": [ - { - "modid": "immersiveengineering", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_lead_ore.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_lead_ore.json deleted file mode 100644 index 8946e64fb8..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_lead_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_lead_ore" - } - ], - "results": [ - { - "item": "immersiveengineering:nugget_lead", - "count": 9 - } - ], - "conditions": [ - { - "modid": "immersiveengineering", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_nickel_ore.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_nickel_ore.json deleted file mode 100644 index 3669b385ec..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_nickel_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_nickel_ore" - } - ], - "results": [ - { - "item": "immersiveengineering:nugget_nickel", - "count": 9 - } - ], - "conditions": [ - { - "modid": "immersiveengineering", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_aluminum.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_aluminum.json new file mode 100644 index 0000000000..4cd261ed9f --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_aluminum.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_aluminum" + } + ], + "results": [ + { + "item": "immersiveengineering:nugget_aluminum", + "count": 9 + } + ], + "conditions": [ + { + "modid": "immersiveengineering", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_lead.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_lead.json new file mode 100644 index 0000000000..3ec9281da7 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_lead.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_lead" + } + ], + "results": [ + { + "item": "immersiveengineering:nugget_lead", + "count": 9 + } + ], + "conditions": [ + { + "modid": "immersiveengineering", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_nickel.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_nickel.json new file mode 100644 index 0000000000..cb5ac6be1c --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_nickel.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_nickel" + } + ], + "results": [ + { + "item": "immersiveengineering:nugget_nickel", + "count": 9 + } + ], + "conditions": [ + { + "modid": "immersiveengineering", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_silver.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_silver.json new file mode 100644 index 0000000000..8d606af5a6 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_silver.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_silver" + } + ], + "results": [ + { + "item": "immersiveengineering:nugget_silver", + "count": 9 + } + ], + "conditions": [ + { + "modid": "immersiveengineering", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_uranium.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_uranium.json new file mode 100644 index 0000000000..29507d2247 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_raw_uranium.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_uranium" + } + ], + "results": [ + { + "item": "immersiveengineering:nugget_uranium", + "count": 9 + } + ], + "conditions": [ + { + "modid": "immersiveengineering", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_silver_ore.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_silver_ore.json deleted file mode 100644 index 552752f4ae..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_silver_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_silver_ore" - } - ], - "results": [ - { - "item": "immersiveengineering:nugget_silver", - "count": 9 - } - ], - "conditions": [ - { - "modid": "immersiveengineering", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_uranium_ore.json b/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_uranium_ore.json deleted file mode 100644 index 718f8c87c8..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/immersiveengineering/crushed_uranium_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_uranium_ore" - } - ], - "results": [ - { - "item": "immersiveengineering:nugget_uranium", - "count": 9 - } - ], - "conditions": [ - { - "modid": "immersiveengineering", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_lead_ore.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_lead_ore.json deleted file mode 100644 index 19d0207ca9..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_lead_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_lead_ore" - } - ], - "results": [ - { - "item": "mekanism:nugget_lead", - "count": 9 - } - ], - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_osmium_ore.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_osmium_ore.json deleted file mode 100644 index b7dbc3a1ae..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_osmium_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_osmium_ore" - } - ], - "results": [ - { - "item": "mekanism:nugget_osmium", - "count": 9 - } - ], - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_lead.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_lead.json new file mode 100644 index 0000000000..86ecffc23c --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_lead.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_lead" + } + ], + "results": [ + { + "item": "mekanism:nugget_lead", + "count": 9 + } + ], + "conditions": [ + { + "modid": "mekanism", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_osmium.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_osmium.json new file mode 100644 index 0000000000..a29e618cd8 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_osmium.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_osmium" + } + ], + "results": [ + { + "item": "mekanism:nugget_osmium", + "count": 9 + } + ], + "conditions": [ + { + "modid": "mekanism", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_tin.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_tin.json new file mode 100644 index 0000000000..46e08e02a8 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_tin.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_tin" + } + ], + "results": [ + { + "item": "mekanism:nugget_tin", + "count": 9 + } + ], + "conditions": [ + { + "modid": "mekanism", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_uranium.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_uranium.json new file mode 100644 index 0000000000..9284bb3557 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_raw_uranium.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_uranium" + } + ], + "results": [ + { + "item": "mekanism:nugget_uranium", + "count": 9 + } + ], + "conditions": [ + { + "modid": "mekanism", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_tin_ore.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_tin_ore.json deleted file mode 100644 index 03bf5f3dd7..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_tin_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_tin_ore" - } - ], - "results": [ - { - "item": "mekanism:nugget_tin", - "count": 9 - } - ], - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_uranium_ore.json b/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_uranium_ore.json deleted file mode 100644 index 2cd3f02635..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/mekanism/crushed_uranium_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_uranium_ore" - } - ], - "results": [ - { - "item": "mekanism:nugget_uranium", - "count": 9 - } - ], - "conditions": [ - { - "modid": "mekanism", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_lead_ore.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_lead_ore.json deleted file mode 100644 index 82449468f3..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_lead_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_lead_ore" - } - ], - "results": [ - { - "item": "thermal:lead_nugget", - "count": 9 - } - ], - "conditions": [ - { - "modid": "thermal", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_nickel_ore.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_nickel_ore.json deleted file mode 100644 index 5e3a5556a1..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_nickel_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_nickel_ore" - } - ], - "results": [ - { - "item": "thermal:nickel_nugget", - "count": 9 - } - ], - "conditions": [ - { - "modid": "thermal", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_lead.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_lead.json new file mode 100644 index 0000000000..793224ebed --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_lead.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_lead" + } + ], + "results": [ + { + "item": "thermal:lead_nugget", + "count": 9 + } + ], + "conditions": [ + { + "modid": "thermal", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_nickel.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_nickel.json new file mode 100644 index 0000000000..a26b3f8bd5 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_nickel.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_nickel" + } + ], + "results": [ + { + "item": "thermal:nickel_nugget", + "count": 9 + } + ], + "conditions": [ + { + "modid": "thermal", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_silver.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_silver.json new file mode 100644 index 0000000000..7ab429b57d --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_silver.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_silver" + } + ], + "results": [ + { + "item": "thermal:silver_nugget", + "count": 9 + } + ], + "conditions": [ + { + "modid": "thermal", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_tin.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_tin.json new file mode 100644 index 0000000000..80681100b1 --- /dev/null +++ b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_raw_tin.json @@ -0,0 +1,20 @@ +{ + "type": "create:splashing", + "ingredients": [ + { + "item": "create:crushed_raw_tin" + } + ], + "results": [ + { + "item": "thermal:tin_nugget", + "count": 9 + } + ], + "conditions": [ + { + "modid": "thermal", + "type": "forge:mod_loaded" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_silver_ore.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_silver_ore.json deleted file mode 100644 index 65d82dc50b..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_silver_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_silver_ore" - } - ], - "results": [ - { - "item": "thermal:silver_nugget", - "count": 9 - } - ], - "conditions": [ - { - "modid": "thermal", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_tin_ore.json b/src/generated/resources/data/create/recipes/splashing/thermal/crushed_tin_ore.json deleted file mode 100644 index 39e63efe74..0000000000 --- a/src/generated/resources/data/create/recipes/splashing/thermal/crushed_tin_ore.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "create:splashing", - "ingredients": [ - { - "item": "create:crushed_tin_ore" - } - ], - "results": [ - { - "item": "thermal:tin_nugget", - "count": 9 - } - ], - "conditions": [ - { - "modid": "thermal", - "type": "forge:mod_loaded" - } - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/tuff_from_stone_types_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/tuff_from_stone_types_tuff_stonecutting.json new file mode 100644 index 0000000000..1832bb7b3f --- /dev/null +++ b/src/generated/resources/data/create/recipes/tuff_from_stone_types_tuff_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/tuff" + }, + "result": "minecraft:tuff", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/tuff_pillar_from_tuff_stonecutting.json b/src/generated/resources/data/create/recipes/tuff_pillar_from_tuff_stonecutting.json deleted file mode 100644 index bd292d2c43..0000000000 --- a/src/generated/resources/data/create/recipes/tuff_pillar_from_tuff_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "minecraft:tuff" - }, - "result": "create:tuff_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/veridium_from_stone_types_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/veridium_from_stone_types_veridium_stonecutting.json new file mode 100644 index 0000000000..7c2be58631 --- /dev/null +++ b/src/generated/resources/data/create/recipes/veridium_from_stone_types_veridium_stonecutting.json @@ -0,0 +1,8 @@ +{ + "type": "minecraft:stonecutting", + "ingredient": { + "tag": "create:stone_types/veridium" + }, + "result": "create:veridium", + "count": 1 +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/veridium_pillar_from_veridium_stonecutting.json b/src/generated/resources/data/create/recipes/veridium_pillar_from_veridium_stonecutting.json deleted file mode 100644 index 02c85870b1..0000000000 --- a/src/generated/resources/data/create/recipes/veridium_pillar_from_veridium_stonecutting.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minecraft:stonecutting", - "ingredient": { - "item": "create:veridium" - }, - "result": "create:veridium_pillar", - "count": 1 -} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/brittle.json b/src/generated/resources/data/create/tags/blocks/brittle.json index f5693187e0..f3f1628a37 100644 --- a/src/generated/resources/data/create/tags/blocks/brittle.json +++ b/src/generated/resources/data/create/tags/blocks/brittle.json @@ -25,10 +25,10 @@ "create:redstone_link", "create:peculiar_bell", "create:haunted_bell", - "#minecraft:doors", - "#minecraft:beds", - "minecraft:flower_pot", "minecraft:bell", - "minecraft:cocoa" + "minecraft:cocoa", + "minecraft:flower_pot", + "#minecraft:beds", + "#minecraft:doors" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/windowable.json b/src/generated/resources/data/create/tags/blocks/contraption_inventory_deny.json similarity index 100% rename from src/generated/resources/data/create/tags/blocks/windowable.json rename to src/generated/resources/data/create/tags/blocks/contraption_inventory_deny.json diff --git a/src/generated/resources/data/create/tags/blocks/copycat_allow.json b/src/generated/resources/data/create/tags/blocks/copycat_allow.json new file mode 100644 index 0000000000..01825818a4 --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/copycat_allow.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:barrel" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/copycat_deny.json b/src/generated/resources/data/create/tags/blocks/copycat_deny.json new file mode 100644 index 0000000000..14671651fa --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/copycat_deny.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "#minecraft:cauldrons", + "#minecraft:saplings", + "#minecraft:climbable" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/fan_transparent.json b/src/generated/resources/data/create/tags/blocks/fan_transparent.json index 4847b23a8b..f7df78dbca 100644 --- a/src/generated/resources/data/create/tags/blocks/fan_transparent.json +++ b/src/generated/resources/data/create/tags/blocks/fan_transparent.json @@ -4,8 +4,13 @@ "create:blaze_burner", "create:lit_blaze_burner", "create:sail_frame", - "#minecraft:fences", + "create:andesite_bars", + "create:brass_bars", + "create:copper_bars", + "create:copycat_base", + "minecraft:iron_bars", "#minecraft:campfires", - "minecraft:iron_bars" + "#minecraft:fences", + "#minecraft:leaves" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/girdable_tracks.json b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json new file mode 100644 index 0000000000..ef33e72efb --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/girdable_tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/movable_empty_collider.json b/src/generated/resources/data/create/tags/blocks/movable_empty_collider.json new file mode 100644 index 0000000000..527ad16b92 --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/movable_empty_collider.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "minecraft:cobweb", + "minecraft:powder_snow", + "minecraft:tripwire", + "minecraft:tripwire_hook", + "#minecraft:fence_gates" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/passive_boiler_heaters.json b/src/generated/resources/data/create/tags/blocks/passive_boiler_heaters.json index dc4ef4afb1..1b882ab573 100644 --- a/src/generated/resources/data/create/tags/blocks/passive_boiler_heaters.json +++ b/src/generated/resources/data/create/tags/blocks/passive_boiler_heaters.json @@ -3,9 +3,9 @@ "values": [ "create:blaze_burner", "create:lit_blaze_burner", - "#minecraft:fire", - "#minecraft:campfires", "minecraft:magma_block", - "minecraft:lava" + "minecraft:lava", + "#minecraft:campfires", + "#minecraft:fire" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/safe_nbt.json b/src/generated/resources/data/create/tags/blocks/safe_nbt.json index 3d607530af..d984ed5650 100644 --- a/src/generated/resources/data/create/tags/blocks/safe_nbt.json +++ b/src/generated/resources/data/create/tags/blocks/safe_nbt.json @@ -19,13 +19,12 @@ "create:andesite_belt_funnel", "create:brass_funnel", "create:brass_belt_funnel", - "create:creative_crate", "create:redstone_link", "create:analog_lever", - "create:placard", "create:pulse_repeater", "create:pulse_extender", - "#minecraft:signs", - "#minecraft:banners" + "create:clipboard", + "#minecraft:banners", + "#minecraft:signs" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/tracks.json b/src/generated/resources/data/create/tags/blocks/tracks.json new file mode 100644 index 0000000000..ef33e72efb --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/tracks.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:track" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/tree_attachments.json b/src/generated/resources/data/create/tags/blocks/tree_attachments.json index dc79f54a01..43a637df4c 100644 --- a/src/generated/resources/data/create/tags/blocks/tree_attachments.json +++ b/src/generated/resources/data/create/tags/blocks/tree_attachments.json @@ -2,9 +2,9 @@ "replace": false, "values": [ "minecraft:bee_nest", - "minecraft:vine", + "minecraft:cocoa", "minecraft:moss_carpet", "minecraft:shroomlight", - "minecraft:cocoa" + "minecraft:vine" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/wrench_pickup.json b/src/generated/resources/data/create/tags/blocks/wrench_pickup.json index 1e8c3abd1f..8c362d71dd 100644 --- a/src/generated/resources/data/create/tags/blocks/wrench_pickup.json +++ b/src/generated/resources/data/create/tags/blocks/wrench_pickup.json @@ -1,9 +1,10 @@ { "replace": false, "values": [ - "#minecraft:rails", - "#minecraft:buttons", - "#minecraft:pressure_plates", + "create:andesite_bars", + "create:brass_bars", + "create:copper_bars", + "create:industrial_iron_block", "minecraft:redstone_wire", "minecraft:redstone_torch", "minecraft:repeater", @@ -17,6 +18,9 @@ "minecraft:tripwire_hook", "minecraft:daylight_detector", "minecraft:target", - "minecraft:hopper" + "minecraft:hopper", + "#minecraft:buttons", + "#minecraft:pressure_plates", + "#minecraft:rails" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/entity_types/ignore_seat.json b/src/generated/resources/data/create/tags/entity_types/ignore_seat.json new file mode 100644 index 0000000000..5e8aecc986 --- /dev/null +++ b/src/generated/resources/data/create/tags/entity_types/ignore_seat.json @@ -0,0 +1,4 @@ +{ + "replace": false, + "values": [] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/contraption_controlled.json b/src/generated/resources/data/create/tags/items/contraption_controlled.json new file mode 100644 index 0000000000..eedd21c2b6 --- /dev/null +++ b/src/generated/resources/data/create/tags/items/contraption_controlled.json @@ -0,0 +1,28 @@ +{ + "replace": false, + "values": [ + "create:portable_fluid_interface", + "create:mechanical_drill", + "create:mechanical_saw", + "create:deployer", + "create:portable_storage_interface", + "create:redstone_contact", + "create:mechanical_harvester", + "create:mechanical_plough", + "create:mechanical_roller", + "create:andesite_funnel", + "create:brass_funnel", + "create:peculiar_bell", + "create:haunted_bell", + "create:andesite_door", + "create:brass_door", + "create:copper_door", + "create:train_door", + "create:framed_glass_door", + "minecraft:bell", + "minecraft:campfire", + "minecraft:soul_campfire", + "minecraft:dispenser", + "minecraft:dropper" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/crushed_ores.json b/src/generated/resources/data/create/tags/items/crushed_ores.json deleted file mode 100644 index 725e331739..0000000000 --- a/src/generated/resources/data/create/tags/items/crushed_ores.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "replace": false, - "values": [ - "create:crushed_iron_ore", - "create:crushed_gold_ore", - "create:crushed_copper_ore", - "create:crushed_zinc_ore", - "create:crushed_osmium_ore", - "create:crushed_platinum_ore", - "create:crushed_silver_ore", - "create:crushed_tin_ore", - "create:crushed_lead_ore", - "create:crushed_quicksilver_ore", - "create:crushed_aluminum_ore", - "create:crushed_uranium_ore", - "create:crushed_nickel_ore" - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/crushed_raw_materials.json b/src/generated/resources/data/create/tags/items/crushed_raw_materials.json new file mode 100644 index 0000000000..c29ba64272 --- /dev/null +++ b/src/generated/resources/data/create/tags/items/crushed_raw_materials.json @@ -0,0 +1,18 @@ +{ + "replace": false, + "values": [ + "create:crushed_raw_iron", + "create:crushed_raw_gold", + "create:crushed_raw_copper", + "create:crushed_raw_zinc", + "create:crushed_raw_osmium", + "create:crushed_raw_platinum", + "create:crushed_raw_silver", + "create:crushed_raw_tin", + "create:crushed_raw_lead", + "create:crushed_raw_quicksilver", + "create:crushed_raw_aluminum", + "create:crushed_raw_uranium", + "create:crushed_raw_nickel" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/deployable_drink.json b/src/generated/resources/data/create/tags/items/deployable_drink.json new file mode 100644 index 0000000000..d5b914f850 --- /dev/null +++ b/src/generated/resources/data/create/tags/items/deployable_drink.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:milk_bucket", + "minecraft:potion" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/pressurized_air_sources.json b/src/generated/resources/data/create/tags/items/pressurized_air_sources.json index 9c5cb97a4e..3b3bbadd02 100644 --- a/src/generated/resources/data/create/tags/items/pressurized_air_sources.json +++ b/src/generated/resources/data/create/tags/items/pressurized_air_sources.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "create:copper_backtank" + "create:copper_backtank", + "create:netherite_backtank" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/andesite.json b/src/generated/resources/data/create/tags/items/stone_types/andesite.json index 7e21bf19dc..0d12df3057 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/andesite.json +++ b/src/generated/resources/data/create/tags/items/stone_types/andesite.json @@ -14,6 +14,7 @@ "create:small_andesite_brick_stairs", "create:small_andesite_brick_wall", "create:layered_andesite", - "create:andesite_pillar" + "create:andesite_pillar", + "minecraft:andesite" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/asurine.json b/src/generated/resources/data/create/tags/items/stone_types/asurine.json index c881c4597f..6cbde5fc68 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/asurine.json +++ b/src/generated/resources/data/create/tags/items/stone_types/asurine.json @@ -14,6 +14,7 @@ "create:small_asurine_brick_stairs", "create:small_asurine_brick_wall", "create:layered_asurine", - "create:asurine_pillar" + "create:asurine_pillar", + "create:asurine" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/calcite.json b/src/generated/resources/data/create/tags/items/stone_types/calcite.json index c55f39cd90..54ec9d0809 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/calcite.json +++ b/src/generated/resources/data/create/tags/items/stone_types/calcite.json @@ -14,6 +14,7 @@ "create:small_calcite_brick_stairs", "create:small_calcite_brick_wall", "create:layered_calcite", - "create:calcite_pillar" + "create:calcite_pillar", + "minecraft:calcite" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/crimsite.json b/src/generated/resources/data/create/tags/items/stone_types/crimsite.json index f4678b9ea9..0961f02279 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/crimsite.json +++ b/src/generated/resources/data/create/tags/items/stone_types/crimsite.json @@ -14,6 +14,7 @@ "create:small_crimsite_brick_stairs", "create:small_crimsite_brick_wall", "create:layered_crimsite", - "create:crimsite_pillar" + "create:crimsite_pillar", + "create:crimsite" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/deepslate.json b/src/generated/resources/data/create/tags/items/stone_types/deepslate.json index 5890622bb7..a78d709939 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/deepslate.json +++ b/src/generated/resources/data/create/tags/items/stone_types/deepslate.json @@ -14,6 +14,7 @@ "create:small_deepslate_brick_stairs", "create:small_deepslate_brick_wall", "create:layered_deepslate", - "create:deepslate_pillar" + "create:deepslate_pillar", + "minecraft:deepslate" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/diorite.json b/src/generated/resources/data/create/tags/items/stone_types/diorite.json index 349145d2c1..8220bfa22c 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/diorite.json +++ b/src/generated/resources/data/create/tags/items/stone_types/diorite.json @@ -14,6 +14,7 @@ "create:small_diorite_brick_stairs", "create:small_diorite_brick_wall", "create:layered_diorite", - "create:diorite_pillar" + "create:diorite_pillar", + "minecraft:diorite" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/dripstone.json b/src/generated/resources/data/create/tags/items/stone_types/dripstone.json index 489b883041..214593d87f 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/dripstone.json +++ b/src/generated/resources/data/create/tags/items/stone_types/dripstone.json @@ -14,6 +14,7 @@ "create:small_dripstone_brick_stairs", "create:small_dripstone_brick_wall", "create:layered_dripstone", - "create:dripstone_pillar" + "create:dripstone_pillar", + "minecraft:dripstone_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/granite.json b/src/generated/resources/data/create/tags/items/stone_types/granite.json index d1184a45d9..8f59cbc125 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/granite.json +++ b/src/generated/resources/data/create/tags/items/stone_types/granite.json @@ -14,6 +14,7 @@ "create:small_granite_brick_stairs", "create:small_granite_brick_wall", "create:layered_granite", - "create:granite_pillar" + "create:granite_pillar", + "minecraft:granite" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/limestone.json b/src/generated/resources/data/create/tags/items/stone_types/limestone.json index b4cca990b9..04ad44ab6f 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/limestone.json +++ b/src/generated/resources/data/create/tags/items/stone_types/limestone.json @@ -14,6 +14,7 @@ "create:small_limestone_brick_stairs", "create:small_limestone_brick_wall", "create:layered_limestone", - "create:limestone_pillar" + "create:limestone_pillar", + "create:limestone" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/ochrum.json b/src/generated/resources/data/create/tags/items/stone_types/ochrum.json index 2710a05f0d..7aaa59e81b 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/ochrum.json +++ b/src/generated/resources/data/create/tags/items/stone_types/ochrum.json @@ -14,6 +14,7 @@ "create:small_ochrum_brick_stairs", "create:small_ochrum_brick_wall", "create:layered_ochrum", - "create:ochrum_pillar" + "create:ochrum_pillar", + "create:ochrum" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/scorchia.json b/src/generated/resources/data/create/tags/items/stone_types/scorchia.json index e28030878a..874eb4c405 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/scorchia.json +++ b/src/generated/resources/data/create/tags/items/stone_types/scorchia.json @@ -14,6 +14,7 @@ "create:small_scorchia_brick_stairs", "create:small_scorchia_brick_wall", "create:layered_scorchia", - "create:scorchia_pillar" + "create:scorchia_pillar", + "create:scorchia" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/scoria.json b/src/generated/resources/data/create/tags/items/stone_types/scoria.json index e286ca52a2..15f0abf3b5 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/scoria.json +++ b/src/generated/resources/data/create/tags/items/stone_types/scoria.json @@ -14,6 +14,7 @@ "create:small_scoria_brick_stairs", "create:small_scoria_brick_wall", "create:layered_scoria", - "create:scoria_pillar" + "create:scoria_pillar", + "create:scoria" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/tuff.json b/src/generated/resources/data/create/tags/items/stone_types/tuff.json index 53091a1d73..50a4d3d353 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/tuff.json +++ b/src/generated/resources/data/create/tags/items/stone_types/tuff.json @@ -14,6 +14,7 @@ "create:small_tuff_brick_stairs", "create:small_tuff_brick_wall", "create:layered_tuff", - "create:tuff_pillar" + "create:tuff_pillar", + "minecraft:tuff" ] } \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/items/stone_types/veridium.json b/src/generated/resources/data/create/tags/items/stone_types/veridium.json index 34a18c3c3f..5536e10731 100644 --- a/src/generated/resources/data/create/tags/items/stone_types/veridium.json +++ b/src/generated/resources/data/create/tags/items/stone_types/veridium.json @@ -14,6 +14,7 @@ "create:small_veridium_brick_stairs", "create:small_veridium_brick_wall", "create:layered_veridium", - "create:veridium_pillar" + "create:veridium_pillar", + "create:veridium" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/storage_blocks.json b/src/generated/resources/data/forge/tags/blocks/storage_blocks.json index 914bc595f2..0d53a97dbb 100644 --- a/src/generated/resources/data/forge/tags/blocks/storage_blocks.json +++ b/src/generated/resources/data/forge/tags/blocks/storage_blocks.json @@ -3,6 +3,8 @@ "values": [ "create:raw_zinc_block", "create:zinc_block", - "create:brass_block" + "create:andesite_alloy_block", + "create:brass_block", + "create:experience_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/storage_blocks/andesite_alloy.json b/src/generated/resources/data/forge/tags/blocks/storage_blocks/andesite_alloy.json new file mode 100644 index 0000000000..49bf45975b --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/storage_blocks/andesite_alloy.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:andesite_alloy_block" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/boots.json b/src/generated/resources/data/forge/tags/items/armors/boots.json new file mode 100644 index 0000000000..7da61d8caa --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/boots.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "create:copper_diving_boots", + "create:netherite_diving_boots" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/chestplates.json b/src/generated/resources/data/forge/tags/items/armors/chestplates.json new file mode 100644 index 0000000000..3b3bbadd02 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/chestplates.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "create:copper_backtank", + "create:netherite_backtank" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/armors/helmets.json b/src/generated/resources/data/forge/tags/items/armors/helmets.json new file mode 100644 index 0000000000..42f6e845e9 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/armors/helmets.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "create:copper_diving_helmet", + "create:netherite_diving_helmet" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/storage_blocks.json b/src/generated/resources/data/forge/tags/items/storage_blocks.json index 914bc595f2..0d53a97dbb 100644 --- a/src/generated/resources/data/forge/tags/items/storage_blocks.json +++ b/src/generated/resources/data/forge/tags/items/storage_blocks.json @@ -3,6 +3,8 @@ "values": [ "create:raw_zinc_block", "create:zinc_block", - "create:brass_block" + "create:andesite_alloy_block", + "create:brass_block", + "create:experience_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/storage_blocks/andesite_alloy.json b/src/generated/resources/data/forge/tags/items/storage_blocks/andesite_alloy.json new file mode 100644 index 0000000000..49bf45975b --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/storage_blocks/andesite_alloy.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:andesite_alloy_block" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/beacon_base_blocks.json b/src/generated/resources/data/minecraft/tags/blocks/beacon_base_blocks.json index a1b3ce3d37..a568cc64fa 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/beacon_base_blocks.json +++ b/src/generated/resources/data/minecraft/tags/blocks/beacon_base_blocks.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "create:zinc_block", - "create:brass_block" + "create:brass_block", + "create:experience_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/climbable.json b/src/generated/resources/data/minecraft/tags/blocks/climbable.json index 4098917428..6f33e5ab5e 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/climbable.json +++ b/src/generated/resources/data/minecraft/tags/blocks/climbable.json @@ -1,8 +1,13 @@ { "replace": false, "values": [ + "create:rope", + "create:pulley_magnet", "create:andesite_ladder", "create:brass_ladder", - "create:copper_ladder" + "create:copper_ladder", + "create:andesite_scaffolding", + "create:brass_scaffolding", + "create:copper_scaffolding" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/doors.json b/src/generated/resources/data/minecraft/tags/blocks/doors.json index 56284a409f..84decc3a15 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/doors.json +++ b/src/generated/resources/data/minecraft/tags/blocks/doors.json @@ -1,6 +1,9 @@ { "replace": false, "values": [ + "create:andesite_door", + "create:brass_door", + "create:copper_door", "create:train_door", "create:framed_glass_door" ] diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json index 3dfa8509f3..a6e05f4379 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -17,6 +17,8 @@ "create:adjustable_chain_gearshift", "create:belt", "create:water_wheel", + "create:large_water_wheel", + "create:water_wheel_structure", "create:encased_fan", "create:nozzle", "create:turntable", @@ -42,33 +44,21 @@ "create:mechanical_bearing", "create:clockwork_bearing", "create:rope_pulley", + "create:elevator_pulley", "create:cart_assembler", "create:linear_chassis", "create:secondary_linear_chassis", "create:radial_chassis", + "create:contraption_controls", "create:mechanical_drill", "create:mechanical_saw", "create:deployer", "create:portable_storage_interface", "create:redstone_contact", + "create:elevator_contact", "create:mechanical_harvester", "create:mechanical_plough", - "create:white_seat", - "create:orange_seat", - "create:magenta_seat", - "create:light_blue_seat", - "create:yellow_seat", - "create:lime_seat", - "create:pink_seat", - "create:gray_seat", - "create:light_gray_seat", - "create:cyan_seat", - "create:purple_seat", - "create:blue_seat", - "create:brown_seat", - "create:green_seat", - "create:red_seat", - "create:black_seat", + "create:mechanical_roller", "create:sail_frame", "create:white_sail", "create:orange_sail", @@ -103,6 +93,25 @@ "create:display_link", "create:redstone_link", "create:analog_lever", - "create:lectern_controller" + "create:lectern_controller", + "create:clipboard", + "create:copycat_step", + "create:copycat_panel", + "create:white_seat", + "create:orange_seat", + "create:magenta_seat", + "create:light_blue_seat", + "create:yellow_seat", + "create:lime_seat", + "create:pink_seat", + "create:gray_seat", + "create:light_gray_seat", + "create:cyan_seat", + "create:purple_seat", + "create:blue_seat", + "create:brown_seat", + "create:green_seat", + "create:red_seat", + "create:black_seat" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 3394d19b5b..a392d86b77 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -20,6 +20,8 @@ "create:belt", "create:creative_motor", "create:water_wheel", + "create:large_water_wheel", + "create:water_wheel_structure", "create:encased_fan", "create:nozzle", "create:turntable", @@ -41,11 +43,6 @@ "create:stressometer", "create:wooden_bracket", "create:metal_bracket", - "create:metal_girder", - "create:metal_girder_encased_shaft", - "create:andesite_ladder", - "create:brass_ladder", - "create:copper_ladder", "create:fluid_pipe", "create:encased_fluid_pipe", "create:glass_fluid_pipe", @@ -89,19 +86,23 @@ "create:mechanical_bearing", "create:clockwork_bearing", "create:rope_pulley", + "create:elevator_pulley", "create:cart_assembler", "create:controller_rail", "create:linear_chassis", "create:secondary_linear_chassis", "create:radial_chassis", "create:sticker", + "create:contraption_controls", "create:mechanical_drill", "create:mechanical_saw", "create:deployer", "create:portable_storage_interface", "create:redstone_contact", + "create:elevator_contact", "create:mechanical_harvester", "create:mechanical_plough", + "create:mechanical_roller", "create:andesite_casing", "create:brass_casing", "create:copper_casing", @@ -120,10 +121,6 @@ "create:small_bogey", "create:large_bogey", "create:controls", - "create:train_door", - "create:train_trapdoor", - "create:framed_glass_door", - "create:framed_glass_trapdoor", "create:item_vault", "create:andesite_funnel", "create:andesite_belt_funnel", @@ -157,13 +154,39 @@ "create:analog_lever", "create:placard", "create:copper_backtank", + "create:netherite_backtank", "create:peculiar_bell", "create:haunted_bell", + "create:clipboard", + "create:andesite_ladder", + "create:brass_ladder", + "create:copper_ladder", + "create:andesite_bars", + "create:brass_bars", + "create:copper_bars", + "create:andesite_scaffolding", + "create:brass_scaffolding", + "create:copper_scaffolding", + "create:metal_girder", + "create:metal_girder_encased_shaft", + "create:copycat_base", + "create:copycat_step", + "create:copycat_panel", + "create:andesite_door", + "create:brass_door", + "create:copper_door", + "create:train_door", + "create:train_trapdoor", + "create:framed_glass_door", + "create:framed_glass_trapdoor", "create:zinc_ore", "create:deepslate_zinc_ore", "create:raw_zinc_block", "create:zinc_block", + "create:andesite_alloy_block", + "create:industrial_iron_block", "create:brass_block", + "create:experience_block", "create:rose_quartz_block", "create:rose_quartz_tiles", "create:small_rose_quartz_tiles", diff --git a/src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json b/src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json index 56284a409f..84decc3a15 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json +++ b/src/generated/resources/data/minecraft/tags/blocks/wooden_doors.json @@ -1,6 +1,9 @@ { "replace": false, "values": [ + "create:andesite_door", + "create:brass_door", + "create:copper_door", "create:train_door", "create:framed_glass_door" ] diff --git a/src/generated/resources/data/forge/tags/items/beacon_payment.json b/src/generated/resources/data/minecraft/tags/items/beacon_payment_items.json similarity index 100% rename from src/generated/resources/data/forge/tags/items/beacon_payment.json rename to src/generated/resources/data/minecraft/tags/items/beacon_payment_items.json diff --git a/src/generated/resources/data/minecraft/tags/items/doors.json b/src/generated/resources/data/minecraft/tags/items/doors.json index 56284a409f..84decc3a15 100644 --- a/src/generated/resources/data/minecraft/tags/items/doors.json +++ b/src/generated/resources/data/minecraft/tags/items/doors.json @@ -1,6 +1,9 @@ { "replace": false, "values": [ + "create:andesite_door", + "create:brass_door", + "create:copper_door", "create:train_door", "create:framed_glass_door" ] diff --git a/src/generated/resources/data/minecraft/tags/items/piglin_loved.json b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json index 478bada693..2f5dc5097a 100644 --- a/src/generated/resources/data/minecraft/tags/items/piglin_loved.json +++ b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json @@ -2,6 +2,6 @@ "replace": false, "values": [ "create:golden_sheet", - "create:crushed_gold_ore" + "create:crushed_raw_gold" ] } \ No newline at end of file diff --git a/src/generated/resources/data/quark/tags/blocks/non_double_door.json b/src/generated/resources/data/quark/tags/blocks/non_double_door.json index 56284a409f..84decc3a15 100644 --- a/src/generated/resources/data/quark/tags/blocks/non_double_door.json +++ b/src/generated/resources/data/quark/tags/blocks/non_double_door.json @@ -1,6 +1,9 @@ { "replace": false, "values": [ + "create:andesite_door", + "create:brass_door", + "create:copper_door", "create:train_door", "create:framed_glass_door" ] diff --git a/src/main/java/com/simibubi/create/AllBlockEntityTypes.java b/src/main/java/com/simibubi/create/AllBlockEntityTypes.java new file mode 100644 index 0000000000..8ff7849e6d --- /dev/null +++ b/src/main/java/com/simibubi/create/AllBlockEntityTypes.java @@ -0,0 +1,893 @@ +package com.simibubi.create; + +import static com.simibubi.create.Create.REGISTRATE; +import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviourBE; + +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlockEntity; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsRenderer; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterBlockEntity; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterRenderer; +import com.simibubi.create.content.contraptions.actors.psi.PSIInstance; +import com.simibubi.create.content.contraptions.actors.psi.PortableFluidInterfaceBlockEntity; +import com.simibubi.create.content.contraptions.actors.psi.PortableItemInterfaceBlockEntity; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceRenderer; +import com.simibubi.create.content.contraptions.actors.roller.RollerBlockEntity; +import com.simibubi.create.content.contraptions.actors.roller.RollerRenderer; +import com.simibubi.create.content.contraptions.bearing.BearingInstance; +import com.simibubi.create.content.contraptions.bearing.BearingRenderer; +import com.simibubi.create.content.contraptions.bearing.ClockworkBearingBlockEntity; +import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlockEntity; +import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlockEntity; +import com.simibubi.create.content.contraptions.chassis.ChassisBlockEntity; +import com.simibubi.create.content.contraptions.chassis.StickerBlockEntity; +import com.simibubi.create.content.contraptions.chassis.StickerInstance; +import com.simibubi.create.content.contraptions.chassis.StickerRenderer; +import com.simibubi.create.content.contraptions.elevator.ElevatorContactBlockEntity; +import com.simibubi.create.content.contraptions.elevator.ElevatorPulleyBlockEntity; +import com.simibubi.create.content.contraptions.elevator.ElevatorPulleyRenderer; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageBlockEntity; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageInstance; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageRenderer; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlockEntity; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonRenderer; +import com.simibubi.create.content.contraptions.pulley.HosePulleyInstance; +import com.simibubi.create.content.contraptions.pulley.PulleyBlockEntity; +import com.simibubi.create.content.contraptions.pulley.PulleyRenderer; +import com.simibubi.create.content.contraptions.pulley.RopePulleyInstance; +import com.simibubi.create.content.decoration.copycat.CopycatBlockEntity; +import com.simibubi.create.content.decoration.placard.PlacardBlockEntity; +import com.simibubi.create.content.decoration.placard.PlacardRenderer; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlockEntity; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorRenderer; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlockEntity; +import com.simibubi.create.content.decoration.steamWhistle.WhistleRenderer; +import com.simibubi.create.content.equipment.armor.BacktankBlockEntity; +import com.simibubi.create.content.equipment.armor.BacktankInstance; +import com.simibubi.create.content.equipment.armor.BacktankRenderer; +import com.simibubi.create.content.equipment.bell.BellRenderer; +import com.simibubi.create.content.equipment.bell.HauntedBellBlockEntity; +import com.simibubi.create.content.equipment.bell.PeculiarBellBlockEntity; +import com.simibubi.create.content.equipment.clipboard.ClipboardBlockEntity; +import com.simibubi.create.content.equipment.toolbox.ToolBoxInstance; +import com.simibubi.create.content.equipment.toolbox.ToolboxBlockEntity; +import com.simibubi.create.content.equipment.toolbox.ToolboxRenderer; +import com.simibubi.create.content.fluids.drain.ItemDrainBlockEntity; +import com.simibubi.create.content.fluids.drain.ItemDrainRenderer; +import com.simibubi.create.content.fluids.hosePulley.HosePulleyBlockEntity; +import com.simibubi.create.content.fluids.hosePulley.HosePulleyRenderer; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlockEntity; +import com.simibubi.create.content.fluids.pipes.SmartFluidPipeBlockEntity; +import com.simibubi.create.content.fluids.pipes.StraightPipeBlockEntity; +import com.simibubi.create.content.fluids.pipes.TransparentStraightPipeRenderer; +import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlockEntity; +import com.simibubi.create.content.fluids.pipes.valve.FluidValveInstance; +import com.simibubi.create.content.fluids.pipes.valve.FluidValveRenderer; +import com.simibubi.create.content.fluids.pump.PumpBlockEntity; +import com.simibubi.create.content.fluids.pump.PumpCogInstance; +import com.simibubi.create.content.fluids.pump.PumpRenderer; +import com.simibubi.create.content.fluids.spout.SpoutBlockEntity; +import com.simibubi.create.content.fluids.spout.SpoutRenderer; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.fluids.tank.FluidTankRenderer; +import com.simibubi.create.content.kinetics.base.CutoutRotatingInstance; +import com.simibubi.create.content.kinetics.base.HalfShaftInstance; +import com.simibubi.create.content.kinetics.base.HorizontalHalfShaftInstance; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.ShaftInstance; +import com.simibubi.create.content.kinetics.base.ShaftRenderer; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltInstance; +import com.simibubi.create.content.kinetics.belt.BeltRenderer; +import com.simibubi.create.content.kinetics.chainDrive.ChainGearshiftBlockEntity; +import com.simibubi.create.content.kinetics.clock.CuckooClockBlockEntity; +import com.simibubi.create.content.kinetics.clock.CuckooClockRenderer; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterRenderer; +import com.simibubi.create.content.kinetics.crafter.ShaftlessCogwheelInstance; +import com.simibubi.create.content.kinetics.crank.HandCrankBlockEntity; +import com.simibubi.create.content.kinetics.crank.HandCrankInstance; +import com.simibubi.create.content.kinetics.crank.HandCrankRenderer; +import com.simibubi.create.content.kinetics.crank.ValveHandleBlockEntity; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelBlockEntity; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelControllerBlockEntity; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity; +import com.simibubi.create.content.kinetics.deployer.DeployerInstance; +import com.simibubi.create.content.kinetics.deployer.DeployerRenderer; +import com.simibubi.create.content.kinetics.drill.DrillBlockEntity; +import com.simibubi.create.content.kinetics.drill.DrillInstance; +import com.simibubi.create.content.kinetics.drill.DrillRenderer; +import com.simibubi.create.content.kinetics.fan.EncasedFanBlockEntity; +import com.simibubi.create.content.kinetics.fan.EncasedFanRenderer; +import com.simibubi.create.content.kinetics.fan.FanInstance; +import com.simibubi.create.content.kinetics.fan.NozzleBlockEntity; +import com.simibubi.create.content.kinetics.flywheel.FlywheelBlockEntity; +import com.simibubi.create.content.kinetics.flywheel.FlywheelInstance; +import com.simibubi.create.content.kinetics.flywheel.FlywheelRenderer; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlockEntity; +import com.simibubi.create.content.kinetics.gauge.GaugeInstance; +import com.simibubi.create.content.kinetics.gauge.GaugeRenderer; +import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity; +import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity; +import com.simibubi.create.content.kinetics.gearbox.GearboxBlockEntity; +import com.simibubi.create.content.kinetics.gearbox.GearboxInstance; +import com.simibubi.create.content.kinetics.gearbox.GearboxRenderer; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmBlockEntity; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmInstance; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmRenderer; +import com.simibubi.create.content.kinetics.millstone.MillstoneBlockEntity; +import com.simibubi.create.content.kinetics.millstone.MillstoneCogInstance; +import com.simibubi.create.content.kinetics.millstone.MillstoneRenderer; +import com.simibubi.create.content.kinetics.mixer.MechanicalMixerBlockEntity; +import com.simibubi.create.content.kinetics.mixer.MechanicalMixerRenderer; +import com.simibubi.create.content.kinetics.mixer.MixerInstance; +import com.simibubi.create.content.kinetics.motor.CreativeMotorBlockEntity; +import com.simibubi.create.content.kinetics.motor.CreativeMotorRenderer; +import com.simibubi.create.content.kinetics.press.MechanicalPressBlockEntity; +import com.simibubi.create.content.kinetics.press.MechanicalPressRenderer; +import com.simibubi.create.content.kinetics.press.PressInstance; +import com.simibubi.create.content.kinetics.saw.SawBlockEntity; +import com.simibubi.create.content.kinetics.saw.SawInstance; +import com.simibubi.create.content.kinetics.saw.SawRenderer; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntity; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogInstance; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogRenderer; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerRenderer; +import com.simibubi.create.content.kinetics.steamEngine.PoweredShaftBlockEntity; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineBlockEntity; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineInstance; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineRenderer; +import com.simibubi.create.content.kinetics.transmission.ClutchBlockEntity; +import com.simibubi.create.content.kinetics.transmission.GearshiftBlockEntity; +import com.simibubi.create.content.kinetics.transmission.SplitShaftInstance; +import com.simibubi.create.content.kinetics.transmission.SplitShaftRenderer; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity; +import com.simibubi.create.content.kinetics.turntable.TurntableBlockEntity; +import com.simibubi.create.content.kinetics.waterwheel.LargeWaterWheelBlockEntity; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelBlockEntity; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelInstance; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelRenderer; +import com.simibubi.create.content.logistics.chute.ChuteBlockEntity; +import com.simibubi.create.content.logistics.chute.ChuteRenderer; +import com.simibubi.create.content.logistics.chute.SmartChuteBlockEntity; +import com.simibubi.create.content.logistics.chute.SmartChuteRenderer; +import com.simibubi.create.content.logistics.crate.CreativeCrateBlockEntity; +import com.simibubi.create.content.logistics.depot.DepotBlockEntity; +import com.simibubi.create.content.logistics.depot.DepotRenderer; +import com.simibubi.create.content.logistics.depot.EjectorBlockEntity; +import com.simibubi.create.content.logistics.depot.EjectorInstance; +import com.simibubi.create.content.logistics.depot.EjectorRenderer; +import com.simibubi.create.content.logistics.funnel.FunnelBlockEntity; +import com.simibubi.create.content.logistics.funnel.FunnelInstance; +import com.simibubi.create.content.logistics.funnel.FunnelRenderer; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlockEntity; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelInstance; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelRenderer; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelBlockEntity; +import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity; +import com.simibubi.create.content.processing.basin.BasinBlockEntity; +import com.simibubi.create.content.processing.basin.BasinRenderer; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlockEntity; +import com.simibubi.create.content.processing.burner.BlazeBurnerRenderer; +import com.simibubi.create.content.redstone.analogLever.AnalogLeverBlockEntity; +import com.simibubi.create.content.redstone.analogLever.AnalogLeverInstance; +import com.simibubi.create.content.redstone.analogLever.AnalogLeverRenderer; +import com.simibubi.create.content.redstone.diodes.BrassDiodeInstance; +import com.simibubi.create.content.redstone.diodes.BrassDiodeRenderer; +import com.simibubi.create.content.redstone.diodes.PulseExtenderBlockEntity; +import com.simibubi.create.content.redstone.diodes.PulseRepeaterBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkRenderer; +import com.simibubi.create.content.redstone.displayLink.source.NixieTubeDisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.NixieTubeDisplayTarget; +import com.simibubi.create.content.redstone.link.RedstoneLinkBlockEntity; +import com.simibubi.create.content.redstone.link.controller.LecternControllerBlockEntity; +import com.simibubi.create.content.redstone.link.controller.LecternControllerRenderer; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlockEntity; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeRenderer; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlockEntity; +import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity; +import com.simibubi.create.content.schematics.cannon.SchematicannonInstance; +import com.simibubi.create.content.schematics.cannon.SchematicannonRenderer; +import com.simibubi.create.content.schematics.table.SchematicTableBlockEntity; +import com.simibubi.create.content.trains.bogey.BogeyBlockEntityRenderer; +import com.simibubi.create.content.trains.bogey.StandardBogeyBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayRenderer; +import com.simibubi.create.content.trains.observer.TrackObserverBlockEntity; +import com.simibubi.create.content.trains.observer.TrackObserverRenderer; +import com.simibubi.create.content.trains.signal.SignalBlockEntity; +import com.simibubi.create.content.trains.signal.SignalRenderer; +import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.content.trains.station.StationRenderer; +import com.simibubi.create.content.trains.track.FakeTrackBlockEntity; +import com.simibubi.create.content.trains.track.TrackBlockEntity; +import com.simibubi.create.content.trains.track.TrackInstance; +import com.simibubi.create.content.trains.track.TrackMaterial; +import com.simibubi.create.content.trains.track.TrackRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.tterrag.registrate.util.entry.BlockEntityEntry; + +public class AllBlockEntityTypes { + + // Schematics + public static final BlockEntityEntry SCHEMATICANNON = REGISTRATE + .blockEntity("schematicannon", SchematicannonBlockEntity::new) + .instance(() -> SchematicannonInstance::new) + .validBlocks(AllBlocks.SCHEMATICANNON) + .renderer(() -> SchematicannonRenderer::new) + .register(); + + public static final BlockEntityEntry SCHEMATIC_TABLE = REGISTRATE + .blockEntity("schematic_table", SchematicTableBlockEntity::new) + .validBlocks(AllBlocks.SCHEMATIC_TABLE) + .register(); + + // Kinetics + public static final BlockEntityEntry BRACKETED_KINETIC = REGISTRATE + .blockEntity("simple_kinetic", BracketedKineticBlockEntity::new) + .instance(() -> BracketedKineticBlockEntityInstance::new, false) + .validBlocks(AllBlocks.SHAFT, AllBlocks.COGWHEEL, AllBlocks.LARGE_COGWHEEL) + .renderer(() -> BracketedKineticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry MOTOR = REGISTRATE + .blockEntity("motor", CreativeMotorBlockEntity::new) + .instance(() -> HalfShaftInstance::new, false) + .validBlocks(AllBlocks.CREATIVE_MOTOR) + .renderer(() -> CreativeMotorRenderer::new) + .register(); + + public static final BlockEntityEntry GEARBOX = REGISTRATE + .blockEntity("gearbox", GearboxBlockEntity::new) + .instance(() -> GearboxInstance::new, false) + .validBlocks(AllBlocks.GEARBOX) + .renderer(() -> GearboxRenderer::new) + .register(); + + public static final BlockEntityEntry ENCASED_SHAFT = REGISTRATE + .blockEntity("encased_shaft", KineticBlockEntity::new) + .instance(() -> ShaftInstance::new, false) + .validBlocks(AllBlocks.ANDESITE_ENCASED_SHAFT, AllBlocks.BRASS_ENCASED_SHAFT, AllBlocks.ENCASED_CHAIN_DRIVE, + AllBlocks.METAL_GIRDER_ENCASED_SHAFT) + .renderer(() -> ShaftRenderer::new) + .register(); + + public static final BlockEntityEntry ENCASED_COGWHEEL = REGISTRATE + .blockEntity("encased_cogwheel", SimpleKineticBlockEntity::new) + .instance(() -> EncasedCogInstance::small, false) + .validBlocks(AllBlocks.ANDESITE_ENCASED_COGWHEEL, AllBlocks.BRASS_ENCASED_COGWHEEL) + .renderer(() -> EncasedCogRenderer::small) + .register(); + + public static final BlockEntityEntry ENCASED_LARGE_COGWHEEL = REGISTRATE + .blockEntity("encased_large_cogwheel", SimpleKineticBlockEntity::new) + .instance(() -> EncasedCogInstance::large, false) + .validBlocks(AllBlocks.ANDESITE_ENCASED_LARGE_COGWHEEL, AllBlocks.BRASS_ENCASED_LARGE_COGWHEEL) + .renderer(() -> EncasedCogRenderer::large) + .register(); + + public static final BlockEntityEntry ADJUSTABLE_CHAIN_GEARSHIFT = REGISTRATE + .blockEntity("adjustable_chain_gearshift", ChainGearshiftBlockEntity::new) + .instance(() -> ShaftInstance::new, false) + .validBlocks(AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) + .renderer(() -> ShaftRenderer::new) + .register(); + + public static final BlockEntityEntry ENCASED_FAN = REGISTRATE + .blockEntity("encased_fan", EncasedFanBlockEntity::new) + .instance(() -> FanInstance::new, false) + .validBlocks(AllBlocks.ENCASED_FAN) + .renderer(() -> EncasedFanRenderer::new) + .register(); + + public static final BlockEntityEntry NOZZLE = REGISTRATE + .blockEntity("nozzle", NozzleBlockEntity::new) + .validBlocks(AllBlocks.NOZZLE) + // .renderer(() -> renderer) + .register(); + + public static final BlockEntityEntry CLUTCH = REGISTRATE + .blockEntity("clutch", ClutchBlockEntity::new) + .instance(() -> SplitShaftInstance::new, false) + .validBlocks(AllBlocks.CLUTCH) + .renderer(() -> SplitShaftRenderer::new) + .register(); + + public static final BlockEntityEntry GEARSHIFT = REGISTRATE + .blockEntity("gearshift", GearshiftBlockEntity::new) + .instance(() -> SplitShaftInstance::new, false) + .validBlocks(AllBlocks.GEARSHIFT) + .renderer(() -> SplitShaftRenderer::new) + .register(); + + public static final BlockEntityEntry TURNTABLE = REGISTRATE + .blockEntity("turntable", TurntableBlockEntity::new) + .instance(() -> SingleRotatingInstance::new, false) + .validBlocks(AllBlocks.TURNTABLE) + .renderer(() -> KineticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry HAND_CRANK = REGISTRATE + .blockEntity("hand_crank", HandCrankBlockEntity::new) + .instance(() -> HandCrankInstance::new) + .validBlocks(AllBlocks.HAND_CRANK) + .renderer(() -> HandCrankRenderer::new) + .register(); + + public static final BlockEntityEntry VALVE_HANDLE = REGISTRATE + .blockEntity("valve_handle", ValveHandleBlockEntity::new) + .instance(() -> HandCrankInstance::new) + .validBlocks(AllBlocks.COPPER_VALVE_HANDLE) + .validBlocks(AllBlocks.DYED_VALVE_HANDLES.toArray()) + .renderer(() -> HandCrankRenderer::new) + .register(); + + public static final BlockEntityEntry CUCKOO_CLOCK = REGISTRATE + .blockEntity("cuckoo_clock", CuckooClockBlockEntity::new) + .instance(() -> HorizontalHalfShaftInstance::new) + .validBlocks(AllBlocks.CUCKOO_CLOCK, AllBlocks.MYSTERIOUS_CUCKOO_CLOCK) + .renderer(() -> CuckooClockRenderer::new) + .register(); + + public static final BlockEntityEntry GANTRY_SHAFT = REGISTRATE + .blockEntity("gantry_shaft", GantryShaftBlockEntity::new) + .instance(() -> SingleRotatingInstance::new, false) + .validBlocks(AllBlocks.GANTRY_SHAFT) + .renderer(() -> KineticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry GANTRY_PINION = REGISTRATE + .blockEntity("gantry_pinion", GantryCarriageBlockEntity::new) + .instance(() -> GantryCarriageInstance::new) + .validBlocks(AllBlocks.GANTRY_CARRIAGE) + .renderer(() -> GantryCarriageRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_PUMP = REGISTRATE + .blockEntity("mechanical_pump", PumpBlockEntity::new) + .instance(() -> PumpCogInstance::new) + .validBlocks(AllBlocks.MECHANICAL_PUMP) + .renderer(() -> PumpRenderer::new) + .register(); + + public static final BlockEntityEntry SMART_FLUID_PIPE = REGISTRATE + .blockEntity("smart_fluid_pipe", SmartFluidPipeBlockEntity::new) + .validBlocks(AllBlocks.SMART_FLUID_PIPE) + .renderer(() -> SmartBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry FLUID_PIPE = REGISTRATE + .blockEntity("fluid_pipe", FluidPipeBlockEntity::new) + .validBlocks(AllBlocks.FLUID_PIPE) + .register(); + + public static final BlockEntityEntry ENCASED_FLUID_PIPE = REGISTRATE + .blockEntity("encased_fluid_pipe", FluidPipeBlockEntity::new) + .validBlocks(AllBlocks.ENCASED_FLUID_PIPE) + .register(); + + public static final BlockEntityEntry GLASS_FLUID_PIPE = REGISTRATE + .blockEntity("glass_fluid_pipe", StraightPipeBlockEntity::new) + .validBlocks(AllBlocks.GLASS_FLUID_PIPE) + .renderer(() -> TransparentStraightPipeRenderer::new) + .register(); + + public static final BlockEntityEntry FLUID_VALVE = REGISTRATE + .blockEntity("fluid_valve", FluidValveBlockEntity::new) + .instance(() -> FluidValveInstance::new) + .validBlocks(AllBlocks.FLUID_VALVE) + .renderer(() -> FluidValveRenderer::new) + .register(); + + public static final BlockEntityEntry FLUID_TANK = REGISTRATE + .blockEntity("fluid_tank", FluidTankBlockEntity::new) + .validBlocks(AllBlocks.FLUID_TANK) + .renderer(() -> FluidTankRenderer::new) + .register(); + + public static final BlockEntityEntry CREATIVE_FLUID_TANK = REGISTRATE + .blockEntity("creative_fluid_tank", CreativeFluidTankBlockEntity::new) + .validBlocks(AllBlocks.CREATIVE_FLUID_TANK) + .renderer(() -> FluidTankRenderer::new) + .register(); + + public static final BlockEntityEntry HOSE_PULLEY = REGISTRATE + .blockEntity("hose_pulley", HosePulleyBlockEntity::new) + .instance(() -> HosePulleyInstance::new) + .validBlocks(AllBlocks.HOSE_PULLEY) + .renderer(() -> HosePulleyRenderer::new) + .register(); + + public static final BlockEntityEntry SPOUT = REGISTRATE + .blockEntity("spout", SpoutBlockEntity::new) + .validBlocks(AllBlocks.SPOUT) + .renderer(() -> SpoutRenderer::new) + .register(); + + public static final BlockEntityEntry ITEM_DRAIN = REGISTRATE + .blockEntity("item_drain", ItemDrainBlockEntity::new) + .validBlocks(AllBlocks.ITEM_DRAIN) + .renderer(() -> ItemDrainRenderer::new) + .register(); + + public static final BlockEntityEntry BELT = REGISTRATE + .blockEntity("belt", BeltBlockEntity::new) + .instance(() -> BeltInstance::new, BeltBlockEntity::shouldRenderNormally) + .validBlocks(AllBlocks.BELT) + .renderer(() -> BeltRenderer::new) + .register(); + + public static final BlockEntityEntry CHUTE = REGISTRATE + .blockEntity("chute", ChuteBlockEntity::new) + .validBlocks(AllBlocks.CHUTE) + .renderer(() -> ChuteRenderer::new) + .register(); + + public static final BlockEntityEntry SMART_CHUTE = REGISTRATE + .blockEntity("smart_chute", SmartChuteBlockEntity::new) + .validBlocks(AllBlocks.SMART_CHUTE) + .renderer(() -> SmartChuteRenderer::new) + .register(); + + public static final BlockEntityEntry ANDESITE_TUNNEL = REGISTRATE + .blockEntity("andesite_tunnel", BeltTunnelBlockEntity::new) + .instance(() -> BeltTunnelInstance::new) + .validBlocks(AllBlocks.ANDESITE_TUNNEL) + .renderer(() -> BeltTunnelRenderer::new) + .register(); + + public static final BlockEntityEntry BRASS_TUNNEL = REGISTRATE + .blockEntity("brass_tunnel", BrassTunnelBlockEntity::new) + .instance(() -> BeltTunnelInstance::new) + .validBlocks(AllBlocks.BRASS_TUNNEL) + .renderer(() -> BeltTunnelRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_ARM = REGISTRATE + .blockEntity("mechanical_arm", ArmBlockEntity::new) + .instance(() -> ArmInstance::new) + .validBlocks(AllBlocks.MECHANICAL_ARM) + .renderer(() -> ArmRenderer::new) + .register(); + + public static final BlockEntityEntry ITEM_VAULT = REGISTRATE + .blockEntity("item_vault", ItemVaultBlockEntity::new) + .validBlocks(AllBlocks.ITEM_VAULT) + .register(); + + public static final BlockEntityEntry MECHANICAL_PISTON = REGISTRATE + .blockEntity("mechanical_piston", MechanicalPistonBlockEntity::new) + .instance(() -> ShaftInstance::new, false) + .validBlocks(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) + .renderer(() -> MechanicalPistonRenderer::new) + .register(); + + public static final BlockEntityEntry WINDMILL_BEARING = REGISTRATE + .blockEntity("windmill_bearing", WindmillBearingBlockEntity::new) + .instance(() -> BearingInstance::new) + .validBlocks(AllBlocks.WINDMILL_BEARING) + .renderer(() -> BearingRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_BEARING = REGISTRATE + .blockEntity("mechanical_bearing", MechanicalBearingBlockEntity::new) + .instance(() -> BearingInstance::new) + .validBlocks(AllBlocks.MECHANICAL_BEARING) + .renderer(() -> BearingRenderer::new) + .register(); + + public static final BlockEntityEntry CLOCKWORK_BEARING = REGISTRATE + .blockEntity("clockwork_bearing", ClockworkBearingBlockEntity::new) + .instance(() -> BearingInstance::new) + .validBlocks(AllBlocks.CLOCKWORK_BEARING) + .renderer(() -> BearingRenderer::new) + .register(); + + public static final BlockEntityEntry ROPE_PULLEY = REGISTRATE + .blockEntity("rope_pulley", PulleyBlockEntity::new) + .instance(() -> RopePulleyInstance::new, false) + .validBlocks(AllBlocks.ROPE_PULLEY) + .renderer(() -> PulleyRenderer::new) + .register(); + + public static final BlockEntityEntry ELEVATOR_PULLEY = + REGISTRATE.blockEntity("elevator_pulley", ElevatorPulleyBlockEntity::new) +// .instance(() -> ElevatorPulleyInstance::new, false) + .validBlocks(AllBlocks.ELEVATOR_PULLEY) + .renderer(() -> ElevatorPulleyRenderer::new) + .register(); + + public static final BlockEntityEntry ELEVATOR_CONTACT = + REGISTRATE.blockEntity("elevator_contact", ElevatorContactBlockEntity::new) + .validBlocks(AllBlocks.ELEVATOR_CONTACT) + .register(); + + public static final BlockEntityEntry CHASSIS = REGISTRATE + .blockEntity("chassis", ChassisBlockEntity::new) + .validBlocks(AllBlocks.RADIAL_CHASSIS, AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS) + // .renderer(() -> renderer) + .register(); + + public static final BlockEntityEntry STICKER = REGISTRATE + .blockEntity("sticker", StickerBlockEntity::new) + .instance(() -> StickerInstance::new, false) + .validBlocks(AllBlocks.STICKER) + .renderer(() -> StickerRenderer::new) + .register(); + + public static final BlockEntityEntry CONTRAPTION_CONTROLS = + REGISTRATE.blockEntity("contraption_controls", ContraptionControlsBlockEntity::new) + .validBlocks(AllBlocks.CONTRAPTION_CONTROLS) + .renderer(() -> ContraptionControlsRenderer::new) + .register(); + + public static final BlockEntityEntry DRILL = REGISTRATE + .blockEntity("drill", DrillBlockEntity::new) + .instance(() -> DrillInstance::new, false) + .validBlocks(AllBlocks.MECHANICAL_DRILL) + .renderer(() -> DrillRenderer::new) + .register(); + + public static final BlockEntityEntry SAW = REGISTRATE + .blockEntity("saw", SawBlockEntity::new) + .instance(() -> SawInstance::new) + .validBlocks(AllBlocks.MECHANICAL_SAW) + .renderer(() -> SawRenderer::new) + .register(); + + public static final BlockEntityEntry HARVESTER = REGISTRATE + .blockEntity("harvester", HarvesterBlockEntity::new) + .validBlocks(AllBlocks.MECHANICAL_HARVESTER) + .renderer(() -> HarvesterRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_ROLLER = + REGISTRATE.blockEntity("mechanical_roller", RollerBlockEntity::new) + .validBlocks(AllBlocks.MECHANICAL_ROLLER) + .renderer(() -> RollerRenderer::new) + .register(); + + public static final BlockEntityEntry PORTABLE_STORAGE_INTERFACE = + REGISTRATE + .blockEntity("portable_storage_interface", PortableItemInterfaceBlockEntity::new) + .instance(() -> PSIInstance::new) + .validBlocks(AllBlocks.PORTABLE_STORAGE_INTERFACE) + .renderer(() -> PortableStorageInterfaceRenderer::new) + .register(); + + public static final BlockEntityEntry PORTABLE_FLUID_INTERFACE = + REGISTRATE + .blockEntity("portable_fluid_interface", PortableFluidInterfaceBlockEntity::new) + .instance(() -> PSIInstance::new) + .validBlocks(AllBlocks.PORTABLE_FLUID_INTERFACE) + .renderer(() -> PortableStorageInterfaceRenderer::new) + .register(); + + public static final BlockEntityEntry STEAM_ENGINE = REGISTRATE + .blockEntity("steam_engine", SteamEngineBlockEntity::new) + .instance(() -> SteamEngineInstance::new, false) + .validBlocks(AllBlocks.STEAM_ENGINE) + .renderer(() -> SteamEngineRenderer::new) + .register(); + + public static final BlockEntityEntry STEAM_WHISTLE = REGISTRATE + .blockEntity("steam_whistle", WhistleBlockEntity::new) + .validBlocks(AllBlocks.STEAM_WHISTLE) + .renderer(() -> WhistleRenderer::new) + .register(); + + public static final BlockEntityEntry POWERED_SHAFT = REGISTRATE + .blockEntity("powered_shaft", PoweredShaftBlockEntity::new) + .instance(() -> SingleRotatingInstance::new, false) + .validBlocks(AllBlocks.POWERED_SHAFT) + .renderer(() -> KineticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry FLYWHEEL = REGISTRATE + .blockEntity("flywheel", FlywheelBlockEntity::new) + .instance(() -> FlywheelInstance::new, false) + .validBlocks(AllBlocks.FLYWHEEL) + .renderer(() -> FlywheelRenderer::new) + .register(); + + public static final BlockEntityEntry MILLSTONE = REGISTRATE + .blockEntity("millstone", MillstoneBlockEntity::new) + .instance(() -> MillstoneCogInstance::new, false) + .validBlocks(AllBlocks.MILLSTONE) + .renderer(() -> MillstoneRenderer::new) + .register(); + + public static final BlockEntityEntry CRUSHING_WHEEL = REGISTRATE + .blockEntity("crushing_wheel", CrushingWheelBlockEntity::new) + .instance(() -> CutoutRotatingInstance::new, false) + .validBlocks(AllBlocks.CRUSHING_WHEEL) + .renderer(() -> KineticBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry CRUSHING_WHEEL_CONTROLLER = + REGISTRATE + .blockEntity("crushing_wheel_controller", CrushingWheelControllerBlockEntity::new) + .validBlocks(AllBlocks.CRUSHING_WHEEL_CONTROLLER) + // .renderer(() -> renderer) + .register(); + + public static final BlockEntityEntry WATER_WHEEL = REGISTRATE + .blockEntity("water_wheel", WaterWheelBlockEntity::new) + .instance(() -> WaterWheelInstance::standard, false) + .validBlocks(AllBlocks.WATER_WHEEL) + .renderer(() -> WaterWheelRenderer::standard) + .register(); + + public static final BlockEntityEntry LARGE_WATER_WHEEL = REGISTRATE + .blockEntity("large_water_wheel", LargeWaterWheelBlockEntity::new) + .instance(() -> WaterWheelInstance::large, false) + .validBlocks(AllBlocks.LARGE_WATER_WHEEL) + .renderer(() -> WaterWheelRenderer::large) + .register(); + + public static final BlockEntityEntry MECHANICAL_PRESS = REGISTRATE + .blockEntity("mechanical_press", MechanicalPressBlockEntity::new) + .instance(() -> PressInstance::new) + .validBlocks(AllBlocks.MECHANICAL_PRESS) + .renderer(() -> MechanicalPressRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_MIXER = REGISTRATE + .blockEntity("mechanical_mixer", MechanicalMixerBlockEntity::new) + .instance(() -> MixerInstance::new) + .validBlocks(AllBlocks.MECHANICAL_MIXER) + .renderer(() -> MechanicalMixerRenderer::new) + .register(); + + public static final BlockEntityEntry DEPLOYER = REGISTRATE + .blockEntity("deployer", DeployerBlockEntity::new) + .instance(() -> DeployerInstance::new) + .validBlocks(AllBlocks.DEPLOYER) + .renderer(() -> DeployerRenderer::new) + .register(); + + public static final BlockEntityEntry BASIN = REGISTRATE + .blockEntity("basin", BasinBlockEntity::new) + .validBlocks(AllBlocks.BASIN) + .renderer(() -> BasinRenderer::new) + .register(); + + public static final BlockEntityEntry HEATER = REGISTRATE + .blockEntity("blaze_heater", BlazeBurnerBlockEntity::new) + .validBlocks(AllBlocks.BLAZE_BURNER) + .renderer(() -> BlazeBurnerRenderer::new) + .register(); + + public static final BlockEntityEntry MECHANICAL_CRAFTER = REGISTRATE + .blockEntity("mechanical_crafter", MechanicalCrafterBlockEntity::new) + .instance(() -> ShaftlessCogwheelInstance::new) + .validBlocks(AllBlocks.MECHANICAL_CRAFTER) + .renderer(() -> MechanicalCrafterRenderer::new) + .register(); + + public static final BlockEntityEntry SEQUENCED_GEARSHIFT = REGISTRATE + .blockEntity("sequenced_gearshift", SequencedGearshiftBlockEntity::new) + .instance(() -> SplitShaftInstance::new, false) + .validBlocks(AllBlocks.SEQUENCED_GEARSHIFT) + .renderer(() -> SplitShaftRenderer::new) + .register(); + + public static final BlockEntityEntry ROTATION_SPEED_CONTROLLER = REGISTRATE + .blockEntity("rotation_speed_controller", SpeedControllerBlockEntity::new) + .instance(() -> ShaftInstance::new) + .validBlocks(AllBlocks.ROTATION_SPEED_CONTROLLER) + .renderer(() -> SpeedControllerRenderer::new) + .register(); + + public static final BlockEntityEntry SPEEDOMETER = REGISTRATE + .blockEntity("speedometer", SpeedGaugeBlockEntity::new) + .instance(() -> GaugeInstance.Speed::new) + .validBlocks(AllBlocks.SPEEDOMETER) + .renderer(() -> GaugeRenderer::speed) + .register(); + + public static final BlockEntityEntry STRESSOMETER = REGISTRATE + .blockEntity("stressometer", StressGaugeBlockEntity::new) + .instance(() -> GaugeInstance.Stress::new) + .validBlocks(AllBlocks.STRESSOMETER) + .renderer(() -> GaugeRenderer::stress) + .register(); + + public static final BlockEntityEntry ANALOG_LEVER = REGISTRATE + .blockEntity("analog_lever", AnalogLeverBlockEntity::new) + .instance(() -> AnalogLeverInstance::new, false) + .validBlocks(AllBlocks.ANALOG_LEVER) + .renderer(() -> AnalogLeverRenderer::new) + .register(); + + public static final BlockEntityEntry PLACARD = REGISTRATE + .blockEntity("placard", PlacardBlockEntity::new) + .validBlocks(AllBlocks.PLACARD) + .renderer(() -> PlacardRenderer::new) + .register(); + + public static final BlockEntityEntry CART_ASSEMBLER = REGISTRATE + .blockEntity("cart_assembler", CartAssemblerBlockEntity::new) + .validBlocks(AllBlocks.CART_ASSEMBLER) + // .renderer(() -> renderer) + .register(); + + // Logistics + public static final BlockEntityEntry REDSTONE_LINK = REGISTRATE + .blockEntity("redstone_link", RedstoneLinkBlockEntity::new) + .validBlocks(AllBlocks.REDSTONE_LINK) + .renderer(() -> SmartBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry NIXIE_TUBE = REGISTRATE + .blockEntity("nixie_tube", NixieTubeBlockEntity::new) + .validBlocks(AllBlocks.ORANGE_NIXIE_TUBE) + .validBlocks(AllBlocks.NIXIE_TUBES.toArray()) + .renderer(() -> NixieTubeRenderer::new) + .onRegister(assignDataBehaviourBE(new NixieTubeDisplayTarget())) + .onRegister(assignDataBehaviourBE(new NixieTubeDisplaySource())) + .register(); + + public static final BlockEntityEntry DISPLAY_LINK = REGISTRATE + .blockEntity("display_link", DisplayLinkBlockEntity::new) + .validBlocks(AllBlocks.DISPLAY_LINK) + .renderer(() -> DisplayLinkRenderer::new) + .register(); + + public static final BlockEntityEntry THRESHOLD_SWITCH = REGISTRATE + .blockEntity("stockpile_switch", ThresholdSwitchBlockEntity::new) + .validBlocks(AllBlocks.THRESHOLD_SWITCH) + .renderer(() -> SmartBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry CREATIVE_CRATE = REGISTRATE + .blockEntity("creative_crate", CreativeCrateBlockEntity::new) + .validBlocks(AllBlocks.CREATIVE_CRATE) + .renderer(() -> SmartBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry DEPOT = REGISTRATE + .blockEntity("depot", DepotBlockEntity::new) + .validBlocks(AllBlocks.DEPOT) + .renderer(() -> DepotRenderer::new) + .register(); + + public static final BlockEntityEntry WEIGHTED_EJECTOR = REGISTRATE + .blockEntity("weighted_ejector", EjectorBlockEntity::new) + .instance(() -> EjectorInstance::new) + .validBlocks(AllBlocks.WEIGHTED_EJECTOR) + .renderer(() -> EjectorRenderer::new) + .register(); + + public static final BlockEntityEntry FUNNEL = REGISTRATE + .blockEntity("funnel", FunnelBlockEntity::new) + .instance(() -> FunnelInstance::new) + .validBlocks(AllBlocks.BRASS_FUNNEL, AllBlocks.BRASS_BELT_FUNNEL, AllBlocks.ANDESITE_FUNNEL, + AllBlocks.ANDESITE_BELT_FUNNEL) + .renderer(() -> FunnelRenderer::new) + .register(); + + public static final BlockEntityEntry SMART_OBSERVER = REGISTRATE + .blockEntity("content_observer", SmartObserverBlockEntity::new) + .validBlocks(AllBlocks.SMART_OBSERVER) + .renderer(() -> SmartBlockEntityRenderer::new) + .register(); + + public static final BlockEntityEntry PULSE_EXTENDER = REGISTRATE + .blockEntity("pulse_extender", PulseExtenderBlockEntity::new) + .instance(() -> BrassDiodeInstance::new, false) + .validBlocks(AllBlocks.PULSE_EXTENDER) + .renderer(() -> BrassDiodeRenderer::new) + .register(); + + public static final BlockEntityEntry PULSE_REPEATER = REGISTRATE + .blockEntity("pulse_repeater", PulseRepeaterBlockEntity::new) + .instance(() -> BrassDiodeInstance::new, false) + .validBlocks(AllBlocks.PULSE_REPEATER) + .renderer(() -> BrassDiodeRenderer::new) + .register(); + + public static final BlockEntityEntry LECTERN_CONTROLLER = REGISTRATE + .blockEntity("lectern_controller", LecternControllerBlockEntity::new) + .validBlocks(AllBlocks.LECTERN_CONTROLLER) + .renderer(() -> LecternControllerRenderer::new) + .register(); + + // Curiosities + public static final BlockEntityEntry BACKTANK = REGISTRATE + .blockEntity("backtank", BacktankBlockEntity::new) + .instance(() -> BacktankInstance::new) + .validBlocks(AllBlocks.COPPER_BACKTANK, AllBlocks.NETHERITE_BACKTANK) + .renderer(() -> BacktankRenderer::new) + .register(); + + public static final BlockEntityEntry PECULIAR_BELL = REGISTRATE + .blockEntity("peculiar_bell", PeculiarBellBlockEntity::new) + .validBlocks(AllBlocks.PECULIAR_BELL) + .renderer(() -> BellRenderer::new) + .register(); + + public static final BlockEntityEntry HAUNTED_BELL = REGISTRATE + .blockEntity("cursed_bell", HauntedBellBlockEntity::new) + .validBlocks(AllBlocks.HAUNTED_BELL) + .renderer(() -> BellRenderer::new) + .register(); + + public static final BlockEntityEntry TOOLBOX = REGISTRATE + .blockEntity("toolbox", ToolboxBlockEntity::new) + .instance(() -> ToolBoxInstance::new, false) + .validBlocks(AllBlocks.TOOLBOXES.toArray()) + .renderer(() -> ToolboxRenderer::new) + .register(); + + public static final BlockEntityEntry TRACK = REGISTRATE + .blockEntity("track", TrackBlockEntity::new) + .instance(() -> TrackInstance::new) + .validBlocksDeferred(TrackMaterial::allBlocks) + .renderer(() -> TrackRenderer::new) + .register(); + + public static final BlockEntityEntry FAKE_TRACK = REGISTRATE + .blockEntity("fake_track", FakeTrackBlockEntity::new) + .validBlocks(AllBlocks.FAKE_TRACK) + .register(); + + public static final BlockEntityEntry BOGEY = REGISTRATE + .blockEntity("bogey", StandardBogeyBlockEntity::new) + .renderer(() -> BogeyBlockEntityRenderer::new) + .validBlocks(AllBlocks.SMALL_BOGEY, AllBlocks.LARGE_BOGEY) + .register(); + + public static final BlockEntityEntry TRACK_STATION = REGISTRATE + .blockEntity("track_station", StationBlockEntity::new) + .renderer(() -> StationRenderer::new) + .validBlocks(AllBlocks.TRACK_STATION) + .register(); + + public static final BlockEntityEntry SLIDING_DOOR = + REGISTRATE.blockEntity("sliding_door", SlidingDoorBlockEntity::new) + .renderer(() -> SlidingDoorRenderer::new) + .validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR, AllBlocks.ANDESITE_DOOR, + AllBlocks.BRASS_DOOR, AllBlocks.COPPER_DOOR) + .register(); + + public static final BlockEntityEntry COPYCAT = + REGISTRATE.blockEntity("copycat", CopycatBlockEntity::new) + .validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP) + .register(); + + public static final BlockEntityEntry FLAP_DISPLAY = REGISTRATE + .blockEntity("flap_display", FlapDisplayBlockEntity::new) + .instance(() -> ShaftlessCogwheelInstance::new) + .renderer(() -> FlapDisplayRenderer::new) + .validBlocks(AllBlocks.DISPLAY_BOARD) + .register(); + + public static final BlockEntityEntry TRACK_SIGNAL = REGISTRATE + .blockEntity("track_signal", SignalBlockEntity::new) + .renderer(() -> SignalRenderer::new) + .validBlocks(AllBlocks.TRACK_SIGNAL) + .register(); + + public static final BlockEntityEntry TRACK_OBSERVER = REGISTRATE + .blockEntity("track_observer", TrackObserverBlockEntity::new) + .renderer(() -> TrackObserverRenderer::new) + .validBlocks(AllBlocks.TRACK_OBSERVER) + .register(); + + public static final BlockEntityEntry CLIPBOARD = REGISTRATE + .blockEntity("clipboard", ClipboardBlockEntity::new) + .validBlocks(AllBlocks.CLIPBOARD) + .register(); + + public static void register() {} +} diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java deleted file mode 100644 index d51f1fa578..0000000000 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ /dev/null @@ -1,197 +0,0 @@ -package com.simibubi.create; - -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.core.Direction; -import net.minecraft.world.item.DyeColor; - -public class AllBlockPartials { - - public static final PartialModel - - SCHEMATICANNON_CONNECTOR = block("schematicannon/connector"), SCHEMATICANNON_PIPE = block("schematicannon/pipe"), - - SHAFTLESS_COGWHEEL = block("cogwheel_shaftless"), SHAFTLESS_LARGE_COGWHEEL = block("large_cogwheel_shaftless"), - COGWHEEL_SHAFT = block("cogwheel_shaft"), SHAFT_HALF = block("shaft_half"), - - BELT_PULLEY = block("belt_pulley"), BELT_START = block("belt/start"), BELT_MIDDLE = block("belt/middle"), - BELT_END = block("belt/end"), BELT_START_BOTTOM = block("belt/start_bottom"), - BELT_MIDDLE_BOTTOM = block("belt/middle_bottom"), BELT_END_BOTTOM = block("belt/end_bottom"), - BELT_DIAGONAL_START = block("belt/diagonal_start"), BELT_DIAGONAL_MIDDLE = block("belt/diagonal_middle"), - BELT_DIAGONAL_END = block("belt/diagonal_end"), - - ENCASED_FAN_INNER = block("encased_fan/propeller"), HAND_CRANK_HANDLE = block("hand_crank/handle"), - MECHANICAL_PRESS_HEAD = block("mechanical_press/head"), MECHANICAL_MIXER_POLE = block("mechanical_mixer/pole"), - MECHANICAL_MIXER_HEAD = block("mechanical_mixer/head"), - MECHANICAL_CRAFTER_LID = block("mechanical_crafter/lid"), - MECHANICAL_CRAFTER_ARROW = block("mechanical_crafter/arrow"), - MECHANICAL_CRAFTER_BELT_FRAME = block("mechanical_crafter/belt"), - MECHANICAL_CRAFTER_BELT = block("mechanical_crafter/belt_animated"), - SAW_BLADE_HORIZONTAL_ACTIVE = block("mechanical_saw/blade_horizontal_active"), - SAW_BLADE_HORIZONTAL_INACTIVE = block("mechanical_saw/blade_horizontal_inactive"), - SAW_BLADE_HORIZONTAL_REVERSED = block("mechanical_saw/blade_horizontal_reversed"), - SAW_BLADE_VERTICAL_ACTIVE = block("mechanical_saw/blade_vertical_active"), - SAW_BLADE_VERTICAL_INACTIVE = block("mechanical_saw/blade_vertical_inactive"), - SAW_BLADE_VERTICAL_REVERSED = block("mechanical_saw/blade_vertical_reversed"), GAUGE_DIAL = block("gauge/dial"), - GAUGE_INDICATOR = block("gauge/indicator"), GAUGE_HEAD_SPEED = block("gauge/speedometer/head"), - GAUGE_HEAD_STRESS = block("gauge/stressometer/head"), BEARING_TOP = block("bearing/top"), - BEARING_TOP_WOODEN = block("bearing/top_wooden"), DRILL_HEAD = block("mechanical_drill/head"), - HARVESTER_BLADE = block("mechanical_harvester/blade"), DEPLOYER_POLE = block("deployer/pole"), - DEPLOYER_HAND_POINTING = block("deployer/hand_pointing"), - DEPLOYER_HAND_PUNCHING = block("deployer/hand_punching"), - DEPLOYER_HAND_HOLDING = block("deployer/hand_holding"), ANALOG_LEVER_HANDLE = block("analog_lever/handle"), - ANALOG_LEVER_INDICATOR = block("analog_lever/indicator"), FUNNEL_FLAP = block("funnel/flap"), - BELT_FUNNEL_FLAP = block("belt_funnel/flap"), BELT_TUNNEL_FLAP = block("belt_tunnel/flap"), - FLEXPEATER_INDICATOR = block("diodes/indicator"), - - CUCKOO_MINUTE_HAND = block("cuckoo_clock/minute_hand"), CUCKOO_HOUR_HAND = block("cuckoo_clock/hour_hand"), - CUCKOO_LEFT_DOOR = block("cuckoo_clock/left_door"), CUCKOO_RIGHT_DOOR = block("cuckoo_clock/right_door"), - CUCKOO_PIG = block("cuckoo_clock/pig"), CUCKOO_CREEPER = block("cuckoo_clock/creeper"), - - GANTRY_COGS = block("gantry_carriage/wheels"), - - ROPE_COIL = block("rope_pulley/rope_coil"), ROPE_HALF = block("rope_pulley/rope_half"), - ROPE_HALF_MAGNET = block("rope_pulley/rope_half_magnet"), - - HOSE_COIL = block("hose_pulley/rope_coil"), HOSE = block("hose_pulley/rope"), - HOSE_MAGNET = block("hose_pulley/pulley_magnet"), HOSE_HALF = block("hose_pulley/rope_half"), - HOSE_HALF_MAGNET = block("hose_pulley/rope_half_magnet"), - - MILLSTONE_COG = block("millstone/inner"), - - SYMMETRY_PLANE = block("symmetry_effect/plane"), SYMMETRY_CROSSPLANE = block("symmetry_effect/crossplane"), - SYMMETRY_TRIPLEPLANE = block("symmetry_effect/tripleplane"), - - STICKER_HEAD = block("sticker/head"), - - PORTABLE_STORAGE_INTERFACE_MIDDLE = block("portable_storage_interface/block_middle"), - PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED = block("portable_storage_interface/block_middle_powered"), - PORTABLE_STORAGE_INTERFACE_TOP = block("portable_storage_interface/block_top"), - - PORTABLE_FLUID_INTERFACE_MIDDLE = block("portable_fluid_interface/block_middle"), - PORTABLE_FLUID_INTERFACE_MIDDLE_POWERED = block("portable_fluid_interface/block_middle_powered"), - PORTABLE_FLUID_INTERFACE_TOP = block("portable_fluid_interface/block_top"), - - ARM_COG = block("mechanical_arm/cog"), ARM_BASE = block("mechanical_arm/base"), - ARM_LOWER_BODY = block("mechanical_arm/lower_body"), ARM_UPPER_BODY = block("mechanical_arm/upper_body"), - ARM_HEAD = block("mechanical_arm/head"), ARM_CLAW_BASE = block("mechanical_arm/claw_base"), - ARM_CLAW_GRIP = block("mechanical_arm/claw_grip"), - - MECHANICAL_PUMP_ARROW = block("mechanical_pump/arrow"), MECHANICAL_PUMP_COG = block("mechanical_pump/cog"), - FLUID_PIPE_CASING = block("fluid_pipe/casing"), FLUID_VALVE_POINTER = block("fluid_valve/pointer"), - - SPOUT_TOP = block("spout/top"), SPOUT_MIDDLE = block("spout/middle"), SPOUT_BOTTOM = block("spout/bottom"), - - PECULIAR_BELL = block("peculiar_bell"), HAUNTED_BELL = block("haunted_bell"), - - TOOLBOX_DRAWER = block("toolbox/drawer"), - - SPEED_CONTROLLER_BRACKET = block("rotation_speed_controller/bracket"), - - GOGGLES = block("goggles"), - - EJECTOR_TOP = block("weighted_ejector/top"), - - COPPER_BACKTANK_SHAFT = block("copper_backtank/block_shaft_input"), - COPPER_BACKTANK_COGS = block("copper_backtank/block_cogs"), - - TRACK_SEGMENT_LEFT = block("track/segment_left"), TRACK_SEGMENT_RIGHT = block("track/segment_right"), - TRACK_TIE = block("track/tie"), GIRDER_SEGMENT_TOP = block("metal_girder/segment_top"), - GIRDER_SEGMENT_MIDDLE = block("metal_girder/segment_middle"), - GIRDER_SEGMENT_BOTTOM = block("metal_girder/segment_bottom"), - - TRACK_STATION_OVERLAY = block("track_overlay/station"), TRACK_SIGNAL_OVERLAY = block("track_overlay/signal"), - TRACK_ASSEMBLING_OVERLAY = block("track_overlay/assembling"), - TRACK_SIGNAL_DUAL_OVERLAY = block("track_overlay/signal_dual"), - TRACK_OBSERVER_OVERLAY = block("track_overlay/observer"), - - BOGEY_FRAME = block("track/bogey/bogey_frame"), SMALL_BOGEY_WHEELS = block("track/bogey/bogey_wheel"), - BOGEY_PIN = block("track/bogey/bogey_drive_wheel_pin"), BOGEY_PISTON = block("track/bogey/bogey_drive_piston"), - BOGEY_DRIVE = block("track/bogey/bogey_drive"), LARGE_BOGEY_WHEELS = block("track/bogey/bogey_drive_wheel"), - - TRAIN_COUPLING_HEAD = block("track/bogey/coupling_head"), - TRAIN_COUPLING_CABLE = block("track/bogey/coupling_cable"), - - TRAIN_CONTROLS_COVER = block("controls/train/cover"), TRAIN_CONTROLS_LEVER = block("controls/train/lever"), - - ENGINE_PISTON = block("steam_engine/piston"), ENGINE_LINKAGE = block("steam_engine/linkage"), - ENGINE_CONNECTOR = block("steam_engine/shaft_connector"), BOILER_GAUGE = block("steam_engine/gauge"), - BOILER_GAUGE_DIAL = block("steam_engine/gauge_dial"), - - SIGNAL_ON = block("track_signal/indicator_on"), SIGNAL_OFF = block("track_signal/indicator_off"), - DISPLAY_LINK_TUBE = block("display_link/tube"), DISPLAY_LINK_GLOW = block("display_link/glow"), - - STATION_ON = block("track_station/flag_on"), STATION_OFF = block("track_station/flag_off"), - STATION_ASSEMBLE = block("track_station/flag_assemble"), - - SIGNAL_PANEL = block("track_signal/panel"), SIGNAL_WHITE_CUBE = block("track_signal/white_cube"), - SIGNAL_WHITE_GLOW = block("track_signal/white_glow"), SIGNAL_WHITE = block("track_signal/white_tube"), - SIGNAL_RED_CUBE = block("track_signal/red_cube"), SIGNAL_RED_GLOW = block("track_signal/red_glow"), - SIGNAL_RED = block("track_signal/red_tube"), SIGNAL_YELLOW_CUBE = block("track_signal/yellow_cube"), - SIGNAL_YELLOW_GLOW = block("track_signal/yellow_glow"), SIGNAL_YELLOW = block("track_signal/yellow_tube"), - - BLAZE_INERT = block("blaze_burner/blaze/inert"), BLAZE_SUPER_ACTIVE = block("blaze_burner/blaze/super_active"), - BLAZE_GOGGLES = block("blaze_burner/goggles"), BLAZE_GOGGLES_SMALL = block("blaze_burner/goggles_small"), - BLAZE_IDLE = block("blaze_burner/blaze/idle"), BLAZE_ACTIVE = block("blaze_burner/blaze/active"), - BLAZE_SUPER = block("blaze_burner/blaze/super"), BLAZE_BURNER_FLAME = block("blaze_burner/flame"), - BLAZE_BURNER_RODS = block("blaze_burner/rods_small"), - BLAZE_BURNER_RODS_2 = block("blaze_burner/rods_large"), - BLAZE_BURNER_SUPER_RODS = block("blaze_burner/superheated_rods_small"), - BLAZE_BURNER_SUPER_RODS_2 = block("blaze_burner/superheated_rods_large"), - - WHISTLE_MOUTH_LARGE = block("steam_whistle/large_mouth"), - WHISTLE_MOUTH_MEDIUM = block("steam_whistle/medium_mouth"), - WHISTLE_MOUTH_SMALL = block("steam_whistle/small_mouth"), - - CRAFTING_BLUEPRINT_1x1 = entity("crafting_blueprint_small"), - CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"), - CRAFTING_BLUEPRINT_3x3 = entity("crafting_blueprint_large"), - - TRAIN_HAT = entity("train_hat"), - - COUPLING_ATTACHMENT = entity("minecart_coupling/attachment"), COUPLING_RING = entity("minecart_coupling/ring"), - COUPLING_CONNECTOR = entity("minecart_coupling/connector") - - ; - - public static final Map> PIPE_ATTACHMENTS = - new EnumMap<>(FluidTransportBehaviour.AttachmentTypes.ComponentPartials.class); - - public static final Map METAL_GIRDER_BRACKETS = new EnumMap<>(Direction.class); - public static final Map TOOLBOX_LIDS = new EnumMap<>(DyeColor.class); - - static { - for (FluidTransportBehaviour.AttachmentTypes.ComponentPartials type : FluidTransportBehaviour.AttachmentTypes.ComponentPartials.values()) { - Map map = new HashMap<>(); - for (Direction d : Iterate.directions) { - String asId = Lang.asId(type.name()); - map.put(d, block("fluid_pipe/" + asId + "/" + Lang.asId(d.getSerializedName()))); - } - PIPE_ATTACHMENTS.put(type, map); - } - for (DyeColor color : DyeColor.values()) - TOOLBOX_LIDS.put(color, block("toolbox/lid/" + Lang.asId(color.name()))); - for (Direction d : Iterate.horizontalDirections) - METAL_GIRDER_BRACKETS.put(d, block("metal_girder/bracket_" + Lang.asId(d.name()))); - } - - private static PartialModel block(String path) { - return new PartialModel(Create.asResource("block/" + path)); - } - - private static PartialModel entity(String path) { - return new PartialModel(Create.asResource("entity/" + path)); - } - - public static void init() { - // init static fields - } - -} diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 6627fc27bc..4514726350 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -2,233 +2,264 @@ package com.simibubi.create; import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour; import static com.simibubi.create.AllMovementBehaviours.movementBehaviour; -import static com.simibubi.create.AllTags.axeOnly; -import static com.simibubi.create.AllTags.axeOrPickaxe; -import static com.simibubi.create.AllTags.pickaxeOnly; -import static com.simibubi.create.AllTags.tagBlockAndItem; -import static com.simibubi.create.content.AllSections.SCHEMATICS; -import static com.simibubi.create.content.logistics.block.display.AllDisplayBehaviours.assignDataBehaviour; +import static com.simibubi.create.Create.REGISTRATE; +import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour; import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll; import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; import static com.simibubi.create.foundation.data.ModelGen.customItemModel; +import static com.simibubi.create.foundation.data.TagGen.axeOnly; +import static com.simibubi.create.foundation.data.TagGen.axeOrPickaxe; +import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly; +import static com.simibubi.create.foundation.data.TagGen.tagBlockAndItem; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllItemTags; -import com.simibubi.create.content.AllSections; -import com.simibubi.create.content.contraptions.base.CasingBlock; -import com.simibubi.create.content.contraptions.components.AssemblyOperatorBlockItem; -import com.simibubi.create.content.contraptions.components.actors.BellMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.DrillBlock; -import com.simibubi.create.content.contraptions.components.actors.DrillMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock; -import com.simibubi.create.content.contraptions.components.actors.HarvesterMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.PloughBlock; -import com.simibubi.create.content.contraptions.components.actors.PloughMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement; -import com.simibubi.create.content.contraptions.components.actors.SawMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.SeatBlock; -import com.simibubi.create.content.contraptions.components.actors.SeatInteractionBehaviour; -import com.simibubi.create.content.contraptions.components.actors.SeatMovementBehaviour; -import com.simibubi.create.content.contraptions.components.clock.CuckooClockBlock; -import com.simibubi.create.content.contraptions.components.crafter.CrafterCTBehaviour; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock; -import com.simibubi.create.content.contraptions.components.crank.HandCrankBlock; -import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelBlock; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerBlock; -import com.simibubi.create.content.contraptions.components.deployer.DeployerBlock; -import com.simibubi.create.content.contraptions.components.deployer.DeployerMovementBehaviour; -import com.simibubi.create.content.contraptions.components.deployer.DeployerMovingInteraction; -import com.simibubi.create.content.contraptions.components.fan.EncasedFanBlock; -import com.simibubi.create.content.contraptions.components.fan.NozzleBlock; -import com.simibubi.create.content.contraptions.components.flywheel.FlywheelBlock; -import com.simibubi.create.content.contraptions.components.millstone.MillstoneBlock; -import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerBlock; -import com.simibubi.create.content.contraptions.components.motor.CreativeMotorBlock; -import com.simibubi.create.content.contraptions.components.motor.CreativeMotorGenerator; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressBlock; -import com.simibubi.create.content.contraptions.components.saw.SawBlock; -import com.simibubi.create.content.contraptions.components.saw.SawGenerator; -import com.simibubi.create.content.contraptions.components.steam.PoweredShaftBlock; -import com.simibubi.create.content.contraptions.components.steam.SteamEngineBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleGenerator; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BlankSailBlockItem; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedBearingMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock.ChassisCTBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.RadialChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsInteractionBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock.MinecartAnchorBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlockItem; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonHeadBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonExtensionPoleBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock; -import com.simibubi.create.content.contraptions.components.tracks.ControllerRailBlock; -import com.simibubi.create.content.contraptions.components.tracks.ControllerRailGenerator; -import com.simibubi.create.content.contraptions.components.turntable.TurntableBlock; -import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelBlock; -import com.simibubi.create.content.contraptions.fluids.PipeAttachmentModel; -import com.simibubi.create.content.contraptions.fluids.PumpBlock; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyBlock; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainBlock; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlockItem; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketGenerator; -import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.GlassFluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeGenerator; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankGenerator; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankItem; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankModel; -import com.simibubi.create.content.contraptions.processing.BasinBlock; -import com.simibubi.create.content.contraptions.processing.BasinGenerator; -import com.simibubi.create.content.contraptions.processing.BasinMovementBehaviour; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerInteractionBehaviour; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerMovementBehaviour; -import com.simibubi.create.content.contraptions.processing.burner.LitBlazeBurnerBlock; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock; -import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftBlock; -import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftGenerator; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltGenerator; -import com.simibubi.create.content.contraptions.relays.belt.BeltModel; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedKineticBlockModel; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyBlock; -import com.simibubi.create.content.contraptions.relays.encased.ClutchBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltGenerator; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCTBehaviour; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogCTBehaviour; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogwheelBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; -import com.simibubi.create.content.contraptions.relays.encased.GearshiftBlock; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeGenerator; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock; -import com.simibubi.create.content.curiosities.armor.CopperBacktankBlock; -import com.simibubi.create.content.curiosities.bell.HauntedBellBlock; -import com.simibubi.create.content.curiosities.bell.HauntedBellMovementBehaviour; -import com.simibubi.create.content.curiosities.bell.PeculiarBellBlock; -import com.simibubi.create.content.curiosities.deco.MetalLadderBlock; -import com.simibubi.create.content.curiosities.deco.PlacardBlock; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.curiosities.deco.TrainTrapdoorBlock; -import com.simibubi.create.content.curiosities.deco.TrapdoorCTBehaviour; -import com.simibubi.create.content.curiosities.girder.ConnectedGirderModel; -import com.simibubi.create.content.curiosities.girder.GirderBlock; -import com.simibubi.create.content.curiosities.girder.GirderBlockStateGenerator; -import com.simibubi.create.content.curiosities.girder.GirderEncasedShaftBlock; -import com.simibubi.create.content.curiosities.toolbox.ToolboxBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelCTBehaviour; -import com.simibubi.create.content.logistics.block.chute.ChuteBlock; -import com.simibubi.create.content.logistics.block.chute.ChuteGenerator; -import com.simibubi.create.content.logistics.block.chute.ChuteItem; -import com.simibubi.create.content.logistics.block.chute.SmartChuteBlock; -import com.simibubi.create.content.logistics.block.depot.DepotBlock; -import com.simibubi.create.content.logistics.block.depot.EjectorBlock; -import com.simibubi.create.content.logistics.block.depot.EjectorItem; -import com.simibubi.create.content.logistics.block.diodes.AbstractDiodeGenerator; -import com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock; -import com.simibubi.create.content.logistics.block.diodes.BrassDiodeGenerator; -import com.simibubi.create.content.logistics.block.diodes.PoweredLatchBlock; -import com.simibubi.create.content.logistics.block.diodes.PoweredLatchGenerator; -import com.simibubi.create.content.logistics.block.diodes.ToggleLatchBlock; -import com.simibubi.create.content.logistics.block.diodes.ToggleLatchGenerator; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlockItem; -import com.simibubi.create.content.logistics.block.display.source.AccumulatedItemCountDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.BoilerDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.EntityNameDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.FillLevelDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.FluidAmountDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.FluidListDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ItemCountDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ItemListDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ItemNameDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ItemThroughputDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.KineticSpeedDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.KineticStressDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ObservedTrainNameSource; -import com.simibubi.create.content.logistics.block.display.source.StationSummaryDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.StopWatchDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.TimeOfDayDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.TrainStatusDisplaySource; -import com.simibubi.create.content.logistics.block.display.target.DisplayBoardTarget; -import com.simibubi.create.content.logistics.block.funnel.AndesiteFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelGenerator; -import com.simibubi.create.content.logistics.block.funnel.BrassFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.FunnelGenerator; -import com.simibubi.create.content.logistics.block.funnel.FunnelItem; -import com.simibubi.create.content.logistics.block.funnel.FunnelMovementBehaviour; -import com.simibubi.create.content.logistics.block.inventories.CreativeCrateBlock; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmBlock; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmItem; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverBlock; -import com.simibubi.create.content.logistics.block.redstone.ContactMovementBehaviour; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeGenerator; -import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkGenerator; -import com.simibubi.create.content.logistics.block.redstone.RoseQuartzLampBlock; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchBlock; -import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; -import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour; -import com.simibubi.create.content.logistics.block.vault.ItemVaultItem; -import com.simibubi.create.content.logistics.item.LecternControllerBlock; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock; -import com.simibubi.create.content.logistics.trains.track.FakeTrackBlock; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlockItem; -import com.simibubi.create.content.logistics.trains.track.TrackBlockStateGenerator; -import com.simibubi.create.content.schematics.block.SchematicTableBlock; -import com.simibubi.create.content.schematics.block.SchematicannonBlock; -import com.simibubi.create.foundation.block.BlockStressDefaults; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlock; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterBlock; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; +import com.simibubi.create.content.contraptions.actors.plough.PloughBlock; +import com.simibubi.create.content.contraptions.actors.plough.PloughMovementBehaviour; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceBlock; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; +import com.simibubi.create.content.contraptions.actors.roller.RollerBlock; +import com.simibubi.create.content.contraptions.actors.roller.RollerBlockItem; +import com.simibubi.create.content.contraptions.actors.roller.RollerMovementBehaviour; +import com.simibubi.create.content.contraptions.actors.seat.SeatBlock; +import com.simibubi.create.content.contraptions.actors.seat.SeatInteractionBehaviour; +import com.simibubi.create.content.contraptions.actors.seat.SeatMovementBehaviour; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsInteractionBehaviour; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsMovementBehaviour; +import com.simibubi.create.content.contraptions.bearing.BlankSailBlockItem; +import com.simibubi.create.content.contraptions.bearing.ClockworkBearingBlock; +import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlock; +import com.simibubi.create.content.contraptions.bearing.SailBlock; +import com.simibubi.create.content.contraptions.bearing.StabilizedBearingMovementBehaviour; +import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlock; +import com.simibubi.create.content.contraptions.behaviour.BellMovementBehaviour; +import com.simibubi.create.content.contraptions.chassis.LinearChassisBlock; +import com.simibubi.create.content.contraptions.chassis.LinearChassisBlock.ChassisCTBehaviour; +import com.simibubi.create.content.contraptions.chassis.RadialChassisBlock; +import com.simibubi.create.content.contraptions.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.elevator.ElevatorContactBlock; +import com.simibubi.create.content.contraptions.elevator.ElevatorPulleyBlock; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageBlock; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock.MinecartAnchorBlock; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockItem; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonHeadBlock; +import com.simibubi.create.content.contraptions.piston.PistonExtensionPoleBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlock; +import com.simibubi.create.content.decoration.MetalLadderBlock; +import com.simibubi.create.content.decoration.MetalScaffoldingBlock; +import com.simibubi.create.content.decoration.TrainTrapdoorBlock; +import com.simibubi.create.content.decoration.TrapdoorCTBehaviour; +import com.simibubi.create.content.decoration.bracket.BracketBlock; +import com.simibubi.create.content.decoration.bracket.BracketBlockItem; +import com.simibubi.create.content.decoration.bracket.BracketGenerator; +import com.simibubi.create.content.decoration.copycat.CopycatBarsModel; +import com.simibubi.create.content.decoration.copycat.CopycatPanelBlock; +import com.simibubi.create.content.decoration.copycat.CopycatPanelModel; +import com.simibubi.create.content.decoration.copycat.CopycatStepBlock; +import com.simibubi.create.content.decoration.copycat.CopycatStepModel; +import com.simibubi.create.content.decoration.copycat.SpecialCopycatPanelBlockState; +import com.simibubi.create.content.decoration.encasing.CasingBlock; +import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour; +import com.simibubi.create.content.decoration.encasing.EncasingRegistry; +import com.simibubi.create.content.decoration.girder.ConnectedGirderModel; +import com.simibubi.create.content.decoration.girder.GirderBlock; +import com.simibubi.create.content.decoration.girder.GirderBlockStateGenerator; +import com.simibubi.create.content.decoration.girder.GirderEncasedShaftBlock; +import com.simibubi.create.content.decoration.placard.PlacardBlock; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleGenerator; +import com.simibubi.create.content.equipment.armor.BacktankBlock; +import com.simibubi.create.content.equipment.bell.HauntedBellBlock; +import com.simibubi.create.content.equipment.bell.HauntedBellMovementBehaviour; +import com.simibubi.create.content.equipment.bell.PeculiarBellBlock; +import com.simibubi.create.content.equipment.clipboard.ClipboardBlock; +import com.simibubi.create.content.equipment.clipboard.ClipboardBlockItem; +import com.simibubi.create.content.equipment.clipboard.ClipboardOverrides; +import com.simibubi.create.content.equipment.toolbox.ToolboxBlock; +import com.simibubi.create.content.fluids.PipeAttachmentModel; +import com.simibubi.create.content.fluids.drain.ItemDrainBlock; +import com.simibubi.create.content.fluids.hosePulley.HosePulleyBlock; +import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.content.fluids.pipes.GlassFluidPipeBlock; +import com.simibubi.create.content.fluids.pipes.SmartFluidPipeBlock; +import com.simibubi.create.content.fluids.pipes.SmartFluidPipeGenerator; +import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock; +import com.simibubi.create.content.fluids.pump.PumpBlock; +import com.simibubi.create.content.fluids.spout.SpoutBlock; +import com.simibubi.create.content.fluids.tank.FluidTankBlock; +import com.simibubi.create.content.fluids.tank.FluidTankGenerator; +import com.simibubi.create.content.fluids.tank.FluidTankItem; +import com.simibubi.create.content.fluids.tank.FluidTankModel; +import com.simibubi.create.content.kinetics.BlockStressDefaults; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltGenerator; +import com.simibubi.create.content.kinetics.belt.BeltModel; +import com.simibubi.create.content.kinetics.chainDrive.ChainDriveBlock; +import com.simibubi.create.content.kinetics.chainDrive.ChainDriveGenerator; +import com.simibubi.create.content.kinetics.chainDrive.ChainGearshiftBlock; +import com.simibubi.create.content.kinetics.clock.CuckooClockBlock; +import com.simibubi.create.content.kinetics.crafter.CrafterCTBehaviour; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlock; +import com.simibubi.create.content.kinetics.crank.HandCrankBlock; +import com.simibubi.create.content.kinetics.crank.ValveHandleBlock; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelBlock; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelControllerBlock; +import com.simibubi.create.content.kinetics.deployer.DeployerBlock; +import com.simibubi.create.content.kinetics.deployer.DeployerMovementBehaviour; +import com.simibubi.create.content.kinetics.deployer.DeployerMovingInteraction; +import com.simibubi.create.content.kinetics.drill.DrillBlock; +import com.simibubi.create.content.kinetics.drill.DrillMovementBehaviour; +import com.simibubi.create.content.kinetics.fan.EncasedFanBlock; +import com.simibubi.create.content.kinetics.fan.NozzleBlock; +import com.simibubi.create.content.kinetics.flywheel.FlywheelBlock; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlock; +import com.simibubi.create.content.kinetics.gauge.GaugeBlock; +import com.simibubi.create.content.kinetics.gauge.GaugeGenerator; +import com.simibubi.create.content.kinetics.gearbox.GearboxBlock; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmBlock; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmItem; +import com.simibubi.create.content.kinetics.millstone.MillstoneBlock; +import com.simibubi.create.content.kinetics.mixer.MechanicalMixerBlock; +import com.simibubi.create.content.kinetics.motor.CreativeMotorBlock; +import com.simibubi.create.content.kinetics.motor.CreativeMotorGenerator; +import com.simibubi.create.content.kinetics.press.MechanicalPressBlock; +import com.simibubi.create.content.kinetics.saw.SawBlock; +import com.simibubi.create.content.kinetics.saw.SawGenerator; +import com.simibubi.create.content.kinetics.saw.SawMovementBehaviour; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockModel; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.CogwheelBlockItem; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogCTBehaviour; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogwheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedShaftBlock; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlock; +import com.simibubi.create.content.kinetics.steamEngine.PoweredShaftBlock; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineBlock; +import com.simibubi.create.content.kinetics.transmission.ClutchBlock; +import com.simibubi.create.content.kinetics.transmission.GearshiftBlock; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlock; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftGenerator; +import com.simibubi.create.content.kinetics.turntable.TurntableBlock; +import com.simibubi.create.content.kinetics.waterwheel.LargeWaterWheelBlock; +import com.simibubi.create.content.kinetics.waterwheel.LargeWaterWheelBlockItem; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelBlock; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelStructuralBlock; +import com.simibubi.create.content.logistics.chute.ChuteBlock; +import com.simibubi.create.content.logistics.chute.ChuteGenerator; +import com.simibubi.create.content.logistics.chute.ChuteItem; +import com.simibubi.create.content.logistics.chute.SmartChuteBlock; +import com.simibubi.create.content.logistics.crate.CreativeCrateBlock; +import com.simibubi.create.content.logistics.depot.DepotBlock; +import com.simibubi.create.content.logistics.depot.EjectorBlock; +import com.simibubi.create.content.logistics.depot.EjectorItem; +import com.simibubi.create.content.logistics.funnel.AndesiteFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelGenerator; +import com.simibubi.create.content.logistics.funnel.BrassFunnelBlock; +import com.simibubi.create.content.logistics.funnel.FunnelGenerator; +import com.simibubi.create.content.logistics.funnel.FunnelItem; +import com.simibubi.create.content.logistics.funnel.FunnelMovementBehaviour; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelCTBehaviour; +import com.simibubi.create.content.logistics.vault.ItemVaultBlock; +import com.simibubi.create.content.logistics.vault.ItemVaultCTBehaviour; +import com.simibubi.create.content.logistics.vault.ItemVaultItem; +import com.simibubi.create.content.materials.ExperienceBlock; +import com.simibubi.create.content.processing.AssemblyOperatorBlockItem; +import com.simibubi.create.content.processing.basin.BasinBlock; +import com.simibubi.create.content.processing.basin.BasinGenerator; +import com.simibubi.create.content.processing.basin.BasinMovementBehaviour; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlockItem; +import com.simibubi.create.content.processing.burner.BlazeBurnerInteractionBehaviour; +import com.simibubi.create.content.processing.burner.BlazeBurnerMovementBehaviour; +import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock; +import com.simibubi.create.content.redstone.RoseQuartzLampBlock; +import com.simibubi.create.content.redstone.analogLever.AnalogLeverBlock; +import com.simibubi.create.content.redstone.contact.ContactMovementBehaviour; +import com.simibubi.create.content.redstone.contact.RedstoneContactBlock; +import com.simibubi.create.content.redstone.contact.RedstoneContactItem; +import com.simibubi.create.content.redstone.diodes.AbstractDiodeGenerator; +import com.simibubi.create.content.redstone.diodes.BrassDiodeBlock; +import com.simibubi.create.content.redstone.diodes.BrassDiodeGenerator; +import com.simibubi.create.content.redstone.diodes.PoweredLatchBlock; +import com.simibubi.create.content.redstone.diodes.PoweredLatchGenerator; +import com.simibubi.create.content.redstone.diodes.ToggleLatchBlock; +import com.simibubi.create.content.redstone.diodes.ToggleLatchGenerator; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockItem; +import com.simibubi.create.content.redstone.displayLink.source.AccumulatedItemCountDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.BoilerDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.CurrentFloorDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.EntityNameDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.FillLevelDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.FluidAmountDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.FluidListDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ItemCountDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ItemListDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ItemNameDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ItemThroughputDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.KineticSpeedDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.KineticStressDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ObservedTrainNameSource; +import com.simibubi.create.content.redstone.displayLink.source.StationSummaryDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.StopWatchDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.TimeOfDayDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.TrainStatusDisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget; +import com.simibubi.create.content.redstone.link.RedstoneLinkBlock; +import com.simibubi.create.content.redstone.link.RedstoneLinkGenerator; +import com.simibubi.create.content.redstone.link.controller.LecternControllerBlock; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlock; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeGenerator; +import com.simibubi.create.content.redstone.rail.ControllerRailBlock; +import com.simibubi.create.content.redstone.rail.ControllerRailGenerator; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlock; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverGenerator; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlock; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchGenerator; +import com.simibubi.create.content.schematics.cannon.SchematicannonBlock; +import com.simibubi.create.content.schematics.table.SchematicTableBlock; +import com.simibubi.create.content.trains.bogey.BogeySizes; +import com.simibubi.create.content.trains.bogey.StandardBogeyBlock; +import com.simibubi.create.content.trains.display.FlapDisplayBlock; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.observer.TrackObserverBlock; +import com.simibubi.create.content.trains.signal.SignalBlock; +import com.simibubi.create.content.trains.station.StationBlock; +import com.simibubi.create.content.trains.track.FakeTrackBlock; +import com.simibubi.create.content.trains.track.TrackBlock; +import com.simibubi.create.content.trains.track.TrackBlockItem; +import com.simibubi.create.content.trains.track.TrackBlockStateGenerator; +import com.simibubi.create.content.trains.track.TrackMaterial; +import com.simibubi.create.content.trains.track.TrackModel; +import com.simibubi.create.content.trains.track.TrackTargetingBlockItem; import com.simibubi.create.foundation.block.CopperBlockSet; import com.simibubi.create.foundation.block.DyedBlockList; import com.simibubi.create.foundation.block.ItemUseOverrides; +import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.BlockStateGen; import com.simibubi.create.foundation.data.BuilderTransformers; import com.simibubi.create.foundation.data.CreateRegistrate; +import com.simibubi.create.foundation.data.MetalBarsGen; import com.simibubi.create.foundation.data.ModelGen; import com.simibubi.create.foundation.data.SharedProperties; -import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.item.ItemDescription; import com.simibubi.create.foundation.item.UncontainableBlockItem; import com.simibubi.create.foundation.utility.ColorHandlers; import com.simibubi.create.foundation.utility.DyeHelper; @@ -242,8 +273,10 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.Registry; +import net.minecraft.data.loot.BlockLoot; import net.minecraft.data.recipes.ShapelessRecipeBuilder; import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; import net.minecraft.world.item.DyeColor; @@ -251,6 +284,7 @@ import net.minecraft.world.item.Rarity; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.IronBarsBlock; import net.minecraft.world.level.block.RotatedPillarBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockBehaviour; @@ -272,18 +306,16 @@ import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.client.model.generators.ModelFile; import net.minecraftforge.common.Tags; +import net.minecraftforge.common.util.ForgeSoundType; public class AllBlocks { - private static final CreateRegistrate REGISTRATE = Create.registrate() - .creativeModeTab(() -> Create.BASE_CREATIVE_TAB); + static { + REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.BASE_CREATIVE_TAB); + } // Schematics - static { - REGISTRATE.startSection(SCHEMATICS); - } - public static final BlockEntry SCHEMATICANNON = REGISTRATE.block("schematicannon", SchematicannonBlock::new) .initialProperties(() -> Blocks.DISPENSER) @@ -317,10 +349,6 @@ public class AllBlocks { // Kinetics - static { - REGISTRATE.startSection(AllSections.KINETICS); - } - public static final BlockEntry SHAFT = REGISTRATE.block("shaft", ShaftBlock::new) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.METAL)) @@ -357,23 +385,26 @@ public class AllBlocks { .register(); public static final BlockEntry ANDESITE_ENCASED_SHAFT = - REGISTRATE.block("andesite_encased_shaft", EncasedShaftBlock::andesite) + REGISTRATE.block("andesite_encased_shaft", p -> new EncasedShaftBlock(p, AllBlocks.ANDESITE_CASING::get)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.encasedShaft("andesite", () -> AllSpriteShifts.ANDESITE_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.SHAFT)) .transform(axeOrPickaxe()) .register(); public static final BlockEntry BRASS_ENCASED_SHAFT = - REGISTRATE.block("brass_encased_shaft", EncasedShaftBlock::brass) + REGISTRATE.block("brass_encased_shaft", p -> new EncasedShaftBlock(p, AllBlocks.BRASS_CASING::get)) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) .transform(BuilderTransformers.encasedShaft("brass", () -> AllSpriteShifts.BRASS_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.SHAFT)) .transform(axeOrPickaxe()) .register(); public static final BlockEntry ANDESITE_ENCASED_COGWHEEL = REGISTRATE - .block("andesite_encased_cogwheel", p -> EncasedCogwheelBlock.andesite(false, p)) + .block("andesite_encased_cogwheel", p -> new EncasedCogwheelBlock(p, false, AllBlocks.ANDESITE_CASING::get)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.encasedCogwheel("andesite", () -> AllSpriteShifts.ANDESITE_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.COGWHEEL)) .onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCogCTBehaviour(AllSpriteShifts.ANDESITE_CASING, Couple.create(AllSpriteShifts.ANDESITE_ENCASED_COGWHEEL_SIDE, AllSpriteShifts.ANDESITE_ENCASED_COGWHEEL_OTHERSIDE)))) @@ -381,28 +412,32 @@ public class AllBlocks { .register(); public static final BlockEntry BRASS_ENCASED_COGWHEEL = - REGISTRATE.block("brass_encased_cogwheel", p -> EncasedCogwheelBlock.brass(false, p)) + REGISTRATE.block("brass_encased_cogwheel", p -> new EncasedCogwheelBlock(p, false, AllBlocks.BRASS_CASING::get)) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) .transform(BuilderTransformers.encasedCogwheel("brass", () -> AllSpriteShifts.BRASS_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.COGWHEEL)) .onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCogCTBehaviour(AllSpriteShifts.BRASS_CASING, Couple.create(AllSpriteShifts.BRASS_ENCASED_COGWHEEL_SIDE, AllSpriteShifts.BRASS_ENCASED_COGWHEEL_OTHERSIDE)))) .transform(axeOrPickaxe()) .register(); - public static final BlockEntry ANDESITE_ENCASED_LARGE_COGWHEEL = - REGISTRATE.block("andesite_encased_large_cogwheel", p -> EncasedCogwheelBlock.andesite(true, p)) - .properties(p -> p.color(MaterialColor.PODZOL)) - .transform(BuilderTransformers.encasedLargeCogwheel("andesite", () -> AllSpriteShifts.ANDESITE_CASING)) - .transform(axeOrPickaxe()) - .register(); + public static final BlockEntry ANDESITE_ENCASED_LARGE_COGWHEEL = REGISTRATE + .block("andesite_encased_large_cogwheel", + p -> new EncasedCogwheelBlock(p, true, AllBlocks.ANDESITE_CASING::get)) + .properties(p -> p.color(MaterialColor.PODZOL)) + .transform(BuilderTransformers.encasedLargeCogwheel("andesite", () -> AllSpriteShifts.ANDESITE_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.LARGE_COGWHEEL)) + .transform(axeOrPickaxe()) + .register(); - public static final BlockEntry BRASS_ENCASED_LARGE_COGWHEEL = - REGISTRATE.block("brass_encased_large_cogwheel", p -> EncasedCogwheelBlock.brass(true, p)) - .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) - .transform(BuilderTransformers.encasedLargeCogwheel("brass", () -> AllSpriteShifts.BRASS_CASING)) - .transform(axeOrPickaxe()) - .register(); + public static final BlockEntry BRASS_ENCASED_LARGE_COGWHEEL = REGISTRATE + .block("brass_encased_large_cogwheel", p -> new EncasedCogwheelBlock(p, true, AllBlocks.BRASS_CASING::get)) + .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) + .transform(BuilderTransformers.encasedLargeCogwheel("brass", () -> AllSpriteShifts.BRASS_CASING)) + .transform(EncasingRegistry.addVariantTo(AllBlocks.LARGE_COGWHEEL)) + .transform(axeOrPickaxe()) + .register(); public static final BlockEntry GEARBOX = REGISTRATE.block("gearbox", GearboxBlock::new) .initialProperties(SharedProperties::stone) @@ -422,6 +457,7 @@ public class AllBlocks { .initialProperties(SharedProperties::stone) .properties(BlockBehaviour.Properties::noOcclusion) .properties(p -> p.color(MaterialColor.PODZOL)) + .addLayer(() -> RenderType::cutoutMipped) .transform(BlockStressDefaults.setNoImpact()) .transform(axeOrPickaxe()) .blockstate((c, p) -> BlockStateGen.axisBlock(c, p, AssetLookup.forPowered(c, p))) @@ -433,6 +469,7 @@ public class AllBlocks { .initialProperties(SharedProperties::stone) .properties(BlockBehaviour.Properties::noOcclusion) .properties(p -> p.color(MaterialColor.PODZOL)) + .addLayer(() -> RenderType::cutoutMipped) .transform(BlockStressDefaults.setNoImpact()) .transform(axeOrPickaxe()) .blockstate((c, p) -> BlockStateGen.axisBlock(c, p, AssetLookup.forPowered(c, p))) @@ -440,28 +477,28 @@ public class AllBlocks { .transform(customItemModel()) .register(); - public static final BlockEntry ENCASED_CHAIN_DRIVE = - REGISTRATE.block("encased_chain_drive", EncasedBeltBlock::new) + public static final BlockEntry ENCASED_CHAIN_DRIVE = + REGISTRATE.block("encased_chain_drive", ChainDriveBlock::new) .initialProperties(SharedProperties::stone) .properties(BlockBehaviour.Properties::noOcclusion) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BlockStressDefaults.setNoImpact()) .transform(axeOrPickaxe()) - .blockstate((c, p) -> new EncasedBeltGenerator((state, suffix) -> p.models() + .blockstate((c, p) -> new ChainDriveGenerator((state, suffix) -> p.models() .getExistingFile(p.modLoc("block/" + c.getName() + "/" + suffix))).generate(c, p)) .item() .transform(customItemModel()) .register(); - public static final BlockEntry ADJUSTABLE_CHAIN_GEARSHIFT = - REGISTRATE.block("adjustable_chain_gearshift", AdjustablePulleyBlock::new) + public static final BlockEntry ADJUSTABLE_CHAIN_GEARSHIFT = + REGISTRATE.block("adjustable_chain_gearshift", ChainGearshiftBlock::new) .initialProperties(SharedProperties::stone) .properties(BlockBehaviour.Properties::noOcclusion) .properties(p -> p.color(MaterialColor.NETHER)) .transform(BlockStressDefaults.setNoImpact()) .transform(axeOrPickaxe()) - .blockstate((c, p) -> new EncasedBeltGenerator((state, suffix) -> { - String powered = state.getValue(AdjustablePulleyBlock.POWERED) ? "_powered" : ""; + .blockstate((c, p) -> new ChainDriveGenerator((state, suffix) -> { + String powered = state.getValue(ChainGearshiftBlock.POWERED) ? "_powered" : ""; return p.models() .withExistingParent(c.getName() + "_" + suffix + powered, p.modLoc("block/encased_chain_drive/" + suffix)) @@ -475,6 +512,7 @@ public class AllBlocks { public static final BlockEntry BELT = REGISTRATE.block("belt", BeltBlock::new) .initialProperties(SharedProperties.BELT_MATERIAL, MaterialColor.COLOR_GRAY) + .addLayer(() -> RenderType::cutoutMipped) .properties(p -> p.sound(SoundType.WOOL)) .properties(p -> p.strength(0.8F)) .properties(p -> p.color(MaterialColor.COLOR_GRAY)) @@ -504,13 +542,41 @@ public class AllBlocks { .properties(p -> p.color(MaterialColor.DIRT)) .properties(BlockBehaviour.Properties::noOcclusion) .transform(axeOrPickaxe()) - .blockstate(BlockStateGen.directionalBlockProviderIgnoresWaterlogged(false)) + .blockstate( + (c, p) -> BlockStateGen.directionalBlockIgnoresWaterlogged(c, p, s -> AssetLookup.partialBaseModel(c, p))) .addLayer(() -> RenderType::cutoutMipped) - .transform(BlockStressDefaults.setCapacity(16.0)) + .transform(BlockStressDefaults.setCapacity(32.0)) .transform(BlockStressDefaults.setGeneratorSpeed(WaterWheelBlock::getSpeedRange)) - .simpleItem() + .item() + .transform(customItemModel()) .register(); + public static final BlockEntry LARGE_WATER_WHEEL = + REGISTRATE.block("large_water_wheel", LargeWaterWheelBlock::new) + .initialProperties(SharedProperties::wooden) + .properties(p -> p.color(MaterialColor.DIRT)) + .properties(BlockBehaviour.Properties::noOcclusion) + .transform(axeOrPickaxe()) + .blockstate((c, p) -> axisBlock(c, p, + s -> s.getValue(LargeWaterWheelBlock.EXTENSION) ? AssetLookup.partialBaseModel(c, p, "extension") + : AssetLookup.partialBaseModel(c, p))) + .transform(BlockStressDefaults.setCapacity(128.0)) + .transform(BlockStressDefaults.setGeneratorSpeed(LargeWaterWheelBlock::getSpeedRange)) + .item(LargeWaterWheelBlockItem::new) + .transform(customItemModel()) + .register(); + + public static final BlockEntry WATER_WHEEL_STRUCTURAL = + REGISTRATE.block("water_wheel_structure", WaterWheelStructuralBlock::new) + .initialProperties(SharedProperties::wooden) + .blockstate((c, p) -> p.getVariantBuilder(c.get()) + .forAllStatesExcept(BlockStateGen.mapToAir(p), WaterWheelStructuralBlock.FACING)) + .properties(p -> p.color(MaterialColor.DIRT)) + .properties(BlockBehaviour.Properties::noOcclusion) + .transform(axeOrPickaxe()) + .lang("Large Water Wheel") + .register(); + public static final BlockEntry ENCASED_FAN = REGISTRATE.block("encased_fan", EncasedFanBlock::new) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.PODZOL)) @@ -570,7 +636,7 @@ public class AllBlocks { .transform(axeOrPickaxe()) .transform(BuilderTransformers.cuckooClock()) .lang("Cuckoo Clock") - .onRegisterAfter(Registry.ITEM_REGISTRY, c -> TooltipHelper.referTo(c, CUCKOO_CLOCK)) + .onRegisterAfter(Registry.ITEM_REGISTRY, c -> ItemDescription.referKey(c, CUCKOO_CLOCK)) .register(); public static final BlockEntry MILLSTONE = REGISTRATE.block("millstone", MillstoneBlock::new) @@ -589,10 +655,11 @@ public class AllBlocks { .initialProperties(SharedProperties::stone) .properties(BlockBehaviour.Properties::noOcclusion) .transform(pickaxeOnly()) - .blockstate(BlockStateGen.axisBlockProvider(false)) + .blockstate((c, p) -> BlockStateGen.axisBlock(c, p, s -> AssetLookup.partialBaseModel(c, p))) .addLayer(() -> RenderType::cutoutMipped) .transform(BlockStressDefaults.setImpact(8.0)) - .simpleItem() + .item() + .transform(customItemModel()) .register(); public static final BlockEntry CRUSHING_WHEEL_CONTROLLER = @@ -603,10 +670,7 @@ public class AllBlocks { .noDrops() .air()) .blockstate((c, p) -> p.getVariantBuilder(c.get()) - .forAllStatesExcept(state -> ConfiguredModel.builder() - .modelFile(p.models() - .getExistingFile(p.mcLoc("block/air"))) - .build(), CrushingWheelControllerBlock.FACING)) + .forAllStatesExcept(BlockStateGen.mapToAir(p), CrushingWheelControllerBlock.FACING)) .register(); public static final BlockEntry MECHANICAL_PRESS = @@ -640,6 +704,7 @@ public class AllBlocks { .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) .transform(pickaxeOnly()) .blockstate(new BasinGenerator()::generate) + .addLayer(() -> RenderType::cutoutMipped) .onRegister(movementBehaviour(new BasinMovementBehaviour())) .item() .transform(customItemModel("_", "block")) @@ -658,7 +723,7 @@ public class AllBlocks { .onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour())) .onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour())) .item(BlazeBurnerBlockItem::withBlaze) - .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) + .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .build() .register(); @@ -705,6 +770,7 @@ public class AllBlocks { .register(); public static final BlockEntry CHUTE = REGISTRATE.block("chute", ChuteBlock::new) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.COLOR_GRAY)) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) @@ -716,9 +782,12 @@ public class AllBlocks { .register(); public static final BlockEntry SMART_CHUTE = REGISTRATE.block("smart_chute", SmartChuteBlock::new) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.COLOR_GRAY)) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) + .properties(p -> p.noOcclusion()) + .properties(p -> p.isRedstoneConductor((level, pos, state) -> false)) .transform(pickaxeOnly()) .blockstate((c, p) -> BlockStateGen.simpleBlock(c, p, AssetLookup.forPowered(c, p))) .item() @@ -763,49 +832,6 @@ public class AllBlocks { .transform(BracketGenerator.itemModel("metal")) .register(); - public static final BlockEntry METAL_GIRDER = REGISTRATE.block("metal_girder", GirderBlock::new) - .initialProperties(SharedProperties::softMetal) - .blockstate(GirderBlockStateGenerator::blockState) - .properties(p -> p.color(MaterialColor.COLOR_GRAY)) - .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) - .transform(pickaxeOnly()) - .onRegister(CreateRegistrate.blockModel(() -> ConnectedGirderModel::new)) - .item() - .transform(customItemModel()) - .register(); - - public static final BlockEntry METAL_GIRDER_ENCASED_SHAFT = - REGISTRATE.block("metal_girder_encased_shaft", GirderEncasedShaftBlock::new) - .initialProperties(SharedProperties::softMetal) - .blockstate(GirderBlockStateGenerator::blockStateWithShaft) - .properties(p -> p.color(MaterialColor.COLOR_GRAY)) - .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) - .transform(pickaxeOnly()) - .loot((p, b) -> p.add(b, RegistrateBlockLootTables.createSingleItemTable(METAL_GIRDER.get()) - .withPool(RegistrateBlockLootTables.applyExplosionCondition(SHAFT.get(), LootPool.lootPool() - .setRolls(ConstantValue.exactly(1.0F)) - .add(LootItem.lootTableItem(SHAFT.get())))))) - .onRegister(CreateRegistrate.blockModel(() -> ConnectedGirderModel::new)) - .register(); - - public static final BlockEntry ANDESITE_LADDER = - REGISTRATE.block("andesite_ladder", MetalLadderBlock::new) - .transform( - BuilderTransformers.ladder("andesite", () -> DataIngredient.items(AllItems.ANDESITE_ALLOY.get()))) - .register(); - - public static final BlockEntry BRASS_LADDER = - REGISTRATE.block("brass_ladder", MetalLadderBlock::new) - .transform( - BuilderTransformers.ladder("brass", () -> DataIngredient.tag(AllTags.forgeItemTag("plates/brass")))) - .register(); - - public static final BlockEntry COPPER_LADDER = - REGISTRATE.block("copper_ladder", MetalLadderBlock::new) - .transform( - BuilderTransformers.ladder("copper", () -> DataIngredient.tag(AllTags.forgeItemTag("plates/copper")))) - .register(); - // Fluids public static final BlockEntry FLUID_PIPE = REGISTRATE.block("fluid_pipe", FluidPipeBlock::new) @@ -818,7 +844,7 @@ public class AllBlocks { .register(); public static final BlockEntry ENCASED_FLUID_PIPE = - REGISTRATE.block("encased_fluid_pipe", EncasedPipeBlock::new) + REGISTRATE.block("encased_fluid_pipe", p -> new EncasedPipeBlock(p, AllBlocks.COPPER_CASING::get)) .initialProperties(SharedProperties::copperMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_LIGHT_GRAY)) .properties(BlockBehaviour.Properties::noOcclusion) @@ -829,6 +855,7 @@ public class AllBlocks { (s, f) -> !s.getValue(EncasedPipeBlock.FACING_TO_PROPERTY_MAP.get(f))))) .onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new)) .loot((p, b) -> p.dropOther(b, FLUID_PIPE.get())) + .transform(EncasingRegistry.addVariantTo(AllBlocks.FLUID_PIPE)) .register(); public static final BlockEntry GLASS_FLUID_PIPE = @@ -890,6 +917,7 @@ public class AllBlocks { REGISTRATE.block("copper_valve_handle", ValveHandleBlock::copper) .transform(pickaxeOnly()) .transform(BuilderTransformers.valveHandle(null)) + .transform(BlockStressDefaults.setCapacity(8.0)) .register(); public static final DyedBlockList DYED_VALVE_HANDLES = new DyedBlockList<>(colour -> { @@ -916,7 +944,7 @@ public class AllBlocks { .onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status")) .addLayer(() -> RenderType::cutoutMipped) .item(FluidTankItem::new) - .model(AssetLookup.customBlockItemModel("_", "block_single_window")) + .model(AssetLookup.customBlockItemModel("_", "block_single_window")) .build() .register(); @@ -976,6 +1004,7 @@ public class AllBlocks { .blockstate((c, p) -> p.directionalBlock(c.get(), AssetLookup.partialBaseModel(c, p))) .onRegister(movementBehaviour(new PortableStorageInterfaceMovement())) .item() + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); @@ -1096,7 +1125,7 @@ public class AllBlocks { REGISTRATE.block("windmill_bearing", WindmillBearingBlock::new) .transform(axeOrPickaxe()) .properties(p -> p.color(MaterialColor.PODZOL)) - .transform(BuilderTransformers.bearing("windmill", "gearbox", true)) + .transform(BuilderTransformers.bearing("windmill", "gearbox")) .transform(BlockStressDefaults.setCapacity(512.0)) .transform(BlockStressDefaults.setGeneratorSpeed(WindmillBearingBlock::getSpeedRange)) .tag(AllBlockTags.SAFE_NBT.tag) @@ -1106,7 +1135,7 @@ public class AllBlocks { REGISTRATE.block("mechanical_bearing", MechanicalBearingBlock::new) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(axeOrPickaxe()) - .transform(BuilderTransformers.bearing("mechanical", "gearbox", false)) + .transform(BuilderTransformers.bearing("mechanical", "gearbox")) .transform(BlockStressDefaults.setImpact(4.0)) .tag(AllBlockTags.SAFE_NBT.tag) .onRegister(movementBehaviour(new StabilizedBearingMovementBehaviour())) @@ -1116,7 +1145,7 @@ public class AllBlocks { REGISTRATE.block("clockwork_bearing", ClockworkBearingBlock::new) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) .transform(axeOrPickaxe()) - .transform(BuilderTransformers.bearing("clockwork", "brass_gearbox", false)) + .transform(BuilderTransformers.bearing("clockwork", "brass_gearbox")) .transform(BlockStressDefaults.setImpact(4.0)) .tag(AllBlockTags.SAFE_NBT.tag) .register(); @@ -1135,6 +1164,7 @@ public class AllBlocks { public static final BlockEntry ROPE = REGISTRATE.block("rope", PulleyBlock.RopeBlock::new) .initialProperties(SharedProperties.BELT_MATERIAL, MaterialColor.COLOR_BROWN) .tag(AllBlockTags.BRITTLE.tag) + .tag(BlockTags.CLIMBABLE) .properties(p -> p.sound(SoundType.WOOL)) .blockstate((c, p) -> p.simpleBlock(c.get(), p.models() .getExistingFile(p.modLoc("block/rope_pulley/" + c.getName())))) @@ -1144,10 +1174,22 @@ public class AllBlocks { REGISTRATE.block("pulley_magnet", PulleyBlock.MagnetBlock::new) .initialProperties(SharedProperties::stone) .tag(AllBlockTags.BRITTLE.tag) + .tag(BlockTags.CLIMBABLE) .blockstate((c, p) -> p.simpleBlock(c.get(), p.models() .getExistingFile(p.modLoc("block/rope_pulley/" + c.getName())))) .register(); + public static final BlockEntry ELEVATOR_PULLEY = + REGISTRATE.block("elevator_pulley", ElevatorPulleyBlock::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) + .transform(axeOrPickaxe()) + .blockstate(BlockStateGen.horizontalBlockProvider(true)) + .transform(BlockStressDefaults.setImpact(4.0)) + .item() + .transform(customItemModel()) + .register(); + public static final BlockEntry CART_ASSEMBLER = REGISTRATE.block("cart_assembler", CartAssemblerBlock::new) .initialProperties(SharedProperties::stone) @@ -1229,6 +1271,19 @@ public class AllBlocks { .transform(customItemModel()) .register(); + public static final BlockEntry CONTRAPTION_CONTROLS = + REGISTRATE.block("contraption_controls", ContraptionControlsBlock::new) + .initialProperties(SharedProperties::stone) + .properties(p -> p.color(MaterialColor.PODZOL)) + .addLayer(() -> RenderType::cutoutMipped) + .transform(axeOrPickaxe()) + .blockstate((c, p) -> p.horizontalBlock(c.get(), s -> AssetLookup.partialBaseModel(c, p))) + .onRegister(movementBehaviour(new ContraptionControlsMovement())) + .onRegister(interactionBehaviour(new ContraptionControlsMovingInteraction())) + .item() + .transform(customItemModel()) + .register(); + public static final BlockEntry MECHANICAL_DRILL = REGISTRATE.block("mechanical_drill", DrillBlock::new) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.PODZOL)) @@ -1237,11 +1292,13 @@ public class AllBlocks { .transform(BlockStressDefaults.setImpact(4.0)) .onRegister(movementBehaviour(new DrillMovementBehaviour())) .item() + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); public static final BlockEntry MECHANICAL_SAW = REGISTRATE.block("mechanical_saw", SawBlock::new) .initialProperties(SharedProperties::stone) + .addLayer(() -> RenderType::cutoutMipped) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(axeOrPickaxe()) .blockstate(new SawGenerator()::generate) @@ -1249,6 +1306,7 @@ public class AllBlocks { .onRegister(movementBehaviour(new SawMovementBehaviour())) .addLayer(() -> RenderType::cutoutMipped) .item() + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); @@ -1261,6 +1319,7 @@ public class AllBlocks { .onRegister(movementBehaviour(new DeployerMovementBehaviour())) .onRegister(interactionBehaviour(new DeployerMovingInteraction())) .item(AssemblyOperatorBlockItem::new) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); @@ -1272,6 +1331,7 @@ public class AllBlocks { .blockstate((c, p) -> p.directionalBlock(c.get(), AssetLookup.partialBaseModel(c, p))) .onRegister(movementBehaviour(new PortableStorageInterfaceMovement())) .item() + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); @@ -1282,6 +1342,25 @@ public class AllBlocks { .transform(axeOrPickaxe()) .onRegister(movementBehaviour(new ContactMovementBehaviour())) .blockstate((c, p) -> p.directionalBlock(c.get(), AssetLookup.forPowered(c, p))) + .item(RedstoneContactItem::new) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) + .transform(customItemModel("_", "block")) + .register(); + + public static final BlockEntry ELEVATOR_CONTACT = + REGISTRATE.block("elevator_contact", ElevatorContactBlock::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW)) + .properties(p -> p.lightLevel(ElevatorContactBlock::getLight)) + .transform(axeOrPickaxe()) + .blockstate((c, p) -> p.directionalBlock(c.get(), state -> { + Boolean calling = state.getValue(ElevatorContactBlock.CALLING); + Boolean powering = state.getValue(ElevatorContactBlock.POWERING); + return powering ? AssetLookup.partialBaseModel(c, p, "powered") + : calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p); + })) + .loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get())) + .onRegister(assignDataBehaviour(new CurrentFloorDisplaySource(), "current_floor")) .item() .transform(customItemModel("_", "block")) .register(); @@ -1295,6 +1374,7 @@ public class AllBlocks { .blockstate(BlockStateGen.horizontalBlockProvider(true)) .addLayer(() -> RenderType::cutoutMipped) .item() + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .transform(customItemModel()) .register(); @@ -1305,45 +1385,24 @@ public class AllBlocks { .transform(axeOrPickaxe()) .onRegister(movementBehaviour(new PloughMovementBehaviour())) .blockstate(BlockStateGen.horizontalBlockProvider(false)) - .simpleItem() - .register(); - - public static final DyedBlockList SEATS = new DyedBlockList<>(colour -> { - String colourName = colour.getSerializedName(); - SeatMovementBehaviour movementBehaviour = new SeatMovementBehaviour(); - SeatInteractionBehaviour interactionBehaviour = new SeatInteractionBehaviour(); - return REGISTRATE.block(colourName + "_seat", p -> new SeatBlock(p, colour, colour == DyeColor.RED)) - .initialProperties(SharedProperties::wooden) - .properties(p -> p.color(colour.getMaterialColor())) - .transform(axeOnly()) - .onRegister(movementBehaviour(movementBehaviour)) - .onRegister(interactionBehaviour(interactionBehaviour)) - .onRegister(assignDataBehaviour(new EntityNameDisplaySource(), "entity_name")) - .blockstate((c, p) -> { - p.simpleBlock(c.get(), p.models() - .withExistingParent(colourName + "_seat", p.modLoc("block/seat")) - .texture("1", p.modLoc("block/seat/top_" + colourName)) - .texture("2", p.modLoc("block/seat/side_" + colourName))); - }) - .recipe((c, p) -> { - ShapelessRecipeBuilder.shapeless(c.get()) - .requires(DyeHelper.getWoolOfDye(colour)) - .requires(ItemTags.WOODEN_SLABS) - .unlockedBy("has_wool", RegistrateRecipeProvider.has(ItemTags.WOOL)) - .save(p, Create.asResource("crafting/kinetics/" + c.getName())); - ShapelessRecipeBuilder.shapeless(c.get()) - .requires(colour.getTag()) - .requires(AllItemTags.SEATS.tag) - .unlockedBy("has_seat", RegistrateRecipeProvider.has(AllItemTags.SEATS.tag)) - .save(p, Create.asResource("crafting/kinetics/" + c.getName() + "_from_other_seat")); - }) - .onRegisterAfter(Registry.ITEM_REGISTRY, v -> TooltipHelper.referTo(v, "block.create.brown_seat")) - .tag(AllBlockTags.SEATS.tag) .item() - .tag(AllItemTags.SEATS.tag) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .build() .register(); - }); + + public static final BlockEntry MECHANICAL_ROLLER = + REGISTRATE.block("mechanical_roller", RollerBlock::new) + .initialProperties(SharedProperties::stone) + .properties(p -> p.color(MaterialColor.COLOR_GRAY) + .noOcclusion()) + .transform(axeOrPickaxe()) + .onRegister(movementBehaviour(new RollerMovementBehaviour())) + .blockstate(BlockStateGen.horizontalBlockProvider(true)) + .addLayer(() -> RenderType::cutoutMipped) + .item(RollerBlockItem::new) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) + .transform(customItemModel()) + .register(); public static final BlockEntry SAIL_FRAME = REGISTRATE.block("sail_frame", p -> SailBlock.frame(p)) .initialProperties(SharedProperties::wooden) @@ -1352,6 +1411,7 @@ public class AllBlocks { .noOcclusion()) .transform(axeOnly()) .blockstate(BlockStateGen.directionalBlockProvider(false)) + .lang("Windmill Sail Frame") .tag(AllBlockTags.WINDMILL_SAILS.tag) .tag(AllBlockTags.FAN_TRANSPARENT.tag) .simpleItem() @@ -1365,6 +1425,7 @@ public class AllBlocks { .noOcclusion()) .transform(axeOnly()) .blockstate(BlockStateGen.directionalBlockProvider(false)) + .lang("Windmill Sail") .tag(AllBlockTags.WINDMILL_SAILS.tag) .item(BlankSailBlockItem::new) .build() @@ -1472,10 +1533,6 @@ public class AllBlocks { // Logistics - static { - REGISTRATE.startSection(AllSections.LOGISTICS); - } - public static final BlockEntry MECHANICAL_ARM = REGISTRATE.block("mechanical_arm", ArmBlock::new) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW)) @@ -1490,7 +1547,7 @@ public class AllBlocks { .transform(customItemModel()) .register(); - public static final BlockEntry TRACK = REGISTRATE.block("track", TrackBlock::new) + public static final BlockEntry TRACK = REGISTRATE.block("track", TrackMaterial.ANDESITE::createBlock) .initialProperties(Material.STONE) .properties(p -> p.color(MaterialColor.METAL) .strength(0.8F) @@ -1498,8 +1555,11 @@ public class AllBlocks { .noOcclusion()) .addLayer(() -> RenderType::cutoutMipped) .transform(pickaxeOnly()) + .onRegister(CreateRegistrate.blockModel(() -> TrackModel::new)) .blockstate(new TrackBlockStateGenerator()::generate) .tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag) + .tag(AllBlockTags.TRACKS.tag) + .tag(AllBlockTags.GIRDABLE_TRACKS.tag) .lang("Train Track") .item(TrackBlockItem::new) .model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName()))) @@ -1568,18 +1628,18 @@ public class AllBlocks { .register(); public static final BlockEntry SMALL_BOGEY = - REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, false)) + REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, BogeySizes.SMALL)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.bogey()) .register(); public static final BlockEntry LARGE_BOGEY = - REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, true)) + REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, BogeySizes.LARGE)) .properties(p -> p.color(MaterialColor.PODZOL)) .transform(BuilderTransformers.bogey()) .register(); - public static final BlockEntry CONTROLS = REGISTRATE.block("controls", ControlsBlock::new) + public static final BlockEntry TRAIN_CONTROLS = REGISTRATE.block("controls", ControlsBlock::new) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) @@ -1595,40 +1655,6 @@ public class AllBlocks { .transform(customItemModel()) .register(); - public static final BlockEntry TRAIN_DOOR = REGISTRATE.block("train_door", SlidingDoorBlock::new) - .transform(BuilderTransformers.slidingDoor("train")) - .properties(p -> p.color(MaterialColor.TERRACOTTA_CYAN) - .sound(SoundType.NETHERITE_BLOCK) - .noOcclusion()) - .register(); - - public static final BlockEntry TRAIN_TRAPDOOR = - REGISTRATE.block("train_trapdoor", TrainTrapdoorBlock::new) - .initialProperties(SharedProperties::softMetal) - .properties(p -> p.color(MaterialColor.TERRACOTTA_CYAN) - .sound(SoundType.NETHERITE_BLOCK)) - .transform(BuilderTransformers.trapdoor(true)) - .register(); - - public static final BlockEntry FRAMED_GLASS_DOOR = - REGISTRATE.block("framed_glass_door", SlidingDoorBlock::new) - .transform(BuilderTransformers.slidingDoor("glass")) - .properties(p -> p.color(MaterialColor.NONE) - .sound(SoundType.GLASS) - .noOcclusion()) - .register(); - - public static final BlockEntry FRAMED_GLASS_TRAPDOOR = - REGISTRATE.block("framed_glass_trapdoor", TrainTrapdoorBlock::new) - .initialProperties(SharedProperties::softMetal) - .transform(BuilderTransformers.trapdoor(false)) - .properties(p -> p.color(MaterialColor.NONE) - .sound(SoundType.GLASS) - .noOcclusion()) - .onRegister(connectedTextures(TrapdoorCTBehaviour::new)) - .addLayer(() -> RenderType::cutoutMipped) - .register(); - public static final BlockEntry ITEM_VAULT = REGISTRATE.block("item_vault", ItemVaultBlock::new) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_BLUE)) @@ -1647,6 +1673,7 @@ public class AllBlocks { public static final BlockEntry ANDESITE_FUNNEL = REGISTRATE.block("andesite_funnel", AndesiteFunnelBlock::new) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.STONE)) .transform(pickaxeOnly()) @@ -1654,22 +1681,25 @@ public class AllBlocks { .onRegister(movementBehaviour(FunnelMovementBehaviour.andesite())) .blockstate(new FunnelGenerator("andesite", false)::generate) .item(FunnelItem::new) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .model(FunnelGenerator.itemModel("andesite")) .build() .register(); public static final BlockEntry ANDESITE_BELT_FUNNEL = REGISTRATE.block("andesite_belt_funnel", p -> new BeltFunnelBlock(AllBlocks.ANDESITE_FUNNEL, p)) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.STONE)) .transform(pickaxeOnly()) .tag(AllBlockTags.SAFE_NBT.tag) - .blockstate(new BeltFunnelGenerator("andesite", new ResourceLocation("block/polished_andesite"))::generate) + .blockstate(new BeltFunnelGenerator("andesite")::generate) .loot((p, b) -> p.dropOther(b, ANDESITE_FUNNEL.get())) .register(); public static final BlockEntry BRASS_FUNNEL = REGISTRATE.block("brass_funnel", BrassFunnelBlock::new) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW)) .transform(pickaxeOnly()) @@ -1677,17 +1707,19 @@ public class AllBlocks { .onRegister(movementBehaviour(FunnelMovementBehaviour.brass())) .blockstate(new FunnelGenerator("brass", true)::generate) .item(FunnelItem::new) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .model(FunnelGenerator.itemModel("brass")) .build() .register(); public static final BlockEntry BRASS_BELT_FUNNEL = REGISTRATE.block("brass_belt_funnel", p -> new BeltFunnelBlock(AllBlocks.BRASS_FUNNEL, p)) + .addLayer(() -> RenderType::cutoutMipped) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW)) .transform(pickaxeOnly()) .tag(AllBlockTags.SAFE_NBT.tag) - .blockstate(new BeltFunnelGenerator("brass", Create.asResource("block/brass_block"))::generate) + .blockstate(new BeltFunnelGenerator("brass")::generate) .loot((p, b) -> p.dropOther(b, BRASS_FUNNEL.get())) .register(); @@ -1708,36 +1740,39 @@ public class AllBlocks { .onRegister(connectedTextures(BrassTunnelCTBehaviour::new)) .register(); - public static final BlockEntry CONTENT_OBSERVER = - REGISTRATE.block("content_observer", ContentObserverBlock::new) + public static final BlockEntry SMART_OBSERVER = + REGISTRATE.block("content_observer", SmartObserverBlock::new) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) + .properties(p -> p.noOcclusion()) .transform(axeOrPickaxe()) - .blockstate((c, p) -> p.horizontalBlock(c.get(), AssetLookup.forPowered(c, p))) + .blockstate(new SmartObserverGenerator()::generate) .onRegister(assignDataBehaviour(new ItemCountDisplaySource(), "count_items")) .onRegister(assignDataBehaviour(new ItemListDisplaySource(), "list_items")) .onRegister(assignDataBehaviour(new FluidAmountDisplaySource(), "count_fluids")) .onRegister(assignDataBehaviour(new FluidListDisplaySource(), "list_fluids")) + .lang("Smart Observer") .item() .transform(customItemModel("_", "block")) .register(); - public static final BlockEntry STOCKPILE_SWITCH = - REGISTRATE.block("stockpile_switch", StockpileSwitchBlock::new) + public static final BlockEntry THRESHOLD_SWITCH = + REGISTRATE.block("stockpile_switch", ThresholdSwitchBlock::new) .initialProperties(SharedProperties::stone) .properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN)) + .properties(p -> p.noOcclusion()) .transform(axeOrPickaxe()) - .blockstate((c, p) -> p.horizontalBlock(c.get(), - AssetLookup.withIndicator(c, p, $ -> AssetLookup.standardModel(c, p), StockpileSwitchBlock.INDICATOR))) + .blockstate(new ThresholdSwitchGenerator()::generate) .onRegister(assignDataBehaviour(new FillLevelDisplaySource(), "fill_level")) - .simpleItem() + .lang("Threshold Switch") + .item() + .transform(customItemModel("threshold_switch", "block_wall")) .register(); public static final BlockEntry CREATIVE_CRATE = REGISTRATE.block("creative_crate", CreativeCrateBlock::new) .transform(BuilderTransformers.crate("creative")) .properties(p -> p.color(MaterialColor.COLOR_PURPLE)) - .tag(AllBlockTags.SAFE_NBT.tag) .register(); public static final BlockEntry DISPLAY_LINK = @@ -1833,7 +1868,6 @@ public class AllBlocks { public static final BlockEntry PLACARD = REGISTRATE.block("placard", PlacardBlock::new) .initialProperties(SharedProperties::copperMetal) .transform(pickaxeOnly()) - .tag(AllBlockTags.SAFE_NBT.tag) .blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.standardModel(c, p))) .simpleItem() .register(); @@ -1888,30 +1922,16 @@ public class AllBlocks { // Curiosities - static { - REGISTRATE.startSection(AllSections.CURIOSITIES); - } - - public static final BlockEntry COPPER_BACKTANK = - REGISTRATE.block("copper_backtank", CopperBacktankBlock::new) + public static final BlockEntry COPPER_BACKTANK = + REGISTRATE.block("copper_backtank", BacktankBlock::new) .initialProperties(SharedProperties::copperMetal) - .blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) - .transform(pickaxeOnly()) - .addLayer(() -> RenderType::cutoutMipped) - .transform(BlockStressDefaults.setImpact(4.0)) - .loot((lt, block) -> { - Builder builder = LootTable.lootTable(); - LootItemCondition.Builder survivesExplosion = ExplosionCondition.survivesExplosion(); - lt.add(block, builder.withPool(LootPool.lootPool() - .when(survivesExplosion) - .setRolls(ConstantValue.exactly(1)) - .add(LootItem.lootTableItem(AllItems.COPPER_BACKTANK.get()) - .apply(CopyNameFunction.copyName(CopyNameFunction.NameSource.BLOCK_ENTITY)) - .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY) - .copy("Air", "Air")) - .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY) - .copy("Enchantments", "Enchantments"))))); - }) + .transform(BuilderTransformers.backtank(AllItems.COPPER_BACKTANK::get)) + .register(); + + public static final BlockEntry NETHERITE_BACKTANK = + REGISTRATE.block("netherite_backtank", BacktankBlock::new) + .initialProperties(SharedProperties::netheriteMetal) + .transform(BuilderTransformers.backtank(AllItems.NETHERITE_BACKTANK::get)) .register(); public static final BlockEntry PECULIAR_BELL = @@ -1953,7 +1973,7 @@ public class AllBlocks { .withExistingParent(colourName + "_toolbox", p.modLoc("block/toolbox/block")) .texture("0", p.modLoc("block/toolbox/" + colourName))); }) - .onRegisterAfter(Registry.ITEM_REGISTRY, v -> TooltipHelper.referTo(v, "block.create.toolbox")) + .onRegisterAfter(Registry.ITEM_REGISTRY, v -> ItemDescription.useKey(v, "block.create.toolbox")) .tag(AllBlockTags.TOOLBOXES.tag) .item(UncontainableBlockItem::new) .model((c, p) -> p.withExistingParent(colourName + "_toolbox", p.modLoc("block/toolbox/item")) @@ -1963,12 +1983,225 @@ public class AllBlocks { .register(); }); + public static final BlockEntry CLIPBOARD = REGISTRATE.block("clipboard", ClipboardBlock::new) + .initialProperties(SharedProperties::wooden) + .transform(axeOrPickaxe()) + .tag(AllBlockTags.SAFE_NBT.tag) + .blockstate((c, p) -> p.horizontalFaceBlock(c.get(), + s -> AssetLookup.partialBaseModel(c, p, s.getValue(ClipboardBlock.WRITTEN) ? "written" : "empty"))) + .loot((lt, b) -> lt.add(b, BlockLoot.noDrop())) + .item(ClipboardBlockItem::new) + .onRegister(ClipboardBlockItem::registerModelOverrides) + .model((c, p) -> ClipboardOverrides.addOverrideModels(c, p)) + .build() + .register(); + // Materials static { - REGISTRATE.startSection(AllSections.PALETTES); + REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.PALETTES_CREATIVE_TAB); } + public static final BlockEntry ANDESITE_LADDER = + REGISTRATE.block("andesite_ladder", MetalLadderBlock::new) + .transform(BuilderTransformers.ladder("andesite", () -> DataIngredient.items(AllItems.ANDESITE_ALLOY.get()), + MaterialColor.STONE)) + .register(); + + public static final BlockEntry BRASS_LADDER = + REGISTRATE.block("brass_ladder", MetalLadderBlock::new) + .transform(BuilderTransformers.ladder("brass", + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/brass")), MaterialColor.TERRACOTTA_YELLOW)) + .register(); + + public static final BlockEntry COPPER_LADDER = + REGISTRATE.block("copper_ladder", MetalLadderBlock::new) + .transform(BuilderTransformers.ladder("copper", + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), MaterialColor.COLOR_ORANGE)) + .register(); + + public static final BlockEntry ANDESITE_BARS = MetalBarsGen.createBars("andesite", true, + () -> DataIngredient.items(AllItems.ANDESITE_ALLOY.get()), MaterialColor.STONE); + public static final BlockEntry BRASS_BARS = MetalBarsGen.createBars("brass", true, + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/brass")), MaterialColor.TERRACOTTA_YELLOW); + public static final BlockEntry COPPER_BARS = MetalBarsGen.createBars("copper", true, + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), MaterialColor.COLOR_ORANGE); + + public static final BlockEntry ANDESITE_SCAFFOLD = REGISTRATE + .block("andesite_scaffolding", MetalScaffoldingBlock::new) + .transform(BuilderTransformers.scaffold("andesite", () -> DataIngredient.items(AllItems.ANDESITE_ALLOY.get()), + MaterialColor.STONE, AllSpriteShifts.ANDESITE_SCAFFOLD, AllSpriteShifts.ANDESITE_SCAFFOLD_INSIDE, + AllSpriteShifts.ANDESITE_CASING)) + .register(); + + public static final BlockEntry BRASS_SCAFFOLD = + REGISTRATE.block("brass_scaffolding", MetalScaffoldingBlock::new) + .transform(BuilderTransformers.scaffold("brass", + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/brass")), MaterialColor.TERRACOTTA_YELLOW, + AllSpriteShifts.BRASS_SCAFFOLD, AllSpriteShifts.BRASS_SCAFFOLD_INSIDE, AllSpriteShifts.BRASS_CASING)) + .register(); + + public static final BlockEntry COPPER_SCAFFOLD = + REGISTRATE.block("copper_scaffolding", MetalScaffoldingBlock::new) + .transform(BuilderTransformers.scaffold("copper", + () -> DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), MaterialColor.COLOR_ORANGE, + AllSpriteShifts.COPPER_SCAFFOLD, AllSpriteShifts.COPPER_SCAFFOLD_INSIDE, AllSpriteShifts.COPPER_CASING)) + .register(); + + public static final BlockEntry METAL_GIRDER = REGISTRATE.block("metal_girder", GirderBlock::new) + .initialProperties(SharedProperties::softMetal) + .blockstate(GirderBlockStateGenerator::blockState) + .properties(p -> p.color(MaterialColor.COLOR_GRAY)) + .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) + .transform(pickaxeOnly()) + .onRegister(CreateRegistrate.blockModel(() -> ConnectedGirderModel::new)) + .item() + .transform(customItemModel()) + .register(); + + public static final BlockEntry METAL_GIRDER_ENCASED_SHAFT = + REGISTRATE.block("metal_girder_encased_shaft", GirderEncasedShaftBlock::new) + .initialProperties(SharedProperties::softMetal) + .blockstate(GirderBlockStateGenerator::blockStateWithShaft) + .properties(p -> p.color(MaterialColor.COLOR_GRAY)) + .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) + .transform(pickaxeOnly()) + .loot((p, b) -> p.add(b, RegistrateBlockLootTables.createSingleItemTable(METAL_GIRDER.get()) + .withPool(RegistrateBlockLootTables.applyExplosionCondition(SHAFT.get(), LootPool.lootPool() + .setRolls(ConstantValue.exactly(1.0F)) + .add(LootItem.lootTableItem(SHAFT.get())))))) + .onRegister(CreateRegistrate.blockModel(() -> ConnectedGirderModel::new)) + .register(); + + public static final BlockEntry COPYCAT_BASE = REGISTRATE.block("copycat_base", Block::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.GLOW_LICHEN)) + .addLayer(() -> RenderType::cutoutMipped) + .tag(AllBlockTags.FAN_TRANSPARENT.tag) + .transform(pickaxeOnly()) + .blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.partialBaseModel(c, p))) + .register(); + + public static final BlockEntry COPYCAT_STEP = + REGISTRATE.block("copycat_step", CopycatStepBlock::new) + .transform(BuilderTransformers.copycat()) + .onRegister(CreateRegistrate.blockModel(() -> CopycatStepModel::new)) + .item() + .recipe((c, p) -> p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/zinc")), c::get, 4)) + .transform(customItemModel("copycat_base", "step")) + .register(); + + public static final BlockEntry COPYCAT_PANEL = + REGISTRATE.block("copycat_panel", CopycatPanelBlock::new) + .transform(BuilderTransformers.copycat()) + .onRegister(CreateRegistrate.blockModel(() -> CopycatPanelModel::new)) + .item() + .recipe((c, p) -> p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/zinc")), c::get, 4)) + .transform(customItemModel("copycat_base", "panel")) + .register(); + + public static final BlockEntry COPYCAT_BARS = + REGISTRATE.block("copycat_bars", WrenchableDirectionalBlock::new) + .blockstate(new SpecialCopycatPanelBlockState("bars")::generate) + .onRegister(CreateRegistrate.blockModel(() -> CopycatBarsModel::new)) + .register(); + + public static final DyedBlockList SEATS = new DyedBlockList<>(colour -> { + String colourName = colour.getSerializedName(); + SeatMovementBehaviour movementBehaviour = new SeatMovementBehaviour(); + SeatInteractionBehaviour interactionBehaviour = new SeatInteractionBehaviour(); + return REGISTRATE.block(colourName + "_seat", p -> new SeatBlock(p, colour, true)) + .initialProperties(SharedProperties::wooden) + .properties(p -> p.color(colour.getMaterialColor())) + .transform(axeOnly()) + .onRegister(movementBehaviour(movementBehaviour)) + .onRegister(interactionBehaviour(interactionBehaviour)) + .onRegister(assignDataBehaviour(new EntityNameDisplaySource(), "entity_name")) + .blockstate((c, p) -> { + p.simpleBlock(c.get(), p.models() + .withExistingParent(colourName + "_seat", p.modLoc("block/seat")) + .texture("1", p.modLoc("block/seat/top_" + colourName)) + .texture("2", p.modLoc("block/seat/side_" + colourName))); + }) + .recipe((c, p) -> { + ShapelessRecipeBuilder.shapeless(c.get()) + .requires(DyeHelper.getWoolOfDye(colour)) + .requires(ItemTags.WOODEN_SLABS) + .unlockedBy("has_wool", RegistrateRecipeProvider.has(ItemTags.WOOL)) + .save(p, Create.asResource("crafting/kinetics/" + c.getName())); + ShapelessRecipeBuilder.shapeless(c.get()) + .requires(colour.getTag()) + .requires(AllItemTags.SEATS.tag) + .unlockedBy("has_seat", RegistrateRecipeProvider.has(AllItemTags.SEATS.tag)) + .save(p, Create.asResource("crafting/kinetics/" + c.getName() + "_from_other_seat")); + }) + .onRegisterAfter(Registry.ITEM_REGISTRY, v -> ItemDescription.useKey(v, "block.create.seat")) + .tag(AllBlockTags.SEATS.tag) + .item() + .tag(AllItemTags.SEATS.tag) + .build() + .register(); + }); + + public static final BlockEntry ANDESITE_DOOR = + REGISTRATE.block("andesite_door", p -> new SlidingDoorBlock(p, true)) + .transform(BuilderTransformers.slidingDoor("andesite")) + .properties(p -> p.color(MaterialColor.STONE) + .sound(SoundType.STONE) + .noOcclusion()) + .register(); + + public static final BlockEntry BRASS_DOOR = + REGISTRATE.block("brass_door", p -> new SlidingDoorBlock(p, false)) + .transform(BuilderTransformers.slidingDoor("brass")) + .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW) + .sound(SoundType.STONE) + .noOcclusion()) + .register(); + + public static final BlockEntry COPPER_DOOR = + REGISTRATE.block("copper_door", p -> new SlidingDoorBlock(p, true)) + .transform(BuilderTransformers.slidingDoor("copper")) + .properties(p -> p.color(MaterialColor.COLOR_ORANGE) + .sound(SoundType.STONE) + .noOcclusion()) + .register(); + + public static final BlockEntry TRAIN_DOOR = + REGISTRATE.block("train_door", p -> new SlidingDoorBlock(p, false)) + .transform(BuilderTransformers.slidingDoor("train")) + .properties(p -> p.color(MaterialColor.TERRACOTTA_CYAN) + .sound(SoundType.NETHERITE_BLOCK) + .noOcclusion()) + .register(); + + public static final BlockEntry TRAIN_TRAPDOOR = + REGISTRATE.block("train_trapdoor", TrainTrapdoorBlock::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.TERRACOTTA_CYAN) + .sound(SoundType.NETHERITE_BLOCK)) + .transform(BuilderTransformers.trapdoor(true)) + .register(); + + public static final BlockEntry FRAMED_GLASS_DOOR = + REGISTRATE.block("framed_glass_door", p -> new SlidingDoorBlock(p, false)) + .transform(BuilderTransformers.slidingDoor("glass")) + .properties(p -> p.color(MaterialColor.NONE) + .sound(SoundType.GLASS) + .noOcclusion()) + .register(); + + public static final BlockEntry FRAMED_GLASS_TRAPDOOR = + REGISTRATE.block("framed_glass_trapdoor", TrainTrapdoorBlock::new) + .initialProperties(SharedProperties::softMetal) + .transform(BuilderTransformers.trapdoor(false)) + .properties(p -> p.color(MaterialColor.NONE) + .sound(SoundType.GLASS) + .noOcclusion()) + .onRegister(connectedTextures(TrapdoorCTBehaviour::new)) + .addLayer(() -> RenderType::cutoutMipped) + .register(); + public static final BlockEntry ZINC_ORE = REGISTRATE.block("zinc_ore", Block::new) .initialProperties(() -> Blocks.GOLD_ORE) .properties(p -> p.color(MaterialColor.METAL)) @@ -2016,7 +2249,7 @@ public class AllBlocks { .build() .register(); - public static final BlockEntry ZINC_BLOCK = REGISTRATE.block("zinc_block", p -> new Block(p)) + public static final BlockEntry ZINC_BLOCK = REGISTRATE.block("zinc_block", Block::new) .initialProperties(() -> Blocks.IRON_BLOCK) .properties(p -> p.color(MaterialColor.GLOW_LICHEN)) .properties(p -> p.requiresCorrectToolForDrops()) @@ -2030,12 +2263,40 @@ public class AllBlocks { .lang("Block of Zinc") .register(); + public static final BlockEntry ANDESITE_ALLOY_BLOCK = REGISTRATE.block("andesite_alloy_block", Block::new) + .initialProperties(() -> Blocks.ANDESITE) + .properties(p -> p.color(MaterialColor.STONE)) + .properties(p -> p.requiresCorrectToolForDrops()) + .transform(pickaxeOnly()) + .blockstate(simpleCubeAll("andesite_block")) + .tag(Tags.Blocks.STORAGE_BLOCKS) + .transform(tagBlockAndItem("storage_blocks/andesite_alloy")) + .tag(Tags.Items.STORAGE_BLOCKS) + .build() + .lang("Block of Andesite Alloy") + .register(); + + public static final BlockEntry INDUSTRIAL_IRON_BLOCK = REGISTRATE.block("industrial_iron_block", Block::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.COLOR_GRAY)) + .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) + .properties(p -> p.requiresCorrectToolForDrops()) + .transform(pickaxeOnly()) + .blockstate((c, p) -> p.simpleBlock(c.get(), p.models() + .cubeColumn(c.getName(), p.modLoc("block/industrial_iron_block"), + p.modLoc("block/industrial_iron_block_top")))) + .tag(AllBlockTags.WRENCH_PICKUP.tag) + .lang("Block of Industrial Iron") + .recipe((c, p) -> p.stonecutting(DataIngredient.tag(Tags.Items.INGOTS_IRON), c::get, 2)) + .simpleItem() + .register(); + public static final BlockEntry BRASS_BLOCK = REGISTRATE.block("brass_block", Block::new) .initialProperties(() -> Blocks.IRON_BLOCK) .properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW)) .properties(p -> p.requiresCorrectToolForDrops()) .transform(pickaxeOnly()) - .blockstate(simpleCubeAll("brass_storage_block")) + .blockstate(simpleCubeAll("brass_block")) .tag(BlockTags.NEEDS_IRON_TOOL) .tag(Tags.Blocks.STORAGE_BLOCKS) .tag(BlockTags.BEACON_BASE_BLOCKS) @@ -2045,6 +2306,26 @@ public class AllBlocks { .lang("Block of Brass") .register(); + public static final BlockEntry EXPERIENCE_BLOCK = + REGISTRATE.block("experience_block", ExperienceBlock::new) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.color(MaterialColor.PLANT)) + .properties(p -> p.sound(new ForgeSoundType(1, .5f, () -> SoundEvents.AMETHYST_BLOCK_BREAK, + () -> SoundEvents.AMETHYST_BLOCK_STEP, () -> SoundEvents.AMETHYST_BLOCK_PLACE, + () -> SoundEvents.AMETHYST_BLOCK_HIT, () -> SoundEvents.AMETHYST_BLOCK_FALL))) + .properties(p -> p.requiresCorrectToolForDrops()) + .properties(p -> p.lightLevel(s -> 15)) + .blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.standardModel(c, p))) + .transform(pickaxeOnly()) + .lang("Block of Experience") + .tag(Tags.Blocks.STORAGE_BLOCKS) + .tag(BlockTags.BEACON_BASE_BLOCKS) + .item() + .properties(p -> p.rarity(Rarity.UNCOMMON)) + .tag(Tags.Items.STORAGE_BLOCKS) + .build() + .register(); + public static final BlockEntry ROSE_QUARTZ_BLOCK = REGISTRATE.block("rose_quartz_block", RotatedPillarBlock::new) .initialProperties(() -> Blocks.AMETHYST_BLOCK) @@ -2082,12 +2363,12 @@ public class AllBlocks { public static final CopperBlockSet COPPER_SHINGLES = new CopperBlockSet(REGISTRATE, "copper_shingles", "copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> { - p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("plates/copper")), c::get, 2); + p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), c::get, 2); }); public static final CopperBlockSet COPPER_TILES = new CopperBlockSet(REGISTRATE, "copper_tiles", "copper_roof_top", CopperBlockSet.DEFAULT_VARIANTS, (c, p) -> { - p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("plates/copper")), c::get, 2); + p.stonecutting(DataIngredient.tag(AllTags.forgeItemTag("ingots/copper")), c::get, 2); }); // Load this class diff --git a/src/main/java/com/simibubi/create/AllBogeyStyles.java b/src/main/java/com/simibubi/create/AllBogeyStyles.java new file mode 100644 index 0000000000..791eeb76cb --- /dev/null +++ b/src/main/java/com/simibubi/create/AllBogeyStyles.java @@ -0,0 +1,132 @@ +package com.simibubi.create; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableMap; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.content.trains.bogey.BogeyRenderer; +import com.simibubi.create.content.trains.bogey.BogeyRenderer.CommonRenderer; +import com.simibubi.create.content.trains.bogey.BogeySizes; +import com.simibubi.create.content.trains.bogey.BogeyStyle; +import com.simibubi.create.content.trains.bogey.StandardBogeyRenderer.CommonStandardBogeyRenderer; +import com.simibubi.create.content.trains.bogey.StandardBogeyRenderer.LargeStandardBogeyRenderer; +import com.simibubi.create.content.trains.bogey.StandardBogeyRenderer.SmallStandardBogeyRenderer; +import com.simibubi.create.foundation.utility.CreateLang; +import com.tterrag.registrate.util.entry.BlockEntry; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class AllBogeyStyles { + public static final Map BOGEY_STYLES = new HashMap<>(); + public static final Map> CYCLE_GROUPS = new HashMap<>(); + private static final Map EMPTY_GROUP = ImmutableMap.of(); + + public static Map getCycleGroup(ResourceLocation cycleGroup) { + return CYCLE_GROUPS.getOrDefault(cycleGroup, EMPTY_GROUP); + } + + public static final String STANDARD_CYCLE_GROUP = "standard"; + + public static final BogeyStyle STANDARD = + create("standard", STANDARD_CYCLE_GROUP).commonRenderer(() -> CommonStandardBogeyRenderer::new) + .displayName(Components.translatable("create.bogey.style.standard")) + .size(BogeySizes.SMALL, () -> SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY) + .size(BogeySizes.LARGE, () -> LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY) + .build(); + + private static BogeyStyleBuilder create(String name, String cycleGroup) { + return create(Create.asResource(name), Create.asResource(cycleGroup)); + } + + public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) { + return new BogeyStyleBuilder(name, cycleGroup); + } + + public static void register() {} + + public static class BogeyStyleBuilder { + protected final Map> sizeRenderers = new HashMap<>(); + protected final Map sizes = new HashMap<>(); + protected final ResourceLocation name; + protected final ResourceLocation cycleGroup; + + protected Component displayName = CreateLang.translateDirect("bogey.style.invalid"); + protected ResourceLocation soundType = AllSoundEvents.TRAIN2.getId(); + protected CompoundTag defaultData = new CompoundTag(); + protected ParticleOptions contactParticle = ParticleTypes.CRIT; + protected ParticleOptions smokeParticle = ParticleTypes.POOF; + protected Optional> commonRenderer = Optional.empty(); + + public BogeyStyleBuilder(ResourceLocation name, ResourceLocation cycleGroup) { + this.name = name; + this.cycleGroup = cycleGroup; + } + + public BogeyStyleBuilder displayName(Component displayName) { + this.displayName = displayName; + return this; + } + + public BogeyStyleBuilder soundType(ResourceLocation soundType) { + this.soundType = soundType; + return this; + } + + public BogeyStyleBuilder defaultData(CompoundTag defaultData) { + this.defaultData = defaultData; + return this; + } + + public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier> renderer, + BlockEntry> blockEntry) { + this.size(size, renderer, blockEntry.getId()); + return this; + } + + public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier> renderer, + ResourceLocation location) { + this.sizes.put(size, location); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + this.sizeRenderers.put(size, () -> new BogeyStyle.SizeRenderData(renderer.get(), renderer.get() + .get())); + }); + return this; + } + + public BogeyStyleBuilder contactParticle(ParticleOptions contactParticle) { + this.contactParticle = contactParticle; + return this; + } + + public BogeyStyleBuilder smokeParticle(ParticleOptions smokeParticle) { + this.smokeParticle = smokeParticle; + return this; + } + + public BogeyStyleBuilder commonRenderer(Supplier> commonRenderer) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + this.commonRenderer = Optional.of(commonRenderer.get()); + }); + return this; + } + + public BogeyStyle build() { + BogeyStyle entry = new BogeyStyle(name, cycleGroup, displayName, soundType, contactParticle, smokeParticle, + defaultData, sizes, sizeRenderers, commonRenderer); + BOGEY_STYLES.put(name, entry); + CYCLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()) + .put(name, entry); + return entry; + } + } +} diff --git a/src/main/java/com/simibubi/create/AllContainerTypes.java b/src/main/java/com/simibubi/create/AllContainerTypes.java deleted file mode 100644 index 337b7074e7..0000000000 --- a/src/main/java/com/simibubi/create/AllContainerTypes.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.simibubi.create; - -import com.simibubi.create.content.curiosities.toolbox.ToolboxContainer; -import com.simibubi.create.content.curiosities.toolbox.ToolboxScreen; -import com.simibubi.create.content.curiosities.tools.BlueprintContainer; -import com.simibubi.create.content.curiosities.tools.BlueprintScreen; -import com.simibubi.create.content.logistics.item.LinkedControllerContainer; -import com.simibubi.create.content.logistics.item.LinkedControllerScreen; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterScreen; -import com.simibubi.create.content.logistics.item.filter.FilterContainer; -import com.simibubi.create.content.logistics.item.filter.FilterScreen; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleContainer; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleScreen; -import com.simibubi.create.content.schematics.block.SchematicTableContainer; -import com.simibubi.create.content.schematics.block.SchematicTableScreen; -import com.simibubi.create.content.schematics.block.SchematicannonContainer; -import com.simibubi.create.content.schematics.block.SchematicannonScreen; -import com.tterrag.registrate.builders.MenuBuilder.ForgeMenuFactory; -import com.tterrag.registrate.builders.MenuBuilder.ScreenFactory; -import com.tterrag.registrate.util.entry.MenuEntry; -import com.tterrag.registrate.util.nullness.NonNullSupplier; - -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.MenuAccess; -import net.minecraft.world.inventory.AbstractContainerMenu; - -public class AllContainerTypes { - - public static final MenuEntry SCHEMATIC_TABLE = - register("schematic_table", SchematicTableContainer::new, () -> SchematicTableScreen::new); - - public static final MenuEntry SCHEMATICANNON = - register("schematicannon", SchematicannonContainer::new, () -> SchematicannonScreen::new); - - public static final MenuEntry FILTER = - register("filter", FilterContainer::new, () -> FilterScreen::new); - - public static final MenuEntry ATTRIBUTE_FILTER = - register("attribute_filter", AttributeFilterContainer::new, () -> AttributeFilterScreen::new); - - public static final MenuEntry CRAFTING_BLUEPRINT = - register("crafting_blueprint", BlueprintContainer::new, () -> BlueprintScreen::new); - - public static final MenuEntry LINKED_CONTROLLER = - register("linked_controller", LinkedControllerContainer::new, () -> LinkedControllerScreen::new); - - public static final MenuEntry TOOLBOX = - register("toolbox", ToolboxContainer::new, () -> ToolboxScreen::new); - - public static final MenuEntry SCHEDULE = - register("schedule", ScheduleContainer::new, () -> ScheduleScreen::new); - - private static > MenuEntry register( - String name, ForgeMenuFactory factory, NonNullSupplier> screenFactory) { - return Create.registrate() - .menu(name, factory, screenFactory) - .register(); - } - - public static void register() {} - -} diff --git a/src/main/java/com/simibubi/create/AllCreativeModeTabs.java b/src/main/java/com/simibubi/create/AllCreativeModeTabs.java new file mode 100644 index 0000000000..14b3edeac3 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllCreativeModeTabs.java @@ -0,0 +1,14 @@ +package com.simibubi.create; + +import com.simibubi.create.content.decoration.palettes.PalettesCreativeModeTab; +import com.simibubi.create.infrastructure.item.BaseCreativeModeTab; + +import net.minecraft.world.item.CreativeModeTab; + +public class AllCreativeModeTabs { + public static final CreativeModeTab BASE_CREATIVE_TAB = new BaseCreativeModeTab(); + public static final CreativeModeTab PALETTES_CREATIVE_TAB = new PalettesCreativeModeTab(); + + public static void init() { + } +} diff --git a/src/main/java/com/simibubi/create/AllEnchantments.java b/src/main/java/com/simibubi/create/AllEnchantments.java index e0531efa9a..3f0a3f8636 100644 --- a/src/main/java/com/simibubi/create/AllEnchantments.java +++ b/src/main/java/com/simibubi/create/AllEnchantments.java @@ -1,8 +1,9 @@ package com.simibubi.create; -import com.simibubi.create.content.curiosities.armor.CapacityEnchantment; -import com.simibubi.create.content.curiosities.weapons.PotatoRecoveryEnchantment; -import com.simibubi.create.foundation.data.CreateRegistrate; +import static com.simibubi.create.Create.REGISTRATE; + +import com.simibubi.create.content.equipment.armor.CapacityEnchantment; +import com.simibubi.create.content.equipment.potatoCannon.PotatoRecoveryEnchantment; import com.tterrag.registrate.util.entry.RegistryEntry; import net.minecraft.world.entity.EquipmentSlot; @@ -11,8 +12,6 @@ import net.minecraft.world.item.enchantment.EnchantmentCategory; public class AllEnchantments { - private static final CreateRegistrate REGISTRATE = Create.registrate(); - public static final RegistryEntry POTATO_RECOVERY = REGISTRATE.object("potato_recovery") .enchantment(EnchantmentCategory.BOW, PotatoRecoveryEnchantment::new) .addSlots(EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND) diff --git a/src/main/java/com/simibubi/create/AllEntityDataSerializers.java b/src/main/java/com/simibubi/create/AllEntityDataSerializers.java index b0d6b2343e..f1f1c0d429 100644 --- a/src/main/java/com/simibubi/create/AllEntityDataSerializers.java +++ b/src/main/java/com/simibubi/create/AllEntityDataSerializers.java @@ -1,6 +1,6 @@ package com.simibubi.create; -import com.simibubi.create.content.logistics.trains.entity.CarriageSyncDataSerializer; +import com.simibubi.create.content.trains.entity.CarriageSyncDataSerializer; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DataSerializerEntry; diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 42ddd1ad1b..f18404cde0 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -1,21 +1,21 @@ package com.simibubi.create; -import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer; -import com.simibubi.create.content.curiosities.tools.BlueprintEntity; -import com.simibubi.create.content.curiosities.tools.BlueprintRenderer; -import com.simibubi.create.content.curiosities.weapons.PotatoProjectileEntity; -import com.simibubi.create.content.curiosities.weapons.PotatoProjectileRenderer; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntityRenderer; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionInstance; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.actors.seat.SeatEntity; +import com.simibubi.create.content.contraptions.gantry.GantryContraptionEntity; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.glue.SuperGlueRenderer; +import com.simibubi.create.content.contraptions.render.ContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.render.OrientedContraptionEntityRenderer; +import com.simibubi.create.content.equipment.blueprint.BlueprintEntity; +import com.simibubi.create.content.equipment.blueprint.BlueprintRenderer; +import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileEntity; +import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileRenderer; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntityRenderer; +import com.simibubi.create.content.trains.entity.CarriageContraptionInstance; import com.simibubi.create.foundation.data.CreateEntityBuilder; import com.tterrag.registrate.util.entry.EntityEntry; import com.tterrag.registrate.util.nullness.NonNullConsumer; @@ -73,7 +73,7 @@ public class AllEntityTypes { MobCategory group, int range, int updateFrequency, boolean sendVelocity, boolean immuneToFire, NonNullConsumer> propertyBuilder) { String id = Lang.asId(name); - return (CreateEntityBuilder) Create.registrate() + return (CreateEntityBuilder) Create.REGISTRATE .entity(id, factory, group) .properties(b -> b.setTrackingRange(range) .setUpdateInterval(updateFrequency) diff --git a/src/main/java/com/simibubi/create/AllFluids.java b/src/main/java/com/simibubi/create/AllFluids.java index 275d61e066..43d3f5f0cf 100644 --- a/src/main/java/com/simibubi/create/AllFluids.java +++ b/src/main/java/com/simibubi/create/AllFluids.java @@ -1,13 +1,14 @@ package com.simibubi.create; +import static com.simibubi.create.Create.REGISTRATE; + import javax.annotation.Nullable; import com.simibubi.create.AllTags.AllFluidTags; -import com.simibubi.create.content.contraptions.fluids.VirtualFluid; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid.PotionFluidAttributes; -import com.simibubi.create.content.palettes.AllPaletteStoneTypes; -import com.simibubi.create.foundation.data.CreateRegistrate; +import com.simibubi.create.content.decoration.palettes.AllPaletteStoneTypes; +import com.simibubi.create.content.fluids.VirtualFluid; +import com.simibubi.create.content.fluids.potion.PotionFluid; +import com.simibubi.create.content.fluids.potion.PotionFluid.PotionFluidAttributes; import com.tterrag.registrate.util.entry.FluidEntry; import net.minecraft.core.BlockPos; @@ -20,8 +21,6 @@ import net.minecraftforge.fluids.ForgeFlowingFluid; public class AllFluids { - private static final CreateRegistrate REGISTRATE = Create.registrate(); - public static final FluidEntry POTION = REGISTRATE.virtualFluid("potion", PotionFluidAttributes::new, PotionFluid::new) .lang("Potion") diff --git a/src/main/java/com/simibubi/create/AllInteractionBehaviours.java b/src/main/java/com/simibubi/create/AllInteractionBehaviours.java index 0ce0c7465d..31c518c5fb 100644 --- a/src/main/java/com/simibubi/create/AllInteractionBehaviours.java +++ b/src/main/java/com/simibubi/create/AllInteractionBehaviours.java @@ -5,11 +5,11 @@ import java.util.List; import org.jetbrains.annotations.Nullable; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.DoorMovingInteraction; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.LeverMovingInteraction; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.TrapdoorMovingInteraction; -import com.simibubi.create.foundation.utility.CreateRegistry; +import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction; +import com.simibubi.create.content.contraptions.behaviour.LeverMovingInteraction; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction; +import com.simibubi.create.foundation.utility.AttachedRegistry; import com.tterrag.registrate.util.nullness.NonNullConsumer; import net.minecraft.resources.ResourceLocation; @@ -18,10 +18,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.IRegistryDelegate; public class AllInteractionBehaviours { - private static final CreateRegistry BLOCK_BEHAVIOURS = new CreateRegistry<>(ForgeRegistries.BLOCKS); + private static final AttachedRegistry BLOCK_BEHAVIOURS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); private static final List GLOBAL_BEHAVIOURS = new ArrayList<>(); public static void registerBehaviour(ResourceLocation block, MovingInteractionBehaviour provider) { @@ -32,11 +31,6 @@ public class AllInteractionBehaviours { BLOCK_BEHAVIOURS.register(block, provider); } - @Deprecated(forRemoval = true) - public static void registerBehaviour(IRegistryDelegate block, MovingInteractionBehaviour provider) { - registerBehaviour(block.name(), provider); - } - public static void registerBehaviourProvider(BehaviourProvider provider) { GLOBAL_BEHAVIOURS.add(provider); } diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 1797c4bd38..9b80a37cbb 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -1,14 +1,10 @@ package com.simibubi.create; import static com.simibubi.create.AllTags.AllItemTags.CREATE_INGOTS; -import static com.simibubi.create.AllTags.AllItemTags.CRUSHED_ORES; +import static com.simibubi.create.AllTags.AllItemTags.CRUSHED_RAW_MATERIALS; import static com.simibubi.create.AllTags.AllItemTags.PLATES; import static com.simibubi.create.AllTags.forgeItemTag; -import static com.simibubi.create.content.AllSections.CURIOSITIES; -import static com.simibubi.create.content.AllSections.KINETICS; -import static com.simibubi.create.content.AllSections.LOGISTICS; -import static com.simibubi.create.content.AllSections.MATERIALS; -import static com.simibubi.create.content.AllSections.SCHEMATICS; +import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.foundation.data.recipe.CompatMetals.ALUMINUM; import static com.simibubi.create.foundation.data.recipe.CompatMetals.LEAD; import static com.simibubi.create.foundation.data.recipe.CompatMetals.NICKEL; @@ -20,64 +16,60 @@ import static com.simibubi.create.foundation.data.recipe.CompatMetals.TIN; import static com.simibubi.create.foundation.data.recipe.CompatMetals.URANIUM; import com.simibubi.create.AllTags.AllItemTags; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MinecartContraptionItem; -import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartCouplingItem; -import com.simibubi.create.content.contraptions.goggles.GogglesItem; -import com.simibubi.create.content.contraptions.goggles.GogglesModel; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyItem; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem; -import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem; -import com.simibubi.create.content.contraptions.relays.gearbox.VerticalGearboxItem; -import com.simibubi.create.content.contraptions.wrench.WrenchItem; -import com.simibubi.create.content.curiosities.BuildersTeaItem; -import com.simibubi.create.content.curiosities.ChromaticCompoundColor; -import com.simibubi.create.content.curiosities.ChromaticCompoundItem; -import com.simibubi.create.content.curiosities.CombustibleItem; -import com.simibubi.create.content.curiosities.ExperienceNuggetItem; -import com.simibubi.create.content.curiosities.RefinedRadianceItem; -import com.simibubi.create.content.curiosities.ShadowSteelItem; -import com.simibubi.create.content.curiosities.TreeFertilizerItem; -import com.simibubi.create.content.curiosities.armor.CopperArmorItem; -import com.simibubi.create.content.curiosities.armor.CopperBacktankItem; -import com.simibubi.create.content.curiosities.armor.CopperBacktankItem.CopperBacktankBlockItem; -import com.simibubi.create.content.curiosities.armor.DivingBootsItem; -import com.simibubi.create.content.curiosities.armor.DivingHelmetItem; -import com.simibubi.create.content.curiosities.symmetry.SymmetryWandItem; -import com.simibubi.create.content.curiosities.tools.BlueprintItem; -import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; -import com.simibubi.create.content.curiosities.tools.SandPaperItem; -import com.simibubi.create.content.curiosities.weapons.PotatoCannonItem; -import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperItem; -import com.simibubi.create.content.logistics.item.LinkedControllerItem; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; -import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; -import com.simibubi.create.content.schematics.item.SchematicItem; +import com.simibubi.create.content.contraptions.glue.SuperGlueItem; +import com.simibubi.create.content.contraptions.minecart.MinecartCouplingItem; +import com.simibubi.create.content.contraptions.mounted.MinecartContraptionItem; +import com.simibubi.create.content.equipment.BuildersTeaItem; +import com.simibubi.create.content.equipment.TreeFertilizerItem; +import com.simibubi.create.content.equipment.armor.AllArmorMaterials; +import com.simibubi.create.content.equipment.armor.BacktankItem; +import com.simibubi.create.content.equipment.armor.BacktankItem.BacktankBlockItem; +import com.simibubi.create.content.equipment.armor.DivingBootsItem; +import com.simibubi.create.content.equipment.armor.DivingHelmetItem; +import com.simibubi.create.content.equipment.blueprint.BlueprintItem; +import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripItem; +import com.simibubi.create.content.equipment.goggles.GogglesItem; +import com.simibubi.create.content.equipment.goggles.GogglesModel; +import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonItem; +import com.simibubi.create.content.equipment.sandPaper.SandPaperItem; +import com.simibubi.create.content.equipment.symmetryWand.SymmetryWandItem; +import com.simibubi.create.content.equipment.wrench.WrenchItem; +import com.simibubi.create.content.equipment.zapper.terrainzapper.WorldshaperItem; +import com.simibubi.create.content.kinetics.belt.item.BeltConnectorItem; +import com.simibubi.create.content.kinetics.gearbox.VerticalGearboxItem; +import com.simibubi.create.content.legacy.ChromaticCompoundColor; +import com.simibubi.create.content.legacy.ChromaticCompoundItem; +import com.simibubi.create.content.legacy.RefinedRadianceItem; +import com.simibubi.create.content.legacy.ShadowSteelItem; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.materials.ExperienceNuggetItem; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlockItem; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyItem; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerItem; +import com.simibubi.create.content.schematics.SchematicAndQuillItem; +import com.simibubi.create.content.schematics.SchematicItem; +import com.simibubi.create.content.trains.schedule.ScheduleItem; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.CreateRegistrate; import com.simibubi.create.foundation.data.recipe.CompatMetals; +import com.simibubi.create.foundation.item.CombustibleItem; import com.simibubi.create.foundation.item.HiddenIngredientItem; +import com.simibubi.create.foundation.item.ItemDescription; import com.simibubi.create.foundation.item.TagDependentIngredientItem; -import com.simibubi.create.foundation.item.TooltipHelper; import com.tterrag.registrate.util.entry.ItemEntry; import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.world.food.FoodProperties; +import net.minecraft.world.item.ArmorMaterials; import net.minecraft.world.item.Item; import net.minecraft.world.item.Rarity; import net.minecraftforge.common.Tags; public class AllItems { - private static final CreateRegistrate REGISTRATE = Create.registrate() - .creativeModeTab(() -> Create.BASE_CREATIVE_TAB); - - // Schematics - static { - REGISTRATE.startSection(MATERIALS); + REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.BASE_CREATIVE_TAB); } public static final ItemEntry WHEAT_FLOUR = @@ -186,10 +178,10 @@ public class AllItems { IRON_SHEET = taggedIngredient("iron_sheet", forgeItemTag("plates/iron"), PLATES.tag), GOLDEN_SHEET = taggedIngredient("golden_sheet", forgeItemTag("plates/gold"), PLATES.tag, ItemTags.PIGLIN_LOVED), - CRUSHED_IRON = taggedIngredient("crushed_iron_ore", CRUSHED_ORES.tag), - CRUSHED_GOLD = taggedIngredient("crushed_gold_ore", CRUSHED_ORES.tag, ItemTags.PIGLIN_LOVED), - CRUSHED_COPPER = taggedIngredient("crushed_copper_ore", CRUSHED_ORES.tag), - CRUSHED_ZINC = taggedIngredient("crushed_zinc_ore", CRUSHED_ORES.tag); + CRUSHED_IRON = taggedIngredient("crushed_raw_iron", CRUSHED_RAW_MATERIALS.tag), + CRUSHED_GOLD = taggedIngredient("crushed_raw_gold", CRUSHED_RAW_MATERIALS.tag, ItemTags.PIGLIN_LOVED), + CRUSHED_COPPER = taggedIngredient("crushed_raw_copper", CRUSHED_RAW_MATERIALS.tag), + CRUSHED_ZINC = taggedIngredient("crushed_raw_zinc", CRUSHED_RAW_MATERIALS.tag); public static final ItemEntry CRUSHED_OSMIUM = compatCrushedOre(OSMIUM), CRUSHED_PLATINUM = compatCrushedOre(PLATINUM), CRUSHED_SILVER = compatCrushedOre(SILVER), @@ -199,10 +191,6 @@ public class AllItems { // Kinetics - static { - REGISTRATE.startSection(KINETICS); - } - public static final ItemEntry BELT_CONNECTOR = REGISTRATE.item("belt_connector", BeltConnectorItem::new) .lang("Mechanical Belt") @@ -239,22 +227,72 @@ public class AllItems { // wrapped by COPPER_BACKTANK for block placement uses. // must be registered as of 1.18.2 - public static final ItemEntry COPPER_BACKTANK_PLACEABLE = REGISTRATE - .item("copper_backtank_placeable", p -> new CopperBacktankBlockItem(AllBlocks.COPPER_BACKTANK.get(), p)) + public static final ItemEntry COPPER_BACKTANK_PLACEABLE = REGISTRATE + .item("copper_backtank_placeable", + p -> new BacktankBlockItem(AllBlocks.COPPER_BACKTANK.get(), AllItems.COPPER_BACKTANK::get, p)) .model((c, p) -> p.withExistingParent(c.getName(), p.mcLoc("item/barrier"))) .register(); - public static final ItemEntry + // wrapped by NETHERITE_BACKTANK for block placement uses. + // must be registered as of 1.18.2 + public static final ItemEntry NETHERITE_BACKTANK_PLACEABLE = REGISTRATE + .item("netherite_backtank_placeable", + p -> new BacktankBlockItem(AllBlocks.NETHERITE_BACKTANK.get(), AllItems.NETHERITE_BACKTANK::get, p)) + .model((c, p) -> p.withExistingParent(c.getName(), p.mcLoc("item/barrier"))) + .register(); - COPPER_BACKTANK = REGISTRATE.item("copper_backtank", p -> new CopperBacktankItem(p, COPPER_BACKTANK_PLACEABLE)) - .model(AssetLookup.customGenericItemModel("_", "item")) - .tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag) - .register(), + public static final ItemEntry - DIVING_HELMET = REGISTRATE.item("diving_helmet", DivingHelmetItem::new) + COPPER_BACKTANK = + REGISTRATE + .item("copper_backtank", + p -> new BacktankItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving"), + COPPER_BACKTANK_PLACEABLE)) + .model(AssetLookup.customGenericItemModel("_", "item")) + .tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag) + .tag(forgeItemTag("armors/chestplates")) .register(), - DIVING_BOOTS = REGISTRATE.item("diving_boots", DivingBootsItem::new) + NETHERITE_BACKTANK = REGISTRATE + .item("netherite_backtank", + p -> new BacktankItem.Layered(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"), + NETHERITE_BACKTANK_PLACEABLE)) + .model(AssetLookup.customGenericItemModel("_", "item")) + .properties(p -> p.fireResistant()) + .tag(AllItemTags.PRESSURIZED_AIR_SOURCES.tag) + .tag(forgeItemTag("armors/chestplates")) + .register(); + + public static final ItemEntry + + COPPER_DIVING_HELMET = + REGISTRATE + .item("copper_diving_helmet", + p -> new DivingHelmetItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving"))) + .tag(forgeItemTag("armors/helmets")) + .register(), + + NETHERITE_DIVING_HELMET = REGISTRATE + .item("netherite_diving_helmet", + p -> new DivingHelmetItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"))) + .properties(p -> p.fireResistant()) + .tag(forgeItemTag("armors/helmets")) + .register(); + + public static final ItemEntry + + COPPER_DIVING_BOOTS = + REGISTRATE + .item("copper_diving_boots", + p -> new DivingBootsItem(AllArmorMaterials.COPPER, p, Create.asResource("copper_diving"))) + .tag(forgeItemTag("armors/boots")) + .register(), + + NETHERITE_DIVING_BOOTS = REGISTRATE + .item("netherite_diving_boots", + p -> new DivingBootsItem(ArmorMaterials.NETHERITE, p, Create.asResource("netherite_diving"))) + .properties(p -> p.fireResistant()) + .tag(forgeItemTag("armors/boots")) .register(); public static final ItemEntry SAND_PAPER = REGISTRATE.item("sand_paper", SandPaperItem::new) @@ -263,7 +301,7 @@ public class AllItems { public static final ItemEntry RED_SAND_PAPER = REGISTRATE.item("red_sand_paper", SandPaperItem::new) .tag(AllTags.AllItemTags.SANDPAPER.tag) - .onRegister(s -> TooltipHelper.referTo(s, SAND_PAPER)) + .onRegister(s -> ItemDescription.referKey(s, SAND_PAPER)) .register(); public static final ItemEntry WRENCH = REGISTRATE.item("wrench", WrenchItem::new) @@ -286,10 +324,6 @@ public class AllItems { // Curiosities - static { - REGISTRATE.startSection(CURIOSITIES); - } - public static final ItemEntry LINKED_CONTROLLER = REGISTRATE.item("linked_controller", LinkedControllerItem::new) .properties(p -> p.stacksTo(1)) @@ -326,18 +360,11 @@ public class AllItems { // Logistics - static { - REGISTRATE.startSection(LOGISTICS); - } - public static final ItemEntry FILTER = REGISTRATE.item("filter", FilterItem::regular) - .model(AssetLookup.existingItemModel()) - .register(); - - public static final ItemEntry ATTRIBUTE_FILTER = - REGISTRATE.item("attribute_filter", FilterItem::attribute) - .model(AssetLookup.existingItemModel()) - .register(); + .lang("List Filter") + .register(), ATTRIBUTE_FILTER = + REGISTRATE.item("attribute_filter", FilterItem::attribute) + .register(); public static final ItemEntry SCHEDULE = REGISTRATE.item("schedule", ScheduleItem::new) .lang("Train Schedule") @@ -345,10 +372,6 @@ public class AllItems { // Schematics - static { - REGISTRATE.startSection(SCHEMATICS); - } - public static final ItemEntry EMPTY_SCHEMATIC = REGISTRATE.item("empty_schematic", Item::new) .properties(p -> p.stacksTo(1)) .register(); @@ -389,9 +412,9 @@ public class AllItems { private static ItemEntry compatCrushedOre(CompatMetals metal) { String metalName = metal.getName(); return REGISTRATE - .item("crushed_" + metalName + "_ore", + .item("crushed_raw_" + metalName, props -> new TagDependentIngredientItem(props, AllTags.forgeItemTag("ores/" + metalName))) - .tag(CRUSHED_ORES.tag) + .tag(CRUSHED_RAW_MATERIALS.tag) .register(); } diff --git a/src/main/java/com/simibubi/create/AllMenuTypes.java b/src/main/java/com/simibubi/create/AllMenuTypes.java new file mode 100644 index 0000000000..853a9e6471 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllMenuTypes.java @@ -0,0 +1,63 @@ +package com.simibubi.create; + +import com.simibubi.create.content.equipment.blueprint.BlueprintMenu; +import com.simibubi.create.content.equipment.blueprint.BlueprintScreen; +import com.simibubi.create.content.equipment.toolbox.ToolboxMenu; +import com.simibubi.create.content.equipment.toolbox.ToolboxScreen; +import com.simibubi.create.content.logistics.filter.AttributeFilterMenu; +import com.simibubi.create.content.logistics.filter.AttributeFilterScreen; +import com.simibubi.create.content.logistics.filter.FilterMenu; +import com.simibubi.create.content.logistics.filter.FilterScreen; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerMenu; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerScreen; +import com.simibubi.create.content.schematics.cannon.SchematicannonMenu; +import com.simibubi.create.content.schematics.cannon.SchematicannonScreen; +import com.simibubi.create.content.schematics.table.SchematicTableMenu; +import com.simibubi.create.content.schematics.table.SchematicTableScreen; +import com.simibubi.create.content.trains.schedule.ScheduleMenu; +import com.simibubi.create.content.trains.schedule.ScheduleScreen; +import com.tterrag.registrate.builders.MenuBuilder.ForgeMenuFactory; +import com.tterrag.registrate.builders.MenuBuilder.ScreenFactory; +import com.tterrag.registrate.util.entry.MenuEntry; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.world.inventory.AbstractContainerMenu; + +public class AllMenuTypes { + + public static final MenuEntry SCHEMATIC_TABLE = + register("schematic_table", SchematicTableMenu::new, () -> SchematicTableScreen::new); + + public static final MenuEntry SCHEMATICANNON = + register("schematicannon", SchematicannonMenu::new, () -> SchematicannonScreen::new); + + public static final MenuEntry FILTER = + register("filter", FilterMenu::new, () -> FilterScreen::new); + + public static final MenuEntry ATTRIBUTE_FILTER = + register("attribute_filter", AttributeFilterMenu::new, () -> AttributeFilterScreen::new); + + public static final MenuEntry CRAFTING_BLUEPRINT = + register("crafting_blueprint", BlueprintMenu::new, () -> BlueprintScreen::new); + + public static final MenuEntry LINKED_CONTROLLER = + register("linked_controller", LinkedControllerMenu::new, () -> LinkedControllerScreen::new); + + public static final MenuEntry TOOLBOX = + register("toolbox", ToolboxMenu::new, () -> ToolboxScreen::new); + + public static final MenuEntry SCHEDULE = + register("schedule", ScheduleMenu::new, () -> ScheduleScreen::new); + + private static > MenuEntry register( + String name, ForgeMenuFactory factory, NonNullSupplier> screenFactory) { + return Create.REGISTRATE + .menu(name, factory, screenFactory) + .register(); + } + + public static void register() {} + +} diff --git a/src/main/java/com/simibubi/create/AllMovementBehaviours.java b/src/main/java/com/simibubi/create/AllMovementBehaviours.java index 843ece1f73..6dde486402 100644 --- a/src/main/java/com/simibubi/create/AllMovementBehaviours.java +++ b/src/main/java/com/simibubi/create/AllMovementBehaviours.java @@ -3,14 +3,14 @@ package com.simibubi.create; import java.util.ArrayList; import java.util.List; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.components.actors.BellMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.CampfireMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.dispenser.DispenserMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.dispenser.DropperMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.foundation.utility.CreateRegistry; +import com.simibubi.create.content.contraptions.behaviour.BellMovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.CampfireMovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.dispenser.DispenserMovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.dispenser.DropperMovementBehaviour; +import com.simibubi.create.foundation.utility.AttachedRegistry; import com.tterrag.registrate.util.nullness.NonNullConsumer; import net.minecraft.resources.ResourceLocation; @@ -18,10 +18,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.IRegistryDelegate; public class AllMovementBehaviours { - private static final CreateRegistry BLOCK_BEHAVIOURS = new CreateRegistry<>(ForgeRegistries.BLOCKS); + private static final AttachedRegistry BLOCK_BEHAVIOURS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); private static final List GLOBAL_BEHAVIOURS = new ArrayList<>(); public static void registerBehaviour(ResourceLocation block, MovementBehaviour behaviour) { @@ -32,11 +31,6 @@ public class AllMovementBehaviours { BLOCK_BEHAVIOURS.register(block, behaviour); } - @Deprecated(forRemoval = true) - public static void registerBehaviour(IRegistryDelegate block, MovementBehaviour behaviour) { - registerBehaviour(block.name(), behaviour); - } - public static void registerBehaviourProvider(BehaviourProvider provider) { GLOBAL_BEHAVIOURS.add(provider); } @@ -66,6 +60,7 @@ public class AllMovementBehaviours { static void registerDefaults() { registerBehaviour(Blocks.BELL, new BellMovementBehaviour()); registerBehaviour(Blocks.CAMPFIRE, new CampfireMovementBehaviour()); + registerBehaviour(Blocks.SOUL_CAMPFIRE, new CampfireMovementBehaviour()); DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours(); registerBehaviour(Blocks.DISPENSER, new DispenserMovementBehaviour()); diff --git a/src/main/java/com/simibubi/create/AllPackets.java b/src/main/java/com/simibubi/create/AllPackets.java new file mode 100644 index 0000000000..76dd155fac --- /dev/null +++ b/src/main/java/com/simibubi/create/AllPackets.java @@ -0,0 +1,283 @@ +package com.simibubi.create; + +import static net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT; +import static net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER; + +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import com.simibubi.create.compat.computercraft.AttachedComputerPacket; +import com.simibubi.create.content.contraptions.ContraptionBlockChangedPacket; +import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket; +import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket.ContraptionColliderLockPacketRequest; +import com.simibubi.create.content.contraptions.ContraptionDisassemblyPacket; +import com.simibubi.create.content.contraptions.ContraptionRelocationPacket; +import com.simibubi.create.content.contraptions.ContraptionStallPacket; +import com.simibubi.create.content.contraptions.TrainCollisionPacket; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionDisableActorPacket; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsInputPacket; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsStopControllingPacket; +import com.simibubi.create.content.contraptions.elevator.ElevatorContactEditPacket; +import com.simibubi.create.content.contraptions.elevator.ElevatorFloorListPacket; +import com.simibubi.create.content.contraptions.elevator.ElevatorTargetFloorPacket; +import com.simibubi.create.content.contraptions.gantry.GantryContraptionUpdatePacket; +import com.simibubi.create.content.contraptions.glue.GlueEffectPacket; +import com.simibubi.create.content.contraptions.glue.SuperGlueRemovalPacket; +import com.simibubi.create.content.contraptions.glue.SuperGlueSelectionPacket; +import com.simibubi.create.content.contraptions.minecart.CouplingCreationPacket; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartControllerUpdatePacket; +import com.simibubi.create.content.contraptions.sync.ClientMotionPacket; +import com.simibubi.create.content.contraptions.sync.ContraptionFluidPacket; +import com.simibubi.create.content.contraptions.sync.ContraptionInteractionPacket; +import com.simibubi.create.content.contraptions.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.content.contraptions.sync.LimbSwingUpdatePacket; +import com.simibubi.create.content.equipment.bell.SoulPulseEffectPacket; +import com.simibubi.create.content.equipment.blueprint.BlueprintAssignCompleteRecipePacket; +import com.simibubi.create.content.equipment.clipboard.ClipboardEditPacket; +import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripInteractionPacket; +import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonPacket; +import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileTypeManager; +import com.simibubi.create.content.equipment.symmetryWand.ConfigureSymmetryWandPacket; +import com.simibubi.create.content.equipment.symmetryWand.SymmetryEffectPacket; +import com.simibubi.create.content.equipment.toolbox.ToolboxDisposeAllPacket; +import com.simibubi.create.content.equipment.toolbox.ToolboxEquipPacket; +import com.simibubi.create.content.equipment.zapper.ZapperBeamPacket; +import com.simibubi.create.content.equipment.zapper.terrainzapper.ConfigureWorldshaperPacket; +import com.simibubi.create.content.fluids.transfer.FluidSplashPacket; +import com.simibubi.create.content.kinetics.gauge.GaugeObservedPacket; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmPlacementPacket; +import com.simibubi.create.content.kinetics.transmission.sequencer.ConfigureSequencedGearshiftPacket; +import com.simibubi.create.content.logistics.depot.EjectorAwardPacket; +import com.simibubi.create.content.logistics.depot.EjectorElytraPacket; +import com.simibubi.create.content.logistics.depot.EjectorPlacementPacket; +import com.simibubi.create.content.logistics.depot.EjectorTriggerPacket; +import com.simibubi.create.content.logistics.filter.FilterScreenPacket; +import com.simibubi.create.content.logistics.funnel.FunnelFlapPacket; +import com.simibubi.create.content.logistics.tunnel.TunnelFlapPacket; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkConfigurationPacket; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerBindPacket; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerInputPacket; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerStopLecternPacket; +import com.simibubi.create.content.redstone.thresholdSwitch.ConfigureThresholdSwitchPacket; +import com.simibubi.create.content.schematics.cannon.ConfigureSchematicannonPacket; +import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; +import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; +import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; +import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; +import com.simibubi.create.content.trains.HonkPacket; +import com.simibubi.create.content.trains.TrainHUDUpdatePacket; +import com.simibubi.create.content.trains.entity.TrainPacket; +import com.simibubi.create.content.trains.entity.TrainPromptPacket; +import com.simibubi.create.content.trains.entity.TrainRelocationPacket; +import com.simibubi.create.content.trains.graph.TrackGraphRequestPacket; +import com.simibubi.create.content.trains.graph.TrackGraphRollCallPacket; +import com.simibubi.create.content.trains.graph.TrackGraphSyncPacket; +import com.simibubi.create.content.trains.schedule.ScheduleEditPacket; +import com.simibubi.create.content.trains.signal.SignalEdgeGroupPacket; +import com.simibubi.create.content.trains.station.StationEditPacket; +import com.simibubi.create.content.trains.station.TrainEditPacket; +import com.simibubi.create.content.trains.station.TrainEditPacket.TrainEditReturnPacket; +import com.simibubi.create.content.trains.track.CurvedTrackDestroyPacket; +import com.simibubi.create.content.trains.track.CurvedTrackSelectionPacket; +import com.simibubi.create.content.trains.track.PlaceExtendedCurvePacket; +import com.simibubi.create.foundation.blockEntity.RemoveBlockEntityPacket; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsPacket; +import com.simibubi.create.foundation.gui.menu.ClearMenuPacket; +import com.simibubi.create.foundation.gui.menu.GhostItemSubmitPacket; +import com.simibubi.create.foundation.networking.ISyncPersistentData; +import com.simibubi.create.foundation.networking.LeftClickPacket; +import com.simibubi.create.foundation.networking.SimplePacketBase; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; +import com.simibubi.create.infrastructure.command.HighlightPacket; +import com.simibubi.create.infrastructure.command.SimpleCreateActions; + +import net.createmod.catnip.net.ClientboundSimpleActionPacket; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.PacketDistributor.TargetPoint; +import net.minecraftforge.network.simple.SimpleChannel; + +public enum AllPackets { + + // Client to Server + CONFIGURE_SCHEMATICANNON(ConfigureSchematicannonPacket.class, ConfigureSchematicannonPacket::new, PLAY_TO_SERVER), + CONFIGURE_STOCKSWITCH(ConfigureThresholdSwitchPacket.class, ConfigureThresholdSwitchPacket::new, PLAY_TO_SERVER), + CONFIGURE_SEQUENCER(ConfigureSequencedGearshiftPacket.class, ConfigureSequencedGearshiftPacket::new, + PLAY_TO_SERVER), + PLACE_SCHEMATIC(SchematicPlacePacket.class, SchematicPlacePacket::new, PLAY_TO_SERVER), + UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new, PLAY_TO_SERVER), + CLEAR_CONTAINER(ClearMenuPacket.class, ClearMenuPacket::new, PLAY_TO_SERVER), + CONFIGURE_FILTER(FilterScreenPacket.class, FilterScreenPacket::new, PLAY_TO_SERVER), + EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new, PLAY_TO_SERVER), + CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new, PLAY_TO_SERVER), + CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new, PLAY_TO_SERVER), + PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new, PLAY_TO_SERVER), + MINECART_COUPLING_CREATION(CouplingCreationPacket.class, CouplingCreationPacket::new, PLAY_TO_SERVER), + INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new, PLAY_TO_SERVER), + SYNC_SCHEMATIC(SchematicSyncPacket.class, SchematicSyncPacket::new, PLAY_TO_SERVER), + LEFT_CLICK(LeftClickPacket.class, LeftClickPacket::new, PLAY_TO_SERVER), + PLACE_EJECTOR(EjectorPlacementPacket.class, EjectorPlacementPacket::new, PLAY_TO_SERVER), + TRIGGER_EJECTOR(EjectorTriggerPacket.class, EjectorTriggerPacket::new, PLAY_TO_SERVER), + EJECTOR_ELYTRA(EjectorElytraPacket.class, EjectorElytraPacket::new, PLAY_TO_SERVER), + LINKED_CONTROLLER_INPUT(LinkedControllerInputPacket.class, LinkedControllerInputPacket::new, PLAY_TO_SERVER), + LINKED_CONTROLLER_BIND(LinkedControllerBindPacket.class, LinkedControllerBindPacket::new, PLAY_TO_SERVER), + LINKED_CONTROLLER_USE_LECTERN(LinkedControllerStopLecternPacket.class, LinkedControllerStopLecternPacket::new, + PLAY_TO_SERVER), + SUBMIT_GHOST_ITEM(GhostItemSubmitPacket.class, GhostItemSubmitPacket::new, PLAY_TO_SERVER), + BLUEPRINT_COMPLETE_RECIPE(BlueprintAssignCompleteRecipePacket.class, BlueprintAssignCompleteRecipePacket::new, + PLAY_TO_SERVER), + CONFIGURE_SYMMETRY_WAND(ConfigureSymmetryWandPacket.class, ConfigureSymmetryWandPacket::new, PLAY_TO_SERVER), + CONFIGURE_WORLDSHAPER(ConfigureWorldshaperPacket.class, ConfigureWorldshaperPacket::new, PLAY_TO_SERVER), + TOOLBOX_EQUIP(ToolboxEquipPacket.class, ToolboxEquipPacket::new, PLAY_TO_SERVER), + TOOLBOX_DISPOSE_ALL(ToolboxDisposeAllPacket.class, ToolboxDisposeAllPacket::new, PLAY_TO_SERVER), + CONFIGURE_SCHEDULE(ScheduleEditPacket.class, ScheduleEditPacket::new, PLAY_TO_SERVER), + CONFIGURE_STATION(StationEditPacket.class, StationEditPacket::new, PLAY_TO_SERVER), + C_CONFIGURE_TRAIN(TrainEditPacket.class, TrainEditPacket::new, PLAY_TO_SERVER), + RELOCATE_TRAIN(TrainRelocationPacket.class, TrainRelocationPacket::new, PLAY_TO_SERVER), + CONTROLS_INPUT(ControlsInputPacket.class, ControlsInputPacket::new, PLAY_TO_SERVER), + CONFIGURE_DATA_GATHERER(DisplayLinkConfigurationPacket.class, DisplayLinkConfigurationPacket::new, PLAY_TO_SERVER), + DESTROY_CURVED_TRACK(CurvedTrackDestroyPacket.class, CurvedTrackDestroyPacket::new, PLAY_TO_SERVER), + SELECT_CURVED_TRACK(CurvedTrackSelectionPacket.class, CurvedTrackSelectionPacket::new, PLAY_TO_SERVER), + PLACE_CURVED_TRACK(PlaceExtendedCurvePacket.class, PlaceExtendedCurvePacket::new, PLAY_TO_SERVER), + GLUE_IN_AREA(SuperGlueSelectionPacket.class, SuperGlueSelectionPacket::new, PLAY_TO_SERVER), + GLUE_REMOVED(SuperGlueRemovalPacket.class, SuperGlueRemovalPacket::new, PLAY_TO_SERVER), + TRAIN_COLLISION(TrainCollisionPacket.class, TrainCollisionPacket::new, PLAY_TO_SERVER), + C_TRAIN_HUD(TrainHUDUpdatePacket.Serverbound.class, TrainHUDUpdatePacket.Serverbound::new, PLAY_TO_SERVER), + C_TRAIN_HONK(HonkPacket.Serverbound.class, HonkPacket.Serverbound::new, PLAY_TO_SERVER), + OBSERVER_STRESSOMETER(GaugeObservedPacket.class, GaugeObservedPacket::new, PLAY_TO_SERVER), + EJECTOR_AWARD(EjectorAwardPacket.class, EjectorAwardPacket::new, PLAY_TO_SERVER), + TRACK_GRAPH_REQUEST(TrackGraphRequestPacket.class, TrackGraphRequestPacket::new, PLAY_TO_SERVER), + CONFIGURE_ELEVATOR_CONTACT(ElevatorContactEditPacket.class, ElevatorContactEditPacket::new, PLAY_TO_SERVER), + REQUEST_FLOOR_LIST(ElevatorFloorListPacket.RequestFloorList.class, ElevatorFloorListPacket.RequestFloorList::new, + PLAY_TO_SERVER), + ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER), + VALUE_SETTINGS(ValueSettingsPacket.class, ValueSettingsPacket::new, PLAY_TO_SERVER), + CLIPBOARD_EDIT(ClipboardEditPacket.class, ClipboardEditPacket::new, PLAY_TO_SERVER), + CONTRAPTION_COLLIDER_LOCK_REQUEST(ContraptionColliderLockPacketRequest.class, + ContraptionColliderLockPacketRequest::new, PLAY_TO_SERVER), + + // Server to Client + SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), + SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new, PLAY_TO_CLIENT), + BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_BLOCK_CHANGED(ContraptionBlockChangedPacket.class, ContraptionBlockChangedPacket::new, PLAY_TO_CLIENT), + GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new, PLAY_TO_CLIENT), + LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new, PLAY_TO_CLIENT), + MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket::new, PLAY_TO_CLIENT), + FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new, PLAY_TO_CLIENT), + GANTRY_UPDATE(GantryContraptionUpdatePacket.class, GantryContraptionUpdatePacket::new, PLAY_TO_CLIENT), + BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT), + TUNNEL_FLAP(TunnelFlapPacket.class, TunnelFlapPacket::new, PLAY_TO_CLIENT), + FUNNEL_FLAP(FunnelFlapPacket.class, FunnelFlapPacket::new, PLAY_TO_CLIENT), + POTATO_CANNON(PotatoCannonPacket.class, PotatoCannonPacket::new, PLAY_TO_CLIENT), + SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT), + PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, + PLAY_TO_CLIENT), + SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, + PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT), + SYNC_RAIL_GRAPH(TrackGraphSyncPacket.class, TrackGraphSyncPacket::new, PLAY_TO_CLIENT), + SYNC_EDGE_GROUP(SignalEdgeGroupPacket.class, SignalEdgeGroupPacket::new, PLAY_TO_CLIENT), + SYNC_TRAIN(TrainPacket.class, TrainPacket::new, PLAY_TO_CLIENT), + REMOVE_TE(RemoveBlockEntityPacket.class, RemoveBlockEntityPacket::new, PLAY_TO_CLIENT), + S_CONFIGURE_TRAIN(TrainEditReturnPacket.class, TrainEditReturnPacket::new, PLAY_TO_CLIENT), + CONTROLS_ABORT(ControlsStopControllingPacket.class, ControlsStopControllingPacket::new, PLAY_TO_CLIENT), + S_TRAIN_HUD(TrainHUDUpdatePacket.class, TrainHUDUpdatePacket::new, PLAY_TO_CLIENT), + S_TRAIN_HONK(HonkPacket.class, HonkPacket::new, PLAY_TO_CLIENT), + S_TRAIN_PROMPT(TrainPromptPacket.class, TrainPromptPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_RELOCATION(ContraptionRelocationPacket.class, ContraptionRelocationPacket::new, PLAY_TO_CLIENT), + TRACK_GRAPH_ROLL_CALL(TrackGraphRollCallPacket.class, TrackGraphRollCallPacket::new, PLAY_TO_CLIENT), + UPDATE_ELEVATOR_FLOORS(ElevatorFloorListPacket.class, ElevatorFloorListPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_ACTOR_TOGGLE(ContraptionDisableActorPacket.class, ContraptionDisableActorPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_COLLIDER_LOCK(ContraptionColliderLockPacket.class, ContraptionColliderLockPacket::new, PLAY_TO_CLIENT), + ATTACHED_COMPUTER(AttachedComputerPacket.class, AttachedComputerPacket::new, PLAY_TO_CLIENT), + + ; + + static { + ClientboundSimpleActionPacket.addAction("rainbowDebug", () -> SimpleCreateActions::rainbowDebug); + ClientboundSimpleActionPacket.addAction("overlayReset", () -> SimpleCreateActions::overlayReset); + ClientboundSimpleActionPacket.addAction("overlayScreen", () -> SimpleCreateActions::overlayScreen); + ClientboundSimpleActionPacket.addAction("experimentalLighting", () -> SimpleCreateActions::experimentalLighting); + ClientboundSimpleActionPacket.addAction("fabulousWarning", () -> SimpleCreateActions::fabulousWarning); + ClientboundSimpleActionPacket.addAction("zoomMultiplier", () -> SimpleCreateActions::zoomMultiplier); + ClientboundSimpleActionPacket.addAction("camAngleYawTarget", () -> value -> SimpleCreateActions.camAngleTarget(value, true)); + ClientboundSimpleActionPacket.addAction("camAnglePitchTarget", () -> value -> SimpleCreateActions.camAngleTarget(value, false)); + ClientboundSimpleActionPacket.addAction("camAngleFunction", () -> SimpleCreateActions::camAngleFunction); + } + + public static final ResourceLocation CHANNEL_NAME = Create.asResource("main"); + public static final int NETWORK_VERSION = 3; + public static final String NETWORK_VERSION_STR = String.valueOf(NETWORK_VERSION); + private static SimpleChannel channel; + + private PacketType packetType; + + AllPackets(Class type, Function factory, + NetworkDirection direction) { + packetType = new PacketType<>(type, factory, direction); + } + + public static void registerPackets() { + channel = NetworkRegistry.ChannelBuilder.named(CHANNEL_NAME) + .serverAcceptedVersions(NETWORK_VERSION_STR::equals) + .clientAcceptedVersions(NETWORK_VERSION_STR::equals) + .networkProtocolVersion(() -> NETWORK_VERSION_STR) + .simpleChannel(); + + for (AllPackets packet : values()) + packet.packetType.register(); + } + + public static SimpleChannel getChannel() { + return channel; + } + + public static void sendToNear(Level world, BlockPos pos, int range, Object message) { + getChannel().send( + PacketDistributor.NEAR.with(TargetPoint.p(pos.getX(), pos.getY(), pos.getZ(), range, world.dimension())), + message); + } + + private static class PacketType { + private static int index = 0; + + private BiConsumer encoder; + private Function decoder; + private BiConsumer> handler; + private Class type; + private NetworkDirection direction; + + private PacketType(Class type, Function factory, NetworkDirection direction) { + encoder = T::write; + decoder = factory; + handler = (packet, contextSupplier) -> { + Context context = contextSupplier.get(); + if (packet.handle(context)) { + context.setPacketHandled(true); + } + }; + this.type = type; + this.direction = direction; + } + + private void register() { + getChannel().messageBuilder(type, index++, direction) + .encoder(encoder) + .decoder(decoder) + .consumer(handler) + .add(); + } + } + +} diff --git a/src/main/java/com/simibubi/create/AllPartialModels.java b/src/main/java/com/simibubi/create/AllPartialModels.java new file mode 100644 index 0000000000..0cc6dcec0c --- /dev/null +++ b/src/main/java/com/simibubi/create/AllPartialModels.java @@ -0,0 +1,233 @@ +package com.simibubi.create; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.DyeColor; + +public class AllPartialModels { + + public static final PartialModel + + SCHEMATICANNON_CONNECTOR = block("schematicannon/connector"), SCHEMATICANNON_PIPE = block("schematicannon/pipe"), + + SHAFTLESS_COGWHEEL = block("cogwheel_shaftless"), SHAFTLESS_LARGE_COGWHEEL = block("large_cogwheel_shaftless"), + COGWHEEL_SHAFT = block("cogwheel_shaft"), SHAFT_HALF = block("shaft_half"), + + BELT_PULLEY = block("belt_pulley"), BELT_START = block("belt/start"), BELT_MIDDLE = block("belt/middle"), + BELT_END = block("belt/end"), BELT_START_BOTTOM = block("belt/start_bottom"), + BELT_MIDDLE_BOTTOM = block("belt/middle_bottom"), BELT_END_BOTTOM = block("belt/end_bottom"), + BELT_DIAGONAL_START = block("belt/diagonal_start"), BELT_DIAGONAL_MIDDLE = block("belt/diagonal_middle"), + BELT_DIAGONAL_END = block("belt/diagonal_end"), + ANDESITE_BELT_COVER_X = block("belt_cover/andesite_belt_cover_x"), + BRASS_BELT_COVER_X = block("belt_cover/brass_belt_cover_x"), + ANDESITE_BELT_COVER_Z = block("belt_cover/andesite_belt_cover_z"), + BRASS_BELT_COVER_Z = block("belt_cover/brass_belt_cover_z"), + + ENCASED_FAN_INNER = block("encased_fan/propeller"), HAND_CRANK_HANDLE = block("hand_crank/handle"), + MECHANICAL_PRESS_HEAD = block("mechanical_press/head"), MECHANICAL_MIXER_POLE = block("mechanical_mixer/pole"), + MECHANICAL_MIXER_HEAD = block("mechanical_mixer/head"), + MECHANICAL_CRAFTER_LID = block("mechanical_crafter/lid"), + MECHANICAL_CRAFTER_ARROW = block("mechanical_crafter/arrow"), + MECHANICAL_CRAFTER_BELT_FRAME = block("mechanical_crafter/belt"), + MECHANICAL_CRAFTER_BELT = block("mechanical_crafter/belt_animated"), + SAW_BLADE_HORIZONTAL_ACTIVE = block("mechanical_saw/blade_horizontal_active"), + SAW_BLADE_HORIZONTAL_INACTIVE = block("mechanical_saw/blade_horizontal_inactive"), + SAW_BLADE_HORIZONTAL_REVERSED = block("mechanical_saw/blade_horizontal_reversed"), + SAW_BLADE_VERTICAL_ACTIVE = block("mechanical_saw/blade_vertical_active"), + SAW_BLADE_VERTICAL_INACTIVE = block("mechanical_saw/blade_vertical_inactive"), + SAW_BLADE_VERTICAL_REVERSED = block("mechanical_saw/blade_vertical_reversed"), GAUGE_DIAL = block("gauge/dial"), + GAUGE_INDICATOR = block("gauge/indicator"), GAUGE_HEAD_SPEED = block("gauge/speedometer/head"), + GAUGE_HEAD_STRESS = block("gauge/stressometer/head"), BEARING_TOP = block("bearing/top"), + BEARING_TOP_WOODEN = block("bearing/top_wooden"), DRILL_HEAD = block("mechanical_drill/head"), + HARVESTER_BLADE = block("mechanical_harvester/blade"), DEPLOYER_POLE = block("deployer/pole"), + DEPLOYER_HAND_POINTING = block("deployer/hand_pointing"), + DEPLOYER_HAND_PUNCHING = block("deployer/hand_punching"), + DEPLOYER_HAND_HOLDING = block("deployer/hand_holding"), ANALOG_LEVER_HANDLE = block("analog_lever/handle"), + ANALOG_LEVER_INDICATOR = block("analog_lever/indicator"), FUNNEL_FLAP = block("funnel/flap"), + BELT_FUNNEL_FLAP = block("belt_funnel/flap"), BELT_TUNNEL_FLAP = block("belt_tunnel/flap"), + FLEXPEATER_INDICATOR = block("diodes/indicator"), + + ROLLER_WHEEL = block("mechanical_roller/wheel"), + ROLLER_FRAME = block("mechanical_roller/frame"), + + CUCKOO_MINUTE_HAND = block("cuckoo_clock/minute_hand"), CUCKOO_HOUR_HAND = block("cuckoo_clock/hour_hand"), + CUCKOO_LEFT_DOOR = block("cuckoo_clock/left_door"), CUCKOO_RIGHT_DOOR = block("cuckoo_clock/right_door"), + CUCKOO_PIG = block("cuckoo_clock/pig"), CUCKOO_CREEPER = block("cuckoo_clock/creeper"), + + GANTRY_COGS = block("gantry_carriage/wheels"), + + ROPE_COIL = block("rope_pulley/rope_coil"), ROPE_HALF = block("rope_pulley/rope_half"), + ROPE_HALF_MAGNET = block("rope_pulley/rope_half_magnet"), + + HOSE_COIL = block("hose_pulley/rope_coil"), HOSE = block("hose_pulley/rope"), + HOSE_MAGNET = block("hose_pulley/pulley_magnet"), HOSE_HALF = block("hose_pulley/rope_half"), + HOSE_HALF_MAGNET = block("hose_pulley/rope_half_magnet"), + + ELEVATOR_COIL = block("elevator_pulley/rope_coil"), ELEVATOR_MAGNET = block("elevator_pulley/pulley_magnet"), + ELEVATOR_BELT = block("elevator_pulley/rope"), ELEVATOR_BELT_HALF = block("elevator_pulley/rope_half"), + + MILLSTONE_COG = block("millstone/inner"), + + SYMMETRY_PLANE = block("symmetry_effect/plane"), SYMMETRY_CROSSPLANE = block("symmetry_effect/crossplane"), + SYMMETRY_TRIPLEPLANE = block("symmetry_effect/tripleplane"), + + STICKER_HEAD = block("sticker/head"), + + PORTABLE_STORAGE_INTERFACE_MIDDLE = block("portable_storage_interface/block_middle"), + PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED = block("portable_storage_interface/block_middle_powered"), + PORTABLE_STORAGE_INTERFACE_TOP = block("portable_storage_interface/block_top"), + + PORTABLE_FLUID_INTERFACE_MIDDLE = block("portable_fluid_interface/block_middle"), + PORTABLE_FLUID_INTERFACE_MIDDLE_POWERED = block("portable_fluid_interface/block_middle_powered"), + PORTABLE_FLUID_INTERFACE_TOP = block("portable_fluid_interface/block_top"), + + ARM_COG = block("mechanical_arm/cog"), ARM_BASE = block("mechanical_arm/base"), + ARM_LOWER_BODY = block("mechanical_arm/lower_body"), ARM_UPPER_BODY = block("mechanical_arm/upper_body"), + ARM_CLAW_BASE = block("mechanical_arm/claw_base"), + ARM_CLAW_BASE_GOGGLES = block("mechanical_arm/claw_base_goggles"), + ARM_CLAW_GRIP_UPPER = block("mechanical_arm/upper_claw_grip"), + ARM_CLAW_GRIP_LOWER = block("mechanical_arm/lower_claw_grip"), + + MECHANICAL_PUMP_COG = block("mechanical_pump/cog"), + FLUID_PIPE_CASING = block("fluid_pipe/casing"), FLUID_VALVE_POINTER = block("fluid_valve/pointer"), + + SPOUT_TOP = block("spout/top"), SPOUT_MIDDLE = block("spout/middle"), SPOUT_BOTTOM = block("spout/bottom"), + + PECULIAR_BELL = block("peculiar_bell"), HAUNTED_BELL = block("haunted_bell"), + + TOOLBOX_DRAWER = block("toolbox/drawer"), + + SPEED_CONTROLLER_BRACKET = block("rotation_speed_controller/bracket"), + + GOGGLES = block("goggles"), + + EJECTOR_TOP = block("weighted_ejector/top"), + + COPPER_BACKTANK_SHAFT = block("copper_backtank/block_shaft_input"), + COPPER_BACKTANK_COGS = block("copper_backtank/block_cogs"), + + NETHERITE_BACKTANK_SHAFT = block("netherite_backtank/block_shaft_input"), + NETHERITE_BACKTANK_COGS = block("netherite_backtank/block_cogs"), + + TRACK_SEGMENT_LEFT = block("track/segment_left"), TRACK_SEGMENT_RIGHT = block("track/segment_right"), + TRACK_TIE = block("track/tie"), GIRDER_SEGMENT_TOP = block("metal_girder/segment_top"), + GIRDER_SEGMENT_MIDDLE = block("metal_girder/segment_middle"), + GIRDER_SEGMENT_BOTTOM = block("metal_girder/segment_bottom"), + + TRACK_STATION_OVERLAY = block("track_overlay/station"), TRACK_SIGNAL_OVERLAY = block("track_overlay/signal"), + TRACK_ASSEMBLING_OVERLAY = block("track_overlay/assembling"), + TRACK_SIGNAL_DUAL_OVERLAY = block("track_overlay/signal_dual"), + TRACK_OBSERVER_OVERLAY = block("track_overlay/observer"), + + BOGEY_FRAME = block("track/bogey/bogey_frame"), SMALL_BOGEY_WHEELS = block("track/bogey/bogey_wheel"), + BOGEY_PIN = block("track/bogey/bogey_drive_wheel_pin"), BOGEY_PISTON = block("track/bogey/bogey_drive_piston"), + BOGEY_DRIVE = block("track/bogey/bogey_drive"), LARGE_BOGEY_WHEELS = block("track/bogey/bogey_drive_wheel"), + + TRAIN_COUPLING_HEAD = block("track/bogey/coupling_head"), + TRAIN_COUPLING_CABLE = block("track/bogey/coupling_cable"), + + TRAIN_CONTROLS_COVER = block("controls/train/cover"), TRAIN_CONTROLS_LEVER = block("controls/train/lever"), + CONTRAPTION_CONTROLS_BUTTON = block("contraption_controls/button"), + + ENGINE_PISTON = block("steam_engine/piston"), ENGINE_LINKAGE = block("steam_engine/linkage"), + ENGINE_CONNECTOR = block("steam_engine/shaft_connector"), BOILER_GAUGE = block("steam_engine/gauge"), + BOILER_GAUGE_DIAL = block("steam_engine/gauge_dial"), + + SIGNAL_ON = block("track_signal/indicator_on"), SIGNAL_OFF = block("track_signal/indicator_off"), + DISPLAY_LINK_TUBE = block("display_link/tube"), DISPLAY_LINK_GLOW = block("display_link/glow"), + + STATION_ON = block("track_station/flag_on"), STATION_OFF = block("track_station/flag_off"), + STATION_ASSEMBLE = block("track_station/flag_assemble"), + + SIGNAL_PANEL = block("track_signal/panel"), SIGNAL_WHITE_CUBE = block("track_signal/white_cube"), + SIGNAL_WHITE_GLOW = block("track_signal/white_glow"), SIGNAL_WHITE = block("track_signal/white_tube"), + SIGNAL_RED_CUBE = block("track_signal/red_cube"), SIGNAL_RED_GLOW = block("track_signal/red_glow"), + SIGNAL_RED = block("track_signal/red_tube"), SIGNAL_YELLOW_CUBE = block("track_signal/yellow_cube"), + SIGNAL_YELLOW_GLOW = block("track_signal/yellow_glow"), SIGNAL_YELLOW = block("track_signal/yellow_tube"), + + BLAZE_INERT = block("blaze_burner/blaze/inert"), BLAZE_SUPER_ACTIVE = block("blaze_burner/blaze/super_active"), + BLAZE_GOGGLES = block("blaze_burner/goggles"), BLAZE_GOGGLES_SMALL = block("blaze_burner/goggles_small"), + BLAZE_IDLE = block("blaze_burner/blaze/idle"), BLAZE_ACTIVE = block("blaze_burner/blaze/active"), + BLAZE_SUPER = block("blaze_burner/blaze/super"), BLAZE_BURNER_FLAME = block("blaze_burner/flame"), + BLAZE_BURNER_RODS = block("blaze_burner/rods_small"), + BLAZE_BURNER_RODS_2 = block("blaze_burner/rods_large"), + BLAZE_BURNER_SUPER_RODS = block("blaze_burner/superheated_rods_small"), + BLAZE_BURNER_SUPER_RODS_2 = block("blaze_burner/superheated_rods_large"), + + WHISTLE_MOUTH_LARGE = block("steam_whistle/large_mouth"), + WHISTLE_MOUTH_MEDIUM = block("steam_whistle/medium_mouth"), + WHISTLE_MOUTH_SMALL = block("steam_whistle/small_mouth"), + + WATER_WHEEL = block("water_wheel/wheel"), + LARGE_WATER_WHEEL = block("large_water_wheel/block"), + LARGE_WATER_WHEEL_EXTENSION = block("large_water_wheel/block_extension"), + + CRAFTING_BLUEPRINT_1x1 = entity("crafting_blueprint_small"), + CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"), + CRAFTING_BLUEPRINT_3x3 = entity("crafting_blueprint_large"), + + TRAIN_HAT = entity("train_hat"), + + COUPLING_ATTACHMENT = entity("minecart_coupling/attachment"), COUPLING_RING = entity("minecart_coupling/ring"), + COUPLING_CONNECTOR = entity("minecart_coupling/connector") + + ; + + public static final Map> PIPE_ATTACHMENTS = + new EnumMap<>(FluidTransportBehaviour.AttachmentTypes.ComponentPartials.class); + + public static final Map METAL_GIRDER_BRACKETS = new EnumMap<>(Direction.class); + public static final Map TOOLBOX_LIDS = new EnumMap<>(DyeColor.class); + public static final Map> FOLDING_DOORS = new HashMap<>(); + public static final List CONTRAPTION_CONTROLS_INDICATOR = new ArrayList<>(); + + static { + for (FluidTransportBehaviour.AttachmentTypes.ComponentPartials type : FluidTransportBehaviour.AttachmentTypes.ComponentPartials.values()) { + Map map = new HashMap<>(); + for (Direction d : Iterate.directions) { + String asId = Lang.asId(type.name()); + map.put(d, block("fluid_pipe/" + asId + "/" + Lang.asId(d.getSerializedName()))); + } + PIPE_ATTACHMENTS.put(type, map); + } + for (DyeColor color : DyeColor.values()) + TOOLBOX_LIDS.put(color, block("toolbox/lid/" + Lang.asId(color.name()))); + for (Direction d : Iterate.horizontalDirections) + METAL_GIRDER_BRACKETS.put(d, block("metal_girder/bracket_" + Lang.asId(d.name()))); + for (int i = 0; i < 8; i++) + CONTRAPTION_CONTROLS_INDICATOR.add(block("contraption_controls/indicator_" + i)); + + putFoldingDoor("andesite_door"); + putFoldingDoor("copper_door"); + } + + private static void putFoldingDoor(String path) { + FOLDING_DOORS.put(Create.asResource(path), + Couple.create(block(path + "/fold_left"), block(path + "/fold_right"))); + } + + private static PartialModel block(String path) { + return new PartialModel(Create.asResource("block/" + path)); + } + + private static PartialModel entity(String path) { + return new PartialModel(Create.asResource("entity/" + path)); + } + + public static void init() { + // init static fields + } + +} diff --git a/src/main/java/com/simibubi/create/AllParticleTypes.java b/src/main/java/com/simibubi/create/AllParticleTypes.java index df0331d3ed..7a192fa917 100644 --- a/src/main/java/com/simibubi/create/AllParticleTypes.java +++ b/src/main/java/com/simibubi/create/AllParticleTypes.java @@ -2,16 +2,15 @@ package com.simibubi.create; import java.util.function.Supplier; -import com.simibubi.create.content.contraptions.components.steam.SteamJetParticleData; -import com.simibubi.create.content.contraptions.fluids.particle.FluidParticleData; -import com.simibubi.create.content.contraptions.particle.AirFlowParticleData; -import com.simibubi.create.content.contraptions.particle.AirParticleData; -import com.simibubi.create.content.contraptions.particle.CubeParticleData; -import com.simibubi.create.content.contraptions.particle.HeaterParticleData; -import com.simibubi.create.content.contraptions.particle.ICustomParticleData; -import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData; -import com.simibubi.create.content.curiosities.bell.SoulBaseParticle; -import com.simibubi.create.content.curiosities.bell.SoulParticle; +import com.simibubi.create.content.equipment.bell.SoulBaseParticle; +import com.simibubi.create.content.equipment.bell.SoulParticle; +import com.simibubi.create.content.fluids.particle.FluidParticleData; +import com.simibubi.create.content.kinetics.base.RotationIndicatorParticleData; +import com.simibubi.create.content.kinetics.fan.AirFlowParticleData; +import com.simibubi.create.content.kinetics.steamEngine.SteamJetParticleData; +import com.simibubi.create.content.trains.CubeParticleData; +import com.simibubi.create.foundation.particle.AirParticleData; +import com.simibubi.create.foundation.particle.ICustomParticleData; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.client.Minecraft; @@ -32,7 +31,6 @@ public enum AllParticleTypes { AIR_FLOW(AirFlowParticleData::new), AIR(AirParticleData::new), STEAM_JET(SteamJetParticleData::new), - HEATER_PARTICLE(HeaterParticleData::new), CUBE(CubeParticleData::new), FLUID_PARTICLE(FluidParticleData::new), BASIN_FLUID(FluidParticleData::new), diff --git a/src/main/java/com/simibubi/create/AllRecipeTypes.java b/src/main/java/com/simibubi/create/AllRecipeTypes.java index 114238f7dd..e9dd26f95f 100644 --- a/src/main/java/com/simibubi/create/AllRecipeTypes.java +++ b/src/main/java/com/simibubi/create/AllRecipeTypes.java @@ -8,26 +8,26 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableSet; import com.simibubi.create.compat.jei.ConversionRecipe; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe; -import com.simibubi.create.content.contraptions.components.crusher.CrushingRecipe; -import com.simibubi.create.content.contraptions.components.deployer.DeployerApplicationRecipe; -import com.simibubi.create.content.contraptions.components.deployer.ManualApplicationRecipe; -import com.simibubi.create.content.contraptions.components.fan.HauntingRecipe; -import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe; -import com.simibubi.create.content.contraptions.components.millstone.MillingRecipe; -import com.simibubi.create.content.contraptions.components.mixer.CompactingRecipe; -import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe; -import com.simibubi.create.content.contraptions.components.press.PressingRecipe; -import com.simibubi.create.content.contraptions.components.saw.CuttingRecipe; -import com.simibubi.create.content.contraptions.fluids.actors.FillingRecipe; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipeSerializer; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.EmptyingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; -import com.simibubi.create.content.curiosities.toolbox.ToolboxDyeingRecipe; -import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe; -import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo; +import com.simibubi.create.content.equipment.sandPaper.SandPaperPolishingRecipe; +import com.simibubi.create.content.equipment.toolbox.ToolboxDyeingRecipe; +import com.simibubi.create.content.fluids.transfer.EmptyingRecipe; +import com.simibubi.create.content.fluids.transfer.FillingRecipe; +import com.simibubi.create.content.kinetics.crafter.MechanicalCraftingRecipe; +import com.simibubi.create.content.kinetics.crusher.CrushingRecipe; +import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe; +import com.simibubi.create.content.kinetics.deployer.ManualApplicationRecipe; +import com.simibubi.create.content.kinetics.fan.HauntingRecipe; +import com.simibubi.create.content.kinetics.fan.SplashingRecipe; +import com.simibubi.create.content.kinetics.millstone.MillingRecipe; +import com.simibubi.create.content.kinetics.mixer.CompactingRecipe; +import com.simibubi.create.content.kinetics.mixer.MixingRecipe; +import com.simibubi.create.content.kinetics.press.PressingRecipe; +import com.simibubi.create.content.kinetics.saw.CuttingRecipe; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeFactory; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeSerializer; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipeSerializer; +import com.simibubi.create.foundation.recipe.IRecipeTypeInfo; import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.utility.lang.Lang; diff --git a/src/main/java/com/simibubi/create/AllShapes.java b/src/main/java/com/simibubi/create/AllShapes.java index c30d3f575a..a093d97992 100644 --- a/src/main/java/com/simibubi/create/AllShapes.java +++ b/src/main/java/com/simibubi/create/AllShapes.java @@ -7,8 +7,8 @@ import static net.minecraft.core.Direction.UP; import java.util.function.BiFunction; -import com.simibubi.create.content.logistics.block.chute.ChuteShapes; -import com.simibubi.create.content.logistics.trains.track.TrackVoxelShapes; +import com.simibubi.create.content.logistics.chute.ChuteShapes; +import com.simibubi.create.content.trains.track.TrackVoxelShapes; import net.createmod.catnip.utility.VoxelShaper; import net.minecraft.core.Direction; @@ -30,6 +30,8 @@ public class AllShapes { CASING_13PX = shape(0, 0, 0, 16, 13, 16).forDirectional(), CASING_12PX = shape(0, 0, 0, 16, 12, 16).forDirectional(), CASING_11PX = shape(0, 0, 0, 16, 11, 16).forDirectional(), + CASING_3PX = shape(0, 0, 0, 16, 3, 16).forDirectional(), + CASING_2PX = shape(0, 0, 0, 16, 2, 16).forDirectional(), MOTOR_BLOCK = shape(3, 0, 3, 13, 14, 13).forDirectional(), FOUR_VOXEL_POLE = shape(6, 0, 6, 10, 16, 10).forAxis(), SIX_VOXEL_POLE = shape(5, 0, 5, 11, 16, 11).forAxis(), @@ -41,15 +43,21 @@ public class AllShapes { .add(2, 13, 2, 14, 16, 14) .add(0, 0, 14, 16, 16, 16) .forHorizontalAxis(), + ELEVATOR_PULLEY = shape(0, 0, 0, 16, 16, 2).add(0, 0, 14, 16, 16, 16) + .add(2, 0, 2, 14, 14, 14) + .forHorizontal(EAST), SAIL_FRAME_COLLISION = shape(0, 5, 0, 16, 9, 16).erase(2, 0, 2, 14, 16, 14) .forDirectional(), SAIL_FRAME = shape(0, 5, 0, 16, 9, 16).forDirectional(), SAIL = shape(0, 5, 0, 16, 10, 16).forDirectional(), HARVESTER_BASE = shape(0, 2, 0, 16, 14, 3).forDirectional(SOUTH), + ROLLER_BASE = shape(0, 0, 0, 16, 16, 10).forDirectional(SOUTH), NOZZLE = shape(2, 0, 2, 14, 14, 14).add(1, 13, 1, 15, 15, 15) .erase(3, 13, 3, 13, 15, 13) .forDirectional(), CRANK = shape(5, 0, 5, 11, 6, 11).add(1, 3, 1, 15, 8, 15) .forDirectional(), + VALVE_HANDLE = shape(5, 0, 5, 11, 4, 11).add(1, 3, 1, 15, 8, 15) + .forDirectional(), CART_ASSEMBLER = shape(0, 12, 0, 16, 16, 16).add(-2, 0, 1, 18, 14, 15) .forHorizontalAxis(), CART_ASSEMBLER_PLAYER_COLLISION = shape(0, 0, 1, 16, 16, 15).forHorizontalAxis(), @@ -104,7 +112,7 @@ public class AllShapes { .add(5, -1, 6, 11, 0, 8) .forHorizontal(SOUTH), PUMP = shape(2, 0, 2, 14, 5, 14).add(4, 0, 4, 12, 16, 12) - .add(3, 12, 3, 13, 16, 13) + .add(3, 11, 3, 13, 16, 13) .forDirectional(Direction.UP), CRUSHING_WHEEL_CONTROLLER_COLLISION = shape(0, 0, 0, 16, 13, 16).forDirectional(Direction.DOWN), @@ -121,7 +129,14 @@ public class AllShapes { GIRDER_BEAM_SHAFT = shape(GIRDER_BEAM.get(Axis.X)).add(SIX_VOXEL_POLE.get(Axis.Z)) .forHorizontalAxis(), + STEP_BOTTOM = shape(0, 0, 8, 16, 8, 16).forHorizontal(SOUTH), + STEP_TOP = shape(0, 8, 8, 16, 16, 16).forHorizontal(SOUTH), + CONTROLS = shape(0, 0, 6, 16, 14, 16).forHorizontal(NORTH), + CONTRAPTION_CONTROLS = shape(0, 0, 6, 2, 14, 16).add(14, 0, 6, 16, 14, 16) + .add(0, 0, 14, 16, 14, 16) + .add(0, 0, 7, 16, 10, 16) + .forHorizontal(NORTH), NIXIE_TUBE = shape(9, 0, 5, 15, 12, 11).add(1, 0, 5, 7, 12, 11) .forHorizontalAxis(), @@ -147,11 +162,18 @@ public class AllShapes { PLACARD = shape(2, 0, 2, 14, 3, 14).forDirectional(UP), + CLIPBOARD_FLOOR = shape(3, 0, 1, 13, 1, 15).forHorizontal(SOUTH), + CLIPBOARD_CEILING = shape(3, 15, 1, 13, 16, 15).forHorizontal(SOUTH), + CLIPBOARD_WALL = shape(3, 1, 0, 13, 15, 1).forHorizontal(SOUTH), + TRACK_ORTHO = shape(TrackVoxelShapes.orthogonal()).forHorizontal(NORTH), TRACK_ASC = shape(TrackVoxelShapes.ascending()).forHorizontal(SOUTH), TRACK_DIAG = shape(TrackVoxelShapes.diagonal()).forHorizontal(SOUTH), TRACK_ORTHO_LONG = shape(TrackVoxelShapes.longOrthogonalZOffset()).forHorizontal(SOUTH), + DEPLOYER_INTERACTION = shape(CASING_12PX.get(UP)).add(SIX_VOXEL_POLE.get(Axis.Y)) + .forDirectional(UP), + WHISTLE_BASE = shape(1, 0, 1, 15, 3, 15).add(5, 0, 5, 11, 8, 11) .forDirectional(UP) @@ -181,9 +203,15 @@ public class AllShapes { // Static Block Shapes public static final VoxelShape - TRACK_CROSS = shape(TRACK_ORTHO.get(SOUTH)).add(TRACK_ORTHO.get(EAST)) + SCAFFOLD_HALF = shape(0, 8, 0, 16, 16, 16).build(), SCAFFOLD_FULL = shape(SCAFFOLD_HALF).add(0, 0, 0, 2, 16, 2) + .add(0, 0, 14, 2, 16, 16) + .add(14, 0, 0, 16, 16, 2) + .add(14, 0, 14, 16, 16, 16) .build(), + TRACK_CROSS = shape(TRACK_ORTHO.get(SOUTH)).add(TRACK_ORTHO.get(EAST)) + .build(), + TRACK_CROSS_DIAG = shape(TRACK_DIAG.get(SOUTH)).add(TRACK_DIAG.get(EAST)) .build(), @@ -210,7 +238,7 @@ public class AllShapes { HEATER_BLOCK_SHAPE = shape(1, 0, 1, 15, 14, 15).build(), HEATER_BLOCK_SPECIAL_COLLISION_SHAPE = shape(0, 0, 0, 16, 4, 16).build(), CRUSHING_WHEEL_COLLISION_SHAPE = cuboid(0, 0, 0, 16, 16, 16), SEAT = cuboid(0, 0, 0, 16, 8, 16), - SEAT_COLLISION = cuboid(0, 0, 0, 16, 6, 16), + SEAT_COLLISION = cuboid(0, 0, 0, 16, 6, 16), SEAT_COLLISION_PLAYERS = cuboid(0, 0, 0, 16, 3, 16), MECHANICAL_PROCESSOR_SHAPE = shape(Shapes.block()).erase(4, 0, 4, 12, 16, 12) .build(), TURNTABLE_SHAPE = shape(1, 4, 1, 15, 8, 15).add(5, 0, 5, 11, 4, 11) @@ -221,12 +249,11 @@ public class AllShapes { BELT_COLLISION_MASK = cuboid(0, 0, 0, 16, 19, 16), SCHEMATICANNON_SHAPE = shape(1, 0, 1, 15, 8, 15).add(0.5, 8, 0.5, 15.5, 11, 15.5) .build(), - PULLEY_MAGNET = shape(3, 0, 3, 13, 2, 13).add(FOUR_VOXEL_POLE.get(UP)) + PULLEY_MAGNET = shape(3, 0, 3, 13, 3, 13).add(FOUR_VOXEL_POLE.get(UP)) .build(), SPOUT = shape(1, 2, 1, 15, 14, 15).add(2, 0, 2, 14, 16, 14) .build(), - MILLSTONE = shape(0, 0, 0, 16, 6, 16).add(2, 6, 2, 14, 13, 14) - .add(3, 13, 3, 13, 16, 13) + MILLSTONE = shape(0, 0, 0, 16, 6, 16).add(2, 6, 2, 14, 16, 14) .build(), CUCKOO_CLOCK = shape(1, 0, 1, 15, 19, 15).build(), GAUGE_SHAPE_UP = shape(1, 0, 0, 15, 2, 16).add(2, 2, 1, 14, 14, 15) @@ -239,9 +266,6 @@ public class AllShapes { .build(), CHUTE = shape(1, 8, 1, 15, 16, 15).add(2, 0, 2, 14, 8, 14) .build(), - SMART_CHUTE = shape(0, 0, 0, 16, 5, 16).add(0, 9, 0, 16, 15, 16) - .add(1, 0, 1, 15, 16, 15) - .build(), TANK = shape(1, 0, 1, 15, 16, 15).build(), TANK_TOP = shape(TANK_TOP_LID).add(TANK) .build(), TANK_BOTTOM = shape(TANK_BOTTOM_LID).add(TANK) @@ -255,8 +279,6 @@ public class AllShapes { FUNNEL_CEILING = shape(2, 8, 2, 14, 18, 14).add(1, 8, 1, 15, 15, 15) .add(0, 6, 0, 16, 12, 16) .build(), - DEPOT = shape(CASING_11PX.get(Direction.UP)).add(1, 11, 1, 15, 13, 15) - .build(), STATION = shape(0, 0, 0, 16, 2, 16).add(1, 0, 1, 15, 13, 15) .build(), diff --git a/src/main/java/com/simibubi/create/AllSpriteShifts.java b/src/main/java/com/simibubi/create/AllSpriteShifts.java index e5eb174c3e..35b4c8c614 100644 --- a/src/main/java/com/simibubi/create/AllSpriteShifts.java +++ b/src/main/java/com/simibubi/create/AllSpriteShifts.java @@ -25,8 +25,15 @@ public class AllSpriteShifts { public static final SpriteShiftEntry BURNER_FLAME = get("block/blaze_burner_flame", "block/blaze_burner_flame_scroll"), - SUPER_BURNER_FLAME = - get("block/blaze_burner_flame", "block/blaze_burner_flame_superheated_scroll"); + SUPER_BURNER_FLAME = get("block/blaze_burner_flame", "block/blaze_burner_flame_superheated_scroll"); + + public static final CTSpriteShiftEntry ANDESITE_SCAFFOLD = horizontal("scaffold/andesite_scaffold"), + BRASS_SCAFFOLD = horizontal("scaffold/brass_scaffold"), + COPPER_SCAFFOLD = horizontal("scaffold/copper_scaffold"); + + public static final CTSpriteShiftEntry ANDESITE_SCAFFOLD_INSIDE = horizontal("scaffold/andesite_scaffold_inside"), + BRASS_SCAFFOLD_INSIDE = horizontal("scaffold/brass_scaffold_inside"), + COPPER_SCAFFOLD_INSIDE = horizontal("scaffold/copper_scaffold_inside"); public static final CTSpriteShiftEntry FRAMED_GLASS = getCT(AllCTTypes.OMNIDIRECTIONAL, "palettes/framed_glass", "palettes/framed_glass"), @@ -35,8 +42,8 @@ public class AllSpriteShifts { VERTICAL_FRAMED_GLASS = getCT(AllCTTypes.VERTICAL, "palettes/framed_glass", "palettes/vertical_framed_glass"), ORNATE_IRON_WINDOW = vertical("palettes/ornate_iron_window"); - public static final CTSpriteShiftEntry CRAFTER_FRONT = getCT(AllCTTypes.OMNIDIRECTIONAL, "crafter_top", "brass_casing"), - CRAFTER_SIDE = vertical("crafter_side"), CRAFTER_OTHERSIDE = horizontal("crafter_side"), + public static final CTSpriteShiftEntry CRAFTER_SIDE = vertical("crafter_side"), + CRAFTER_OTHERSIDE = horizontal("crafter_side"), ANDESITE_ENCASED_COGWHEEL_SIDE = vertical("andesite_encased_cogwheel_side"), ANDESITE_ENCASED_COGWHEEL_OTHERSIDE = horizontal("andesite_encased_cogwheel_side"), BRASS_ENCASED_COGWHEEL_SIDE = vertical("brass_encased_cogwheel_side"), @@ -47,24 +54,29 @@ public class AllSpriteShifts { BRASS_CASING = omni("brass_casing"), COPPER_CASING = omni("copper_casing"), SHADOW_STEEL_CASING = omni("shadow_steel_casing"), REFINED_RADIANCE_CASING = omni("refined_radiance_casing"), RAILWAY_CASING = omni("railway_casing"), RAILWAY_CASING_SIDE = omni("railway_casing_side"), - CREATIVE_CASING = getCT(AllCTTypes.CROSS, "creative_casing"); + CREATIVE_CASING = getCT(AllCTTypes.RECTANGLE, "creative_casing"); public static final CTSpriteShiftEntry CHASSIS_SIDE = omni("linear_chassis_side"), SECONDARY_CHASSIS_SIDE = omni("secondary_linear_chassis_side"), CHASSIS = omni("linear_chassis_end"), CHASSIS_STICKY = omni("linear_chassis_end_sticky"); - public static final CTSpriteShiftEntry BRASS_TUNNEL_TOP = vertical("brass_tunnel_top"), - FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "fluid_tank"), FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "fluid_tank_top"), + public static final CTSpriteShiftEntry BRASS_TUNNEL_TOP = vertical("tunnel/brass_tunnel_top"), + FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "fluid_tank"), + FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "fluid_tank_top"), FLUID_TANK_INNER = getCT(AllCTTypes.RECTANGLE, "fluid_tank_inner"), - CREATIVE_FLUID_TANK = getCT(AllCTTypes.CROSS, "creative_fluid_tank"); + CREATIVE_FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "creative_fluid_tank"); public static final Couple VAULT_TOP = vault("top"), VAULT_FRONT = vault("front"), VAULT_SIDE = vault("side"), VAULT_BOTTOM = vault("bottom"); + public static final SpriteShiftEntry ELEVATOR_BELT = + get("block/elevator_pulley_belt", "block/elevator_pulley_belt_scroll"), + ELEVATOR_COIL = get("block/elevator_pulley_coil", "block/elevator_pulley_coil_scroll"); + public static final SpriteShiftEntry BELT = get("block/belt", "block/belt_scroll"), BELT_OFFSET = get("block/belt_offset", "block/belt_scroll"), BELT_DIAGONAL = get("block/belt_diagonal", "block/belt_diagonal_scroll"), - ANDESIDE_BELT_CASING = get("block/brass_casing_belt", "block/andesite_casing_belt"), + ANDESIDE_BELT_CASING = get("block/belt/brass_belt_casing", "block/belt/andesite_belt_casing"), CRAFTER_THINGIES = get("block/crafter_thingies", "block/crafter_thingies"); static { @@ -81,14 +93,15 @@ public class AllSpriteShifts { String id = color.getSerializedName(); DYED_BELTS.put(color, get("block/belt", "block/belt/" + id + "_scroll")); DYED_OFFSET_BELTS.put(color, get("block/belt_offset", "block/belt/" + id + "_scroll")); - DYED_DIAGONAL_BELTS.put(color, - get("block/belt_diagonal", "block/belt/" + id + "_diagonal_scroll")); + DYED_DIAGONAL_BELTS.put(color, get("block/belt_diagonal", "block/belt/" + id + "_diagonal_scroll")); } } private static Couple vault(String name) { - final String prefixed = "vault_" + name; - return Couple.createWithContext(b -> getCT(AllCTTypes.CROSS, prefixed, b ? prefixed : prefixed + "_large")); + final String prefixed = "block/vault/vault_" + name; + return Couple.createWithContext( + medium -> CTSpriteShifter.getCT(AllCTTypes.RECTANGLE, Create.asResource(prefixed + "_small"), + Create.asResource(medium ? prefixed + "_medium" : prefixed + "_large"))); } // @@ -112,7 +125,8 @@ public class AllSpriteShifts { } private static CTSpriteShiftEntry getCT(CTType type, String blockTextureName, String connectedTextureName) { - return CTSpriteShifter.getCT(type, Create.asResource("block/" + blockTextureName), Create.asResource("block/" + connectedTextureName + "_connected")); + return CTSpriteShifter.getCT(type, Create.asResource("block/" + blockTextureName), + Create.asResource("block/" + connectedTextureName + "_connected")); } private static CTSpriteShiftEntry getCT(CTType type, String blockTextureName) { diff --git a/src/main/java/com/simibubi/create/AllStitchedTextures.java b/src/main/java/com/simibubi/create/AllStitchedTextures.java deleted file mode 100644 index 5e8909404d..0000000000 --- a/src/main/java/com/simibubi/create/AllStitchedTextures.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.simibubi.create; - -import com.jozufozu.flywheel.core.StitchedSprite; - -public class AllStitchedTextures { - - public static final StitchedSprite SUPER_GLUE = new StitchedSprite(Create.asResource("entity/super_glue/slime")); - - public static void init() { - } -} diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index 8229939326..78993bf73c 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -2,44 +2,32 @@ package com.simibubi.create; import static com.simibubi.create.AllTags.NameSpace.FORGE; import static com.simibubi.create.AllTags.NameSpace.MOD; +import static com.simibubi.create.AllTags.NameSpace.QUARK; import static com.simibubi.create.AllTags.NameSpace.TIC; import java.util.Collections; -import com.simibubi.create.foundation.data.CreateRegistrate; -import com.simibubi.create.foundation.data.recipe.Mods; -import com.tterrag.registrate.builders.BlockBuilder; -import com.tterrag.registrate.builders.ItemBuilder; -import com.tterrag.registrate.providers.ProviderType; -import com.tterrag.registrate.util.nullness.NonNullFunction; - import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.data.tags.TagsProvider.TagAppender; +import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.common.Tags; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistryEntry; public class AllTags { - - private static final CreateRegistrate REGISTRATE = Create.registrate() - .creativeModeTab(() -> Create.BASE_CREATIVE_TAB); - public static > TagKey optionalTag(IForgeRegistry registry, ResourceLocation id) { return registry.tags() @@ -62,34 +50,12 @@ public class AllTags { return forgeTag(ForgeRegistries.FLUIDS, path); } - public static NonNullFunction, BlockBuilder> axeOrPickaxe() { - return b -> b.tag(BlockTags.MINEABLE_WITH_AXE) - .tag(BlockTags.MINEABLE_WITH_PICKAXE); - } - - public static NonNullFunction, BlockBuilder> axeOnly() { - return b -> b.tag(BlockTags.MINEABLE_WITH_AXE); - } - - public static NonNullFunction, BlockBuilder> pickaxeOnly() { - return b -> b.tag(BlockTags.MINEABLE_WITH_PICKAXE); - } - - public static NonNullFunction, ItemBuilder>> tagBlockAndItem( - String... path) { - return b -> { - for (String p : path) - b.tag(forgeBlockTag(p)); - ItemBuilder> item = b.item(); - for (String p : path) - item.tag(forgeItemTag(p)); - return item; - }; - } - public enum NameSpace { - MOD(Create.ID, false, true), FORGE("forge"), TIC("tconstruct"), QUARK("quark") + MOD(Create.ID, false, true), + FORGE("forge"), + TIC("tconstruct"), + QUARK("quark") ; @@ -106,7 +72,6 @@ public class AllTags { this.optionalDefault = optionalDefault; this.alwaysDatagenDefault = alwaysDatagenDefault; } - } public enum AllBlockTags { @@ -115,26 +80,32 @@ public class AllTags { CASING, FAN_TRANSPARENT, NON_MOVABLE, + MOVABLE_EMPTY_COLLIDER, ORE_OVERRIDE_STONE, PASSIVE_BOILER_HEATERS, SAFE_NBT, SEATS, TOOLBOXES, + TRACKS, + GIRDABLE_TRACKS, + TREE_ATTACHMENTS, VALVE_HANDLES, WINDMILL_SAILS, - WINDOWABLE, WRENCH_PICKUP, - TREE_ATTACHMENTS, + COPYCAT_ALLOW, + COPYCAT_DENY, + CONTRAPTION_INVENTORY_DENY, RELOCATION_NOT_SUPPORTED(FORGE), WG_STONE(FORGE), SLIMY_LOGS(TIC), - NON_DOUBLE_DOOR(NameSpace.QUARK), + NON_DOUBLE_DOOR(QUARK), ; public final TagKey tag; + public final boolean alwaysDatagen; AllBlockTags() { this(MOD); @@ -159,9 +130,7 @@ public class AllTags { } else { tag = BlockTags.create(id); } - if (alwaysDatagen) { - REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, prov -> prov.tag(tag)); - } + this.alwaysDatagen = alwaysDatagen; } @SuppressWarnings("deprecation") @@ -170,36 +139,15 @@ public class AllTags { .is(tag); } + public boolean matches(ItemStack stack) { + return stack != null && stack.getItem() instanceof BlockItem blockItem && matches(blockItem.getBlock()); + } + public boolean matches(BlockState state) { return state.is(tag); } - public void add(Block... values) { - REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, prov -> prov.tag(tag) - .add(values)); - } - - public void addOptional(Mods mod, String... ids) { - REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, prov -> { - TagAppender builder = prov.tag(tag); - for (String id : ids) - builder.addOptional(mod.asResource(id)); - }); - } - - public void includeIn(TagKey parent) { - REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, prov -> prov.tag(parent) - .addTag(tag)); - } - - public void includeIn(AllBlockTags parent) { - includeIn(parent.tag); - } - - public void includeAll(TagKey child) { - REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, prov -> prov.tag(tag) - .addTag(child)); - } + private static void init() {} } @@ -209,7 +157,9 @@ public class AllTags { BLAZE_BURNER_FUEL_SPECIAL(MOD, "blaze_burner_fuel/special"), CASING, CREATE_INGOTS, - CRUSHED_ORES, + CRUSHED_RAW_MATERIALS, + MODDED_STRIPPED_LOGS, + MODDED_STRIPPED_WOOD, PRESSURIZED_AIR_SOURCES, SANDPAPER, SEATS, @@ -219,18 +169,18 @@ public class AllTags { VALVE_HANDLES, VANILLA_STRIPPED_LOGS, VANILLA_STRIPPED_WOOD, - MODDED_STRIPPED_LOGS, - MODDED_STRIPPED_WOOD, + DEPLOYABLE_DRINK, + CONTRAPTION_CONTROLLED, STRIPPED_LOGS(FORGE), STRIPPED_WOOD(FORGE), - BEACON_PAYMENT(FORGE), PLATES(FORGE), WRENCH(FORGE, "tools/wrench") ; public final TagKey tag; + public final boolean alwaysDatagen; AllItemTags() { this(MOD); @@ -255,9 +205,7 @@ public class AllTags { } else { tag = ItemTags.create(id); } - if (alwaysDatagen) { - REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, prov -> prov.tag(tag)); - } + this.alwaysDatagen = alwaysDatagen; } @SuppressWarnings("deprecation") @@ -270,32 +218,7 @@ public class AllTags { return stack.is(tag); } - public void add(Item... values) { - REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, prov -> prov.tag(tag) - .add(values)); - } - - public void addOptional(Mods mod, String... ids) { - REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, prov -> { - TagAppender builder = prov.tag(tag); - for (String id : ids) - builder.addOptional(mod.asResource(id)); - }); - } - - public void includeIn(TagKey parent) { - REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, prov -> prov.tag(parent) - .addTag(tag)); - } - - public void includeIn(AllItemTags parent) { - includeIn(parent.tag); - } - - public void includeAll(TagKey child) { - REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, prov -> prov.tag(tag) - .addTag(child)); - } + private static void init() {} } @@ -309,6 +232,7 @@ public class AllTags { ; public final TagKey tag; + public final boolean alwaysDatagen; AllFluidTags() { this(MOD); @@ -333,9 +257,7 @@ public class AllTags { } else { tag = FluidTags.create(id); } - if (alwaysDatagen) { - REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, prov -> prov.tag(tag)); - } + this.alwaysDatagen = alwaysDatagen; } @SuppressWarnings("deprecation") @@ -347,123 +269,58 @@ public class AllTags { return state.is(tag); } - public void add(Fluid... values) { - REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, prov -> prov.tag(tag) - .add(values)); - } - - public void includeIn(TagKey parent) { - REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, prov -> prov.tag(parent) - .addTag(tag)); - } - - public void includeIn(AllFluidTags parent) { - includeIn(parent.tag); - } - - public void includeAll(TagKey child) { - REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, prov -> prov.tag(tag) - .addTag(child)); - } + private static void init() {} } - public static void register() { - AllFluidTags.BOTTOMLESS_ALLOW.add(Fluids.WATER, Fluids.LAVA); + public enum AllEntityTags { - AllItemTags.VANILLA_STRIPPED_LOGS.add(Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_BIRCH_LOG, - Items.STRIPPED_CRIMSON_STEM, Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_OAK_LOG, - Items.STRIPPED_SPRUCE_LOG, Items.STRIPPED_WARPED_STEM); + IGNORE_SEAT, - AllItemTags.VANILLA_STRIPPED_LOGS.includeIn(AllItemTags.STRIPPED_LOGS); + ; - AllItemTags.VANILLA_STRIPPED_WOOD.add(Items.STRIPPED_ACACIA_WOOD, Items.STRIPPED_BIRCH_WOOD, - Items.STRIPPED_CRIMSON_HYPHAE, Items.STRIPPED_DARK_OAK_WOOD, Items.STRIPPED_JUNGLE_WOOD, - Items.STRIPPED_OAK_WOOD, Items.STRIPPED_SPRUCE_WOOD, Items.STRIPPED_WARPED_HYPHAE); + public final TagKey> tag; + public final boolean alwaysDatagen; - AllItemTags.VANILLA_STRIPPED_WOOD.includeIn(AllItemTags.STRIPPED_WOOD); - - AllItemTags.CREATE_INGOTS.includeIn(AllItemTags.BEACON_PAYMENT); - AllItemTags.CREATE_INGOTS.includeIn(Tags.Items.INGOTS); - - AllItemTags.UPRIGHT_ON_BELT.add(Items.GLASS_BOTTLE, Items.POTION, Items.SPLASH_POTION, Items.LINGERING_POTION, - Items.HONEY_BOTTLE, Items.CAKE); - - AllItemTags.SLEEPERS.add(Items.STONE_SLAB, Items.SMOOTH_STONE_SLAB, Items.ANDESITE_SLAB); - - AllBlockTags.WINDMILL_SAILS.includeAll(BlockTags.WOOL); - - AllBlockTags.BRITTLE.includeAll(BlockTags.DOORS); - AllBlockTags.BRITTLE.includeAll(BlockTags.BEDS); - AllBlockTags.BRITTLE.add(Blocks.FLOWER_POT, Blocks.BELL, Blocks.COCOA); - - AllBlockTags.FAN_TRANSPARENT.includeAll(BlockTags.FENCES); - AllBlockTags.FAN_TRANSPARENT.includeAll(BlockTags.CAMPFIRES); - AllBlockTags.FAN_TRANSPARENT.add(Blocks.IRON_BARS); - - AllBlockTags.PASSIVE_BOILER_HEATERS.includeAll(BlockTags.FIRE); - AllBlockTags.PASSIVE_BOILER_HEATERS.includeAll(BlockTags.CAMPFIRES); - AllBlockTags.PASSIVE_BOILER_HEATERS.add(Blocks.MAGMA_BLOCK, Blocks.LAVA); - - AllBlockTags.SAFE_NBT.includeAll(BlockTags.SIGNS); - AllBlockTags.SAFE_NBT.includeAll(BlockTags.BANNERS); - - AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.RAILS); - AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.BUTTONS); - AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.PRESSURE_PLATES); - AllBlockTags.WRENCH_PICKUP.add(Blocks.REDSTONE_WIRE, Blocks.REDSTONE_TORCH, Blocks.REPEATER, Blocks.LEVER, - Blocks.COMPARATOR, Blocks.OBSERVER, Blocks.REDSTONE_WALL_TORCH, Blocks.PISTON, Blocks.STICKY_PISTON, - Blocks.TRIPWIRE, Blocks.TRIPWIRE_HOOK, Blocks.DAYLIGHT_DETECTOR, Blocks.TARGET, Blocks.HOPPER); - - AllBlockTags.TREE_ATTACHMENTS.add(Blocks.BEE_NEST, Blocks.VINE, Blocks.MOSS_CARPET, Blocks.SHROOMLIGHT, - Blocks.COCOA); - - AllBlockTags.ORE_OVERRIDE_STONE.includeAll(BlockTags.STONE_ORE_REPLACEABLES); - - registerCompat(); - } - - private static void registerCompat() { - AllBlockTags.NON_MOVABLE.addOptional(Mods.IE, "connector_lv", "connector_lv_relay", "connector_mv", - "connector_mv_relay", "connector_hv", "connector_hv_relay", "connector_bundled", "connector_structural", - "connector_redstone", "connector_probe", "breaker_switch"); - - strippedWoodCompat(Mods.ARS_N, "blue_archwood", "purple_archwood", "green_archwood", "red_archwood"); - strippedWoodCompat(Mods.BTN, "livingwood", "dreamwood"); - strippedWoodCompat(Mods.FA, "cherrywood", "mysterywood"); - strippedWoodCompat(Mods.HEX, "akashic"); - strippedWoodCompat(Mods.ID, "menril"); - strippedWoodCompat(Mods.BYG, "aspen", "baobab", "enchanted", "cherry", "cika", "cypress", "ebony", "ether", - "fir", "green_enchanted", "holly", "jacaranda", "lament", "mahogany", "mangrove", "maple", "nightshade", - "palm", "palo_verde", "pine", "rainbow_eucalyptus", "redwood", "skyris", "willow", "witch_hazel", - "zelkova"); - strippedWoodCompat(Mods.SG, "netherwood"); - strippedWoodCompat(Mods.TF, "twilight_oak", "canopy", "mangrove", "dark", "time", "transformation", "mining", - "sorting"); - strippedWoodCompat(Mods.TIC, "greenheart", "skyroot", "bloodshroom"); - strippedWoodCompat(Mods.AP, "twisted"); - strippedWoodCompat(Mods.Q, "azalea", "blossom"); - strippedWoodCompat(Mods.ECO, "coconut", "walnut", "azalea"); - strippedWoodCompat(Mods.BOP, "fir", "redwood", "cherry", "mahogany", "jacaranda", "palm", "willow", "dead", - "magic", "umbran", "hellbark"); - strippedWoodCompat(Mods.BSK, "bluebright", "starlit", "frostbright", "lunar", "dusk", "maple", "cherry"); - - AllItemTags.MODDED_STRIPPED_LOGS.addOptional(Mods.BYG, "stripped_bulbis_stem"); - AllItemTags.MODDED_STRIPPED_WOOD.addOptional(Mods.BYG, "stripped_bulbis_wood"); - - AllItemTags.MODDED_STRIPPED_LOGS.includeIn(AllItemTags.STRIPPED_LOGS); - AllItemTags.MODDED_STRIPPED_WOOD.includeIn(AllItemTags.STRIPPED_WOOD); - } - - private static void strippedWoodCompat(Mods mod, String... woodtypes) { - for (int i = 0; i < woodtypes.length; i++) { - String type = woodtypes[i]; - String strippedPre = mod.strippedIsSuffix ? "" : "stripped_"; - String strippedPost = mod.strippedIsSuffix ? "_stripped" : ""; - AllItemTags.MODDED_STRIPPED_LOGS.addOptional(mod, strippedPre + type + "_log" + strippedPost); - AllItemTags.MODDED_STRIPPED_WOOD.addOptional(mod, - strippedPre + type + (mod.omitWoodSuffix ? "" : "_wood") + strippedPost); + AllEntityTags() { + this(MOD); } + + AllEntityTags(NameSpace namespace) { + this(namespace, namespace.optionalDefault, namespace.alwaysDatagenDefault); + } + + AllEntityTags(NameSpace namespace, String path) { + this(namespace, path, namespace.optionalDefault, namespace.alwaysDatagenDefault); + } + + AllEntityTags(NameSpace namespace, boolean optional, boolean alwaysDatagen) { + this(namespace, null, optional, alwaysDatagen); + } + + AllEntityTags(NameSpace namespace, String path, boolean optional, boolean alwaysDatagen) { + ResourceLocation id = new ResourceLocation(namespace.id, path == null ? Lang.asId(name()) : path); + if (optional) { + tag = optionalTag(ForgeRegistries.ENTITIES, id); + } else { + tag = TagKey.create(Registry.ENTITY_TYPE_REGISTRY, id); + } + this.alwaysDatagen = alwaysDatagen; + } + + public boolean matches(Entity entity) { + return entity.getType() + .is(tag); + } + + private static void init() {} + } + public static void init() { + AllBlockTags.init(); + AllItemTags.init(); + AllFluidTags.init(); + AllEntityTags.init(); + } } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java deleted file mode 100644 index 3647ad732c..0000000000 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ /dev/null @@ -1,827 +0,0 @@ -package com.simibubi.create; - -import static com.simibubi.create.content.logistics.block.display.AllDisplayBehaviours.assignDataBehaviourTE; - -import com.simibubi.create.content.contraptions.base.CutoutRotatingInstance; -import com.simibubi.create.content.contraptions.base.HalfShaftInstance; -import com.simibubi.create.content.contraptions.base.HorizontalHalfShaftInstance; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.components.actors.DrillInstance; -import com.simibubi.create.content.contraptions.components.actors.DrillRenderer; -import com.simibubi.create.content.contraptions.components.actors.DrillTileEntity; -import com.simibubi.create.content.contraptions.components.actors.HarvesterRenderer; -import com.simibubi.create.content.contraptions.components.actors.HarvesterTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PSIInstance; -import com.simibubi.create.content.contraptions.components.actors.PortableFluidInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableItemInterfaceTileEntity; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceRenderer; -import com.simibubi.create.content.contraptions.components.clock.CuckooClockRenderer; -import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterInstance; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterRenderer; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; -import com.simibubi.create.content.contraptions.components.crank.HandCrankInstance; -import com.simibubi.create.content.contraptions.components.crank.HandCrankRenderer; -import com.simibubi.create.content.contraptions.components.crank.HandCrankTileEntity; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerTileEntity; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelTileEntity; -import com.simibubi.create.content.contraptions.components.deployer.DeployerInstance; -import com.simibubi.create.content.contraptions.components.deployer.DeployerRenderer; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; -import com.simibubi.create.content.contraptions.components.fan.EncasedFanRenderer; -import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity; -import com.simibubi.create.content.contraptions.components.fan.FanInstance; -import com.simibubi.create.content.contraptions.components.fan.NozzleTileEntity; -import com.simibubi.create.content.contraptions.components.flywheel.FlyWheelInstance; -import com.simibubi.create.content.contraptions.components.flywheel.FlywheelRenderer; -import com.simibubi.create.content.contraptions.components.flywheel.FlywheelTileEntity; -import com.simibubi.create.content.contraptions.components.millstone.MillStoneCogInstance; -import com.simibubi.create.content.contraptions.components.millstone.MillstoneRenderer; -import com.simibubi.create.content.contraptions.components.millstone.MillstoneTileEntity; -import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerRenderer; -import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; -import com.simibubi.create.content.contraptions.components.mixer.MixerInstance; -import com.simibubi.create.content.contraptions.components.motor.CreativeMotorRenderer; -import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressRenderer; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; -import com.simibubi.create.content.contraptions.components.press.PressInstance; -import com.simibubi.create.content.contraptions.components.saw.SawInstance; -import com.simibubi.create.content.contraptions.components.saw.SawRenderer; -import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; -import com.simibubi.create.content.contraptions.components.steam.PoweredShaftTileEntity; -import com.simibubi.create.content.contraptions.components.steam.SteamEngineRenderer; -import com.simibubi.create.content.contraptions.components.steam.SteamEngineTileEntity; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleRenderer; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.HosePulleyInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.RopePulleyInstance; -import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity; -import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity; -import com.simibubi.create.content.contraptions.fluids.PumpCogInstance; -import com.simibubi.create.content.contraptions.fluids.PumpRenderer; -import com.simibubi.create.content.contraptions.fluids.PumpTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainTileEntity; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutRenderer; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveInstance; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveRenderer; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.TransparentStraightPipeRenderer; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankRenderer; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.content.contraptions.processing.BasinRenderer; -import com.simibubi.create.content.contraptions.processing.BasinTileEntity; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerRenderer; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerRenderer; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.sequencer.SequencedGearshiftTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.BeltInstance; -import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedKineticTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedKineticTileInstance; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedKineticTileRenderer; -import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogInstance; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogRenderer; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; -import com.simibubi.create.content.contraptions.relays.encased.ShaftRenderer; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftInstance; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeInstance; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer; -import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; -import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxInstance; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxRenderer; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity; -import com.simibubi.create.content.contraptions.relays.gearbox.GearshiftTileEntity; -import com.simibubi.create.content.curiosities.armor.CopperBacktankInstance; -import com.simibubi.create.content.curiosities.armor.CopperBacktankRenderer; -import com.simibubi.create.content.curiosities.armor.CopperBacktankTileEntity; -import com.simibubi.create.content.curiosities.bell.BellRenderer; -import com.simibubi.create.content.curiosities.bell.HauntedBellTileEntity; -import com.simibubi.create.content.curiosities.bell.PeculiarBellTileEntity; -import com.simibubi.create.content.curiosities.deco.PlacardRenderer; -import com.simibubi.create.content.curiosities.deco.PlacardTileEntity; -import com.simibubi.create.content.curiosities.deco.SlidingDoorRenderer; -import com.simibubi.create.content.curiosities.deco.SlidingDoorTileEntity; -import com.simibubi.create.content.curiosities.toolbox.ToolBoxInstance; -import com.simibubi.create.content.curiosities.toolbox.ToolboxRenderer; -import com.simibubi.create.content.curiosities.toolbox.ToolboxTileEntity; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelInstance; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelRenderer; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; -import com.simibubi.create.content.logistics.block.chute.ChuteRenderer; -import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity; -import com.simibubi.create.content.logistics.block.chute.SmartChuteRenderer; -import com.simibubi.create.content.logistics.block.chute.SmartChuteTileEntity; -import com.simibubi.create.content.logistics.block.depot.DepotRenderer; -import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; -import com.simibubi.create.content.logistics.block.depot.EjectorInstance; -import com.simibubi.create.content.logistics.block.depot.EjectorRenderer; -import com.simibubi.create.content.logistics.block.depot.EjectorTileEntity; -import com.simibubi.create.content.logistics.block.diodes.BrassDiodeInstance; -import com.simibubi.create.content.logistics.block.diodes.BrassDiodeRenderer; -import com.simibubi.create.content.logistics.block.diodes.PulseExtenderTileEntity; -import com.simibubi.create.content.logistics.block.diodes.PulseRepeaterTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkRenderer; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; -import com.simibubi.create.content.logistics.block.display.source.NixieTubeDisplaySource; -import com.simibubi.create.content.logistics.block.display.target.NixieTubeDisplayTarget; -import com.simibubi.create.content.logistics.block.funnel.FunnelInstance; -import com.simibubi.create.content.logistics.block.funnel.FunnelRenderer; -import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; -import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInstance; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverInstance; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer; -import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; -import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; -import com.simibubi.create.content.logistics.item.LecternControllerRenderer; -import com.simibubi.create.content.logistics.item.LecternControllerTileEntity; -import com.simibubi.create.content.logistics.trains.BogeyTileEntityRenderer; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayRenderer; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverRenderer; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverTileEntity; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalRenderer; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; -import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; -import com.simibubi.create.content.logistics.trains.track.TrackInstance; -import com.simibubi.create.content.logistics.trains.track.TrackRenderer; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; -import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; -import com.simibubi.create.content.schematics.block.SchematicannonInstance; -import com.simibubi.create.content.schematics.block.SchematicannonRenderer; -import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; -import com.tterrag.registrate.util.entry.BlockEntityEntry; - -public class AllTileEntities { - - // Schematics - public static final BlockEntityEntry SCHEMATICANNON = Create.registrate() - .tileEntity("schematicannon", SchematicannonTileEntity::new) - .instance(() -> SchematicannonInstance::new) - .validBlocks(AllBlocks.SCHEMATICANNON) - .renderer(() -> SchematicannonRenderer::new) - .register(); - - public static final BlockEntityEntry SCHEMATIC_TABLE = Create.registrate() - .tileEntity("schematic_table", SchematicTableTileEntity::new) - .validBlocks(AllBlocks.SCHEMATIC_TABLE) - .register(); - - // Kinetics - public static final BlockEntityEntry BRACKETED_KINETIC = Create.registrate() - .tileEntity("simple_kinetic", BracketedKineticTileEntity::new) - .instance(() -> BracketedKineticTileInstance::new, false) - .validBlocks(AllBlocks.SHAFT, AllBlocks.COGWHEEL, AllBlocks.LARGE_COGWHEEL) - .renderer(() -> BracketedKineticTileRenderer::new) - .register(); - - public static final BlockEntityEntry MOTOR = Create.registrate() - .tileEntity("motor", CreativeMotorTileEntity::new) - .instance(() -> HalfShaftInstance::new, false) - .validBlocks(AllBlocks.CREATIVE_MOTOR) - .renderer(() -> CreativeMotorRenderer::new) - .register(); - - public static final BlockEntityEntry GEARBOX = Create.registrate() - .tileEntity("gearbox", GearboxTileEntity::new) - .instance(() -> GearboxInstance::new, false) - .validBlocks(AllBlocks.GEARBOX) - .renderer(() -> GearboxRenderer::new) - .register(); - - public static final BlockEntityEntry ENCASED_SHAFT = Create.registrate() - .tileEntity("encased_shaft", KineticTileEntity::new) - .instance(() -> ShaftInstance::new, false) - .validBlocks(AllBlocks.ANDESITE_ENCASED_SHAFT, AllBlocks.BRASS_ENCASED_SHAFT, AllBlocks.ENCASED_CHAIN_DRIVE, - AllBlocks.METAL_GIRDER_ENCASED_SHAFT) - .renderer(() -> ShaftRenderer::new) - .register(); - - public static final BlockEntityEntry ENCASED_COGWHEEL = Create.registrate() - .tileEntity("encased_cogwheel", SimpleKineticTileEntity::new) - .instance(() -> EncasedCogInstance::small, false) - .validBlocks(AllBlocks.ANDESITE_ENCASED_COGWHEEL, AllBlocks.BRASS_ENCASED_COGWHEEL) - .renderer(() -> EncasedCogRenderer::small) - .register(); - - public static final BlockEntityEntry ENCASED_LARGE_COGWHEEL = Create.registrate() - .tileEntity("encased_large_cogwheel", SimpleKineticTileEntity::new) - .instance(() -> EncasedCogInstance::large, false) - .validBlocks(AllBlocks.ANDESITE_ENCASED_LARGE_COGWHEEL, AllBlocks.BRASS_ENCASED_LARGE_COGWHEEL) - .renderer(() -> EncasedCogRenderer::large) - .register(); - - public static final BlockEntityEntry ADJUSTABLE_PULLEY = Create.registrate() - .tileEntity("adjustable_pulley", AdjustablePulleyTileEntity::new) - .instance(() -> ShaftInstance::new, false) - .validBlocks(AllBlocks.ADJUSTABLE_CHAIN_GEARSHIFT) - .renderer(() -> ShaftRenderer::new) - .register(); - - public static final BlockEntityEntry ENCASED_FAN = Create.registrate() - .tileEntity("encased_fan", EncasedFanTileEntity::new) - .instance(() -> FanInstance::new, false) - .validBlocks(AllBlocks.ENCASED_FAN) - .renderer(() -> EncasedFanRenderer::new) - .register(); - - public static final BlockEntityEntry NOZZLE = Create.registrate() - .tileEntity("nozzle", NozzleTileEntity::new) - .validBlocks(AllBlocks.NOZZLE) - // .renderer(() -> renderer) - .register(); - - public static final BlockEntityEntry CLUTCH = Create.registrate() - .tileEntity("clutch", ClutchTileEntity::new) - .instance(() -> SplitShaftInstance::new, false) - .validBlocks(AllBlocks.CLUTCH) - .renderer(() -> SplitShaftRenderer::new) - .register(); - - public static final BlockEntityEntry GEARSHIFT = Create.registrate() - .tileEntity("gearshift", GearshiftTileEntity::new) - .instance(() -> SplitShaftInstance::new, false) - .validBlocks(AllBlocks.GEARSHIFT) - .renderer(() -> SplitShaftRenderer::new) - .register(); - - public static final BlockEntityEntry TURNTABLE = Create.registrate() - .tileEntity("turntable", TurntableTileEntity::new) - .instance(() -> SingleRotatingInstance::new, false) - .validBlocks(AllBlocks.TURNTABLE) - .renderer(() -> KineticTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry HAND_CRANK = Create.registrate() - .tileEntity("hand_crank", HandCrankTileEntity::new) - .instance(() -> HandCrankInstance::new) - .validBlocks(AllBlocks.HAND_CRANK, AllBlocks.COPPER_VALVE_HANDLE) - .validBlocks(AllBlocks.DYED_VALVE_HANDLES.toArray()) - .renderer(() -> HandCrankRenderer::new) - .register(); - - public static final BlockEntityEntry CUCKOO_CLOCK = Create.registrate() - .tileEntity("cuckoo_clock", CuckooClockTileEntity::new) - .instance(() -> HorizontalHalfShaftInstance::new) - .validBlocks(AllBlocks.CUCKOO_CLOCK, AllBlocks.MYSTERIOUS_CUCKOO_CLOCK) - .renderer(() -> CuckooClockRenderer::new) - .register(); - - public static final BlockEntityEntry GANTRY_SHAFT = Create.registrate() - .tileEntity("gantry_shaft", GantryShaftTileEntity::new) - .instance(() -> SingleRotatingInstance::new, false) - .validBlocks(AllBlocks.GANTRY_SHAFT) - .renderer(() -> KineticTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry GANTRY_PINION = Create.registrate() - .tileEntity("gantry_pinion", GantryCarriageTileEntity::new) - .instance(() -> GantryCarriageInstance::new) - .validBlocks(AllBlocks.GANTRY_CARRIAGE) - .renderer(() -> GantryCarriageRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_PUMP = Create.registrate() - .tileEntity("mechanical_pump", PumpTileEntity::new) - .instance(() -> PumpCogInstance::new) - .validBlocks(AllBlocks.MECHANICAL_PUMP) - .renderer(() -> PumpRenderer::new) - .register(); - - public static final BlockEntityEntry SMART_FLUID_PIPE = Create.registrate() - .tileEntity("smart_fluid_pipe", SmartFluidPipeTileEntity::new) - .validBlocks(AllBlocks.SMART_FLUID_PIPE) - .renderer(() -> SmartTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry FLUID_PIPE = Create.registrate() - .tileEntity("fluid_pipe", FluidPipeTileEntity::new) - .validBlocks(AllBlocks.FLUID_PIPE) - .register(); - - public static final BlockEntityEntry ENCASED_FLUID_PIPE = Create.registrate() - .tileEntity("encased_fluid_pipe", FluidPipeTileEntity::new) - .validBlocks(AllBlocks.ENCASED_FLUID_PIPE) - .register(); - - public static final BlockEntityEntry GLASS_FLUID_PIPE = Create.registrate() - .tileEntity("glass_fluid_pipe", StraightPipeTileEntity::new) - .validBlocks(AllBlocks.GLASS_FLUID_PIPE) - .renderer(() -> TransparentStraightPipeRenderer::new) - .register(); - - public static final BlockEntityEntry FLUID_VALVE = Create.registrate() - .tileEntity("fluid_valve", FluidValveTileEntity::new) - .instance(() -> FluidValveInstance::new) - .validBlocks(AllBlocks.FLUID_VALVE) - .renderer(() -> FluidValveRenderer::new) - .register(); - - public static final BlockEntityEntry FLUID_TANK = Create.registrate() - .tileEntity("fluid_tank", FluidTankTileEntity::new) - .validBlocks(AllBlocks.FLUID_TANK) - .renderer(() -> FluidTankRenderer::new) - .register(); - - public static final BlockEntityEntry CREATIVE_FLUID_TANK = Create.registrate() - .tileEntity("creative_fluid_tank", CreativeFluidTankTileEntity::new) - .validBlocks(AllBlocks.CREATIVE_FLUID_TANK) - .renderer(() -> FluidTankRenderer::new) - .register(); - - public static final BlockEntityEntry HOSE_PULLEY = Create.registrate() - .tileEntity("hose_pulley", HosePulleyTileEntity::new) - .instance(() -> HosePulleyInstance::new) - .validBlocks(AllBlocks.HOSE_PULLEY) - .renderer(() -> HosePulleyRenderer::new) - .register(); - - public static final BlockEntityEntry SPOUT = Create.registrate() - .tileEntity("spout", SpoutTileEntity::new) - .validBlocks(AllBlocks.SPOUT) - .renderer(() -> SpoutRenderer::new) - .register(); - - public static final BlockEntityEntry ITEM_DRAIN = Create.registrate() - .tileEntity("item_drain", ItemDrainTileEntity::new) - .validBlocks(AllBlocks.ITEM_DRAIN) - .renderer(() -> ItemDrainRenderer::new) - .register(); - - public static final BlockEntityEntry BELT = Create.registrate() - .tileEntity("belt", BeltTileEntity::new) - .instance(() -> BeltInstance::new, BeltTileEntity::shouldRenderNormally) - .validBlocks(AllBlocks.BELT) - .renderer(() -> BeltRenderer::new) - .register(); - - public static final BlockEntityEntry CHUTE = Create.registrate() - .tileEntity("chute", ChuteTileEntity::new) - .validBlocks(AllBlocks.CHUTE) - .renderer(() -> ChuteRenderer::new) - .register(); - - public static final BlockEntityEntry SMART_CHUTE = Create.registrate() - .tileEntity("smart_chute", SmartChuteTileEntity::new) - .validBlocks(AllBlocks.SMART_CHUTE) - .renderer(() -> SmartChuteRenderer::new) - .register(); - - public static final BlockEntityEntry ANDESITE_TUNNEL = Create.registrate() - .tileEntity("andesite_tunnel", BeltTunnelTileEntity::new) - .instance(() -> BeltTunnelInstance::new) - .validBlocks(AllBlocks.ANDESITE_TUNNEL) - .renderer(() -> BeltTunnelRenderer::new) - .register(); - - public static final BlockEntityEntry BRASS_TUNNEL = Create.registrate() - .tileEntity("brass_tunnel", BrassTunnelTileEntity::new) - .instance(() -> BeltTunnelInstance::new) - .validBlocks(AllBlocks.BRASS_TUNNEL) - .renderer(() -> BeltTunnelRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_ARM = Create.registrate() - .tileEntity("mechanical_arm", ArmTileEntity::new) - .instance(() -> ArmInstance::new) - .validBlocks(AllBlocks.MECHANICAL_ARM) - .renderer(() -> ArmRenderer::new) - .register(); - - public static final BlockEntityEntry ITEM_VAULT = Create.registrate() - .tileEntity("item_vault", ItemVaultTileEntity::new) - .validBlocks(AllBlocks.ITEM_VAULT) - .register(); - - public static final BlockEntityEntry MECHANICAL_PISTON = Create.registrate() - .tileEntity("mechanical_piston", MechanicalPistonTileEntity::new) - .instance(() -> ShaftInstance::new, false) - .validBlocks(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON) - .renderer(() -> MechanicalPistonRenderer::new) - .register(); - - public static final BlockEntityEntry WINDMILL_BEARING = Create.registrate() - .tileEntity("windmill_bearing", WindmillBearingTileEntity::new) - .instance(() -> BearingInstance::new) - .validBlocks(AllBlocks.WINDMILL_BEARING) - .renderer(() -> BearingRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_BEARING = Create.registrate() - .tileEntity("mechanical_bearing", MechanicalBearingTileEntity::new) - .instance(() -> BearingInstance::new) - .validBlocks(AllBlocks.MECHANICAL_BEARING) - .renderer(() -> BearingRenderer::new) - .register(); - - public static final BlockEntityEntry CLOCKWORK_BEARING = Create.registrate() - .tileEntity("clockwork_bearing", ClockworkBearingTileEntity::new) - .instance(() -> BearingInstance::new) - .validBlocks(AllBlocks.CLOCKWORK_BEARING) - .renderer(() -> BearingRenderer::new) - .register(); - - public static final BlockEntityEntry ROPE_PULLEY = Create.registrate() - .tileEntity("rope_pulley", PulleyTileEntity::new) - .instance(() -> RopePulleyInstance::new, false) - .validBlocks(AllBlocks.ROPE_PULLEY) - .renderer(() -> PulleyRenderer::new) - .register(); - - public static final BlockEntityEntry CHASSIS = Create.registrate() - .tileEntity("chassis", ChassisTileEntity::new) - .validBlocks(AllBlocks.RADIAL_CHASSIS, AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS) - // .renderer(() -> renderer) - .register(); - - public static final BlockEntityEntry STICKER = Create.registrate() - .tileEntity("sticker", StickerTileEntity::new) - .instance(() -> StickerInstance::new, false) - .validBlocks(AllBlocks.STICKER) - .renderer(() -> StickerRenderer::new) - .register(); - - public static final BlockEntityEntry DRILL = Create.registrate() - .tileEntity("drill", DrillTileEntity::new) - .instance(() -> DrillInstance::new, false) - .validBlocks(AllBlocks.MECHANICAL_DRILL) - .renderer(() -> DrillRenderer::new) - .register(); - - public static final BlockEntityEntry SAW = Create.registrate() - .tileEntity("saw", SawTileEntity::new) - .instance(() -> SawInstance::new) - .validBlocks(AllBlocks.MECHANICAL_SAW) - .renderer(() -> SawRenderer::new) - .register(); - - public static final BlockEntityEntry HARVESTER = Create.registrate() - .tileEntity("harvester", HarvesterTileEntity::new) - .validBlocks(AllBlocks.MECHANICAL_HARVESTER) - .renderer(() -> HarvesterRenderer::new) - .register(); - - public static final BlockEntityEntry PORTABLE_STORAGE_INTERFACE = - Create.registrate() - .tileEntity("portable_storage_interface", PortableItemInterfaceTileEntity::new) - .instance(() -> PSIInstance::new) - .validBlocks(AllBlocks.PORTABLE_STORAGE_INTERFACE) - .renderer(() -> PortableStorageInterfaceRenderer::new) - .register(); - - public static final BlockEntityEntry PORTABLE_FLUID_INTERFACE = - Create.registrate() - .tileEntity("portable_fluid_interface", PortableFluidInterfaceTileEntity::new) - .instance(() -> PSIInstance::new) - .validBlocks(AllBlocks.PORTABLE_FLUID_INTERFACE) - .renderer(() -> PortableStorageInterfaceRenderer::new) - .register(); - - public static final BlockEntityEntry STEAM_ENGINE = Create.registrate() - .tileEntity("steam_engine", SteamEngineTileEntity::new) - .validBlocks(AllBlocks.STEAM_ENGINE) - .renderer(() -> SteamEngineRenderer::new) - .register(); - - public static final BlockEntityEntry STEAM_WHISTLE = Create.registrate() - .tileEntity("steam_whistle", WhistleTileEntity::new) - .validBlocks(AllBlocks.STEAM_WHISTLE) - .renderer(() -> WhistleRenderer::new) - .register(); - - public static final BlockEntityEntry POWERED_SHAFT = Create.registrate() - .tileEntity("powered_shaft", PoweredShaftTileEntity::new) - .instance(() -> SingleRotatingInstance::new, false) - .validBlocks(AllBlocks.POWERED_SHAFT) - .renderer(() -> KineticTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry FLYWHEEL = Create.registrate() - .tileEntity("flywheel", FlywheelTileEntity::new) - .instance(() -> FlyWheelInstance::new, false) - .validBlocks(AllBlocks.FLYWHEEL) - .renderer(() -> FlywheelRenderer::new) - .register(); - - public static final BlockEntityEntry MILLSTONE = Create.registrate() - .tileEntity("millstone", MillstoneTileEntity::new) - .instance(() -> MillStoneCogInstance::new, false) - .validBlocks(AllBlocks.MILLSTONE) - .renderer(() -> MillstoneRenderer::new) - .register(); - - public static final BlockEntityEntry CRUSHING_WHEEL = Create.registrate() - .tileEntity("crushing_wheel", CrushingWheelTileEntity::new) - .instance(() -> CutoutRotatingInstance::new, false) - .validBlocks(AllBlocks.CRUSHING_WHEEL) - .renderer(() -> KineticTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry CRUSHING_WHEEL_CONTROLLER = - Create.registrate() - .tileEntity("crushing_wheel_controller", CrushingWheelControllerTileEntity::new) - .validBlocks(AllBlocks.CRUSHING_WHEEL_CONTROLLER) - // .renderer(() -> renderer) - .register(); - - public static final BlockEntityEntry WATER_WHEEL = Create.registrate() - .tileEntity("water_wheel", WaterWheelTileEntity::new) - .instance(() -> CutoutRotatingInstance::new, false) - .validBlocks(AllBlocks.WATER_WHEEL) - .renderer(() -> KineticTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_PRESS = Create.registrate() - .tileEntity("mechanical_press", MechanicalPressTileEntity::new) - .instance(() -> PressInstance::new) - .validBlocks(AllBlocks.MECHANICAL_PRESS) - .renderer(() -> MechanicalPressRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_MIXER = Create.registrate() - .tileEntity("mechanical_mixer", MechanicalMixerTileEntity::new) - .instance(() -> MixerInstance::new) - .validBlocks(AllBlocks.MECHANICAL_MIXER) - .renderer(() -> MechanicalMixerRenderer::new) - .register(); - - public static final BlockEntityEntry DEPLOYER = Create.registrate() - .tileEntity("deployer", DeployerTileEntity::new) - .instance(() -> DeployerInstance::new) - .validBlocks(AllBlocks.DEPLOYER) - .renderer(() -> DeployerRenderer::new) - .register(); - - public static final BlockEntityEntry BASIN = Create.registrate() - .tileEntity("basin", BasinTileEntity::new) - .validBlocks(AllBlocks.BASIN) - .renderer(() -> BasinRenderer::new) - .register(); - - public static final BlockEntityEntry HEATER = Create.registrate() - .tileEntity("blaze_heater", BlazeBurnerTileEntity::new) - .validBlocks(AllBlocks.BLAZE_BURNER) - .renderer(() -> BlazeBurnerRenderer::new) - .register(); - - public static final BlockEntityEntry MECHANICAL_CRAFTER = Create.registrate() - .tileEntity("mechanical_crafter", MechanicalCrafterTileEntity::new) - .instance(() -> MechanicalCrafterInstance::new) - .validBlocks(AllBlocks.MECHANICAL_CRAFTER) - .renderer(() -> MechanicalCrafterRenderer::new) - .register(); - - public static final BlockEntityEntry SEQUENCED_GEARSHIFT = Create.registrate() - .tileEntity("sequenced_gearshift", SequencedGearshiftTileEntity::new) - .instance(() -> SplitShaftInstance::new, false) - .validBlocks(AllBlocks.SEQUENCED_GEARSHIFT) - .renderer(() -> SplitShaftRenderer::new) - .register(); - - public static final BlockEntityEntry ROTATION_SPEED_CONTROLLER = Create.registrate() - .tileEntity("rotation_speed_controller", SpeedControllerTileEntity::new) - .instance(() -> ShaftInstance::new) - .validBlocks(AllBlocks.ROTATION_SPEED_CONTROLLER) - .renderer(() -> SpeedControllerRenderer::new) - .register(); - - public static final BlockEntityEntry SPEEDOMETER = Create.registrate() - .tileEntity("speedometer", SpeedGaugeTileEntity::new) - .instance(() -> GaugeInstance.Speed::new) - .validBlocks(AllBlocks.SPEEDOMETER) - .renderer(() -> GaugeRenderer::speed) - .register(); - - public static final BlockEntityEntry STRESSOMETER = Create.registrate() - .tileEntity("stressometer", StressGaugeTileEntity::new) - .instance(() -> GaugeInstance.Stress::new) - .validBlocks(AllBlocks.STRESSOMETER) - .renderer(() -> GaugeRenderer::stress) - .register(); - - public static final BlockEntityEntry ANALOG_LEVER = Create.registrate() - .tileEntity("analog_lever", AnalogLeverTileEntity::new) - .instance(() -> AnalogLeverInstance::new, false) - .validBlocks(AllBlocks.ANALOG_LEVER) - .renderer(() -> AnalogLeverRenderer::new) - .register(); - - public static final BlockEntityEntry PLACARD = Create.registrate() - .tileEntity("placard", PlacardTileEntity::new) - .validBlocks(AllBlocks.PLACARD) - .renderer(() -> PlacardRenderer::new) - .register(); - - public static final BlockEntityEntry CART_ASSEMBLER = Create.registrate() - .tileEntity("cart_assembler", CartAssemblerTileEntity::new) - .validBlocks(AllBlocks.CART_ASSEMBLER) - // .renderer(() -> renderer) - .register(); - - // Logistics - public static final BlockEntityEntry REDSTONE_LINK = Create.registrate() - .tileEntity("redstone_link", RedstoneLinkTileEntity::new) - .validBlocks(AllBlocks.REDSTONE_LINK) - .renderer(() -> SmartTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry NIXIE_TUBE = Create.registrate() - .tileEntity("nixie_tube", NixieTubeTileEntity::new) - .validBlocks(AllBlocks.ORANGE_NIXIE_TUBE) - .validBlocks(AllBlocks.NIXIE_TUBES.toArray()) - .renderer(() -> NixieTubeRenderer::new) - .onRegister(assignDataBehaviourTE(new NixieTubeDisplayTarget())) - .onRegister(assignDataBehaviourTE(new NixieTubeDisplaySource())) - .register(); - - public static final BlockEntityEntry DISPLAY_LINK = Create.registrate() - .tileEntity("display_link", DisplayLinkTileEntity::new) - .validBlocks(AllBlocks.DISPLAY_LINK) - .renderer(() -> DisplayLinkRenderer::new) - .register(); - - public static final BlockEntityEntry STOCKPILE_SWITCH = Create.registrate() - .tileEntity("stockpile_switch", StockpileSwitchTileEntity::new) - .validBlocks(AllBlocks.STOCKPILE_SWITCH) - .renderer(() -> SmartTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry CREATIVE_CRATE = Create.registrate() - .tileEntity("creative_crate", CreativeCrateTileEntity::new) - .validBlocks(AllBlocks.CREATIVE_CRATE) - .renderer(() -> SmartTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry DEPOT = Create.registrate() - .tileEntity("depot", DepotTileEntity::new) - .validBlocks(AllBlocks.DEPOT) - .renderer(() -> DepotRenderer::new) - .register(); - - public static final BlockEntityEntry WEIGHTED_EJECTOR = Create.registrate() - .tileEntity("weighted_ejector", EjectorTileEntity::new) - .instance(() -> EjectorInstance::new) - .validBlocks(AllBlocks.WEIGHTED_EJECTOR) - .renderer(() -> EjectorRenderer::new) - .register(); - - public static final BlockEntityEntry FUNNEL = Create.registrate() - .tileEntity("funnel", FunnelTileEntity::new) - .instance(() -> FunnelInstance::new) - .validBlocks(AllBlocks.BRASS_FUNNEL, AllBlocks.BRASS_BELT_FUNNEL, AllBlocks.ANDESITE_FUNNEL, - AllBlocks.ANDESITE_BELT_FUNNEL) - .renderer(() -> FunnelRenderer::new) - .register(); - - public static final BlockEntityEntry CONTENT_OBSERVER = Create.registrate() - .tileEntity("content_observer", ContentObserverTileEntity::new) - .validBlocks(AllBlocks.CONTENT_OBSERVER) - .renderer(() -> SmartTileEntityRenderer::new) - .register(); - - public static final BlockEntityEntry PULSE_EXTENDER = Create.registrate() - .tileEntity("pulse_extender", PulseExtenderTileEntity::new) - .instance(() -> BrassDiodeInstance::new, false) - .validBlocks(AllBlocks.PULSE_EXTENDER) - .renderer(() -> BrassDiodeRenderer::new) - .register(); - - public static final BlockEntityEntry PULSE_REPEATER = Create.registrate() - .tileEntity("pulse_repeater", PulseRepeaterTileEntity::new) - .instance(() -> BrassDiodeInstance::new, false) - .validBlocks(AllBlocks.PULSE_REPEATER) - .renderer(() -> BrassDiodeRenderer::new) - .register(); - - public static final BlockEntityEntry LECTERN_CONTROLLER = Create.registrate() - .tileEntity("lectern_controller", LecternControllerTileEntity::new) - .validBlocks(AllBlocks.LECTERN_CONTROLLER) - .renderer(() -> LecternControllerRenderer::new) - .register(); - - // Curiosities - public static final BlockEntityEntry COPPER_BACKTANK = Create.registrate() - .tileEntity("copper_backtank", CopperBacktankTileEntity::new) - .instance(() -> CopperBacktankInstance::new) - .validBlocks(AllBlocks.COPPER_BACKTANK) - .renderer(() -> CopperBacktankRenderer::new) - .register(); - - public static final BlockEntityEntry PECULIAR_BELL = Create.registrate() - .tileEntity("peculiar_bell", PeculiarBellTileEntity::new) - .validBlocks(AllBlocks.PECULIAR_BELL) - .renderer(() -> BellRenderer::new) - .register(); - - public static final BlockEntityEntry HAUNTED_BELL = Create.registrate() - .tileEntity("cursed_bell", HauntedBellTileEntity::new) - .validBlocks(AllBlocks.HAUNTED_BELL) - .renderer(() -> BellRenderer::new) - .register(); - - public static final BlockEntityEntry TOOLBOX = Create.registrate() - .tileEntity("toolbox", ToolboxTileEntity::new) - .instance(() -> ToolBoxInstance::new, false) - .validBlocks(AllBlocks.TOOLBOXES.toArray()) - .renderer(() -> ToolboxRenderer::new) - .register(); - - public static final BlockEntityEntry TRACK = Create.registrate() - .tileEntity("track", TrackTileEntity::new) - .instance(() -> TrackInstance::new) - .renderer(() -> TrackRenderer::new) - .validBlocks(AllBlocks.TRACK) - .register(); - - public static final BlockEntityEntry FAKE_TRACK = Create.registrate() - .tileEntity("fake_track", FakeTrackTileEntity::new) - .validBlocks(AllBlocks.FAKE_TRACK) - .register(); - - public static final BlockEntityEntry BOGEY = Create.registrate() - .tileEntity("bogey", StandardBogeyTileEntity::new) - .renderer(() -> BogeyTileEntityRenderer::new) - .validBlocks(AllBlocks.SMALL_BOGEY, AllBlocks.LARGE_BOGEY) - .register(); - - public static final BlockEntityEntry TRACK_STATION = Create.registrate() - .tileEntity("track_station", StationTileEntity::new) - .renderer(() -> StationRenderer::new) - .validBlocks(AllBlocks.TRACK_STATION) - .register(); - - public static final BlockEntityEntry SLIDING_DOOR = Create.registrate() - .tileEntity("sliding_door", SlidingDoorTileEntity::new) - .renderer(() -> SlidingDoorRenderer::new) - .validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR) - .register(); - - public static final BlockEntityEntry FLAP_DISPLAY = Create.registrate() - .tileEntity("flap_display", FlapDisplayTileEntity::new) - .instance(() -> MechanicalCrafterInstance::new) - .renderer(() -> FlapDisplayRenderer::new) - .validBlocks(AllBlocks.DISPLAY_BOARD) - .register(); - - public static final BlockEntityEntry TRACK_SIGNAL = Create.registrate() - .tileEntity("track_signal", SignalTileEntity::new) - .renderer(() -> SignalRenderer::new) - .validBlocks(AllBlocks.TRACK_SIGNAL) - .register(); - - public static final BlockEntityEntry TRACK_OBSERVER = Create.registrate() - .tileEntity("track_observer", TrackObserverTileEntity::new) - .renderer(() -> TrackObserverRenderer::new) - .validBlocks(AllBlocks.TRACK_OBSERVER) - .register(); - - public static void register() {} -} diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 3142561418..255eb5a9a9 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -2,47 +2,52 @@ package com.simibubi.create; import java.util.Random; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.mojang.logging.LogUtils; import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.compat.Mods; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.compat.curios.Curios; -import com.simibubi.create.content.CreateItemGroup; -import com.simibubi.create.content.contraptions.TorquePropagator; -import com.simibubi.create.content.contraptions.fluids.tank.BoilerHeaters; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes; -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler; -import com.simibubi.create.content.logistics.block.display.AllDisplayBehaviours; -import com.simibubi.create.content.logistics.block.mechanicalArm.AllArmInteractionPointTypes; -import com.simibubi.create.content.logistics.trains.GlobalRailwayManager; -import com.simibubi.create.content.palettes.AllPaletteBlocks; -import com.simibubi.create.content.palettes.PalettesItemGroup; +import com.simibubi.create.content.contraptions.ContraptionMovementSetting; +import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.equipment.potatoCannon.BuiltinPotatoProjectileTypes; +import com.simibubi.create.content.fluids.tank.BoilerHeaters; +import com.simibubi.create.content.kinetics.TorquePropagator; +import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes; +import com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler; +import com.simibubi.create.content.schematics.SchematicInstances; import com.simibubi.create.content.schematics.ServerSchematicLoader; -import com.simibubi.create.content.schematics.filtering.SchematicInstances; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.content.trains.bogey.BogeySizes; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.block.CopperRegistries; -import com.simibubi.create.foundation.command.ServerLagger; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.ContraptionMovementSetting; +import com.simibubi.create.foundation.data.AllLangPartials; import com.simibubi.create.foundation.data.CreateRegistrate; import com.simibubi.create.foundation.data.LangMerger; +import com.simibubi.create.foundation.data.TagGen; import com.simibubi.create.foundation.data.recipe.MechanicalCraftingRecipeGen; import com.simibubi.create.foundation.data.recipe.ProcessingRecipeGen; import com.simibubi.create.foundation.data.recipe.SequencedAssemblyRecipeGen; import com.simibubi.create.foundation.data.recipe.StandardRecipeGen; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.gui.CreateTheme; +import com.simibubi.create.foundation.item.ItemDescription; +import com.simibubi.create.foundation.item.KineticStats; +import com.simibubi.create.foundation.item.TooltipModifier; import com.simibubi.create.foundation.ponder.CreatePonderPlugin; -import com.simibubi.create.foundation.utility.CreateRegistry; -import com.simibubi.create.foundation.worldgen.AllFeatures; -import com.simibubi.create.foundation.worldgen.AllOreFeatureConfigEntries; -import com.simibubi.create.foundation.worldgen.AllPlacementModifiers; -import com.simibubi.create.foundation.worldgen.BuiltinRegistration; -import com.tterrag.registrate.util.nullness.NonNullSupplier; +import com.simibubi.create.foundation.utility.AttachedRegistry; +import com.simibubi.create.foundation.utility.CreateNBTProcessors; +import com.simibubi.create.infrastructure.command.ServerLagger; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.worldgen.AllFeatures; +import com.simibubi.create.infrastructure.worldgen.AllOreFeatureConfigEntries; +import com.simibubi.create.infrastructure.worldgen.AllPlacementModifiers; +import com.simibubi.create.infrastructure.worldgen.BuiltinRegistration; import net.createmod.catnip.utility.lang.LangBuilder; import net.createmod.ponder.foundation.PonderIndex; @@ -50,7 +55,6 @@ import net.minecraft.data.DataGenerator; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.ForgeMod; @@ -69,27 +73,32 @@ public class Create { public static final String ID = "create"; public static final String NAME = "Create"; - public static final String VERSION = "0.5e"; + public static final String VERSION = "0.5.1c"; - public static final Logger LOGGER = LogManager.getLogger(); + public static final Logger LOGGER = LogUtils.getLogger(); public static final Gson GSON = new GsonBuilder().setPrettyPrinting() .disableHtmlEscaping() .create(); - public static final CreativeModeTab BASE_CREATIVE_TAB = new CreateItemGroup(); - public static final CreativeModeTab PALETTES_CREATIVE_TAB = new PalettesItemGroup(); + /** Use the {@link Random} of a local {@link Level} or {@link Entity} or create one */ + @Deprecated + public static final Random RANDOM = new Random(); + + public static final CreateRegistrate REGISTRATE = CreateRegistrate.create(ID); + + static { + REGISTRATE.setTooltipModifierFactory(item -> { + return new ItemDescription.Modifier(item, CreateTheme.Key.STANDARD_TOOLTIP.palette()) + .andThen(TooltipModifier.mapNull(KineticStats.create(item))); + }); + } public static final ServerSchematicLoader SCHEMATIC_RECEIVER = new ServerSchematicLoader(); public static final RedstoneLinkNetworkHandler REDSTONE_LINK_NETWORK_HANDLER = new RedstoneLinkNetworkHandler(); public static final TorquePropagator TORQUE_PROPAGATOR = new TorquePropagator(); public static final GlobalRailwayManager RAILWAYS = new GlobalRailwayManager(); public static final ServerLagger LAGGER = new ServerLagger(); - /** Use the {@link Random} of a local {@link Level} or {@link Entity} or create one */ - @Deprecated - public static final Random RANDOM = new Random(); - - private static final NonNullSupplier REGISTRATE = CreateRegistrate.lazy(ID); public Create() { onCtor(); @@ -102,15 +111,18 @@ public class Create { .getModEventBus(); IEventBus forgeEventBus = MinecraftForge.EVENT_BUS; + REGISTRATE.registerEventListeners(modEventBus); + AllSoundEvents.prepare(); + AllTags.init(); + AllCreativeModeTabs.init(); AllBlocks.register(); AllItems.register(); AllFluids.register(); - AllTags.register(); AllPaletteBlocks.register(); - AllContainerTypes.register(); + AllMenuTypes.register(); AllEntityTypes.register(); - AllTileEntities.register(); + AllBlockEntityTypes.register(); AllEnchantments.register(); AllRecipeTypes.register(modEventBus); AllParticleTypes.register(modEventBus); @@ -120,6 +132,8 @@ public class Create { AllFeatures.register(modEventBus); AllPlacementModifiers.register(modEventBus); BuiltinRegistration.register(modEventBus); + BogeySizes.init(); + AllBogeyStyles.register(); AllConfigs.register(modLoadingContext); @@ -129,6 +143,7 @@ public class Create { ContraptionMovementSetting.registerDefaults(); AllArmInteractionPointTypes.register(); BlockSpoutingBehaviour.registerDefaults(); + ComputerCraftProxy.register(); ForgeMod.enableMilkFluid(); CopperRegistries.inject(); @@ -141,16 +156,17 @@ public class Create { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.onCtorClient(modEventBus, forgeEventBus)); - Mods.CURIOS.executeIfInstalled(() -> Curios::init); + Mods.CURIOS.executeIfInstalled(() -> () -> Curios.init(modEventBus, forgeEventBus)); } public static void init(final FMLCommonSetupEvent event) { - CreateRegistry.unwrapAll(); AllPackets.registerPackets(); SchematicInstances.register(); BuiltinPotatoProjectileTypes.register(); + CreateNBTProcessors.register(); event.enqueueWork(() -> { + AttachedRegistry.unwrapAll(); AllAdvancements.register(); AllTriggers.register(); BoilerHeaters.registerDefaults(); @@ -158,10 +174,11 @@ public class Create { } public static void gatherData(GatherDataEvent event) { + TagGen.datagen(); DataGenerator gen = event.getGenerator(); if (event.includeClient()) { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> PonderIndex.addPlugin(new CreatePonderPlugin())); - gen.addProvider(new LangMerger(gen)); + gen.addProvider(new LangMerger(gen, ID, NAME, AllLangPartials.values())); gen.addProvider(AllSoundEvents.provider(gen)); } if (event.includeServer()) { @@ -174,10 +191,6 @@ public class Create { } } - public static CreateRegistrate registrate() { - return REGISTRATE.get(); - } - public static LangBuilder lang() { return new LangBuilder(ID); } diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 11d12d8ca3..27ef263a15 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -2,33 +2,36 @@ package com.simibubi.create; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueSelectionHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.contraptions.components.structureMovement.render.SBBContraptionManager; -import com.simibubi.create.content.contraptions.goggles.GoggleOverlayRenderer; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; -import com.simibubi.create.content.curiosities.armor.CopperBacktankArmorLayer; -import com.simibubi.create.content.curiosities.bell.SoulPulseEffectHandler; -import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient; -import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; -import com.simibubi.create.content.curiosities.weapons.PotatoCannonRenderHandler; -import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler; -import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler; -import com.simibubi.create.content.logistics.trains.GlobalRailwayManager; -import com.simibubi.create.content.schematics.ClientSchematicLoader; +import com.simibubi.create.content.contraptions.glue.SuperGlueSelectionHandler; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.contraptions.render.SBBContraptionManager; +import com.simibubi.create.content.decoration.encasing.CasingConnectivity; +import com.simibubi.create.content.equipment.armor.RemainingAirOverlay; +import com.simibubi.create.content.equipment.bell.SoulPulseEffectHandler; +import com.simibubi.create.content.equipment.blueprint.BlueprintOverlayRenderer; +import com.simibubi.create.content.equipment.goggles.GoggleOverlayRenderer; +import com.simibubi.create.content.equipment.potatoCannon.PotatoCannonRenderHandler; +import com.simibubi.create.content.equipment.toolbox.ToolboxHandlerClient; +import com.simibubi.create.content.equipment.zapper.ZapperRenderHandler; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.waterwheel.WaterWheelRenderer; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerClientHandler; +import com.simibubi.create.content.schematics.client.ClientSchematicLoader; import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.content.schematics.client.SchematicHandler; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.content.trains.TrainHUD; +import com.simibubi.create.content.trains.track.TrackPlacementOverlay; import com.simibubi.create.foundation.ClientResourceReloadListener; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.gui.CreateMainMenuScreen; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsClient; import com.simibubi.create.foundation.ponder.CreatePonderPlugin; import com.simibubi.create.foundation.render.CachedPartialBuffers; import com.simibubi.create.foundation.render.CreateContexts; import com.simibubi.create.foundation.render.FlwSuperBufferFactory; import com.simibubi.create.foundation.utility.ModelSwapper; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.gui.CreateMainMenuScreen; import net.createmod.catnip.config.ui.BaseConfigScreen; import net.createmod.catnip.config.ui.ConfigScreen; @@ -64,6 +67,7 @@ public class CreateClient { public static final PotatoCannonRenderHandler POTATO_CANNON_RENDER_HANDLER = new PotatoCannonRenderHandler(); public static final SoulPulseEffectHandler SOUL_PULSE_EFFECT_HANDLER = new SoulPulseEffectHandler(); public static final GlobalRailwayManager RAILWAYS = new GlobalRailwayManager(); + public static final ValueSettingsClient VALUE_SETTINGS_HANDLER = new ValueSettingsClient(); public static final ClientResourceReloadListener RESOURCE_RELOAD_LISTENER = new ClientResourceReloadListener(); @@ -80,17 +84,27 @@ public class CreateClient { } public static void clientInit(final FMLClientSetupEvent event) { + //BUFFER_CACHE.registerCompartment(CachedBufferer.GENERIC_BLOCK); + //BUFFER_CACHE.registerCompartment(CachedPartialBuffers.partial); + //BUFFER_CACHE.registerCompartment(CachedBufferer.DIRECTIONAL_PARTIAL); + //BUFFER_CACHE.registerCompartment(KineticBlockEntityRenderer.KINETIC_BLOCK); + //BUFFER_CACHE.registerCompartment(WaterWheelRenderer.WATER_WHEEL); + //BUFFER_CACHE.registerCompartment(SBBContraptionManager.CONTRAPTION, 20); + //BUFFER_CACHE.registerCompartment(WorldSectionElement.DOC_WORLD_SECTION, 20); SuperBufferFactory.setInstance(new FlwSuperBufferFactory()); SuperByteBufferCache.getInstance().registerCompartment(CachedPartialBuffers.PARTIAL); SuperByteBufferCache.getInstance().registerCompartment(CachedPartialBuffers.DIRECTIONAL_PARTIAL); - SuperByteBufferCache.getInstance().registerCompartment(KineticTileEntityRenderer.KINETIC_TILE); + SuperByteBufferCache.getInstance().registerCompartment(KineticBlockEntityRenderer.KINETIC_BLOCK); + SuperByteBufferCache.getInstance().registerCompartment(WaterWheelRenderer.WATER_WHEEL); SuperByteBufferCache.getInstance().registerCompartment(SBBContraptionManager.CONTRAPTION, 20); AllKeys.register(); - AllBlockPartials.init(); - AllStitchedTextures.init(); + AllPartialModels.init(); + + //AllPonderTags.register(); + //PonderIndex.register(); PonderIndex.addPlugin(new CreatePonderPlugin()); setupConfigUIBackground(); @@ -100,13 +114,15 @@ public class CreateClient { private static void registerOverlays() { // Register overlays in reverse order - OverlayRegistry.registerOverlayAbove(ForgeIngameGui.AIR_LEVEL_ELEMENT, "Create's Remaining Air", CopperBacktankArmorLayer.REMAINING_AIR_OVERLAY); + OverlayRegistry.registerOverlayAbove(ForgeIngameGui.AIR_LEVEL_ELEMENT, "Create's Remaining Air", RemainingAirOverlay.INSTANCE); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.EXPERIENCE_BAR_ELEMENT, "Create's Train Driver HUD", TrainHUD.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Goggle Information", GoggleOverlayRenderer.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Blueprints", BlueprintOverlayRenderer.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Linked Controller", LinkedControllerClientHandler.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Schematics", SCHEMATIC_HANDLER.getOverlayRenderer()); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Toolboxes", ToolboxHandlerClient.OVERLAY); + OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Value Settings", VALUE_SETTINGS_HANDLER); + OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Track Placement", TrackPlacementOverlay.OVERLAY); } private static void setupConfigUIBackground() { @@ -124,8 +140,8 @@ public class CreateClient { ConfigScreen.shadowState = AllBlocks.LARGE_COGWHEEL.getDefaultState().setValue(CogWheelBlock.AXIS, Direction.Axis.Y); BaseConfigScreen.setDefaultActionFor(Create.ID, base -> base - .withTitles("Client Settings", "World Generation Settings", "Gameplay Settings") - .withSpecs(AllConfigs.CLIENT.specification, AllConfigs.COMMON.specification, AllConfigs.SERVER.specification) + .withButtonLabels("Client Settings", "World Generation Settings", "Gameplay Settings") + .withSpecs(AllConfigs.client().specification, AllConfigs.common().specification, AllConfigs.server().specification) ); } @@ -142,7 +158,7 @@ public class CreateClient { if (mc.options.graphicsMode != GraphicsStatus.FABULOUS) return; - if (AllConfigs.CLIENT.ignoreFabulousWarning.get()) + if (AllConfigs.client().ignoreFabulousWarning.get()) return; MutableComponent text = ComponentUtils.wrapInSquareBrackets(Components.literal("WARN")) diff --git a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java b/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java index 8915492b85..9bdcf69d49 100644 --- a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java +++ b/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java @@ -6,7 +6,7 @@ import java.util.function.Consumer; import com.simibubi.create.Create; import com.simibubi.create.compat.tconstruct.SpoutCasting; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity; +import com.simibubi.create.content.fluids.spout.SpoutBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; @@ -43,7 +43,7 @@ public abstract class BlockSpoutingBehaviour { * @param simulate whether the spout is testing or actually performing this behaviour * @return amount filled into the block, 0 to idle/cancel */ - public abstract int fillBlock(Level world, BlockPos pos, SpoutTileEntity spout, FluidStack availableFluid, + public abstract int fillBlock(Level world, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate); public static void registerDefaults() { diff --git a/src/main/java/com/simibubi/create/api/connectivity/ConnectivityHandler.java b/src/main/java/com/simibubi/create/api/connectivity/ConnectivityHandler.java index 811d8932d4..c520e031f9 100644 --- a/src/main/java/com/simibubi/create/api/connectivity/ConnectivityHandler.java +++ b/src/main/java/com/simibubi/create/api/connectivity/ConnectivityHandler.java @@ -13,8 +13,8 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.Pair; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; -import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity; +import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -31,14 +31,14 @@ import net.minecraftforge.items.CapabilityItemHandler; public class ConnectivityHandler { - public static void formMulti(T be) { + public static void formMulti(T be) { SearchCache cache = new SearchCache<>(); List frontier = new ArrayList<>(); frontier.add(be); formMulti(be.getType(), be.getLevel(), cache, frontier); } - private static void formMulti(BlockEntityType type, + private static void formMulti(BlockEntityType type, BlockGetter level, SearchCache cache, List frontier) { PriorityQueue> creationQueue = makeCreationQueue(); Set visited = new HashSet<>(); @@ -110,7 +110,7 @@ public class ConnectivityHandler { } } - private static int tryToFormNewMulti(T be, SearchCache cache, + private static int tryToFormNewMulti(T be, SearchCache cache, boolean simulate) { int bestWidth = 1; int bestAmount = -1; @@ -132,7 +132,7 @@ public class ConnectivityHandler { return bestAmount; splitMultiAndInvalidate(be, cache, false); - if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank()) + if (be instanceof IMultiBlockEntityContainer.Fluid ifluid && ifluid.hasTank()) ifluid.setTankSize(0, bestAmount); tryToFormNewMultiOfWidth(be, bestWidth, cache, false); @@ -145,7 +145,7 @@ public class ConnectivityHandler { return bestAmount; } - private static int tryToFormNewMultiOfWidth(T be, int width, + private static int tryToFormNewMultiOfWidth(T be, int width, SearchCache cache, boolean simulate) { int amount = 0; int height = 0; @@ -158,7 +158,7 @@ public class ConnectivityHandler { // optional fluid handling IFluidTank beTank = null; FluidStack fluid = FluidStack.EMPTY; - if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank()) { + if (be instanceof IMultiBlockEntityContainer.Fluid ifluid && ifluid.hasTank()) { beTank = ifluid.getTank(0); fluid = beTank.getFluid(); } @@ -213,7 +213,7 @@ public class ConnectivityHandler { break Search; } } - if (controller instanceof IMultiTileContainer.Fluid ifluidCon && ifluidCon.hasTank()) { + if (controller instanceof IMultiBlockEntityContainer.Fluid ifluidCon && ifluidCon.hasTank()) { FluidStack otherFluid = ifluidCon.getFluid(0); if (!fluid.isEmpty() && !otherFluid.isEmpty() && !fluid.isFluidEqual(otherFluid)) break Search; @@ -245,17 +245,17 @@ public class ConnectivityHandler { extraData = be.modifyExtraData(extraData); - if (part instanceof IMultiTileContainer.Fluid ifluidPart && ifluidPart.hasTank()) { + if (part instanceof IMultiBlockEntityContainer.Fluid ifluidPart && ifluidPart.hasTank()) { IFluidTank tankAt = ifluidPart.getTank(0); FluidStack fluidAt = tankAt.getFluid(); if (!fluidAt.isEmpty()) { // making this generic would be a rather large mess, unfortunately if (beTank != null && fluid.isEmpty() - && beTank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank) { - ((CreativeFluidTankTileEntity.CreativeSmartFluidTank) beTank) + && beTank instanceof CreativeFluidTankBlockEntity.CreativeSmartFluidTank) { + ((CreativeFluidTankBlockEntity.CreativeSmartFluidTank) beTank) .setContainedFluid(fluidAt); } - if (be instanceof IMultiTileContainer.Fluid ifluidBE && ifluidBE.hasTank() + if (be instanceof IMultiBlockEntityContainer.Fluid ifluidBE && ifluidBE.hasTank() && beTank != null) { beTank.fill(fluidAt, IFluidHandler.FluidAction.EXECUTE); } @@ -278,18 +278,18 @@ public class ConnectivityHandler { return amount; } - public static void splitMulti(T be) { + public static void splitMulti(T be) { splitMultiAndInvalidate(be, null, false); } // tryReconnect helps whenever only a few tanks have been removed - private static void splitMultiAndInvalidate(T be, + private static void splitMultiAndInvalidate(T be, @Nullable SearchCache cache, boolean tryReconnect) { Level level = be.getLevel(); if (level == null) return; - be = be.getControllerTE(); + be = be.getControllerBE(); if (be == null) return; @@ -305,7 +305,7 @@ public class ConnectivityHandler { // fluid handling, if present FluidStack toDistribute = FluidStack.EMPTY; int maxCapacity = 0; - if (be instanceof IMultiTileContainer.Fluid ifluidBE && ifluidBE.hasTank()) { + if (be instanceof IMultiBlockEntityContainer.Fluid ifluidBE && ifluidBE.hasTank()) { toDistribute = ifluidBE.getFluid(0); maxCapacity = ifluidBE.getTankSize(0); if (!toDistribute.isEmpty() && !be.isRemoved()) @@ -330,16 +330,16 @@ public class ConnectivityHandler { .equals(origin)) continue; - T controllerBE = partAt.getControllerTE(); + T controllerBE = partAt.getControllerBE(); partAt.setExtraData((controllerBE == null ? null : controllerBE.getExtraData())); partAt.removeController(true); if (!toDistribute.isEmpty() && partAt != be) { FluidStack copy = toDistribute.copy(); IFluidTank tank = - (partAt instanceof IMultiTileContainer.Fluid ifluidPart ? ifluidPart.getTank(0) : null); + (partAt instanceof IMultiBlockEntityContainer.Fluid ifluidPart ? ifluidPart.getTank(0) : null); // making this generic would be a rather large mess, unfortunately - if (tank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank creativeTank) { + if (tank instanceof CreativeFluidTankBlockEntity.CreativeSmartFluidTank creativeTank) { if (creativeTank.isEmpty()) creativeTank.setContainedFluid(toDistribute); } else { @@ -360,10 +360,10 @@ public class ConnectivityHandler { } } - if (be instanceof IMultiTileContainer.Inventory iinv && iinv.hasInventory()) + if (be instanceof IMultiBlockEntityContainer.Inventory inv && inv.hasInventory()) be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) .invalidate(); - if (be instanceof IMultiTileContainer.Fluid ifluid && ifluid.hasTank()) + if (be instanceof IMultiBlockEntityContainer.Fluid fluid && fluid.hasTank()) be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) .invalidate(); @@ -371,12 +371,12 @@ public class ConnectivityHandler { formMulti(be.getType(), level, cache == null ? new SearchCache<>() : cache, frontier); } - private static PriorityQueue> makeCreationQueue() { + private static PriorityQueue> makeCreationQueue() { return new PriorityQueue<>((one, two) -> two.getKey() - one.getKey()); } @Nullable - public static T partAt(BlockEntityType type, BlockGetter level, + public static T partAt(BlockEntityType type, BlockGetter level, BlockPos pos) { BlockEntity be = level.getBlockEntity(pos); if (be != null && be.getType() == type && !be.isRemoved()) @@ -384,7 +384,7 @@ public class ConnectivityHandler { return null; } - public static boolean isConnected(BlockGetter level, BlockPos pos, + public static boolean isConnected(BlockGetter level, BlockPos pos, BlockPos other) { T one = checked(level.getBlockEntity(pos)); T two = checked(level.getBlockEntity(other)); @@ -396,13 +396,13 @@ public class ConnectivityHandler { @Nullable @SuppressWarnings("unchecked") - private static T checked(BlockEntity be) { - if (be instanceof IMultiTileContainer) + private static T checked(BlockEntity be) { + if (be instanceof IMultiBlockEntityContainer) return (T) be; return null; } - private static class SearchCache { + private static class SearchCache { Map> controllerMap; public SearchCache() { diff --git a/src/main/java/com/simibubi/create/api/event/BlockEntityBehaviourEvent.java b/src/main/java/com/simibubi/create/api/event/BlockEntityBehaviourEvent.java new file mode 100644 index 0000000000..398783d74a --- /dev/null +++ b/src/main/java/com/simibubi/create/api/event/BlockEntityBehaviourEvent.java @@ -0,0 +1,58 @@ +package com.simibubi.create.api.event; + +import java.lang.reflect.Type; +import java.util.Map; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.eventbus.api.GenericEvent; + +/** + * Event that is fired just before a SmartBlockEntity is being deserialized
+ * Also if a new one is placed
+ * Use it to attach a new {@link BlockEntityBehaviour} or replace existing ones + * (with caution)
+ *
+ * Actual setup of the behaviours internal workings and data should be done in + * BlockEntityBehaviour#read() and BlockEntityBehaviour#initialize() + * respectively.
+ *
+ * Because of the earliness of this event, the added behaviours will have access + * to the initial NBT read (unless the BE was placed, not loaded), thereby + * allowing block entities to store and retrieve data for injected behaviours. + */ +public class BlockEntityBehaviourEvent extends GenericEvent { + + private T smartBlockEntity; + private Map, BlockEntityBehaviour> behaviours; + + public BlockEntityBehaviourEvent(T blockEntity, Map, BlockEntityBehaviour> behaviours) { + smartBlockEntity = blockEntity; + this.behaviours = behaviours; + } + + @Override + public Type getGenericType() { + return smartBlockEntity.getClass(); + } + + public void attach(BlockEntityBehaviour behaviour) { + behaviours.put(behaviour.getType(), behaviour); + } + + public BlockEntityBehaviour remove(BehaviourType type) { + return behaviours.remove(type); + } + + public T getBlockEntity() { + return smartBlockEntity; + } + + public BlockState getBlockState() { + return smartBlockEntity.getBlockState(); + } + +} diff --git a/src/main/java/com/simibubi/create/api/event/TileEntityBehaviourEvent.java b/src/main/java/com/simibubi/create/api/event/TileEntityBehaviourEvent.java deleted file mode 100644 index 657d21065f..0000000000 --- a/src/main/java/com/simibubi/create/api/event/TileEntityBehaviourEvent.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.simibubi.create.api.event; - -import java.lang.reflect.Type; -import java.util.Map; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; - -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.eventbus.api.GenericEvent; - -/** - * Event that is fired just before a SmartTileEntity is being deserialized
- * Also if a new one is placed
- * Use it to attach a new {@link TileEntityBehaviour} or replace existing ones - * (with caution)
- *
- * Actual setup of the behaviours internal workings and data should be done in - * TileEntityBehaviour#read() and TileEntityBehaviour#initialize() - * respectively.
- *
- * Because of the earliness of this event, the added behaviours will have access - * to the initial NBT read (unless the TE was placed, not loaded), thereby - * allowing tiles to store and retrieve data for injected behaviours. - */ -public class TileEntityBehaviourEvent extends GenericEvent { - - private T smartTileEntity; - private Map, TileEntityBehaviour> behaviours; - - public TileEntityBehaviourEvent(T tileEntity, Map, TileEntityBehaviour> behaviours) { - smartTileEntity = tileEntity; - this.behaviours = behaviours; - } - - @Override - public Type getGenericType() { - return smartTileEntity.getClass(); - } - - public void attach(TileEntityBehaviour behaviour) { - behaviours.put(behaviour.getType(), behaviour); - } - - public TileEntityBehaviour remove(BehaviourType type) { - return behaviours.remove(type); - } - - public T getTileEntity() { - return smartTileEntity; - } - - public BlockState getBlockState() { - return smartTileEntity.getBlockState(); - } - -} diff --git a/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java b/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java new file mode 100644 index 0000000000..d48e2a3a79 --- /dev/null +++ b/src/main/java/com/simibubi/create/api/event/TrackGraphMergeEvent.java @@ -0,0 +1,22 @@ +package com.simibubi.create.api.event; + +import com.simibubi.create.content.trains.graph.TrackGraph; + +import net.minecraftforge.eventbus.api.Event; + +public class TrackGraphMergeEvent extends Event{ + private TrackGraph mergedInto, mergedFrom; + + public TrackGraphMergeEvent(TrackGraph from, TrackGraph into) { + mergedInto = into; + mergedFrom = from; + } + + public TrackGraph getGraphMergedInto() { + return mergedInto; + } + + public TrackGraph getGraphMergedFrom() { + return mergedFrom; + } +} diff --git a/src/main/java/com/simibubi/create/compat/Mods.java b/src/main/java/com/simibubi/create/compat/Mods.java index bccf79f7ce..9d71f076b7 100644 --- a/src/main/java/com/simibubi/create/compat/Mods.java +++ b/src/main/java/com/simibubi/create/compat/Mods.java @@ -4,7 +4,10 @@ import java.util.Optional; import java.util.function.Supplier; import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import net.minecraftforge.fml.ModList; +import net.minecraftforge.registries.ForgeRegistries; /** * For compatibility with and without another mod present, we have to define load conditions of the specific code @@ -12,7 +15,11 @@ import net.minecraftforge.fml.ModList; public enum Mods { DYNAMICTREES, TCONSTRUCT, - CURIOS; + CURIOS, + + COMPUTERCRAFT, + STORAGEDRAWERS, + XLPACKETS; /** * @return a boolean of whether the mod is loaded or not based on mod id @@ -48,4 +55,8 @@ public enum Mods { toExecute.get().run(); } } + + public Block getBlock(String id) { + return ForgeRegistries.BLOCKS.getValue(new ResourceLocation(asId(), id)); + } } diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java new file mode 100644 index 0000000000..956aad0b6c --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/AbstractComputerBehaviour.java @@ -0,0 +1,57 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class AbstractComputerBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + boolean hasAttachedComputer; + + public AbstractComputerBehaviour(SmartBlockEntity te) { + super(te); + this.hasAttachedComputer = false; + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + hasAttachedComputer = nbt.getBoolean("HasAttachedComputer"); + super.read(nbt, clientPacket); + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + nbt.putBoolean("HasAttachedComputer", hasAttachedComputer); + super.write(nbt, clientPacket); + } + + public boolean isPeripheralCap(Capability cap) { + return false; + } + + public LazyOptional getPeripheralCapability() { + return LazyOptional.empty(); + } + + public void removePeripheral() {} + + public void setHasAttachedComputer(boolean hasAttachedComputer) { + this.hasAttachedComputer = hasAttachedComputer; + } + + public boolean hasAttachedComputer() { + return hasAttachedComputer; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java new file mode 100644 index 0000000000..0304e864be --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/AttachedComputerPacket.java @@ -0,0 +1,37 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.SyncedBlockEntity; +import com.simibubi.create.foundation.networking.BlockEntityDataPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class AttachedComputerPacket extends BlockEntityDataPacket { + + private final boolean hasAttachedComputer; + + public AttachedComputerPacket(BlockPos blockEntityPos, boolean hasAttachedComputer) { + super(blockEntityPos); + this.hasAttachedComputer = hasAttachedComputer; + } + + public AttachedComputerPacket(FriendlyByteBuf buffer) { + super(buffer); + this.hasAttachedComputer = buffer.readBoolean(); + } + + @Override + protected void writeData(FriendlyByteBuf buffer) { + buffer.writeBoolean(hasAttachedComputer); + } + + @Override + protected void handlePacket(SyncedBlockEntity blockEntity) { + if (blockEntity instanceof SmartBlockEntity sbe) { + sbe.getBehaviour(AbstractComputerBehaviour.TYPE) + .setHasAttachedComputer(hasAttachedComputer); + } + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java b/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java new file mode 100644 index 0000000000..04c27c8ec8 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/ComputerCraftProxy.java @@ -0,0 +1,30 @@ +package com.simibubi.create.compat.computercraft; + +import java.util.function.Function; + +import com.simibubi.create.compat.Mods; +import com.simibubi.create.compat.computercraft.implementation.ComputerBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; + +public class ComputerCraftProxy { + + public static void register() { + fallbackFactory = FallbackComputerBehaviour::new; + Mods.COMPUTERCRAFT.executeIfInstalled(() -> ComputerCraftProxy::registerWithDependency); + } + + private static void registerWithDependency() { + /* Comment if computercraft.implementation is not in the source set */ + computerFactory = ComputerBehaviour::new; + } + + private static Function fallbackFactory; + private static Function computerFactory; + + public static AbstractComputerBehaviour behaviour(SmartBlockEntity sbe) { + if (computerFactory == null) + return fallbackFactory.apply(sbe); + return computerFactory.apply(sbe); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java b/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java new file mode 100644 index 0000000000..be5af1dc7b --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/ComputerScreen.java @@ -0,0 +1,96 @@ +package com.simibubi.create.compat.computercraft; + +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.compat.Mods; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.gui.widget.AbstractSimiWidget; +import net.createmod.catnip.gui.widget.ElementWidget; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +public class ComputerScreen extends AbstractSimiScreen { + + private final AllGuiTextures background = AllGuiTextures.COMPUTER; + + private final Supplier displayTitle; + private final RenderWindowFunction additional; + private final Screen previousScreen; + private final Supplier hasAttachedComputer; + + private AbstractSimiWidget computerWidget; + private IconButton confirmButton; + + public ComputerScreen(Component title, @Nullable RenderWindowFunction additional, Screen previousScreen, Supplier hasAttachedComputer) { + this(title, () -> title, additional, previousScreen, hasAttachedComputer); + } + + public ComputerScreen(Component title, Supplier displayTitle, @Nullable RenderWindowFunction additional, Screen previousScreen, Supplier hasAttachedComputer) { + super(title); + this.displayTitle = displayTitle; + this.additional = additional; + this.previousScreen = previousScreen; + this.hasAttachedComputer = hasAttachedComputer; + } + + @Override + public void tick() { + if (!hasAttachedComputer.get()) + minecraft.setScreen(previousScreen); + + super.tick(); + } + + @Override + protected void init() { + setWindowSize(background.getWidth(), background.getHeight()); + super.init(); + + int x = guiLeft; + int y = guiTop; + + Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { + computerWidget = new ElementWidget(x + 33, y + 38) + .showingElement(GuiGameElement.of(Mods.COMPUTERCRAFT.getBlock("computer_advanced"))); + computerWidget.getToolTip().add(CreateLang.translate("gui.attached_computer.hint").component()); + addRenderableWidget(computerWidget); + }); + + confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(this::onClose); + addRenderableWidget(confirmButton); + } + + + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + + font.draw(ms, displayTitle.get(), x + background.getWidth() / 2.0F - font.width(displayTitle.get()) / 2.0F, y + 4, 0x442000); + font.drawWordWrap(CreateLang.translate("gui.attached_computer.controlled").component(), x + 55, y + 32, 111, 0x7A7A7A); + + if (additional != null) + additional.render(ms, mouseX, mouseY, partialTicks, x, y, background); + } + + @FunctionalInterface + public interface RenderWindowFunction { + + void render(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, AllGuiTextures background); + + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java new file mode 100644 index 0000000000..7e58c270d6 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/FallbackComputerBehaviour.java @@ -0,0 +1,16 @@ +package com.simibubi.create.compat.computercraft; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; + +public class FallbackComputerBehaviour extends AbstractComputerBehaviour { + + public FallbackComputerBehaviour(SmartBlockEntity te) { + super(te); + } + + @Override + public boolean hasAttachedComputer() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java new file mode 100644 index 0000000000..e33cc4a9d1 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/ComputerBehaviour.java @@ -0,0 +1,74 @@ +package com.simibubi.create.compat.computercraft.implementation; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.implementation.peripherals.DisplayLinkPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SequencedGearshiftPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedControllerPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.SpeedGaugePeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.StationPeripheral; +import com.simibubi.create.compat.computercraft.implementation.peripherals.StressGaugePeripheral; +import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity; +import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; + +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.capabilities.CapabilityToken; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullSupplier; + +public class ComputerBehaviour extends AbstractComputerBehaviour { + + protected static final Capability PERIPHERAL_CAPABILITY = + CapabilityManager.get(new CapabilityToken<>() { + }); + LazyOptional peripheral; + NonNullSupplier peripheralSupplier; + + public ComputerBehaviour(SmartBlockEntity te) { + super(te); + this.peripheralSupplier = getPeripheralFor(te); + } + + public static NonNullSupplier getPeripheralFor(SmartBlockEntity be) { + if (be instanceof SpeedControllerBlockEntity scbe) + return () -> new SpeedControllerPeripheral(scbe, scbe.targetSpeed); + if (be instanceof DisplayLinkBlockEntity dlbe) + return () -> new DisplayLinkPeripheral(dlbe); + if (be instanceof SequencedGearshiftBlockEntity sgbe) + return () -> new SequencedGearshiftPeripheral(sgbe); + if (be instanceof SpeedGaugeBlockEntity sgbe) + return () -> new SpeedGaugePeripheral(sgbe); + if (be instanceof StressGaugeBlockEntity sgbe) + return () -> new StressGaugePeripheral(sgbe); + if (be instanceof StationBlockEntity sbe) + return () -> new StationPeripheral(sbe); + + throw new IllegalArgumentException("No peripheral available for " + be.getType() + .getRegistryName()); + } + + @Override + public boolean isPeripheralCap(Capability cap) { + return cap == PERIPHERAL_CAPABILITY; + } + + @Override + public LazyOptional getPeripheralCapability() { + if (peripheral == null || !peripheral.isPresent()) + peripheral = LazyOptional.of(peripheralSupplier); + return peripheral.cast(); + } + + @Override + public void removePeripheral() { + if (peripheral != null) + peripheral.invalidate(); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java new file mode 100644 index 0000000000..3c957274ed --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/CreateLuaTable.java @@ -0,0 +1,172 @@ +package com.simibubi.create.compat.computercraft.implementation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaTable; +import dan200.computercraft.api.lua.LuaValues; + +public class CreateLuaTable implements LuaTable { + + private final Map map; + + public CreateLuaTable() { + this.map = new HashMap<>(); + } + + public CreateLuaTable(Map map) { + this.map = new HashMap<>(map); + } + + public boolean getBoolean(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof Boolean)) + throw LuaValues.badField(key, "boolean", LuaValues.getType(value)); + + return (Boolean) value; + } + + public String getString(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof String)) + throw LuaValues.badField(key, "string", LuaValues.getType(value)); + + return (String) value; + } + + public CreateLuaTable getTable(String key) throws LuaException { + Object value = get(key); + + if (!(value instanceof Map)) + throw LuaValues.badField(key, "table", LuaValues.getType(value)); + + return new CreateLuaTable((Map) value); + } + + public Optional getOptBoolean(String key) throws LuaException { + Object value = get(key); + + if (value == null) + return Optional.empty(); + + if (!(value instanceof Boolean)) + throw LuaValues.badField(key, "boolean", LuaValues.getType(value)); + + return Optional.of((Boolean) value); + } + + public Set stringKeySet() throws LuaException { + Set stringSet = new HashSet<>(); + + for (Object key : keySet()) { + if (!(key instanceof String)) + throw new LuaException("key " + key + " is not string (got " + LuaValues.getType(key) + ")"); + + stringSet.add((String) key); + } + + return Collections.unmodifiableSet(stringSet); + } + + public Collection tableValues() throws LuaException { + List tables = new ArrayList<>(); + + for (int i = 1; i <= size(); i++) { + Object value = get((double) i); + + if (!(value instanceof Map)) + throw new LuaException("value " + value + " is not table (got " + LuaValues.getType(value) + ")"); + + tables.add(new CreateLuaTable((Map) value)); + } + + return Collections.unmodifiableList(tables); + } + + public Map getMap() { + return map; + } + + @Nullable + @Override + public Object put(Object key, Object value) { + return map.put(key, value); + } + + public void putBoolean(String key, boolean value) { + map.put(key, value); + } + + public void putDouble(String key, double value) { + map.put(key, value); + } + + public void putString(String key, String value) { + map.put(key, value); + } + + public void putTable(String key, CreateLuaTable value) { + map.put(key, value); + } + + public void putTable(int i, CreateLuaTable value) { + map.put(i, value); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return map.containsKey(o); + } + + @Override + public boolean containsValue(Object o) { + return map.containsValue(o); + } + + @Override + public Object get(Object o) { + return map.get(o); + } + + @NotNull + @Override + public Set keySet() { + return map.keySet(); + } + + @NotNull + @Override + public Collection values() { + return map.values(); + } + + @NotNull + @Override + public Set> entrySet() { + return map.entrySet(); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java new file mode 100644 index 0000000000..2d1c9d29bd --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/DisplayLinkPeripheral.java @@ -0,0 +1,108 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; + +import dan200.computercraft.api.lua.LuaFunction; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; + +public class DisplayLinkPeripheral extends SyncedPeripheral { + + public static final String TAG_KEY = "ComputerSourceList"; + private final AtomicInteger cursorX = new AtomicInteger(); + private final AtomicInteger cursorY = new AtomicInteger(); + + public DisplayLinkPeripheral(DisplayLinkBlockEntity blockEntity) { + super(blockEntity); + } + + @LuaFunction + public final void setCursorPos(int x, int y) { + cursorX.set(x - 1); + cursorY.set(y - 1); + } + + @LuaFunction + public final Object[] getCursorPos() { + return new Object[] {cursorX.get() + 1, cursorY.get() + 1}; + } + + @LuaFunction(mainThread = true) + public final Object[] getSize() { + DisplayTargetStats stats = blockEntity.activeTarget.provideStats(new DisplayLinkContext(blockEntity.getLevel(), blockEntity)); + return new Object[]{stats.maxRows(), stats.maxColumns()}; + } + + @LuaFunction + public final boolean isColor() { + return false; + } + + @LuaFunction + public final boolean isColour() { + return false; + } + + @LuaFunction + public final void write(String text) { + ListTag tag = blockEntity.getSourceConfig().getList(TAG_KEY, Tag.TAG_STRING); + + int x = cursorX.get(); + int y = cursorY.get(); + + for (int i = tag.size(); i <= y; i++) { + tag.add(StringTag.valueOf("")); + } + + StringBuilder builder = new StringBuilder(tag.getString(y)); + + builder.append(" ".repeat(Math.max(0, x - builder.length()))); + builder.replace(x, x + text.length(), text); + + tag.set(y, StringTag.valueOf(builder.toString())); + + synchronized (blockEntity) { + blockEntity.getSourceConfig().put(TAG_KEY, tag); + } + + cursorX.set(x + text.length()); + } + + @LuaFunction + public final void clearLine() { + ListTag tag = blockEntity.getSourceConfig().getList(TAG_KEY, Tag.TAG_STRING); + + if (tag.size() > cursorY.get()) + tag.set(cursorY.get(), StringTag.valueOf("")); + + synchronized (blockEntity) { + blockEntity.getSourceConfig().put(TAG_KEY, tag); + } + } + + @LuaFunction + public final void clear() { + synchronized (blockEntity) { + blockEntity.getSourceConfig().put(TAG_KEY, new ListTag()); + } + } + + @LuaFunction(mainThread = true) + public final void update() { + blockEntity.tickSource(); + } + + @NotNull + @Override + public String getType() { + return "Create_DisplayLink"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java new file mode 100644 index 0000000000..9d83359f89 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SequencedGearshiftPeripheral.java @@ -0,0 +1,54 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.kinetics.transmission.sequencer.Instruction; +import com.simibubi.create.content.kinetics.transmission.sequencer.InstructionSpeedModifiers; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencerInstructions; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; + +public class SequencedGearshiftPeripheral extends SyncedPeripheral { + + public SequencedGearshiftPeripheral(SequencedGearshiftBlockEntity blockEntity) { + super(blockEntity); + } + + @LuaFunction(mainThread = true) + public final void rotate(IArguments arguments) throws LuaException { + runInstruction(arguments, SequencerInstructions.TURN_ANGLE); + } + + @LuaFunction(mainThread = true) + public final void move(IArguments arguments) throws LuaException { + runInstruction(arguments, SequencerInstructions.TURN_DISTANCE); + } + + @LuaFunction + public final boolean isRunning() { + return !this.blockEntity.isIdle(); + } + + private void runInstruction(IArguments arguments, SequencerInstructions instructionType) throws LuaException { + int speedModifier = arguments.count() > 1 ? arguments.getInt(1) : 1; + this.blockEntity.getInstructions().clear(); + + this.blockEntity.getInstructions().add(new Instruction( + instructionType, + InstructionSpeedModifiers.getByModifier(speedModifier), + Math.abs(arguments.getInt(0)))); + this.blockEntity.getInstructions().add(new Instruction(SequencerInstructions.END)); + + this.blockEntity.run(0); + } + + @NotNull + @Override + public String getType() { + return "Create_SequencedGearshift"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java new file mode 100644 index 0000000000..233a81e97e --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedControllerPeripheral.java @@ -0,0 +1,35 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; + +import dan200.computercraft.api.lua.LuaFunction; + +public class SpeedControllerPeripheral extends SyncedPeripheral { + + private final ScrollValueBehaviour targetSpeed; + + public SpeedControllerPeripheral(SpeedControllerBlockEntity blockEntity, ScrollValueBehaviour targetSpeed) { + super(blockEntity); + this.targetSpeed = targetSpeed; + } + + @LuaFunction(mainThread = true) + public final void setTargetSpeed(int speed) { + this.targetSpeed.setValue(speed); + } + + @LuaFunction + public final float getTargetSpeed() { + return this.targetSpeed.getValue(); + } + + @NotNull + @Override + public String getType() { + return "Create_RotationSpeedController"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java new file mode 100644 index 0000000000..d6ff9d20bf --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SpeedGaugePeripheral.java @@ -0,0 +1,26 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity; + +import dan200.computercraft.api.lua.LuaFunction; + +public class SpeedGaugePeripheral extends SyncedPeripheral { + + public SpeedGaugePeripheral(SpeedGaugeBlockEntity blockEntity) { + super(blockEntity); + } + + @LuaFunction + public final float getSpeed() { + return this.blockEntity.getSpeed(); + } + + @NotNull + @Override + public String getType() { + return "Create_Speedometer"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java new file mode 100644 index 0000000000..1c50e6ff20 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StationPeripheral.java @@ -0,0 +1,269 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.Map; + +import javax.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.compat.computercraft.implementation.CreateLuaTable; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.content.trains.station.TrainEditPacket; +import com.simibubi.create.foundation.utility.StringHelper; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.nbt.ByteTag; +import net.minecraft.nbt.CollectionTag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraftforge.network.PacketDistributor; + +public class StationPeripheral extends SyncedPeripheral { + + public StationPeripheral(StationBlockEntity blockEntity) { + super(blockEntity); + } + + @LuaFunction(mainThread = true) + public final void assemble() throws LuaException { + if (!blockEntity.isAssembling()) + throw new LuaException("station must be in assembly mode"); + + blockEntity.assemble(null); + + if (blockEntity.getStation() == null || blockEntity.getStation().getPresentTrain() == null) + throw new LuaException("failed to assemble train"); + + if (!blockEntity.exitAssemblyMode()) + throw new LuaException("failed to exit assembly mode"); + } + + @LuaFunction(mainThread = true) + public final void disassemble() throws LuaException { + if (blockEntity.isAssembling()) + throw new LuaException("station must not be in assembly mode"); + + getTrainOrThrow(); + + if (!blockEntity.enterAssemblyMode(null)) + throw new LuaException("could not disassemble train"); + } + + @LuaFunction(mainThread = true) + public final void setAssemblyMode(boolean assemblyMode) throws LuaException { + if (assemblyMode) { + if (!blockEntity.enterAssemblyMode(null)) + throw new LuaException("failed to enter assembly mode"); + } else { + if (!blockEntity.exitAssemblyMode()) + throw new LuaException("failed to exit assembly mode"); + } + } + + @LuaFunction + public final boolean isInAssemblyMode() { + return blockEntity.isAssembling(); + } + + @LuaFunction + public final String getStationName() throws LuaException { + GlobalStation station = blockEntity.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.name; + } + + @LuaFunction(mainThread = true) + public final void setStationName(String name) throws LuaException { + if (!blockEntity.updateName(name)) + throw new LuaException("could not set station name"); + } + + @LuaFunction + public final boolean isTrainPresent() throws LuaException { + GlobalStation station = blockEntity.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getPresentTrain() != null; + } + + @LuaFunction + public final boolean isTrainImminent() throws LuaException { + GlobalStation station = blockEntity.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getImminentTrain() != null; + } + + @LuaFunction + public final boolean isTrainEnroute() throws LuaException { + GlobalStation station = blockEntity.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + return station.getNearestTrain() != null; + } + + @LuaFunction + public final String getTrainName() throws LuaException { + Train train = getTrainOrThrow(); + return train.name.getString(); + } + + @LuaFunction(mainThread = true) + public final void setTrainName(String name) throws LuaException { + Train train = getTrainOrThrow(); + train.name = Components.literal(name); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId())); + } + + @LuaFunction + public final boolean hasSchedule() throws LuaException { + Train train = getTrainOrThrow(); + return train.runtime.getSchedule() != null; + } + + @LuaFunction + public final CreateLuaTable getSchedule() throws LuaException { + Train train = getTrainOrThrow(); + + Schedule schedule = train.runtime.getSchedule(); + if (schedule == null) + throw new LuaException("train doesn't have a schedule"); + + return fromCompoundTag(schedule.write()); + } + + @LuaFunction(mainThread = true) + public final void setSchedule(IArguments arguments) throws LuaException { + Train train = getTrainOrThrow(); + Schedule schedule = Schedule.fromTag(toCompoundTag(new CreateLuaTable(arguments.getTable(0)))); + boolean autoSchedule = train.runtime.getSchedule() == null || train.runtime.isAutoSchedule; + train.runtime.setSchedule(schedule, autoSchedule); + } + + private @NotNull Train getTrainOrThrow() throws LuaException { + GlobalStation station = blockEntity.getStation(); + if (station == null) + throw new LuaException("station is not connected to a track"); + + Train train = station.getPresentTrain(); + if (train == null) + throw new LuaException("there is no train present"); + + return train; + } + + private static @NotNull CreateLuaTable fromCompoundTag(CompoundTag tag) throws LuaException { + return (CreateLuaTable) fromNBTTag(null, tag); + } + + private static @NotNull Object fromNBTTag(@Nullable String key, Tag tag) throws LuaException { + byte type = tag.getId(); + + if (type == Tag.TAG_BYTE && key != null && key.equals("Count")) + return ((NumericTag) tag).getAsByte(); + else if (type == Tag.TAG_BYTE) + return ((NumericTag) tag).getAsByte() != 0; + else if (type == Tag.TAG_SHORT || type == Tag.TAG_INT || type == Tag.TAG_LONG) + return ((NumericTag) tag).getAsLong(); + else if (type == Tag.TAG_FLOAT || type == Tag.TAG_DOUBLE) + return ((NumericTag) tag).getAsDouble(); + else if (type == Tag.TAG_STRING) + return tag.getAsString(); + else if (type == Tag.TAG_LIST || type == Tag.TAG_BYTE_ARRAY || type == Tag.TAG_INT_ARRAY || type == Tag.TAG_LONG_ARRAY) { + CreateLuaTable list = new CreateLuaTable(); + CollectionTag listTag = (CollectionTag) tag; + + for (int i = 0; i < listTag.size(); i++) { + list.put(i + 1, fromNBTTag(null, listTag.get(i))); + } + + return list; + + } else if (type == Tag.TAG_COMPOUND) { + CreateLuaTable table = new CreateLuaTable(); + CompoundTag compoundTag = (CompoundTag) tag; + + for (String compoundKey : compoundTag.getAllKeys()) { + table.put( + StringHelper.camelCaseToSnakeCase(compoundKey), + fromNBTTag(compoundKey, compoundTag.get(compoundKey)) + ); + } + + return table; + } + + throw new LuaException("unknown tag type " + tag.getType().getName()); + } + + private static @NotNull CompoundTag toCompoundTag(CreateLuaTable table) throws LuaException { + return (CompoundTag) toNBTTag(null, table.getMap()); + } + + private static @NotNull Tag toNBTTag(@Nullable String key, Object value) throws LuaException { + if (value instanceof Boolean v) + return ByteTag.valueOf(v); + else if (value instanceof Byte || (key != null && key.equals("count"))) + return ByteTag.valueOf(((Number) value).byteValue()); + else if (value instanceof Number v) { + // If number is numerical integer + if (v.intValue() == v.doubleValue()) + return IntTag.valueOf(v.intValue()); + else + return DoubleTag.valueOf(v.doubleValue()); + + } else if (value instanceof String v) + return StringTag.valueOf(v); + else if (value instanceof Map v && v.containsKey(1.0)) { // List + ListTag list = new ListTag(); + for (Object o : v.values()) { + list.add(toNBTTag(null, o)); + } + + return list; + + } else if (value instanceof Map v) { // Table/Map + CompoundTag compound = new CompoundTag(); + for (Object objectKey : v.keySet()) { + if (!(objectKey instanceof String compoundKey)) + throw new LuaException("table key is not of type string"); + + compound.put( + // Items serialize their resource location as "id" and not as "Id". + // This check is needed to see if the 'i' should be left lowercase or not. + // Items store "count" in the same compound tag, so we can check for its presence to see if this is a serialized item + compoundKey.equals("id") && v.containsKey("count") ? "id" : StringHelper.snakeCaseToCamelCase(compoundKey), + toNBTTag(compoundKey, v.get(compoundKey)) + ); + } + + return compound; + } + + throw new LuaException("unknown object type " + value.getClass().getName()); + } + + @NotNull + @Override + public String getType() { + return "Create_Station"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java new file mode 100644 index 0000000000..19c45a1625 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/StressGaugePeripheral.java @@ -0,0 +1,31 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity; + +import dan200.computercraft.api.lua.LuaFunction; + +public class StressGaugePeripheral extends SyncedPeripheral { + + public StressGaugePeripheral(StressGaugeBlockEntity blockEntity) { + super(blockEntity); + } + + @LuaFunction + public final float getStress() { + return this.blockEntity.getNetworkStress(); + } + + @LuaFunction + public final float getStressCapacity() { + return this.blockEntity.getNetworkCapacity(); + } + + @NotNull + @Override + public String getType() { + return "Create_Stressometer"; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java new file mode 100644 index 0000000000..7c0b1f7b11 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/computercraft/implementation/peripherals/SyncedPeripheral.java @@ -0,0 +1,50 @@ +package com.simibubi.create.compat.computercraft.implementation.peripherals; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.compat.computercraft.AttachedComputerPacket; +import com.simibubi.create.compat.computercraft.implementation.ComputerBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; + +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraftforge.network.PacketDistributor; + +public abstract class SyncedPeripheral implements IPeripheral { + + protected final T blockEntity; + private final AtomicInteger computers = new AtomicInteger(); + + public SyncedPeripheral(T blockEntity) { + this.blockEntity = blockEntity; + } + + @Override + public void attach(@NotNull IComputerAccess computer) { + computers.incrementAndGet(); + updateBlockEntity(); + } + + @Override + public void detach(@NotNull IComputerAccess computer) { + computers.decrementAndGet(); + updateBlockEntity(); + } + + private void updateBlockEntity() { + boolean hasAttachedComputer = computers.get() > 0; + + blockEntity.getBehaviour(ComputerBehaviour.TYPE).setHasAttachedComputer(hasAttachedComputer); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new AttachedComputerPacket(blockEntity.getBlockPos(), hasAttachedComputer)); + } + + @Override + public boolean equals(@Nullable IPeripheral other) { + return this == other; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/curios/Curios.java b/src/main/java/com/simibubi/create/compat/curios/Curios.java index 5666771258..97eea93e2a 100644 --- a/src/main/java/com/simibubi/create/compat/curios/Curios.java +++ b/src/main/java/com/simibubi/create/compat/curios/Curios.java @@ -1,40 +1,83 @@ package com.simibubi.create.compat.curios; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.goggles.GogglesItem; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.equipment.armor.BacktankUtil; +import com.simibubi.create.content.equipment.goggles.GogglesItem; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import top.theillusivec4.curios.api.CuriosCapability; import top.theillusivec4.curios.api.SlotTypeMessage; import top.theillusivec4.curios.api.SlotTypePreset; +import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; public class Curios { - public static void init() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(Curios::onInterModEnqueue); - FMLJavaModLoadingContext.get().getModEventBus().addListener(Curios::onClientSetup); - GogglesItem.addIsWearingPredicate(player -> { - AtomicBoolean hasGoggles = new AtomicBoolean(false); - player.getCapability(CuriosCapability.INVENTORY).ifPresent(handler -> { - ICurioStacksHandler stacksHandler = handler.getCurios().get("head"); - if(stacksHandler != null) hasGoggles.set(stacksHandler.getStacks().getStackInSlot(0).getItem() == AllItems.GOGGLES.get()); - }); - return hasGoggles.get(); - }); + /** + * Resolves the Stacks Handler Map given an Entity. + * It is recommended to then use a `.map(curiosMap -> curiosMap.get({key})`, + * which can be null and would therefore be caught by the Optional::map function. + * + * @param entity The entity which possibly has a Curio Inventory capability + * @return An optional of the Stacks Handler Map + */ + private static Optional> resolveCuriosMap(LivingEntity entity) { + return entity.getCapability(CuriosCapability.INVENTORY).map(ICuriosItemHandler::getCurios); + } - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(CuriosRenderers::onLayerRegister)); + public static void init(IEventBus modEventBus, IEventBus forgeEventBus) { + modEventBus.addListener(Curios::onInterModEnqueue); + modEventBus.addListener(Curios::onClientSetup); + + GogglesItem.addIsWearingPredicate(player -> resolveCuriosMap(player) + .map(curiosMap -> curiosMap.get("head")) + .map(stacksHandler -> { + // Check all the Head slots for Goggles existing + int slots = stacksHandler.getSlots(); + for (int slot = 0; slot < slots; slot++) + if (AllItems.GOGGLES.isIn(stacksHandler.getStacks().getStackInSlot(slot))) + return true; + + return false; + }) + .orElse(false)); + + BacktankUtil.addBacktankSupplier(entity -> resolveCuriosMap(entity) + .map(curiosMap -> { + List stacks = new ArrayList<>(); + for (ICurioStacksHandler stacksHandler : curiosMap.values()) { + // Search all the curio slots for pressurized air sources, and add them to the list + int slots = stacksHandler.getSlots(); + for (int slot = 0; slot < slots; slot++) { + final ItemStack itemStack = stacksHandler.getStacks().getStackInSlot(slot); + if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack)) + stacks.add(itemStack); + } + } + + return stacks; + }).orElse(new ArrayList<>())); + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> modEventBus.addListener(CuriosRenderers::onLayerRegister)); } private static void onInterModEnqueue(final InterModEnqueueEvent event) { - InterModComms.sendTo("curios", SlotTypeMessage.REGISTER_TYPE, () -> SlotTypePreset.HEAD.getMessageBuilder().build()); + InterModComms.sendTo("curios", SlotTypeMessage.REGISTER_TYPE, () -> SlotTypePreset.HEAD.getMessageBuilder() + .build()); } private static void onClientSetup(final FMLClientSetupEvent event) { diff --git a/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java b/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java index d4a25db7c6..c46d9a4142 100644 --- a/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java +++ b/src/main/java/com/simibubi/create/compat/jei/BlueprintTransferHandler.java @@ -4,9 +4,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.jetbrains.annotations.Nullable; -import com.simibubi.create.content.curiosities.tools.BlueprintAssignCompleteRecipePacket; -import com.simibubi.create.content.curiosities.tools.BlueprintContainer; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.equipment.blueprint.BlueprintAssignCompleteRecipePacket; +import com.simibubi.create.content.equipment.blueprint.BlueprintMenu; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; import mezz.jei.api.recipe.transfer.IRecipeTransferError; @@ -17,11 +17,11 @@ import net.minecraft.world.item.crafting.CraftingRecipe; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class BlueprintTransferHandler implements IRecipeTransferHandler { +public class BlueprintTransferHandler implements IRecipeTransferHandler { @Override - public Class getContainerClass() { - return BlueprintContainer.class; + public Class getContainerClass() { + return BlueprintMenu.class; } @Override @@ -30,11 +30,11 @@ public class BlueprintTransferHandler implements IRecipeTransferHandler r instanceof CraftingRecipe && !(r instanceof IShapedRecipe) && r.getIngredients() .size() > 1 - && !MechanicalPressTileEntity.canCompress(r) && !AllRecipeTypes.shouldIgnoreInAutomation(r), + && !MechanicalPressBlockEntity.canCompress(r) && !AllRecipeTypes.shouldIgnoreInAutomation(r), BasinRecipe::convertShapeless) .catalyst(AllBlocks.MECHANICAL_MIXER::get) .catalyst(AllBlocks.BASIN::get) @@ -206,7 +206,7 @@ public class CreateJEI implements IModPlugin { .enableWhen(c -> c.allowShapedSquareInPress) .addAllRecipesIf( r -> (r instanceof CraftingRecipe) && !(r instanceof MechanicalCraftingRecipe) - && MechanicalPressTileEntity.canCompress(r) && !AllRecipeTypes.shouldIgnoreInAutomation(r), + && MechanicalPressBlockEntity.canCompress(r) && !AllRecipeTypes.shouldIgnoreInAutomation(r), BasinRecipe::convertShapeless) .catalyst(AllBlocks.MECHANICAL_PRESS::get) .catalyst(AllBlocks.BASIN::get) @@ -232,7 +232,7 @@ public class CreateJEI implements IModPlugin { woodCutting = builder(CondensedBlockCuttingRecipe.class) .enableIf(c -> c.allowWoodcuttingOnSaw.get() && ModList.get() .isLoaded("druidcraft")) - .addRecipes(() -> CondensedBlockCuttingRecipe.condenseRecipes(getTypedRecipesExcluding(SawTileEntity.woodcuttingRecipeType.get(), AllRecipeTypes::shouldIgnoreInAutomation))) + .addRecipes(() -> CondensedBlockCuttingRecipe.condenseRecipes(getTypedRecipesExcluding(SawBlockEntity.woodcuttingRecipeType.get(), AllRecipeTypes::shouldIgnoreInAutomation))) .catalyst(AllBlocks.MECHANICAL_SAW::get) .doubleItemIcon(AllBlocks.MECHANICAL_SAW.get(), Items.OAK_STAIRS) .emptyBackground(177, 70) @@ -456,11 +456,9 @@ public class CreateJEI implements IModPlugin { return addRecipeListConsumer(recipes -> { List> excludedRecipes = getTypedRecipes(recipeType.get()); recipes.removeIf(recipe -> { - for (Recipe excludedRecipe : excludedRecipes) { - if (doInputsMatch(recipe, excludedRecipe)) { + for (Recipe excludedRecipe : excludedRecipes) + if (doInputsMatch(recipe, excludedRecipe) && doOutputsMatch(recipe, excludedRecipe)) return true; - } - } return false; }); }); @@ -503,7 +501,7 @@ public class CreateJEI implements IModPlugin { public CreateRecipeCategory build(String name, CreateRecipeCategory.Factory factory) { Supplier> recipesSupplier; - if (predicate.test(AllConfigs.SERVER.recipes)) { + if (predicate.test(AllConfigs.server().recipes)) { recipesSupplier = () -> { List recipes = new ArrayList<>(); for (Consumer> consumer : recipeListConsumers) @@ -570,4 +568,8 @@ public class CreateJEI implements IModPlugin { .test(matchingStacks[0]); } + public static boolean doOutputsMatch(Recipe recipe1, Recipe recipe2) { + return ItemStack.isSame(recipe1.getResultItem(), recipe2.getResultItem()); + } + } diff --git a/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java b/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java index 6dc404182a..9f3db72c96 100644 --- a/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java +++ b/src/main/java/com/simibubi/create/compat/jei/GhostIngredientHandler.java @@ -5,11 +5,11 @@ import java.util.List; import javax.annotation.ParametersAreNonnullByDefault; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterScreen; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; -import com.simibubi.create.foundation.gui.container.GhostItemContainer; -import com.simibubi.create.foundation.gui.container.GhostItemSubmitPacket; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.logistics.filter.AttributeFilterScreen; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.GhostItemMenu; +import com.simibubi.create.foundation.gui.menu.GhostItemSubmitPacket; import mezz.jei.api.gui.handlers.IGhostIngredientHandler; import net.minecraft.MethodsReturnNonnullByDefault; @@ -19,7 +19,7 @@ import net.minecraft.world.item.ItemStack; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class GhostIngredientHandler> +public class GhostIngredientHandler> implements IGhostIngredientHandler> { @Override @@ -52,7 +52,7 @@ public class GhostIngredientHandler> return true; } - private static class GhostTarget> implements Target { + private static class GhostTarget> implements Target { private final Rect2i area; private final AbstractSimiContainerScreen gui; @@ -82,7 +82,7 @@ public class GhostIngredientHandler> return; // sync new filter contents with server - AllPackets.channel.sendToServer(new GhostItemSubmitPacket(stack, slotIndex)); + AllPackets.getChannel().sendToServer(new GhostItemSubmitPacket(stack, slotIndex)); } } } diff --git a/src/main/java/com/simibubi/create/compat/jei/PotionFluidSubtypeInterpreter.java b/src/main/java/com/simibubi/create/compat/jei/PotionFluidSubtypeInterpreter.java index 88ad8fd507..0950f04dbd 100644 --- a/src/main/java/com/simibubi/create/compat/jei/PotionFluidSubtypeInterpreter.java +++ b/src/main/java/com/simibubi/create/compat/jei/PotionFluidSubtypeInterpreter.java @@ -2,7 +2,7 @@ package com.simibubi.create.compat.jei; import java.util.List; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid.BottleType; +import com.simibubi.create.content.fluids.potion.PotionFluid.BottleType; import mezz.jei.api.ingredients.subtypes.IIngredientSubtypeInterpreter; import mezz.jei.api.ingredients.subtypes.UidContext; diff --git a/src/main/java/com/simibubi/create/compat/jei/SlotMover.java b/src/main/java/com/simibubi/create/compat/jei/SlotMover.java index 0198d562cf..7116680543 100644 --- a/src/main/java/com/simibubi/create/compat/jei/SlotMover.java +++ b/src/main/java/com/simibubi/create/compat/jei/SlotMover.java @@ -2,7 +2,7 @@ package com.simibubi.create.compat.jei; import java.util.List; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import mezz.jei.api.gui.handlers.IGuiContainerHandler; import net.minecraft.client.renderer.Rect2i; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java index e0518af17f..39cd32e34e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/BasinCategory.java @@ -10,10 +10,10 @@ import org.apache.commons.lang3.mutable.MutableInt; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.HeatCondition; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.processing.recipe.HeatCondition; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.item.ItemHelper; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java index f76adc63b4..20572dd9c6 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/CreateRecipeCategory.java @@ -12,8 +12,8 @@ import org.jetbrains.annotations.NotNull; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllFluids; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java index 01df270748..e01e46856e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java @@ -7,9 +7,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedCrushingWheels; -import com.simibubi.create.content.contraptions.components.crusher.AbstractCrushingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; +import com.simibubi.create.content.kinetics.crusher.AbstractCrushingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/DeployingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/DeployingCategory.java index 606c20d00f..1d1752962f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/DeployingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/DeployingCategory.java @@ -1,10 +1,13 @@ package com.simibubi.create.compat.jei.category; +import java.util.List; + import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedDeployer; -import com.simibubi.create.content.contraptions.components.deployer.DeployerApplicationRecipe; +import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.utility.CreateLang; @@ -34,22 +37,28 @@ public class DeployingCategory extends CreateRecipeCategory tooltip.add(1, CreateLang.translateDirect("recipe.deploying.not_consumed").withStyle(ChatFormatting.GOLD))); + List results = recipe.getRollableResults(); + boolean single = results.size() == 1; + for (int i = 0; i < results.size(); i++) { + ProcessingOutput output = results.get(i); + int xOffset = i % 2 == 0 ? 0 : 19; + int yOffset = (i / 2) * -19; + builder.addSlot(RecipeIngredientRole.OUTPUT, single ? 132 : 132 + xOffset, 51 + yOffset) + .setBackground(getRenderedSlot(output), -1, -1) + .addItemStack(output.getStack()) + .addTooltipCallback(addStochasticTooltip(output)); } + if (recipe.shouldKeepHeldItem()) + handItemSlot.addTooltipCallback((recipeSlotView, tooltip) -> tooltip.add(1, CreateLang.translateDirect("recipe.deploying.not_consumed").withStyle(ChatFormatting.GOLD))); + } @Override public void draw(DeployerApplicationRecipe recipe, IRecipeSlotsView recipeSlotsView, PoseStack matrixStack, double mouseX, double mouseY) { AllGuiTextures.JEI_SHADOW.render(matrixStack, 62, 57); - AllGuiTextures.JEI_DOWN_ARROW.render(matrixStack, 126, 29); + AllGuiTextures.JEI_DOWN_ARROW.render(matrixStack, 126, 29 + (recipe.getRollableResults().size() > 2 ? -19 : 0)); deployer.draw(matrixStack, getBackground().getWidth() / 2 - 13, 22); } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/FanHauntingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/FanHauntingCategory.java index caa719c24c..683a59d7c7 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/FanHauntingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/FanHauntingCategory.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; -import com.simibubi.create.content.contraptions.components.fan.HauntingRecipe; +import com.simibubi.create.content.kinetics.fan.HauntingRecipe; import com.simibubi.create.foundation.gui.AllGuiTextures; import net.createmod.catnip.gui.element.GuiGameElement; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/FanWashingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/FanWashingCategory.java index b862a9fdc5..6255592292 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/FanWashingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/FanWashingCategory.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; -import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe; +import com.simibubi.create.content.kinetics.fan.SplashingRecipe; import net.createmod.catnip.gui.element.GuiGameElement; import net.minecraft.world.level.material.Fluids; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/ItemApplicationCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/ItemApplicationCategory.java index 565378a2c6..d1ee74ef64 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/ItemApplicationCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/ItemApplicationCategory.java @@ -1,5 +1,6 @@ package com.simibubi.create.compat.jei.category; +import java.util.List; import java.util.Optional; import javax.annotation.ParametersAreNonnullByDefault; @@ -7,7 +8,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; -import com.simibubi.create.content.contraptions.processing.ItemApplicationRecipe; +import com.simibubi.create.content.kinetics.deployer.ItemApplicationRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.utility.CreateLang; @@ -46,10 +48,17 @@ public class ItemApplicationCategory extends CreateRecipeCategory {} ); - builder.addSlot(RecipeIngredientRole.OUTPUT, 132, 38) - .setBackground(getRenderedSlot(recipe.getRollableResults().get(0)), -1, -1) - .addItemStack(recipe.getResultItem()) - .addTooltipCallback(addStochasticTooltip(recipe.getRollableResults().get(0))); + List results = recipe.getRollableResults(); + boolean single = results.size() == 1; + for (int i = 0; i < results.size(); i++) { + ProcessingOutput output = results.get(i); + int xOffset = i % 2 == 0 ? 0 : 19; + int yOffset = (i / 2) * -19; + builder.addSlot(RecipeIngredientRole.OUTPUT, single ? 132 : 132 + xOffset, 38 + yOffset) + .setBackground(getRenderedSlot(output), -1, -1) + .addItemStack(output.getStack()) + .addTooltipCallback(addStochasticTooltip(output)); + } } @Override diff --git a/src/main/java/com/simibubi/create/compat/jei/category/ItemDrainCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/ItemDrainCategory.java index 76aeba99f6..b8a9479cd6 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/ItemDrainCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/ItemDrainCategory.java @@ -7,9 +7,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; import com.simibubi.create.compat.jei.category.animations.AnimatedItemDrain; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; -import com.simibubi.create.content.contraptions.processing.EmptyingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.fluids.transfer.EmptyingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.constants.VanillaTypes; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java index 9fc0945fec..f9943a9766 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java @@ -6,8 +6,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedMillstone; -import com.simibubi.create.content.contraptions.components.crusher.AbstractCrushingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.content.kinetics.crusher.AbstractCrushingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java index ad0bade4d1..4cd7c70150 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java @@ -5,8 +5,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedBlazeBurner; import com.simibubi.create.compat.jei.category.animations.AnimatedMixer; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.HeatCondition; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.recipe.HeatCondition; import mezz.jei.api.gui.ingredient.IRecipeSlotsView; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java index 7cb7773d92..c7618096c5 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java @@ -5,8 +5,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedBlazeBurner; import com.simibubi.create.compat.jei.category.animations.AnimatedPress; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.HeatCondition; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.recipe.HeatCondition; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java index 4ea81aa75f..03e15aa65c 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java @@ -4,8 +4,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe; +import com.simibubi.create.content.equipment.sandPaper.SandPaperPolishingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PressingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PressingCategory.java index b0bffa08c7..ba3084c884 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PressingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PressingCategory.java @@ -6,8 +6,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedPress; -import com.simibubi.create.content.contraptions.components.press.PressingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.content.kinetics.press.PressingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java index e03e2d29ce..a7f9adaf03 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java @@ -7,11 +7,11 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.utility.CreateLang; @@ -57,7 +57,7 @@ public abstract class ProcessingViaFanCategory> extends Crea matrixStack.mulPose(Vector3f.XP.rotationDegrees(-12.5f)); matrixStack.mulPose(Vector3f.YP.rotationDegrees(22.5f)); - AnimatedKinetics.defaultBlockElement(AllBlockPartials.ENCASED_FAN_INNER) + AnimatedKinetics.defaultBlockElement(AllPartialModels.ENCASED_FAN_INNER) .rotateBlock(180, 0, AnimatedKinetics.getCurrentAngle() * 16) .scale(SCALE) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java index 4db6a713d3..b852d7e9c6 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java @@ -6,8 +6,8 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.animations.AnimatedSaw; -import com.simibubi.create.content.contraptions.components.saw.CuttingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.content.kinetics.saw.CuttingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import com.simibubi.create.foundation.gui.AllGuiTextures; import mezz.jei.api.gui.builder.IRecipeLayoutBuilder; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SequencedAssemblyCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SequencedAssemblyCategory.java index 9cfb8e8e60..ba0e41674e 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SequencedAssemblyCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SequencedAssemblyCategory.java @@ -11,8 +11,8 @@ import org.jetbrains.annotations.NotNull; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.compat.jei.category.sequencedAssembly.SequencedAssemblySubCategory; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedRecipe; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.content.processing.sequenced.SequencedRecipe; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SpoutCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SpoutCategory.java index 692d294ec3..e8dee8cfbc 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SpoutCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SpoutCategory.java @@ -8,10 +8,10 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; import com.simibubi.create.compat.jei.category.animations.AnimatedSpout; -import com.simibubi.create.content.contraptions.fluids.actors.FillingRecipe; -import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.fluids.transfer.FillingRecipe; +import com.simibubi.create.content.fluids.transfer.GenericItemFilling; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.gui.AllGuiTextures; diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedBlazeBurner.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedBlazeBurner.java index 04ce87abfb..976db5e56d 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedBlazeBurner.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedBlazeBurner.java @@ -4,10 +4,10 @@ import com.jozufozu.flywheel.core.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.foundation.render.CachedPartialBuffers; import net.createmod.catnip.render.SpriteShiftEntry; @@ -43,9 +43,9 @@ public class AnimatedBlazeBurner extends AnimatedKinetics { .render(matrixStack); PartialModel blaze = - heatLevel == HeatLevel.SEETHING ? AllBlockPartials.BLAZE_SUPER : AllBlockPartials.BLAZE_ACTIVE; - PartialModel rods2 = heatLevel == HeatLevel.SEETHING ? AllBlockPartials.BLAZE_BURNER_SUPER_RODS_2 - : AllBlockPartials.BLAZE_BURNER_RODS_2; + heatLevel == HeatLevel.SEETHING ? AllPartialModels.BLAZE_SUPER : AllPartialModels.BLAZE_ACTIVE; + PartialModel rods2 = heatLevel == HeatLevel.SEETHING ? AllPartialModels.BLAZE_BURNER_SUPER_RODS_2 + : AllPartialModels.BLAZE_BURNER_RODS_2; blockElement(blaze).atLocal(1, 1.8, 1) .rotate(0, 180, 0) @@ -87,7 +87,7 @@ public class AnimatedBlazeBurner extends AnimatedKinetics { MultiBufferSource.BufferSource buffer = mc.renderBuffers() .bufferSource(); VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - CachedPartialBuffers.partial(AllBlockPartials.BLAZE_BURNER_FLAME, Blocks.AIR.defaultBlockState()) + CachedPartialBuffers.partial(AllPartialModels.BLAZE_BURNER_FLAME, Blocks.AIR.defaultBlockState()) .shiftUVScrolling(spriteShift, (float) uScroll, (float) vScroll) .light(LightTexture.FULL_BRIGHT) .renderInto(matrixStack, vb); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedDeployer.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedDeployer.java index b331b58af9..75b0a73d05 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedDeployer.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedDeployer.java @@ -2,9 +2,9 @@ package com.simibubi.create.compat.jei.category.animations; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.deployer.DeployerBlock; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.deployer.DeployerBlock; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.core.Direction; @@ -37,11 +37,11 @@ public class AnimatedDeployer extends AnimatedKinetics { matrixStack.pushPose(); matrixStack.translate(0, offset * 17, 0); - blockElement(AllBlockPartials.DEPLOYER_POLE) + blockElement(AllPartialModels.DEPLOYER_POLE) .rotateBlock(90, 0, 0) .scale(scale) .render(matrixStack); - blockElement(AllBlockPartials.DEPLOYER_HAND_HOLDING) + blockElement(AllPartialModels.DEPLOYER_HAND_HOLDING) .rotateBlock(90, 0, 0) .scale(scale) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java index e4fe8aa33b..6efb3824c8 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedKinetics.java @@ -1,8 +1,8 @@ package com.simibubi.create.compat.jei.category.animations; import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.gui.CustomLightingSettings; import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; @@ -50,7 +50,7 @@ public abstract class AnimatedKinetics implements IDrawable { } protected PartialModel cogwheel() { - return AllBlockPartials.SHAFTLESS_COGWHEEL; + return AllPartialModels.SHAFTLESS_COGWHEEL; } protected GuiGameElement.GuiRenderBuilder blockElement(BlockState state) { diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMillstone.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMillstone.java index 85ee7970c1..33c1fce6b2 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMillstone.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMillstone.java @@ -1,8 +1,8 @@ package com.simibubi.create.compat.jei.category.animations; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.gui.AllGuiTextures; public class AnimatedMillstone extends AnimatedKinetics { @@ -15,7 +15,7 @@ public class AnimatedMillstone extends AnimatedKinetics { matrixStack.translate(-2, 18, 0); int scale = 22; - blockElement(AllBlockPartials.MILLSTONE_COG) + blockElement(AllPartialModels.MILLSTONE_COG) .rotateBlock(22.5, getCurrentAngle() * 2, 0) .scale(scale) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java index 87600cd94b..88e85840f1 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedMixer.java @@ -2,8 +2,8 @@ package com.simibubi.create.compat.jei.category.animations; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.util.Mth; @@ -31,12 +31,12 @@ public class AnimatedMixer extends AnimatedKinetics { float animation = ((Mth.sin(AnimationTickHolder.getRenderTime() / 32f) + 1) / 5) + .5f; - blockElement(AllBlockPartials.MECHANICAL_MIXER_POLE) + blockElement(AllPartialModels.MECHANICAL_MIXER_POLE) .atLocal(0, animation, 0) .scale(scale) .render(matrixStack); - blockElement(AllBlockPartials.MECHANICAL_MIXER_HEAD) + blockElement(AllPartialModels.MECHANICAL_MIXER_HEAD) .rotateBlock(0, getCurrentAngle() * 4, 0) .atLocal(0, animation, 0) .scale(scale) diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java index 873c29b008..03f147809f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedPress.java @@ -2,8 +2,8 @@ package com.simibubi.create.compat.jei.category.animations; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.core.Direction.Axis; @@ -33,7 +33,7 @@ public class AnimatedPress extends AnimatedKinetics { .scale(scale) .render(matrixStack); - blockElement(AllBlockPartials.MECHANICAL_PRESS_HEAD) + blockElement(AllPartialModels.MECHANICAL_PRESS_HEAD) .atLocal(0, -getAnimatedHeadOffset(), 0) .scale(scale) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSaw.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSaw.java index 97990ddeea..5e50189142 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSaw.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSaw.java @@ -2,9 +2,9 @@ package com.simibubi.create.compat.jei.category.animations; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.saw.SawBlock; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.saw.SawBlock; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; @@ -32,7 +32,7 @@ public class AnimatedSaw extends AnimatedKinetics { .scale(scale) .render(matrixStack); - blockElement(AllBlockPartials.SAW_BLADE_VERTICAL_ACTIVE) + blockElement(AllPartialModels.SAW_BLADE_VERTICAL_ACTIVE) .rotateBlock(0, -90, -90) .scale(scale) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java index 60184df0f9..d71286d208 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/animations/AnimatedSpout.java @@ -6,8 +6,8 @@ import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.fluid.FluidRenderer; import net.createmod.catnip.gui.UIRenderHelper; @@ -45,15 +45,15 @@ public class AnimatedSpout extends AnimatedKinetics { matrixStack.pushPose(); - blockElement(AllBlockPartials.SPOUT_TOP) + blockElement(AllPartialModels.SPOUT_TOP) .scale(scale) .render(matrixStack); matrixStack.translate(0, -3 * squeeze / 32f, 0); - blockElement(AllBlockPartials.SPOUT_MIDDLE) + blockElement(AllPartialModels.SPOUT_MIDDLE) .scale(scale) .render(matrixStack); matrixStack.translate(0, -3 * squeeze / 32f, 0); - blockElement(AllBlockPartials.SPOUT_BOTTOM) + blockElement(AllPartialModels.SPOUT_BOTTOM) .scale(scale) .render(matrixStack); matrixStack.translate(0, -3 * squeeze / 32f, 0); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/sequencedAssembly/SequencedAssemblySubCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/sequencedAssembly/SequencedAssemblySubCategory.java index b247883a91..8ddb0b3efc 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/sequencedAssembly/SequencedAssemblySubCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/sequencedAssembly/SequencedAssemblySubCategory.java @@ -6,8 +6,8 @@ import com.simibubi.create.compat.jei.category.animations.AnimatedDeployer; import com.simibubi.create.compat.jei.category.animations.AnimatedPress; import com.simibubi.create.compat.jei.category.animations.AnimatedSaw; import com.simibubi.create.compat.jei.category.animations.AnimatedSpout; -import com.simibubi.create.content.contraptions.components.deployer.DeployerApplicationRecipe; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedRecipe; +import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe; +import com.simibubi.create.content.processing.sequenced.SequencedRecipe; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/compat/storageDrawers/StorageDrawers.java b/src/main/java/com/simibubi/create/compat/storageDrawers/StorageDrawers.java new file mode 100644 index 0000000000..f671c259a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/storageDrawers/StorageDrawers.java @@ -0,0 +1,41 @@ +package com.simibubi.create.compat.storageDrawers; + +import com.simibubi.create.compat.Mods; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.IItemHandler; + +public class StorageDrawers { + + public static boolean isDrawer(BlockEntity be) { + return be != null && Mods.STORAGEDRAWERS.asId() + .equals(be.getType() + .getRegistryName() + .getNamespace()); + } + + public static float getTrueFillLevel(IItemHandler inv, FilteringBehaviour filtering) { + float occupied = 0; + float totalSpace = 0; + + for (int slot = 1; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + int space = inv.getSlotLimit(slot); + int count = stackInSlot.getCount(); + if (space == 0) + continue; + + totalSpace += 1; + if (filtering.test(stackInSlot)) + occupied += count * (1f / space); + } + + if (totalSpace == 0) + return 0; + + return occupied / totalSpace; + } + +} diff --git a/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java b/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java index 9f839b988f..4e2c5fe06c 100644 --- a/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java +++ b/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java @@ -2,9 +2,9 @@ package com.simibubi.create.compat.tconstruct; import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.compat.Mods; -import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.fluids.spout.SpoutBlockEntity; import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.core.BlockPos; @@ -25,23 +25,23 @@ public class SpoutCasting extends BlockSpoutingBehaviour { ResourceLocation BASIN = new ResourceLocation("tconstruct", "basin"); @Override - public int fillBlock(Level level, BlockPos pos, SpoutTileEntity spout, FluidStack availableFluid, + public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate) { if (!enabled()) return 0; - BlockEntity te = level.getBlockEntity(pos); - if (te == null) + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity == null) return 0; - IFluidHandler handler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, Direction.UP) + IFluidHandler handler = blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, Direction.UP) .orElse(null); if (handler == null) return 0; if (handler.getTanks() != 1) return 0; - ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(te.getType()); + ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(blockEntity.getType()); if (!registryName.equals(TABLE) && !registryName.equals(BASIN)) return 0; if (!handler.isFluidValid(0, availableFluid)) @@ -66,7 +66,7 @@ public class SpoutCasting extends BlockSpoutingBehaviour { TICON_PRESENT = Mods.TCONSTRUCT.isLoaded(); if (!TICON_PRESENT) return false; - return AllConfigs.SERVER.recipes.allowCastingBySpout.get(); + return AllConfigs.server().recipes.allowCastingBySpout.get(); } } diff --git a/src/main/java/com/simibubi/create/content/AllSections.java b/src/main/java/com/simibubi/create/content/AllSections.java deleted file mode 100644 index 46453440ac..0000000000 --- a/src/main/java/com/simibubi/create/content/AllSections.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.simibubi.create.content; - -import com.simibubi.create.Create; -import com.simibubi.create.foundation.item.ItemDescription.Palette; - -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; - -public enum AllSections { - - /** Create's kinetic mechanisms */ - KINETICS(Palette.Red), - - /** Item transport and other Utility */ - LOGISTICS(Palette.Yellow), - - /** Tools for strucuture movement and replication */ - SCHEMATICS(Palette.Blue), - - /** Decorative blocks */ - PALETTES(Palette.Green), - - /** Helpful gadgets and other shenanigans */ - CURIOSITIES(Palette.Purple), - - /** Base materials, ingredients and tools */ - MATERIALS(Palette.Green), - - /** Fallback section */ - UNASSIGNED(Palette.Gray) - - ; - - private Palette tooltipPalette; - - private AllSections(Palette tooltipPalette) { - this.tooltipPalette = tooltipPalette; - } - - public Palette getTooltipPalette() { - return tooltipPalette; - } - - public static AllSections of(ItemStack stack) { - Item item = stack.getItem(); - if (item instanceof BlockItem) - return ofBlock(((BlockItem) item).getBlock()); - return ofItem(item); - } - - static AllSections ofItem(Item item) { - return Create.registrate() - .getSection(item); - } - - static AllSections ofBlock(Block block) { - return Create.registrate() - .getSection(block); - } - -} diff --git a/src/main/java/com/simibubi/create/content/CreateItemGroup.java b/src/main/java/com/simibubi/create/content/CreateItemGroup.java deleted file mode 100644 index ed03bc6899..0000000000 --- a/src/main/java/com/simibubi/create/content/CreateItemGroup.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.simibubi.create.content; - -import java.util.EnumSet; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.item.CreateItemGroupBase; - -import net.minecraft.world.item.ItemStack; - -public class CreateItemGroup extends CreateItemGroupBase { - - public CreateItemGroup() { - super("base"); - } - - @Override - protected EnumSet getSections() { - return EnumSet.complementOf(EnumSet.of(AllSections.PALETTES)); - } - - @Override - public ItemStack makeIcon() { - return AllBlocks.COGWHEEL.asStack(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/AbstractContraptionEntity.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/AbstractContraptionEntity.java index 603aac2b46..f581d72397 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/AbstractContraptionEntity.java @@ -1,6 +1,5 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; -import java.io.IOException; import java.util.Collection; import java.util.IdentityHashMap; import java.util.List; @@ -14,29 +13,30 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.tuple.MutablePair; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllItems; import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement; -import com.simibubi.create.content.contraptions.components.actors.SeatBlock; -import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsStopControllingPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; +import com.simibubi.create.content.contraptions.actors.seat.SeatBlock; +import com.simibubi.create.content.contraptions.actors.seat.SeatEntity; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsStopControllingPacket; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.contraptions.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.mixin.accessor.ServerLevelAccessor; -import com.simibubi.create.foundation.networking.AllPackets; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; @@ -44,7 +44,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -129,7 +128,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit } public boolean supportsTerrainCollision() { - return contraption instanceof TranslatingContraption; + return contraption instanceof TranslatingContraption && !(contraption instanceof ElevatorContraption); } protected void contraptionInitialize() { @@ -140,7 +139,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public boolean collisionEnabled() { return true; } - + public void registerColliding(Entity collidingEntity) { collidingEntities.put(collidingEntity, new MutableInt()); } @@ -164,7 +163,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit return; contraption.getSeatMapping() .put(passenger.getUUID(), seatIndex); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), new ContraptionSeatMappingPacket(getId(), contraption.getSeatMapping())); } @@ -181,7 +180,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit .put("ContraptionDismountLocation", VecHelper.writeNBT(transformedVector)); contraption.getSeatMapping() .remove(passenger.getUUID()); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), new ContraptionSeatMappingPacket(getId(), contraption.getSeatMapping(), passenger.getId())); } @@ -271,7 +270,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public void stopControlling(BlockPos controlsLocalPos) { getControllingPlayer().map(level::getPlayerByUUID) .map(p -> (p instanceof ServerPlayer) ? ((ServerPlayer) p) : null) - .ifPresent(p -> AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> p), + .ifPresent(p -> AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> p), new ControlsStopControllingPacket())); setControllingPlayer(null); } @@ -280,9 +279,12 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit InteractionHand interactionHand) { int indexOfSeat = contraption.getSeats() .indexOf(localPos); - if (indexOfSeat == -1 || AllItems.WRENCH.isIn(player.getItemInHand(interactionHand))) - return contraption.interactors.containsKey(localPos) && contraption.interactors.get(localPos) - .handlePlayerInteraction(player, interactionHand, localPos, this); + if (indexOfSeat == -1 || AllItems.WRENCH.isIn(player.getItemInHand(interactionHand))) { + if (contraption.interactors.containsKey(localPos)) + return contraption.interactors.get(localPos) + .handlePlayerInteraction(player, interactionHand, localPos, this); + return contraption.storage.handlePlayerStorageInteraction(contraption, player, localPos); + } if (player.isPassenger()) return false; @@ -319,7 +321,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public Vec3 toGlobalVector(Vec3 localVec, float partialTicks) { return toGlobalVector(localVec, partialTicks, false); } - + public Vec3 toGlobalVector(Vec3 localVec, float partialTicks, boolean prevAnchor) { Vec3 anchor = prevAnchor ? getPrevAnchorVec() : getAnchorVec(); Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); @@ -329,7 +331,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit .add(anchor); return localVec; } - + public Vec3 toLocalVector(Vec3 localVec, float partialTicks) { return toLocalVector(localVec, partialTicks, false); } @@ -414,7 +416,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public void setBlock(BlockPos localPos, StructureBlockInfo newInfo) { contraption.blocks.put(localPos, newInfo); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), new ContraptionBlockChangedPacket(getId(), localPos, newInfo.state)); } @@ -448,7 +450,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit context.rotation = v -> applyRotation(v, 1); context.position = actorPosition; - if (!isActorActive(context, actor)) + if (!isActorActive(context, actor) && !actor.mustTickWhileDisabled()) continue; if (newPosVisited && !context.stall) { actor.visitNewPosition(context, gridPosition); @@ -510,7 +512,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit } protected void onContraptionStalled() { - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), new ContraptionStallPacket(getId(), getX(), getY(), getZ(), getStalledAngle())); } @@ -546,7 +548,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public Vec3 getAnchorVec() { return position(); } - + public Vec3 getPrevAnchorVec() { return getPrevPositionVec(); } @@ -598,22 +600,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit CompoundTag compound = new CompoundTag(); writeAdditional(compound, true); - try { - ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); - NbtIo.write(compound, dataOutput); - byte[] byteArray = dataOutput.toByteArray(); - int estimatedPacketSize = byteArray.length; - if (estimatedPacketSize > 2_000_000) { - Create.LOGGER.warn("Could not send Contraption Spawn Data (Packet too big): " - + getContraption().getType().id + " @" + position() + " (" + getUUID().toString() + ")"); - buffer.writeNbt(new CompoundTag()); - return; - } - - } catch (IOException e) { - e.printStackTrace(); - buffer.writeNbt(new CompoundTag()); - return; + if (ContraptionData.isTooLargeForSync(compound)) { + String info = getContraption().getType().id + " @" + position() + " (" + getStringUUID() + ")"; + Create.LOGGER.warn("Could not send Contraption Spawn Data (Packet too big): " + info); + compound = null; } buffer.writeNbt(compound); @@ -633,7 +623,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit @Override public void readSpawnData(FriendlyByteBuf additionalData) { - readAdditional(additionalData.readNbt(), true); + CompoundTag nbt = additionalData.readAnySizeNbt(); + if (nbt != null) { + readAdditional(nbt, true); + } } @Override @@ -660,7 +653,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit StructureTransform transform = makeStructureTransform(); contraption.stop(level); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> this), new ContraptionDisassemblyPacket(this.getId(), transform)); contraption.addBlocksToWorld(level, transform); @@ -756,7 +749,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit protected abstract float getStalledAngle(); - protected abstract void handleStallInformation(float x, float y, float z, float angle); + protected abstract void handleStallInformation(double x, double y, double z, float angle); @OnlyIn(Dist.CLIENT) protected void handleBlockChange(BlockPos localPos, BlockState newState) { @@ -823,7 +816,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit public Vec3 getContactPointMotion(Vec3 globalContactPoint) { if (prevPosInvalid) return Vec3.ZERO; - + Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0, true), 1, true); Vec3 contraptionLocalMovement = contactPoint.subtract(globalContactPoint); Vec3 contraptionAnchorMovement = position().subtract(getPrevPositionVec()); @@ -883,7 +876,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit if (xRotation != 0) matrix.multiply(new Matrix3d().asXRotation(AngleHelper.rad(-xRotation))); if (yRotation != 0) - matrix.multiply(new Matrix3d().asYRotation(AngleHelper.rad(yRotation))); + matrix.multiply(new Matrix3d().asYRotation(AngleHelper.rad(-yRotation))); if (zRotation != 0) matrix.multiply(new Matrix3d().asZRotation(AngleHelper.rad(-zRotation))); return matrix; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java b/src/main/java/com/simibubi/create/content/contraptions/AssemblyException.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java rename to src/main/java/com/simibubi/create/content/contraptions/AssemblyException.java index 3049d691dd..5e53e00329 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java +++ b/src/main/java/com/simibubi/create/content/contraptions/AssemblyException.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; -import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -62,11 +62,11 @@ public class AssemblyException extends Exception { } public static AssemblyException structureTooLarge() { - return new AssemblyException("structureTooLarge", AllConfigs.SERVER.kinetics.maxBlocksMoved.get()); + return new AssemblyException("structureTooLarge", AllConfigs.server().kinetics.maxBlocksMoved.get()); } public static AssemblyException tooManyPistonPoles() { - return new AssemblyException("tooManyPistonPoles", AllConfigs.SERVER.kinetics.maxPistonPoles.get()); + return new AssemblyException("tooManyPistonPoles", AllConfigs.server().kinetics.maxPistonPoles.get()); } public static AssemblyException noPistonPoles() { @@ -74,7 +74,7 @@ public class AssemblyException extends Exception { } public static AssemblyException notEnoughSails(int sails) { - return new AssemblyException("not_enough_sails", sails, AllConfigs.SERVER.kinetics.minimumWindmillSails.get()); + return new AssemblyException("not_enough_sails", sails, AllConfigs.server().kinetics.minimumWindmillSails.get()); } public boolean hasPosition() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java b/src/main/java/com/simibubi/create/content/contraptions/BlockMovementChecks.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java rename to src/main/java/com/simibubi/create/content/contraptions/BlockMovementChecks.java index 6c8ac0fe68..0a223944da 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java +++ b/src/main/java/com/simibubi/create/content/contraptions/BlockMovementChecks.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import java.util.ArrayList; import java.util.List; @@ -6,34 +6,32 @@ import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.api.connectivity.ConnectivityHandler; -import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock; -import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock; -import com.simibubi.create.content.contraptions.components.actors.PloughBlock; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceBlock; -import com.simibubi.create.content.contraptions.components.crank.HandCrankBlock; -import com.simibubi.create.content.contraptions.components.fan.NozzleBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; -import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock; -import com.simibubi.create.foundation.config.ContraptionMovementSetting; +import com.simibubi.create.content.contraptions.actors.AttachedActorBlock; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterBlock; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceBlock; +import com.simibubi.create.content.contraptions.bearing.ClockworkBearingBlock; +import com.simibubi.create.content.contraptions.bearing.ClockworkBearingBlockEntity; +import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlock; +import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlockEntity; +import com.simibubi.create.content.contraptions.bearing.SailBlock; +import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; +import com.simibubi.create.content.contraptions.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.pulley.PulleyBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlockEntity; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock; +import com.simibubi.create.content.fluids.tank.FluidTankBlock; +import com.simibubi.create.content.kinetics.crank.HandCrankBlock; +import com.simibubi.create.content.kinetics.fan.NozzleBlock; +import com.simibubi.create.content.logistics.vault.ItemVaultBlock; +import com.simibubi.create.content.redstone.link.RedstoneLinkBlock; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.content.trains.station.StationBlock; +import com.simibubi.create.content.trains.track.ITrackBlock; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -46,7 +44,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.DiodeBlock; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.FaceAttachedHorizontalDirectionalBlock; -import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.FlowerPotBlock; import net.minecraft.world.level.block.GrindstoneBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; @@ -175,14 +172,14 @@ public class BlockMovementChecks { private static boolean isMovementNecessaryFallback(BlockState state, Level world, BlockPos pos) { if (isBrittle(state)) return true; - if (state.getBlock() instanceof FenceGateBlock) + if (AllBlockTags.MOVABLE_EMPTY_COLLIDER.matches(state)) return true; - if (state.getMaterial() - .isReplaceable()) - return false; if (state.getCollisionShape(world, pos) .isEmpty()) return false; + if (state.getMaterial() + .isReplaceable()) + return false; return true; } @@ -203,19 +200,19 @@ public class BlockMovementChecks { if (block instanceof MechanicalPistonBlock && state.getValue(MechanicalPistonBlock.STATE) != PistonState.MOVING) return true; if (block instanceof MechanicalBearingBlock) { - BlockEntity te = world.getBlockEntity(pos); - if (te instanceof MechanicalBearingTileEntity) - return !((MechanicalBearingTileEntity) te).isRunning(); + BlockEntity be = world.getBlockEntity(pos); + if (be instanceof MechanicalBearingBlockEntity) + return !((MechanicalBearingBlockEntity) be).isRunning(); } if (block instanceof ClockworkBearingBlock) { - BlockEntity te = world.getBlockEntity(pos); - if (te instanceof ClockworkBearingTileEntity) - return !((ClockworkBearingTileEntity) te).isRunning(); + BlockEntity be = world.getBlockEntity(pos); + if (be instanceof ClockworkBearingBlockEntity) + return !((ClockworkBearingBlockEntity) be).isRunning(); } if (block instanceof PulleyBlock) { - BlockEntity te = world.getBlockEntity(pos); - if (te instanceof PulleyTileEntity) - return !((PulleyTileEntity) te).running; + BlockEntity be = world.getBlockEntity(pos); + if (be instanceof PulleyBlockEntity) + return !((PulleyBlockEntity) be).running; } if (AllBlocks.BELT.has(state)) @@ -340,7 +337,7 @@ public class BlockMovementChecks { return direction == state.getValue(StickerBlock.FACING) && !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite()); } - if (block instanceof IBogeyBlock bogey) + if (block instanceof AbstractBogeyBlock bogey) return bogey.getStickySurfaces(world, pos, state) .contains(direction); if (block instanceof WhistleBlock) @@ -356,10 +353,6 @@ public class BlockMovementChecks { return state.getValue(BlockStateProperties.FACING) == facing; if (AllBlocks.MECHANICAL_BEARING.has(state)) return state.getValue(BlockStateProperties.FACING) == facing; - if (AllBlocks.MECHANICAL_HARVESTER.has(state)) - return state.getValue(HarvesterBlock.FACING) == facing; - if (AllBlocks.MECHANICAL_PLOUGH.has(state)) - return state.getValue(PloughBlock.FACING) == facing; if (AllBlocks.CART_ASSEMBLER.has(state)) return Direction.DOWN == facing; @@ -367,7 +360,7 @@ public class BlockMovementChecks { return state.getValue(BlockStateProperties.FACING) == facing; if (AllBlocks.PORTABLE_STORAGE_INTERFACE.has(state)) return state.getValue(PortableStorageInterfaceBlock.FACING) == facing; - if (state.getBlock() instanceof AttachedActorBlock) + if (state.getBlock() instanceof AttachedActorBlock && !AllBlocks.MECHANICAL_ROLLER.has(state)) return state.getValue(BlockStateProperties.HORIZONTAL_FACING) == facing; if (AllBlocks.ROPE_PULLEY.has(state)) return facing == Direction.DOWN; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/Contraption.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java rename to src/main/java/com/simibubi/create/content/contraptions/Contraption.java index 7b2811d455..6c5fac5131 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/Contraption.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isPistonHead; import java.util.ArrayList; import java.util.Collection; @@ -24,57 +24,61 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllInteractionBehaviours; import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.HarvesterMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.SeatBlock; -import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.steam.PoweredShaftTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonHeadBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonExtensionPoleBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock.MagnetBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock.RopeBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.render.EmptyLighter; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; -import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; -import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; +import com.simibubi.create.content.contraptions.actors.seat.SeatBlock; +import com.simibubi.create.content.contraptions.actors.seat.SeatEntity; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlock; +import com.simibubi.create.content.contraptions.bearing.StabilizedContraption; +import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlock; +import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlockEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; +import com.simibubi.create.content.contraptions.chassis.ChassisBlockEntity; +import com.simibubi.create.content.contraptions.chassis.StickerBlock; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageBlock; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonHeadBlock; +import com.simibubi.create.content.contraptions.piston.PistonExtensionPoleBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlock.MagnetBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlock.RopeBlock; +import com.simibubi.create.content.contraptions.pulley.PulleyBlockEntity; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.EmptyLighter; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; +import com.simibubi.create.content.kinetics.steamEngine.PoweredShaftBlockEntity; +import com.simibubi.create.content.logistics.crate.CreativeCrateBlockEntity; +import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity; +import com.simibubi.create.content.redstone.contact.RedstoneContactBlock; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.ICoordinate; -import com.simibubi.create.foundation.utility.NBTProcessors; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.BBHelper; import net.createmod.catnip.utility.BlockFace; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.NBTProcessors; import net.createmod.catnip.utility.UniqueLinkedList; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -87,6 +91,7 @@ import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.village.poi.PoiType; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; @@ -137,6 +142,8 @@ public abstract class Contraption { protected Map blocks; protected List> actors; protected Map interactors; + protected List disabledActors; + protected List superglue; protected List seats; protected Map seatMapping; @@ -151,9 +158,9 @@ public abstract class Contraption { // Client public Map modelData; - public Map presentTileEntities; - public List maybeInstancedTileEntities; - public List specialRenderedTileEntities; + public Map presentBlockEntities; + public List maybeInstancedBlockEntities; + public List specialRenderedBlockEntities; protected ContraptionWorld world; public boolean deferInvalidate; @@ -162,15 +169,16 @@ public abstract class Contraption { blocks = new HashMap<>(); seats = new ArrayList<>(); actors = new ArrayList<>(); + disabledActors = new ArrayList<>(); modelData = new HashMap<>(); interactors = new HashMap<>(); superglue = new ArrayList<>(); seatMapping = new HashMap<>(); glueToRemove = new HashSet<>(); initialPassengers = new HashMap<>(); - presentTileEntities = new HashMap<>(); - maybeInstancedTileEntities = new ArrayList<>(); - specialRenderedTileEntities = new ArrayList<>(); + presentBlockEntities = new HashMap<>(); + maybeInstancedBlockEntities = new ArrayList<>(); + specialRenderedBlockEntities = new ArrayList<>(); pendingSubContraptions = new ArrayList<>(); stabilizedSubContraptions = new HashMap<>(); simplifiedEntityColliders = Optional.empty(); @@ -187,7 +195,7 @@ public abstract class Contraption { public abstract boolean canBeStabilized(Direction facing, BlockPos localPos); - protected abstract ContraptionType getType(); + public abstract ContraptionType getType(); protected boolean customBlockPlacement(LevelAccessor world, BlockPos pos, BlockState state) { return false; @@ -315,8 +323,8 @@ public abstract class Contraption { if (AllBlocks.BELT.has(state)) moveBelt(pos, frontier, visited, state); - if (AllBlocks.WINDMILL_BEARING.has(state) && world.getBlockEntity(pos)instanceof WindmillBearingTileEntity wbte) - wbte.disassembleForMovement(); + if (AllBlocks.WINDMILL_BEARING.has(state) && world.getBlockEntity(pos)instanceof WindmillBearingBlockEntity wbbe) + wbbe.disassembleForMovement(); if (AllBlocks.GANTRY_CARRIAGE.has(state)) moveGantryPinion(world, pos, frontier, visited, state); @@ -342,7 +350,7 @@ public abstract class Contraption { } // Bogeys tend to have sticky sides - if (state.getBlock()instanceof IBogeyBlock bogey) + if (state.getBlock()instanceof AbstractBogeyBlock bogey) for (Direction d : bogey.getStickySurfaces(world, pos, state)) if (!visited.contains(pos.relative(d))) frontier.add(pos.relative(d)); @@ -415,7 +423,7 @@ public abstract class Contraption { } addBlock(pos, capture(world, pos)); - if (blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get()) + if (blocks.size() <= AllConfigs.server().kinetics.maxBlocksMoved.get()) return true; else throw AssemblyException.structureTooLarge(); @@ -540,7 +548,7 @@ public abstract class Contraption { } private void movePulley(Level world, BlockPos pos, Queue frontier, Set visited) { - int limit = AllConfigs.SERVER.kinetics.maxRopeLength.get(); + int limit = AllConfigs.server().kinetics.maxRopeLength.get(); BlockPos ropePos = pos; while (limit-- >= 0) { ropePos = ropePos.below(); @@ -583,10 +591,10 @@ public abstract class Contraption { private boolean moveChassis(Level world, BlockPos pos, Direction movementDirection, Queue frontier, Set visited) { - BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof ChassisTileEntity)) + BlockEntity be = world.getBlockEntity(pos); + if (!(be instanceof ChassisBlockEntity)) return false; - ChassisTileEntity chassis = (ChassisTileEntity) te; + ChassisBlockEntity chassis = (ChassisBlockEntity) be; chassis.addAttachedChasses(frontier, visited); List includedBlockPositions = chassis.getIncludedBlockPositions(movementDirection, false); if (includedBlockPositions == null) @@ -603,7 +611,7 @@ public abstract class Contraption { blockstate = blockstate.setValue(RedstoneContactBlock.POWERED, true); if (AllBlocks.POWERED_SHAFT.has(blockstate)) blockstate = BlockHelper.copyProperties(blockstate, AllBlocks.SHAFT.getDefaultState()); - if (AllBlocks.CONTROLS.has(blockstate)) + if (blockstate.getBlock() instanceof ControlsBlock && getType() == ContraptionType.CARRIAGE) blockstate = blockstate.setValue(ControlsBlock.OPEN, true); if (blockstate.hasProperty(SlidingDoorBlock.VISIBLE)) blockstate = blockstate.setValue(SlidingDoorBlock.VISIBLE, false); @@ -615,11 +623,11 @@ public abstract class Contraption { blockstate = blockstate.setValue(PressurePlateBlock.POWERED, false); world.scheduleTick(pos, blockstate.getBlock(), -1); } - CompoundTag compoundnbt = getTileEntityNBT(world, pos); - BlockEntity tileentity = world.getBlockEntity(pos); - if (tileentity instanceof PoweredShaftTileEntity) - tileentity = AllTileEntities.BRACKETED_KINETIC.create(pos, blockstate); - return Pair.of(new StructureBlockInfo(pos, blockstate, compoundnbt), tileentity); + CompoundTag compoundnbt = getBlockEntityNBT(world, pos); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof PoweredShaftBlockEntity) + blockEntity = AllBlockEntityTypes.BRACKETED_KINETIC.create(pos, blockstate); + return Pair.of(new StructureBlockInfo(pos, blockstate, compoundnbt), blockEntity); } protected void addBlock(BlockPos pos, Pair pair) { @@ -631,8 +639,8 @@ public abstract class Contraption { return; bounds = bounds.minmax(new AABB(localPos)); - BlockEntity te = pair.getValue(); - storage.addBlock(localPos, te); + BlockEntity be = pair.getValue(); + storage.addBlock(localPos, be); if (AllMovementBehaviours.getBehaviour(captured.state) != null) actors.add(MutablePair.of(structureBlockInfo, null)); @@ -641,24 +649,24 @@ public abstract class Contraption { if (interactionBehaviour != null) interactors.put(localPos, interactionBehaviour); - if (te instanceof CreativeCrateTileEntity - && ((CreativeCrateTileEntity) te).getBehaviour(FilteringBehaviour.TYPE) + if (be instanceof CreativeCrateBlockEntity + && ((CreativeCrateBlockEntity) be).getBehaviour(FilteringBehaviour.TYPE) .getFilter() .isEmpty()) hasUniversalCreativeCrate = true; } @Nullable - protected CompoundTag getTileEntityNBT(Level world, BlockPos pos) { - BlockEntity tileentity = world.getBlockEntity(pos); - if (tileentity == null) + protected CompoundTag getBlockEntityNBT(Level world, BlockPos pos) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity == null) return null; - CompoundTag nbt = tileentity.saveWithFullMetadata(); + CompoundTag nbt = blockEntity.saveWithFullMetadata(); nbt.remove("x"); nbt.remove("y"); nbt.remove("z"); - if ((tileentity instanceof FluidTankTileEntity || tileentity instanceof ItemVaultTileEntity) + if ((blockEntity instanceof FluidTankBlockEntity || blockEntity instanceof ItemVaultBlockEntity) && nbt.contains("Controller")) nbt.put("Controller", NbtUtils.writeBlockPos(toLocalPos(NbtUtils.readBlockPos(nbt.getCompound("Controller"))))); @@ -680,8 +688,8 @@ public abstract class Contraption { public void readNBT(Level world, CompoundTag nbt, boolean spawnData) { blocks.clear(); - presentTileEntities.clear(); - specialRenderedTileEntities.clear(); + presentBlockEntities.clear(); + specialRenderedBlockEntities.clear(); Tag blocks = nbt.get("Blocks"); // used to differentiate between the 'old' and the paletted serialization @@ -700,6 +708,10 @@ public abstract class Contraption { getActors().add(MutablePair.of(info, context)); }); + disabledActors = NBTHelper.readItemList(nbt.getList("DisabledActors", Tag.TAG_COMPOUND)); + for (ItemStack stack : disabledActors) + setActorsActive(stack, false); + superglue.clear(); NBTHelper.iterateCompoundList(nbt.getList("Superglue", Tag.TAG_COMPOUND), c -> superglue.add(SuperGlueEntity.readBoundingBox(c))); @@ -726,7 +738,7 @@ public abstract class Contraption { interactors.put(pos, behaviour); }); - storage.read(nbt, presentTileEntities, spawnData); + storage.read(nbt, presentBlockEntities, spawnData); if (nbt.contains("BoundsFront")) bounds = NBTHelper.readAABB(nbt.getList("BoundsFront", 5)); @@ -744,14 +756,18 @@ public abstract class Contraption { ListTag actorsNBT = new ListTag(); for (MutablePair actor : getActors()) { + MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(actor.left.state); + if (behaviour == null) + continue; CompoundTag compound = new CompoundTag(); compound.put("Pos", NbtUtils.writeBlockPos(actor.left.pos)); - AllMovementBehaviours.getBehaviour(actor.left.state) - .writeExtraData(actor.right); + behaviour.writeExtraData(actor.right); actor.right.writeToNBT(compound); actorsNBT.add(compound); } + ListTag disabledActorsNBT = NBTHelper.writeItemList(disabledActors); + ListTag superglueNBT = new ListTag(); if (!spawnPacket) { for (AABB glueEntry : superglue) { @@ -788,6 +804,7 @@ public abstract class Contraption { nbt.put("Blocks", blocksNBT); nbt.put("Actors", actorsNBT); + nbt.put("DisabledActors", disabledActorsNBT); nbt.put("Interactors", interactorNBT); nbt.put("Superglue", superglueNBT); nbt.put("Anchor", NbtUtils.writeBlockPos(anchor)); @@ -872,24 +889,24 @@ public abstract class Contraption { tag.putInt("y", info.pos.getY()); tag.putInt("z", info.pos.getZ()); - BlockEntity te = BlockEntity.loadStatic(info.pos, info.state, tag); - if (te == null) + BlockEntity be = BlockEntity.loadStatic(info.pos, info.state, tag); + if (be == null) return; - te.setLevel(world); - modelData.put(info.pos, te.getModelData()); - if (te instanceof KineticTileEntity kte) - kte.setSpeed(0); - te.getBlockState(); + be.setLevel(world); + modelData.put(info.pos, be.getModelData()); + if (be instanceof KineticBlockEntity kbe) + kbe.setSpeed(0); + be.getBlockState(); MovementBehaviour movementBehaviour = AllMovementBehaviours.getBehaviour(info.state); if (movementBehaviour == null || !movementBehaviour.hasSpecialInstancedRendering()) - maybeInstancedTileEntities.add(te); + maybeInstancedBlockEntities.add(be); - if (movementBehaviour != null && !movementBehaviour.renderAsNormalTileEntity()) + if (movementBehaviour != null && !movementBehaviour.renderAsNormalBlockEntity()) return; - presentTileEntities.put(info.pos, te); - specialRenderedTileEntities.add(te); + presentBlockEntities.put(info.pos, be); + specialRenderedBlockEntities.add(be); }); } @@ -1051,33 +1068,34 @@ public abstract class Contraption { boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal(); verticalRotation = verticalRotation && transform.rotation != Rotation.NONE; if (verticalRotation) { - if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock || state.getBlock() instanceof DoorBlock) + if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock + || state.getBlock() instanceof DoorBlock) world.destroyBlock(targetPos, true); } - BlockEntity tileEntity = world.getBlockEntity(targetPos); + BlockEntity blockEntity = world.getBlockEntity(targetPos); CompoundTag tag = block.nbt; - if (tileEntity != null) - tag = NBTProcessors.process(tileEntity, tag, false); - if (tileEntity != null && tag != null) { + if (blockEntity != null) + tag = NBTProcessors.process(blockEntity, tag, false); + if (blockEntity != null && tag != null) { tag.putInt("x", targetPos.getX()); tag.putInt("y", targetPos.getY()); tag.putInt("z", targetPos.getZ()); - if (verticalRotation && tileEntity instanceof PulleyTileEntity) { + if (verticalRotation && blockEntity instanceof PulleyBlockEntity) { tag.remove("Offset"); tag.remove("InitialOffset"); } - if (tileEntity instanceof IMultiTileContainer && tag.contains("LastKnownPos")) + if (blockEntity instanceof IMultiBlockEntityContainer && tag.contains("LastKnownPos")) tag.put("LastKnownPos", NbtUtils.writeBlockPos(BlockPos.ZERO.below(Integer.MAX_VALUE - 1))); - tileEntity.load(tag); - storage.addStorageToWorld(block, tileEntity); + blockEntity.load(tag); + storage.addStorageToWorld(block, blockEntity); } - transform.apply(tileEntity); + transform.apply(blockEntity); } } @@ -1118,12 +1136,56 @@ public abstract class Contraption { } public void startMoving(Level world) { + disabledActors.clear(); + for (MutablePair pair : actors) { MovementContext context = new MovementContext(world, pair.left, this); - AllMovementBehaviours.getBehaviour(pair.left.state) - .startMoving(context); + MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state); + if (behaviour != null) + behaviour.startMoving(context); pair.setRight(context); + if (behaviour instanceof ContraptionControlsMovement) + disableActorOnStart(context); } + + for (ItemStack stack : disabledActors) + setActorsActive(stack, false); + } + + protected void disableActorOnStart(MovementContext context) { + if (!ContraptionControlsMovement.isDisabledInitially(context)) + return; + ItemStack filter = ContraptionControlsMovement.getFilter(context); + if (filter == null) + return; + if (isActorTypeDisabled(filter)) + return; + disabledActors.add(filter); + } + + public boolean isActorTypeDisabled(ItemStack filter) { + return disabledActors.stream() + .anyMatch(i -> ContraptionControlsMovement.isSameFilter(i, filter)); + } + + public void setActorsActive(ItemStack referenceStack, boolean enable) { + for (MutablePair pair : actors) { + MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state); + if (behaviour == null) + continue; + ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right); + if (behaviourStack == null) + continue; + if (!referenceStack.isEmpty() && !ContraptionControlsMovement.isSameFilter(referenceStack, behaviourStack)) + continue; + pair.right.disabled = !enable; + if (!enable) + behaviour.onDisabledByControls(pair.right); + } + } + + public List getDisabledActors() { + return disabledActors; } public void stop(Level world) { @@ -1137,8 +1199,12 @@ public abstract class Contraption { } public void forEachActor(Level world, BiConsumer callBack) { - for (MutablePair pair : actors) - callBack.accept(AllMovementBehaviours.getBehaviour(pair.getLeft().state), pair.getRight()); + for (MutablePair pair : actors) { + MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.getLeft().state); + if (behaviour == null) + continue; + callBack.accept(behaviour, pair.getRight()); + } } protected boolean shouldUpdateAfterMovement(StructureBlockInfo info) { @@ -1212,6 +1278,14 @@ public abstract class Contraption { return actors; } + @Nullable + public MutablePair getActorAt(BlockPos localPos) { + for (MutablePair pair : actors) + if (localPos.equals(pair.left.pos)) + return pair; + return null; + } + public Map getInteractors() { return interactors; } @@ -1294,7 +1368,7 @@ public abstract class Contraption { } public Collection getSpecialRenderedTEs() { - return specialRenderedTileEntities; + return specialRenderedBlockEntities; } public boolean isHiddenInPortal(BlockPos localPos) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionBlockChangedPacket.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionBlockChangedPacket.java new file mode 100644 index 0000000000..bd082b9ba2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionBlockChangedPacket.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionBlockChangedPacket extends SimplePacketBase { + + int entityID; + BlockPos localPos; + BlockState newState; + + public ContraptionBlockChangedPacket(int id, BlockPos pos, BlockState state) { + entityID = id; + localPos = pos; + newState = state; + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + buffer.writeBlockPos(localPos); + buffer.writeNbt(NbtUtils.writeBlockState(newState)); + } + + public ContraptionBlockChangedPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + localPos = buffer.readBlockPos(); + newState = NbtUtils.readBlockState(buffer.readNbt()); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> AbstractContraptionEntity.handleBlockChangedPacket(this))); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionCollider.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java rename to src/main/java/com/simibubi/create/content/contraptions/ContraptionCollider.java index f48e104254..7edfbad984 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionCollider.java @@ -1,33 +1,45 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import static net.minecraft.world.entity.Entity.collideBoundingBox; +import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.commons.lang3.tuple.MutablePair; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; -import com.simibubi.create.content.contraptions.components.actors.HarvesterMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity.ContraptionRotationState; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity.ContraptionRotationState; +import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket.ContraptionColliderLockPacketRequest; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.sync.ClientMotionPacket; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.collision.OrientedBB; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.player.RemotePlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; @@ -48,6 +60,7 @@ import net.minecraft.world.level.block.CocoaBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; @@ -60,6 +73,9 @@ public class ContraptionCollider { NONE, CLIENT, REMOTE, SERVER } + private static MutablePair, Double> safetyLock = new MutablePair<>(); + private static Map> remoteSafetyLocks = new WeakHashMap<>(); + static void collideEntities(AbstractContraptionEntity contraptionEntity) { Level world = contraptionEntity.getCommandSenderWorld(); Contraption contraption = contraptionEntity.getContraption(); @@ -75,6 +91,10 @@ public class ContraptionCollider { Vec3 anchorVec = contraptionEntity.getAnchorVec(); ContraptionRotationState rotation = null; + if (world.isClientSide() && safetyLock.left != null && safetyLock.left.get() == contraptionEntity) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> saveClientPlayerFromClipping(contraptionEntity, contraptionMotion)); + // After death, multiple refs to the client player may show up in the area boolean skipClientPlayer = false; @@ -85,8 +105,13 @@ public class ContraptionCollider { continue; PlayerType playerType = getPlayerType(entity); - if (playerType == PlayerType.REMOTE) + if (playerType == PlayerType.REMOTE) { + if (!(contraption instanceof TranslatingContraption)) + continue; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> saveRemotePlayerFromClipping((Player) entity, contraptionEntity, contraptionMotion)); continue; + } entity.getSelfAndPassengers() .forEach(e -> { @@ -97,11 +122,12 @@ public class ContraptionCollider { if (playerType == PlayerType.SERVER) continue; - if (playerType == PlayerType.CLIENT) + if (playerType == PlayerType.CLIENT) { if (skipClientPlayer) continue; else skipClientPlayer = true; + } // Init matrix if (rotation == null) @@ -115,13 +141,15 @@ public class ContraptionCollider { float yawOffset = rotation.getYawOffset(); Vec3 position = getWorldToLocalTranslation(entity, anchorVec, rotationMatrix, yawOffset); + motion = motion.subtract(contraptionMotion); + motion = rotationMatrix.transform(motion); + // Prepare entity bounds AABB localBB = entityBounds.move(position) .inflate(1.0E-7D); + OrientedBB obb = new OrientedBB(localBB); obb.setRotation(rotationMatrix); - motion = motion.subtract(contraptionMotion); - motion = rotationMatrix.transform(motion); // Use simplified bbs when present final Vec3 motionCopy = motion; @@ -339,6 +367,10 @@ public class ContraptionCollider { if (surfaceCollision.isTrue()) { contraptionEntity.registerColliding(entity); entity.fallDistance = 0; + for (Entity rider : entity.getIndirectPassengers()) + if (getPlayerType(rider) == PlayerType.CLIENT) + AllPackets.getChannel() + .sendToServer(new ClientMotionPacket(rider.getDeltaMovement(), true, 0)); boolean canWalk = bounce != 0 || slide == 0; if (canWalk || !rotation.hasVerticalRotation()) { if (canWalk) @@ -362,11 +394,113 @@ public class ContraptionCollider { float limbSwing = Mth.sqrt((float) (d0 * d0 + d1 * d1)) * 4.0F; if (limbSwing > 1.0F) limbSwing = 1.0F; - AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true, limbSwing)); + AllPackets.getChannel() + .sendToServer(new ClientMotionPacket(entityMotion, true, limbSwing)); + + if (entity.isOnGround() && contraption instanceof TranslatingContraption) { + safetyLock.setLeft(new WeakReference<>(contraptionEntity)); + safetyLock.setRight(entity.getY() - contraptionEntity.getY()); + } } } + private static int packetCooldown = 0; + + @OnlyIn(Dist.CLIENT) + private static void saveClientPlayerFromClipping(AbstractContraptionEntity contraptionEntity, + Vec3 contraptionMotion) { + LocalPlayer entity = Minecraft.getInstance().player; + if (entity.isPassenger()) + return; + + double prevDiff = safetyLock.right; + double currentDiff = entity.getY() - contraptionEntity.getY(); + double motion = contraptionMotion.subtract(entity.getDeltaMovement()).y; + double trend = Math.signum(currentDiff - prevDiff); + + ClientPacketListener handler = entity.connection; + if (handler.getOnlinePlayers() + .size() > 1) { + if (packetCooldown > 0) + packetCooldown--; + if (packetCooldown == 0) { + AllPackets.getChannel() + .sendToServer(new ContraptionColliderLockPacketRequest(contraptionEntity.getId(), currentDiff)); + packetCooldown = 3; + } + } + + if (trend == 0) + return; + if (trend == Math.signum(motion)) + return; + + double speed = contraptionMotion.multiply(0, 1, 0) + .lengthSqr(); + if (trend > 0 && speed < 0.1) + return; + if (speed < 0.05) + return; + + if (!savePlayerFromClipping(entity, contraptionEntity, contraptionMotion, prevDiff)) + safetyLock.setLeft(null); + } + + @OnlyIn(Dist.CLIENT) + public static void lockPacketReceived(int contraptionId, int remotePlayerId, double suggestedOffset) { + ClientLevel level = Minecraft.getInstance().level; + if (!(level.getEntity(contraptionId) instanceof ControlledContraptionEntity contraptionEntity)) + return; + if (!(level.getEntity(remotePlayerId) instanceof RemotePlayer player)) + return; + remoteSafetyLocks.computeIfAbsent(contraptionEntity, $ -> new WeakHashMap<>()) + .put(player, suggestedOffset); + } + + @OnlyIn(Dist.CLIENT) + private static void saveRemotePlayerFromClipping(Player entity, AbstractContraptionEntity contraptionEntity, + Vec3 contraptionMotion) { + if (entity.isPassenger()) + return; + + Map locksOnThisContraption = + remoteSafetyLocks.getOrDefault(contraptionEntity, Collections.emptyMap()); + double prevDiff = locksOnThisContraption.getOrDefault(entity, entity.getY() - contraptionEntity.getY()); + if (!savePlayerFromClipping(entity, contraptionEntity, contraptionMotion, prevDiff)) + if (locksOnThisContraption.containsKey(entity)) + locksOnThisContraption.remove(entity); + } + + @OnlyIn(Dist.CLIENT) + private static boolean savePlayerFromClipping(Player entity, AbstractContraptionEntity contraptionEntity, + Vec3 contraptionMotion, double yStartOffset) { + AABB bb = entity.getBoundingBox() + .deflate(1 / 4f, 0, 1 / 4f); + double shortestDistance = Double.MAX_VALUE; + double yStart = entity.getStepHeight() + contraptionEntity.getY() + yStartOffset; + double rayLength = Math.max(5, Math.abs(entity.getY() - yStart)); + + for (int rayIndex = 0; rayIndex < 4; rayIndex++) { + Vec3 start = new Vec3(rayIndex / 2 == 0 ? bb.minX : bb.maxX, yStart, rayIndex % 2 == 0 ? bb.minZ : bb.maxZ); + Vec3 end = start.add(0, -rayLength, 0); + + BlockHitResult hitResult = ContraptionHandlerClient.rayTraceContraption(start, end, contraptionEntity); + if (hitResult == null) + continue; + + Vec3 hit = contraptionEntity.toGlobalVector(hitResult.getLocation(), 1); + double hitDiff = start.y - hit.y; + if (shortestDistance > hitDiff) + shortestDistance = hitDiff; + } + + if (shortestDistance > rayLength) + return false; + entity.setPos(entity.getX(), yStart - shortestDistance, entity.getZ()); + return true; + } + private static Vec3 handleDamageFromTrain(Level world, AbstractContraptionEntity contraptionEntity, Vec3 contraptionMotion, Entity entity, Vec3 entityMotion, PlayerType playerType) { @@ -387,7 +521,7 @@ public class ContraptionCollider { return entityMotion; if (cce.nonDamageTicks != 0) return entityMotion; - if (!AllConfigs.SERVER.trains.trainsCauseDamage.get()) + if (!AllConfigs.server().trains.trainsCauseDamage.get()) return entityMotion; Vec3 diffMotion = contraptionMotion.subtract(entity.getDeltaMovement()); @@ -404,7 +538,8 @@ public class ContraptionCollider { return entityMotion; if (playerType == PlayerType.CLIENT) { - AllPackets.channel.sendToServer(new TrainCollisionPacket((int) (damage * 16), contraptionEntity.getId())); + AllPackets.getChannel() + .sendToServer(new TrainCollisionPacket((int) (damage * 16), contraptionEntity.getId())); world.playSound((Player) entity, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT, SoundSource.NEUTRAL, 1, .75f); } else { @@ -442,15 +577,6 @@ public class ContraptionCollider { return true; } - public static Vec3 getWorldToLocalTranslation(Entity entity, AbstractContraptionEntity contraptionEntity) { - return getWorldToLocalTranslation(entity, contraptionEntity.getAnchorVec(), - contraptionEntity.getRotationState()); - } - - public static Vec3 getWorldToLocalTranslation(Entity entity, Vec3 anchorVec, ContraptionRotationState rotation) { - return getWorldToLocalTranslation(entity, anchorVec, rotation.asMatrix(), rotation.getYawOffset()); - } - public static Vec3 getWorldToLocalTranslation(Entity entity, Vec3 anchorVec, Matrix3d rotationMatrix, float yawOffset) { Vec3 entityPosition = entity.position(); @@ -458,35 +584,29 @@ public class ContraptionCollider { .getYsize() / 2, 0); Vec3 position = entityPosition; position = position.add(centerY); - position = position.subtract(VecHelper.CENTER_OF_ORIGIN); - position = position.subtract(anchorVec); - position = VecHelper.rotate(position, -yawOffset, Axis.Y); - position = rotationMatrix.transform(position); - position = position.add(VecHelper.CENTER_OF_ORIGIN); + position = worldToLocalPos(position, anchorVec, rotationMatrix, yawOffset); position = position.subtract(centerY); position = position.subtract(entityPosition); return position; } - public static Vec3 getWorldToLocalTranslation(Vec3 entity, AbstractContraptionEntity contraptionEntity) { - return getWorldToLocalTranslation(entity, contraptionEntity.getAnchorVec(), + public static Vec3 worldToLocalPos(Vec3 worldPos, AbstractContraptionEntity contraptionEntity) { + return worldToLocalPos(worldPos, contraptionEntity.getAnchorVec(), contraptionEntity.getRotationState()); } - public static Vec3 getWorldToLocalTranslation(Vec3 inPos, Vec3 anchorVec, ContraptionRotationState rotation) { - return getWorldToLocalTranslation(inPos, anchorVec, rotation.asMatrix(), rotation.getYawOffset()); + public static Vec3 worldToLocalPos(Vec3 worldPos, Vec3 anchorVec, ContraptionRotationState rotation) { + return worldToLocalPos(worldPos, anchorVec, rotation.asMatrix(), rotation.getYawOffset()); } - public static Vec3 getWorldToLocalTranslation(Vec3 inPos, Vec3 anchorVec, Matrix3d rotationMatrix, - float yawOffset) { - Vec3 position = inPos; - position = position.subtract(VecHelper.CENTER_OF_ORIGIN); - position = position.subtract(anchorVec); - position = VecHelper.rotate(position, -yawOffset, Axis.Y); - position = rotationMatrix.transform(position); - position = position.add(VecHelper.CENTER_OF_ORIGIN); - position = position.subtract(inPos); - return position; + public static Vec3 worldToLocalPos(Vec3 worldPos, Vec3 anchorVec, Matrix3d rotationMatrix, float yawOffset) { + Vec3 localPos = worldPos; + localPos = localPos.subtract(anchorVec); + localPos = localPos.subtract(VecHelper.CENTER_OF_ORIGIN); + localPos = VecHelper.rotate(localPos, -yawOffset, Axis.Y); + localPos = rotationMatrix.transform(localPos); + localPos = localPos.add(VecHelper.CENTER_OF_ORIGIN); + return localPos; } /** From Entity#collide **/ @@ -612,7 +732,7 @@ public class ContraptionCollider { .intersects(otherBounds.move(otherMotion))) continue; - for (BlockPos colliderPos : contraption.getColliders(world, movementDirection)) { + for (BlockPos colliderPos : contraption.getOrCreateColliders(world, movementDirection)) { colliderPos = colliderPos.offset(gridPos) .subtract(new BlockPos(otherPosition)); if (!otherContraption.getBlocks() @@ -627,7 +747,7 @@ public class ContraptionCollider { public static boolean isCollidingWithWorld(Level world, TranslatingContraption contraption, BlockPos anchor, Direction movementDirection) { - for (BlockPos pos : contraption.getColliders(world, movementDirection)) { + for (BlockPos pos : contraption.getOrCreateColliders(world, movementDirection)) { BlockPos colliderPos = pos.offset(anchor); if (!world.isLoaded(colliderPos)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionColliderLockPacket.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionColliderLockPacket.java new file mode 100644 index 0000000000..3b4ff0eeb4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionColliderLockPacket.java @@ -0,0 +1,78 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +public class ContraptionColliderLockPacket extends SimplePacketBase { + + protected int contraption; + protected double offset; + private int sender; + + public ContraptionColliderLockPacket(int contraption, double offset, int sender) { + this.contraption = contraption; + this.offset = offset; + this.sender = sender; + } + + public ContraptionColliderLockPacket(FriendlyByteBuf buffer) { + contraption = buffer.readVarInt(); + offset = buffer.readDouble(); + sender = buffer.readVarInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeVarInt(contraption); + buffer.writeDouble(offset); + buffer.writeVarInt(sender); + } + + @Override + public boolean handle(Context context) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> ContraptionCollider.lockPacketReceived(contraption, sender, offset)); + return true; + } + + public static class ContraptionColliderLockPacketRequest extends SimplePacketBase { + + protected int contraption; + protected double offset; + + public ContraptionColliderLockPacketRequest(int contraption, double offset) { + this.contraption = contraption; + this.offset = offset; + } + + public ContraptionColliderLockPacketRequest(FriendlyByteBuf buffer) { + contraption = buffer.readVarInt(); + offset = buffer.readDouble(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeVarInt(contraption); + buffer.writeDouble(offset); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + AllPackets.getChannel() + .send(PacketDistributor.TRACKING_ENTITY.with(context::getSender), + new ContraptionColliderLockPacket(contraption, offset, context.getSender() + .getId())); + }); + return true; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionData.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionData.java new file mode 100644 index 0000000000..c204d4edf1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionData.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.compat.Mods; +import com.simibubi.create.foundation.mixin.accessor.NbtAccounterAccessor; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import io.netty.buffer.Unpooled; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; + +public class ContraptionData { + /** + * A sane, default maximum for contraption data size. + */ + public static final int DEFAULT_MAX = 2_000_000; + /** + * XL Packets expands the NBT packet limit to 2 GB. + */ + public static final int EXPANDED_MAX = 2_000_000_000; + /** + * Minecart item sizes are limited by the vanilla slot change packet ({@link ClientboundContainerSetSlotPacket}). + * {@link ContraptionData#DEFAULT_MAX} is used as the default. + * XL Packets expands the size limit to ~2 GB. If the mod is loaded, we take advantage of it and use the higher limit. + */ + public static final int PICKUP_MAX = Mods.XLPACKETS.isLoaded() ? EXPANDED_MAX : DEFAULT_MAX; + + /** + * @return true if the given NBT is too large for a contraption to be synced to clients. + */ + public static boolean isTooLargeForSync(CompoundTag data) { + int max = AllConfigs.server().kinetics.maxDataSize.get(); + return max != 0 && packetSize(data) > max; + } + + /** + * @return true if the given NBT is too large for a contraption to be picked up with a wrench. + */ + public static boolean isTooLargeForPickup(CompoundTag data) { + return packetSize(data) > PICKUP_MAX; + } + + /** + * @return the size of the given NBT when put through a packet, in bytes. + */ + public static long packetSize(CompoundTag data) { + FriendlyByteBuf test = new FriendlyByteBuf(Unpooled.buffer()); + test.writeNbt(data); + NbtAccounter sizeTracker = new NbtAccounter(Long.MAX_VALUE); + test.readNbt(sizeTracker); + long size = ((NbtAccounterAccessor) sizeTracker).create$getUsage(); + test.release(); + return size; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionDisassemblyPacket.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionDisassemblyPacket.java new file mode 100644 index 0000000000..44d56748c7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionDisassemblyPacket.java @@ -0,0 +1,38 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionDisassemblyPacket extends SimplePacketBase { + + int entityID; + StructureTransform transform; + + public ContraptionDisassemblyPacket(int entityID, StructureTransform transform) { + this.entityID = entityID; + this.transform = transform; + } + + public ContraptionDisassemblyPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + transform = StructureTransform.fromBuffer(buffer); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + transform.writeToBuffer(buffer); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> AbstractContraptionEntity.handleDisassemblyPacket(this))); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionHandler.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/ContraptionHandler.java index e0c8c91e07..14b6715d36 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import java.lang.ref.WeakReference; import java.util.Collection; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionHandlerClient.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java rename to src/main/java/com/simibubi/create/content/contraptions/ContraptionHandlerClient.java index 6a5ebc1e57..8a5f42c577 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionHandlerClient.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import java.lang.ref.WeakReference; import java.util.Collection; @@ -8,10 +8,10 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableObject; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.sync.ContraptionInteractionPacket; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.TrainRelocator; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; @@ -91,7 +91,7 @@ public class ContraptionHandlerClient { Collection> contraptions = ContraptionHandler.loadedContraptions.get(mc.level) .values(); - + for (WeakReference ref : contraptions) { AbstractContraptionEntity contraptionEntity = ref.get(); if (contraptionEntity == null) @@ -109,7 +109,7 @@ public class ContraptionHandlerClient { BlockPos pos = rayTraceResult.getBlockPos(); if (contraptionEntity.handlePlayerInteraction(player, pos, face, hand)) { - AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, pos, face)); + AllPackets.getChannel().sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, pos, face)); } else if (handleSpecialInteractions(contraptionEntity, player, pos, face, hand)) { } else continue; diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionMovementSetting.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionMovementSetting.java new file mode 100644 index 0000000000..eb858293d3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionMovementSetting.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.contraptions; + +import java.util.Collection; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.utility.AttachedRegistry; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraftforge.common.extensions.IForgeBlock; +import net.minecraftforge.registries.ForgeRegistries; + +public enum ContraptionMovementSetting { + MOVABLE, NO_PICKUP, UNMOVABLE; + + private static final AttachedRegistry> SETTING_SUPPLIERS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); + + public static void register(ResourceLocation block, Supplier settingSupplier) { + SETTING_SUPPLIERS.register(block, settingSupplier); + } + + public static void register(Block block, Supplier settingSupplier) { + SETTING_SUPPLIERS.register(block, settingSupplier); + } + + @Nullable + public static ContraptionMovementSetting get(Block block) { + if (block instanceof IMovementSettingProvider provider) + return provider.getContraptionMovementSetting(); + Supplier supplier = SETTING_SUPPLIERS.get(block); + if (supplier == null) + return null; + return supplier.get(); + } + + public static boolean allAre(Collection blocks, ContraptionMovementSetting are) { + return blocks.stream().anyMatch(b -> get(b.state.getBlock()) == are); + } + + public static boolean isNoPickup(Collection blocks) { + return allAre(blocks, ContraptionMovementSetting.NO_PICKUP); + } + + public static void registerDefaults() { + register(Blocks.SPAWNER, () -> AllConfigs.server().kinetics.spawnerMovement.get()); + register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.server().kinetics.amethystMovement.get()); + register(Blocks.OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get()); + register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get()); + register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.server().kinetics.obsidianMovement.get()); + } + + public interface IMovementSettingProvider extends IForgeBlock { + ContraptionMovementSetting getContraptionMovementSetting(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionRelocationPacket.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionRelocationPacket.java new file mode 100644 index 0000000000..8513de073b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionRelocationPacket.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionRelocationPacket extends SimplePacketBase { + + int entityID; + + public ContraptionRelocationPacket(int entityID) { + this.entityID = entityID; + } + + public ContraptionRelocationPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> OrientedContraptionEntity.handleRelocationPacket(this))); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionStallPacket.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionStallPacket.java new file mode 100644 index 0000000000..0cb3ff2a1f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionStallPacket.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionStallPacket extends SimplePacketBase { + + int entityID; + double x; + double y; + double z; + float angle; + + public ContraptionStallPacket(int entityID, double posX, double posY, double posZ, float angle) { + this.entityID = entityID; + this.x = posX; + this.y = posY; + this.z = posZ; + this.angle = angle; + } + + public ContraptionStallPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + x = buffer.readDouble(); + y = buffer.readDouble(); + z = buffer.readDouble(); + angle = buffer.readFloat(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + writeAll(buffer, x, y, z); + buffer.writeFloat(angle); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork( + () -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AbstractContraptionEntity.handleStallPacket(this))); + return true; + } + + private void writeAll(FriendlyByteBuf buffer, double... doubles) { + for (double d : doubles) + buffer.writeDouble(d); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionType.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionType.java new file mode 100644 index 0000000000..1b85efc417 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionType.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.contraptions; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Supplier; + +import com.simibubi.create.content.contraptions.bearing.BearingContraption; +import com.simibubi.create.content.contraptions.bearing.ClockworkContraption; +import com.simibubi.create.content.contraptions.bearing.StabilizedContraption; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; +import com.simibubi.create.content.contraptions.gantry.GantryContraption; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; +import com.simibubi.create.content.contraptions.piston.PistonContraption; +import com.simibubi.create.content.contraptions.pulley.PulleyContraption; +import com.simibubi.create.content.trains.entity.CarriageContraption; + +public class ContraptionType { + + public static final Map ENTRIES = new HashMap<>(); + public static final ContraptionType + PISTON = register("piston", PistonContraption::new), + BEARING = register("bearing", BearingContraption::new), + PULLEY = register("pulley", PulleyContraption::new), + CLOCKWORK = register("clockwork", ClockworkContraption::new), + MOUNTED = register("mounted", MountedContraption::new), + STABILIZED = register("stabilized", StabilizedContraption::new), + GANTRY = register("gantry", GantryContraption::new), + CARRIAGE = register("carriage", CarriageContraption::new), + ELEVATOR = register("elevator", ElevatorContraption::new); + + Supplier factory; + String id; + + public static ContraptionType register(String id, Supplier factory) { + ContraptionType value = new ContraptionType(id, factory); + ENTRIES.put(id, value); + return value; + } + + private ContraptionType(String id, Supplier factory) { + this.factory = factory; + this.id = id; + } + + public static Contraption fromType(String type) { + for (Entry allContraptionTypes : ENTRIES.entrySet()) + if (type.equals(allContraptionTypes.getKey())) + return allContraptionTypes.getValue().factory.get(); + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ContraptionWorld.java b/src/main/java/com/simibubi/create/content/contraptions/ContraptionWorld.java new file mode 100644 index 0000000000..2bd389092a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ContraptionWorld.java @@ -0,0 +1,61 @@ +package com.simibubi.create.content.contraptions; + +import net.createmod.catnip.utility.worldWrappers.WrappedWorld; +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; + +public class ContraptionWorld extends WrappedWorld { + final Contraption contraption; + private final int minY; + private final int height; + + public ContraptionWorld(Level world, Contraption contraption) { + super(world); + + this.contraption = contraption; + + // Include 1 block above/below contraption height range to avoid certain edge-case Starlight crashes with + // downward-facing mechanical pistons. + minY = nextMultipleOf16(contraption.bounds.minY - 1); + height = nextMultipleOf16(contraption.bounds.maxY + 1) - minY; + } + + // https://math.stackexchange.com/questions/291468 + private static int nextMultipleOf16(double a) { + return (((Math.abs((int) a) - 1) | 15) + 1) * Mth.sign(a); + } + + @Override + public BlockState getBlockState(BlockPos pos) { + StructureTemplate.StructureBlockInfo blockInfo = contraption.getBlocks().get(pos); + + if (blockInfo != null) + return blockInfo.state; + + return Blocks.AIR.defaultBlockState(); + } + + @Override + public void playLocalSound(double x, double y, double z, SoundEvent sound, SoundSource category, float volume, float pitch, boolean distanceDelay) { + world.playLocalSound(x, y, z, sound, category, volume, pitch, distanceDelay); + } + + // Ensure that we provide accurate information about ContraptionWorld height to mods (such as Starlight) which + // expect Levels to only have blocks located in chunks within their height range. + + @Override + public int getHeight() { + return height; + } + + @Override + public int getMinBuildHeight() { + return minY; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/ControlledContraptionEntity.java similarity index 87% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/ControlledContraptionEntity.java index 496ef15e2e..1bd5ddcb23 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/ControlledContraptionEntity.java @@ -1,19 +1,21 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import static net.createmod.catnip.utility.math.AngleHelper.angleLerp; +package com.simibubi.create.content.contraptions; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllEntityTypes; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; +import com.simibubi.create.content.contraptions.bearing.BearingContraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -49,6 +51,15 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { return entity; } + @Override + public void setPos(double x, double y, double z) { + super.setPos(x, y, z); + if (!level.isClientSide()) + return; + for (Entity entity : getPassengers()) + positionRider(entity); + } + @Override public Vec3 getContactPointMotion(Vec3 globalContactPoint) { if (contraption instanceof TranslatingContraption) @@ -62,7 +73,6 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { if (contraption instanceof BearingContraption) rotationAxis = ((BearingContraption) contraption).getFacing() .getAxis(); - } @Override @@ -113,10 +123,15 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { public void setAngle(float angle) { this.angle = angle; + + if (!level.isClientSide()) + return; + for (Entity entity : getPassengers()) + positionRider(entity); } public float getAngle(float partialTicks) { - return partialTicks == 1.0F ? angle : angleLerp(partialTicks, prevAngle, angle); + return partialTicks == 1.0F ? angle : AngleHelper.angleLerp(partialTicks, prevAngle, angle); } public void setRotationAxis(Axis rotationAxis) { @@ -190,10 +205,10 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { return null; if (!level.isLoaded(controllerPos)) return null; - BlockEntity te = level.getBlockEntity(controllerPos); - if (!(te instanceof IControlContraption)) + BlockEntity be = level.getBlockEntity(controllerPos); + if (!(be instanceof IControlContraption)) return null; - return (IControlContraption) te; + return (IControlContraption) be; } @Override @@ -219,7 +234,7 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity { } @Override - protected void handleStallInformation(float x, float y, float z, float angle) { + protected void handleStallInformation(double x, double y, double z, float angle) { setPosRaw(x, y, z); this.angle = this.prevAngle = angle; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/DirectionalExtenderScrollOptionSlot.java b/src/main/java/com/simibubi/create/content/contraptions/DirectionalExtenderScrollOptionSlot.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/DirectionalExtenderScrollOptionSlot.java rename to src/main/java/com/simibubi/create/content/contraptions/DirectionalExtenderScrollOptionSlot.java index 17e1f91d39..9b03187115 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/DirectionalExtenderScrollOptionSlot.java +++ b/src/main/java/com/simibubi/create/content/contraptions/DirectionalExtenderScrollOptionSlot.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import java.util.function.BiPredicate; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; import net.createmod.catnip.utility.math.AngleHelper; import net.minecraft.core.Direction; @@ -19,13 +19,13 @@ public class DirectionalExtenderScrollOptionSlot extends CenteredSideValueBoxTra } @Override - protected Vec3 getLocalOffset(BlockState state) { + public Vec3 getLocalOffset(BlockState state) { return super.getLocalOffset(state) .add(Vec3.atLowerCornerOf(state.getValue(BlockStateProperties.FACING).getNormal()).scale(-2 / 16f)); } @Override - protected void rotate(BlockState state, PoseStack ms) { + public void rotate(BlockState state, PoseStack ms) { if (!getSide().getAxis().isHorizontal()) TransformStack.cast(ms) .rotateY(AngleHelper.horizontalAngle(state.getValue(BlockStateProperties.FACING)) + 180); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java b/src/main/java/com/simibubi/create/content/contraptions/IControlContraption.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java rename to src/main/java/com/simibubi/create/content/contraptions/IControlContraption.java index 0b1b7864d2..042f66b483 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/IControlContraption.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/IDisplayAssemblyExceptions.java b/src/main/java/com/simibubi/create/content/contraptions/IDisplayAssemblyExceptions.java new file mode 100644 index 0000000000..706b524c21 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/IDisplayAssemblyExceptions.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.contraptions; + +import java.util.Arrays; +import java.util.List; + +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.FontHelper.Palette; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; + +public interface IDisplayAssemblyExceptions { + + default boolean addExceptionToTooltip(List tooltip) { + AssemblyException e = getLastAssemblyException(); + if (e == null) + return false; + + if (!tooltip.isEmpty()) + tooltip.add(Components.immutableEmpty()); + + tooltip.add(IHaveGoggleInformation.componentSpacing.plainCopy() + .append(CreateLang.translateDirect("gui.assembly.exception") + .withStyle(ChatFormatting.GOLD))); + + String text = e.component.getString(); + Arrays.stream(text.split("\n")) + .forEach(l -> TooltipHelper.cutStringTextComponent(l, Palette.GRAY_AND_WHITE) + .forEach(c -> tooltip.add(IHaveGoggleInformation.componentSpacing.plainCopy() + .append(c)))); + + return true; + } + + AssemblyException getLastAssemblyException(); + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlock.java b/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlock.java new file mode 100644 index 0000000000..61c4cb0aa7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlock.java @@ -0,0 +1,7 @@ +package com.simibubi.create.content.contraptions; + +import net.minecraft.world.level.block.state.BlockState; + +public interface ITransformableBlock { + BlockState transform(BlockState state, StructureTransform transform); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlockEntity.java new file mode 100644 index 0000000000..cadd35946a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/ITransformableBlockEntity.java @@ -0,0 +1,7 @@ +package com.simibubi.create.content.contraptions; + +public interface ITransformableBlockEntity { + + void transform(StructureTransform transform); + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java b/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java deleted file mode 100644 index 53e03fd017..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.simibubi.create.content.contraptions; - -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.config.AllConfigs; - -import net.createmod.catnip.CatnipClient; -import net.createmod.catnip.render.SuperByteBufferCache; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.VoxelShape; - -public class KineticDebugger { - - public static void tick() { - if (!isActive()) { - if (KineticTileEntityRenderer.rainbowMode) { - KineticTileEntityRenderer.rainbowMode = false; - SuperByteBufferCache.getInstance().invalidate(); - } - return; - } - - KineticTileEntity te = getSelectedTE(); - if (te == null) - return; - - Level world = Minecraft.getInstance().level; - BlockPos toOutline = te.hasSource() ? te.source : te.getBlockPos(); - BlockState state = te.getBlockState(); - VoxelShape shape = world.getBlockState(toOutline) - .getBlockSupportShape(world, toOutline); - - if (te.getTheoreticalSpeed() != 0 && !shape.isEmpty()) - CatnipClient.OUTLINER.chaseAABB("kineticSource", shape.bounds() - .move(toOutline)) - .lineWidth(1 / 16f) - .colored(te.hasSource() ? Color.generateFromLong(te.network).getRGB() : 0xffcc00); - - if (state.getBlock() instanceof IRotate) { - Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); - Vec3 vec = Vec3.atLowerCornerOf(Direction.get(AxisDirection.POSITIVE, axis) - .getNormal()); - Vec3 center = VecHelper.getCenterOf(te.getBlockPos()); - CatnipClient.OUTLINER.showLine("rotationAxis", center.add(vec), center.subtract(vec)) - .lineWidth(1 / 16f); - } - - } - - public static boolean isActive() { - return Minecraft.getInstance().options.renderDebug && AllConfigs.CLIENT.rainbowDebug.get(); - } - - public static KineticTileEntity getSelectedTE() { - HitResult obj = Minecraft.getInstance().hitResult; - ClientLevel world = Minecraft.getInstance().level; - if (obj == null) - return null; - if (world == null) - return null; - if (!(obj instanceof BlockHitResult)) - return null; - - BlockHitResult ray = (BlockHitResult) obj; - BlockEntity te = world.getBlockEntity(ray.getBlockPos()); - if (!(te instanceof KineticTileEntity)) - return null; - - return (KineticTileEntity) te; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java b/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java deleted file mode 100644 index a3e06a4243..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/KineticNetwork.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.simibubi.create.content.contraptions; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -public class KineticNetwork { - - public Long id; - public boolean initialized; - public Map sources; - public Map members; - - private float currentCapacity; - private float currentStress; - private float unloadedCapacity; - private float unloadedStress; - private int unloadedMembers; - - public KineticNetwork() { - sources = new HashMap<>(); - members = new HashMap<>(); - } - - public void initFromTE(float maxStress, float currentStress, int members) { - unloadedCapacity = maxStress; - unloadedStress = currentStress; - unloadedMembers = members; - initialized = true; - updateStress(); - updateCapacity(); - } - - public void addSilently(KineticTileEntity te, float lastCapacity, float lastStress) { - if (members.containsKey(te)) - return; - if (te.isSource()) { - unloadedCapacity -= lastCapacity * getStressMultiplierForSpeed(te.getGeneratedSpeed()); - float addedStressCapacity = te.calculateAddedStressCapacity(); - sources.put(te, addedStressCapacity); - } - - unloadedStress -= lastStress * getStressMultiplierForSpeed(te.getTheoreticalSpeed()); - float stressApplied = te.calculateStressApplied(); - members.put(te, stressApplied); - - unloadedMembers--; - if (unloadedMembers < 0) - unloadedMembers = 0; - if (unloadedCapacity < 0) - unloadedCapacity = 0; - if (unloadedStress < 0) - unloadedStress = 0; - } - - public void add(KineticTileEntity te) { - if (members.containsKey(te)) - return; - if (te.isSource()) - sources.put(te, te.calculateAddedStressCapacity()); - members.put(te, te.calculateStressApplied()); - updateFromNetwork(te); - te.networkDirty = true; - } - - public void updateCapacityFor(KineticTileEntity te, float capacity) { - sources.put(te, capacity); - updateCapacity(); - } - - public void updateStressFor(KineticTileEntity te, float stress) { - members.put(te, stress); - updateStress(); - } - - public void remove(KineticTileEntity te) { - if (!members.containsKey(te)) - return; - if (te.isSource()) - sources.remove(te); - members.remove(te); - te.updateFromNetwork(0, 0, 0); - - if (members.isEmpty()) { - TorquePropagator.networks.get(te.getLevel()) - .remove(this.id); - return; - } - - members.keySet() - .stream() - .findFirst() - .map(member -> member.networkDirty = true); - } - - public void sync() { - for (KineticTileEntity te : members.keySet()) - updateFromNetwork(te); - } - - private void updateFromNetwork(KineticTileEntity te) { - te.updateFromNetwork(currentCapacity, currentStress, getSize()); - } - - public void updateCapacity() { - float newMaxStress = calculateCapacity(); - if (currentCapacity != newMaxStress) { - currentCapacity = newMaxStress; - sync(); - } - } - - public void updateStress() { - float newStress = calculateStress(); - if (currentStress != newStress) { - currentStress = newStress; - sync(); - } - } - - public void updateNetwork() { - float newStress = calculateStress(); - float newMaxStress = calculateCapacity(); - if (currentStress != newStress || currentCapacity != newMaxStress) { - currentStress = newStress; - currentCapacity = newMaxStress; - sync(); - } - } - - public float calculateCapacity() { - float presentCapacity = 0; - for (Iterator iterator = sources.keySet() - .iterator(); iterator.hasNext();) { - KineticTileEntity te = iterator.next(); - if (te.getLevel() - .getBlockEntity(te.getBlockPos()) != te) { - iterator.remove(); - continue; - } - presentCapacity += getActualCapacityOf(te); - } - float newMaxStress = presentCapacity + unloadedCapacity; - return newMaxStress; - } - - public float calculateStress() { - float presentStress = 0; - for (Iterator iterator = members.keySet() - .iterator(); iterator.hasNext();) { - KineticTileEntity te = iterator.next(); - if (te.getLevel() - .getBlockEntity(te.getBlockPos()) != te) { - iterator.remove(); - continue; - } - presentStress += getActualStressOf(te); - } - float newStress = presentStress + unloadedStress; - return newStress; - } - - public float getActualCapacityOf(KineticTileEntity te) { - return sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed()); - } - - public float getActualStressOf(KineticTileEntity te) { - return members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed()); - } - - private static float getStressMultiplierForSpeed(float speed) { - return Math.abs(speed); - } - - public int getSize() { - return unloadedMembers + members.size(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedFluidStorage.java b/src/main/java/com/simibubi/create/content/contraptions/MountedFluidStorage.java new file mode 100644 index 0000000000..db2734c761 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedFluidStorage.java @@ -0,0 +1,173 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.sync.ContraptionFluidPacket; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity.CreativeSmartFluidTank; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.foundation.fluid.SmartFluidTank; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.network.PacketDistributor; + +public class MountedFluidStorage { + + SmartFluidTank tank; + private boolean valid; + private BlockEntity blockEntity; + + private int packetCooldown = 0; + private boolean sendPacket = false; + + public static boolean canUseAsStorage(BlockEntity be) { + if (be instanceof FluidTankBlockEntity) + return ((FluidTankBlockEntity) be).isController(); + return false; + } + + public MountedFluidStorage(BlockEntity be) { + assignBlockEntity(be); + } + + public void assignBlockEntity(BlockEntity be) { + this.blockEntity = be; + tank = createMountedTank(be); + } + + private SmartFluidTank createMountedTank(BlockEntity be) { + if (be instanceof CreativeFluidTankBlockEntity) + return new CreativeSmartFluidTank( + ((FluidTankBlockEntity) be).getTotalTankSize() * FluidTankBlockEntity.getCapacityMultiplier(), $ -> { + }); + if (be instanceof FluidTankBlockEntity) + return new SmartFluidTank( + ((FluidTankBlockEntity) be).getTotalTankSize() * FluidTankBlockEntity.getCapacityMultiplier(), + this::onFluidStackChanged); + return null; + } + + public void tick(Entity entity, BlockPos pos, boolean isRemote) { + if (!isRemote) { + if (packetCooldown > 0) + packetCooldown--; + else if (sendPacket) { + sendPacket = false; + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), + new ContraptionFluidPacket(entity.getId(), pos, tank.getFluid())); + packetCooldown = 8; + } + return; + } + + if (!(blockEntity instanceof FluidTankBlockEntity)) + return; + FluidTankBlockEntity tank = (FluidTankBlockEntity) blockEntity; + tank.getFluidLevel() + .tickChaser(); + } + + public void updateFluid(FluidStack fluid) { + tank.setFluid(fluid); + if (!(blockEntity instanceof FluidTankBlockEntity)) + return; + float fillState = tank.getFluidAmount() / (float) tank.getCapacity(); + FluidTankBlockEntity tank = (FluidTankBlockEntity) blockEntity; + if (tank.getFluidLevel() == null) + tank.setFluidLevel(LerpedFloat.linear() + .startWithValue(fillState)); + tank.getFluidLevel() + .chase(fillState, 0.5, Chaser.EXP); + IFluidTank tankInventory = tank.getTankInventory(); + if (tankInventory instanceof SmartFluidTank) + ((SmartFluidTank) tankInventory).setFluid(fluid); + } + + public void removeStorageFromWorld() { + valid = false; + if (blockEntity == null) + return; + + IFluidHandler teHandler = blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + .orElse(null); + if (!(teHandler instanceof SmartFluidTank)) + return; + SmartFluidTank smartTank = (SmartFluidTank) teHandler; + tank.setFluid(smartTank.getFluid()); + sendPacket = false; + valid = true; + } + + private void onFluidStackChanged(FluidStack fs) { + sendPacket = true; + } + + public void addStorageToWorld(BlockEntity be) { + if (tank instanceof CreativeSmartFluidTank) + return; + + LazyOptional capability = be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + IFluidHandler teHandler = capability.orElse(null); + if (!(teHandler instanceof SmartFluidTank)) + return; + + SmartFluidTank inv = (SmartFluidTank) teHandler; + inv.setFluid(tank.getFluid() + .copy()); + } + + public IFluidHandler getFluidHandler() { + return tank; + } + + public CompoundTag serialize() { + if (!valid) + return null; + CompoundTag tag = tank.writeToNBT(new CompoundTag()); + tag.putInt("Capacity", tank.getCapacity()); + + if (tank instanceof CreativeSmartFluidTank) { + NBTHelper.putMarker(tag, "Bottomless"); + tag.put("ProvidedStack", tank.getFluid() + .writeToNBT(new CompoundTag())); + } + return tag; + } + + public static MountedFluidStorage deserialize(CompoundTag nbt) { + MountedFluidStorage storage = new MountedFluidStorage(null); + if (nbt == null) + return storage; + + int capacity = nbt.getInt("Capacity"); + storage.tank = new SmartFluidTank(capacity, storage::onFluidStackChanged); + storage.valid = true; + + if (nbt.contains("Bottomless")) { + FluidStack providedStack = FluidStack.loadFluidStackFromNBT(nbt.getCompound("ProvidedStack")); + CreativeSmartFluidTank creativeSmartFluidTank = new CreativeSmartFluidTank(capacity, $ -> { + }); + creativeSmartFluidTank.setContainedFluid(providedStack); + storage.tank = creativeSmartFluidTank; + return storage; + } + + storage.tank.readFromNBT(nbt); + return storage; + } + + public boolean isValid() { + return valid; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java b/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java new file mode 100644 index 0000000000..8fa0c6778d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedStorage.java @@ -0,0 +1,215 @@ +package com.simibubi.create.content.contraptions; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity; +import com.simibubi.create.content.logistics.crate.BottomlessItemHandler; +import com.simibubi.create.content.logistics.vault.ItemVaultBlockEntity; +import com.simibubi.create.content.processing.recipe.ProcessingInventory; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BarrelBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; + +public class MountedStorage { + + private static final ItemStackHandler dummyHandler = new ItemStackHandler(); + + ItemStackHandler handler; + boolean noFuel; + boolean valid; + + private BlockEntity blockEntity; + + public static boolean canUseAsStorage(BlockEntity be) { + if (be == null) + return false; + if (be instanceof MechanicalCrafterBlockEntity) + return false; + if (AllBlockEntityTypes.CREATIVE_CRATE.is(be)) + return true; + if (be instanceof ShulkerBoxBlockEntity) + return true; + if (be instanceof ChestBlockEntity) + return true; + if (be instanceof BarrelBlockEntity) + return true; + if (be instanceof ItemVaultBlockEntity) + return true; + + try { + LazyOptional capability = be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + IItemHandler handler = capability.orElse(null); + if (handler instanceof ItemStackHandler) + return !(handler instanceof ProcessingInventory); + return canUseModdedInventory(be, handler); + + } catch (Exception e) { + return false; + } + } + + public static boolean canUseModdedInventory(BlockEntity be, IItemHandler handler) { + if (!(handler instanceof IItemHandlerModifiable validItemHandler)) + return false; + BlockState blockState = be.getBlockState(); + if (AllBlockTags.CONTRAPTION_INVENTORY_DENY.matches(blockState)) + return false; + + // There doesn't appear to be much of a standard for tagging chests/barrels + String blockId = blockState.getBlock() + .getRegistryName() + .getPath(); + if (blockId.contains("ender")) + return false; + return blockId.endsWith("_chest") || blockId.endsWith("_barrel"); + } + + public MountedStorage(BlockEntity be) { + this.blockEntity = be; + handler = dummyHandler; + noFuel = be instanceof ItemVaultBlockEntity; + } + + public void removeStorageFromWorld() { + valid = false; + if (blockEntity == null) + return; + + if (blockEntity instanceof ChestBlockEntity) { + CompoundTag tag = blockEntity.saveWithFullMetadata(); + if (tag.contains("LootTable", 8)) + return; + + handler = new ItemStackHandler(((ChestBlockEntity) blockEntity).getContainerSize()); + NonNullList items = NonNullList.withSize(handler.getSlots(), ItemStack.EMPTY); + ContainerHelper.loadAllItems(tag, items); + for (int i = 0; i < items.size(); i++) + handler.setStackInSlot(i, items.get(i)); + valid = true; + return; + } + + IItemHandler beHandler = blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .orElse(dummyHandler); + if (beHandler == dummyHandler) + return; + + // multiblock vaults need to provide individual invs + if (blockEntity instanceof ItemVaultBlockEntity) { + handler = ((ItemVaultBlockEntity) blockEntity).getInventoryOfBlock(); + valid = true; + return; + } + + // be uses ItemStackHandler + if (beHandler instanceof ItemStackHandler) { + handler = (ItemStackHandler) beHandler; + valid = true; + return; + } + + // serialization not accessible -> fill into a serializable handler + if (beHandler instanceof IItemHandlerModifiable) { + IItemHandlerModifiable inv = (IItemHandlerModifiable) beHandler; + handler = new ItemStackHandler(beHandler.getSlots()); + for (int slot = 0; slot < handler.getSlots(); slot++) { + handler.setStackInSlot(slot, inv.getStackInSlot(slot)); + inv.setStackInSlot(slot, ItemStack.EMPTY); + } + valid = true; + return; + } + + } + + public void addStorageToWorld(BlockEntity be) { + // FIXME: More dynamic mounted storage in .4 + if (handler instanceof BottomlessItemHandler) + return; + + if (be instanceof ChestBlockEntity) { + CompoundTag tag = be.saveWithFullMetadata(); + tag.remove("Items"); + NonNullList items = NonNullList.withSize(handler.getSlots(), ItemStack.EMPTY); + for (int i = 0; i < items.size(); i++) + items.set(i, handler.getStackInSlot(i)); + ContainerHelper.saveAllItems(tag, items); + be.load(tag); + return; + } + + if (be instanceof ItemVaultBlockEntity) { + ((ItemVaultBlockEntity) be).applyInventoryToBlock(handler); + return; + } + + LazyOptional capability = be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + IItemHandler teHandler = capability.orElse(null); + if (!(teHandler instanceof IItemHandlerModifiable)) + return; + + IItemHandlerModifiable inv = (IItemHandlerModifiable) teHandler; + for (int slot = 0; slot < Math.min(inv.getSlots(), handler.getSlots()); slot++) + inv.setStackInSlot(slot, handler.getStackInSlot(slot)); + } + + public IItemHandlerModifiable getItemHandler() { + return handler; + } + + public CompoundTag serialize() { + if (!valid) + return null; + + CompoundTag tag = handler.serializeNBT(); + if (noFuel) + NBTHelper.putMarker(tag, "NoFuel"); + if (!(handler instanceof BottomlessItemHandler)) + return tag; + + NBTHelper.putMarker(tag, "Bottomless"); + tag.put("ProvidedStack", handler.getStackInSlot(0) + .serializeNBT()); + return tag; + } + + public static MountedStorage deserialize(CompoundTag nbt) { + MountedStorage storage = new MountedStorage(null); + storage.handler = new ItemStackHandler(); + if (nbt == null) + return storage; + storage.valid = true; + storage.noFuel = nbt.contains("NoFuel"); + + if (nbt.contains("Bottomless")) { + ItemStack providedStack = ItemStack.of(nbt.getCompound("ProvidedStack")); + storage.handler = new BottomlessItemHandler(() -> providedStack); + return storage; + } + + storage.handler.deserializeNBT(nbt); + return storage; + } + + public boolean isValid() { + return valid; + } + + public boolean canUseForFuel() { + return !noFuel; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedStorageInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageInteraction.java new file mode 100644 index 0000000000..db1c057984 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageInteraction.java @@ -0,0 +1,68 @@ +package com.simibubi.create.content.contraptions; + +import java.util.List; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class MountedStorageInteraction { + + public static final List> menus = ImmutableList.of(MenuType.GENERIC_9x1, MenuType.GENERIC_9x2, + MenuType.GENERIC_9x3, MenuType.GENERIC_9x4, MenuType.GENERIC_9x5, MenuType.GENERIC_9x6); + + public static MenuProvider createMenuProvider(Component displayName, IItemHandlerModifiable handler, + int slotCount, Supplier stillValid) { + int rows = Mth.clamp(slotCount / 9, 1, 6); + MenuType menuType = menus.get(rows - 1); + Component menuName = CreateLang.translateDirect("contraptions.moving_container", displayName); + + return new MenuProvider() { + + @Override + public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) { + return new ChestMenu(menuType, pContainerId, pPlayerInventory, new StorageInteractionContainer(handler, stillValid), + rows); + } + + @Override + public Component getDisplayName() { + return menuName; + } + + }; + } + + public static class StorageInteractionContainer extends RecipeWrapper { + + private Supplier stillValid; + + public StorageInteractionContainer(IItemHandlerModifiable inv, Supplier stillValid) { + super(inv); + this.stillValid = stillValid; + } + + @Override + public boolean stillValid(Player player) { + return stillValid.get(); + } + + @Override + public int getMaxStackSize() { + return 64; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java new file mode 100644 index 0000000000..e70e250707 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/MountedStorageManager.java @@ -0,0 +1,262 @@ +package com.simibubi.create.content.contraptions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import com.simibubi.create.content.contraptions.Contraption.ContraptionInvWrapper; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.foundation.fluid.CombinedTankWrapper; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.ChestBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.ChestType; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.CombinedInvWrapper; + +public class MountedStorageManager { + + protected ContraptionInvWrapper inventory; + protected ContraptionInvWrapper fuelInventory; + protected CombinedTankWrapper fluidInventory; + protected Map storage; + protected Map fluidStorage; + + public MountedStorageManager() { + storage = new HashMap<>(); + fluidStorage = new HashMap<>(); + } + + public void entityTick(AbstractContraptionEntity entity) { + fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, entity.level.isClientSide)); + } + + public void createHandlers() { + Collection itemHandlers = storage.values(); + + inventory = wrapItems(itemHandlers.stream() + .map(MountedStorage::getItemHandler) + .toList(), false); + + fuelInventory = wrapItems(itemHandlers.stream() + .filter(MountedStorage::canUseForFuel) + .map(MountedStorage::getItemHandler) + .toList(), true); + + fluidInventory = wrapFluids(fluidStorage.values() + .stream() + .map(MountedFluidStorage::getFluidHandler) + .collect(Collectors.toList())); + } + + protected ContraptionInvWrapper wrapItems(Collection list, boolean fuel) { + return new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); + } + + protected CombinedTankWrapper wrapFluids(Collection list) { + return new CombinedTankWrapper(Arrays.copyOf(list.toArray(), list.size(), IFluidHandler[].class)); + } + + public void addBlock(BlockPos localPos, BlockEntity be) { + if (be != null && MountedStorage.canUseAsStorage(be)) + storage.put(localPos, new MountedStorage(be)); + if (be != null && MountedFluidStorage.canUseAsStorage(be)) + fluidStorage.put(localPos, new MountedFluidStorage(be)); + } + + public void read(CompoundTag nbt, Map presentBlockEntities, boolean clientPacket) { + storage.clear(); + NBTHelper.iterateCompoundList(nbt.getList("Storage", Tag.TAG_COMPOUND), c -> storage + .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedStorage.deserialize(c.getCompound("Data")))); + + fluidStorage.clear(); + NBTHelper.iterateCompoundList(nbt.getList("FluidStorage", Tag.TAG_COMPOUND), c -> fluidStorage + .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedFluidStorage.deserialize(c.getCompound("Data")))); + + if (clientPacket && presentBlockEntities != null) + bindTanks(presentBlockEntities); + + List handlers = new ArrayList<>(); + List fuelHandlers = new ArrayList<>(); + for (MountedStorage mountedStorage : storage.values()) { + IItemHandlerModifiable itemHandler = mountedStorage.getItemHandler(); + handlers.add(itemHandler); + if (mountedStorage.canUseForFuel()) + fuelHandlers.add(itemHandler); + } + + inventory = wrapItems(handlers, false); + fuelInventory = wrapItems(fuelHandlers, true); + fluidInventory = wrapFluids(fluidStorage.values() + .stream() + .map(MountedFluidStorage::getFluidHandler) + .toList()); + } + + public void bindTanks(Map presentBlockEntities) { + fluidStorage.forEach((pos, mfs) -> { + BlockEntity blockEntity = presentBlockEntities.get(pos); + if (!(blockEntity instanceof FluidTankBlockEntity)) + return; + FluidTankBlockEntity tank = (FluidTankBlockEntity) blockEntity; + IFluidTank tankInventory = tank.getTankInventory(); + if (tankInventory instanceof FluidTank) + ((FluidTank) tankInventory).setFluid(mfs.tank.getFluid()); + tank.getFluidLevel() + .startWithValue(tank.getFillState()); + mfs.assignBlockEntity(tank); + }); + } + + public void write(CompoundTag nbt, boolean clientPacket) { + ListTag storageNBT = new ListTag(); + if (!clientPacket) + for (BlockPos pos : storage.keySet()) { + CompoundTag c = new CompoundTag(); + MountedStorage mountedStorage = storage.get(pos); + if (!mountedStorage.isValid()) + continue; + c.put("Pos", NbtUtils.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + storageNBT.add(c); + } + + ListTag fluidStorageNBT = new ListTag(); + for (BlockPos pos : fluidStorage.keySet()) { + CompoundTag c = new CompoundTag(); + MountedFluidStorage mountedStorage = fluidStorage.get(pos); + if (!mountedStorage.isValid()) + continue; + c.put("Pos", NbtUtils.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + fluidStorageNBT.add(c); + } + + nbt.put("Storage", storageNBT); + nbt.put("FluidStorage", fluidStorageNBT); + } + + public void removeStorageFromWorld() { + storage.values() + .forEach(MountedStorage::removeStorageFromWorld); + fluidStorage.values() + .forEach(MountedFluidStorage::removeStorageFromWorld); + } + + public void addStorageToWorld(StructureBlockInfo block, BlockEntity blockEntity) { + if (storage.containsKey(block.pos)) { + MountedStorage mountedStorage = storage.get(block.pos); + if (mountedStorage.isValid()) + mountedStorage.addStorageToWorld(blockEntity); + } + + if (fluidStorage.containsKey(block.pos)) { + MountedFluidStorage mountedStorage = fluidStorage.get(block.pos); + if (mountedStorage.isValid()) + mountedStorage.addStorageToWorld(blockEntity); + } + } + + public void clear() { + for (int i = 0; i < inventory.getSlots(); i++) + if (!inventory.isSlotExternal(i)) + inventory.setStackInSlot(i, ItemStack.EMPTY); + for (int i = 0; i < fluidInventory.getTanks(); i++) + fluidInventory.drain(fluidInventory.getFluidInTank(i), FluidAction.EXECUTE); + } + + public void updateContainedFluid(BlockPos localPos, FluidStack containedFluid) { + MountedFluidStorage mountedFluidStorage = fluidStorage.get(localPos); + if (mountedFluidStorage != null) + mountedFluidStorage.updateFluid(containedFluid); + } + + public void attachExternal(IItemHandlerModifiable externalStorage) { + inventory = new ContraptionInvWrapper(externalStorage, inventory); + fuelInventory = new ContraptionInvWrapper(externalStorage, fuelInventory); + } + + public IItemHandlerModifiable getItems() { + return inventory; + } + + public IItemHandlerModifiable getFuelItems() { + return fuelInventory; + } + + public IFluidHandler getFluids() { + return fluidInventory; + } + + public boolean handlePlayerStorageInteraction(Contraption contraption, Player player, BlockPos localPos) { + if (player.level.isClientSide()) { + BlockEntity localBE = contraption.presentBlockEntities.get(localPos); + return MountedStorage.canUseAsStorage(localBE); + } + + MountedStorageManager storageManager = contraption.getStorageForSpawnPacket(); + MountedStorage storage = storageManager.storage.get(localPos); + if (storage == null || storage.getItemHandler() == null) + return false; + IItemHandlerModifiable handler = storage.getItemHandler(); + + StructureBlockInfo info = contraption.getBlocks() + .get(localPos); + if (info != null && info.state.hasProperty(ChestBlock.TYPE)) { + ChestType chestType = info.state.getValue(ChestBlock.TYPE); + Direction facing = info.state.getOptionalValue(ChestBlock.FACING) + .orElse(Direction.SOUTH); + Direction connectedDirection = + chestType == ChestType.LEFT ? facing.getClockWise() : facing.getCounterClockWise(); + + if (chestType != ChestType.SINGLE) { + MountedStorage storage2 = storageManager.storage.get(localPos.relative(connectedDirection)); + if (storage2 != null && storage2.getItemHandler() != null) + handler = chestType == ChestType.RIGHT ? new CombinedInvWrapper(handler, storage2.getItemHandler()) + : new CombinedInvWrapper(storage2.getItemHandler(), handler); + } + } + + int slotCount = handler.getSlots(); + if (slotCount == 0) + return false; + if (slotCount % 9 != 0) + return false; + + Supplier stillValid = () -> contraption.entity.isAlive() + && player.distanceToSqr(contraption.entity.toGlobalVector(Vec3.atCenterOf(localPos), 0)) < 64; + Component name = info != null ? info.state.getBlock() + .getName() : Components.literal("Container"); + player.openMenu(MountedStorageInteraction.createMenuProvider(name, handler, slotCount, stillValid)); + + Vec3 soundPos = contraption.entity.toGlobalVector(Vec3.atCenterOf(localPos), 0); + player.level.playSound(null, new BlockPos(soundPos), SoundEvents.BARREL_OPEN, SoundSource.BLOCKS, 0.75f, 1f); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/OrientedContraptionEntity.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/OrientedContraptionEntity.java index 95d45ed4fd..c04314920c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/OrientedContraptionEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import static net.createmod.catnip.utility.math.AngleHelper.angleLerp; @@ -10,12 +10,12 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllEntityTypes; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.train.MinecartSim2020; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.content.contraptions.bearing.StabilizedContraption; +import com.simibubi.create.content.contraptions.minecart.MinecartSim2020; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity.CartMovementMode; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; import com.simibubi.create.foundation.item.ItemHelper; import net.createmod.catnip.utility.Couple; @@ -496,7 +496,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { Vec3 anchorVec = super.getAnchorVec(); return anchorVec.subtract(.5, 0, .5); } - + @Override public Vec3 getPrevAnchorVec() { Vec3 prevAnchorVec = super.getPrevAnchorVec(); @@ -515,7 +515,7 @@ public class OrientedContraptionEntity extends AbstractContraptionEntity { } @Override - protected void handleStallInformation(float x, float y, float z, float angle) { + protected void handleStallInformation(double x, double y, double z, float angle) { yaw = angle; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java b/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java deleted file mode 100644 index 6e4dbc6664..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/RotationPropagator.java +++ /dev/null @@ -1,445 +0,0 @@ -package com.simibubi.create.content.contraptions; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS; - -import java.util.LinkedList; -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.contraptions.relays.encased.DirectionalShaftHalvesTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock; -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftTileEntity; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity; -import com.simibubi.create.foundation.config.AllConfigs; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - - -public class RotationPropagator { - - private static final int MAX_FLICKER_SCORE = 128; - - /** - * Determines the change in rotation between two attached kinetic entities. For - * instance, an axis connection returns 1 while a 1-to-1 gear connection - * reverses the rotation and therefore returns -1. - * - * @param from - * @param to - * @return - */ - private static float getRotationSpeedModifier(KineticTileEntity from, KineticTileEntity to) { - final BlockState stateFrom = from.getBlockState(); - final BlockState stateTo = to.getBlockState(); - - Block fromBlock = stateFrom.getBlock(); - Block toBlock = stateTo.getBlock(); - if (!(fromBlock instanceof IRotate && toBlock instanceof IRotate)) - return 0; - - final IRotate definitionFrom = (IRotate) fromBlock; - final IRotate definitionTo = (IRotate) toBlock; - final BlockPos diff = to.getBlockPos() - .subtract(from.getBlockPos()); - final Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); - final Level world = from.getLevel(); - - boolean alignedAxes = true; - for (Axis axis : Axis.values()) - if (axis != direction.getAxis()) - if (axis.choose(diff.getX(), diff.getY(), diff.getZ()) != 0) - alignedAxes = false; - - boolean connectedByAxis = - alignedAxes && definitionFrom.hasShaftTowards(world, from.getBlockPos(), stateFrom, direction) - && definitionTo.hasShaftTowards(world, to.getBlockPos(), stateTo, direction.getOpposite()); - - boolean connectedByGears = ICogWheel.isSmallCog(stateFrom) - && ICogWheel.isSmallCog(stateTo); - - float custom = from.propagateRotationTo(to, stateFrom, stateTo, diff, connectedByAxis, connectedByGears); - if (custom != 0) - return custom; - - // Axis <-> Axis - if (connectedByAxis) { - float axisModifier = getAxisModifier(to, direction.getOpposite()); - if (axisModifier != 0) - axisModifier = 1 / axisModifier; - return getAxisModifier(from, direction) * axisModifier; - } - - // Attached Encased Belts - if (fromBlock instanceof EncasedBeltBlock && toBlock instanceof EncasedBeltBlock) { - boolean connected = EncasedBeltBlock.areBlocksConnected(stateFrom, stateTo, direction); - return connected ? EncasedBeltBlock.getRotationSpeedModifier(from, to) : 0; - } - - // Large Gear <-> Large Gear - if (isLargeToLargeGear(stateFrom, stateTo, diff)) { - Axis sourceAxis = stateFrom.getValue(AXIS); - Axis targetAxis = stateTo.getValue(AXIS); - int sourceAxisDiff = sourceAxis.choose(diff.getX(), diff.getY(), diff.getZ()); - int targetAxisDiff = targetAxis.choose(diff.getX(), diff.getY(), diff.getZ()); - - return sourceAxisDiff > 0 ^ targetAxisDiff > 0 ? -1 : 1; - } - - // Gear <-> Large Gear - if (ICogWheel.isLargeCog(stateFrom) && ICogWheel.isSmallCog(stateTo)) - if (isLargeToSmallCog(stateFrom, stateTo, definitionTo, diff)) - return -2f; - if (ICogWheel.isLargeCog(stateTo) && ICogWheel.isSmallCog(stateFrom)) - if (isLargeToSmallCog(stateTo, stateFrom, definitionFrom, diff)) - return -.5f; - - // Gear <-> Gear - if (connectedByGears) { - if (diff.distManhattan(BlockPos.ZERO) != 1) - return 0; - if (ICogWheel.isLargeCog(stateTo)) - return 0; - if (direction.getAxis() == definitionFrom.getRotationAxis(stateFrom)) - return 0; - if (definitionFrom.getRotationAxis(stateFrom) == definitionTo.getRotationAxis(stateTo)) - return -1; - } - - return 0; - } - - private static float getConveyedSpeed(KineticTileEntity from, KineticTileEntity to) { - final BlockState stateFrom = from.getBlockState(); - final BlockState stateTo = to.getBlockState(); - - // Rotation Speed Controller <-> Large Gear - if (isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos() - .subtract(from.getBlockPos()))) - return SpeedControllerTileEntity.getConveyedSpeed(from, to, true); - if (isLargeCogToSpeedController(stateTo, stateFrom, from.getBlockPos() - .subtract(to.getBlockPos()))) - return SpeedControllerTileEntity.getConveyedSpeed(to, from, false); - - float rotationSpeedModifier = getRotationSpeedModifier(from, to); - return from.getTheoreticalSpeed() * rotationSpeedModifier; - } - - private static boolean isLargeToLargeGear(BlockState from, BlockState to, BlockPos diff) { - if (!ICogWheel.isLargeCog(from) || !ICogWheel.isLargeCog(to)) - return false; - Axis fromAxis = from.getValue(AXIS); - Axis toAxis = to.getValue(AXIS); - if (fromAxis == toAxis) - return false; - for (Axis axis : Axis.values()) { - int axisDiff = axis.choose(diff.getX(), diff.getY(), diff.getZ()); - if (axis == fromAxis || axis == toAxis) { - if (axisDiff == 0) - return false; - - } else if (axisDiff != 0) - return false; - } - return true; - } - - private static float getAxisModifier(KineticTileEntity te, Direction direction) { - if (!(te.hasSource()||te.isSource()) || !(te instanceof DirectionalShaftHalvesTileEntity)) - return 1; - Direction source = ((DirectionalShaftHalvesTileEntity) te).getSourceFacing(); - - if (te instanceof GearboxTileEntity) - return direction.getAxis() == source.getAxis() ? direction == source ? 1 : -1 - : direction.getAxisDirection() == source.getAxisDirection() ? -1 : 1; - - if (te instanceof SplitShaftTileEntity) - return ((SplitShaftTileEntity) te).getRotationSpeedModifier(direction); - - return 1; - } - - private static boolean isLargeToSmallCog(BlockState from, BlockState to, IRotate defTo, BlockPos diff) { - Axis axisFrom = from.getValue(AXIS); - if (axisFrom != defTo.getRotationAxis(to)) - return false; - if (axisFrom.choose(diff.getX(), diff.getY(), diff.getZ()) != 0) - return false; - for (Axis axis : Axis.values()) { - if (axis == axisFrom) - continue; - if (Math.abs(axis.choose(diff.getX(), diff.getY(), diff.getZ())) != 1) - return false; - } - return true; - } - - private static boolean isLargeCogToSpeedController(BlockState from, BlockState to, BlockPos diff) { - if (!ICogWheel.isLargeCog(from) || !AllBlocks.ROTATION_SPEED_CONTROLLER.has(to)) - return false; - if (!diff.equals(BlockPos.ZERO.below())) - return false; - Axis axis = from.getValue(CogWheelBlock.AXIS); - if (axis.isVertical()) - return false; - if (to.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == axis) - return false; - return true; - } - - /** - * Insert the added position to the kinetic network. - * - * @param worldIn - * @param pos - */ - public static void handleAdded(Level worldIn, BlockPos pos, KineticTileEntity addedTE) { - if (worldIn.isClientSide) - return; - if (!worldIn.isLoaded(pos)) - return; - propagateNewSource(addedTE); - } - - /** - * Search for sourceless networks attached to the given entity and update them. - * - * @param currentTE - */ - private static void propagateNewSource(KineticTileEntity currentTE) { - BlockPos pos = currentTE.getBlockPos(); - Level world = currentTE.getLevel(); - - for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) { - float speedOfCurrent = currentTE.getTheoreticalSpeed(); - float speedOfNeighbour = neighbourTE.getTheoreticalSpeed(); - float newSpeed = getConveyedSpeed(currentTE, neighbourTE); - float oppositeSpeed = getConveyedSpeed(neighbourTE, currentTE); - - if (newSpeed == 0 && oppositeSpeed == 0) - continue; - - boolean incompatible = - Math.signum(newSpeed) != Math.signum(speedOfNeighbour) && (newSpeed != 0 && speedOfNeighbour != 0); - - boolean tooFast = Math.abs(newSpeed) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get() - || Math.abs(oppositeSpeed) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get(); - // Check for both the new speed and the opposite speed, just in case - - boolean speedChangedTooOften = currentTE.getFlickerScore() > MAX_FLICKER_SCORE; - if (tooFast || speedChangedTooOften) { - world.destroyBlock(pos, true); - return; - } - - // Opposite directions - if (incompatible) { - world.destroyBlock(pos, true); - return; - - // Same direction: overpower the slower speed - } else { - - // Neighbour faster, overpower the incoming tree - if (Math.abs(oppositeSpeed) > Math.abs(speedOfCurrent)) { - float prevSpeed = currentTE.getSpeed(); - currentTE.setSource(neighbourTE.getBlockPos()); - currentTE.setSpeed(getConveyedSpeed(neighbourTE, currentTE)); - currentTE.onSpeedChanged(prevSpeed); - currentTE.sendData(); - - propagateNewSource(currentTE); - return; - } - - // Current faster, overpower the neighbours' tree - if (Math.abs(newSpeed) >= Math.abs(speedOfNeighbour)) { - - // Do not overpower you own network -> cycle - if (!currentTE.hasNetwork() || currentTE.network.equals(neighbourTE.network)) { - float epsilon = Math.abs(speedOfNeighbour) / 256f / 256f; - if (Math.abs(newSpeed) > Math.abs(speedOfNeighbour) + epsilon) - world.destroyBlock(pos, true); - continue; - } - - if (currentTE.hasSource() && currentTE.source.equals(neighbourTE.getBlockPos())) - currentTE.removeSource(); - - float prevSpeed = neighbourTE.getSpeed(); - neighbourTE.setSource(currentTE.getBlockPos()); - neighbourTE.setSpeed(getConveyedSpeed(currentTE, neighbourTE)); - neighbourTE.onSpeedChanged(prevSpeed); - neighbourTE.sendData(); - propagateNewSource(neighbourTE); - continue; - } - } - - if (neighbourTE.getTheoreticalSpeed() == newSpeed) - continue; - - float prevSpeed = neighbourTE.getSpeed(); - neighbourTE.setSpeed(newSpeed); - neighbourTE.setSource(currentTE.getBlockPos()); - neighbourTE.onSpeedChanged(prevSpeed); - neighbourTE.sendData(); - propagateNewSource(neighbourTE); - - } - } - - /** - * Remove the given entity from the network. - * - * @param worldIn - * @param pos - * @param removedTE - */ - public static void handleRemoved(Level worldIn, BlockPos pos, KineticTileEntity removedTE) { - if (worldIn.isClientSide) - return; - if (removedTE == null) - return; - if (removedTE.getTheoreticalSpeed() == 0) - return; - - for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedTE)) { - BlockState neighbourState = worldIn.getBlockState(neighbourPos); - if (!(neighbourState.getBlock() instanceof IRotate)) - continue; - BlockEntity tileEntity = worldIn.getBlockEntity(neighbourPos); - if (!(tileEntity instanceof KineticTileEntity)) - continue; - - final KineticTileEntity neighbourTE = (KineticTileEntity) tileEntity; - if (!neighbourTE.hasSource() || !neighbourTE.source.equals(pos)) - continue; - - propagateMissingSource(neighbourTE); - } - - } - - /** - * Clear the entire subnetwork depending on the given entity and find a new - * source - * - * @param updateTE - */ - private static void propagateMissingSource(KineticTileEntity updateTE) { - final Level world = updateTE.getLevel(); - - List potentialNewSources = new LinkedList<>(); - List frontier = new LinkedList<>(); - frontier.add(updateTE.getBlockPos()); - BlockPos missingSource = updateTE.hasSource() ? updateTE.source : null; - - while (!frontier.isEmpty()) { - final BlockPos pos = frontier.remove(0); - BlockEntity tileEntity = world.getBlockEntity(pos); - if (!(tileEntity instanceof KineticTileEntity)) - continue; - final KineticTileEntity currentTE = (KineticTileEntity) tileEntity; - - currentTE.removeSource(); - currentTE.sendData(); - - for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) { - if (neighbourTE.getBlockPos() - .equals(missingSource)) - continue; - if (!neighbourTE.hasSource()) - continue; - - if (!neighbourTE.source.equals(pos)) { - potentialNewSources.add(neighbourTE); - continue; - } - - if (neighbourTE.isSource()) - potentialNewSources.add(neighbourTE); - - frontier.add(neighbourTE.getBlockPos()); - } - } - - for (KineticTileEntity newSource : potentialNewSources) { - if (newSource.hasSource() || newSource.isSource()) { - propagateNewSource(newSource); - return; - } - } - } - - private static KineticTileEntity findConnectedNeighbour(KineticTileEntity currentTE, BlockPos neighbourPos) { - BlockState neighbourState = currentTE.getLevel() - .getBlockState(neighbourPos); - if (!(neighbourState.getBlock() instanceof IRotate)) - return null; - if (!neighbourState.hasBlockEntity()) - return null; - BlockEntity neighbourTE = currentTE.getLevel() - .getBlockEntity(neighbourPos); - if (!(neighbourTE instanceof KineticTileEntity)) - return null; - KineticTileEntity neighbourKTE = (KineticTileEntity) neighbourTE; - if (!(neighbourKTE.getBlockState() - .getBlock() instanceof IRotate)) - return null; - if (!isConnected(currentTE, neighbourKTE) && !isConnected(neighbourKTE, currentTE)) - return null; - return neighbourKTE; - } - - public static boolean isConnected(KineticTileEntity from, KineticTileEntity to) { - final BlockState stateFrom = from.getBlockState(); - final BlockState stateTo = to.getBlockState(); - return isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos() - .subtract(from.getBlockPos())) || getRotationSpeedModifier(from, to) != 0 - || from.isCustomConnection(to, stateFrom, stateTo); - } - - private static List getConnectedNeighbours(KineticTileEntity te) { - List neighbours = new LinkedList<>(); - for (BlockPos neighbourPos : getPotentialNeighbourLocations(te)) { - final KineticTileEntity neighbourTE = findConnectedNeighbour(te, neighbourPos); - if (neighbourTE == null) - continue; - - neighbours.add(neighbourTE); - } - return neighbours; - } - - private static List getPotentialNeighbourLocations(KineticTileEntity te) { - List neighbours = new LinkedList<>(); - - if (!te.getLevel() - .isAreaLoaded(te.getBlockPos(), 1)) - return neighbours; - - for (Direction facing : Iterate.directions) - neighbours.add(te.getBlockPos() - .relative(facing)); - - BlockState blockState = te.getBlockState(); - if (!(blockState.getBlock() instanceof IRotate)) - return neighbours; - IRotate block = (IRotate) blockState.getBlock(); - return te.addPropagationLocations(block, blockState, neighbours); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java b/src/main/java/com/simibubi/create/content/contraptions/StructureTransform.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java rename to src/main/java/com/simibubi/create/content/contraptions/StructureTransform.java index d57596b28f..fbe8bd8916 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java +++ b/src/main/java/com/simibubi/create/content/contraptions/StructureTransform.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; @@ -109,9 +109,9 @@ public class StructureTransform { return applyWithoutOffset(localPos).offset(offset); } - public void apply(BlockEntity te) { - if (te instanceof ITransformableTE) - ((ITransformableTE) te).transform(this); + public void apply(BlockEntity be) { + if (be instanceof ITransformableBlockEntity) + ((ITransformableBlockEntity) be).transform(this); } /** @@ -143,7 +143,8 @@ public class StructureTransform { EnumProperty faceProperty = FaceAttachedHorizontalDirectionalBlock.FACE; Direction stateFacing = state.getValue(facingProperty); AttachFace stateFace = state.getValue(faceProperty); - Direction forcedAxis = rotationAxis == Axis.Z ? Direction.EAST : Direction.SOUTH; + boolean z = rotationAxis == Axis.Z; + Direction forcedAxis = z ? Direction.WEST : Direction.SOUTH; if (stateFacing.getAxis() == rotationAxis && stateFace == AttachFace.WALL) return state; @@ -160,7 +161,7 @@ public class StructureTransform { continue; } - if (stateFacing.getAxisDirection() == AxisDirection.POSITIVE) { + if (stateFacing.getAxisDirection() == (z ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE)) { state = state.setValue(faceProperty, AttachFace.FLOOR); continue; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/TorquePropagator.java b/src/main/java/com/simibubi/create/content/contraptions/TorquePropagator.java deleted file mode 100644 index d4ca1ec72f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/TorquePropagator.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.contraptions; - -import java.util.HashMap; -import java.util.Map; - -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.createmod.catnip.utility.WorldHelper; -import net.minecraft.world.level.LevelAccessor; - -public class TorquePropagator { - - static Map> networks = new HashMap<>(); - - public void onLoadWorld(LevelAccessor world) { - networks.put(world, new HashMap<>()); - Create.LOGGER.debug("Prepared Kinetic Network Space for " + WorldHelper.getDimensionID(world)); - } - - public void onUnloadWorld(LevelAccessor world) { - networks.remove(world); - Create.LOGGER.debug("Removed Kinetic Network Space for " + WorldHelper.getDimensionID(world)); - } - - public KineticNetwork getOrCreateNetworkFor(KineticTileEntity te) { - Long id = te.network; - KineticNetwork network; - Map map = networks.computeIfAbsent(te.getLevel(), $ -> new HashMap<>()); - if (id == null) - return null; - - if (!map.containsKey(id)) { - network = new KineticNetwork(); - network.id = te.network; - map.put(id, network); - } - network = map.get(id); - return network; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TrainCollisionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/TrainCollisionPacket.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TrainCollisionPacket.java rename to src/main/java/com/simibubi/create/content/contraptions/TrainCollisionPacket.java index f68876821b..926e89433c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TrainCollisionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/TrainCollisionPacket.java @@ -1,8 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions; -import java.util.function.Supplier; - -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.network.FriendlyByteBuf; @@ -36,10 +34,9 @@ public class TrainCollisionPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); Level level = player.level; Entity entity = level.getEntity(contraptionEntityId); @@ -50,7 +47,7 @@ public class TrainCollisionPacket extends SimplePacketBase { player.level.playSound(player, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT, SoundSource.NEUTRAL, 1, .75f); }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/TranslatingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/TranslatingContraption.java new file mode 100644 index 0000000000..e547f49f75 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/TranslatingContraption.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.contraptions; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; + +public abstract class TranslatingContraption extends Contraption { + + protected Set cachedColliders; + protected Direction cachedColliderDirection; + + public Set getOrCreateColliders(Level world, Direction movementDirection) { + if (getBlocks() == null) + return Collections.emptySet(); + if (cachedColliders == null || cachedColliderDirection != movementDirection) { + cachedColliderDirection = movementDirection; + cachedColliders= createColliders(world, movementDirection); + } + return cachedColliders; + } + + public Set createColliders(Level world, Direction movementDirection) { + Set colliders = new HashSet<>(); + for (StructureBlockInfo info : getBlocks().values()) { + BlockPos offsetPos = info.pos.relative(movementDirection); + if (info.state.getCollisionShape(world, offsetPos) + .isEmpty()) + continue; + if (getBlocks().containsKey(offsetPos) + && !getBlocks().get(offsetPos).state.getCollisionShape(world, offsetPos) + .isEmpty()) + continue; + colliders.add(info.pos); + } + return colliders; + } + + @Override + public void removeBlocksFromWorld(Level world, BlockPos offset) { + int count = blocks.size(); + super.removeBlocksFromWorld(world, offset); + if (count != blocks.size()) { + cachedColliders = null; + } + } + + @Override + public boolean canBeStabilized(Direction facing, BlockPos localPos) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/AttachedActorBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/AttachedActorBlock.java new file mode 100644 index 0000000000..7ffb86954e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/AttachedActorBlock.java @@ -0,0 +1,100 @@ +package com.simibubi.create.content.contraptions.actors; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public abstract class AttachedActorBlock extends HorizontalDirectionalBlock + implements IWrenchable, ProperWaterloggedBlock { + + protected AttachedActorBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return InteractionResult.FAIL; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + Direction direction = state.getValue(FACING); + return AllShapes.HARVESTER_BASE.get(direction); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(FACING, WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { + Direction direction = state.getValue(FACING); + BlockPos offset = pos.relative(direction.getOpposite()); + return BlockHelper.hasBlockSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Direction facing; + if (context.getClickedFace() + .getAxis() + .isVertical()) + facing = context.getHorizontalDirection() + .getOpposite(); + else { + BlockState blockState = context.getLevel() + .getBlockState(context.getClickedPos() + .relative(context.getClickedFace() + .getOpposite())); + if (blockState.getBlock() instanceof AttachedActorBlock) + facing = blockState.getValue(FACING); + else + facing = context.getClickedFace(); + } + return withWater(defaultBlockState().setValue(FACING, facing), context); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlock.java new file mode 100644 index 0000000000..9898d1549a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlock.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class ContraptionControlsBlock extends ControlsBlock implements IBE { + + public ContraptionControlsBlock(Properties pProperties) { + super(pProperties); + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + return onBlockEntityUse(pLevel, pPos, cte -> { + cte.pressButton(); + if (!pLevel.isClientSide()) { + cte.disabled = !cte.disabled; + cte.notifyUpdate(); + ContraptionControlsBlockEntity.sendStatus(pPlayer, cte.filtering.getFilter(), !cte.disabled); + AllSoundEvents.CONTROLLER_CLICK.play(cte.getLevel(), null, cte.getBlockPos(), 1, + cte.disabled ? 0.8f : 1.5f); + } + return InteractionResult.SUCCESS; + }); + } + + @Override + public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos, + boolean pIsMoving) { + withBlockEntityDo(pLevel, pPos, ContraptionControlsBlockEntity::updatePoweredState); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return AllShapes.CONTRAPTION_CONTROLS.get(pState.getValue(FACING)); + } + + @Override + public Class getBlockEntityClass() { + return ContraptionControlsBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CONTRAPTION_CONTROLS.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlockEntity.java new file mode 100644 index 0000000000..67550eeada --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsBlockEntity.java @@ -0,0 +1,155 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import java.util.List; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllTags.AllItemTags; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.DyeHelper; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class ContraptionControlsBlockEntity extends SmartBlockEntity { + + public FilteringBehaviour filtering; + public boolean disabled; + public boolean powered; + + public LerpedFloat indicator; + public LerpedFloat button; + + public ContraptionControlsBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + indicator = LerpedFloat.angular() + .startWithValue(0); + button = LerpedFloat.linear() + .startWithValue(0) + .chase(0, 0.125f, Chaser.EXP); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = new FilteringBehaviour(this, new ControlsSlot())); + filtering.setLabel(CreateLang.translateDirect("contraptions.contoller.target")); + filtering.withPredicate(AllItemTags.CONTRAPTION_CONTROLLED::matches); + } + + public void pressButton() { + button.setValue(1); + } + + public void updatePoweredState() { + if (level.isClientSide()) + return; + boolean powered = level.hasNeighborSignal(worldPosition); + if (this.powered == powered) + return; + this.powered = powered; + this.disabled = powered; + notifyUpdate(); + } + + @Override + public void initialize() { + super.initialize(); + updatePoweredState(); + } + + @Override + public void tick() { + super.tick(); + if (!level.isClientSide()) + return; + tickAnimations(); + int value = disabled ? 4 * 45 : 0; + indicator.setValue(value); + indicator.updateChaseTarget(value); + } + + public void tickAnimations() { + button.tickChaser(); + indicator.tickChaser(); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + disabled = tag.getBoolean("Disabled"); + powered = tag.getBoolean("Powered"); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + tag.putBoolean("Disabled", disabled); + tag.putBoolean("Powered", powered); + } + + public static void sendStatus(Player player, ItemStack filter, boolean enabled) { + MutableComponent state = CreateLang.translate("contraption.controls.actor_toggle." + (enabled ? "on" : "off")) + .color(DyeHelper.DYE_TABLE.get(enabled ? DyeColor.LIME : DyeColor.ORANGE) + .getFirst()) + .component(); + + if (filter.isEmpty()) { + CreateLang.translate("contraption.controls.all_actor_toggle", state) + .sendStatus(player); + return; + } + + CreateLang.translate("contraption.controls.specific_actor_toggle", filter.getHoverName() + .getString(), state) + .sendStatus(player); + } + + public static class ControlsSlot extends ValueBoxTransform.Sided { + + @Override + public Vec3 getLocalOffset(BlockState state) { + Direction facing = state.getValue(ControlsBlock.FACING); + float yRot = AngleHelper.horizontalAngle(facing); + return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12f, 5.5f), yRot, Axis.Y); + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + Direction facing = state.getValue(ControlsBlock.FACING); + float yRot = AngleHelper.horizontalAngle(facing); + TransformStack.cast(ms) + .rotateY(yRot + 180) + .rotateX(67.5f); + } + + @Override + public float getScale() { + return .508f; + } + + @Override + protected Vec3 getSouthLocation() { + return Vec3.ZERO; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovement.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovement.java new file mode 100644 index 0000000000..8c4e2efa97 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovement.java @@ -0,0 +1,161 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.IntAttached; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.ItemHandlerHelper; + +public class ContraptionControlsMovement implements MovementBehaviour { + + @Override + public ItemStack canBeDisabledVia(MovementContext context) { + return null; + } + + @Override + public void startMoving(MovementContext context) { + if (context.contraption instanceof ElevatorContraption && context.blockEntityData != null) + context.blockEntityData.remove("Filter"); + } + + @Override + public void stopMoving(MovementContext context) { + ItemStack filter = getFilter(context); + if (filter != null) + context.blockEntityData.putBoolean("Disabled", context.contraption.isActorTypeDisabled(filter) + || context.contraption.isActorTypeDisabled(ItemStack.EMPTY)); + } + + public static boolean isSameFilter(ItemStack stack1, ItemStack stack2) { + if (stack1.isEmpty() && stack2.isEmpty()) + return true; + return ItemHandlerHelper.canItemStacksStack(stack1, stack2); + } + + public static ItemStack getFilter(MovementContext ctx) { + CompoundTag blockEntityData = ctx.blockEntityData; + if (blockEntityData == null) + return null; + return ItemStack.of(blockEntityData.getCompound("Filter")); + } + + public static boolean isDisabledInitially(MovementContext ctx) { + return ctx.blockEntityData != null && ctx.blockEntityData.getBoolean("Disabled"); + } + + @Override + public void tick(MovementContext ctx) { + if (!ctx.world.isClientSide()) + return; + + Contraption contraption = ctx.contraption; + if (!(contraption instanceof ElevatorContraption ec)) { + if (!(contraption.presentBlockEntities.get(ctx.localPos) instanceof ContraptionControlsBlockEntity cbe)) + return; + ItemStack filter = getFilter(ctx); + int value = + contraption.isActorTypeDisabled(filter) || contraption.isActorTypeDisabled(ItemStack.EMPTY) ? 4 * 45 + : 0; + cbe.indicator.setValue(value); + cbe.indicator.updateChaseTarget(value); + cbe.tickAnimations(); + return; + } + + if (!(ctx.temporaryData instanceof ElevatorFloorSelection)) + ctx.temporaryData = new ElevatorFloorSelection(); + + ElevatorFloorSelection efs = (ElevatorFloorSelection) ctx.temporaryData; + tickFloorSelection(efs, ec); + + if (!(contraption.presentBlockEntities.get(ctx.localPos) instanceof ContraptionControlsBlockEntity cbe)) + return; + + cbe.tickAnimations(); + + int currentY = (int) Math.round(contraption.entity.getY() + ec.getContactYOffset()); + boolean atTargetY = ec.clientYTarget == currentY; + + LerpedFloat indicator = cbe.indicator; + float currentIndicator = indicator.getChaseTarget(); + boolean below = atTargetY ? currentIndicator > 0 : ec.clientYTarget <= currentY; + + if (currentIndicator == 0 && !atTargetY) { + int startingPoint = below ? 181 : -181; + indicator.setValue(startingPoint); + indicator.updateChaseTarget(startingPoint); + cbe.tickAnimations(); + return; + } + + int currentStage = Mth.floor(((currentIndicator % 360) + 360) % 360); + if (!atTargetY || currentStage / 45 != 0) { + float increment = currentStage / 45 == (below ? 4 : 3) ? 2.25f : 33.75f; + indicator.chase(currentIndicator + (below ? increment : -increment), 45f, Chaser.LINEAR); + return; + } + + indicator.setValue(0); + indicator.updateChaseTarget(0); + return; + } + + public static void tickFloorSelection(ElevatorFloorSelection efs, ElevatorContraption ec) { + if (ec.namesList.isEmpty()) { + efs.currentShortName = "X"; + efs.currentLongName = "No Floors"; + efs.currentIndex = 0; + efs.targetYEqualsSelection = true; + return; + } + + efs.currentIndex = Mth.clamp(efs.currentIndex, 0, ec.namesList.size() - 1); + IntAttached> entry = ec.namesList.get(efs.currentIndex); + efs.currentTargetY = entry.getFirst(); + efs.currentShortName = entry.getSecond() + .getFirst(); + efs.currentLongName = entry.getSecond() + .getSecond(); + efs.targetYEqualsSelection = efs.currentTargetY == ec.clientYTarget; + + if (ec.isTargetUnreachable(efs.currentTargetY)) + efs.currentLongName = CreateLang.translate("contraption.controls.floor_unreachable") + .string(); + } + + @Override + public boolean renderAsNormalBlockEntity() { + return true; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void renderInContraption(MovementContext ctx, VirtualRenderWorld renderWorld, ContraptionMatrices matrices, + MultiBufferSource buffer) { + ContraptionControlsRenderer.renderInContraption(ctx, renderWorld, matrices, buffer); + } + + public static class ElevatorFloorSelection { + public int currentIndex = 0; + public int currentTargetY = 0; + public boolean targetYEqualsSelection = true; + public String currentShortName = ""; + public String currentLongName = ""; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovingInteraction.java new file mode 100644 index 0000000000..bbc5cf56f6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsMovingInteraction.java @@ -0,0 +1,127 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang3.tuple.MutablePair; + +import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; +import com.simibubi.create.content.contraptions.elevator.ElevatorTargetFloorPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.network.PacketDistributor; + +public class ContraptionControlsMovingInteraction extends MovingInteractionBehaviour { + + @Override + public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, + AbstractContraptionEntity contraptionEntity) { + Contraption contraption = contraptionEntity.getContraption(); + + MutablePair actor = contraption.getActorAt(localPos); + if (actor == null) + return false; + MovementContext ctx = actor.right; + if (ctx == null) + return false; + if (contraption instanceof ElevatorContraption ec) + return elevatorInteraction(localPos, contraptionEntity, ec, ctx); + if (contraptionEntity.level.isClientSide()) { + if (contraption.presentBlockEntities.get(ctx.localPos) instanceof ContraptionControlsBlockEntity cbe) + cbe.pressButton(); + return true; + } + + ItemStack filter = ContraptionControlsMovement.getFilter(ctx); + boolean disable = true; + boolean invert = false; + + List disabledActors = contraption.getDisabledActors(); + for (Iterator iterator = disabledActors.iterator(); iterator.hasNext();) { + ItemStack presentFilter = iterator.next(); + boolean sameFilter = ContraptionControlsMovement.isSameFilter(presentFilter, filter); + if (presentFilter.isEmpty()) { + iterator.remove(); + disable = false; + if (!sameFilter) + invert = true; + continue; + } + if (!sameFilter) + continue; + iterator.remove(); + disable = false; + break; + } + + if (invert) { + for (MutablePair pair : contraption.getActors()) { + MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state); + if (behaviour == null) + continue; + ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right); + if (behaviourStack == null) + continue; + if (ContraptionControlsMovement.isSameFilter(behaviourStack, filter)) + continue; + if (contraption.isActorTypeDisabled(behaviourStack)) + continue; + disabledActors.add(behaviourStack); + send(contraptionEntity, behaviourStack, true); + } + } + + if (filter.isEmpty()) + disabledActors.clear(); + if (disable) + disabledActors.add(filter); + + contraption.setActorsActive(filter, !disable); + ContraptionControlsBlockEntity.sendStatus(player, filter, !disable); + send(contraptionEntity, filter, disable); + + AllSoundEvents.CONTROLLER_CLICK.play(player.level, null, + new BlockPos(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 1)), 1, disable ? 0.8f : 1.5f); + + return true; + } + + private void send(AbstractContraptionEntity contraptionEntity, ItemStack filter, boolean disable) { + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> contraptionEntity), + new ContraptionDisableActorPacket(contraptionEntity.getId(), filter, !disable)); + } + + private boolean elevatorInteraction(BlockPos localPos, AbstractContraptionEntity contraptionEntity, + ElevatorContraption contraption, MovementContext ctx) { + if (!contraptionEntity.level.isClientSide()) { + BlockPos pos = new BlockPos(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 1)); + AllSoundEvents.CONTROLLER_CLICK.play(contraptionEntity.level, null, pos, 1, 1.5f); + AllSoundEvents.CONTRAPTION_ASSEMBLE.play(contraptionEntity.level, null, pos, 0.75f, 0.8f); + return true; + } + if (!(ctx.temporaryData instanceof ElevatorFloorSelection efs)) + return false; + if (efs.currentTargetY == contraption.clientYTarget) + return true; + + AllPackets.getChannel().sendToServer(new ElevatorTargetFloorPacket(contraptionEntity, efs.currentTargetY)); + if (contraption.presentBlockEntities.get(ctx.localPos) instanceof ContraptionControlsBlockEntity cbe) + cbe.pressButton(); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsRenderer.java new file mode 100644 index 0000000000..5bff7c8f08 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionControlsRenderer.java @@ -0,0 +1,143 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import java.util.Random; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; +import com.simibubi.create.foundation.utility.DyeHelper; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.catnip.utility.theme.Color; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class ContraptionControlsRenderer extends SmartBlockEntityRenderer { + + private static Random r = new Random(); + + public ContraptionControlsRenderer(Context context) { + super(context); + } + + @Override + protected void renderSafe(ContraptionControlsBlockEntity blockEntity, float pt, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + BlockState blockState = blockEntity.getBlockState(); + Direction facing = blockState.getValue(ContraptionControlsBlock.FACING) + .getOpposite(); + Vec3 buttonMovementAxis = VecHelper.rotate(new Vec3(0, 1, -.325), AngleHelper.horizontalAngle(facing), Axis.Y); + Vec3 buttonMovement = buttonMovementAxis.scale(-0.07f + -1 / 24f * blockEntity.button.getValue(pt)); + Vec3 buttonOffset = buttonMovementAxis.scale(0.07f); + + ms.pushPose(); + ms.translate(buttonMovement.x, buttonMovement.y, buttonMovement.z); + super.renderSafe(blockEntity, pt, ms, buffer, light, overlay); + ms.translate(buttonOffset.x, buttonOffset.y, buttonOffset.z); + + VertexConsumer vc = buffer.getBuffer(RenderType.solid()); + CachedPartialBuffers.partialFacing(AllPartialModels.CONTRAPTION_CONTROLS_BUTTON, blockState, facing) + .light(light) + .renderInto(ms, vc); + + ms.popPose(); + + int i = (((int) blockEntity.indicator.getValue(pt) / 45) % 8) + 8; + CachedPartialBuffers.partialFacing(AllPartialModels.CONTRAPTION_CONTROLS_INDICATOR.get(i % 8), blockState, facing) + .light(light) + .renderInto(ms, vc); + } + + public static void renderInContraption(MovementContext ctx, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + + if (!(ctx.temporaryData instanceof ElevatorFloorSelection efs)) + return; + if (!AllBlocks.CONTRAPTION_CONTROLS.has(ctx.state)) + return; + + Entity cameraEntity = Minecraft.getInstance() + .getCameraEntity(); + float playerDistance = (float) (ctx.position == null || cameraEntity == null ? 0 + : ctx.position.distanceToSqr(cameraEntity.getEyePosition())); + + float flicker = r.nextFloat(); + Couple couple = DyeHelper.DYE_TABLE.get(efs.targetYEqualsSelection ? DyeColor.WHITE : DyeColor.ORANGE); + int brightColor = couple.getFirst(); + int darkColor = couple.getSecond(); + int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4); + Font fontRenderer = Minecraft.getInstance().font; + float shadowOffset = .5f; + + String text = efs.currentShortName; + String description = efs.currentLongName; + PoseStack ms = matrices.getViewProjection(); + TransformStack msr = TransformStack.cast(ms); + + ms.pushPose(); + msr.translate(ctx.localPos); + msr.rotateCentered(Direction.UP, + AngleHelper.rad(AngleHelper.horizontalAngle(ctx.state.getValue(ContraptionControlsBlock.FACING)))); + ms.translate(0.275f + 0.125f, 1, 0.5f); + msr.rotate(Direction.WEST, AngleHelper.rad(67.5f)); + + float buttondepth = -.25f; + if (ctx.contraption.presentBlockEntities.get(ctx.localPos) instanceof ContraptionControlsBlockEntity cbe) + buttondepth += -1 / 24f * cbe.button.getValue(WorldTickHolder.getPartialTicks(renderWorld)); + + if (!text.isBlank() && playerDistance < 100) { + int actualWidth = fontRenderer.width(text); + int width = Math.max(actualWidth, 12); + float scale = 1 / (5f * (width - .5f)); + float heightCentering = (width - 8f) / 2; + + ms.pushPose(); + ms.translate(0, .15f, buttondepth); + ms.scale(scale, -scale, scale); + ms.translate(Math.max(0, width - actualWidth) / 2, heightCentering, 0); + NixieTubeRenderer.drawInWorldString(ms, buffer, text, flickeringBrightColor); + ms.translate(shadowOffset, shadowOffset, -1 / 16f); + NixieTubeRenderer.drawInWorldString(ms, buffer, text, Color.mixColors(darkColor, 0, .35f)); + ms.popPose(); + } + + if (!description.isBlank() && playerDistance < 20) { + int actualWidth = fontRenderer.width(description); + int width = Math.max(actualWidth, 55); + float scale = 1 / (3f * (width - .5f)); + float heightCentering = (width - 8f) / 2; + + ms.pushPose(); + ms.translate(-.0635f, 0.06f, buttondepth); + ms.scale(scale, -scale, scale); + ms.translate(Math.max(0, width - actualWidth) / 2, heightCentering, 0); + NixieTubeRenderer.drawInWorldString(ms, buffer, description, flickeringBrightColor); + ms.popPose(); + } + + ms.popPose(); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionDisableActorPacket.java b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionDisableActorPacket.java new file mode 100644 index 0000000000..6122b53d05 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/contraptionControls/ContraptionDisableActorPacket.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.contraptions.actors.contraptionControls; + +import java.util.Iterator; +import java.util.List; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionDisableActorPacket extends SimplePacketBase { + + private int entityID; + private ItemStack filter; + private boolean enable; + + public ContraptionDisableActorPacket(int entityID, ItemStack filter, boolean enable) { + this.entityID = entityID; + this.filter = filter; + this.enable = enable; + } + + public ContraptionDisableActorPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + enable = buffer.readBoolean(); + filter = buffer.readItem(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + buffer.writeBoolean(enable); + buffer.writeItem(filter); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityID); + if (!(entityByID instanceof AbstractContraptionEntity ace)) + return; + + Contraption contraption = ace.getContraption(); + List disabledActors = contraption.getDisabledActors(); + if (filter.isEmpty()) + disabledActors.clear(); + + if (!enable) { + disabledActors.add(filter); + contraption.setActorsActive(filter, false); + return; + } + + for (Iterator iterator = disabledActors.iterator(); iterator.hasNext();) { + ItemStack next = iterator.next(); + if (ContraptionControlsMovement.isSameFilter(next, filter) || next.isEmpty()) + iterator.remove(); + } + + contraption.setActorsActive(filter, true); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorData.java b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorData.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorData.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorData.java index 8432de7487..32d04c8469 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.flwdata; +package com.simibubi.create.content.contraptions.actors.flwdata; import com.jozufozu.flywheel.api.InstanceData; import com.mojang.math.Quaternion; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorType.java b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorType.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorType.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorType.java index edcb0d54d4..90dfffb870 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/ActorType.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/ActorType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.flwdata; +package com.simibubi.create.content.contraptions.actors.flwdata; import com.jozufozu.flywheel.api.struct.Batched; import com.jozufozu.flywheel.api.struct.Instanced; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/UnsafeActorWriter.java b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/UnsafeActorWriter.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/UnsafeActorWriter.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/UnsafeActorWriter.java index 4479e800d1..c54b11db1a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/UnsafeActorWriter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/UnsafeActorWriter.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.flwdata; +package com.simibubi.create.content.contraptions.actors.flwdata; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/package-info.java new file mode 100644 index 0000000000..0498b1729e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/flwdata/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.simibubi.create.content.contraptions.actors.flwdata; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterActorInstance.java new file mode 100644 index 0000000000..e5ebd297fc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterActorInstance.java @@ -0,0 +1,100 @@ +package com.simibubi.create.content.contraptions.actors.harvester; + +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.Vec3; + +public class HarvesterActorInstance extends ActorInstance { + static float originOffset = 1 / 16f; + static Vec3 rotOffset = new Vec3(0.5f, -2 * originOffset + 0.5f, originOffset + 0.5f); + + protected ModelData harvester; + private Direction facing; + + protected float horizontalAngle; + + private double rotation; + private double previousRotation; + + public HarvesterActorInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, MovementContext context) { + super(materialManager, simulationWorld, context); + + Material material = materialManager.defaultCutout() + .material(Materials.TRANSFORMED); + + BlockState state = context.state; + + facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING); + + harvester = material.getModel(getRollingPartial(), state).createInstance(); + + horizontalAngle = facing.toYRot() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0); + + harvester.setBlockLight(localBlockLight()); + } + + protected PartialModel getRollingPartial() { + return AllPartialModels.HARVESTER_BLADE; + } + + protected Vec3 getRotationOffset() { + return rotOffset; + } + + protected double getRadius() { + return 6.5; + } + + @Override + public void tick() { + super.tick(); + + previousRotation = rotation; + + if (context.contraption.stalled || context.disabled + || VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite())) + return; + + double arcLength = context.motion.length(); + + double radians = arcLength * 16 / getRadius(); + + float deg = AngleHelper.deg(radians); + + deg = (float) (((int) (deg * 3000)) / 3000); + + rotation += deg * 1.25; + + rotation %= 360; + } + + @Override + public void beginFrame() { + harvester.loadIdentity() + .translate(context.localPos) + .centre() + .rotateY(horizontalAngle) + .unCentre() + .translate(getRotationOffset()) + .rotateX(getRotation()) + .translateBack(getRotationOffset()); + } + + protected double getRotation() { + return AngleHelper.angleLerp(AnimationTickHolder.getPartialTicks(), previousRotation, rotation); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlock.java new file mode 100644 index 0000000000..31e8da7236 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlock.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.actors.harvester; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.contraptions.actors.AttachedActorBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.world.level.block.entity.BlockEntityType; + +public class HarvesterBlock extends AttachedActorBlock implements IBE { + + public HarvesterBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + } + + @Override + public Class getBlockEntityClass() { + return HarvesterBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.HARVESTER.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlockEntity.java new file mode 100644 index 0000000000..b87ac1b5e5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterBlockEntity.java @@ -0,0 +1,32 @@ +package com.simibubi.create.content.contraptions.actors.harvester; + +import com.simibubi.create.foundation.blockEntity.CachedRenderBBBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class HarvesterBlockEntity extends CachedRenderBBBlockEntity { + + // For simulations such as Ponder + private float manuallyAnimatedSpeed; + + public HarvesterBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition); + } + + public float getAnimatedSpeed() { + return manuallyAnimatedSpeed; + } + + public void setAnimatedSpeed(float speed) { + manuallyAnimatedSpeed = speed; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterMovementBehaviour.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterMovementBehaviour.java index 14578f4091..bb7aff3757 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterMovementBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.harvester; import javax.annotation.Nullable; @@ -6,13 +6,13 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.VecHelper; import net.minecraft.client.renderer.MultiBufferSource; @@ -39,8 +39,9 @@ public class HarvesterMovementBehaviour implements MovementBehaviour { @Override public boolean isActive(MovementContext context) { - return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(HarvesterBlock.FACING) - .getOpposite()); + return MovementBehaviour.super.isActive(context) + && !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(HarvesterBlock.FACING) + .getOpposite()); } @Override @@ -96,7 +97,7 @@ public class HarvesterMovementBehaviour implements MovementBehaviour { MutableBoolean seedSubtracted = new MutableBoolean(notCropButCuttable); BlockState state = stateVisited; BlockHelper.destroyBlockAs(world, pos, null, item, effectChance, stack -> { - if (AllConfigs.SERVER.kinetics.harvesterReplants.get() && !seedSubtracted.getValue() + if (AllConfigs.server().kinetics.harvesterReplants.get() && !seedSubtracted.getValue() && stack.sameItem(new ItemStack(state.getBlock()))) { stack.shrink(1); seedSubtracted.setTrue(); @@ -109,8 +110,8 @@ public class HarvesterMovementBehaviour implements MovementBehaviour { } public boolean isValidCrop(Level world, BlockPos pos, BlockState state) { - boolean harvestPartial = AllConfigs.SERVER.kinetics.harvestPartiallyGrown.get(); - boolean replant = AllConfigs.SERVER.kinetics.harvesterReplants.get(); + boolean harvestPartial = AllConfigs.server().kinetics.harvestPartiallyGrown.get(); + boolean replant = AllConfigs.server().kinetics.harvesterReplants.get(); if (state.getBlock() instanceof CropBlock) { CropBlock crop = (CropBlock) state.getBlock(); @@ -174,7 +175,7 @@ public class HarvesterMovementBehaviour implements MovementBehaviour { } private BlockState cutCrop(Level world, BlockPos pos, BlockState state) { - if (!AllConfigs.SERVER.kinetics.harvesterReplants.get()) { + if (!AllConfigs.server().kinetics.harvesterReplants.get()) { if (state.getFluidState() .isEmpty()) return Blocks.AIR.defaultBlockState(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterRenderer.java new file mode 100644 index 0000000000..e70dbd94de --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/harvester/HarvesterRenderer.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.contraptions.actors.harvester; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class HarvesterRenderer extends SafeBlockEntityRenderer { + + private static final Vec3 PIVOT = new Vec3(0, 6, 9); + + public HarvesterRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(HarvesterBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.HARVESTER_BLADE, blockState); + transform(be.getLevel(), blockState.getValue(HarvesterBlock.FACING), superBuffer, be.getAnimatedSpeed(), PIVOT); + superBuffer.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffers) { + BlockState blockState = context.state; + Direction facing = blockState.getValue(HORIZONTAL_FACING); + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.HARVESTER_BLADE, blockState); + float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()) + ? context.getAnimationSpeed() + : 0); + if (context.contraption.stalled) + speed = 0; + + superBuffer.transform(matrices.getModel()); + transform(context.world, facing, superBuffer, speed, PIVOT); + + superBuffer + .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), buffers.getBuffer(RenderType.cutoutMipped())); + } + + public static void transform(Level world, Direction facing, SuperByteBuffer superBuffer, float speed, Vec3 pivot) { + float originOffset = 1 / 16f; + Vec3 rotOffset = new Vec3(0, pivot.y * originOffset, pivot.z * originOffset); + float time = WorldTickHolder.getRenderTime(world) / 20; + float angle = (time * speed) % 360; + + superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing))) + .translate(rotOffset.x, rotOffset.y, rotOffset.z) + .rotate(Direction.WEST, AngleHelper.rad(angle)) + .translate(-rotOffset.x, -rotOffset.y, -rotOffset.z); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughBlock.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughBlock.java index ef9372851d..ed70dfd0f6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughBlock.java @@ -1,8 +1,9 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.plough; import java.util.UUID; import com.mojang.authlib.GameProfile; +import com.simibubi.create.content.contraptions.actors.AttachedActorBlock; import net.minecraft.server.level.ServerLevel; import net.minecraftforge.common.util.FakePlayer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughMovementBehaviour.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughMovementBehaviour.java index ec698e5982..fd6a265f26 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/plough/PloughMovementBehaviour.java @@ -1,9 +1,10 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.plough; -import com.simibubi.create.content.contraptions.components.actors.PloughBlock.PloughFakePlayer; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.track.FakeTrackBlock; +import com.simibubi.create.content.contraptions.actors.plough.PloughBlock.PloughFakePlayer; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; +import com.simibubi.create.content.trains.track.FakeTrackBlock; +import com.simibubi.create.content.trains.track.ITrackBlock; import com.simibubi.create.foundation.advancement.AllAdvancements; import net.createmod.catnip.utility.VecHelper; @@ -38,8 +39,9 @@ public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean isActive(MovementContext context) { - return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(PloughBlock.FACING) - .getOpposite()); + return super.isActive(context) + && !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(PloughBlock.FACING) + .getOpposite()); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PIInstance.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PIInstance.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PIInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/psi/PIInstance.java index cf317ef486..a0a3ab7dbf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PIInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PIInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.psi; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.Materials; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIActorInstance.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIActorInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIActorInstance.java index 679179192b..bc256c419a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIActorInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIActorInstance.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.psi; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.animation.LerpedFloat; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIInstance.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIInstance.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIInstance.java index 18364e8a3b..5717aa2233 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PSIInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PSIInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.psi; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.instance.DynamicInstance; @@ -7,12 +7,12 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import net.createmod.catnip.utility.AnimationTickHolder; -public class PSIInstance extends BlockEntityInstance implements DynamicInstance, TickableInstance { +public class PSIInstance extends BlockEntityInstance implements DynamicInstance, TickableInstance { private final PIInstance instance; - public PSIInstance(MaterialManager materialManager, PortableStorageInterfaceTileEntity tile) { - super(materialManager, tile); + public PSIInstance(MaterialManager materialManager, PortableStorageInterfaceBlockEntity blockEntity) { + super(materialManager, blockEntity); instance = new PIInstance(materialManager, blockState, getInstancePosition()); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableFluidInterfaceBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableFluidInterfaceBlockEntity.java new file mode 100644 index 0000000000..99b3106343 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableFluidInterfaceBlockEntity.java @@ -0,0 +1,120 @@ +package com.simibubi.create.content.contraptions.actors.psi; + +import com.simibubi.create.content.contraptions.Contraption; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.templates.FluidTank; + +public class PortableFluidInterfaceBlockEntity extends PortableStorageInterfaceBlockEntity { + + protected LazyOptional capability; + + public PortableFluidInterfaceBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + capability = createEmptyHandler(); + } + + @Override + public void startTransferringTo(Contraption contraption, float distance) { + LazyOptional oldcap = capability; + capability = LazyOptional.of(() -> new InterfaceFluidHandler(contraption.getSharedFluidTanks())); + oldcap.invalidate(); + super.startTransferringTo(contraption, distance); + } + + @Override + protected void invalidateCapability() { + capability.invalidate(); + } + + @Override + protected void stopTransferring() { + LazyOptional oldcap = capability; + capability = createEmptyHandler(); + oldcap.invalidate(); + super.stopTransferring(); + } + + private LazyOptional createEmptyHandler() { + return LazyOptional.of(() -> new InterfaceFluidHandler(new FluidTank(0))); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isFluidHandlerCap(cap)) + return capability.cast(); + return super.getCapability(cap, side); + } + + public class InterfaceFluidHandler implements IFluidHandler { + + private IFluidHandler wrapped; + + public InterfaceFluidHandler(IFluidHandler wrapped) { + this.wrapped = wrapped; + } + + @Override + public int getTanks() { + return wrapped.getTanks(); + } + + @Override + public FluidStack getFluidInTank(int tank) { + return wrapped.getFluidInTank(tank); + } + + @Override + public int getTankCapacity(int tank) { + return wrapped.getTankCapacity(tank); + } + + @Override + public boolean isFluidValid(int tank, FluidStack stack) { + return wrapped.isFluidValid(tank, stack); + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (!isConnected()) + return 0; + int fill = wrapped.fill(resource, action); + if (fill > 0 && action.execute()) + keepAlive(); + return fill; + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + if (!canTransfer()) + return FluidStack.EMPTY; + FluidStack drain = wrapped.drain(resource, action); + if (!drain.isEmpty() && action.execute()) + keepAlive(); + return drain; + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + if (!canTransfer()) + return FluidStack.EMPTY; + FluidStack drain = wrapped.drain(maxDrain, action); + if (!drain.isEmpty() && action.execute()) + keepAlive(); + return drain; + } + + public void keepAlive() { + onContentTransferred(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableItemInterfaceBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableItemInterfaceBlockEntity.java new file mode 100644 index 0000000000..fd72d56279 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableItemInterfaceBlockEntity.java @@ -0,0 +1,85 @@ +package com.simibubi.create.content.contraptions.actors.psi; + +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.foundation.item.ItemHandlerWrapper; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; + +public class PortableItemInterfaceBlockEntity extends PortableStorageInterfaceBlockEntity { + + protected LazyOptional capability; + + public PortableItemInterfaceBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + capability = createEmptyHandler(); + } + + @Override + public void startTransferringTo(Contraption contraption, float distance) { + LazyOptional oldCap = capability; + capability = LazyOptional.of(() -> new InterfaceItemHandler(contraption.getSharedInventory())); + oldCap.invalidate(); + super.startTransferringTo(contraption, distance); + } + + @Override + protected void stopTransferring() { + LazyOptional oldCap = capability; + capability = createEmptyHandler(); + oldCap.invalidate(); + super.stopTransferring(); + } + + private LazyOptional createEmptyHandler() { + return LazyOptional.of(() -> new InterfaceItemHandler(new ItemStackHandler(0))); + } + + @Override + protected void invalidateCapability() { + capability.invalidate(); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return capability.cast(); + return super.getCapability(cap, side); + } + + class InterfaceItemHandler extends ItemHandlerWrapper { + + public InterfaceItemHandler(IItemHandlerModifiable wrapped) { + super(wrapped); + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (!canTransfer()) + return ItemStack.EMPTY; + ItemStack extractItem = super.extractItem(slot, amount, simulate); + if (!simulate && !extractItem.isEmpty()) + onContentTransferred(); + return extractItem; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (!canTransfer()) + return stack; + ItemStack insertItem = super.insertItem(slot, stack, simulate); + if (!simulate && !insertItem.equals(stack, false)) + onContentTransferred(); + return insertItem; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlock.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlock.java index 9bda8441ef..9faee84b6a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlock.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.psi; import javax.annotation.ParametersAreNonnullByDefault; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.minecraft.MethodsReturnNonnullByDefault; @@ -25,7 +25,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public class PortableStorageInterfaceBlock extends WrenchableDirectionalBlock - implements ITE { + implements IBE { boolean fluids; @@ -45,7 +45,7 @@ public class PortableStorageInterfaceBlock extends WrenchableDirectionalBlock @Override public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, boolean p_220069_6_) { - withTileEntityDo(world, pos, PortableStorageInterfaceTileEntity::neighbourChanged); + withBlockEntityDo(world, pos, PortableStorageInterfaceBlockEntity::neighbourChanged); } @Override @@ -75,19 +75,19 @@ public class PortableStorageInterfaceBlock extends WrenchableDirectionalBlock @Override public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return getTileEntityOptional(worldIn, pos).map(te -> te.isConnected() ? 15 : 0) + return getBlockEntityOptional(worldIn, pos).map(be -> be.isConnected() ? 15 : 0) .orElse(0); } @Override - public Class getTileEntityClass() { - return PortableStorageInterfaceTileEntity.class; + public Class getBlockEntityClass() { + return PortableStorageInterfaceBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return fluids ? AllTileEntities.PORTABLE_FLUID_INTERFACE.get() - : AllTileEntities.PORTABLE_STORAGE_INTERFACE.get(); + public BlockEntityType getBlockEntityType() { + return fluids ? AllBlockEntityTypes.PORTABLE_FLUID_INTERFACE.get() + : AllBlockEntityTypes.PORTABLE_STORAGE_INTERFACE.get(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlockEntity.java new file mode 100644 index 0000000000..37704cdff7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceBlockEntity.java @@ -0,0 +1,202 @@ +package com.simibubi.create.content.contraptions.actors.psi; + +import java.util.List; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public abstract class PortableStorageInterfaceBlockEntity extends SmartBlockEntity { + + public static final int ANIMATION = 4; + protected int transferTimer; + protected float distance; + protected LerpedFloat connectionAnimation; + protected boolean powered; + protected Entity connectedEntity; + + public int keepAlive = 0; + + public PortableStorageInterfaceBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + transferTimer = 0; + connectionAnimation = LerpedFloat.linear() + .startWithValue(0); + powered = false; + } + + public void startTransferringTo(Contraption contraption, float distance) { + if (connectedEntity == contraption.entity) + return; + this.distance = Math.min(2, distance); + connectedEntity = contraption.entity; + startConnecting(); + notifyUpdate(); + } + + protected void stopTransferring() { + connectedEntity = null; + level.updateNeighborsAt(worldPosition, getBlockState().getBlock()); + } + + public boolean canTransfer() { + if (connectedEntity != null && !connectedEntity.isAlive()) + stopTransferring(); + return connectedEntity != null && isConnected(); + } + + @Override + public void initialize() { + super.initialize(); + powered = level.hasNeighborSignal(worldPosition); + if (!powered) + notifyContraptions(); + } + + protected abstract void invalidateCapability(); + + @Override + public void tick() { + super.tick(); + boolean wasConnected = isConnected(); + int timeUnit = getTransferTimeout(); + int animation = ANIMATION; + + if (keepAlive > 0) { + keepAlive--; + if (keepAlive == 0 && !level.isClientSide) { + stopTransferring(); + transferTimer = ANIMATION - 1; + sendData(); + return; + } + } + + transferTimer = Math.min(transferTimer, ANIMATION * 2 + timeUnit); + + boolean timerCanDecrement = transferTimer > ANIMATION || transferTimer > 0 && keepAlive == 0 + && (isVirtual() || !level.isClientSide || transferTimer != ANIMATION); + + if (timerCanDecrement && (!isVirtual() || transferTimer != ANIMATION)) { + transferTimer--; + if (transferTimer == ANIMATION - 1) + sendData(); + if (transferTimer <= 0 || powered) + stopTransferring(); + } + + boolean isConnected = isConnected(); + if (wasConnected != isConnected && !level.isClientSide) + setChanged(); + + float progress = 0; + if (isConnected) + progress = 1; + else if (transferTimer >= timeUnit + animation) + progress = Mth.lerp((transferTimer - timeUnit - animation) / (float) animation, 1, 0); + else if (transferTimer < animation) + progress = Mth.lerp(transferTimer / (float) animation, 0, 1); + connectionAnimation.setValue(progress); + } + + @Override + public void invalidate() { + super.invalidate(); + invalidateCapability(); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + transferTimer = compound.getInt("Timer"); + distance = compound.getFloat("Distance"); + boolean poweredPreviously = powered; + powered = compound.getBoolean("Powered"); + if (clientPacket && powered != poweredPreviously && !powered) + notifyContraptions(); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("Timer", transferTimer); + compound.putFloat("Distance", distance); + compound.putBoolean("Powered", powered); + } + + public void neighbourChanged() { + boolean isBlockPowered = level.hasNeighborSignal(worldPosition); + if (isBlockPowered == powered) + return; + powered = isBlockPowered; + if (!powered) + notifyContraptions(); + if (powered) + stopTransferring(); + sendData(); + } + + private void notifyContraptions() { + level.getEntitiesOfClass(AbstractContraptionEntity.class, new AABB(worldPosition).inflate(3)) + .forEach(AbstractContraptionEntity::refreshPSIs); + } + + public boolean isPowered() { + return powered; + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); + } + + public boolean isTransferring() { + return transferTimer > ANIMATION; + } + + boolean isConnected() { + int timeUnit = getTransferTimeout(); + return transferTimer >= ANIMATION && transferTimer <= timeUnit + ANIMATION; + } + + float getExtensionDistance(float partialTicks) { + return (float) (Math.pow(connectionAnimation.getValue(partialTicks), 2) * distance / 2); + } + + float getConnectionDistance() { + return distance; + } + + public void startConnecting() { + transferTimer = 6 + ANIMATION * 2; + } + + public void onContentTransferred() { + int timeUnit = getTransferTimeout(); + transferTimer = timeUnit + ANIMATION; + award(AllAdvancements.PSI); + sendData(); + } + + protected Integer getTransferTimeout() { + return AllConfigs.server().logistics.psiTimeout.get(); + } + + @Override + public void addBehaviours(List behaviours) { + registerAwardables(behaviours, AllAdvancements.PSI); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceMovement.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceMovement.java index e6f55f8e45..420419e32f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceMovement.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.psi; import java.util.Optional; @@ -6,12 +6,12 @@ import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.trains.entity.CarriageContraption; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.animation.LerpedFloat; @@ -98,7 +98,7 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { if (!currentFacingIfValid.isPresent()) return; - PortableStorageInterfaceTileEntity stationaryInterface = + PortableStorageInterfaceBlockEntity stationaryInterface = getStationaryInterfaceAt(context.world, pos, context.state, currentFacingIfValid.get()); if (stationaryInterface == null) { reset(context); @@ -108,7 +108,7 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { if (stationaryInterface.connectedEntity == null) stationaryInterface.startTransferringTo(context.contraption, stationaryInterface.distance); - boolean timerBelow = stationaryInterface.transferTimer <= PortableStorageInterfaceTileEntity.ANIMATION; + boolean timerBelow = stationaryInterface.transferTimer <= PortableStorageInterfaceBlockEntity.ANIMATION; stationaryInterface.keepAlive = 2; if (context.stall && timerBelow) { context.stall = false; @@ -123,7 +123,7 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { return false; Direction currentFacing = currentFacingIfValid.get(); - PortableStorageInterfaceTileEntity psi = + PortableStorageInterfaceBlockEntity psi = findStationaryInterface(context.world, pos, context.state, currentFacing); if (psi == null) @@ -165,10 +165,10 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { getAnimation(context).chase(0, 0.25f, Chaser.LINEAR); } - private PortableStorageInterfaceTileEntity findStationaryInterface(Level world, BlockPos pos, BlockState state, + private PortableStorageInterfaceBlockEntity findStationaryInterface(Level world, BlockPos pos, BlockState state, Direction facing) { for (int i = 0; i < 2; i++) { - PortableStorageInterfaceTileEntity interfaceAt = + PortableStorageInterfaceBlockEntity interfaceAt = getStationaryInterfaceAt(world, pos.relative(facing, i), state, facing); if (interfaceAt == null) continue; @@ -177,10 +177,10 @@ public class PortableStorageInterfaceMovement implements MovementBehaviour { return null; } - private PortableStorageInterfaceTileEntity getStationaryInterfaceAt(Level world, BlockPos pos, BlockState state, + private PortableStorageInterfaceBlockEntity getStationaryInterfaceAt(Level world, BlockPos pos, BlockState state, Direction facing) { - BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof PortableStorageInterfaceTileEntity psi)) + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof PortableStorageInterfaceBlockEntity psi)) return null; BlockState blockState = world.getBlockState(pos); if (blockState.getBlock() != state.getBlock()) diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceRenderer.java new file mode 100644 index 0000000000..97b9674b01 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/psi/PortableStorageInterfaceRenderer.java @@ -0,0 +1,118 @@ +package com.simibubi.create.content.contraptions.actors.psi; + +import java.util.function.Consumer; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public class PortableStorageInterfaceRenderer extends SafeBlockEntityRenderer { + + public PortableStorageInterfaceRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(PortableStorageInterfaceBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) + return; + + BlockState blockState = be.getBlockState(); + float progress = be.getExtensionDistance(partialTicks); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + render(blockState, be.isConnected(), progress, null, sbb -> sbb.light(light) + .renderInto(ms, vb)); + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + BlockState blockState = context.state; + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + float renderPartialTicks = AnimationTickHolder.getPartialTicks(); + + LerpedFloat animation = PortableStorageInterfaceMovement.getAnimation(context); + float progress = animation.getValue(renderPartialTicks); + boolean lit = animation.settled(); + render(blockState, lit, progress, matrices.getModel(), + sbb -> sbb + .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), vb)); + } + + private static void render(BlockState blockState, boolean lit, float progress, PoseStack local, + Consumer drawCallback) { + SuperByteBuffer middle = CachedPartialBuffers.partial(getMiddleForState(blockState, lit), blockState); + SuperByteBuffer top = CachedPartialBuffers.partial(getTopForState(blockState), blockState); + + if (local != null) { + middle.transform(local); + top.transform(local); + } + Direction facing = blockState.getValue(PortableStorageInterfaceBlock.FACING); + rotateToFacing(middle, facing); + rotateToFacing(top, facing); + middle.translate(0, progress * 0.5f + 0.375f, 0); + top.translate(0, progress, 0); + + drawCallback.accept(middle); + drawCallback.accept(top); + } + + private static void rotateToFacing(SuperByteBuffer buffer, Direction facing) { + buffer.centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) + .unCentre(); + } + + static PortableStorageInterfaceBlockEntity getTargetPSI(MovementContext context) { + String _workingPos_ = PortableStorageInterfaceMovement._workingPos_; + if (!context.data.contains(_workingPos_)) + return null; + + BlockPos pos = NbtUtils.readBlockPos(context.data.getCompound(_workingPos_)); + BlockEntity blockEntity = context.world.getBlockEntity(pos); + if (!(blockEntity instanceof PortableStorageInterfaceBlockEntity psi)) + return null; + + if (!psi.isTransferring()) + return null; + return psi; + } + + static PartialModel getMiddleForState(BlockState state, boolean lit) { + if (AllBlocks.PORTABLE_FLUID_INTERFACE.has(state)) + return lit ? AllPartialModels.PORTABLE_FLUID_INTERFACE_MIDDLE_POWERED + : AllPartialModels.PORTABLE_FLUID_INTERFACE_MIDDLE; + return lit ? AllPartialModels.PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED + : AllPartialModels.PORTABLE_STORAGE_INTERFACE_MIDDLE; + } + + static PartialModel getTopForState(BlockState state) { + if (AllBlocks.PORTABLE_FLUID_INTERFACE.has(state)) + return AllPartialModels.PORTABLE_FLUID_INTERFACE_TOP; + return AllPartialModels.PORTABLE_STORAGE_INTERFACE_TOP; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/PaveTask.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/PaveTask.java new file mode 100644 index 0000000000..eedc2fdb25 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/PaveTask.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; + +public class PaveTask { + + private Couple horizontalInterval; + private Map, Float> heightValues = new HashMap<>(); + + public PaveTask(double h1, double h2) { + horizontalInterval = Couple.create(h1, h2); + } + + public Couple getHorizontalInterval() { + return horizontalInterval; + } + + public void put(int x, int z, float y) { + heightValues.put(Couple.create(x, z), y); + } + + public float get(Couple coords) { + return heightValues.get(coords); + } + + public Set> keys() { + return heightValues.keySet(); + } + + public void put(BlockPos p) { + put(p.getX(), p.getZ(), p.getY()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerActorInstance.java new file mode 100644 index 0000000000..1e76217e74 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerActorInstance.java @@ -0,0 +1,64 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterActorInstance; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; + +import net.minecraft.world.phys.Vec3; + +public class RollerActorInstance extends HarvesterActorInstance { + + ModelData frame; + + public RollerActorInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, + MovementContext context) { + super(materialManager, simulationWorld, context); + + Material material = materialManager.defaultCutout() + .material(Materials.TRANSFORMED); + frame = material.getModel(AllPartialModels.ROLLER_FRAME, context.state) + .createInstance(); + frame.setBlockLight(localBlockLight()); + } + + @Override + public void beginFrame() { + harvester.loadIdentity() + .translate(context.localPos) + .centre() + .rotateY(horizontalAngle) + .unCentre() + .translate(0, -.25, 17 / 16f) + .rotateX(getRotation()) + .translate(0, -.5, .5) + .rotateY(90); + + frame.loadIdentity() + .translate(context.localPos) + .centre() + .rotateY(horizontalAngle + 180) + .unCentre(); + } + + @Override + protected PartialModel getRollingPartial() { + return AllPartialModels.ROLLER_WHEEL; + } + + @Override + protected Vec3 getRotationOffset() { + return Vec3.ZERO; + } + + @Override + protected double getRadius() { + return 16.5; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlock.java new file mode 100644 index 0000000000..13bfa3733b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlock.java @@ -0,0 +1,107 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import java.util.function.Predicate; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.actors.AttachedActorBlock; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.placement.PoleHelper; + +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class RollerBlock extends AttachedActorBlock implements IBE { + + public static DamageSource damageSourceRoller = new DamageSource("create.mechanical_roller"); + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public RollerBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return withWater(defaultBlockState().setValue(FACING, context.getHorizontalDirection() + .getOpposite()), context); + } + + @Override + public Class getBlockEntityClass() { + return RollerBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_ROLLER.get(); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return Shapes.block(); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { + return true; + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); + withBlockEntityDo(pLevel, pPos, RollerBlockEntity::searchForSharedValues); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + ItemStack heldItem = player.getItemInHand(hand); + + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldItem)) { + placementHelper.getOffset(player, world, state, pos, ray) + .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return InteractionResult.SUCCESS; + } + } + + return InteractionResult.PASS; + } + + private static class PlacementHelper extends PoleHelper { + + public PlacementHelper() { + super(AllBlocks.MECHANICAL_ROLLER::has, state -> state.getValue(FACING) + .getClockWise() + .getAxis(), FACING); + } + + @Override + public Predicate getItemPredicate() { + return AllBlocks.MECHANICAL_ROLLER::isIn; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java new file mode 100644 index 0000000000..5ee41d2b1d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockEntity.java @@ -0,0 +1,208 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import java.util.List; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Lang; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.StairBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class RollerBlockEntity extends SmartBlockEntity { + + // For simulations such as Ponder + private float manuallyAnimatedSpeed; + + public FilteringBehaviour filtering; + public ScrollOptionBehaviour mode; + + private boolean dontPropagate; + + public RollerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + dontPropagate = false; + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = new FilteringBehaviour(this, new RollerValueBox(3))); + behaviours.add(mode = new ScrollOptionBehaviour(RollingMode.class, + CreateLang.translateDirect("contraptions.roller_mode"), this, new RollerValueBox(-3))); + + filtering.setLabel(CreateLang.translateDirect("contraptions.mechanical_roller.pave_material")); + filtering.withCallback(this::onFilterChanged); + filtering.withPredicate(this::isValidMaterial); + mode.withCallback(this::onModeChanged); + } + + protected void onModeChanged(int mode) { + shareValuesToAdjacent(); + } + + protected void onFilterChanged(ItemStack newFilter) { + shareValuesToAdjacent(); + } + + protected boolean isValidMaterial(ItemStack newFilter) { + if (newFilter.isEmpty()) + return true; + BlockState appliedState = RollerMovementBehaviour.getStateToPaveWith(newFilter); + if (appliedState.isAir()) + return false; + if (appliedState.getBlock() instanceof EntityBlock) + return false; + if (appliedState.getBlock() instanceof StairBlock) + return false; + VoxelShape shape = appliedState.getShape(level, worldPosition); + if (shape.isEmpty() || !shape.bounds() + .equals(Shapes.block() + .bounds())) + return false; + VoxelShape collisionShape = appliedState.getCollisionShape(level, worldPosition); + if (collisionShape.isEmpty()) + return false; + return true; + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).inflate(1); + } + + public float getAnimatedSpeed() { + return manuallyAnimatedSpeed; + } + + public void setAnimatedSpeed(float speed) { + manuallyAnimatedSpeed = speed; + } + + public void searchForSharedValues() { + BlockState blockState = getBlockState(); + Direction facing = blockState.getOptionalValue(RollerBlock.FACING) + .orElse(Direction.SOUTH); + + for (int side : Iterate.positiveAndNegative) { + BlockPos pos = worldPosition.relative(facing.getClockWise(), side); + if (level.getBlockState(pos) != blockState) + continue; + if (!(level.getBlockEntity(pos) instanceof RollerBlockEntity otherRoller)) + continue; + acceptSharedValues(otherRoller.mode.getValue(), otherRoller.filtering.getFilter()); + shareValuesToAdjacent(); + break; + } + } + + protected void acceptSharedValues(int mode, ItemStack filter) { + dontPropagate = true; + this.filtering.setFilter(filter); + this.mode.setValue(mode); + dontPropagate = false; + notifyUpdate(); + } + + public void shareValuesToAdjacent() { + if (dontPropagate || level.isClientSide()) + return; + BlockState blockState = getBlockState(); + Direction facing = blockState.getOptionalValue(RollerBlock.FACING) + .orElse(Direction.SOUTH); + + for (int side : Iterate.positiveAndNegative) { + for (int i = 1; i < 100; i++) { + BlockPos pos = worldPosition.relative(facing.getClockWise(), side * i); + if (level.getBlockState(pos) != blockState) + break; + if (!(level.getBlockEntity(pos) instanceof RollerBlockEntity otherRoller)) + break; + otherRoller.acceptSharedValues(mode.getValue(), filtering.getFilter()); + } + } + } + + static enum RollingMode implements INamedIconOptions { + + TUNNEL_PAVE(AllIcons.I_ROLLER_PAVE), + STRAIGHT_FILL(AllIcons.I_ROLLER_FILL), + WIDE_FILL(AllIcons.I_ROLLER_WIDE_FILL), + + ; + + private String translationKey; + private AllIcons icon; + + private RollingMode(AllIcons icon) { + this.icon = icon; + translationKey = "contraptions.roller_mode." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + + } + + private final class RollerValueBox extends ValueBoxTransform { + + private int hOffset; + + public RollerValueBox(int hOffset) { + this.hOffset = hOffset; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + Direction facing = state.getValue(RollerBlock.FACING); + float yRot = AngleHelper.horizontalAngle(facing) + 180; + TransformStack.cast(ms) + .rotateY(yRot) + .rotateX(90); + } + + @Override + public boolean testHit(BlockState state, Vec3 localHit) { + Vec3 offset = getLocalOffset(state); + if (offset == null) + return false; + return localHit.distanceTo(offset) < scale / 3; + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + Direction facing = state.getValue(RollerBlock.FACING); + float stateAngle = AngleHelper.horizontalAngle(facing) + 180; + return VecHelper.rotateCentered(VecHelper.voxelSpace(8 + hOffset, 15.5f, 11), stateAngle, Axis.Y); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockItem.java new file mode 100644 index 0000000000..3bf7c6070f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerBlockItem.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class RollerBlockItem extends BlockItem { + + public RollerBlockItem(Block pBlock, Properties pProperties) { + super(pBlock, pProperties); + } + + @Override + public InteractionResult place(BlockPlaceContext ctx) { + BlockPos clickedPos = ctx.getClickedPos(); + Level level = ctx.getLevel(); + BlockState blockStateBelow = level.getBlockState(clickedPos.below()); + if (!Block.isFaceFull(blockStateBelow.getCollisionShape(level, clickedPos.below()), Direction.UP)) + return super.place(ctx); + Direction clickedFace = ctx.getClickedFace(); + return super.place(BlockPlaceContext.at(ctx, clickedPos.relative(Direction.UP), clickedFace)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java new file mode 100644 index 0000000000..113d529ebc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerMovementBehaviour.java @@ -0,0 +1,470 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.actors.roller.RollerBlockEntity.RollingMode; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.pulley.PulleyContraption; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.trains.bogey.StandardBogeyBlock; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageBogey; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TravellingPoint; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.FallingBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.registries.ForgeRegistries; + +public class RollerMovementBehaviour extends BlockBreakingMovementBehaviour { + + @Override + public boolean isActive(MovementContext context) { + return super.isActive(context) && !(context.contraption instanceof PulleyContraption) + && VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(RollerBlock.FACING)); + } + + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Nullable + @Override + public ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, + MovementContext context) { + return new RollerActorInstance(materialManager, simulationWorld, context); + } + + @Override + public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffers) { + if (!ContraptionRenderDispatcher.canInstance()) + RollerRenderer.renderInContraption(context, renderWorld, matrices, buffers); + } + + @Override + public Vec3 getActiveAreaOffset(MovementContext context) { + return Vec3.atLowerCornerOf(context.state.getValue(RollerBlock.FACING) + .getNormal()) + .scale(.45) + .subtract(0, 2, 0); + } + + @Override + protected float getBlockBreakingSpeed(MovementContext context) { + return Mth.clamp(super.getBlockBreakingSpeed(context) * 1.5f, 1 / 128f, 16f); + } + + @Override + public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { + return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) + .isEmpty() && !AllBlocks.TRACK.has(state); + } + + @Override + protected DamageSource getDamageSource() { + return RollerBlock.damageSourceRoller; + } + + @Override + public void visitNewPosition(MovementContext context, BlockPos pos) { + Level world = context.world; + BlockState stateVisited = world.getBlockState(pos); + if (!stateVisited.isRedstoneConductor(world, pos)) + damageEntities(context, pos, world); + if (world.isClientSide) + return; + + List positionsToBreak = getPositionsToBreak(context, pos); + if (positionsToBreak.isEmpty()) { + triggerPaver(context, pos); + return; + } + + BlockPos argMax = null; + double max = -1; + for (BlockPos toBreak : positionsToBreak) { + float hardness = context.world.getBlockState(toBreak) + .getDestroySpeed(world, toBreak); + if (hardness < max) + continue; + max = hardness; + argMax = toBreak; + } + + if (argMax == null) { + triggerPaver(context, pos); + return; + } + + context.data.put("ReferencePos", NbtUtils.writeBlockPos(pos)); + context.data.put("BreakingPos", NbtUtils.writeBlockPos(argMax)); + context.stall = true; + } + + @Override + protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { + super.onBlockBroken(context, pos, brokenState); + if (!context.data.contains("ReferencePos")) + return; + + BlockPos referencePos = NbtUtils.readBlockPos(context.data.getCompound("ReferencePos")); + for (BlockPos otherPos : getPositionsToBreak(context, referencePos)) + if (!otherPos.equals(pos)) + destroyBlock(context, otherPos); + + triggerPaver(context, referencePos); + context.data.remove("ReferencePos"); + } + + @Override + protected void destroyBlock(MovementContext context, BlockPos breakingPos) { + BlockState blockState = context.world.getBlockState(breakingPos); + boolean noHarvest = blockState.is(BlockTags.NEEDS_IRON_TOOL) || blockState.is(BlockTags.NEEDS_STONE_TOOL) + || blockState.is(BlockTags.NEEDS_DIAMOND_TOOL); + + BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> { + if (noHarvest || context.world.random.nextBoolean()) + return; + this.dropItem(context, stack); + }); + + super.destroyBlock(context, breakingPos); + } + + RollerTravellingPoint rollerScout = new RollerTravellingPoint(); + + protected List getPositionsToBreak(MovementContext context, BlockPos visitedPos) { + ArrayList positions = new ArrayList<>(); + + RollingMode mode = getMode(context); + if (mode != RollingMode.TUNNEL_PAVE) + return positions; + + int startingY = 1; + if (!getStateToPaveWith(context).isAir()) { + ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); + if (!ItemHelper + .extract(context.contraption.getSharedInventory(), + stack -> FilterItem.test(context.world, stack, filter), 1, true) + .isEmpty()) + startingY = 0; + } + + // Train + PaveTask profileForTracks = createHeightProfileForTracks(context); + if (profileForTracks != null) { + for (Couple coords : profileForTracks.keys()) { + float height = profileForTracks.get(coords); + BlockPos targetPosition = new BlockPos(coords.getFirst(), height, coords.getSecond()); + boolean shouldPlaceSlab = height > Math.floor(height) + .45; + if (startingY == 1 && shouldPlaceSlab && context.world.getBlockState(targetPosition.above()) + .getOptionalValue(SlabBlock.TYPE) + .orElse(SlabType.DOUBLE) == SlabType.BOTTOM) + startingY = 2; + for (int i = startingY; i <= (shouldPlaceSlab ? 3 : 2); i++) + if (testBreakerTarget(context, targetPosition.above(i), i)) + positions.add(targetPosition.above(i)); + } + return positions; + } + + // Otherwise + for (int i = startingY; i <= 2; i++) + if (testBreakerTarget(context, visitedPos.above(i), i)) + positions.add(visitedPos.above(i)); + + return positions; + } + + protected boolean testBreakerTarget(MovementContext context, BlockPos target, int columnY) { + BlockState stateToPaveWith = getStateToPaveWith(context); + BlockState stateToPaveWithAsSlab = getStateToPaveWithAsSlab(context); + BlockState stateAbove = context.world.getBlockState(target); + if (columnY == 0 && stateAbove.is(stateToPaveWith.getBlock())) + return false; + if (stateToPaveWithAsSlab != null && columnY == 1 && stateAbove.is(stateToPaveWithAsSlab.getBlock())) + return false; + return canBreak(context.world, target, stateAbove); + } + + @Nullable + protected PaveTask createHeightProfileForTracks(MovementContext context) { + if (context.contraption == null) + return null; + if (!(context.contraption.entity instanceof CarriageContraptionEntity cce)) + return null; + Carriage carriage = cce.getCarriage(); + if (carriage == null) + return null; + Train train = carriage.train; + if (train == null || train.graph == null) + return null; + + CarriageBogey mainBogey = carriage.bogeys.getFirst(); + TravellingPoint point = mainBogey.trailing(); + + rollerScout.node1 = point.node1; + rollerScout.node2 = point.node2; + rollerScout.edge = point.edge; + rollerScout.position = point.position; + + Axis axis = Axis.X; + StructureBlockInfo info = context.contraption.getBlocks() + .get(BlockPos.ZERO); + if (info != null && info.state.hasProperty(StandardBogeyBlock.AXIS)) + axis = info.state.getValue(StandardBogeyBlock.AXIS); + + Direction orientation = cce.getInitialOrientation(); + Direction rollerFacing = context.state.getValue(RollerBlock.FACING); + + int step = orientation.getAxisDirection() + .getStep(); + double widthWiseOffset = axis.choose(-context.localPos.getZ(), 0, -context.localPos.getX()) * step; + double lengthWiseOffset = axis.choose(-context.localPos.getX(), 0, context.localPos.getZ()) * step - 1; + + if (rollerFacing == orientation.getClockWise()) + lengthWiseOffset += 1; + + double distanceToTravel = 2; + PaveTask heightProfile = new PaveTask(widthWiseOffset, widthWiseOffset); + ITrackSelector steering = rollerScout.steer(SteerDirection.NONE, new Vec3(0, 1, 0)); + + rollerScout.traversalCallback = (edge, coords) -> { + }; + rollerScout.travel(train.graph, lengthWiseOffset + 1, steering); + + rollerScout.traversalCallback = (edge, coords) -> TrackPaverV2.pave(heightProfile, train.graph, edge, + coords.getFirst(), coords.getSecond()); + rollerScout.travel(train.graph, distanceToTravel, steering); + + for (Couple entry : heightProfile.keys()) + heightProfile.put(entry.getFirst(), entry.getSecond(), context.localPos.getY() + heightProfile.get(entry)); + + return heightProfile; + } + + protected void triggerPaver(MovementContext context, BlockPos pos) { + BlockState stateToPaveWith = getStateToPaveWith(context); + BlockState stateToPaveWithAsSlab = getStateToPaveWithAsSlab(context); + RollingMode mode = getMode(context); + + Vec3 directionVec = Vec3.atLowerCornerOf(context.state.getValue(RollerBlock.FACING) + .getClockWise() + .getNormal()); + directionVec = context.rotation.apply(directionVec); + PaveResult paveResult = PaveResult.PASS; + int yOffset = 0; + + List> paveSet = new ArrayList<>(); + PaveTask profileForTracks = createHeightProfileForTracks(context); + if (profileForTracks == null) + paveSet.add(Pair.of(pos, false)); + else + for (Couple coords : profileForTracks.keys()) { + float height = profileForTracks.get(coords); + boolean shouldPlaceSlab = height > Math.floor(height) + .45; + BlockPos targetPosition = new BlockPos(coords.getFirst(), height, coords.getSecond()); + paveSet.add(Pair.of(targetPosition, shouldPlaceSlab)); + } + + if (paveSet.isEmpty()) + return; + + while (paveResult == PaveResult.PASS) { + if (yOffset > AllConfigs.server().kinetics.rollerFillDepth.get()) { + paveResult = PaveResult.FAIL; + break; + } + + Set> currentLayer = new HashSet<>(); + if (mode == RollingMode.WIDE_FILL) { + for (Pair anchor : paveSet) { + int radius = (yOffset + 1) / 2; + for (int i = -radius; i <= radius; i++) + for (int j = -radius; j <= radius; j++) + if (BlockPos.ZERO.distManhattan(new BlockPos(i, 0, j)) <= radius) + currentLayer.add(Pair.of(anchor.getFirst() + .offset(i, -yOffset, j), anchor.getSecond())); + } + } else + for (Pair anchor : paveSet) + currentLayer.add(Pair.of(anchor.getFirst() + .below(yOffset), anchor.getSecond())); + + boolean completelyBlocked = true; + boolean anyBlockPlaced = false; + + for (Pair currentPos : currentLayer) { + if (stateToPaveWithAsSlab != null && yOffset == 0 && currentPos.getSecond()) + tryFill(context, currentPos.getFirst() + .above(), stateToPaveWithAsSlab); + paveResult = tryFill(context, currentPos.getFirst(), stateToPaveWith); + if (paveResult != PaveResult.FAIL) + completelyBlocked = false; + if (paveResult == PaveResult.SUCCESS) + anyBlockPlaced = true; + } + + if (anyBlockPlaced) + paveResult = PaveResult.SUCCESS; + else if (!completelyBlocked || yOffset == 0) + paveResult = PaveResult.PASS; + + if (paveResult == PaveResult.SUCCESS && stateToPaveWith.getBlock() instanceof FallingBlock) + paveResult = PaveResult.PASS; + if (paveResult != PaveResult.PASS) + break; + if (mode == RollingMode.TUNNEL_PAVE) + break; + + yOffset++; + } + + if (paveResult == PaveResult.SUCCESS) { + context.data.putInt("WaitingTicks", 2); + context.data.put("LastPos", NbtUtils.writeBlockPos(pos)); + context.stall = true; + } + } + + public static BlockState getStateToPaveWith(ItemStack itemStack) { + if (itemStack.getItem()instanceof BlockItem bi) { + BlockState defaultBlockState = bi.getBlock() + .defaultBlockState(); + if (defaultBlockState.hasProperty(SlabBlock.TYPE)) + defaultBlockState = defaultBlockState.setValue(SlabBlock.TYPE, SlabType.DOUBLE); + return defaultBlockState; + } + return Blocks.AIR.defaultBlockState(); + } + + protected BlockState getStateToPaveWith(MovementContext context) { + return getStateToPaveWith(ItemStack.of(context.blockEntityData.getCompound("Filter"))); + } + + protected BlockState getStateToPaveWithAsSlab(MovementContext context) { + BlockState stateToPaveWith = getStateToPaveWith(context); + if (stateToPaveWith.hasProperty(SlabBlock.TYPE)) + return stateToPaveWith.setValue(SlabBlock.TYPE, SlabType.BOTTOM); + + Block block = stateToPaveWith.getBlock(); + if (block == null) + return null; + + ResourceLocation rl = block.getRegistryName(); + String namespace = rl.getNamespace(); + String blockName = rl.getPath(); + int nameLength = blockName.length(); + + List possibleSlabLocations = new ArrayList<>(); + possibleSlabLocations.add(blockName + "_slab"); + + if (blockName.endsWith("s") && nameLength > 1) + possibleSlabLocations.add(blockName.substring(0, nameLength - 1) + "_slab"); + if (blockName.endsWith("planks") && nameLength > 7) + possibleSlabLocations.add(blockName.substring(0, nameLength - 7) + "_slab"); + + for (String locationAttempt : possibleSlabLocations) { + Optional result = ForgeRegistries.BLOCKS.getHolder(new ResourceLocation(namespace, locationAttempt)) + .map(slabHolder -> slabHolder.value()); + if (result.isEmpty()) + continue; + return result.get() + .defaultBlockState(); + } + + return null; + } + + protected RollingMode getMode(MovementContext context) { + return RollingMode.values()[context.blockEntityData.getInt("ScrollValue")]; + } + + private final class RollerTravellingPoint extends TravellingPoint { + + public BiConsumer> traversalCallback; + + @Override + protected Double edgeTraversedFrom(TrackGraph graph, boolean forward, IEdgePointListener edgePointListener, + ITurnListener turnListener, double prevPos, double totalDistance) { + double from = forward ? prevPos : position; + double to = forward ? position : prevPos; + traversalCallback.accept(edge, Couple.create(from, to)); + return super.edgeTraversedFrom(graph, forward, edgePointListener, turnListener, prevPos, totalDistance); + } + + } + + private enum PaveResult { + FAIL, PASS, SUCCESS; + } + + protected PaveResult tryFill(MovementContext context, BlockPos targetPos, BlockState toPlace) { + Level level = context.world; + if (!level.isLoaded(targetPos)) + return PaveResult.FAIL; + BlockState existing = level.getBlockState(targetPos); + if (existing.is(toPlace.getBlock())) + return PaveResult.PASS; + if (!existing.is(BlockTags.LEAVES) && !existing.getMaterial() + .isReplaceable() + && !existing.getCollisionShape(level, targetPos) + .isEmpty()) + return PaveResult.FAIL; + + ItemStack filter = ItemStack.of(context.blockEntityData.getCompound("Filter")); + ItemStack held = ItemHelper.extract(context.contraption.getSharedInventory(), + stack -> FilterItem.test(context.world, stack, filter), 1, false); + if (held.isEmpty()) + return PaveResult.FAIL; + + level.setBlockAndUpdate(targetPos, toPlace); + return PaveResult.SUCCESS; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerRenderer.java new file mode 100644 index 0000000000..b3e7e49fae --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/RollerRenderer.java @@ -0,0 +1,90 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.actors.harvester.HarvesterRenderer; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class RollerRenderer extends SmartBlockEntityRenderer { + + public RollerRenderer(Context context) { + super(context); + } + + @Override + protected void renderSafe(RollerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + BlockState blockState = be.getBlockState(); + + ms.pushPose(); + ms.translate(0, -0.25, 0); + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.ROLLER_WHEEL, blockState); + Direction facing = blockState.getValue(RollerBlock.FACING); + superBuffer.translate(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(17 / 16f)); + HarvesterRenderer.transform(be.getLevel(), facing, superBuffer, be.getAnimatedSpeed(), Vec3.ZERO); + superBuffer.translate(0, -.5, .5) + .rotateY(90) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + ms.popPose(); + + CachedPartialBuffers.partial(AllPartialModels.ROLLER_FRAME, blockState) + .rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing) + 180)) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffers) { + BlockState blockState = context.state; + Direction facing = blockState.getValue(HORIZONTAL_FACING); + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.ROLLER_WHEEL, blockState); + float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()) + ? context.getAnimationSpeed() + : -context.getAnimationSpeed()); + if (context.contraption.stalled) + speed = 0; + + superBuffer.transform(matrices.getModel()) + .translate(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(17 / 16f)); + HarvesterRenderer.transform(context.world, facing, superBuffer, speed, Vec3.ZERO); + + PoseStack viewProjection = matrices.getViewProjection(); + viewProjection.pushPose(); + viewProjection.translate(0, -.25, 0); + int contraptionWorldLight = ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld); + superBuffer.translate(0, -.5, .5) + .rotateY(90) + .light(matrices.getWorld(), contraptionWorldLight) + .renderInto(viewProjection, buffers.getBuffer(RenderType.cutoutMipped())); + viewProjection.popPose(); + + CachedPartialBuffers.partial(AllPartialModels.ROLLER_FRAME, blockState) + .transform(matrices.getModel()) + .rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing) + 180)) + .light(matrices.getWorld(), contraptionWorldLight) + .renderInto(viewProjection, buffers.getBuffer(RenderType.cutoutMipped())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/roller/TrackPaverV2.java b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/TrackPaverV2.java new file mode 100644 index 0000000000..0ed878aafd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/roller/TrackPaverV2.java @@ -0,0 +1,217 @@ +package com.simibubi.create.content.contraptions.actors.roller; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.track.BezierConnection; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class TrackPaverV2 { + + public static void pave(PaveTask task, TrackGraph graph, TrackEdge edge, double from, double to) { + if (edge.isTurn()) { + paveCurve(task, edge.getTurn(), from, to); + return; + } + + Vec3 location1 = edge.node1.getLocation() + .getLocation(); + Vec3 location2 = edge.node2.getLocation() + .getLocation(); + Vec3 diff = location2.subtract(location1); + Vec3 direction = VecHelper.clampComponentWise(diff, 1); + int extent = (int) Math.round((to - from) / direction.length()); + double length = edge.getLength(); + + BlockPos pos = new BlockPos(edge.getPosition(graph, Mth.clamp(from, 1 / 16f, length - 1 / 16f) / length) + .subtract(0, diff.y != 0 ? 1 : 0.5, 0)); + + paveStraight(task, pos, direction, extent); + } + + public static void paveStraight(PaveTask task, BlockPos startPos, Vec3 direction, int extent) { + Set toPlaceOn = new HashSet<>(); + Vec3 start = VecHelper.getCenterOf(startPos); + Vec3 mainNormal = direction.cross(new Vec3(0, 1, 0)); + Vec3 normalizedDirection = direction.normalize(); + + boolean isDiagonalTrack = direction.multiply(1, 0, 1) + .length() > 1.125f; + double r1 = task.getHorizontalInterval() + .getFirst(); + int flip = (int) Math.signum(r1); + double r2 = r1 + flip; + + if (isDiagonalTrack) { + r1 /= Mth.SQRT_OF_TWO; + r2 /= Mth.SQRT_OF_TWO; + } + + int currentOffset = (int) (Math.abs(r1) * 2 + .5f); + int nextOffset = (int) (Math.abs(r2) * 2 + .5f); + + for (int i = 0; i < extent; i++) { + Vec3 offset = direction.scale(i); + Vec3 mainPos = start.add(offset.x, offset.y, offset.z); + Vec3 targetVec = mainPos.add(mainNormal.scale(flip * (int) (currentOffset / 2.0))); + + if (!isDiagonalTrack) { + toPlaceOn.add(new BlockPos(targetVec)); + continue; + } + + boolean placeRow = currentOffset % 2 == 0 || nextOffset % 2 == 1; + boolean placeSides = currentOffset % 2 == 1 || nextOffset % 2 == 0; + + if (placeSides) { + for (int side : Iterate.positiveAndNegative) { + Vec3 sideOffset = normalizedDirection.scale(side) + .add(mainNormal.normalize() + .scale(flip)) + .scale(.5); + toPlaceOn.add(new BlockPos(targetVec.add(sideOffset))); + } + } + + if (placeRow) { + if (Math.abs(currentOffset % 2) == 1) + targetVec = mainPos.add(mainNormal.scale(flip * (int) ((currentOffset + 1) / 2.0))); + toPlaceOn.add(new BlockPos(targetVec)); + } + + } + + toPlaceOn.forEach(task::put); + } + + public static void paveCurve(PaveTask task, BezierConnection bc, double from, double to) { + Map, Double> yLevels = new HashMap<>(); + Map, Double> tLevels = new HashMap<>(); + + BlockPos tePosition = bc.tePositions.getFirst(); + double radius = -task.getHorizontalInterval() + .getFirst(); + double r1 = radius - .575; + double r2 = radius + .575; + + double handleLength = bc.getHandleLength(); + Vec3 start = bc.starts.getFirst() + .subtract(Vec3.atLowerCornerOf(tePosition)) + .add(0, 3 / 16f, 0); + Vec3 end = bc.starts.getSecond() + .subtract(Vec3.atLowerCornerOf(tePosition)) + .add(0, 3 / 16f, 0); + Vec3 startHandle = bc.axes.getFirst() + .scale(handleLength) + .add(start); + Vec3 endHandle = bc.axes.getSecond() + .scale(handleLength) + .add(end); + Vec3 startNormal = bc.normals.getFirst(); + Vec3 endNormal = bc.normals.getSecond(); + + int segCount = bc.getSegmentCount(); + float[] lut = bc.getStepLUT(); + double localFrom = from / bc.getLength(); + double localTo = to / bc.getLength(); + + for (int i = 0; i < segCount; i++) { + + float t = i == segCount ? 1 : i * lut[i] / segCount; + float t1 = (i + 1) == segCount ? 1 : (i + 1) * lut[(i + 1)] / segCount; + + if (t1 < localFrom) + continue; + if (t > localTo) + continue; + + Vec3 vt = VecHelper.bezier(start, end, startHandle, endHandle, t); + Vec3 vNormal = startNormal.equals(endNormal) ? startNormal : VecHelper.slerp(t, startNormal, endNormal); + Vec3 hNormal = vNormal.cross(VecHelper.bezierDerivative(start, end, startHandle, endHandle, t) + .normalize()) + .normalize(); + vt = vt.add(vNormal.scale(-1.175f)); + + Vec3 vt1 = VecHelper.bezier(start, end, startHandle, endHandle, t1); + Vec3 vNormal1 = startNormal.equals(endNormal) ? startNormal : VecHelper.slerp(t1, startNormal, endNormal); + Vec3 hNormal1 = vNormal1.cross(VecHelper.bezierDerivative(start, end, startHandle, endHandle, t1) + .normalize()) + .normalize(); + vt1 = vt1.add(vNormal1.scale(-1.175f)); + + Vec3 a3 = vt.add(hNormal.scale(r2)); + Vec3 b3 = vt1.add(hNormal1.scale(r2)); + Vec3 c3 = vt1.add(hNormal1.scale(r1)); + Vec3 d3 = vt.add(hNormal.scale(r1)); + + Vec2 a = vec2(a3); + Vec2 b = vec2(b3); + Vec2 c = vec2(c3); + Vec2 d = vec2(d3); + + AABB aabb = new AABB(a3, b3).minmax(new AABB(c3, d3)); + + double y = vt.add(vt1).y / 2f; + for (int scanX = Mth.floor(aabb.minX); scanX <= aabb.maxX; scanX++) { + for (int scanZ = Mth.floor(aabb.minZ); scanZ <= aabb.maxZ; scanZ++) { + + Vec2 p = new Vec2(scanX + .5f, scanZ + .5f); + if (!isInTriangle(a, b, c, p) && !isInTriangle(a, c, d, p)) + continue; + + Pair key = Pair.of(scanX, scanZ); + if (!yLevels.containsKey(key) || yLevels.get(key) > y) { + yLevels.put(key, y); + tLevels.put(key, (t + t1) / 2d); + } + } + } + + } + + // + + for (Entry, Double> entry : yLevels.entrySet()) { + double yValue = entry.getValue(); + int floor = Mth.floor(yValue); + BlockPos targetPos = new BlockPos(entry.getKey() + .getFirst(), floor, + entry.getKey() + .getSecond()).offset(tePosition); + task.put(targetPos.getX(), targetPos.getZ(), targetPos.getY() + (yValue - floor >= .5 ? .5f : 0)); + } + } + + private static Vec2 vec2(Vec3 vec3) { + return new Vec2((float) vec3.x, (float) vec3.z); + } + + private static boolean isInTriangle(Vec2 a, Vec2 b, Vec2 c, Vec2 p) { + float pcx = p.x - c.x; + float pcy = p.y - c.y; + float cbx = c.x - b.x; + float bcy = b.y - c.y; + float d = bcy * (a.x - c.x) + cbx * (a.y - c.y); + float s = bcy * pcx + cbx * pcy; + float t = (c.y - a.y) * pcx + (a.x - c.x) * pcy; + return d < 0 ? s <= 0 && t <= 0 && s + t >= d : s >= 0 && t >= 0 && s + t <= d; + } + + public static double lineToPointDiff2d(Vec3 l1, Vec3 l2, Vec3 p) { + return Math.abs((l2.x - l1.x) * (l1.z - p.z) - (l1.x - p.x) * (l2.z - l1.z)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatBlock.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatBlock.java index 3ebd4be6c8..43df043286 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.seat; import java.util.List; @@ -8,8 +8,10 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.google.common.base.Optional; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; +import com.simibubi.create.AllTags.AllEntityTags; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; @@ -40,6 +42,7 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.EntityCollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; @ParametersAreNonnullByDefault @@ -127,7 +130,9 @@ public class SeatBlock extends Block implements ProperWaterloggedBlock { @Override public VoxelShape getCollisionShape(BlockState p_220071_1_, BlockGetter p_220071_2_, BlockPos p_220071_3_, - CollisionContext p_220071_4_) { + CollisionContext ctx) { + if (ctx instanceof EntityCollisionContext ecc && ecc.getEntity() instanceof Player) + return AllShapes.SEAT_COLLISION_PLAYERS; return AllShapes.SEAT_COLLISION; } @@ -186,6 +191,12 @@ public class SeatBlock extends Block implements ProperWaterloggedBlock { return false; if (passenger instanceof Player) return false; + if (AllEntityTags.IGNORE_SEAT.matches(passenger)) + return false; + if (!AllConfigs.server().logistics.seatHostileMobs.get() && !passenger.getType() + .getCategory() + .isFriendly()) + return false; return passenger instanceof LivingEntity; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatEntity.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatEntity.java index 761a6c30ba..dcc3494589 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.seat; import com.simibubi.create.AllEntityTypes; diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatInteractionBehaviour.java new file mode 100644 index 0000000000..522d0a9b26 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatInteractionBehaviour.java @@ -0,0 +1,32 @@ +package com.simibubi.create.content.contraptions.actors.seat; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; + +public class SeatInteractionBehaviour extends MovingInteractionBehaviour { + + @Override + public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, + AbstractContraptionEntity contraptionEntity) { + return false; + } + + @Override + public void handleEntityCollision(Entity entity, BlockPos localPos, AbstractContraptionEntity contraptionEntity) { + Contraption contraption = contraptionEntity.getContraption(); + int index = contraption.getSeats() + .indexOf(localPos); + if (index == -1) + return; + if (!SeatBlock.canBePickedUp(entity)) + return; + contraptionEntity.addSittingPassenger(entity, index); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatMovementBehaviour.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatMovementBehaviour.java index efaded0fd0..cf61d7c4c4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/seat/SeatMovementBehaviour.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.contraptions.actors.seat; import java.util.Map; import java.util.UUID; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsBlock.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsBlock.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsBlock.java index 9eae0dba5d..e299b3616a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsBlock.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionWorld; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.contraptions.ContraptionWorld; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsHandler.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsHandler.java index f7cc8edcb1..2667c87e27 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsHandler.java @@ -1,15 +1,16 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashSet; import java.util.Vector; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.platform.InputConstants; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.foundation.utility.ControlsUtil; import com.simibubi.create.foundation.utility.CreateLang; @@ -23,10 +24,10 @@ public class ControlsHandler { public static Collection currentlyPressed = new HashSet<>(); public static int PACKET_RATE = 5; - static int packetCooldown; + private static int packetCooldown; - static WeakReference entityRef = new WeakReference<>(null); - static BlockPos controlsPos; + private static WeakReference entityRef = new WeakReference<>(null); + private static BlockPos controlsPos; public static void levelUnloaded(LevelAccessor level) { packetCooldown = 0; @@ -49,7 +50,7 @@ public class ControlsHandler { AbstractContraptionEntity abstractContraptionEntity = entityRef.get(); if (!currentlyPressed.isEmpty() && abstractContraptionEntity != null) - AllPackets.channel.sendToServer(new ControlsInputPacket(currentlyPressed, false, + AllPackets.getChannel().sendToServer(new ControlsInputPacket(currentlyPressed, false, abstractContraptionEntity.getId(), controlsPos, false)); packetCooldown = 0; @@ -73,7 +74,7 @@ public class ControlsHandler { .getWindow(), GLFW.GLFW_KEY_ESCAPE)) { BlockPos pos = controlsPos; stopControlling(); - AllPackets.channel + AllPackets.getChannel() .sendToServer(new ControlsInputPacket(currentlyPressed, false, entity.getId(), pos, true)); return; } @@ -92,14 +93,14 @@ public class ControlsHandler { // Released Keys if (!releasedKeys.isEmpty()) { - AllPackets.channel + AllPackets.getChannel() .sendToServer(new ControlsInputPacket(releasedKeys, false, entity.getId(), controlsPos, false)); // AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .5f, true); } // Newly Pressed Keys if (!newKeys.isEmpty()) { - AllPackets.channel.sendToServer(new ControlsInputPacket(newKeys, true, entity.getId(), controlsPos, false)); + AllPackets.getChannel().sendToServer(new ControlsInputPacket(newKeys, true, entity.getId(), controlsPos, false)); packetCooldown = PACKET_RATE; // AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .75f, true); } @@ -107,7 +108,7 @@ public class ControlsHandler { // Keepalive Pressed Keys if (packetCooldown == 0) { // if (!pressedKeys.isEmpty()) { - AllPackets.channel + AllPackets.getChannel() .sendToServer(new ControlsInputPacket(pressedKeys, true, entity.getId(), controlsPos, false)); packetCooldown = PACKET_RATE; // } @@ -117,4 +118,14 @@ public class ControlsHandler { controls.forEach(kb -> kb.setDown(false)); } + @Nullable + public static AbstractContraptionEntity getContraption() { + return entityRef.get(); + } + + @Nullable + public static BlockPos getControlsPos() { + return controlsPos; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInputPacket.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInputPacket.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInputPacket.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInputPacket.java index e1800777be..4853605364 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInputPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInputPacket.java @@ -1,11 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import java.util.ArrayList; import java.util.Collection; import java.util.UUID; -import java.util.function.Supplier; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.core.BlockPos; @@ -55,10 +54,9 @@ public class ControlsInputPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); Level world = player.getCommandSenderWorld(); UUID uniqueID = player.getUUID(); @@ -77,7 +75,7 @@ public class ControlsInputPacket extends SimplePacketBase { .closerThan(player.position(), 16)) ControlsServerHandler.receivePressed(world, ace, controlsPos, uniqueID, activatedButtons, press); }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInteractionBehaviour.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInteractionBehaviour.java index d64f24d1aa..726eb424a4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsInteractionBehaviour.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import java.util.UUID; import com.google.common.base.Objects; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsMovementBehaviour.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsMovementBehaviour.java index d0dbee40b9..1414de207c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsMovementBehaviour.java @@ -1,19 +1,20 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import java.util.Collection; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; import net.createmod.ponder.utility.WorldTickHolder; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -27,6 +28,11 @@ public class ControlsMovementBehaviour implements MovementBehaviour { LerpedFloat equipAnimation = LerpedFloat.linear(); } + @Override + public ItemStack canBeDisabledVia(MovementContext context) { + return null; + } + @Override public void stopMoving(MovementContext context) { context.contraption.entity.stopControlling(context.localPos); @@ -66,8 +72,8 @@ public class ControlsMovementBehaviour implements MovementBehaviour { inverted = !info.state.getValue(ControlsBlock.FACING) .equals(initialOrientation); - if (ControlsHandler.entityRef.get() == entity && ControlsHandler.controlsPos != null - && ControlsHandler.controlsPos.equals(context.localPos)) { + if (ControlsHandler.getContraption() == entity && ControlsHandler.getControlsPos() != null + && ControlsHandler.getControlsPos().equals(context.localPos)) { Collection pressed = ControlsHandler.currentlyPressed; angles.equipAnimation.chase(1, .2f, Chaser.EXP); angles.steering.chase((pressed.contains(3) ? 1 : 0) + (pressed.contains(2) ? -1 : 0), 0.2f, Chaser.EXP); diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsRenderer.java new file mode 100644 index 0000000000..2edd98f3c4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsRenderer.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.contraptions.actors.trainControls; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class ControlsRenderer { + + public static void render(MovementContext context, VirtualRenderWorld renderWorld, ContraptionMatrices matrices, + MultiBufferSource buffer, float equipAnimation, float firstLever, float secondLever) { + BlockState state = context.state; + Direction facing = state.getValue(ControlsBlock.FACING); + + SuperByteBuffer cover = CachedPartialBuffers.partial(AllPartialModels.TRAIN_CONTROLS_COVER, state); + float hAngle = 180 + AngleHelper.horizontalAngle(facing); + PoseStack ms = matrices.getModel(); + cover.transform(ms) + .centre() + .rotateY(hAngle) + .unCentre() + .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.cutoutMipped())); + + double yOffset = Mth.lerp(equipAnimation * equipAnimation, -0.15f, 0.05f); + + for (boolean first : Iterate.trueAndFalse) { + float vAngle = (float) Mth.clamp(first ? firstLever * 70 - 25 : secondLever * 15, -45, 45); + SuperByteBuffer lever = CachedPartialBuffers.partial(AllPartialModels.TRAIN_CONTROLS_LEVER, state); + ms.pushPose(); + TransformStack.cast(ms) + .centre() + .rotateY(hAngle) + .translate(0, 0, 4 / 16f) + .rotateX(vAngle - 45) + .translate(0, yOffset, 0) + .rotateX(45) + .unCentre() + .translate(0, -2 / 16f, -3 / 16f) + .translate(first ? 0 : 6 / 16f, 0, 0); + lever.transform(ms) + .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); + ms.popPose(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsServerHandler.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsServerHandler.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsServerHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsServerHandler.java index 55e19ffb12..b1cf6fc9ff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsServerHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsServerHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.contraptions.actors.trainControls; import java.util.ArrayList; import java.util.Collection; @@ -8,7 +8,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import net.createmod.catnip.utility.IntAttached; import net.createmod.catnip.utility.WorldAttached; diff --git a/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsStopControllingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsStopControllingPacket.java new file mode 100644 index 0000000000..2434071495 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/actors/trainControls/ControlsStopControllingPacket.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.contraptions.actors.trainControls; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ControlsStopControllingPacket extends SimplePacketBase { + + public ControlsStopControllingPacket() {} + + public ControlsStopControllingPacket(FriendlyByteBuf buffer) {} + + @Override + public void write(FriendlyByteBuf buffer) {} + + @Override + public boolean handle(Context context) { + context.enqueueWork(ControlsHandler::stopControlling); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java deleted file mode 100644 index 8181db7470..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/BackHalfShaftInstance.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.MaterialManager; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class BackHalfShaftInstance extends HalfShaftInstance { - public BackHalfShaftInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Direction getShaftDirection() { - return blockState.getValue(BlockStateProperties.FACING).getOpposite(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/CutoutRotatingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/CutoutRotatingInstance.java deleted file mode 100644 index 3c625fa2a0..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/CutoutRotatingInstance.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.foundation.render.AllMaterialSpecs; - -public class CutoutRotatingInstance extends SingleRotatingInstance { - public CutoutRotatingInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - protected Material getRotatingMaterial() { - return materialManager.defaultCutout() - .material(AllMaterialSpecs.ROTATING); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java deleted file mode 100644 index 8086f7cc0f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import java.util.List; - -import com.simibubi.create.content.contraptions.KineticNetwork; -import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; -import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class GeneratingKineticTileEntity extends KineticTileEntity { - - public boolean reActivateSource; - - public GeneratingKineticTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - protected void notifyStressCapacityChange(float capacity) { - getOrCreateNetwork().updateCapacityFor(this, capacity); - } - - @Override - public void removeSource() { - if (hasSource() && isSource()) - reActivateSource = true; - super.removeSource(); - } - - @Override - public void setSource(BlockPos source) { - super.setSource(source); - BlockEntity tileEntity = level.getBlockEntity(source); - if (!(tileEntity instanceof KineticTileEntity)) - return; - KineticTileEntity sourceTe = (KineticTileEntity) tileEntity; - if (reActivateSource && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed())) - reActivateSource = false; - } - - @Override - public void tick() { - super.tick(); - if (reActivateSource) { - updateGeneratedRotation(); - reActivateSource = false; - } - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - boolean added = super.addToGoggleTooltip(tooltip, isPlayerSneaking); - if (!StressImpact.isEnabled()) - return added; - - float stressBase = calculateAddedStressCapacity(); - if (Mth.equal(stressBase, 0)) - return added; - - CreateLang.translate("gui.goggles.generator_stats") - .forGoggles(tooltip); - CreateLang.translate("tooltip.capacityProvided") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - - float speed = getTheoreticalSpeed(); - if (speed != getGeneratedSpeed() && speed != 0) - stressBase *= getGeneratedSpeed() / speed; - speed = Math.abs(speed); - - float stressTotal = stressBase * speed; - - CreateLang.number(stressTotal) - .translate("generic.unit.stress") - .style(ChatFormatting.AQUA) - .space() - .add(CreateLang.translate("gui.goggles.at_current_speed") - .style(ChatFormatting.DARK_GRAY)) - .forGoggles(tooltip, 1); - - return true; - } - - public void updateGeneratedRotation() { - float speed = getGeneratedSpeed(); - float prevSpeed = this.speed; - - if (level.isClientSide) - return; - - if (prevSpeed != speed) { - if (!hasSource()) { - SpeedLevel levelBefore = SpeedLevel.of(this.speed); - SpeedLevel levelafter = SpeedLevel.of(speed); - if (levelBefore != levelafter) - effects.queueRotationIndicators(); - } - - applyNewSpeed(prevSpeed, speed); - } - - if (hasNetwork() && speed != 0) { - KineticNetwork network = getOrCreateNetwork(); - notifyStressCapacityChange(calculateAddedStressCapacity()); - getOrCreateNetwork().updateStressFor(this, calculateStressApplied()); - network.updateStress(); - } - - onSpeedChanged(prevSpeed); - sendData(); - } - - public void applyNewSpeed(float prevSpeed, float speed) { - - // Speed changed to 0 - if (speed == 0) { - if (hasSource()) { - notifyStressCapacityChange(0); - getOrCreateNetwork().updateStressFor(this, calculateStressApplied()); - return; - } - detachKinetics(); - setSpeed(0); - setNetwork(null); - return; - } - - // Now turning - create a new Network - if (prevSpeed == 0) { - setSpeed(speed); - setNetwork(createNetworkId()); - attachKinetics(); - return; - } - - // Change speed when overpowered by other generator - if (hasSource()) { - - // Staying below Overpowered speed - if (Math.abs(prevSpeed) >= Math.abs(speed)) { - if (Math.signum(prevSpeed) != Math.signum(speed)) - level.destroyBlock(worldPosition, true); - return; - } - - // Faster than attached network -> become the new source - detachKinetics(); - setSpeed(speed); - source = null; - setNetwork(createNetworkId()); - attachKinetics(); - return; - } - - // Reapply source - detachKinetics(); - setSpeed(speed); - attachKinetics(); - } - - public Long createNetworkId() { - return worldPosition.asLong(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java deleted file mode 100644 index 6ddaf3acf9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HalfShaftInstance.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class HalfShaftInstance extends SingleRotatingInstance { - public HalfShaftInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - Direction dir = getShaftDirection(); - return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, dir); - } - - protected Direction getShaftDirection() { - return blockState.getValue(BlockStateProperties.FACING); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java deleted file mode 100644 index 275adabda6..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalHalfShaftInstance.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.MaterialManager; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class HorizontalHalfShaftInstance extends HalfShaftInstance { - - public HorizontalHalfShaftInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Direction getShaftDirection() { - return blockState.getValue(BlockStateProperties.HORIZONTAL_FACING).getOpposite(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlock.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlock.java deleted file mode 100644 index aa54f395b2..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticBlock.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.item.ItemDescription.Palette; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class KineticBlock extends Block implements IRotate { - - protected static final Palette color = Palette.Red; - - public KineticBlock(Properties properties) { - super(properties); - } - - @Override - public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { - // onBlockAdded is useless for init, as sometimes the TE gets re-instantiated - - // however, if a block change occurs that does not change kinetic connections, - // we can prevent a major re-propagation here - - BlockEntity tileEntity = worldIn.getBlockEntity(pos); - if (tileEntity instanceof KineticTileEntity) { - KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity; - kineticTileEntity.preventSpeedUpdate = 0; - - if (oldState.getBlock() != state.getBlock()) - return; - if (state.hasBlockEntity() != oldState.hasBlockEntity()) - return; - if (!areStatesKineticallyEquivalent(oldState, state)) - return; - - kineticTileEntity.preventSpeedUpdate = 2; - } - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return false; - } - - protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { - if (oldState.getBlock() != newState.getBlock()) - return false; - return getRotationAxis(newState) == getRotationAxis(oldState); - } - - @Override - public void updateIndirectNeighbourShapes(BlockState stateIn, LevelAccessor worldIn, BlockPos pos, int flags, - int count) { - if (worldIn.isClientSide()) - return; - - BlockEntity tileEntity = worldIn.getBlockEntity(pos); - if (!(tileEntity instanceof KineticTileEntity)) - return; - KineticTileEntity kte = (KineticTileEntity) tileEntity; - - if (kte.preventSpeedUpdate > 0) - return; - - // Remove previous information when block is added - kte.warnOfMovement(); - kte.clearKineticInformation(); - kte.updateSpeed = true; - } - - @Override - public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { - AdvancementBehaviour.setPlacedBy(worldIn, pos, placer); - if (worldIn.isClientSide) - return; - - BlockEntity tileEntity = worldIn.getBlockEntity(pos); - if (!(tileEntity instanceof KineticTileEntity)) - return; - - KineticTileEntity kte = (KineticTileEntity) tileEntity; - kte.effects.queueRotationIndicators(); - } - - public float getParticleTargetRadius() { - return .65f; - } - - public float getParticleInitialRadius() { - return .75f; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java deleted file mode 100644 index 8c37ae193a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ /dev/null @@ -1,601 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import static net.minecraft.ChatFormatting.GOLD; -import static net.minecraft.ChatFormatting.GRAY; - -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.KineticNetwork; -import com.simibubi.create.content.contraptions.RotationPropagator; -import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; -import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock; -import com.simibubi.create.foundation.block.BlockStressValues; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.sound.SoundScapes; -import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.FontHelper; -import net.minecraft.ChatFormatting; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; - -public class KineticTileEntity extends SmartTileEntity implements IHaveGoggleInformation, IHaveHoveringInformation { - - public @Nullable Long network; - public @Nullable BlockPos source; - public boolean networkDirty; - public boolean updateSpeed; - public int preventSpeedUpdate; - - protected KineticEffectHandler effects; - protected float speed; - protected float capacity; - protected float stress; - protected boolean overStressed; - protected boolean wasMoved; - - private int flickerTally; - private int networkSize; - private int validationCountdown; - protected float lastStressApplied; - protected float lastCapacityProvided; - - public KineticTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - effects = new KineticEffectHandler(this); - updateSpeed = true; - } - - @Override - public void initialize() { - if (hasNetwork() && !level.isClientSide) { - KineticNetwork network = getOrCreateNetwork(); - if (!network.initialized) - network.initFromTE(capacity, stress, networkSize); - network.addSilently(this, lastCapacityProvided, lastStressApplied); - } - - super.initialize(); - } - - @Override - public void tick() { - if (!level.isClientSide && needsSpeedUpdate()) - attachKinetics(); - - super.tick(); - effects.tick(); - - preventSpeedUpdate = 0; - - if (level.isClientSide) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio()); - return; - } - - if (validationCountdown-- <= 0) { - validationCountdown = AllConfigs.SERVER.kinetics.kineticValidationFrequency.get(); - validateKinetics(); - } - - if (getFlickerScore() > 0) - flickerTally = getFlickerScore() - 1; - - if (networkDirty) { - if (hasNetwork()) - getOrCreateNetwork().updateNetwork(); - networkDirty = false; - } - } - - private void validateKinetics() { - if (hasSource()) { - if (!hasNetwork()) { - removeSource(); - return; - } - - if (!level.isLoaded(source)) - return; - - BlockEntity tileEntity = level.getBlockEntity(source); - KineticTileEntity sourceTe = - tileEntity instanceof KineticTileEntity ? (KineticTileEntity) tileEntity : null; - if (sourceTe == null || sourceTe.speed == 0) { - removeSource(); - detachKinetics(); - return; - } - - return; - } - - if (speed != 0) { - if (getGeneratedSpeed() == 0) - speed = 0; - } - } - - public void updateFromNetwork(float maxStress, float currentStress, int networkSize) { - networkDirty = false; - this.capacity = maxStress; - this.stress = currentStress; - this.networkSize = networkSize; - boolean overStressed = maxStress < currentStress && StressImpact.isEnabled(); - setChanged(); - - if (overStressed != this.overStressed) { - float prevSpeed = getSpeed(); - this.overStressed = overStressed; - onSpeedChanged(prevSpeed); - sendData(); - } - } - - protected Block getStressConfigKey() { - return getBlockState().getBlock(); - } - - public float calculateStressApplied() { - float impact = (float) BlockStressValues.getImpact(getStressConfigKey()); - this.lastStressApplied = impact; - return impact; - } - - public float calculateAddedStressCapacity() { - float capacity = (float) BlockStressValues.getCapacity(getStressConfigKey()); - this.lastCapacityProvided = capacity; - return capacity; - } - - public void onSpeedChanged(float previousSpeed) { - boolean fromOrToZero = (previousSpeed == 0) != (getSpeed() == 0); - boolean directionSwap = !fromOrToZero && Math.signum(previousSpeed) != Math.signum(getSpeed()); - if (fromOrToZero || directionSwap) - flickerTally = getFlickerScore() + 5; - setChanged(); - } - - @Override - public void setRemoved() { - super.setRemoved(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - if (!level.isClientSide) { - if (hasNetwork()) - getOrCreateNetwork().remove(this); - detachKinetics(); - } - super.setRemovedNotDueToChunkUnload(); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - compound.putFloat("Speed", speed); - - if (needsSpeedUpdate()) - compound.putBoolean("NeedsSpeedUpdate", true); - - if (hasSource()) - compound.put("Source", NbtUtils.writeBlockPos(source)); - - if (hasNetwork()) { - CompoundTag networkTag = new CompoundTag(); - networkTag.putLong("Id", this.network); - networkTag.putFloat("Stress", stress); - networkTag.putFloat("Capacity", capacity); - networkTag.putInt("Size", networkSize); - - if (lastStressApplied != 0) - networkTag.putFloat("AddedStress", lastStressApplied); - if (lastCapacityProvided != 0) - networkTag.putFloat("AddedCapacity", lastCapacityProvided); - - compound.put("Network", networkTag); - } - - super.write(compound, clientPacket); - } - - public boolean needsSpeedUpdate() { - return updateSpeed; - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - boolean overStressedBefore = overStressed; - clearKineticInformation(); - - // DO NOT READ kinetic information when placed after movement - if (wasMoved) { - super.read(compound, clientPacket); - return; - } - - speed = compound.getFloat("Speed"); - - if (compound.contains("Source")) - source = NbtUtils.readBlockPos(compound.getCompound("Source")); - - if (compound.contains("Network")) { - CompoundTag networkTag = compound.getCompound("Network"); - network = networkTag.getLong("Id"); - stress = networkTag.getFloat("Stress"); - capacity = networkTag.getFloat("Capacity"); - networkSize = networkTag.getInt("Size"); - lastStressApplied = networkTag.getFloat("AddedStress"); - lastCapacityProvided = networkTag.getFloat("AddedCapacity"); - overStressed = capacity < stress && StressImpact.isEnabled(); - } - - super.read(compound, clientPacket); - - if (clientPacket && overStressedBefore != overStressed && speed != 0) - effects.triggerOverStressedEffect(); - - if (clientPacket) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - } - - public float getGeneratedSpeed() { - return 0; - } - - public boolean isSource() { - return getGeneratedSpeed() != 0; - } - - public float getSpeed() { - if (overStressed) - return 0; - return getTheoreticalSpeed(); - } - - public float getTheoreticalSpeed() { - return speed; - } - - public void setSpeed(float speed) { - this.speed = speed; - } - - public boolean hasSource() { - return source != null; - } - - public void setSource(BlockPos source) { - this.source = source; - if (level == null || level.isClientSide) - return; - - BlockEntity tileEntity = level.getBlockEntity(source); - if (!(tileEntity instanceof KineticTileEntity)) { - removeSource(); - return; - } - - KineticTileEntity sourceTe = (KineticTileEntity) tileEntity; - setNetwork(sourceTe.network); - } - - public void removeSource() { - float prevSpeed = getSpeed(); - - speed = 0; - source = null; - setNetwork(null); - - onSpeedChanged(prevSpeed); - } - - public void setNetwork(@Nullable Long networkIn) { - if (network == networkIn) - return; - if (network != null) - getOrCreateNetwork().remove(this); - - network = networkIn; - setChanged(); - - if (networkIn == null) - return; - - network = networkIn; - KineticNetwork network = getOrCreateNetwork(); - network.initialized = true; - network.add(this); - } - - public KineticNetwork getOrCreateNetwork() { - return Create.TORQUE_PROPAGATOR.getOrCreateNetworkFor(this); - } - - public boolean hasNetwork() { - return network != null; - } - - public void attachKinetics() { - updateSpeed = false; - RotationPropagator.handleAdded(level, worldPosition, this); - } - - public void detachKinetics() { - RotationPropagator.handleRemoved(level, worldPosition, this); - } - - public boolean isSpeedRequirementFulfilled() { - BlockState state = getBlockState(); - if (!(getBlockState().getBlock() instanceof IRotate)) - return true; - IRotate def = (IRotate) state.getBlock(); - SpeedLevel minimumRequiredSpeedLevel = def.getMinimumRequiredSpeedLevel(); - return Math.abs(getSpeed()) >= minimumRequiredSpeedLevel.getSpeedValue(); - } - - public static void switchToBlockState(Level world, BlockPos pos, BlockState state) { - if (world.isClientSide) - return; - - BlockEntity tileEntityIn = world.getBlockEntity(pos); - BlockState currentState = world.getBlockState(pos); - boolean isKinetic = tileEntityIn instanceof KineticTileEntity; - - if (currentState == state) - return; - if (tileEntityIn == null || !isKinetic) { - world.setBlock(pos, state, 3); - return; - } - - KineticTileEntity tileEntity = (KineticTileEntity) tileEntityIn; - if (state.getBlock() instanceof KineticBlock - && !((KineticBlock) state.getBlock()).areStatesKineticallyEquivalent(currentState, state)) { - if (tileEntity.hasNetwork()) - tileEntity.getOrCreateNetwork() - .remove(tileEntity); - tileEntity.detachKinetics(); - tileEntity.removeSource(); - } - - world.setBlock(pos, state, 3); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { - boolean notFastEnough = !isSpeedRequirementFulfilled() && getSpeed() != 0; - - if (overStressed && AllConfigs.CLIENT.enableOverstressedTooltip.get()) { - CreateLang.translate("gui.stressometer.overstressed") - .style(GOLD) - .forGoggles(tooltip); - Component hint = CreateLang.translateDirect("gui.contraptions.network_overstressed"); - List cutString = TooltipHelper.cutTextComponent(hint, GRAY, ChatFormatting.WHITE); - for (int i = 0; i < cutString.size(); i++) - Create.lang() - .add(cutString.get(i) - .copy()) - .forGoggles(tooltip); - return true; - } - - if (notFastEnough) { - CreateLang.translate("tooltip.speedRequirement") - .style(GOLD) - .forGoggles(tooltip); - MutableComponent hint = - CreateLang.translateDirect("gui.contraptions.not_fast_enough", I18n.get(getBlockState().getBlock() - .getDescriptionId())); - List cutString = FontHelper.cutTextComponent(hint, GRAY, ChatFormatting.WHITE); - for (int i = 0; i < cutString.size(); i++) - Create.lang() - .add(cutString.get(i) - .copy()) - .forGoggles(tooltip); - return true; - } - - return false; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - boolean added = false; - - if (!StressImpact.isEnabled()) - return added; - float stressAtBase = calculateStressApplied(); - if (Mth.equal(stressAtBase, 0)) - return added; - - CreateLang.translate("gui.goggles.kinetic_stats") - .forGoggles(tooltip); - - addStressImpactStats(tooltip, stressAtBase); - - return true; - - } - - protected void addStressImpactStats(List tooltip, float stressAtBase) { - CreateLang.translate("tooltip.stressImpact") - .style(GRAY) - .forGoggles(tooltip); - - float stressTotal = stressAtBase * Math.abs(getTheoreticalSpeed()); - - CreateLang.number(stressTotal) - .translate("generic.unit.stress") - .style(ChatFormatting.AQUA) - .space() - .add(CreateLang.translate("gui.goggles.at_current_speed") - .style(ChatFormatting.DARK_GRAY)) - .forGoggles(tooltip, 1); - } - - public void clearKineticInformation() { - speed = 0; - source = null; - network = null; - overStressed = false; - stress = 0; - capacity = 0; - lastStressApplied = 0; - lastCapacityProvided = 0; - } - - public void warnOfMovement() { - wasMoved = true; - } - - public int getFlickerScore() { - return flickerTally; - } - - public static float convertToDirection(float axisSpeed, Direction d) { - return d.getAxisDirection() == AxisDirection.POSITIVE ? axisSpeed : -axisSpeed; - } - - public static float convertToLinear(float speed) { - return speed / 512f; - } - - public static float convertToAngular(float speed) { - return speed * 3 / 10f; - } - - public boolean isOverStressed() { - return overStressed; - } - - // Custom Propagation - - /** - * Specify ratio of transferred rotation from this kinetic component to a - * specific other. - * - * @param target other Kinetic TE to transfer to - * @param stateFrom this TE's blockstate - * @param stateTo other TE's blockstate - * @param diff difference in position (to.pos - from.pos) - * @param connectedViaAxes whether these kinetic blocks are connected via mutual - * IRotate.hasShaftTowards() - * @param connectedViaCogs whether these kinetic blocks are connected via mutual - * IRotate.hasIntegratedCogwheel() - * @return factor of rotation speed from this TE to other. 0 if no rotation is - * transferred, or the standard rules apply (integrated shafts/cogs) - */ - public float propagateRotationTo(KineticTileEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, - boolean connectedViaAxes, boolean connectedViaCogs) { - return 0; - } - - /** - * Specify additional locations the rotation propagator should look for - * potentially connected components. Neighbour list contains offset positions in - * all 6 directions by default. - * - * @param block - * @param state - * @param neighbours - * @return - */ - public List addPropagationLocations(IRotate block, BlockState state, List neighbours) { - if (!canPropagateDiagonally(block, state)) - return neighbours; - - Axis axis = block.getRotationAxis(state); - BlockPos.betweenClosedStream(new BlockPos(-1, -1, -1), new BlockPos(1, 1, 1)) - .forEach(offset -> { - if (axis.choose(offset.getX(), offset.getY(), offset.getZ()) != 0) - return; - if (offset.distSqr(BlockPos.ZERO) != 2) - return; - neighbours.add(worldPosition.offset(offset)); - }); - return neighbours; - } - - /** - * Specify whether this component can propagate speed to the other in any - * circumstance. Shaft and cogwheel connections are already handled by internal - * logic. Does not have to be specified on both ends, it is assumed that this - * relation is symmetrical. - * - * @param other - * @param state - * @param otherState - * @return true if this and the other component should check their propagation - * factor and are not already connected via integrated cogs or shafts - */ - public boolean isCustomConnection(KineticTileEntity other, BlockState state, BlockState otherState) { - return false; - } - - protected boolean canPropagateDiagonally(IRotate block, BlockState state) { - return ICogWheel.isSmallCog(state); - } - - @Override - public void requestModelDataUpdate() { - super.requestModelDataUpdate(); - if (!this.remove) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - } - - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - float componentSpeed = Math.abs(getSpeed()); - if (componentSpeed == 0) - return; - float pitch = Mth.clamp((componentSpeed / 256f) + .45f, .85f, 1f); - - if (isNoisy()) - SoundScapes.play(AmbienceGroup.KINETIC, worldPosition, pitch); - - Block block = getBlockState().getBlock(); - if (ICogWheel.isSmallCog(block) || ICogWheel.isLargeCog(block) || block instanceof GearboxBlock) - SoundScapes.play(AmbienceGroup.COG, worldPosition, pitch); - } - - protected boolean isNoisy() { - return true; - } - - public int getRotationAngleOffset(Axis axis) { - return 0; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java deleted file mode 100644 index 82b52ccf95..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntityRenderer.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import org.apache.commons.lang3.ArrayUtils; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.render.SuperByteBufferCache; -import net.createmod.catnip.utility.theme.Color; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class KineticTileEntityRenderer extends SafeTileEntityRenderer { - - public static final SuperByteBufferCache.Compartment KINETIC_TILE = new SuperByteBufferCache.Compartment<>(); - public static boolean rainbowMode = false; - - protected static final RenderType[] REVERSED_CHUNK_BUFFER_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); - static { - ArrayUtils.reverse(REVERSED_CHUNK_BUFFER_LAYERS); - } - - public KineticTileEntityRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState state = getRenderedBlockState(te); - RenderType type = getRenderType(te, state); - if (type != null) - renderRotatingBuffer(te, getRotatedModel(te, state), ms, buffer.getBuffer(type), light); - } - - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return te.getBlockState(); - } - - protected RenderType getRenderType(KineticTileEntity te, BlockState state) { - for (RenderType type : REVERSED_CHUNK_BUFFER_LAYERS) - if (ItemBlockRenderTypes.canRenderInLayer(state, type)) - return type; - return null; - } - - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedBlockBuffers.block(KINETIC_TILE, state); - } - - public static void renderRotatingKineticBlock(KineticTileEntity te, BlockState renderedState, PoseStack ms, - VertexConsumer buffer, int light) { - SuperByteBuffer superByteBuffer = CachedBlockBuffers.block(KINETIC_TILE, renderedState); - renderRotatingBuffer(te, superByteBuffer, ms, buffer, light); - } - - public static void renderRotatingBuffer(KineticTileEntity te, SuperByteBuffer superBuffer, PoseStack ms, - VertexConsumer buffer, int light) { - standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, buffer); - } - - public static float getAngleForTe(KineticTileEntity te, final BlockPos pos, Axis axis) { - float time = WorldTickHolder.getRenderTime(te.getLevel()); - float offset = getRotationOffsetForPosition(te, pos, axis); - float angle = ((time * te.getSpeed() * 3f / 10 + offset) % 360) / 180 * (float) Math.PI; - return angle; - } - - public static SuperByteBuffer standardKineticRotationTransform(SuperByteBuffer buffer, KineticTileEntity te, - int light) { - final BlockPos pos = te.getBlockPos(); - Axis axis = ((IRotate) te.getBlockState() - .getBlock()).getRotationAxis(te.getBlockState()); - return kineticRotationTransform(buffer, te, axis, getAngleForTe(te, pos, axis), light); - } - - public static SuperByteBuffer kineticRotationTransform(SuperByteBuffer buffer, KineticTileEntity te, Axis axis, - float angle, int light) { - buffer.light(light); - buffer.rotateCentered(Direction.get(AxisDirection.POSITIVE, axis), angle); - - if (KineticDebugger.isActive()) { - rainbowMode = true; - buffer.color(te.hasNetwork() ? Color.generateFromLong(te.network) : Color.WHITE); - } else { - float overStressedEffect = te.effects.overStressedEffect; - if (overStressedEffect != 0) - if (overStressedEffect > 0) - buffer.color(Color.WHITE.mixWith(Color.RED, overStressedEffect)); - else - buffer.color(Color.WHITE.mixWith(Color.SPRING_GREEN, -overStressedEffect)); - else - buffer.color(Color.WHITE); - } - - return buffer; - } - - public static float getRotationOffsetForPosition(KineticTileEntity te, final BlockPos pos, final Axis axis) { - float offset = ICogWheel.isLargeCog(te.getBlockState()) ? 11.25f : 0; - double d = (((axis == Axis.X) ? 0 : pos.getX()) + ((axis == Axis.Y) ? 0 : pos.getY()) - + ((axis == Axis.Z) ? 0 : pos.getZ())) % 2; - if (d == 0) - offset = 22.5f; - return offset + te.getRotationAngleOffset(axis); - } - - public static BlockState shaft(Axis axis) { - return AllBlocks.SHAFT.getDefaultState() - .setValue(BlockStateProperties.AXIS, axis); - } - - public static Axis getRotationAxisOf(KineticTileEntity te) { - return ((IRotate) te.getBlockState() - .getBlock()).getRotationAxis(te.getBlockState()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileInstance.java deleted file mode 100644 index bcaf4e4360..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileInstance.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.foundation.render.AllMaterialSpecs; - -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class KineticTileInstance extends BlockEntityInstance { - - protected final Direction.Axis axis; - - public KineticTileInstance(MaterialManager modelManager, T tile) { - super(modelManager, tile); - axis = (blockState.getBlock()instanceof IRotate irotate) ? irotate.getRotationAxis(blockState) : Axis.Y; - } - - protected final void updateRotation(RotatingData instance) { - updateRotation(instance, getRotationAxis(), getTileSpeed()); - } - - protected final void updateRotation(RotatingData instance, Direction.Axis axis) { - updateRotation(instance, axis, getTileSpeed()); - } - - protected final void updateRotation(RotatingData instance, float speed) { - updateRotation(instance, getRotationAxis(), speed); - } - - protected final void updateRotation(RotatingData instance, Direction.Axis axis, float speed) { - instance.setRotationAxis(axis) - .setRotationOffset(getRotationOffset(axis)) - .setRotationalSpeed(speed) - .setColor(blockEntity); - } - - protected final RotatingData setup(RotatingData key) { - return setup(key, getRotationAxis(), getTileSpeed()); - } - - protected final RotatingData setup(RotatingData key, Direction.Axis axis) { - return setup(key, axis, getTileSpeed()); - } - - protected final RotatingData setup(RotatingData key, float speed) { - return setup(key, getRotationAxis(), speed); - } - - protected final RotatingData setup(RotatingData key, Direction.Axis axis, float speed) { - key.setRotationAxis(axis) - .setRotationalSpeed(speed) - .setRotationOffset(getRotationOffset(axis)) - .setColor(blockEntity) - .setPosition(getInstancePosition()); - - return key; - } - - protected float getRotationOffset(final Direction.Axis axis) { - float offset = ICogWheel.isLargeCog(blockState) ? 11.25f : 0; - double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY()) - + ((axis == Direction.Axis.Z) ? 0 : pos.getZ())) % 2; - if (d == 0) { - offset = 22.5f; - } - return offset; - } - - protected Direction.Axis getRotationAxis() { - return axis; - } - - protected float getTileSpeed() { - return blockEntity.getSpeed(); - } - - protected BlockState shaft() { - return shaft(getRotationAxis()); - } - - protected Material getRotatingMaterial() { - return materialManager.defaultSolid() - .material(AllMaterialSpecs.ROTATING); - } - - public static BlockState shaft(Direction.Axis axis) { - return AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, axis); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java deleted file mode 100644 index d103b26b55..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/SingleRotatingInstance.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.simibubi.create.content.contraptions.base; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.world.level.block.state.BlockState; - -public class SingleRotatingInstance extends KineticTileInstance { - - protected RotatingData rotatingModel; - - public SingleRotatingInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - public void init() { - rotatingModel = setup(getModel().createInstance()); - } - - @Override - public void update() { - updateRotation(rotatingModel); - } - - @Override - public void updateLight() { - relight(pos, rotatingModel); - } - - @Override - public void remove() { - rotatingModel.delete(); - } - - protected BlockState getRenderedBlockState() { - return blockState; - } - - protected Instancer getModel() { - return getRotatingMaterial().getModel(getRenderedBlockState()); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/package-info.java deleted file mode 100644 index 5eed859463..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.simibubi.create.content.contraptions.base.flwdata; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/AnchoredLighter.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/AnchoredLighter.java new file mode 100644 index 0000000000..43788e2239 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/AnchoredLighter.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.jozufozu.flywheel.util.box.GridAlignedBB; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; + +public class AnchoredLighter extends ContraptionLighter { + + public AnchoredLighter(Contraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bb = GridAlignedBB.from(contraption.bounds); + bb.translate(contraption.anchor); + return bb; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingBlock.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/BearingBlock.java index 2f1c210e54..8f52312b78 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingBlock.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -36,9 +36,9 @@ public abstract class BearingBlock extends DirectionalKineticBlock { public InteractionResult onWrenched(BlockState state, UseOnContext context) { InteractionResult resultType = super.onWrenched(state, context); if (!context.getLevel().isClientSide && resultType.consumesAction()) { - BlockEntity te = context.getLevel().getBlockEntity(context.getClickedPos()); - if (te instanceof MechanicalBearingTileEntity) { - ((MechanicalBearingTileEntity) te).disassemble(); + BlockEntity be = context.getLevel().getBlockEntity(context.getClickedPos()); + if (be instanceof MechanicalBearingBlockEntity) { + ((MechanicalBearingBlockEntity) be).disassemble(); } } return resultType; diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingContraption.java new file mode 100644 index 0000000000..2b36c58085 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingContraption.java @@ -0,0 +1,112 @@ +package com.simibubi.create.content.contraptions.bearing; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.decoration.copycat.CopycatBlockEntity; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class BearingContraption extends Contraption { + + protected int sailBlocks; + protected Direction facing; + + private boolean isWindmill; + + public BearingContraption() {} + + public BearingContraption(boolean isWindmill, Direction facing) { + this.isWindmill = isWindmill; + this.facing = facing; + } + + @Override + public boolean assemble(Level world, BlockPos pos) throws AssemblyException { + BlockPos offset = pos.relative(facing); + if (!searchMovedStructure(world, offset, null)) + return false; + startMoving(world); + expandBoundsAroundAxis(facing.getAxis()); + if (isWindmill && sailBlocks < AllConfigs.server().kinetics.minimumWindmillSails.get()) + throw AssemblyException.notEnoughSails(sailBlocks); + if (blocks.isEmpty()) + return false; + return true; + } + + @Override + public ContraptionType getType() { + return ContraptionType.BEARING; + } + + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pos.equals(anchor.relative(facing.getOpposite())); + } + + @Override + public void addBlock(BlockPos pos, Pair capture) { + BlockPos localPos = pos.subtract(anchor); + if (!getBlocks().containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(getSailBlock(capture))) + sailBlocks++; + super.addBlock(pos, capture); + } + + private BlockState getSailBlock(Pair capture) { + BlockState state = capture.getKey().state; + if (AllBlocks.COPYCAT_PANEL.has(state) && capture.getRight() instanceof CopycatBlockEntity cbe) + return cbe.getMaterial(); + return state; + } + + @Override + public CompoundTag writeNBT(boolean spawnPacket) { + CompoundTag tag = super.writeNBT(spawnPacket); + tag.putInt("Sails", sailBlocks); + tag.putInt("Facing", facing.get3DDataValue()); + return tag; + } + + @Override + public void readNBT(Level world, CompoundTag tag, boolean spawnData) { + sailBlocks = tag.getInt("Sails"); + facing = Direction.from3DDataValue(tag.getInt("Facing")); + super.readNBT(world, tag, spawnData); + } + + public int getSailBlocks() { + return sailBlocks; + } + + public Direction getFacing() { + return facing; + } + + @Override + public boolean canBeStabilized(Direction facing, BlockPos localPos) { + if (facing.getOpposite() == this.facing && BlockPos.ZERO.equals(localPos)) + return false; + return facing.getAxis() == this.facing.getAxis(); + } + + @OnlyIn(Dist.CLIENT) + @Override + public ContraptionLighter makeLighter() { + return new AnchoredLighter(this); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingInstance.java new file mode 100644 index 0000000000..03a9671ea7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingInstance.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.BackHalfShaftInstance; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class BearingInstance extends BackHalfShaftInstance implements DynamicInstance { + final OrientedData topInstance; + + final Vector3f rotationAxis; + final Quaternion blockOrientation; + + public BearingInstance(MaterialManager materialManager, B blockEntity) { + super(materialManager, blockEntity); + + Direction facing = blockState.getValue(BlockStateProperties.FACING); + rotationAxis = Direction.get(Direction.AxisDirection.POSITIVE, axis).step(); + + blockOrientation = getBlockStateOrientation(facing); + + PartialModel top = + blockEntity.isWoodenTop() ? AllPartialModels.BEARING_TOP_WOODEN : AllPartialModels.BEARING_TOP; + + topInstance = getOrientedMaterial().getModel(top, blockState).createInstance(); + + topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation); + } + + @Override + public void beginFrame() { + + float interpolatedAngle = blockEntity.getInterpolatedAngle(AnimationTickHolder.getPartialTicks() - 1); + Quaternion rot = rotationAxis.rotationDegrees(interpolatedAngle); + + rot.mul(blockOrientation); + + topInstance.setRotation(rot); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, topInstance); + } + + @Override + public void remove() { + super.remove(); + topInstance.delete(); + } + + static Quaternion getBlockStateOrientation(Direction facing) { + Quaternion orientation; + + if (facing.getAxis().isHorizontal()) { + orientation = Vector3f.YP.rotationDegrees(AngleHelper.horizontalAngle(facing.getOpposite())); + } else { + orientation = Quaternion.ONE.copy(); + } + + orientation.mul(Vector3f.XP.rotationDegrees(-90 - AngleHelper.verticalAngle(facing))); + return orientation; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingRenderer.java new file mode 100644 index 0000000000..c18a429350 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/BearingRenderer.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class BearingRenderer extends KineticBlockEntityRenderer { + + public BearingRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + final Direction facing = be.getBlockState() + .getValue(BlockStateProperties.FACING); + PartialModel top = + be.isWoodenTop() ? AllPartialModels.BEARING_TOP_WOODEN : AllPartialModels.BEARING_TOP; + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(top, be.getBlockState()); + + float interpolatedAngle = be.getInterpolatedAngle(partialTicks - 1); + kineticRotationTransform(superBuffer, be, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI), light); + + if (facing.getAxis() + .isHorizontal()) + superBuffer.rotateCentered(Direction.UP, + AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite()))); + superBuffer.rotateCentered(Direction.EAST, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing))); + superBuffer.renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + + @Override + protected SuperByteBuffer getRotatedModel(KineticBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, state, state + .getValue(BearingBlock.FACING) + .getOpposite()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BlankSailBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/BlankSailBlockItem.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BlankSailBlockItem.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/BlankSailBlockItem.java index 49f8ad8e7d..b8ef959e9d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BlankSailBlockItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/BlankSailBlockItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; import java.util.Map; diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlock.java new file mode 100644 index 0000000000..f04c93965f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlock.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class ClockworkBearingBlock extends BearingBlock implements IBE { + + public ClockworkBearingBlock(Properties properties) { + super(properties); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, + Player player, InteractionHand handIn, BlockHitResult hit) { + if (!player.mayBuild()) + return InteractionResult.FAIL; + if (player.isShiftKeyDown()) + return InteractionResult.FAIL; + if (player.getItemInHand(handIn).isEmpty()) { + if (!worldIn.isClientSide) { + withBlockEntityDo(worldIn, pos, be -> { + if (be.running) { + be.disassemble(); + return; + } + be.assembleNextTick = true; + }); + } + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + public Class getBlockEntityClass() { + return ClockworkBearingBlockEntity.class; + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + InteractionResult resultType = super.onWrenched(state, context); + if (!context.getLevel().isClientSide && resultType.consumesAction()) + withBlockEntityDo(context.getLevel(), context.getClickedPos(), ClockworkBearingBlockEntity::disassemble); + return resultType; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CLOCKWORK_BEARING.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlockEntity.java new file mode 100644 index 0000000000..1f2c3a0b38 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkBearingBlockEntity.java @@ -0,0 +1,432 @@ +package com.simibubi.create.content.contraptions.bearing; + +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.contraptions.bearing.ClockworkContraption.HandType; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.createmod.catnip.utility.lang.Lang; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class ClockworkBearingBlockEntity extends KineticBlockEntity + implements IBearingBlockEntity, IDisplayAssemblyExceptions { + + protected ControlledContraptionEntity hourHand; + protected ControlledContraptionEntity minuteHand; + protected float hourAngle; + protected float minuteAngle; + protected float clientHourAngleDiff; + protected float clientMinuteAngleDiff; + + protected boolean running; + protected boolean assembleNextTick; + protected AssemblyException lastException; + protected ScrollOptionBehaviour operationMode; + + private float prevForcedAngle; + + public ClockworkBearingBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(3); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + operationMode = new ScrollOptionBehaviour<>(ClockHands.class, + CreateLang.translateDirect("contraptions.clockwork.clock_hands"), this, getMovementModeSlot()); + behaviours.add(operationMode); + registerAwardables(behaviours, AllAdvancements.CLOCKWORK_BEARING); + } + + @Override + public boolean isWoodenTop() { + return false; + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) { + prevForcedAngle = hourAngle; + clientMinuteAngleDiff /= 2; + clientHourAngleDiff /= 2; + } + + if (!level.isClientSide && assembleNextTick) { + assembleNextTick = false; + if (running) { + boolean canDisassemble = true; + if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption() + .getBlocks() + .isEmpty())) { + if (hourHand != null) + hourHand.getContraption() + .stop(level); + if (minuteHand != null) + minuteHand.getContraption() + .stop(level); + disassemble(); + } + return; + } else + assemble(); + return; + } + + if (!running) + return; + + if (!(hourHand != null && hourHand.isStalled())) { + float newAngle = hourAngle + getHourArmSpeed(); + hourAngle = (float) (newAngle % 360); + } + + if (!(minuteHand != null && minuteHand.isStalled())) { + float newAngle = minuteAngle + getMinuteArmSpeed(); + minuteAngle = (float) (newAngle % 360); + } + + applyRotations(); + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + + protected void applyRotations() { + BlockState blockState = getBlockState(); + Axis axis = Axis.X; + + if (blockState.hasProperty(BlockStateProperties.FACING)) + axis = blockState.getValue(BlockStateProperties.FACING) + .getAxis(); + + if (hourHand != null) { + hourHand.setAngle(hourAngle); + hourHand.setRotationAxis(axis); + } + if (minuteHand != null) { + minuteHand.setAngle(minuteAngle); + minuteHand.setRotationAxis(axis); + } + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (hourHand != null && !level.isClientSide) + sendData(); + } + + public float getHourArmSpeed() { + float speed = getAngularSpeed() / 2f; + + if (speed != 0) { + ClockHands mode = ClockHands.values()[operationMode.getValue()]; + float hourTarget = mode == ClockHands.HOUR_FIRST ? getHourTarget(false) + : mode == ClockHands.MINUTE_FIRST ? getMinuteTarget() : getHourTarget(true); + float shortestAngleDiff = AngleHelper.getShortestAngleDiff(hourAngle, hourTarget); + if (shortestAngleDiff < 0) { + speed = Math.max(speed, shortestAngleDiff); + } else { + speed = Math.min(-speed, shortestAngleDiff); + } + } + + return speed + clientHourAngleDiff / 3f; + } + + public float getMinuteArmSpeed() { + float speed = getAngularSpeed(); + + if (speed != 0) { + ClockHands mode = ClockHands.values()[operationMode.getValue()]; + float minuteTarget = mode == ClockHands.MINUTE_FIRST ? getHourTarget(false) : getMinuteTarget(); + float shortestAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngle, minuteTarget); + if (shortestAngleDiff < 0) { + speed = Math.max(speed, shortestAngleDiff); + } else { + speed = Math.min(-speed, shortestAngleDiff); + } + } + + return speed + clientMinuteAngleDiff / 3f; + } + + protected float getHourTarget(boolean cycle24) { + boolean isNatural = level.dimensionType() + .natural(); + int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); + int hours = (dayTime / 1000 + 6) % 24; + int offset = getBlockState().getValue(ClockworkBearingBlock.FACING) + .getAxisDirection() + .getStep(); + float hourTarget = (float) (offset * -360 / (cycle24 ? 24f : 12f) * (hours % (cycle24 ? 24 : 12))); + return hourTarget; + } + + protected float getMinuteTarget() { + boolean isNatural = level.dimensionType() + .natural(); + int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); + int minutes = (dayTime % 1000) * 60 / 1000; + int offset = getBlockState().getValue(ClockworkBearingBlock.FACING) + .getAxisDirection() + .getStep(); + float minuteTarget = (float) (offset * -360 / 60f * (minutes)); + return minuteTarget; + } + + public float getAngularSpeed() { + float speed = -Math.abs(getSpeed() * 3 / 10f); + if (level.isClientSide) + speed *= ServerSpeedProvider.get(); + return speed; + } + + public void assemble() { + if (!(level.getBlockState(worldPosition) + .getBlock() instanceof ClockworkBearingBlock)) + return; + + Direction direction = getBlockState().getValue(BlockStateProperties.FACING); + + // Collect Construct + Pair contraption; + try { + contraption = ClockworkContraption.assembleClockworkAt(level, worldPosition, direction); + lastException = null; + } catch (AssemblyException e) { + lastException = e; + sendData(); + return; + } + if (contraption == null) + return; + if (contraption.getLeft() == null) + return; + if (contraption.getLeft() + .getBlocks() + .isEmpty()) + return; + BlockPos anchor = worldPosition.relative(direction); + + contraption.getLeft() + .removeBlocksFromWorld(level, BlockPos.ZERO); + hourHand = ControlledContraptionEntity.create(level, this, contraption.getLeft()); + hourHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + hourHand.setRotationAxis(direction.getAxis()); + level.addFreshEntity(hourHand); + + if (contraption.getLeft() + .containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + + if (contraption.getRight() != null) { + anchor = worldPosition.relative(direction, contraption.getRight().offset + 1); + contraption.getRight() + .removeBlocksFromWorld(level, BlockPos.ZERO); + minuteHand = ControlledContraptionEntity.create(level, this, contraption.getRight()); + minuteHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + minuteHand.setRotationAxis(direction.getAxis()); + level.addFreshEntity(minuteHand); + + if (contraption.getRight() + .containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + } + + award(AllAdvancements.CLOCKWORK_BEARING); + + // Run + running = true; + hourAngle = 0; + minuteAngle = 0; + sendData(); + } + + public void disassemble() { + if (!running && hourHand == null && minuteHand == null) + return; + + hourAngle = 0; + minuteAngle = 0; + applyRotations(); + + if (hourHand != null) { + hourHand.disassemble(); + } + if (minuteHand != null) + minuteHand.disassemble(); + + hourHand = null; + minuteHand = null; + running = false; + sendData(); + } + + @Override + public void attach(ControlledContraptionEntity contraption) { + if (!(contraption.getContraption() instanceof ClockworkContraption)) + return; + + ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); + setChanged(); + Direction facing = getBlockState().getValue(BlockStateProperties.FACING); + BlockPos anchor = worldPosition.relative(facing, cc.offset + 1); + if (cc.handType == HandType.HOUR) { + this.hourHand = contraption; + hourHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + } else { + this.minuteHand = contraption; + minuteHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + } + if (!level.isClientSide) { + this.running = true; + sendData(); + } + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putFloat("HourAngle", hourAngle); + compound.putFloat("MinuteAngle", minuteAngle); + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + float hourAngleBefore = hourAngle; + float minuteAngleBefore = minuteAngle; + + running = compound.getBoolean("Running"); + hourAngle = compound.getFloat("HourAngle"); + minuteAngle = compound.getFloat("MinuteAngle"); + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + + if (running) { + clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle); + clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle); + hourAngle = hourAngleBefore; + minuteAngle = minuteAngleBefore; + } else { + hourHand = null; + minuteHand = null; + } + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + assembleNextTick = true; + } + + @Override + public boolean isValid() { + return !isRemoved(); + } + + @Override + public float getInterpolatedAngle(float partialTicks) { + if (isVirtual()) + return Mth.lerp(partialTicks, prevForcedAngle, hourAngle); + if (hourHand == null || hourHand.isStalled()) + partialTicks = 0; + return Mth.lerp(partialTicks, hourAngle, hourAngle + getHourArmSpeed()); + } + + @Override + public void onStall() { + if (!level.isClientSide) + sendData(); + } + + @Override + public void remove() { + if (!level.isClientSide) + disassemble(); + super.remove(); + } + + @Override + public boolean isAttachedTo(AbstractContraptionEntity contraption) { + if (!(contraption.getContraption() instanceof ClockworkContraption)) + return false; + ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); + if (cc.handType == HandType.HOUR) + return this.hourHand == contraption; + else + return this.minuteHand == contraption; + } + + public boolean isRunning() { + return running; + } + + static enum ClockHands implements INamedIconOptions { + + HOUR_FIRST(AllIcons.I_HOUR_HAND_FIRST), + MINUTE_FIRST(AllIcons.I_MINUTE_HAND_FIRST), + HOUR_FIRST_24(AllIcons.I_HOUR_HAND_FIRST_24), + + ; + + private String translationKey; + private AllIcons icon; + + private ClockHands(AllIcons icon) { + this.icon = icon; + translationKey = "contraptions.clockwork." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + + } + + @Override + public BlockPos getBlockPosition() { + return worldPosition; + } + + public void setAngle(float forcedAngle) { + hourAngle = forcedAngle; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkContraption.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkContraption.java index 5d82af30a1..ce0de7e5f5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/ClockworkContraption.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; import java.util.HashSet; import java.util.Queue; @@ -6,10 +6,10 @@ import java.util.Set; import org.apache.commons.lang3.tuple.Pair; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.core.BlockPos; @@ -27,7 +27,7 @@ public class ClockworkContraption extends Contraption { private Set ignoreBlocks = new HashSet<>(); @Override - protected ContraptionType getType() { + public ContraptionType getType() { return ContraptionType.CLOCKWORK; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/IBearingBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/IBearingBlockEntity.java new file mode 100644 index 0000000000..31031de2c6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/IBearingBlockEntity.java @@ -0,0 +1,26 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.simibubi.create.content.contraptions.DirectionalExtenderScrollOptionSlot; +import com.simibubi.create.content.contraptions.IControlContraption; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.minecraft.core.Direction.Axis; + +public interface IBearingBlockEntity extends IControlContraption { + + float getInterpolatedAngle(float partialTicks); + + boolean isWoodenTop(); + + default ValueBoxTransform getMovementModeSlot() { + return new DirectionalExtenderScrollOptionSlot((state, d) -> { + Axis axis = d.getAxis(); + Axis bearingAxis = state.getValue(BearingBlock.FACING) + .getAxis(); + return bearingAxis != axis; + }); + } + + void setAngle(float forcedAngle); + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlock.java new file mode 100644 index 0000000000..5e19fd434a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlock.java @@ -0,0 +1,54 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class MechanicalBearingBlock extends BearingBlock implements IBE { + + public MechanicalBearingBlock(Properties properties) { + super(properties); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (!player.mayBuild()) + return InteractionResult.FAIL; + if (player.isShiftKeyDown()) + return InteractionResult.FAIL; + if (player.getItemInHand(handIn) + .isEmpty()) { + if (worldIn.isClientSide) + return InteractionResult.SUCCESS; + withBlockEntityDo(worldIn, pos, be -> { + if (be.running) { + be.disassemble(); + return; + } + be.assembleNextTick = true; + }); + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + public Class getBlockEntityClass() { + return MechanicalBearingBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_BEARING.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlockEntity.java new file mode 100644 index 0000000000..b046b7acfc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/MechanicalBearingBlockEntity.java @@ -0,0 +1,359 @@ +package com.simibubi.create.content.contraptions.bearing; + +import java.util.List; + +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencerInstructions; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class MechanicalBearingBlockEntity extends GeneratingKineticBlockEntity + implements IBearingBlockEntity, IDisplayAssemblyExceptions { + + protected ScrollOptionBehaviour movementMode; + protected ControlledContraptionEntity movedContraption; + protected float angle; + protected boolean running; + protected boolean assembleNextTick; + protected float clientAngleDiff; + protected AssemblyException lastException; + protected double sequencedAngleLimit; + + private float prevAngle; + + public MechanicalBearingBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(3); + sequencedAngleLimit = -1; + } + + @Override + public boolean isWoodenTop() { + return false; + } + + @Override + protected boolean syncSequenceContext() { + return true; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + movementMode = new ScrollOptionBehaviour<>(RotationMode.class, + CreateLang.translateDirect("contraptions.movement_mode"), this, getMovementModeSlot()); + behaviours.add(movementMode); + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + public void remove() { + if (!level.isClientSide) + disassemble(); + super.remove(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putFloat("Angle", angle); + if (sequencedAngleLimit >= 0) + compound.putDouble("SequencedAngleLimit", sequencedAngleLimit); + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + if (wasMoved) { + super.read(compound, clientPacket); + return; + } + + float angleBefore = angle; + running = compound.getBoolean("Running"); + angle = compound.getFloat("Angle"); + sequencedAngleLimit = compound.contains("SequencedAngleLimit") ? compound.getDouble("SequencedAngleLimit") : -1; + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + if (!clientPacket) + return; + if (running) { + if (movedContraption == null || !movedContraption.isStalled()) { + clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle); + angle = angleBefore; + } + } else + movedContraption = null; + } + + @Override + public float getInterpolatedAngle(float partialTicks) { + if (isVirtual()) + return Mth.lerp(partialTicks + .5f, prevAngle, angle); + if (movedContraption == null || movedContraption.isStalled() || !running) + partialTicks = 0; + float angularSpeed = getAngularSpeed(); + if (sequencedAngleLimit >= 0) + angularSpeed = (float) Mth.clamp(angularSpeed, -sequencedAngleLimit, sequencedAngleLimit); + return Mth.lerp(partialTicks, angle, angle + angularSpeed); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + assembleNextTick = true; + sequencedAngleLimit = -1; + + if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { + if (!movedContraption.isStalled()) { + angle = Math.round(angle); + applyRotation(); + } + movedContraption.getContraption() + .stop(level); + } + + if (!isWindmill() && sequenceContext != null + && sequenceContext.instruction() == SequencerInstructions.TURN_ANGLE) + sequencedAngleLimit = sequenceContext.getEffectiveValue(getTheoreticalSpeed()); + } + + public float getAngularSpeed() { + float speed = convertToAngular(isWindmill() ? getGeneratedSpeed() : getSpeed()); + if (getSpeed() == 0) + speed = 0; + if (level.isClientSide) { + speed *= ServerSpeedProvider.get(); + speed += clientAngleDiff / 3f; + } + return speed; + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + + protected boolean isWindmill() { + return false; + } + + @Override + public BlockPos getBlockPosition() { + return worldPosition; + } + + public void assemble() { + if (!(level.getBlockState(worldPosition) + .getBlock() instanceof BearingBlock)) + return; + + Direction direction = getBlockState().getValue(BearingBlock.FACING); + BearingContraption contraption = new BearingContraption(isWindmill(), direction); + try { + if (!contraption.assemble(level, worldPosition)) + return; + + lastException = null; + } catch (AssemblyException e) { + lastException = e; + sendData(); + return; + } + + if (isWindmill()) + award(AllAdvancements.WINDMILL); + if (contraption.getSailBlocks() >= 16 * 8) + award(AllAdvancements.WINDMILL_MAXED); + + contraption.removeBlocksFromWorld(level, BlockPos.ZERO); + movedContraption = ControlledContraptionEntity.create(level, this, contraption); + BlockPos anchor = worldPosition.relative(direction); + movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + movedContraption.setRotationAxis(direction.getAxis()); + level.addFreshEntity(movedContraption); + + AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + + running = true; + angle = 0; + sendData(); + updateGeneratedRotation(); + } + + public void disassemble() { + if (!running && movedContraption == null) + return; + angle = 0; + sequencedAngleLimit = -1; + if (isWindmill()) + applyRotation(); + if (movedContraption != null) { + movedContraption.disassemble(); + AllSoundEvents.CONTRAPTION_DISASSEMBLE.playOnServer(level, worldPosition); + } + + movedContraption = null; + running = false; + updateGeneratedRotation(); + assembleNextTick = false; + sendData(); + } + + @Override + public void tick() { + super.tick(); + + prevAngle = angle; + if (level.isClientSide) + clientAngleDiff /= 2; + + if (!level.isClientSide && assembleNextTick) { + assembleNextTick = false; + if (running) { + boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE + || (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED); + if (speed == 0 && (canDisassemble || movedContraption == null || movedContraption.getContraption() + .getBlocks() + .isEmpty())) { + if (movedContraption != null) + movedContraption.getContraption() + .stop(level); + disassemble(); + return; + } + } else { + if (speed == 0 && !isWindmill()) + return; + assemble(); + } + } + + if (!running) + return; + + if (!(movedContraption != null && movedContraption.isStalled())) { + float angularSpeed = getAngularSpeed(); + if (sequencedAngleLimit >= 0) { + angularSpeed = (float) Mth.clamp(angularSpeed, -sequencedAngleLimit, sequencedAngleLimit); + sequencedAngleLimit = Math.max(0, sequencedAngleLimit - Math.abs(angularSpeed)); + } + float newAngle = angle + angularSpeed; + angle = (float) (newAngle % 360); + } + + applyRotation(); + } + + public boolean isNearInitialAngle() { + return Math.abs(angle) < 22.5 || Math.abs(angle) > 360 - 22.5; + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (movedContraption != null && !level.isClientSide) + sendData(); + } + + protected void applyRotation() { + if (movedContraption == null) + return; + movedContraption.setAngle(angle); + BlockState blockState = getBlockState(); + if (blockState.hasProperty(BlockStateProperties.FACING)) + movedContraption.setRotationAxis(blockState.getValue(BlockStateProperties.FACING) + .getAxis()); + } + + @Override + public void attach(ControlledContraptionEntity contraption) { + BlockState blockState = getBlockState(); + if (!(contraption.getContraption() instanceof BearingContraption)) + return; + if (!blockState.hasProperty(BearingBlock.FACING)) + return; + + this.movedContraption = contraption; + setChanged(); + BlockPos anchor = worldPosition.relative(blockState.getValue(BearingBlock.FACING)); + movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + if (!level.isClientSide) { + this.running = true; + sendData(); + } + } + + @Override + public void onStall() { + if (!level.isClientSide) + sendData(); + } + + @Override + public boolean isValid() { + return !isRemoved(); + } + + @Override + public boolean isAttachedTo(AbstractContraptionEntity contraption) { + return movedContraption == contraption; + } + + public boolean isRunning() { + return running; + } + + @Override + public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { + if (super.addToTooltip(tooltip, isPlayerSneaking)) + return true; + if (isPlayerSneaking) + return false; + if (!isWindmill() && getSpeed() == 0) + return false; + if (running) + return false; + BlockState state = getBlockState(); + if (!(state.getBlock() instanceof BearingBlock)) + return false; + + BlockState attachedState = level.getBlockState(worldPosition.relative(state.getValue(BearingBlock.FACING))); + if (attachedState.getMaterial() + .isReplaceable()) + return false; + TooltipHelper.addHint(tooltip, "hint.empty_bearing"); + return true; + } + + public void setAngle(float forcedAngle) { + angle = forcedAngle; + } + + public ControlledContraptionEntity getMovedContraption() { + return movedContraption; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/SailBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/SailBlock.java index 25d7b81ded..e94d2202e5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/SailBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; import java.util.ArrayList; import java.util.HashSet; @@ -21,6 +21,8 @@ import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; @@ -84,12 +86,17 @@ public class SailBlock extends WrenchableDirectionalBlock { ItemStack heldItem = player.getItemInHand(hand); IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); - if (placementHelper.matchesItem(heldItem)) - return placementHelper.getOffset(player, world, state, pos, ray) - .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldItem)) { + placementHelper.getOffset(player, world, state, pos, ray) + .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return InteractionResult.SUCCESS; + } + } if (heldItem.getItem() instanceof ShearsItem) { if (!world.isClientSide) + world.playSound(null, pos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1.0f, 1.0f); applyDye(state, world, pos, ray.getLocation(), null); return InteractionResult.SUCCESS; } @@ -100,6 +107,7 @@ public class SailBlock extends WrenchableDirectionalBlock { DyeColor color = DyeColor.getColor(heldItem); if (color != null) { if (!world.isClientSide) + world.playSound(null, pos, SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0f, 1.1f - world.random.nextFloat() * .2f); applyDye(state, world, pos, ray.getLocation(), color); return InteractionResult.SUCCESS; } @@ -119,7 +127,8 @@ public class SailBlock extends WrenchableDirectionalBlock { } // Dye all adjacent - List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, hit, state.getValue(FACING).getAxis()); + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, hit, state.getValue(FACING) + .getAxis()); for (Direction d : directions) { BlockPos offset = pos.relative(d); BlockState adjacentState = world.getBlockState(offset); @@ -182,7 +191,8 @@ public class SailBlock extends WrenchableDirectionalBlock { } @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, + Player player) { ItemStack pickBlock = super.getCloneItemStack(state, target, world, pos, player); if (pickBlock.isEmpty()) return AllBlocks.SAIL.get() diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingInstance.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingInstance.java index 909f94895f..054b8d1c9d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.Materials; @@ -6,10 +6,10 @@ import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; import com.simibubi.create.foundation.render.AllMaterialSpecs; import net.createmod.catnip.utility.AnimationTickHolder; @@ -38,7 +38,7 @@ public class StabilizedBearingInstance extends ActorInstance { topInstance = materialManager.defaultSolid() .material(Materials.ORIENTED) - .getModel(AllBlockPartials.BEARING_TOP, blockState) + .getModel(AllPartialModels.BEARING_TOP, blockState) .createInstance(); int blockLight = localBlockLight(); @@ -48,7 +48,7 @@ public class StabilizedBearingInstance extends ActorInstance { shaft = materialManager.defaultSolid() .material(AllMaterialSpecs.ROTATING) - .getModel(AllBlockPartials.SHAFT_HALF, blockState, blockState.getValue(BlockStateProperties.FACING).getOpposite()) + .getModel(AllPartialModels.SHAFT_HALF, blockState, blockState.getValue(BlockStateProperties.FACING).getOpposite()) .createInstance(); // not rotating so no need to set speed, axis, etc. diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingMovementBehaviour.java similarity index 75% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingMovementBehaviour.java index 20f7c3714e..eae805fe4d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedBearingMovementBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; +package com.simibubi.create.content.contraptions.bearing; import javax.annotation.Nullable; @@ -6,15 +6,15 @@ import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.mojang.math.Quaternion; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.render.CachedPartialBuffers; import net.createmod.catnip.render.SuperByteBuffer; @@ -23,12 +23,18 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; public class StabilizedBearingMovementBehaviour implements MovementBehaviour { + @Override + public ItemStack canBeDisabledVia(MovementContext context) { + return null; + } + @Override @OnlyIn(Dist.CLIENT) public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, @@ -37,7 +43,7 @@ public class StabilizedBearingMovementBehaviour implements MovementBehaviour { return; Direction facing = context.state.getValue(BlockStateProperties.FACING); - PartialModel top = AllBlockPartials.BEARING_TOP; + PartialModel top = AllPartialModels.BEARING_TOP; SuperByteBuffer superBuffer = CachedPartialBuffers.partial(top, context.state); float renderPartialTicks = AnimationTickHolder.getPartialTicks(); @@ -53,8 +59,10 @@ public class StabilizedBearingMovementBehaviour implements MovementBehaviour { rotation.mul(orientation); + orientation = rotation; + superBuffer.transform(matrices.getModel()); - superBuffer.rotateCentered(rotation); + superBuffer.rotateCentered(orientation); // render superBuffer diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedContraption.java new file mode 100644 index 0000000000..c4ef7cf302 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/StabilizedContraption.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.NonStationaryLighter; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class StabilizedContraption extends Contraption { + + private Direction facing; + + public StabilizedContraption() {} + + public StabilizedContraption(Direction facing) { + this.facing = facing; + } + + @Override + public boolean assemble(Level world, BlockPos pos) throws AssemblyException { + BlockPos offset = pos.relative(facing); + if (!searchMovedStructure(world, offset, null)) + return false; + startMoving(world); + if (blocks.isEmpty()) + return false; + return true; + } + + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return false; + } + + @Override + public ContraptionType getType() { + return ContraptionType.STABILIZED; + } + + @Override + public CompoundTag writeNBT(boolean spawnPacket) { + CompoundTag tag = super.writeNBT(spawnPacket); + tag.putInt("Facing", facing.get3DDataValue()); + return tag; + } + + @Override + public void readNBT(Level world, CompoundTag tag, boolean spawnData) { + facing = Direction.from3DDataValue(tag.getInt("Facing")); + super.readNBT(world, tag, spawnData); + } + + @Override + public boolean canBeStabilized(Direction facing, BlockPos localPos) { + return false; + } + + public Direction getFacing() { + return facing; + } + + @Override + @OnlyIn(Dist.CLIENT) + public ContraptionLighter makeLighter() { + return new NonStationaryLighter<>(this); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlock.java new file mode 100644 index 0000000000..ccbcee5d88 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlock.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.contraptions.bearing; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class WindmillBearingBlock extends BearingBlock implements IBE { + + public WindmillBearingBlock(Properties properties) { + super(properties); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (!player.mayBuild()) + return InteractionResult.FAIL; + if (player.isShiftKeyDown()) + return InteractionResult.FAIL; + if (player.getItemInHand(handIn) + .isEmpty()) { + if (worldIn.isClientSide) + return InteractionResult.SUCCESS; + withBlockEntityDo(worldIn, pos, be -> { + if (be.running) { + be.disassemble(); + return; + } + be.assembleNextTick = true; + }); + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + public Class getBlockEntityClass() { + return WindmillBearingBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.WINDMILL_BEARING.get(); + } + + public static Couple getSpeedRange() { + return Couple.create(1, 16); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlockEntity.java new file mode 100644 index 0000000000..8d942487ac --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/bearing/WindmillBearingBlockEntity.java @@ -0,0 +1,149 @@ +package com.simibubi.create.content.contraptions.bearing; + +import java.util.List; + +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class WindmillBearingBlockEntity extends MechanicalBearingBlockEntity { + + protected ScrollOptionBehaviour movementDirection; + protected float lastGeneratedSpeed; + + protected boolean queuedReassembly; + + public WindmillBearingBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void updateGeneratedRotation() { + super.updateGeneratedRotation(); + lastGeneratedSpeed = getGeneratedSpeed(); + queuedReassembly = false; + } + + @Override + public void onSpeedChanged(float prevSpeed) { + boolean cancelAssembly = assembleNextTick; + super.onSpeedChanged(prevSpeed); + assembleNextTick = cancelAssembly; + } + + @Override + public void tick() { + super.tick(); + if (level.isClientSide()) + return; + if (!queuedReassembly) + return; + queuedReassembly = false; + if (!running) + assembleNextTick = true; + } + + public void disassembleForMovement() { + if (!running) + return; + disassemble(); + queuedReassembly = true; + } + + @Override + public float getGeneratedSpeed() { + if (!running) + return 0; + if (movedContraption == null) + return lastGeneratedSpeed; + int sails = ((BearingContraption) movedContraption.getContraption()).getSailBlocks() + / AllConfigs.server().kinetics.windmillSailsPerRPM.get(); + return Mth.clamp(sails, 1, 16) * getAngleSpeedDirection(); + } + + @Override + protected boolean isWindmill() { + return true; + } + + protected float getAngleSpeedDirection() { + RotationDirection rotationDirection = RotationDirection.values()[movementDirection.getValue()]; + return (rotationDirection == RotationDirection.CLOCKWISE ? 1 : -1); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putFloat("LastGenerated", lastGeneratedSpeed); + compound.putBoolean("QueueAssembly", queuedReassembly); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + if (!wasMoved) + lastGeneratedSpeed = compound.getFloat("LastGenerated"); + queuedReassembly = compound.getBoolean("QueueAssembly"); + super.read(compound, clientPacket); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.remove(movementMode); + movementDirection = new ScrollOptionBehaviour<>(RotationDirection.class, + CreateLang.translateDirect("contraptions.windmill.rotation_direction"), this, getMovementModeSlot()); + movementDirection.withCallback($ -> onDirectionChanged()); + behaviours.add(movementDirection); + registerAwardables(behaviours, AllAdvancements.WINDMILL, AllAdvancements.WINDMILL_MAXED); + } + + private void onDirectionChanged() { + if (!running) + return; + if (!level.isClientSide) + updateGeneratedRotation(); + } + + @Override + public boolean isWoodenTop() { + return true; + } + + public static enum RotationDirection implements INamedIconOptions { + + CLOCKWISE(AllIcons.I_REFRESH), COUNTER_CLOCKWISE(AllIcons.I_ROTATE_CCW), + + ; + + private String translationKey; + private AllIcons icon; + + private RotationDirection(AllIcons icon) { + this.icon = icon; + translationKey = "generic." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/behaviour/BellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/BellMovementBehaviour.java new file mode 100644 index 0000000000..367d06ffcb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/BellMovementBehaviour.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.contraptions.behaviour; + +import com.simibubi.create.content.equipment.bell.AbstractBellBlock; +import com.simibubi.create.content.trains.entity.CarriageContraption; + +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.Vec3; + +public class BellMovementBehaviour implements MovementBehaviour { + + @Override + public boolean renderAsNormalBlockEntity() { + return true; + } + + @Override + public boolean isActive(MovementContext context) { + return MovementBehaviour.super.isActive(context) && !(context.contraption instanceof CarriageContraption); + } + + @Override + public void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) { + double dotProduct = oldMotion.dot(motion); + + if (dotProduct <= 0 && (context.relativeMotion.length() != 0) || context.firstMovement) + playSound(context); + } + + @Override + public void stopMoving(MovementContext context) { + if (context.position != null && isActive(context)) + playSound(context); + } + + public static void playSound(MovementContext context) { + Level world = context.world; + BlockPos pos = new BlockPos(context.position); + Block block = context.state.getBlock(); + + if (block instanceof AbstractBellBlock) { + ((AbstractBellBlock) block).playSound(world, pos); + } else { + // Vanilla bell sound + world.playSound(null, pos, SoundEvents.BELL_BLOCK, + SoundSource.BLOCKS, 2f, 1f); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/behaviour/CampfireMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/CampfireMovementBehaviour.java new file mode 100644 index 0000000000..69a075c23f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/CampfireMovementBehaviour.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.contraptions.behaviour; + +import java.util.Random; + +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.level.block.CampfireBlock; + +public class CampfireMovementBehaviour implements MovementBehaviour { + @Override + public boolean renderAsNormalBlockEntity() { + return true; + } + + @Override + public void tick(MovementContext context) { + if (context.world == null || !context.world.isClientSide || context.position == null + || !context.state.getValue(CampfireBlock.LIT) || context.disabled) + return; + + // Mostly copied from CampfireBlock and CampfireBlockEntity + Random random = context.world.random; + if (random.nextFloat() < 0.11F) { + for (int i = 0; i < random.nextInt(2) + 2; ++i) { + context.world.addAlwaysVisibleParticle( + context.state.getValue(CampfireBlock.SIGNAL_FIRE) ? ParticleTypes.CAMPFIRE_SIGNAL_SMOKE + : ParticleTypes.CAMPFIRE_COSY_SMOKE, + true, context.position.x() + random.nextDouble() / (random.nextBoolean() ? 3D : -3D), + context.position.y() + random.nextDouble() + random.nextDouble(), + context.position.z() + random.nextDouble() / (random.nextBoolean() ? 3D : -3D), 0.0D, 0.07D, + 0.0D); + } + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/DoorMovingInteraction.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/DoorMovingInteraction.java index 0c5b7a22db..d58c0d129d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/DoorMovingInteraction.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction; +package com.simibubi.create.content.contraptions.behaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/LeverMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/LeverMovingInteraction.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/LeverMovingInteraction.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/LeverMovingInteraction.java index 021ecf75da..19472df5d1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/LeverMovingInteraction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/LeverMovingInteraction.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction; +package com.simibubi.create.content.contraptions.behaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.Contraption; import net.minecraft.core.BlockPos; import net.minecraft.sounds.SoundEvents; diff --git a/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementBehaviour.java new file mode 100644 index 0000000000..3cf7dd7a6b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementBehaviour.java @@ -0,0 +1,101 @@ +package com.simibubi.create.content.contraptions.behaviour; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.ItemHandlerHelper; + +public interface MovementBehaviour { + + default boolean isActive(MovementContext context) { + return !context.disabled; + } + + default void tick(MovementContext context) {} + + default void startMoving(MovementContext context) {} + + default void visitNewPosition(MovementContext context, BlockPos pos) {} + + default Vec3 getActiveAreaOffset(MovementContext context) { + return Vec3.ZERO; + } + + @Nullable + default ItemStack canBeDisabledVia(MovementContext context) { + Block block = context.state.getBlock(); + if (block == null) + return null; + return new ItemStack(block); + } + + default void onDisabledByControls(MovementContext context) { + cancelStall(context); + } + + default boolean mustTickWhileDisabled() { + return false; + } + + default void dropItem(MovementContext context, ItemStack stack) { + ItemStack remainder; + if (AllConfigs.server().kinetics.moveItemsToStorage.get()) + remainder = ItemHandlerHelper.insertItem(context.contraption.getSharedInventory(), stack, false); + else + remainder = stack; + if (remainder.isEmpty()) + return; + + // Actors might void items if their positions is undefined + Vec3 vec = context.position; + if (vec == null) + return; + + ItemEntity itemEntity = new ItemEntity(context.world, vec.x, vec.y, vec.z, remainder); + itemEntity.setDeltaMovement(context.motion.add(0, 0.5f, 0) + .scale(context.world.random.nextFloat() * .3f)); + context.world.addFreshEntity(itemEntity); + } + + default void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) {} + + default void stopMoving(MovementContext context) {} + + default void cancelStall(MovementContext context) { + context.stall = false; + } + + default void writeExtraData(MovementContext context) {} + + default boolean renderAsNormalBlockEntity() { + return false; + } + + default boolean hasSpecialInstancedRendering() { + return false; + } + + @OnlyIn(Dist.CLIENT) + default void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) {} + + @OnlyIn(Dist.CLIENT) + @Nullable + default ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, + MovementContext context) { + return null; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java index 953fa42f6e..7e5447d315 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovementContext.java @@ -1,7 +1,9 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions.behaviour; import java.util.function.UnaryOperator; +import com.simibubi.create.content.contraptions.Contraption; + import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -21,9 +23,10 @@ public class MovementContext { public Level world; public BlockState state; public BlockPos localPos; - public CompoundTag tileData; + public CompoundTag blockEntityData; public boolean stall; + public boolean disabled; public boolean firstMovement; public CompoundTag data; public Contraption contraption; @@ -32,10 +35,11 @@ public class MovementContext { public MovementContext(Level world, StructureBlockInfo info, Contraption contraption) { this.world = world; this.state = info.state; - this.tileData = info.nbt; + this.blockEntityData = info.nbt; this.contraption = contraption; localPos = info.pos; + disabled = false; firstMovement = true; motion = Vec3.ZERO; relativeMotion = Vec3.ZERO; @@ -48,6 +52,8 @@ public class MovementContext { public float getAnimationSpeed() { int modifier = 1000; double length = -motion.length(); + if (disabled) + return 0; if (world.isClientSide && contraption.stalled) return 700; if (Math.abs(length) < 1 / 512f) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovingInteractionBehaviour.java similarity index 75% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/MovingInteractionBehaviour.java index cd8285595c..b6b2d698c0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/MovingInteractionBehaviour.java @@ -1,7 +1,9 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions.behaviour; import org.apache.commons.lang3.tuple.MutablePair; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; + import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; @@ -12,10 +14,10 @@ public abstract class MovingInteractionBehaviour { protected void setContraptionActorData(AbstractContraptionEntity contraptionEntity, int index, StructureBlockInfo info, MovementContext ctx) { - contraptionEntity.contraption.actors.remove(index); - contraptionEntity.contraption.actors.add(index, MutablePair.of(info, ctx)); + contraptionEntity.getContraption().getActors().remove(index); + contraptionEntity.getContraption().getActors().add(index, MutablePair.of(info, ctx)); if (contraptionEntity.level.isClientSide) - contraptionEntity.contraption.deferInvalidate = true; + contraptionEntity.getContraption().deferInvalidate = true; } protected void setContraptionBlockData(AbstractContraptionEntity contraptionEntity, BlockPos pos, diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/SimpleBlockMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/SimpleBlockMovingInteraction.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/SimpleBlockMovingInteraction.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/SimpleBlockMovingInteraction.java index eceb3c0c23..69de088b2f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/SimpleBlockMovingInteraction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/SimpleBlockMovingInteraction.java @@ -1,8 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction; +package com.simibubi.create.content.contraptions.behaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; import net.minecraft.core.BlockPos; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/TrapdoorMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/TrapdoorMovingInteraction.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/TrapdoorMovingInteraction.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/TrapdoorMovingInteraction.java index 18aed3fafa..226dcfa2e3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/TrapdoorMovingInteraction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/TrapdoorMovingInteraction.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction; +package com.simibubi.create.content.contraptions.behaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.Contraption; import net.minecraft.core.BlockPos; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/ContraptionBlockSource.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/ContraptionBlockSource.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/ContraptionBlockSource.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/ContraptionBlockSource.java index d64758b334..870da5cdb0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/ContraptionBlockSource.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/ContraptionBlockSource.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenseItemLocation.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenseItemLocation.java index 2b0b23916f..c9134e0b3f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenseItemLocation.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenseItemLocation.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; public class DispenseItemLocation { private final boolean internal; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenserMovementBehaviour.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenserMovementBehaviour.java index 8ca9d96847..1018e98875 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DispenserMovementBehaviour.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import java.util.HashMap; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.foundation.mixin.accessor.DispenserBlockAccessor; import net.minecraft.core.BlockPos; @@ -79,7 +79,7 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour { return; } } catch (NullPointerException ignored) { - itemStack = backup; // Something went wrong with the TE being null in ContraptionBlockSource, reset the stack + itemStack = backup; // Something went wrong with the BE being null in ContraptionBlockSource, reset the stack } setItemStackAt(location, DEFAULT_BEHAVIOUR.dispense(itemStack, context, pos), context); // the default: launch the item diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DropperMovementBehaviour.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DropperMovementBehaviour.java index 03bf61698d..3f854219e8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DropperMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/DropperMovementBehaviour.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import java.util.ArrayList; import java.util.List; import java.util.Random; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.core.BlockPos; @@ -50,7 +50,7 @@ public class DropperMovementBehaviour implements MovementBehaviour { private void updateTemporaryData(MovementContext context) { if (!(context.temporaryData instanceof NonNullList) && context.world != null) { NonNullList stacks = NonNullList.withSize(getInvSize(), ItemStack.EMPTY); - ContainerHelper.loadAllItems(context.tileData, stacks); + ContainerHelper.loadAllItems(context.blockEntityData, stacks); context.temporaryData = stacks; } } @@ -84,7 +84,7 @@ public class DropperMovementBehaviour implements MovementBehaviour { NonNullList stacks = getStacks(context); if (stacks == null) return; - ContainerHelper.saveAllItems(context.tileData, stacks); + ContainerHelper.saveAllItems(context.blockEntityData, stacks); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/IMovedDispenseItemBehaviour.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/IMovedDispenseItemBehaviour.java index 7143b9a057..dd3fd642cb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/IMovedDispenseItemBehaviour.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import java.util.Random; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.minecraft.Util; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedDefaultDispenseItemBehaviour.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedDefaultDispenseItemBehaviour.java index 45b5a89d77..1ad03f1bcf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedDefaultDispenseItemBehaviour.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -49,13 +49,13 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha facingVec.normalize(); Direction closestToFacing = getClosestFacingDirection(facingVec); - Container iinventory = HopperBlockEntity.getContainerAt(context.world, pos.relative(closestToFacing)); - if (iinventory == null) { + Container inventory = HopperBlockEntity.getContainerAt(context.world, pos.relative(closestToFacing)); + if (inventory == null) { this.playDispenseSound(context.world, pos); this.spawnDispenseParticles(context.world, pos, closestToFacing); return this.dispenseStack(itemStack, context, pos, facingVec); } else { - if (HopperBlockEntity.addItem(null, iinventory, itemStack.copy() + if (HopperBlockEntity.addItem(null, inventory, itemStack.copy() .split(1), closestToFacing.getOpposite()) .isEmpty()) itemStack.shrink(1); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedOptionalDispenseBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedOptionalDispenseBehaviour.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedOptionalDispenseBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedOptionalDispenseBehaviour.java index b1af00626b..3e9e77ed13 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedOptionalDispenseBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedOptionalDispenseBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import net.minecraft.core.BlockPos; import net.minecraft.world.level.LevelAccessor; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedProjectileDispenserBehaviour.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedProjectileDispenserBehaviour.java index 4add4a76ed..2d99d36172 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/MovedProjectileDispenserBehaviour.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.foundation.mixin.accessor.AbstractProjectileDispenseBehaviorAccessor; import net.minecraft.core.BlockPos; @@ -20,12 +20,12 @@ public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDisp double x = pos.getX() + facing.x * .7 + .5; double y = pos.getY() + facing.y * .7 + .5; double z = pos.getZ() + facing.z * .7 + .5; - Projectile ProjectileEntity = this.getProjectileEntity(context.world, x, y, z, itemStack.copy()); - if (ProjectileEntity == null) + Projectile projectile = this.getProjectileEntity(context.world, x, y, z, itemStack.copy()); + if (projectile == null) return itemStack; Vec3 effectiveMovementVec = facing.scale(getProjectileVelocity()).add(context.motion); - ProjectileEntity.shoot(effectiveMovementVec.x, effectiveMovementVec.y, effectiveMovementVec.z, (float) effectiveMovementVec.length(), this.getProjectileInaccuracy()); - context.world.addFreshEntity(ProjectileEntity); + projectile.shoot(effectiveMovementVec.x, effectiveMovementVec.y, effectiveMovementVec.z, (float) effectiveMovementVec.length(), this.getProjectileInaccuracy()); + context.world.addFreshEntity(projectile); itemStack.shrink(1); return itemStack; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/SimplePos.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java rename to src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/SimplePos.java index 3d62bd8c7b..9b8c22acca 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java +++ b/src/main/java/com/simibubi/create/content/contraptions/behaviour/dispenser/SimplePos.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.actors.dispenser; +package com.simibubi.create.content.contraptions.behaviour.dispenser; import net.minecraft.core.Position; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/AbstractChassisBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/chassis/AbstractChassisBlock.java index 0dc957d611..5d1543fba7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/AbstractChassisBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; +package com.simibubi.create.content.contraptions.chassis; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -28,7 +28,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.Tags; -public abstract class AbstractChassisBlock extends RotatedPillarBlock implements IWrenchable, ITE, ITransformableBlock { +public abstract class AbstractChassisBlock extends RotatedPillarBlock implements IWrenchable, IBE, ITransformableBlock { public AbstractChassisBlock(Properties properties) { super(properties); @@ -179,13 +179,13 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements } @Override - public Class getTileEntityClass() { - return ChassisTileEntity.class; + public Class getBlockEntityClass() { + return ChassisBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CHASSIS.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CHASSIS.get(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisBlockEntity.java new file mode 100644 index 0000000000..fc135c2863 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisBlockEntity.java @@ -0,0 +1,301 @@ +package com.simibubi.create.content.contraptions.chassis; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllKeys; +import com.simibubi.create.content.contraptions.BlockMovementChecks; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.BulkScrollValueBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class ChassisBlockEntity extends SmartBlockEntity { + + ScrollValueBehaviour range; + + public int currentlySelectedRange; + + public ChassisBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + int max = AllConfigs.server().kinetics.maxChassisRange.get(); + range = new ChassisScrollValueBehaviour(CreateLang.translateDirect("contraptions.chassis.range"), this, + new CenteredSideValueBoxTransform(), be -> ((ChassisBlockEntity) be).collectChassisGroup()); + range.requiresWrench(); + range.between(1, max); + range.withClientCallback( + i -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ChassisRangeDisplay.display(this))); + range.setValue(max / 2); + range.withFormatter(s -> String.valueOf(currentlySelectedRange)); + behaviours.add(range); + currentlySelectedRange = range.getValue(); + } + + @Override + public void initialize() { + super.initialize(); + if (getBlockState().getBlock() instanceof RadialChassisBlock) + range.setLabel(CreateLang.translateDirect("contraptions.chassis.radius")); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + if (clientPacket) + currentlySelectedRange = getRange(); + } + + public int getRange() { + return range.getValue(); + } + + public List getIncludedBlockPositions(Direction forcedMovement, boolean visualize) { + if (!(getBlockState().getBlock() instanceof AbstractChassisBlock)) + return Collections.emptyList(); + return isRadial() ? getIncludedBlockPositionsRadial(forcedMovement, visualize) + : getIncludedBlockPositionsLinear(forcedMovement, visualize); + } + + protected boolean isRadial() { + return level.getBlockState(worldPosition) + .getBlock() instanceof RadialChassisBlock; + } + + public List collectChassisGroup() { + Queue frontier = new LinkedList<>(); + List collected = new ArrayList<>(); + Set visited = new HashSet<>(); + frontier.add(worldPosition); + while (!frontier.isEmpty()) { + BlockPos current = frontier.poll(); + if (visited.contains(current)) + continue; + visited.add(current); + BlockEntity blockEntity = level.getBlockEntity(current); + if (blockEntity instanceof ChassisBlockEntity) { + ChassisBlockEntity chassis = (ChassisBlockEntity) blockEntity; + collected.add(chassis); + visited.add(current); + chassis.addAttachedChasses(frontier, visited); + } + } + return collected; + } + + public boolean addAttachedChasses(Queue frontier, Set visited) { + BlockState state = getBlockState(); + if (!(state.getBlock() instanceof AbstractChassisBlock)) + return false; + Axis axis = state.getValue(AbstractChassisBlock.AXIS); + if (isRadial()) { + + // Collect chain of radial chassis + for (int offset : new int[] { -1, 1 }) { + Direction direction = Direction.get(AxisDirection.POSITIVE, axis); + BlockPos currentPos = worldPosition.relative(direction, offset); + if (!level.isLoaded(currentPos)) + return false; + + BlockState neighbourState = level.getBlockState(currentPos); + if (!AllBlocks.RADIAL_CHASSIS.has(neighbourState)) + continue; + if (axis != neighbourState.getValue(BlockStateProperties.AXIS)) + continue; + if (!visited.contains(currentPos)) + frontier.add(currentPos); + } + + return true; + } + + // Collect group of connected linear chassis + for (Direction offset : Iterate.directions) { + BlockPos current = worldPosition.relative(offset); + if (visited.contains(current)) + continue; + if (!level.isLoaded(current)) + return false; + + BlockState neighbourState = level.getBlockState(current); + if (!LinearChassisBlock.isChassis(neighbourState)) + continue; + if (!LinearChassisBlock.sameKind(state, neighbourState)) + continue; + if (neighbourState.getValue(LinearChassisBlock.AXIS) != axis) + continue; + + frontier.add(current); + } + + return true; + } + + private List getIncludedBlockPositionsLinear(Direction forcedMovement, boolean visualize) { + List positions = new ArrayList<>(); + BlockState state = getBlockState(); + AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); + Axis axis = state.getValue(AbstractChassisBlock.AXIS); + Direction facing = Direction.get(AxisDirection.POSITIVE, axis); + int chassisRange = visualize ? currentlySelectedRange : getRange(); + + for (int offset : new int[] { 1, -1 }) { + if (offset == -1) + facing = facing.getOpposite(); + boolean sticky = state.getValue(block.getGlueableSide(state, facing)); + for (int i = 1; i <= chassisRange; i++) { + BlockPos current = worldPosition.relative(facing, i); + BlockState currentState = level.getBlockState(current); + + if (forcedMovement != facing && !sticky) + break; + + // Ignore replaceable Blocks and Air-like + if (!BlockMovementChecks.isMovementNecessary(currentState, level, current)) + break; + if (BlockMovementChecks.isBrittle(currentState)) + break; + + positions.add(current); + + if (BlockMovementChecks.isNotSupportive(currentState, facing)) + break; + } + } + + return positions; + } + + private List getIncludedBlockPositionsRadial(Direction forcedMovement, boolean visualize) { + List positions = new ArrayList<>(); + BlockState state = level.getBlockState(worldPosition); + Axis axis = state.getValue(AbstractChassisBlock.AXIS); + AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); + int chassisRange = visualize ? currentlySelectedRange : getRange(); + + for (Direction facing : Iterate.directions) { + if (facing.getAxis() == axis) + continue; + if (!state.getValue(block.getGlueableSide(state, facing))) + continue; + + BlockPos startPos = worldPosition.relative(facing); + List localFrontier = new LinkedList<>(); + Set localVisited = new HashSet<>(); + localFrontier.add(startPos); + + while (!localFrontier.isEmpty()) { + BlockPos searchPos = localFrontier.remove(0); + BlockState searchedState = level.getBlockState(searchPos); + + if (localVisited.contains(searchPos)) + continue; + if (!searchPos.closerThan(worldPosition, chassisRange + .5f)) + continue; + if (!BlockMovementChecks.isMovementNecessary(searchedState, level, searchPos)) + continue; + if (BlockMovementChecks.isBrittle(searchedState)) + continue; + + localVisited.add(searchPos); + if (!searchPos.equals(worldPosition)) + positions.add(searchPos); + + for (Direction offset : Iterate.directions) { + if (offset.getAxis() == axis) + continue; + if (searchPos.equals(worldPosition) && offset != facing) + continue; + if (BlockMovementChecks.isNotSupportive(searchedState, offset)) + continue; + + localFrontier.add(searchPos.relative(offset)); + } + } + } + + return positions; + } + + class ChassisScrollValueBehaviour extends BulkScrollValueBehaviour { + + public ChassisScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot, + Function> groupGetter) { + super(label, be, slot, groupGetter); + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + ImmutableList rows = ImmutableList.of(CreateLang.translateDirect("contraptions.chassis.distance")); + ValueSettingsFormatter formatter = + new ValueSettingsFormatter(vs -> new ValueSettings(vs.row(), vs.value() + 1).format()); + return new ValueSettingsBoard(label, max - 1, 1, rows, formatter); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void newSettingHovered(ValueSettings valueSetting) { + if (!level.isClientSide) + return; + if (!AllKeys.ctrlDown()) + currentlySelectedRange = valueSetting.value() + 1; + else + for (SmartBlockEntity be : getBulk()) + if (be instanceof ChassisBlockEntity cbe) + cbe.currentlySelectedRange = valueSetting.value() + 1; + ChassisRangeDisplay.display(ChassisBlockEntity.this); + } + + @Override + public void setValueSettings(Player player, ValueSettings vs, boolean ctrlHeld) { + super.setValueSettings(player, new ValueSettings(vs.row(), vs.value() + 1), ctrlHeld); + } + + @Override + public ValueSettings getValueSettings() { + ValueSettings vs = super.getValueSettings(); + return new ValueSettings(vs.row(), vs.value() - 1); + } + + @Override + public String getClipboardKey() { + return "Chassis"; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisRangeDisplay.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisRangeDisplay.java new file mode 100644 index 0000000000..3b9c1c23f3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/ChassisRangeDisplay.java @@ -0,0 +1,205 @@ +package com.simibubi.create.content.contraptions.chassis; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.mojang.datafixers.util.Pair; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllKeys; +import com.simibubi.create.AllSpecialTextures; + +import net.createmod.catnip.CatnipClient; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +public class ChassisRangeDisplay { + + private static final int DISPLAY_TIME = 200; + private static GroupEntry lastHoveredGroup = null; + + private static class Entry { + ChassisBlockEntity be; + int timer; + + public Entry(ChassisBlockEntity be) { + this.be = be; + timer = DISPLAY_TIME; + CatnipClient.OUTLINER.showCluster(getOutlineKey(), createSelection(be)) + .colored(0xFFFFFF) + .disableLineNormals() + .lineWidth(1 / 16f) + .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED); + } + + protected Object getOutlineKey() { + return Pair.of(be.getBlockPos(), 1); + } + + protected Set createSelection(ChassisBlockEntity chassis) { + Set positions = new HashSet<>(); + List includedBlockPositions = chassis.getIncludedBlockPositions(null, true); + if (includedBlockPositions == null) + return Collections.emptySet(); + positions.addAll(includedBlockPositions); + return positions; + } + + } + + private static class GroupEntry extends Entry { + + List includedBEs; + + public GroupEntry(ChassisBlockEntity be) { + super(be); + } + + @Override + protected Object getOutlineKey() { + return this; + } + + @Override + protected Set createSelection(ChassisBlockEntity chassis) { + Set list = new HashSet<>(); + includedBEs = be.collectChassisGroup(); + if (includedBEs == null) + return list; + for (ChassisBlockEntity chassisBlockEntity : includedBEs) + list.addAll(super.createSelection(chassisBlockEntity)); + return list; + } + + } + + static Map entries = new HashMap<>(); + static List groupEntries = new ArrayList<>(); + + public static void tick() { + Player player = Minecraft.getInstance().player; + Level world = Minecraft.getInstance().level; + boolean hasWrench = AllItems.WRENCH.isIn(player.getMainHandItem()); + + for (Iterator iterator = entries.keySet() + .iterator(); iterator.hasNext();) { + BlockPos pos = iterator.next(); + Entry entry = entries.get(pos); + if (tickEntry(entry, hasWrench)) + iterator.remove(); + CatnipClient.OUTLINER.keep(entry.getOutlineKey()); + } + + for (Iterator iterator = groupEntries.iterator(); iterator.hasNext();) { + GroupEntry group = iterator.next(); + if (tickEntry(group, hasWrench)) { + iterator.remove(); + if (group == lastHoveredGroup) + lastHoveredGroup = null; + } + CatnipClient.OUTLINER.keep(group.getOutlineKey()); + } + + if (!hasWrench) + return; + + HitResult over = Minecraft.getInstance().hitResult; + if (!(over instanceof BlockHitResult)) + return; + BlockHitResult ray = (BlockHitResult) over; + BlockPos pos = ray.getBlockPos(); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity == null || blockEntity.isRemoved()) + return; + if (!(blockEntity instanceof ChassisBlockEntity)) + return; + + boolean ctrl = AllKeys.ctrlDown(); + ChassisBlockEntity chassisBlockEntity = (ChassisBlockEntity) blockEntity; + + if (ctrl) { + GroupEntry existingGroupForPos = getExistingGroupForPos(pos); + if (existingGroupForPos != null) { + for (ChassisBlockEntity included : existingGroupForPos.includedBEs) + entries.remove(included.getBlockPos()); + existingGroupForPos.timer = DISPLAY_TIME; + return; + } + } + + if (!entries.containsKey(pos) || ctrl) + display(chassisBlockEntity); + else { + if (!ctrl) + entries.get(pos).timer = DISPLAY_TIME; + } + } + + private static boolean tickEntry(Entry entry, boolean hasWrench) { + ChassisBlockEntity chassisBlockEntity = entry.be; + Level beWorld = chassisBlockEntity.getLevel(); + Level world = Minecraft.getInstance().level; + + if (chassisBlockEntity.isRemoved() || beWorld == null || beWorld != world + || !world.isLoaded(chassisBlockEntity.getBlockPos())) { + return true; + } + + if (!hasWrench && entry.timer > 20) { + entry.timer = 20; + return false; + } + + entry.timer--; + if (entry.timer == 0) + return true; + return false; + } + + public static void display(ChassisBlockEntity chassis) { + + // Display a group and kill any selections of its contained chassis blocks + if (AllKeys.ctrlDown()) { + GroupEntry hoveredGroup = new GroupEntry(chassis); + + for (ChassisBlockEntity included : hoveredGroup.includedBEs) + CatnipClient.OUTLINER.remove(Pair.of(included.getBlockPos(), 1)); + + groupEntries.forEach(entry -> CatnipClient.OUTLINER.remove(entry.getOutlineKey())); + groupEntries.clear(); + entries.clear(); + groupEntries.add(hoveredGroup); + return; + } + + // Display an individual chassis and kill any group selections that contained it + BlockPos pos = chassis.getBlockPos(); + GroupEntry entry = getExistingGroupForPos(pos); + if (entry != null) + CatnipClient.OUTLINER.remove(entry.getOutlineKey()); + + groupEntries.clear(); + entries.clear(); + entries.put(pos, new Entry(chassis)); + + } + + private static GroupEntry getExistingGroupForPos(BlockPos pos) { + for (GroupEntry groupEntry : groupEntries) + for (ChassisBlockEntity chassis : groupEntry.includedBEs) + if (pos.equals(chassis.getBlockPos())) + return groupEntry; + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/LinearChassisBlock.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/chassis/LinearChassisBlock.java index 6545e64ec7..63c400bcee 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/LinearChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/LinearChassisBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; +package com.simibubi.create.content.contraptions.chassis; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/RadialChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/RadialChassisBlock.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/RadialChassisBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/chassis/RadialChassisBlock.java index 1c0888855e..f0f297c32a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/RadialChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/RadialChassisBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; +package com.simibubi.create.content.contraptions.chassis; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlock.java index 2d7d0244b9..d2f71a28ba 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlock.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; +package com.simibubi.create.content.contraptions.chassis; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.minecraft.core.BlockPos; @@ -26,7 +26,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.phys.Vec3; -public class StickerBlock extends WrenchableDirectionalBlock implements ITE { +public class StickerBlock extends WrenchableDirectionalBlock implements IBE { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public static final BooleanProperty EXTENDED = BlockStateProperties.EXTENDED; @@ -75,13 +75,13 @@ public class StickerBlock extends WrenchableDirectionalBlock implements ITE getTileEntityClass() { - return StickerTileEntity.class; + public Class getBlockEntityClass() { + return StickerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.STICKER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.STICKER.get(); } // Slime block stuff diff --git a/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlockEntity.java new file mode 100644 index 0000000000..43d3bf9a4d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerBlockEntity.java @@ -0,0 +1,102 @@ +package com.simibubi.create.content.contraptions.chassis; + +import java.util.List; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.glue.SuperGlueItem; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class StickerBlockEntity extends SmartBlockEntity { + + LerpedFloat piston; + boolean update; + + public StickerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + piston = LerpedFloat.linear(); + update = false; + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void initialize() { + super.initialize(); + if (!level.isClientSide) + return; + piston.startWithValue(isBlockStateExtended() ? 1 : 0); + } + + public boolean isBlockStateExtended() { + BlockState blockState = getBlockState(); + boolean extended = AllBlocks.STICKER.has(blockState) && blockState.getValue(StickerBlock.EXTENDED); + return extended; + } + + @Override + public void tick() { + super.tick(); + if (!level.isClientSide) + return; + piston.tickChaser(); + + if (isAttachedToBlock() && piston.getValue(0) != piston.getValue() && piston.getValue() == 1) { + SuperGlueItem.spawnParticles(level, worldPosition, getBlockState().getValue(StickerBlock.FACING), true); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(true)); + } + + if (!update) + return; + update = false; + int target = isBlockStateExtended() ? 1 : 0; + if (isAttachedToBlock() && target == 0 && piston.getChaseTarget() == 1) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(false)); + piston.chase(target, .4f, Chaser.LINEAR); + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + } + + public boolean isAttachedToBlock() { + BlockState blockState = getBlockState(); + if (!AllBlocks.STICKER.has(blockState)) + return false; + Direction direction = blockState.getValue(StickerBlock.FACING); + return SuperGlueEntity.isValidFace(level, worldPosition.relative(direction), direction.getOpposite()); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket) + update = true; + } + + @OnlyIn(Dist.CLIENT) + public void playSound(boolean attach) { + AllSoundEvents.SLIME_ADDED.play(level, Minecraft.getInstance().player, worldPosition, 0.35f, attach ? 0.75f : 0.2f); + } + + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerInstance.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/chassis/StickerInstance.java index ce923e75a9..4fe045dbd3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerInstance.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; +package com.simibubi.create.content.contraptions.chassis; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.math.AngleHelper; @@ -12,7 +12,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; import net.minecraft.util.Mth; -public class StickerInstance extends BlockEntityInstance implements DynamicInstance { +public class StickerInstance extends BlockEntityInstance implements DynamicInstance { float lastOffset = Float.NaN; final Direction facing; @@ -21,12 +21,12 @@ public class StickerInstance extends BlockEntityInstance impl private final ModelData head; - public StickerInstance(MaterialManager modelManager, StickerTileEntity tile) { - super(modelManager, tile); + public StickerInstance(MaterialManager materialManager, StickerBlockEntity blockEntity) { + super(materialManager, blockEntity); - head = getTransformMaterial().getModel(AllBlockPartials.STICKER_HEAD, blockState).createInstance(); + head = getTransformMaterial().getModel(AllPartialModels.STICKER_HEAD, blockState).createInstance(); - fakeWorld = tile.getLevel() != Minecraft.getInstance().level; + fakeWorld = blockEntity.getLevel() != Minecraft.getInstance().level; facing = blockState.getValue(StickerBlock.FACING); offset = blockState.getValue(StickerBlock.EXTENDED) ? 1 : 0; diff --git a/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerRenderer.java new file mode 100644 index 0000000000..7783bf126c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/chassis/StickerRenderer.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.chassis; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class StickerRenderer extends SafeBlockEntityRenderer { + + public StickerRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(StickerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + BlockState state = be.getBlockState(); + SuperByteBuffer head = CachedPartialBuffers.partial(AllPartialModels.STICKER_HEAD, state); + float offset = be.piston.getValue(WorldTickHolder.getPartialTicks(be.getLevel())); + + if (be.getLevel() != Minecraft.getInstance().level && !be.isVirtual()) + offset = state.getValue(StickerBlock.EXTENDED) ? 1 : 0; + + Direction facing = state.getValue(StickerBlock.FACING); + head.nudge(be.hashCode()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing) + 90) + .unCentre() + .translate(0, (offset * offset) * 4 / 16f, 0); + + head.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/AttachedActorBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/AttachedActorBlock.java deleted file mode 100644 index 4ec3b6aa1c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/AttachedActorBlock.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.utility.BlockHelper; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public abstract class AttachedActorBlock extends HorizontalDirectionalBlock implements IWrenchable { - - protected AttachedActorBlock(Properties p_i48377_1_) { - super(p_i48377_1_); - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - return InteractionResult.FAIL; - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - Direction direction = state.getValue(FACING); - return AllShapes.HARVESTER_BASE.get(direction); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(FACING); - super.createBlockStateDefinition(builder); - } - - @Override - public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { - Direction direction = state.getValue(FACING); - BlockPos offset = pos.relative(direction.getOpposite()); - return BlockHelper.hasBlockSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - Direction facing; - if (context.getClickedFace().getAxis().isVertical()) - facing = context.getHorizontalDirection().getOpposite(); - else { - BlockState blockState = - context.getLevel().getBlockState(context.getClickedPos().relative(context.getClickedFace().getOpposite())); - if (blockState.getBlock() instanceof AttachedActorBlock) - facing = blockState.getValue(FACING); - else - facing = context.getClickedFace(); - } - return defaultBlockState().setValue(FACING, facing); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java deleted file mode 100644 index e521fdfada..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.curiosities.bell.AbstractBellBlock; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; - -import net.minecraft.core.BlockPos; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.phys.Vec3; - -public class BellMovementBehaviour implements MovementBehaviour { - - @Override - public boolean renderAsNormalTileEntity() { - return true; - } - - @Override - public boolean isActive(MovementContext context) { - return !(context.contraption instanceof CarriageContraption); - } - - @Override - public void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) { - double dotProduct = oldMotion.dot(motion); - - if (dotProduct <= 0 && (context.relativeMotion.length() != 0) || context.firstMovement) - playSound(context); - } - - @Override - public void stopMoving(MovementContext context) { - if (context.position != null && isActive(context)) - playSound(context); - } - - public static void playSound(MovementContext context) { - Level world = context.world; - BlockPos pos = new BlockPos(context.position); - Block block = context.state.getBlock(); - - if (block instanceof AbstractBellBlock) { - ((AbstractBellBlock) block).playSound(world, pos); - } else { - // Vanilla bell sound - world.playSound(null, pos, SoundEvents.BELL_BLOCK, - SoundSource.BLOCKS, 2f, 1f); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java deleted file mode 100644 index 5aa22c9dce..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import java.util.concurrent.atomic.AtomicInteger; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.utility.BlockHelper; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.AirBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity { - - public static final AtomicInteger NEXT_BREAKER_ID = new AtomicInteger(); - protected int ticksUntilNextProgress; - protected int destroyProgress; - protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet(); - protected BlockPos breakingPos; - - public BlockBreakingKineticTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - if (destroyProgress == -1) - destroyNextTick(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (ticksUntilNextProgress == -1) - destroyNextTick(); - } - - public void destroyNextTick() { - ticksUntilNextProgress = 1; - } - - protected abstract BlockPos getBreakingPos(); - - protected boolean shouldRun() { - return true; - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("Progress", destroyProgress); - compound.putInt("NextTick", ticksUntilNextProgress); - if (breakingPos != null) - compound.put("Breaking", NbtUtils.writeBlockPos(breakingPos)); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - destroyProgress = compound.getInt("Progress"); - ticksUntilNextProgress = compound.getInt("NextTick"); - if (compound.contains("Breaking")) - breakingPos = NbtUtils.readBlockPos(compound.getCompound("Breaking")); - super.read(compound, clientPacket); - } - - @Override - public void setRemoved() { - if (!level.isClientSide && destroyProgress != 0) - level.destroyBlockProgress(breakerId, breakingPos, -1); - super.setRemoved(); - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) - return; - if (!shouldRun()) - return; - if (getSpeed() == 0) - return; - - breakingPos = getBreakingPos(); - - if (ticksUntilNextProgress < 0) - return; - if (ticksUntilNextProgress-- > 0) - return; - - BlockState stateToBreak = level.getBlockState(breakingPos); - float blockHardness = stateToBreak.getDestroySpeed(level, breakingPos); - - if (!canBreak(stateToBreak, blockHardness)) { - if (destroyProgress != 0) { - destroyProgress = 0; - level.destroyBlockProgress(breakerId, breakingPos, -1); - } - return; - } - - float breakSpeed = getBreakSpeed(); - destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); - level.playSound(null, worldPosition, stateToBreak.getSoundType() - .getHitSound(), SoundSource.NEUTRAL, .25f, 1); - - if (destroyProgress >= 10) { - onBlockBroken(stateToBreak); - destroyProgress = 0; - ticksUntilNextProgress = -1; - level.destroyBlockProgress(breakerId, breakingPos, -1); - return; - } - - ticksUntilNextProgress = (int) (blockHardness / breakSpeed); - level.destroyBlockProgress(breakerId, breakingPos, (int) destroyProgress); - } - - public boolean canBreak(BlockState stateToBreak, float blockHardness) { - return isBreakable(stateToBreak, blockHardness); - } - - public static boolean isBreakable(BlockState stateToBreak, float blockHardness) { - return !(stateToBreak.getMaterial() - .isLiquid() || stateToBreak.getBlock() instanceof AirBlock || blockHardness == -1); - } - - public void onBlockBroken(BlockState stateToBreak) { - Vec3 vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(breakingPos), level.random, .125f); - BlockHelper.destroyBlock(level, breakingPos, 1f, (stack) -> { - if (stack.isEmpty()) - return; - if (!level.getGameRules() - .getBoolean(GameRules.RULE_DOBLOCKDROPS)) - return; - if (level.restoringBlockSnapshots) - return; - - ItemEntity itementity = new ItemEntity(level, vec.x, vec.y, vec.z, stack); - itementity.setDefaultPickUpDelay(); - itementity.setDeltaMovement(Vec3.ZERO); - level.addFreshEntity(itementity); - }); - } - - protected float getBreakSpeed() { - return Math.abs(getSpeed() / 100f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java deleted file mode 100644 index a107be587a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/CampfireMovementBehaviour.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import java.util.Random; - -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; - -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.world.level.block.CampfireBlock; - -public class CampfireMovementBehaviour implements MovementBehaviour { - @Override - public boolean renderAsNormalTileEntity() { - return true; - } - - @Override - public void tick(MovementContext context) { - if (context.world == null || !context.world.isClientSide || context.position == null - || !context.state.getValue(CampfireBlock.LIT)) - return; - - // Mostly copied from CampfireBlock and CampfireTileEntity - Random random = context.world.random; - if (random.nextFloat() < 0.11F) { - for (int i = 0; i < random.nextInt(2) + 2; ++i) { - context.world.addAlwaysVisibleParticle( - context.state.getValue(CampfireBlock.SIGNAL_FIRE) ? ParticleTypes.CAMPFIRE_SIGNAL_SMOKE - : ParticleTypes.CAMPFIRE_COSY_SMOKE, - true, context.position.x() + random.nextDouble() / (random.nextBoolean() ? 3D : -3D), - context.position.y() + random.nextDouble() + random.nextDouble(), - context.position.z() + random.nextDouble() / (random.nextBoolean() ? 3D : -3D), 0.0D, 0.07D, - 0.0D); - } - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillBlock.java deleted file mode 100644 index 39915dcbcd..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillBlock.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SimpleWaterloggedBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.level.material.PushReaction; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class DrillBlock extends DirectionalKineticBlock implements ITE, SimpleWaterloggedBlock { - public static DamageSource damageSourceDrill = new DamageSource("create.mechanical_drill").bypassArmor(); - - public DrillBlock(Properties properties) { - super(properties); - registerDefaultState(super.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); - } - - @Override - public void entityInside(BlockState state, Level worldIn, BlockPos pos, Entity entityIn) { - if (entityIn instanceof ItemEntity) - return; - if (!new AABB(pos).deflate(.1f) - .intersects(entityIn.getBoundingBox())) - return; - withTileEntityDo(worldIn, pos, te -> { - if (te.getSpeed() == 0) - return; - entityIn.hurt(damageSourceDrill, (float) getDamage(te.getSpeed())); - }); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return AllShapes.CASING_12PX.get(state.getValue(FACING)); - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - withTileEntityDo(worldIn, pos, DrillTileEntity::destroyNextTick); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(FACING) - .getAxis(); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face == state.getValue(FACING) - .getOpposite(); - } - - @Override - public PushReaction getPistonPushReaction(BlockState state) { - return PushReaction.NORMAL; - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - public FluidState getFluidState(BlockState state) { - return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) : Fluids.EMPTY.defaultFluidState(); - } - - @Override - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(BlockStateProperties.WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, - LevelAccessor world, BlockPos pos, BlockPos neighbourPos) { - if (state.getValue(BlockStateProperties.WATERLOGGED)) - world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); - return state; - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - FluidState FluidState = context.getLevel().getFluidState(context.getClickedPos()); - return super.getStateForPlacement(context).setValue(BlockStateProperties.WATERLOGGED, Boolean.valueOf(FluidState.getType() == Fluids.WATER)); - } - - public static double getDamage(float speed) { - float speedAbs = Math.abs(speed); - double sub1 = Math.min(speedAbs / 16, 2); - double sub2 = Math.min(speedAbs / 32, 4); - double sub3 = Math.min(speedAbs / 64, 4); - return Mth.clamp(sub1 + sub2 + sub3, 1, 10); - } - - @Override - public Class getTileEntityClass() { - return DrillTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.DRILL.get(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java deleted file mode 100644 index cf949ebd48..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillInstance.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class DrillInstance extends SingleRotatingInstance { - - public DrillInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - BlockState referenceState = blockEntity.getBlockState(); - Direction facing = referenceState.getValue(BlockStateProperties.FACING); - return getRotatingMaterial().getModel(AllBlockPartials.DRILL_HEAD, referenceState, facing); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java deleted file mode 100644 index 729895524a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillMovementBehaviour.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.core.BlockPos; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { - - @Override - public boolean isActive(MovementContext context) { - return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(DrillBlock.FACING) - .getOpposite()); - } - - @Override - public Vec3 getActiveAreaOffset(MovementContext context) { - return Vec3.atLowerCornerOf(context.state.getValue(DrillBlock.FACING) - .getNormal()).scale(.65f); - } - - @Override - @OnlyIn(value = Dist.CLIENT) - public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - if (!ContraptionRenderDispatcher.canInstance()) - DrillRenderer.renderInContraption(context, renderWorld, matrices, buffer); - } - - @Override - public boolean hasSpecialInstancedRendering() { - return true; - } - - @Nullable - @Override - public ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, MovementContext context) { - return new DrillActorInstance(materialManager, simulationWorld, context); - } - - @Override - protected DamageSource getDamageSource() { - return DrillBlock.damageSourceDrill; - } - - @Override - public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { - return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) - .isEmpty() && !AllBlocks.TRACK.has(state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java deleted file mode 100644 index d429f261ae..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillRenderer.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; - -public class DrillRenderer extends KineticTileEntityRenderer { - - public DrillRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacing(AllBlockPartials.DRILL_HEAD, state); - } - - public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - BlockState state = context.state; - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllBlockPartials.DRILL_HEAD, state); - Direction facing = state.getValue(DrillBlock.FACING); - - float speed = (float) (context.contraption.stalled - || !VecHelper.isVecPointingTowards(context.relativeMotion, facing - .getOpposite()) ? context.getAnimationSpeed() : 0); - float time = AnimationTickHolder.getRenderTime() / 20; - float angle = (float) (((time * speed) % 360)); - - superBuffer - .transform(matrices.getModel()) - .centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(AngleHelper.verticalAngle(facing)) - .rotateZ(angle) - .unCentre() - .light(matrices.getWorld(), - ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); - - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillTileEntity.java deleted file mode 100644 index 8879fa80d2..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillTileEntity.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class DrillTileEntity extends BlockBreakingKineticTileEntity { - - public DrillTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected BlockPos getBreakingPos() { - return getBlockPos().relative(getBlockState().getValue(DrillBlock.FACING)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java deleted file mode 100644 index 517367a8dc..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterActorInstance.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.Vec3; - -public class HarvesterActorInstance extends ActorInstance { - static double oneOverRadius = 16.0 / 6.5; - static float originOffset = 1 / 16f; - static Vec3 rotOffset = new Vec3(0.5f, -2 * originOffset + 0.5f, originOffset + 0.5f); - - - ModelData harvester; - private Direction facing; - - private float horizontalAngle; - - private double rotation; - private double previousRotation; - - public HarvesterActorInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, MovementContext context) { - super(materialManager, simulationWorld, context); - - Material material = materialManager.defaultCutout() - .material(Materials.TRANSFORMED); - - BlockState state = context.state; - - facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING); - - harvester = material.getModel(AllBlockPartials.HARVESTER_BLADE, state).createInstance(); - - horizontalAngle = facing.toYRot() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0); - - harvester.setBlockLight(localBlockLight()); - } - - @Override - public void tick() { - super.tick(); - - previousRotation = rotation; - - if (context.contraption.stalled || VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite())) - return; - - double arcLength = context.motion.length(); - - double radians = arcLength * oneOverRadius; - - - - float deg = AngleHelper.deg(radians); - - deg = (float) (((int) (deg * 3000)) / 3000); - - rotation += deg * 1.25; - - rotation %= 360; - } - - @Override - public void beginFrame() { - harvester.loadIdentity() - .translate(context.localPos) - .centre() - .rotateY(horizontalAngle) - .unCentre() - .translate(rotOffset) - .rotateX(getRotation()) - .translateBack(rotOffset); - } - - private double getRotation() { - return AngleHelper.angleLerp(AnimationTickHolder.getPartialTicks(), previousRotation, rotation); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterBlock.java deleted file mode 100644 index b5f4fd5668..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterBlock.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.world.level.block.entity.BlockEntityType; - -public class HarvesterBlock extends AttachedActorBlock implements ITE { - - public HarvesterBlock(Properties p_i48377_1_) { - super(p_i48377_1_); - } - - @Override - public Class getTileEntityClass() { - return HarvesterTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.HARVESTER.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java deleted file mode 100644 index 09125719d5..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterRenderer.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; - -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class HarvesterRenderer extends SafeTileEntityRenderer { - - public HarvesterRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(HarvesterTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllBlockPartials.HARVESTER_BLADE, blockState); - transform(te.getLevel(), blockState.getValue(HarvesterBlock.FACING), superBuffer, - te.getAnimatedSpeed()); - superBuffer.light(light) - .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); - } - - public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffers) { - BlockState blockState = context.state; - Direction facing = blockState.getValue(HORIZONTAL_FACING); - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllBlockPartials.HARVESTER_BLADE, blockState); - float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()) - ? context.getAnimationSpeed() - : 0); - if (context.contraption.stalled) - speed = 0; - - superBuffer.transform(matrices.getModel()); - transform(context.world, facing, superBuffer, speed); - - superBuffer - .light(matrices.getWorld(), - ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), buffers.getBuffer(RenderType.cutoutMipped())); - } - - public static void transform(Level world, Direction facing, SuperByteBuffer superBuffer, float speed) { - float originOffset = 1 / 16f; - Vec3 rotOffset = new Vec3(0, -2 * originOffset, originOffset).add(VecHelper.getCenterOf(BlockPos.ZERO)); - float time = WorldTickHolder.getRenderTime(world) / 20; - float angle = (time * speed) % 360; - - superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing))) - .translate(rotOffset.x, rotOffset.y, rotOffset.z) - .rotate(Direction.WEST, AngleHelper.rad(angle)) - .translate(-rotOffset.x, -rotOffset.y, -rotOffset.z); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterTileEntity.java deleted file mode 100644 index 93dc35fa31..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/HarvesterTileEntity.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class HarvesterTileEntity extends CachedRenderBBTileEntity { - - // For simulations such as Ponder - private float manuallyAnimatedSpeed; - - public HarvesterTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition); - } - - public float getAnimatedSpeed() { - return manuallyAnimatedSpeed; - } - - public void setAnimatedSpeed(float speed) { - manuallyAnimatedSpeed = speed; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java deleted file mode 100644 index ec1b2ff608..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableFluidInterfaceTileEntity.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; - -public class PortableFluidInterfaceTileEntity extends PortableStorageInterfaceTileEntity { - - protected LazyOptional capability; - - public PortableFluidInterfaceTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - capability = createEmptyHandler(); - } - - @Override - public void startTransferringTo(Contraption contraption, float distance) { - LazyOptional oldcap = capability; - capability = LazyOptional.of(() -> new InterfaceFluidHandler(contraption.getSharedFluidTanks())); - oldcap.invalidate(); - super.startTransferringTo(contraption, distance); - } - - @Override - protected void invalidateCapability() { - capability.invalidate(); - } - - @Override - protected void stopTransferring() { - LazyOptional oldcap = capability; - capability = createEmptyHandler(); - oldcap.invalidate(); - super.stopTransferring(); - } - - private LazyOptional createEmptyHandler() { - return LazyOptional.of(() -> new InterfaceFluidHandler(new FluidTank(0))); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isFluidHandlerCap(cap)) - return capability.cast(); - return super.getCapability(cap, side); - } - - public class InterfaceFluidHandler implements IFluidHandler { - - private IFluidHandler wrapped; - - public InterfaceFluidHandler(IFluidHandler wrapped) { - this.wrapped = wrapped; - } - - @Override - public int getTanks() { - return wrapped.getTanks(); - } - - @Override - public FluidStack getFluidInTank(int tank) { - return wrapped.getFluidInTank(tank); - } - - @Override - public int getTankCapacity(int tank) { - return wrapped.getTankCapacity(tank); - } - - @Override - public boolean isFluidValid(int tank, FluidStack stack) { - return wrapped.isFluidValid(tank, stack); - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - if (!isConnected()) - return 0; - int fill = wrapped.fill(resource, action); - if (fill > 0 && action.execute()) - keepAlive(); - return fill; - } - - @Override - public FluidStack drain(FluidStack resource, FluidAction action) { - if (!canTransfer()) - return FluidStack.EMPTY; - FluidStack drain = wrapped.drain(resource, action); - if (!drain.isEmpty() && action.execute()) - keepAlive(); - return drain; - } - - @Override - public FluidStack drain(int maxDrain, FluidAction action) { - if (!canTransfer()) - return FluidStack.EMPTY; - FluidStack drain = wrapped.drain(maxDrain, action); - if (!drain.isEmpty() && action.execute()) - keepAlive(); - return drain; - } - - public void keepAlive() { - onContentTransferred(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java deleted file mode 100644 index d729c61800..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableItemInterfaceTileEntity.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.foundation.item.ItemHandlerWrapper; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; - -public class PortableItemInterfaceTileEntity extends PortableStorageInterfaceTileEntity { - - protected LazyOptional capability; - - public PortableItemInterfaceTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - capability = createEmptyHandler(); - } - - @Override - public void startTransferringTo(Contraption contraption, float distance) { - LazyOptional oldCap = capability; - capability = LazyOptional.of(() -> new InterfaceItemHandler(contraption.getSharedInventory())); - oldCap.invalidate(); - super.startTransferringTo(contraption, distance); - } - - @Override - protected void stopTransferring() { - LazyOptional oldCap = capability; - capability = createEmptyHandler(); - oldCap.invalidate(); - super.stopTransferring(); - } - - private LazyOptional createEmptyHandler() { - return LazyOptional.of(() -> new InterfaceItemHandler(new ItemStackHandler(0))); - } - - @Override - protected void invalidateCapability() { - capability.invalidate(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return capability.cast(); - return super.getCapability(cap, side); - } - - class InterfaceItemHandler extends ItemHandlerWrapper { - - public InterfaceItemHandler(IItemHandlerModifiable wrapped) { - super(wrapped); - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (!canTransfer()) - return ItemStack.EMPTY; - ItemStack extractItem = super.extractItem(slot, amount, simulate); - if (!simulate && !extractItem.isEmpty()) - onContentTransferred(); - return extractItem; - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (!canTransfer()) - return stack; - ItemStack insertItem = super.insertItem(slot, stack, simulate); - if (!simulate && !insertItem.equals(stack, false)) - onContentTransferred(); - return insertItem; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceRenderer.java deleted file mode 100644 index 30c2afdfce..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceRenderer.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import java.util.function.Consumer; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -public class PortableStorageInterfaceRenderer extends SafeTileEntityRenderer { - - public PortableStorageInterfaceRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(PortableStorageInterfaceTileEntity te, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) - return; - - BlockState blockState = te.getBlockState(); - float progress = te.getExtensionDistance(partialTicks); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - render(blockState, te.isConnected(), progress, null, sbb -> sbb.light(light) - .renderInto(ms, vb)); - } - - public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - BlockState blockState = context.state; - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - float renderPartialTicks = AnimationTickHolder.getPartialTicks(); - - LerpedFloat animation = PortableStorageInterfaceMovement.getAnimation(context); - float progress = animation.getValue(renderPartialTicks); - boolean lit = animation.settled(); - render(blockState, lit, progress, matrices.getModel(), - sbb -> sbb - .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), vb)); - } - - private static void render(BlockState blockState, boolean lit, float progress, PoseStack local, - Consumer drawCallback) { - SuperByteBuffer middle = CachedPartialBuffers.partial(getMiddleForState(blockState, lit), blockState); - SuperByteBuffer top = CachedPartialBuffers.partial(getTopForState(blockState), blockState); - - if (local != null) { - middle.transform(local); - top.transform(local); - } - Direction facing = blockState.getValue(PortableStorageInterfaceBlock.FACING); - rotateToFacing(middle, facing); - rotateToFacing(top, facing); - middle.translate(0, progress * 0.5f + 0.375f, 0); - top.translate(0, progress, 0); - - drawCallback.accept(middle); - drawCallback.accept(top); - } - - private static void rotateToFacing(SuperByteBuffer buffer, Direction facing) { - buffer.translate(.5f, .5f, .5f) - .rotate(Direction.Axis.Y, AngleHelper.horizontalAngle(facing)) - .rotate(Direction.Axis.X, facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .translate(-.5f, -.5f, -.5f); - } - - static PortableStorageInterfaceTileEntity getTargetPSI(MovementContext context) { - String _workingPos_ = PortableStorageInterfaceMovement._workingPos_; - if (!context.data.contains(_workingPos_)) - return null; - - BlockPos pos = NbtUtils.readBlockPos(context.data.getCompound(_workingPos_)); - BlockEntity tileEntity = context.world.getBlockEntity(pos); - if (!(tileEntity instanceof PortableStorageInterfaceTileEntity psi)) - return null; - - if (!psi.isTransferring()) - return null; - return psi; - } - - static PartialModel getMiddleForState(BlockState state, boolean lit) { - if (AllBlocks.PORTABLE_FLUID_INTERFACE.has(state)) - return lit ? AllBlockPartials.PORTABLE_FLUID_INTERFACE_MIDDLE_POWERED - : AllBlockPartials.PORTABLE_FLUID_INTERFACE_MIDDLE; - return lit ? AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE_POWERED - : AllBlockPartials.PORTABLE_STORAGE_INTERFACE_MIDDLE; - } - - static PartialModel getTopForState(BlockState state) { - if (AllBlocks.PORTABLE_FLUID_INTERFACE.has(state)) - return AllBlockPartials.PORTABLE_FLUID_INTERFACE_TOP; - return AllBlockPartials.PORTABLE_STORAGE_INTERFACE_TOP; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java deleted file mode 100644 index 8f540b1161..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceTileEntity.java +++ /dev/null @@ -1,202 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import java.util.List; - -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public abstract class PortableStorageInterfaceTileEntity extends SmartTileEntity { - - public static final int ANIMATION = 4; - protected int transferTimer; - protected float distance; - protected LerpedFloat connectionAnimation; - protected boolean powered; - protected Entity connectedEntity; - - public int keepAlive = 0; - - public PortableStorageInterfaceTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - transferTimer = 0; - connectionAnimation = LerpedFloat.linear() - .startWithValue(0); - powered = false; - } - - public void startTransferringTo(Contraption contraption, float distance) { - if (connectedEntity == contraption.entity) - return; - this.distance = Math.min(2, distance); - connectedEntity = contraption.entity; - startConnecting(); - notifyUpdate(); - } - - protected void stopTransferring() { - connectedEntity = null; - level.updateNeighborsAt(worldPosition, getBlockState().getBlock()); - } - - public boolean canTransfer() { - if (connectedEntity != null && !connectedEntity.isAlive()) - stopTransferring(); - return connectedEntity != null && isConnected(); - } - - @Override - public void initialize() { - super.initialize(); - powered = level.hasNeighborSignal(worldPosition); - if (!powered) - notifyContraptions(); - } - - protected abstract void invalidateCapability(); - - @Override - public void tick() { - super.tick(); - boolean wasConnected = isConnected(); - int timeUnit = getTransferTimeout(); - int animation = ANIMATION; - - if (keepAlive > 0) { - keepAlive--; - if (keepAlive == 0 && !level.isClientSide) { - stopTransferring(); - transferTimer = ANIMATION - 1; - sendData(); - return; - } - } - - transferTimer = Math.min(transferTimer, ANIMATION * 2 + getTransferTimeout()); - - boolean timerCanDecrement = transferTimer > ANIMATION || transferTimer > 0 && keepAlive == 0 - && (isVirtual() || !level.isClientSide || transferTimer != ANIMATION); - - if (timerCanDecrement && (!isVirtual() || transferTimer != timeUnit)) { - transferTimer--; - if (transferTimer == ANIMATION - 1) - sendData(); - if (transferTimer <= 0 || powered) - stopTransferring(); - } - - boolean isConnected = isConnected(); - if (wasConnected != isConnected && !level.isClientSide) - setChanged(); - - float progress = 0; - if (isConnected) - progress = 1; - else if (transferTimer >= timeUnit + animation) - progress = Mth.lerp((transferTimer - timeUnit - animation) / (float) animation, 1, 0); - else if (transferTimer < animation) - progress = Mth.lerp(transferTimer / (float) animation, 0, 1); - connectionAnimation.setValue(progress); - } - - @Override - public void setRemoved() { - super.setRemoved(); - invalidateCapability(); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - transferTimer = compound.getInt("Timer"); - distance = compound.getFloat("Distance"); - boolean poweredPreviously = powered; - powered = compound.getBoolean("Powered"); - if (clientPacket && powered != poweredPreviously && !powered) - notifyContraptions(); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.putInt("Timer", transferTimer); - compound.putFloat("Distance", distance); - compound.putBoolean("Powered", powered); - } - - public void neighbourChanged() { - boolean isBlockPowered = level.hasNeighborSignal(worldPosition); - if (isBlockPowered == powered) - return; - powered = isBlockPowered; - if (!powered) - notifyContraptions(); - if (powered) - stopTransferring(); - sendData(); - } - - private void notifyContraptions() { - level.getEntitiesOfClass(AbstractContraptionEntity.class, new AABB(worldPosition).inflate(3)) - .forEach(AbstractContraptionEntity::refreshPSIs); - } - - public boolean isPowered() { - return powered; - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); - } - - public boolean isTransferring() { - return transferTimer > ANIMATION; - } - - boolean isConnected() { - int timeUnit = getTransferTimeout(); - return transferTimer >= ANIMATION && transferTimer <= timeUnit + ANIMATION; - } - - float getExtensionDistance(float partialTicks) { - return (float) (Math.pow(connectionAnimation.getValue(partialTicks), 2) * distance / 2); - } - - float getConnectionDistance() { - return distance; - } - - public void startConnecting() { - transferTimer = getTransferTimeout() + ANIMATION * 2; - } - - public void onContentTransferred() { - int timeUnit = getTransferTimeout(); - transferTimer = timeUnit + ANIMATION; - award(AllAdvancements.PSI); - sendData(); - } - - protected Integer getTransferTimeout() { - return AllConfigs.SERVER.logistics.psiTimeout.get(); - } - - @Override - public void addBehaviours(List behaviours) { - registerAwardables(behaviours, AllAdvancements.PSI); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatInteractionBehaviour.java deleted file mode 100644 index 47e9beb0c0..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatInteractionBehaviour.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.simibubi.create.content.contraptions.components.actors; - -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; - -public class SeatInteractionBehaviour extends MovingInteractionBehaviour { - - @Override - public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, - AbstractContraptionEntity contraptionEntity) { - return false; - } - - @Override - public void handleEntityCollision(Entity entity, BlockPos localPos, AbstractContraptionEntity contraptionEntity) { - Contraption contraption = contraptionEntity.getContraption(); - int index = contraption.getSeats() - .indexOf(localPos); - if (index == -1) - return; - if (!SeatBlock.canBePickedUp(entity)) - return; - contraptionEntity.addSittingPassenger(entity, index); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/StorageInterfaceMovement.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/StorageInterfaceMovement.java deleted file mode 100644 index 93be485cbf..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/StorageInterfaceMovement.java +++ /dev/null @@ -1,157 +0,0 @@ -//package com.simibubi.create.content.contraptions.components.actors; -// -//import java.util.function.Predicate; -// -//import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -//import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -//import com.simibubi.create.content.logistics.block.transposer.TransposerBlock; -//import com.simibubi.create.content.logistics.block.transposer.TransposerTileEntity; -//import com.simibubi.create.foundation.config.AllConfigs; -//import com.simibubi.create.foundation.item.ItemHelper; -//import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -//import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -//import com.simibubi.create.foundation.tileEntity.behaviour.inventory.SingleTargetAutoExtractingBehaviour; -//import com.simibubi.create.foundation.utility.VecHelper; -// -//import net.minecraft.item.ItemStack; -//import net.minecraft.nbt.NBTUtil; -//import net.minecraft.tileentity.TileEntity; -//import net.minecraft.core.Direction; -//import net.minecraft.core.Direction.Axis; -//import net.minecraft.util.math.BlockPos; -//import net.minecraft.util.math.vector.Vector3d; -//import net.minecraft.world.World; -//import net.minecraftforge.items.IItemHandlerModifiable; -//import net.minecraftforge.items.ItemHandlerHelper; -// -//public class StorageInterfaceMovement extends MovementBehaviour { -// -// private static final String _exporting_ = "Exporting"; -// private static final String _delay_ = "Delay"; -// private static final String _workingPos_ = "WorkingPos"; -// -// @Override -// public Vector3d getActiveAreaOffset(MovementContext context) { -// return new Vector3d(context.state.get(PortableStorageInterfaceBlock.FACING).getDirectionVec()).scale(.85f); -// } -// -// @Override -// public void visitNewPosition(MovementContext context, BlockPos pos) { -// Direction currentFacing = getCurrentFacing(context); -// TransposerTileEntity transposer = getValidTransposer(context.world, pos, currentFacing.getAxis()); -// if (transposer == null) -// return; -// context.data.put(_workingPos_, NBTUtil.writeBlockPos(pos)); -// context.data.putBoolean(_exporting_, -// TransposerBlock.getBlockFacing(transposer.getBlockState()) != currentFacing); -// context.stall = true; -// } -// -// @Override -// public void tick(MovementContext context) { -// if (!context.data.contains(_workingPos_)) -// return; -// if (context.world.isRemote) -// return; -// -// BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_)); -// TransposerTileEntity transposer = getValidTransposer(context.world, pos, getCurrentFacing(context).getAxis()); -// if (transposer == null) { -// reset(context); -// return; -// } -// -// int nextExtract = context.data.getInt(_delay_); -// if (nextExtract > 0) { -// nextExtract--; -// context.data.putInt(_delay_, nextExtract); -// return; -// } -// -// boolean extract = context.data.getBoolean(_exporting_); -// boolean success = false; -// IItemHandlerModifiable inv = context.contraption.inventory; -// SingleTargetAutoExtractingBehaviour extracting = -// TileEntityBehaviour.get(transposer, SingleTargetAutoExtractingBehaviour.TYPE); -// FilteringBehaviour filtering = TileEntityBehaviour.get(transposer, FilteringBehaviour.TYPE); -// -// if (extract) { -// // Export from Contraption -// Predicate test = extracting.getFilterTest(); -// int exactAmount = extracting.getAmountFromFilter(); -// ItemStack itemExtracted = ItemStack.EMPTY; -// if (exactAmount != -1) -// itemExtracted = ItemHelper.extract(inv, test, exactAmount, false); -// else -// itemExtracted = ItemHelper.extract(inv, test, transposer::amountToExtract, false); -// -// if (!itemExtracted.isEmpty()) { -// transposer.onExtract(itemExtracted); -// success = exactAmount == -1; -// } -// -// } else { -// // Import to Contraption -// if (extracting != null) { -// extracting.setSynchronized(false); -// extracting.withAdditionalFilter(stack -> { -// if (filtering.anyAmount()) -// return true; -// return ItemHandlerHelper.insertItemStacked(inv, stack, true).isEmpty(); -// }); -// -// extracting.withAmountThreshold(stack -> { -// ItemStack tester = stack.copy(); -// tester.setCount(tester.getMaxStackSize()); -// return stack.getCount() - ItemHandlerHelper.insertItemStacked(inv, stack, true).getCount(); -// }); -// -// extracting.setCallback(stack -> { -// ItemHandlerHelper.insertItemStacked(inv, stack, false); -// }); -// -// success = extracting.extract() && filtering.anyAmount(); -// extracting.setSynchronized(true); -// transposer.applyFilteringCallbacks(); -// extracting.setCallback(transposer::onExtract); -// } -// } -// -// if (!success) { -// reset(context); -// return; -// } -// -// context.data.putInt(_delay_, AllConfigs.SERVER.logistics.extractorDelay.get()); -// } -// -// @Override -// public void stopMoving(MovementContext context) { -// reset(context); -// } -// -// public void reset(MovementContext context) { -// context.data.remove(_workingPos_); -// context.data.remove(_delay_); -// context.data.remove(_exporting_); -// context.stall = false; -// } -// -// private TransposerTileEntity getValidTransposer(World world, BlockPos pos, Axis validAxis) { -// TileEntity te = world.getTileEntity(pos); -// if (!(te instanceof TransposerTileEntity)) -// return null; -// if (TransposerBlock.getBlockFacing(world.getBlockState(pos)).getAxis() != validAxis) -// return null; -// if (world.isBlockPowered(pos)) -// return null; -// return (TransposerTileEntity) te; -// } -// -// private Direction getCurrentFacing(MovementContext context) { -// Vector3d directionVec = new Vector3d(context.state.get(PortableStorageInterfaceBlock.FACING).getDirectionVec()); -// directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z); -// return Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z); -// } -// -//} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/package-info.java deleted file mode 100644 index 1254030774..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/flwdata/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.simibubi.create.content.contraptions.components.actors.flwdata; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java deleted file mode 100644 index f0575b1a10..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockRenderer.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.simibubi.create.content.contraptions.components.clock; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity.Animation; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class CuckooClockRenderer extends KineticTileEntityRenderer { - - public CuckooClockRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - if (!(te instanceof CuckooClockTileEntity)) - return; - - CuckooClockTileEntity clock = (CuckooClockTileEntity) te; - BlockState blockState = te.getBlockState(); - Direction direction = blockState.getValue(CuckooClockBlock.HORIZONTAL_FACING); - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - // Render Hands - SuperByteBuffer hourHand = CachedPartialBuffers.partial(AllBlockPartials.CUCKOO_HOUR_HAND, blockState); - SuperByteBuffer minuteHand = CachedPartialBuffers.partial(AllBlockPartials.CUCKOO_MINUTE_HAND, blockState); - float hourAngle = clock.hourHand.getValue(partialTicks); - float minuteAngle = clock.minuteHand.getValue(partialTicks); - rotateHand(hourHand, hourAngle, direction).light(light) - .renderInto(ms, vb); - rotateHand(minuteHand, minuteAngle, direction).light(light) - .renderInto(ms, vb); - - // Doors - SuperByteBuffer leftDoor = CachedPartialBuffers.partial(AllBlockPartials.CUCKOO_LEFT_DOOR, blockState); - SuperByteBuffer rightDoor = CachedPartialBuffers.partial(AllBlockPartials.CUCKOO_RIGHT_DOOR, blockState); - float angle = 0; - float offset = 0; - - if (clock.animationType != null) { - float value = clock.animationProgress.getValue(partialTicks); - int step = clock.animationType == Animation.SURPRISE ? 3 : 15; - for (int phase = 30; phase <= 60; phase += step) { - float local = value - phase; - if (local < -step / 3) - continue; - else if (local < 0) - angle = Mth.lerp(((value - (phase - 5)) / 5), 0, 135); - else if (local < step / 3) - angle = 135; - else if (local < 2 * step / 3) - angle = Mth.lerp(((value - (phase + 5)) / 5), 135, 0); - - } - } - - rotateDoor(leftDoor, angle, true, direction).light(light) - .renderInto(ms, vb); - rotateDoor(rightDoor, angle, false, direction).light(light) - .renderInto(ms, vb); - - // Figure - if (clock.animationType != Animation.NONE) { - offset = -(angle / 135) * 1 / 2f + 10 / 16f; - PartialModel partialModel = (clock.animationType == Animation.PIG ? AllBlockPartials.CUCKOO_PIG : AllBlockPartials.CUCKOO_CREEPER); - SuperByteBuffer figure = - CachedPartialBuffers.partial(partialModel, blockState); - figure.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(direction.getCounterClockWise()))); - figure.translate(offset, 0, 0); - figure.light(light) - .renderInto(ms, vb); - } - - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, state, state - .getValue(CuckooClockBlock.HORIZONTAL_FACING) - .getOpposite()); - } - - private SuperByteBuffer rotateHand(SuperByteBuffer buffer, float angle, Direction facing) { - float pivotX = 2 / 16f; - float pivotY = 6 / 16f; - float pivotZ = 8 / 16f; - buffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getCounterClockWise()))); - buffer.translate(pivotX, pivotY, pivotZ); - buffer.rotate(Direction.EAST, AngleHelper.rad(angle)); - buffer.translate(-pivotX, -pivotY, -pivotZ); - return buffer; - } - - private SuperByteBuffer rotateDoor(SuperByteBuffer buffer, float angle, boolean left, Direction facing) { - float pivotX = 2 / 16f; - float pivotY = 0; - float pivotZ = (left ? 6 : 10) / 16f; - buffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getCounterClockWise()))); - buffer.translate(pivotX, pivotY, pivotZ); - buffer.rotate(Direction.UP, AngleHelper.rad(angle) * (left ? -1 : 1)); - buffer.translate(-pivotX, -pivotY, -pivotZ); - return buffer; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java deleted file mode 100644 index e86e9eeee9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.simibubi.create.content.contraptions.components.clock; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.level.Explosion; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class CuckooClockTileEntity extends KineticTileEntity { - - public static DamageSource CUCKOO_SURPRISE = new DamageSource("create.cuckoo_clock_explosion").setExplosion(); - - public LerpedFloat hourHand = LerpedFloat.angular(); - public LerpedFloat minuteHand = LerpedFloat.angular(); - public LerpedFloat animationProgress = LerpedFloat.linear(); - public Animation animationType; - private boolean sendAnimationUpdate; - - enum Animation { - PIG, CREEPER, SURPRISE, NONE; - } - - public CuckooClockTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - animationType = Animation.NONE; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.CUCKOO_CLOCK); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (clientPacket && compound.contains("Animation")) { - animationType = NBTHelper.readEnum(compound, "Animation", Animation.class); - animationProgress.startWithValue(0); - } - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (clientPacket && sendAnimationUpdate) - NBTHelper.writeEnum(compound, "Animation", animationType); - sendAnimationUpdate = false; - super.write(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - if (getSpeed() == 0) - return; - - - boolean isNatural = level.dimensionType().natural(); - int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); - int hours = (dayTime / 1000 + 6) % 24; - int minutes = (dayTime % 1000) * 60 / 1000; - - if (!isNatural) { - if (level.isClientSide) { - moveHands(hours, minutes); - - if (AnimationTickHolder.getTicks() % 6 == 0) - playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 2f); - else if (AnimationTickHolder.getTicks() % 3 == 0) - playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 1.5f); - } - return; - } - - if (!level.isClientSide) { - if (animationType == Animation.NONE) { - if (hours == 12 && minutes < 5) - startAnimation(Animation.PIG); - if (hours == 18 && minutes < 36 && minutes > 31) - startAnimation(Animation.CREEPER); - } else { - float value = animationProgress.getValue(); - animationProgress.setValue(value + 1); - if (value > 100) - animationType = Animation.NONE; - - if (animationType == Animation.SURPRISE && Mth.equal(animationProgress.getValue(), 50)) { - Vec3 center = VecHelper.getCenterOf(worldPosition); - level.destroyBlock(worldPosition, false); - level.explode(null, CUCKOO_SURPRISE, null, center.x, center.y, center.z, 3, false, - Explosion.BlockInteraction.BREAK); - } - - } - } - - if (level.isClientSide) { - moveHands(hours, minutes); - - if (animationType == Animation.NONE) { - if (AnimationTickHolder.getTicks() % 32 == 0) - playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 2f); - else if (AnimationTickHolder.getTicks() % 16 == 0) - playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 1.5f); - } else { - - boolean isSurprise = animationType == Animation.SURPRISE; - float value = animationProgress.getValue(); - animationProgress.setValue(value + 1); - if (value > 100) - animationType = null; - - // sounds - - if (value == 1) - playSound(SoundEvents.NOTE_BLOCK_CHIME, 2, .5f); - if (value == 21) - playSound(SoundEvents.NOTE_BLOCK_CHIME, 2, 0.793701f); - - if (value > 30 && isSurprise) { - Vec3 pos = VecHelper.offsetRandomly(VecHelper.getCenterOf(this.worldPosition), level.random, .5f); - level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y, pos.z, 0, 0, 0); - } - if (value == 40 && isSurprise) - playSound(SoundEvents.TNT_PRIMED, 1f, 1f); - - int step = isSurprise ? 3 : 15; - for (int phase = 30; phase <= 60; phase += step) { - if (value == phase - step / 3) - playSound(SoundEvents.CHEST_OPEN, 1 / 16f, 2f); - if (value == phase) { - if (animationType == Animation.PIG) - playSound(SoundEvents.PIG_AMBIENT, 1 / 4f, 1f); - else - playSound(SoundEvents.CREEPER_HURT, 1 / 4f, 3f); - } - if (value == phase + step / 3) - playSound(SoundEvents.CHEST_CLOSE, 1 / 16f, 2f); - - } - - } - - return; - } - } - - public void startAnimation(Animation animation) { - animationType = animation; - if (animation != null && CuckooClockBlock.containsSurprise(getBlockState())) - animationType = Animation.SURPRISE; - animationProgress.startWithValue(0); - sendAnimationUpdate = true; - - if (animation == Animation.CREEPER) - awardIfNear(AllAdvancements.CUCKOO_CLOCK, 32); - - sendData(); - } - - public void moveHands(int hours, int minutes) { - float hourTarget = (float) (360 / 12 * (hours % 12)); - float minuteTarget = (float) (360 / 60 * minutes); - - hourHand.chase(hourTarget, .2f, Chaser.EXP); - minuteHand.chase(minuteTarget, .2f, Chaser.EXP); - - hourHand.tickChaser(); - minuteHand.tickChaser(); - } - - private void playSound(SoundEvent sound, float volume, float pitch) { - Vec3 vec = VecHelper.getCenterOf(worldPosition); - level.playLocalSound(vec.x, vec.y, vec.z, sound, SoundSource.BLOCKS, volume, pitch, false); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterCTBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterCTBehaviour.java deleted file mode 100644 index 369d369084..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterCTBehaviour.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crafter; - -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; - -import org.jetbrains.annotations.Nullable; - -import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput; -import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; -import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -public class CrafterCTBehaviour extends ConnectedTextureBehaviour.Base { - - @Override - public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, - Direction face) { - if (state.getBlock() != other.getBlock()) - return false; - if (state.getValue(HORIZONTAL_FACING) != other.getValue(HORIZONTAL_FACING)) - return false; - - ConnectedInput input1 = CrafterHelper.getInput(reader, pos); - ConnectedInput input2 = CrafterHelper.getInput(reader, otherPos); - - if (input1 == null || input2 == null) - return false; - if (input1.data.isEmpty() || input2.data.isEmpty()) - return false; - try { - if (pos.offset(input1.data.get(0)) - .equals(otherPos.offset(input2.data.get(0)))) - return true; - } catch (IndexOutOfBoundsException e) { - // race condition. data somehow becomes empty between the last 2 if statements - } - - return false; - } - - @Override - protected boolean reverseUVs(BlockState state, Direction direction) { - if (!direction.getAxis() - .isVertical()) - return false; - Direction facing = state.getValue(HORIZONTAL_FACING); - if (facing.getAxis() == direction.getAxis()) - return false; - - boolean isNegative = facing.getAxisDirection() == AxisDirection.NEGATIVE; - if (direction == Direction.DOWN && facing.getAxis() == Axis.Z) - return !isNegative; - return isNegative; - } - - @Override - public CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite) { - Direction facing = state.getValue(HORIZONTAL_FACING); - boolean isFront = facing.getAxis() == direction.getAxis(); - boolean isVertical = direction.getAxis() - .isVertical(); - boolean facingX = facing.getAxis() == Axis.X; - return isFront ? AllSpriteShifts.CRAFTER_FRONT - : isVertical && !facingX ? AllSpriteShifts.CRAFTER_OTHERSIDE : AllSpriteShifts.CRAFTER_SIDE; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterHelper.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterHelper.java deleted file mode 100644 index d04f3449e0..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/CrafterHelper.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crafter; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.entity.BlockEntity; - -public class CrafterHelper { - - public static MechanicalCrafterTileEntity getCrafter(BlockAndTintGetter reader, BlockPos pos) { - BlockEntity te = reader.getBlockEntity(pos); - if (!(te instanceof MechanicalCrafterTileEntity)) - return null; - return (MechanicalCrafterTileEntity) te; - } - - public static ConnectedInputHandler.ConnectedInput getInput(BlockAndTintGetter reader, BlockPos pos) { - MechanicalCrafterTileEntity crafter = getCrafter(reader, pos); - return crafter == null ? null : crafter.input; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java deleted file mode 100644 index f0536efbfa..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterInstance.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crafter; - -import java.util.function.Supplier; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.core.Direction; - -public class MechanicalCrafterInstance extends SingleRotatingInstance { - - public MechanicalCrafterInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - Direction facing = blockState.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); - - return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, blockState, facing, rotateToFace(facing)); - } - - private Supplier rotateToFace(Direction facing) { - return () -> { - PoseStack stack = new PoseStack(); - TransformStack stacker = TransformStack.cast(stack) - .centre(); - - if (facing.getAxis() == Direction.Axis.X) stacker.rotateZ(90); - else if (facing.getAxis() == Direction.Axis.Z) stacker.rotateX(90); - - stacker.unCentre(); - return stack; - }; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java deleted file mode 100644 index 44d06a55f7..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterRenderer.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crafter; - -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; -import static com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer.standardKineticRotationTransform; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase; -import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Pointing; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class MechanicalCrafterRenderer extends SafeTileEntityRenderer { - - public MechanicalCrafterRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(MechanicalCrafterTileEntity te, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - ms.pushPose(); - Direction facing = te.getBlockState() - .getValue(HORIZONTAL_FACING); - Vec3 vec = Vec3.atLowerCornerOf(facing.getNormal()) - .scale(.58) - .add(.5, .5, .5); - - if (te.phase == Phase.EXPORTING) { - Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(te.getBlockState()); - float progress = - Mth.clamp((1000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); - vec = vec.add(Vec3.atLowerCornerOf(targetDirection.getNormal()) - .scale(progress * .75f)); - } - - ms.translate(vec.x, vec.y, vec.z); - ms.scale(1 / 2f, 1 / 2f, 1 / 2f); - float yRot = AngleHelper.horizontalAngle(facing); - ms.mulPose(Vector3f.YP.rotationDegrees(yRot)); - renderItems(te, partialTicks, ms, buffer, light, overlay); - ms.popPose(); - - renderFast(te, partialTicks, ms, buffer, light); - } - - public void renderItems(MechanicalCrafterTileEntity te, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - if (te.phase == Phase.IDLE) { - ItemStack stack = te.getInventory() - .getItem(0); - if (!stack.isEmpty()) { - ms.pushPose(); - ms.translate(0, 0, -1 / 256f); - ms.mulPose(Vector3f.YP.rotationDegrees(180)); - Minecraft.getInstance() - .getItemRenderer() - .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); - ms.popPose(); - } - } else { - // render grouped items - GroupedItems items = te.groupedItems; - float distance = .5f; - - ms.pushPose(); - - if (te.phase == Phase.CRAFTING) { - items = te.groupedItemsBeforeCraft; - items.calcStats(); - float progress = - Mth.clamp((2000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); - float earlyProgress = Mth.clamp(progress * 2, 0, 1); - float lateProgress = Mth.clamp(progress * 2 - 1, 0, 1); - - ms.scale(1 - lateProgress, 1 - lateProgress, 1 - lateProgress); - Vec3 centering = - new Vec3(-items.minX + (-items.width + 1) / 2f, -items.minY + (-items.height + 1) / 2f, 0) - .scale(earlyProgress); - ms.translate(centering.x * .5f, centering.y * .5f, 0); - distance += (-4 * (progress - .5f) * (progress - .5f) + 1) * .25f; - } - - boolean onlyRenderFirst = te.phase == Phase.INSERTING || te.phase == Phase.CRAFTING && te.countDown < 1000; - final float spacing = distance; - items.grid.forEach((pair, stack) -> { - if (onlyRenderFirst && (pair.getLeft() - .intValue() != 0 - || pair.getRight() - .intValue() != 0)) - return; - - ms.pushPose(); - Integer x = pair.getKey(); - Integer y = pair.getValue(); - ms.translate(x * spacing, y * spacing, 0); - - int offset = 0; - if (te.phase == Phase.EXPORTING && te.getBlockState().hasProperty(MechanicalCrafterBlock.POINTING)) { - Pointing value = te.getBlockState().getValue(MechanicalCrafterBlock.POINTING); - offset = value == Pointing.UP ? -1 : value == Pointing.LEFT ? 2 : value == Pointing.RIGHT ? -2 : 1; - } - - TransformStack.cast(ms) - .rotateY(180) - .translate(0, 0, (x + y * 3 + offset * 9) / 1024f ); - Minecraft.getInstance() - .getItemRenderer() - .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); - ms.popPose(); - }); - - ms.popPose(); - - if (te.phase == Phase.CRAFTING) { - items = te.groupedItems; - float progress = - Mth.clamp((1000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); - float earlyProgress = Mth.clamp(progress * 2, 0, 1); - float lateProgress = Mth.clamp(progress * 2 - 1, 0, 1); - - ms.mulPose(Vector3f.ZP.rotationDegrees(earlyProgress * 2 * 360)); - float upScaling = earlyProgress * 1.125f; - float downScaling = 1 + (1 - lateProgress) * .125f; - ms.scale(upScaling, upScaling, upScaling); - ms.scale(downScaling, downScaling, downScaling); - - items.grid.forEach((pair, stack) -> { - if (pair.getLeft() - .intValue() != 0 - || pair.getRight() - .intValue() != 0) - return; - ms.pushPose(); - ms.mulPose(Vector3f.YP.rotationDegrees(180)); - Minecraft.getInstance() - .getItemRenderer() - .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); - ms.popPose(); - }); - } - - } - } - - public void renderFast(MechanicalCrafterTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light) { - BlockState blockState = te.getBlockState(); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - if (!Backend.canUseInstancing(te.getLevel())) { - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllBlockPartials.SHAFTLESS_COGWHEEL, blockState); - standardKineticRotationTransform(superBuffer, te, light); - superBuffer.rotateCentered(Direction.UP, (float) (blockState.getValue(HORIZONTAL_FACING) - .getAxis() != Direction.Axis.X ? 0 : Math.PI / 2)); - superBuffer.rotateCentered(Direction.EAST, (float) (Math.PI / 2)); - superBuffer.renderInto(ms, vb); - } - - Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(blockState); - BlockPos pos = te.getBlockPos(); - - if ((te.covered || te.phase != Phase.IDLE) && te.phase != Phase.CRAFTING && te.phase != Phase.INSERTING) { - SuperByteBuffer lidBuffer = renderAndTransform(AllBlockPartials.MECHANICAL_CRAFTER_LID, blockState); - lidBuffer.light(light) - .renderInto(ms, vb); - } - - if (MechanicalCrafterBlock.isValidTarget(te.getLevel(), pos.relative(targetDirection), blockState)) { - SuperByteBuffer beltBuffer = renderAndTransform(AllBlockPartials.MECHANICAL_CRAFTER_BELT, blockState); - SuperByteBuffer beltFrameBuffer = - renderAndTransform(AllBlockPartials.MECHANICAL_CRAFTER_BELT_FRAME, blockState); - - if (te.phase == Phase.EXPORTING) { - int textureIndex = (int) ((te.getCountDownSpeed() / 128f * AnimationTickHolder.getTicks())); - beltBuffer.shiftUVtoSheet(AllSpriteShifts.CRAFTER_THINGIES, (textureIndex % 4) / 4f, 0, 1); - } - - beltBuffer.light(light) - .renderInto(ms, vb); - beltFrameBuffer.light(light) - .renderInto(ms, vb); - - } else { - SuperByteBuffer arrowBuffer = renderAndTransform(AllBlockPartials.MECHANICAL_CRAFTER_ARROW, blockState); - arrowBuffer.light(light) - .renderInto(ms, vb); - } - - } - - private SuperByteBuffer renderAndTransform(PartialModel renderBlock, BlockState crafterState) { - SuperByteBuffer buffer = CachedPartialBuffers.partial(renderBlock, crafterState); - float xRot = crafterState.getValue(MechanicalCrafterBlock.POINTING) - .getXRotation(); - float yRot = AngleHelper.horizontalAngle(crafterState.getValue(HORIZONTAL_FACING)); - buffer.rotateCentered(Direction.UP, (float) ((yRot + 90) / 180 * Math.PI)); - buffer.rotateCentered(Direction.EAST, (float) ((xRot) / 180 * Math.PI)); - return buffer; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java deleted file mode 100644 index bebeb26538..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java +++ /dev/null @@ -1,542 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crafter; - -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map.Entry; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput; -import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.BlockFace; -import net.createmod.catnip.utility.Pointing; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; - -public class MechanicalCrafterTileEntity extends KineticTileEntity { - - enum Phase { - IDLE, ACCEPTING, ASSEMBLING, EXPORTING, WAITING, CRAFTING, INSERTING; - } - - public static class Inventory extends SmartInventory { - - private MechanicalCrafterTileEntity te; - - public Inventory(MechanicalCrafterTileEntity te) { - super(1, te, 1, false); - this.te = te; - forbidExtraction(); - whenContentsChanged(slot -> { - if (getItem(slot).isEmpty()) - return; - if (te.phase == Phase.IDLE) - te.checkCompletedRecipe(false); - }); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (te.phase != Phase.IDLE) - return stack; - if (te.covered) - return stack; - ItemStack insertItem = super.insertItem(slot, stack, simulate); - if (insertItem.getCount() != stack.getCount() && !simulate) - te.getLevel() - .playSound(null, te.getBlockPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .5f); - return insertItem; - } - - } - - protected Inventory inventory; - protected GroupedItems groupedItems = new GroupedItems(); - protected ConnectedInput input = new ConnectedInput(); - protected LazyOptional invSupplier = - LazyOptional.of(() -> input.getItemHandler(level, worldPosition)); - protected boolean reRender; - protected Phase phase; - protected int countDown; - protected boolean covered; - protected boolean wasPoweredBefore; - - protected GroupedItems groupedItemsBeforeCraft; // for rendering on client - private InvManipulationBehaviour inserting; - private EdgeInteractionBehaviour connectivity; - - private ItemStack scriptedResult = ItemStack.EMPTY; - - public MechanicalCrafterTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(20); - phase = Phase.IDLE; - groupedItemsBeforeCraft = new GroupedItems(); - inventory = new Inventory(this); - - // Does not get serialized due to active checking in tick - wasPoweredBefore = true; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - inserting = new InvManipulationBehaviour(this, this::getTargetFace); - connectivity = new EdgeInteractionBehaviour(this, ConnectedInputHandler::toggleConnection) - .connectivity(ConnectedInputHandler::shouldConnect) - .require(AllItems.WRENCH.get()); - behaviours.add(inserting); - behaviours.add(connectivity); - registerAwardables(behaviours, AllAdvancements.CRAFTER, AllAdvancements.CRAFTER_LAZY); - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - if (!Mth.equal(getSpeed(), 0)) { - award(AllAdvancements.CRAFTER); - if (Math.abs(getSpeed()) < 5) - award(AllAdvancements.CRAFTER_LAZY); - } - } - - public void blockChanged() { - removeBehaviour(InvManipulationBehaviour.TYPE); - inserting = new InvManipulationBehaviour(this, this::getTargetFace); - attachBehaviourLate(inserting); - } - - public BlockFace getTargetFace(Level world, BlockPos pos, BlockState state) { - return new BlockFace(pos, MechanicalCrafterBlock.getTargetDirection(state)); - } - - public Direction getTargetDirection() { - return MechanicalCrafterBlock.getTargetDirection(getBlockState()); - } - - @Override - public void writeSafe(CompoundTag compound) { - super.writeSafe(compound); - if (input == null) - return; - - CompoundTag inputNBT = new CompoundTag(); - input.write(inputNBT); - compound.put("ConnectedInput", inputNBT); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.put("Inventory", inventory.serializeNBT()); - - CompoundTag inputNBT = new CompoundTag(); - input.write(inputNBT); - compound.put("ConnectedInput", inputNBT); - - CompoundTag groupedItemsNBT = new CompoundTag(); - groupedItems.write(groupedItemsNBT); - compound.put("GroupedItems", groupedItemsNBT); - - compound.putString("Phase", phase.name()); - compound.putInt("CountDown", countDown); - compound.putBoolean("Cover", covered); - - super.write(compound, clientPacket); - - if (clientPacket && reRender) { - compound.putBoolean("Redraw", true); - reRender = false; - } - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - Phase phaseBefore = phase; - GroupedItems before = this.groupedItems; - - inventory.deserializeNBT(compound.getCompound("Inventory")); - input.read(compound.getCompound("ConnectedInput")); - groupedItems = GroupedItems.read(compound.getCompound("GroupedItems")); - phase = Phase.IDLE; - String name = compound.getString("Phase"); - for (Phase phase : Phase.values()) - if (phase.name() - .equals(name)) - this.phase = phase; - countDown = compound.getInt("CountDown"); - covered = compound.getBoolean("Cover"); - super.read(compound, clientPacket); - if (!clientPacket) - return; - if (compound.contains("Redraw")) - level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); - if (phaseBefore != phase && phase == Phase.CRAFTING) - groupedItemsBeforeCraft = before; - if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) { - Direction facing = getBlockState().getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); - Vec3 vec = Vec3.atLowerCornerOf(facing.getNormal()) - .scale(.75) - .add(VecHelper.getCenterOf(worldPosition)); - Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState()); - vec = vec.add(Vec3.atLowerCornerOf(targetDirection.getNormal()) - .scale(1)); - level.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0); - } - } - - @Override - public void setRemoved() { - invSupplier.invalidate(); - super.setRemoved(); - } - - public int getCountDownSpeed() { - if (getSpeed() == 0) - return 0; - return Mth.clamp((int) Math.abs(getSpeed()), 4, 250); - } - - @Override - public void tick() { - super.tick(); - - if (phase == Phase.ACCEPTING) - return; - - boolean onClient = level.isClientSide; - boolean runLogic = !onClient || isVirtual(); - - if (wasPoweredBefore != level.hasNeighborSignal(worldPosition)) { - wasPoweredBefore = level.hasNeighborSignal(worldPosition); - if (wasPoweredBefore) { - if (!runLogic) - return; - checkCompletedRecipe(true); - } - } - - if (phase == Phase.ASSEMBLING) { - countDown -= getCountDownSpeed(); - if (countDown < 0) { - countDown = 0; - if (!runLogic) - return; - if (RecipeGridHandler.getTargetingCrafter(this) != null) { - phase = Phase.EXPORTING; - countDown = 1000; - sendData(); - return; - } - - ItemStack result = - isVirtual() ? scriptedResult : RecipeGridHandler.tryToApplyRecipe(level, groupedItems); - - if (result != null) { - List containers = new ArrayList<>(); - groupedItems.grid.values() - .forEach(stack -> { - if (stack.hasContainerItem()) - containers.add(stack.getContainerItem() - .copy()); - }); - - if (isVirtual()) - groupedItemsBeforeCraft = groupedItems; - - groupedItems = new GroupedItems(result); - for (int i = 0; i < containers.size(); i++) { - ItemStack stack = containers.get(i); - GroupedItems container = new GroupedItems(); - container.grid.put(Pair.of(i, 0), stack); - container.mergeOnto(groupedItems, Pointing.LEFT); - } - - phase = Phase.CRAFTING; - countDown = 2000; - sendData(); - return; - } - ejectWholeGrid(); - return; - } - } - - if (phase == Phase.EXPORTING) { - countDown -= getCountDownSpeed(); - - if (countDown < 0) { - countDown = 0; - if (!runLogic) - return; - - MechanicalCrafterTileEntity targetingCrafter = RecipeGridHandler.getTargetingCrafter(this); - if (targetingCrafter == null) { - ejectWholeGrid(); - return; - } - - Pointing pointing = getBlockState().getValue(MechanicalCrafterBlock.POINTING); - groupedItems.mergeOnto(targetingCrafter.groupedItems, pointing); - groupedItems = new GroupedItems(); - - float pitch = targetingCrafter.groupedItems.grid.size() * 1 / 16f + .5f; - AllSoundEvents.CRAFTER_CLICK.playOnServer(level, worldPosition, 1, pitch); - - phase = Phase.WAITING; - countDown = 0; - sendData(); - targetingCrafter.continueIfAllPrecedingFinished(); - targetingCrafter.sendData(); - return; - } - } - - if (phase == Phase.CRAFTING) { - - if (onClient) { - Direction facing = getBlockState().getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); - float progress = countDown / 2000f; - Vec3 facingVec = Vec3.atLowerCornerOf(facing.getNormal()); - Vec3 vec = facingVec.scale(.65) - .add(VecHelper.getCenterOf(worldPosition)); - Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .125f) - .multiply(VecHelper.axisAlingedPlaneOf(facingVec)) - .normalize() - .scale(progress * .5f) - .add(vec); - if (progress > .5f) - level.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0); - - if (!groupedItemsBeforeCraft.grid.isEmpty() && progress < .5f) { - if (groupedItems.grid.containsKey(Pair.of(0, 0))) { - ItemStack stack = groupedItems.grid.get(Pair.of(0, 0)); - groupedItemsBeforeCraft = new GroupedItems(); - - for (int i = 0; i < 10; i++) { - Vec3 randVec = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .125f) - .multiply(VecHelper.axisAlingedPlaneOf(facingVec)) - .normalize() - .scale(.25f); - Vec3 offset2 = randVec.add(vec); - randVec = randVec.scale(.35f); - level.addParticle(new ItemParticleOption(ParticleTypes.ITEM, stack), offset2.x, offset2.y, - offset2.z, randVec.x, randVec.y, randVec.z); - } - } - } - } - - int prev = countDown; - countDown -= getCountDownSpeed(); - - if (countDown < 1000 && prev >= 1000) { - AllSoundEvents.CRAFTER_CLICK.playOnServer(level, worldPosition, 1, 2); - AllSoundEvents.CRAFTER_CRAFT.playOnServer(level, worldPosition); - } - - if (countDown < 0) { - countDown = 0; - if (!runLogic) - return; - tryInsert(); - return; - } - } - - if (phase == Phase.INSERTING) { - if (runLogic && isTargetingBelt()) - tryInsert(); - return; - } - } - - protected boolean isTargetingBelt() { - DirectBeltInputBehaviour behaviour = getTargetingBelt(); - return behaviour != null && behaviour.canInsertFromSide(getTargetDirection()); - } - - protected DirectBeltInputBehaviour getTargetingBelt() { - BlockPos targetPos = worldPosition.relative(getTargetDirection()); - return TileEntityBehaviour.get(level, targetPos, DirectBeltInputBehaviour.TYPE); - } - - public void tryInsert() { - if (!inserting.hasInventory() && !isTargetingBelt()) { - ejectWholeGrid(); - return; - } - - boolean chagedPhase = phase != Phase.INSERTING; - final List> inserted = new LinkedList<>(); - - DirectBeltInputBehaviour behaviour = getTargetingBelt(); - for (Entry, ItemStack> entry : groupedItems.grid.entrySet()) { - Pair pair = entry.getKey(); - ItemStack stack = entry.getValue(); - BlockFace face = getTargetFace(level, worldPosition, getBlockState()); - - ItemStack remainder = behaviour == null ? inserting.insert(stack.copy()) - : behaviour.handleInsertion(stack, face.getFace(), false); - if (!remainder.isEmpty()) { - stack.setCount(remainder.getCount()); - continue; - } - - inserted.add(pair); - } - - inserted.forEach(groupedItems.grid::remove); - if (groupedItems.grid.isEmpty()) - ejectWholeGrid(); - else - phase = Phase.INSERTING; - if (!inserted.isEmpty() || chagedPhase) - sendData(); - } - - public void ejectWholeGrid() { - List chain = RecipeGridHandler.getAllCraftersOfChain(this); - if (chain == null) - return; - chain.forEach(MechanicalCrafterTileEntity::eject); - } - - public void eject() { - BlockState blockState = getBlockState(); - boolean present = AllBlocks.MECHANICAL_CRAFTER.has(blockState); - Vec3 vec = present ? Vec3.atLowerCornerOf(blockState.getValue(HORIZONTAL_FACING) - .getNormal()) - .scale(.75f) : Vec3.ZERO; - Vec3 ejectPos = VecHelper.getCenterOf(worldPosition) - .add(vec); - groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack)); - if (!inventory.getItem(0) - .isEmpty()) - dropItem(ejectPos, inventory.getItem(0)); - phase = Phase.IDLE; - groupedItems = new GroupedItems(); - inventory.setStackInSlot(0, ItemStack.EMPTY); - sendData(); - } - - public void dropItem(Vec3 ejectPos, ItemStack stack) { - ItemEntity itemEntity = new ItemEntity(level, ejectPos.x, ejectPos.y, ejectPos.z, stack); - itemEntity.setDefaultPickUpDelay(); - level.addFreshEntity(itemEntity); - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (level.isClientSide && !isVirtual()) - return; - if (phase == Phase.IDLE && craftingItemPresent()) - checkCompletedRecipe(false); - if (phase == Phase.INSERTING) - tryInsert(); - } - - public boolean craftingItemPresent() { - return !inventory.getItem(0) - .isEmpty(); - } - - public boolean craftingItemOrCoverPresent() { - return !inventory.getItem(0) - .isEmpty() || covered; - } - - protected void checkCompletedRecipe(boolean poweredStart) { - if (getSpeed() == 0) - return; - if (level.isClientSide && !isVirtual()) - return; - List chain = RecipeGridHandler.getAllCraftersOfChainIf(this, - poweredStart ? MechanicalCrafterTileEntity::craftingItemPresent - : MechanicalCrafterTileEntity::craftingItemOrCoverPresent, - poweredStart); - if (chain == null) - return; - chain.forEach(MechanicalCrafterTileEntity::begin); - } - - protected void begin() { - phase = Phase.ACCEPTING; - groupedItems = new GroupedItems(inventory.getItem(0)); - inventory.setStackInSlot(0, ItemStack.EMPTY); - if (RecipeGridHandler.getPrecedingCrafters(this) - .isEmpty()) { - phase = Phase.ASSEMBLING; - countDown = 500; - } - sendData(); - } - - protected void continueIfAllPrecedingFinished() { - List preceding = RecipeGridHandler.getPrecedingCrafters(this); - if (preceding == null) { - ejectWholeGrid(); - return; - } - - for (MechanicalCrafterTileEntity mechanicalCrafterTileEntity : preceding) - if (mechanicalCrafterTileEntity.phase != Phase.WAITING) - return; - - phase = Phase.ASSEMBLING; - countDown = Math.max(100, getCountDownSpeed() + 1); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return invSupplier.cast(); - return super.getCapability(cap, side); - } - - public void connectivityChanged() { - reRender = true; - sendData(); - invSupplier.invalidate(); - invSupplier = LazyOptional.of(() -> input.getItemHandler(level, worldPosition)); - } - - public Inventory getInventory() { - return inventory; - } - - public void setScriptedResult(ItemStack scriptedResult) { - this.scriptedResult = scriptedResult; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java deleted file mode 100644 index 7eacbb4542..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankInstance.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crank; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class HandCrankInstance extends SingleRotatingInstance implements DynamicInstance { - - private final HandCrankTileEntity tile; - private ModelData crank; - private Direction facing; - - public HandCrankInstance(MaterialManager modelManager, HandCrankTileEntity tile) { - super(modelManager, tile); - this.tile = tile; - - Block block = blockState.getBlock(); - PartialModel renderedHandle = null; - if (block instanceof HandCrankBlock) - renderedHandle = ((HandCrankBlock) block).getRenderedHandle(); - if (renderedHandle == null) - return; - - facing = blockState.getValue(BlockStateProperties.FACING); - Direction opposite = facing.getOpposite(); - Instancer model = getTransformMaterial().getModel(renderedHandle, blockState, opposite); - crank = model.createInstance(); - - rotateCrank(); - } - - @Override - public void beginFrame() { - if (crank == null) return; - - rotateCrank(); - } - - private void rotateCrank() { - Direction.Axis axis = facing.getAxis(); - float angle = (tile.independentAngle + AnimationTickHolder.getPartialTicks() * tile.chasingVelocity) / 360; - - crank.loadIdentity() - .translate(getInstancePosition()) - .centre() - .rotate(Direction.get(Direction.AxisDirection.POSITIVE, axis), angle) - .unCentre(); - } - - @Override - public void remove() { - super.remove(); - if (crank != null) crank.delete(); - } - - @Override - public void updateLight() { - super.updateLight(); - if (crank != null) relight(pos, crank); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java deleted file mode 100644 index 6ca4e53090..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankRenderer.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crank; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class HandCrankRenderer extends KineticTileEntityRenderer { - - public HandCrankRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState state = te.getBlockState(); - Block block = state.getBlock(); - PartialModel renderedHandle = null; - if (block instanceof HandCrankBlock) - renderedHandle = ((HandCrankBlock) block).getRenderedHandle(); - if (renderedHandle == null) - return; - - Direction facing = state.getValue(FACING); - SuperByteBuffer handle = CachedPartialBuffers.partialFacing(renderedHandle, state, facing.getOpposite()); - HandCrankTileEntity crank = (HandCrankTileEntity) te; - kineticRotationTransform(handle, te, facing.getAxis(), - (crank.independentAngle + partialTicks * crank.chasingVelocity) / 360, light); - handle.renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java deleted file mode 100644 index 534f9aec86..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crank; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class HandCrankTileEntity extends GeneratingKineticTileEntity { - - public int inUse; - public boolean backwards; - public float independentAngle; - public float chasingVelocity; - - public HandCrankTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - public void turn(boolean back) { - boolean update = false; - - if (getGeneratedSpeed() == 0 || back != backwards) - update = true; - - inUse = 10; - this.backwards = back; - if (update && !level.isClientSide) - updateGeneratedRotation(); - } - - @Override - public float getGeneratedSpeed() { - Block block = getBlockState().getBlock(); - if (!(block instanceof HandCrankBlock)) - return 0; - HandCrankBlock crank = (HandCrankBlock) block; - int speed = (inUse == 0 ? 0 : backwards ? -1 : 1) * crank.getRotationSpeed(); - return convertToDirection(speed, getBlockState().getValue(HandCrankBlock.FACING)); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("InUse", inUse); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - inUse = compound.getInt("InUse"); - super.read(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - - float actualSpeed = getSpeed(); - chasingVelocity += ((actualSpeed * 10 / 3f) - chasingVelocity) * .25f; - independentAngle += chasingVelocity; - - if (inUse > 0) { - inUse--; - - if (inUse == 0 && !level.isClientSide) - updateGeneratedRotation(); - } - } - - @Override - protected Block getStressConfigKey() { - return AllBlocks.HAND_CRANK.get(); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - super.tickAudio(); - if (inUse > 0 && AnimationTickHolder.getTicks() % 10 == 0) { - if (!AllBlocks.HAND_CRANK.has(getBlockState())) - return; - AllSoundEvents.CRANKING.playAt(level, worldPosition, (inUse) / 2.5f, .65f + (10 - inUse) / 10f, true); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/ValveHandleBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/ValveHandleBlock.java deleted file mode 100644 index 9666c0e461..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/ValveHandleBlock.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crank; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.utility.BlockHelper; - -import net.createmod.catnip.utility.Couple; -import net.minecraft.core.BlockPos; -import net.minecraft.core.NonNullList; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@ParametersAreNonnullByDefault -public class ValveHandleBlock extends HandCrankBlock { - - private final DyeColor color; - private final boolean inCreativeTab; - - public static ValveHandleBlock copper(Properties properties) { - return new ValveHandleBlock(properties, null, true); - } - - public static ValveHandleBlock dyed(Properties properties, DyeColor color) { - return new ValveHandleBlock(properties, color, false); - } - - private ValveHandleBlock(Properties properties, DyeColor color, boolean inCreativeTab) { - super(properties); - this.color = color; - this.inCreativeTab = inCreativeTab; - } - - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult hit) { - ItemStack heldItem = player.getItemInHand(hand); - DyeColor color = DyeColor.getColor(heldItem); - if (color != null && color != this.color) { - if (world.isClientSide) - return InteractionResult.SUCCESS; - BlockState newState = BlockHelper.copyProperties(state, AllBlocks.DYED_VALVE_HANDLES.get(color).getDefaultState()); - world.setBlockAndUpdate(pos, newState); - return InteractionResult.SUCCESS; - } - - return super.use(state, world, pos, player, hand, hit); - } - - @Override - public void fillItemCategory(CreativeModeTab group, NonNullList p_149666_2_) { - if (group != CreativeModeTab.TAB_SEARCH && !inCreativeTab) - return; - super.fillItemCategory(group, p_149666_2_); - } - - @Override - @OnlyIn(Dist.CLIENT) - public PartialModel getRenderedHandle() { - return null; - } - - @Override - public int getRotationSpeed() { - return 16; - } - - public static Couple getSpeedRange() { - return Couple.create(16, 16); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/AbstractCrushingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/AbstractCrushingRecipe.java deleted file mode 100644 index ec8c290d47..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/AbstractCrushingRecipe.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crusher; - -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; -import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo; - -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public abstract class AbstractCrushingRecipe extends ProcessingRecipe { - - public AbstractCrushingRecipe(IRecipeTypeInfo recipeType, ProcessingRecipeParams params) { - super(recipeType, params); - } - - @Override - protected int getMaxInputCount() { - return 1; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java deleted file mode 100644 index cff2190d0a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java +++ /dev/null @@ -1,375 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crusher; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.UUID; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingInventory; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.sound.SoundScapes; -import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.BlockParticleOption; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class CrushingWheelControllerTileEntity extends SmartTileEntity { - - public Entity processingEntity; - private UUID entityUUID; - protected boolean searchForEntity; - - public ProcessingInventory inventory; - protected LazyOptional handler = LazyOptional.of(() -> inventory); - private RecipeWrapper wrapper; - public float crushingspeed; - - public CrushingWheelControllerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inventory = new ProcessingInventory(this::itemInserted) { - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return super.isItemValid(slot, stack) && processingEntity == null; - } - - }; - wrapper = new RecipeWrapper(inventory); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)); - } - - private boolean supportsDirectBeltInput(Direction side) { - BlockState blockState = getBlockState(); - if (blockState == null) - return false; - Direction direction = blockState.getValue(CrushingWheelControllerBlock.FACING); - return direction == Direction.DOWN || direction == side; - } - - @Override - public void tick() { - super.tick(); - if (searchForEntity) { - searchForEntity = false; - List search = level.getEntities((Entity) null, new AABB(getBlockPos()), - e -> entityUUID.equals(e.getUUID())); - if (search.isEmpty()) - clear(); - else - processingEntity = search.get(0); - } - - if (!isOccupied()) - return; - if (crushingspeed == 0) - return; - - if (level.isClientSide) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio()); - - float speed = crushingspeed * 4; - - Vec3 centerPos = VecHelper.getCenterOf(worldPosition); - Direction facing = getBlockState().getValue(CrushingWheelControllerBlock.FACING); - int offset = facing.getAxisDirection() - .getStep(); - Vec3 outSpeed = new Vec3((facing.getAxis() == Axis.X ? 0.25D : 0.0D) * offset, - offset == 1 ? (facing.getAxis() == Axis.Y ? 0.5D : 0.0D) : 0.0D // Increased upwards speed so upwards - // crushing wheels shoot out the item - // properly. - , (facing.getAxis() == Axis.Z ? 0.25D : 0.0D) * offset); // No downwards speed, so downwards crushing wheels - // drop the items as before. - Vec3 outPos = centerPos.add((facing.getAxis() == Axis.X ? .55f * offset : 0f), - (facing.getAxis() == Axis.Y ? .55f * offset : 0f), (facing.getAxis() == Axis.Z ? .55f * offset : 0f)); - - if (!hasEntity()) { - - float processingSpeed = - Mth.clamp((speed) / (!inventory.appliedRecipe ? Mth.log2(inventory.getStackInSlot(0) - .getCount()) : 1), .25f, 20); - inventory.remainingTime -= processingSpeed; - spawnParticles(inventory.getStackInSlot(0)); - - if (level.isClientSide) - return; - - if (inventory.remainingTime < 20 && !inventory.appliedRecipe) { - applyRecipe(); - inventory.appliedRecipe = true; - level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); - return; - } - - if (inventory.remainingTime > 0) { - return; - } - inventory.remainingTime = 0; - - // Output Items - if (facing != Direction.UP) { - BlockPos nextPos = worldPosition.offset(facing.getAxis() == Axis.X ? 1f * offset : 0f, (-1f), - facing.getAxis() == Axis.Z ? 1f * offset : 0f); - DirectBeltInputBehaviour behaviour = - TileEntityBehaviour.get(level, nextPos, DirectBeltInputBehaviour.TYPE); - if (behaviour != null) { - boolean changed = false; - if (!behaviour.canInsertFromSide(facing)) - return; - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stack = inventory.getStackInSlot(slot); - if (stack.isEmpty()) - continue; - ItemStack remainder = behaviour.handleInsertion(stack, facing, false); - if (remainder.equals(stack, false)) - continue; - inventory.setStackInSlot(slot, remainder); - changed = true; - } - if (changed) { - setChanged(); - sendData(); - } - return; - } - } - - // Eject Items - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stack = inventory.getStackInSlot(slot); - if (stack.isEmpty()) - continue; - ItemEntity entityIn = new ItemEntity(level, outPos.x, outPos.y, outPos.z, stack); - entityIn.setDeltaMovement(outSpeed); - entityIn.getPersistentData() - .put("BypassCrushingWheel", NbtUtils.writeBlockPos(worldPosition)); - level.addFreshEntity(entityIn); - } - inventory.clear(); - level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); - - return; - } - - if (!processingEntity.isAlive() || !processingEntity.getBoundingBox() - .intersects(new AABB(worldPosition).inflate(.5f))) { - clear(); - return; - } - - double xMotion = ((worldPosition.getX() + .5f) - processingEntity.getX()) / 2f; - double zMotion = ((worldPosition.getZ() + .5f) - processingEntity.getZ()) / 2f; - if (processingEntity.isShiftKeyDown()) - xMotion = zMotion = 0; - double movement = Math.max(-speed / 4f, -.5f) * -offset; - processingEntity.setDeltaMovement( - new Vec3(facing.getAxis() == Axis.X ? movement : xMotion, facing.getAxis() == Axis.Y ? movement : 0f // Do - // not - // move - // entities - // upwards - // or - // downwards - // for - // horizontal - // crushers, - , facing.getAxis() == Axis.Z ? movement : zMotion)); // Or they'll only get their feet crushed. - - if (level.isClientSide) - return; - - if (!(processingEntity instanceof ItemEntity)) { - Vec3 entityOutPos = outPos.add(facing.getAxis() == Axis.X ? .5f * offset : 0f, - facing.getAxis() == Axis.Y ? .5f * offset : 0f, facing.getAxis() == Axis.Z ? .5f * offset : 0f); - int crusherDamage = AllConfigs.SERVER.kinetics.crushingDamage.get(); - - if (processingEntity instanceof LivingEntity) { - if ((((LivingEntity) processingEntity).getHealth() - crusherDamage <= 0) // Takes LivingEntity instances - // as exception, so it can - // move them before it would - // kill them. - && (((LivingEntity) processingEntity).hurtTime <= 0)) { // This way it can actually output the items - // to the right spot. - processingEntity.setPos(entityOutPos.x, entityOutPos.y, entityOutPos.z); - } - } - processingEntity.hurt(CrushingWheelTileEntity.DAMAGE_SOURCE, crusherDamage); - if (!processingEntity.isAlive()) { - processingEntity.setPos(entityOutPos.x, entityOutPos.y, entityOutPos.z); - } - return; - } - - ItemEntity itemEntity = (ItemEntity) processingEntity; - itemEntity.setPickUpDelay(20); - if (facing.getAxis() == Axis.Y) { - if (processingEntity.getY() * -offset < (centerPos.y - .25f) * -offset) { - intakeItem(itemEntity); - } - } else if (facing.getAxis() == Axis.Z) { - if (processingEntity.getZ() * -offset < (centerPos.z - .25f) * -offset) { - intakeItem(itemEntity); - } - } else { - if (processingEntity.getX() * -offset < (centerPos.x - .25f) * -offset) { - intakeItem(itemEntity); - } - } - } - - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - float pitch = Mth.clamp((crushingspeed / 256f) + .45f, .85f, 1f); - if (entityUUID == null && inventory.getStackInSlot(0) - .isEmpty()) - return; - SoundScapes.play(AmbienceGroup.CRUSHING, worldPosition, pitch); - } - - private void intakeItem(ItemEntity itemEntity) { - inventory.clear(); - inventory.setStackInSlot(0, itemEntity.getItem() - .copy()); - itemInserted(inventory.getStackInSlot(0)); - itemEntity.discard(); - level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); - } - - protected void spawnParticles(ItemStack stack) { - if (stack == null || stack.isEmpty()) - return; - - ParticleOptions particleData = null; - if (stack.getItem() instanceof BlockItem) - particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() - .defaultBlockState()); - else - particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); - - Random r = level.random; - for (int i = 0; i < 4; i++) - level.addParticle(particleData, worldPosition.getX() + r.nextFloat(), worldPosition.getY() + r.nextFloat(), - worldPosition.getZ() + r.nextFloat(), 0, 0, 0); - } - - private void applyRecipe() { - Optional> recipe = findRecipe(); - - List list = new ArrayList<>(); - if (recipe.isPresent()) { - int rolls = inventory.getStackInSlot(0) - .getCount(); - inventory.clear(); - for (int roll = 0; roll < rolls; roll++) { - List rolledResults = recipe.get() - .rollResults(); - for (int i = 0; i < rolledResults.size(); i++) { - ItemStack stack = rolledResults.get(i); - ItemHelper.addToList(stack, list); - } - } - for (int slot = 0; slot < list.size() && slot + 1 < inventory.getSlots(); slot++) - inventory.setStackInSlot(slot + 1, list.get(slot)); - } else { - inventory.clear(); - } - - } - - public Optional> findRecipe() { - Optional> crushingRecipe = AllRecipeTypes.CRUSHING.find(wrapper, level); - if (!crushingRecipe.isPresent()) - crushingRecipe = AllRecipeTypes.MILLING.find(wrapper, level); - return crushingRecipe; - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (hasEntity()) - compound.put("Entity", NbtUtils.createUUID(entityUUID)); - compound.put("Inventory", inventory.serializeNBT()); - compound.putFloat("Speed", crushingspeed); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (compound.contains("Entity") && !isOccupied()) { - entityUUID = NbtUtils.loadUUID(NBTHelper.getINBT(compound, "Entity")); - this.searchForEntity = true; - } - crushingspeed = compound.getFloat("Speed"); - inventory.deserializeNBT(compound.getCompound("Inventory")); - } - - public void startCrushing(Entity entity) { - processingEntity = entity; - entityUUID = entity.getUUID(); - } - - private void itemInserted(ItemStack stack) { - Optional> recipe = findRecipe(); - inventory.remainingTime = recipe.isPresent() ? recipe.get() - .getProcessingDuration() : 100; - inventory.appliedRecipe = false; - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return handler.cast(); - return super.getCapability(cap, side); - } - - public void clear() { - processingEntity = null; - entityUUID = null; - } - - public boolean isOccupied() { - return hasEntity() || !inventory.isEmpty(); - } - - public boolean hasEntity() { - return processingEntity != null; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java deleted file mode 100644 index 8cf82d834f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelTileEntity.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.simibubi.create.content.contraptions.components.crusher; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.living.LivingDropsEvent; -import net.minecraftforge.event.entity.living.LootingLevelEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber -public class CrushingWheelTileEntity extends KineticTileEntity { - - public static final DamageSource DAMAGE_SOURCE = new DamageSource("create.crush").bypassArmor() - .setScalesWithDifficulty(); - - public CrushingWheelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(20); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.CRUSHING_WHEEL, AllAdvancements.CRUSHER_MAXED); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - fixControllers(); - } - - public void fixControllers() { - for (Direction d : Iterate.directions) - ((CrushingWheelBlock) getBlockState().getBlock()).updateControllers(getBlockState(), getLevel(), getBlockPos(), - d); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).inflate(1); - } - - @Override - public void lazyTick() { - super.lazyTick(); - fixControllers(); - } - - @SubscribeEvent - public static void crushingIsFortunate(LootingLevelEvent event) { - if (event.getDamageSource() != DAMAGE_SOURCE) - return; - event.setLootingLevel(2); //This does not currently increase mob drops. It seems like this only works for damage done by an entity. - } - - @SubscribeEvent - public static void handleCrushedMobDrops(LivingDropsEvent event) { - if (event.getSource() != CrushingWheelTileEntity.DAMAGE_SOURCE) - return; - Vec3 outSpeed = Vec3.ZERO; - for (ItemEntity outputItem : event.getDrops()) { - outputItem.setDeltaMovement(outSpeed); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/BeltDeployerCallbacks.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/BeltDeployerCallbacks.java deleted file mode 100644 index 82b69aa972..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/BeltDeployerCallbacks.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import java.util.List; -import java.util.stream.Collectors; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.State; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.processing.ItemApplicationRecipe; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.advancement.CreateAdvancement; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.items.ItemHandlerHelper; - -public class BeltDeployerCallbacks { - - public static ProcessingResult onItemReceived(TransportedItemStack s, TransportedItemStackHandlerBehaviour i, - DeployerTileEntity deployerTileEntity) { - - if (deployerTileEntity.getSpeed() == 0) - return ProcessingResult.PASS; - if (deployerTileEntity.mode == Mode.PUNCH) - return ProcessingResult.PASS; - BlockState blockState = deployerTileEntity.getBlockState(); - if (!blockState.hasProperty(FACING) || blockState.getValue(FACING) != Direction.DOWN) - return ProcessingResult.PASS; - if (deployerTileEntity.state != State.WAITING) - return ProcessingResult.HOLD; - if (deployerTileEntity.redstoneLocked) - return ProcessingResult.PASS; - - DeployerFakePlayer player = deployerTileEntity.getPlayer(); - ItemStack held = player == null ? ItemStack.EMPTY : player.getMainHandItem(); - - if (held.isEmpty()) - return ProcessingResult.HOLD; - if (deployerTileEntity.getRecipe(s.stack) == null) - return ProcessingResult.PASS; - - deployerTileEntity.start(); - return ProcessingResult.HOLD; - } - - public static ProcessingResult whenItemHeld(TransportedItemStack s, TransportedItemStackHandlerBehaviour i, - DeployerTileEntity deployerTileEntity) { - - if (deployerTileEntity.getSpeed() == 0) - return ProcessingResult.PASS; - BlockState blockState = deployerTileEntity.getBlockState(); - if (!blockState.hasProperty(FACING) || blockState.getValue(FACING) != Direction.DOWN) - return ProcessingResult.PASS; - - DeployerFakePlayer player = deployerTileEntity.getPlayer(); - ItemStack held = player == null ? ItemStack.EMPTY : player.getMainHandItem(); - if (held.isEmpty()) - return ProcessingResult.HOLD; - - Recipe recipe = deployerTileEntity.getRecipe(s.stack); - if (recipe == null) - return ProcessingResult.PASS; - - if (deployerTileEntity.state == State.RETRACTING && deployerTileEntity.timer == 1000) { - activate(s, i, deployerTileEntity, recipe); - return ProcessingResult.HOLD; - } - - if (deployerTileEntity.state == State.WAITING) { - if (deployerTileEntity.redstoneLocked) - return ProcessingResult.PASS; - deployerTileEntity.start(); - } - - return ProcessingResult.HOLD; - } - - public static void activate(TransportedItemStack transported, TransportedItemStackHandlerBehaviour handler, - DeployerTileEntity deployerTileEntity, Recipe recipe) { - - List collect = - InWorldProcessing.applyRecipeOn(ItemHandlerHelper.copyStackWithSize(transported.stack, 1), recipe) - .stream() - .map(stack -> { - TransportedItemStack copy = transported.copy(); - boolean centered = BeltHelper.isItemUpright(stack); - copy.stack = stack; - copy.locked = true; - copy.angle = centered ? 180 : Create.RANDOM.nextInt(360); - return copy; - }) - .map(t -> { - t.locked = false; - return t; - }) - .collect(Collectors.toList()); - - deployerTileEntity.award(AllAdvancements.DEPLOYER); - - TransportedItemStack left = transported.copy(); - deployerTileEntity.player.spawnedItemEffects = transported.stack.copy(); - left.stack.shrink(1); - ItemStack resultItem = null; - - if (collect.isEmpty()) { - resultItem = left.stack.copy(); - handler.handleProcessingOnItem(transported, TransportedResult.convertTo(left)); - } else { - resultItem = collect.get(0).stack.copy(); - handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(collect, left)); - } - - ItemStack heldItem = deployerTileEntity.player.getMainHandItem(); - boolean unbreakable = heldItem.hasTag() && heldItem.getTag() - .getBoolean("Unbreakable"); - boolean keepHeld = - recipe instanceof ItemApplicationRecipe && ((ItemApplicationRecipe) recipe).shouldKeepHeldItem(); - - if (!unbreakable && !keepHeld) { - if (heldItem.isDamageableItem()) - heldItem.hurtAndBreak(1, deployerTileEntity.player, - s -> s.broadcastBreakEvent(InteractionHand.MAIN_HAND)); - else - heldItem.shrink(1); - } - - if (resultItem != null && !resultItem.isEmpty()) - awardAdvancements(deployerTileEntity, resultItem); - - BlockPos pos = deployerTileEntity.getBlockPos(); - Level world = deployerTileEntity.getLevel(); - if (heldItem.isEmpty()) - world.playSound(null, pos, SoundEvents.ITEM_BREAK, SoundSource.BLOCKS, .25f, 1); - world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, .25f, .75f); - if (recipe instanceof SandPaperPolishingRecipe) - AllSoundEvents.SANDING_SHORT.playOnServer(world, pos, .35f, 1f); - - deployerTileEntity.sendData(); - } - - private static void awardAdvancements(DeployerTileEntity deployerTileEntity, ItemStack created) { - CreateAdvancement advancement = null; - - if (AllBlocks.ANDESITE_CASING.isIn(created)) - advancement = AllAdvancements.ANDESITE_CASING; - else if (AllBlocks.BRASS_CASING.isIn(created)) - advancement = AllAdvancements.BRASS_CASING; - else if (AllBlocks.COPPER_CASING.isIn(created)) - advancement = AllAdvancements.COPPER_CASING; - else if (AllBlocks.RAILWAY_CASING.isIn(created)) - advancement = AllAdvancements.TRAIN_CASING; - else - return; - - deployerTileEntity.award(advancement); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerBlock.java deleted file mode 100644 index 24d2ee65b1..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerBlock.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllItems; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.components.AssemblyOperatorUseContext; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.PushReaction; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class DeployerBlock extends DirectionalAxisKineticBlock implements ITE { - - public DeployerBlock(Properties properties) { - super(properties); - } - - @Override - public PushReaction getPistonPushReaction(BlockState state) { - return PushReaction.NORMAL; - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return AllShapes.CASING_12PX.get(state.getValue(FACING)); - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - if (context.getClickedFace() == state.getValue(FACING)) { - if (!context.getLevel().isClientSide) - withTileEntityDo(context.getLevel(), context.getClickedPos(), DeployerTileEntity::changeMode); - return InteractionResult.SUCCESS; - } - return super.onWrenched(state, context); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.hasBlockEntity() && state.getBlock() != newState.getBlock()) { - withTileEntityDo(worldIn, pos, te -> { - if (te.player != null && !isMoving) { - te.player.getInventory() - .dropAll(); - te.overflowItems.forEach(itemstack -> te.player.drop(itemstack, true, false)); - te.player.discard(); - te.player = null; - } - }); - - TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE); - worldIn.removeBlockEntity(pos); - } - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - ItemStack heldByPlayer = player.getItemInHand(handIn) - .copy(); - if (AllItems.WRENCH.isIn(heldByPlayer)) - return InteractionResult.PASS; - - if (hit.getDirection() != state.getValue(FACING)) - return InteractionResult.PASS; - if (worldIn.isClientSide) - return InteractionResult.SUCCESS; - - withTileEntityDo(worldIn, pos, te -> { - ItemStack heldByDeployer = te.player.getMainHandItem() - .copy(); - if (heldByDeployer.isEmpty() && heldByPlayer.isEmpty()) - return; - - player.setItemInHand(handIn, heldByDeployer); - te.player.setItemInHand(InteractionHand.MAIN_HAND, heldByPlayer); - te.sendData(); - }); - - return InteractionResult.SUCCESS; - } - - @Override - public Class getTileEntityClass() { - return DeployerTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.DEPLOYER.get(); - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, world, pos, oldState, isMoving); - withTileEntityDo(world, pos, DeployerTileEntity::redstoneUpdate); - } - - @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, - boolean p_220069_6_) { - withTileEntityDo(world, pos, DeployerTileEntity::redstoneUpdate); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - protected Direction getFacingForPlacement(BlockPlaceContext context) { - if (context instanceof AssemblyOperatorUseContext) - return Direction.DOWN; - else - return super.getFacingForPlacement(context); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFakePlayer.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFakePlayer.java deleted file mode 100644 index dbe1859804..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFakePlayer.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import java.util.OptionalInt; -import java.util.UUID; - -import org.apache.commons.lang3.tuple.Pair; - -import com.mojang.authlib.GameProfile; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CKinetics; -import com.simibubi.create.foundation.utility.CreateLang; - -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import net.minecraft.core.BlockPos; -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.PacketFlow; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.network.ServerGamePacketListenerImpl; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.EntityDamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.Pose; -import net.minecraft.world.entity.monster.Creeper; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.util.FakePlayer; -import net.minecraftforge.event.entity.EntityEvent; -import net.minecraftforge.event.entity.living.LivingDropsEvent; -import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; -import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber -public class DeployerFakePlayer extends FakePlayer { - - private static final Connection NETWORK_MANAGER = new Connection(PacketFlow.CLIENTBOUND); - public static final GameProfile DEPLOYER_PROFILE = - new GameProfile(UUID.fromString("9e2faded-cafe-4ec2-c314-dad129ae971d"), "Deployer"); - Pair blockBreakingProgress; - ItemStack spawnedItemEffects; - public boolean placedTracks; - public boolean onMinecartContraption; - - public DeployerFakePlayer(ServerLevel world) { - super(world, DEPLOYER_PROFILE); - connection = new FakePlayNetHandler(world.getServer(), this); - } - - @Override - public OptionalInt openMenu(MenuProvider container) { - return OptionalInt.empty(); - } - - @Override - public Component getDisplayName() { - return CreateLang.translateDirect("block.deployer.damage_source_name"); - } - - @Override - @OnlyIn(Dist.CLIENT) - public float getEyeHeight(Pose poseIn) { - return 0; - } - - @Override - public Vec3 position() { - return new Vec3(getX(), getY(), getZ()); - } - - @Override - public float getCurrentItemAttackStrengthDelay() { - return 1 / 64f; - } - - @Override - public boolean canEat(boolean ignoreHunger) { - return false; - } - - @Override - public ItemStack eat(Level world, ItemStack stack) { - stack.shrink(1); - return stack; - } - - @SubscribeEvent - public static void deployerHasEyesOnHisFeet(EntityEvent.Size event) { - if (event.getEntity() instanceof DeployerFakePlayer) - event.setNewEyeHeight(0); - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) { - if (!(event.getSource() instanceof EntityDamageSource)) - return; - EntityDamageSource source = (EntityDamageSource) event.getSource(); - Entity trueSource = source.getEntity(); - if (trueSource != null && trueSource instanceof DeployerFakePlayer) { - DeployerFakePlayer fakePlayer = (DeployerFakePlayer) trueSource; - event.getDrops() - .forEach(stack -> fakePlayer.getInventory() - .placeItemBackInInventory(stack.getItem())); - event.setCanceled(true); - } - } - - @Override - protected void equipEventAndSound(ItemStack p_147219_) {} - - @Override - public void remove(RemovalReason p_150097_) { - if (blockBreakingProgress != null && !level.isClientSide) - level.destroyBlockProgress(getId(), blockBreakingProgress.getKey(), -1); - super.remove(p_150097_); - } - - @SubscribeEvent - public static void deployerKillsDoNotSpawnXP(LivingExperienceDropEvent event) { - if (event.getAttackingPlayer() instanceof DeployerFakePlayer) - event.setCanceled(true); - } - - @SubscribeEvent - public static void entitiesDontRetaliate(LivingSetAttackTargetEvent event) { - if (!(event.getTarget() instanceof DeployerFakePlayer)) - return; - LivingEntity entityLiving = event.getEntityLiving(); - if (!(entityLiving instanceof Mob)) - return; - Mob mob = (Mob) entityLiving; - - CKinetics.DeployerAggroSetting setting = AllConfigs.SERVER.kinetics.ignoreDeployerAttacks.get(); - - switch (setting) { - case ALL: - mob.setTarget(null); - break; - case CREEPERS: - if (mob instanceof Creeper) - mob.setTarget(null); - break; - case NONE: - default: - } - } - - private static class FakePlayNetHandler extends ServerGamePacketListenerImpl { - public FakePlayNetHandler(MinecraftServer server, ServerPlayer playerIn) { - super(server, NETWORK_MANAGER, playerIn); - } - - @Override - public void send(Packet packetIn) {} - - @Override - public void send(Packet packetIn, GenericFutureListener> futureListeners) {} - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFilterSlot.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFilterSlot.java deleted file mode 100644 index bbbe1a2924..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerFilterSlot.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class DeployerFilterSlot extends ValueBoxTransform { - - @Override - protected Vec3 getLocalOffset(BlockState state) { - Direction facing = state.getValue(DeployerBlock.FACING); - Vec3 vec = VecHelper.voxelSpace(8f, 13.5f, 11.5f); - - float yRot = AngleHelper.horizontalAngle(facing); - float xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; - vec = VecHelper.rotateCentered(vec, yRot, Axis.Y); - vec = VecHelper.rotateCentered(vec, xRot, Axis.X); - - return vec; - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - Direction facing = state.getValue(DeployerBlock.FACING); - float xRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; - float yRot = AngleHelper.horizontalAngle(facing) + 180; - TransformStack.cast(ms) - .rotateY(yRot) - .rotateX(xRot); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java deleted file mode 100644 index cd0804c299..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerInstance.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.api.instance.TickableInstance; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.mojang.math.Quaternion; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.util.Mth; - -public class DeployerInstance extends ShaftInstance implements DynamicInstance, TickableInstance { - - final DeployerTileEntity tile; - final Direction facing; - final float yRot; - final float xRot; - final float zRot; - - protected final OrientedData pole; - - protected OrientedData hand; - - PartialModel currentHand; - float progress; - - public DeployerInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); - - this.tile = (DeployerTileEntity) super.blockEntity; - facing = blockState.getValue(FACING); - - boolean rotatePole = blockState.getValue(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Direction.Axis.Z; - - yRot = AngleHelper.horizontalAngle(facing); - xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; - zRot = rotatePole ? 90 : 0; - - pole = getOrientedMaterial().getModel(AllBlockPartials.DEPLOYER_POLE, blockState).createInstance(); - - currentHand = this.tile.getHandPose(); - - hand = getOrientedMaterial().getModel(currentHand, blockState).createInstance(); - - progress = getProgress(AnimationTickHolder.getPartialTicks()); - updateRotation(pole, hand, yRot, xRot, zRot); - updatePosition(); - } - - @Override - public void tick() { - PartialModel handPose = tile.getHandPose(); - - if (currentHand != handPose) { - currentHand = handPose; - getOrientedMaterial().getModel(currentHand, blockState) - .stealInstance(hand); - } - } - - @Override - public void beginFrame() { - - float newProgress = getProgress(AnimationTickHolder.getPartialTicks()); - - if (Mth.equal(newProgress, progress)) return; - - progress = newProgress; - - updatePosition(); - } - - @Override - public void updateLight() { - super.updateLight(); - relight(pos, hand, pole); - } - - @Override - public void remove() { - super.remove(); - hand.delete(); - pole.delete(); - } - - private float getProgress(float partialTicks) { - if (tile.state == DeployerTileEntity.State.EXPANDING) { - float f = 1 - (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f; - if (tile.fistBump) - f *= f; - return f; - } - if (tile.state == DeployerTileEntity.State.RETRACTING) - return (tile.timer - partialTicks * tile.getTimerSpeed()) / 1000f; - return 0; - } - - private void updatePosition() { - float handLength = currentHand == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 - : currentHand == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; - float distance = Math.min(Mth.clamp(progress, 0, 1) * (tile.reach + handLength), 21 / 16f); - Vec3i facingVec = facing.getNormal(); - BlockPos blockPos = getInstancePosition(); - - float x = blockPos.getX() + ((float) facingVec.getX()) * distance; - float y = blockPos.getY() + ((float) facingVec.getY()) * distance; - float z = blockPos.getZ() + ((float) facingVec.getZ()) * distance; - - pole.setPosition(x, y, z); - hand.setPosition(x, y, z); - } - - static void updateRotation(OrientedData pole, OrientedData hand, float yRot, float xRot, float zRot) { - - Quaternion q = Direction.UP.step().rotationDegrees(yRot); - q.mul(Direction.EAST.step().rotationDegrees(xRot)); - - hand.setRotation(q); - - q.mul(Direction.SOUTH.step().rotationDegrees(zRot)); - - pole.setRotation(q); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java deleted file mode 100644 index 5d8b000472..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerItemHandler.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemHandlerHelper; - -public class DeployerItemHandler implements IItemHandlerModifiable { - - private DeployerTileEntity te; - private DeployerFakePlayer player; - - public DeployerItemHandler(DeployerTileEntity te) { - this.te = te; - this.player = te.player; - } - - @Override - public int getSlots() { - return 1 + te.overflowItems.size(); - } - - @Override - public ItemStack getStackInSlot(int slot) { - return slot >= te.overflowItems.size() ? getHeld() : te.overflowItems.get(slot); - } - - public ItemStack getHeld() { - if (player == null) - return ItemStack.EMPTY; - return player.getMainHandItem(); - } - - public void set(ItemStack stack) { - if (player == null) - return; - if (te.getLevel().isClientSide) - return; - player.setItemInHand(InteractionHand.MAIN_HAND, stack); - te.setChanged(); - te.sendData(); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (slot < te.overflowItems.size()) - return stack; - if (!isItemValid(slot, stack)) - return stack; - - ItemStack held = getHeld(); - if (held.isEmpty()) { - if (!simulate) - set(stack); - return ItemStack.EMPTY; - } - - if (!ItemHandlerHelper.canItemStacksStack(held, stack)) - return stack; - - int space = held.getMaxStackSize() - held.getCount(); - ItemStack remainder = stack.copy(); - ItemStack split = remainder.split(space); - - if (space == 0) - return stack; - if (!simulate) { - held = held.copy(); - held.setCount(held.getCount() + split.getCount()); - set(held); - } - - return remainder; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (amount == 0) - return ItemStack.EMPTY; - - if (slot < te.overflowItems.size()) { - ItemStack itemStack = te.overflowItems.get(slot); - int toExtract = Math.min(amount, itemStack.getCount()); - ItemStack extracted = simulate ? itemStack.copy() : itemStack.split(toExtract); - extracted.setCount(toExtract); - if (!simulate && itemStack.isEmpty()) - te.overflowItems.remove(slot); - if (!simulate && !extracted.isEmpty()) - te.setChanged(); - return extracted; - } - - ItemStack held = getHeld(); - if (amount == 0 || held.isEmpty()) - return ItemStack.EMPTY; - if (!te.filtering.getFilter() - .isEmpty() && te.filtering.test(held)) - return ItemStack.EMPTY; - if (simulate) - return held.copy() - .split(amount); - - ItemStack toReturn = held.split(amount); - te.setChanged(); - te.sendData(); - return toReturn; - } - - @Override - public int getSlotLimit(int slot) { - return Math.min(getStackInSlot(slot).getMaxStackSize(), 64); - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - FilteringBehaviour filteringBehaviour = te.getBehaviour(FilteringBehaviour.TYPE); - return filteringBehaviour == null || filteringBehaviour.test(stack); - } - - @Override - public void setStackInSlot(int slot, ItemStack stack) { - if (slot < te.overflowItems.size()) { - te.overflowItems.set(slot, stack); - return; - } - set(stack); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovingInteraction.java deleted file mode 100644 index 3584d31815..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovingInteraction.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import org.apache.commons.lang3.tuple.MutablePair; - -import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.Tag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; - -public class DeployerMovingInteraction extends MovingInteractionBehaviour { - - @Override - public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, - AbstractContraptionEntity contraptionEntity) { - StructureBlockInfo info = contraptionEntity.getContraption() - .getBlocks() - .get(localPos); - if (info == null) - return false; - MovementContext ctx = null; - int index = -1; - for (MutablePair pair : contraptionEntity.getContraption() - .getActors()) { - if (info.equals(pair.left)) { - ctx = pair.right; - index = contraptionEntity.getContraption() - .getActors() - .indexOf(pair); - break; - } - } - if (ctx == null) - return false; - - ItemStack heldStack = player.getItemInHand(activeHand); - if (heldStack.getItem() - .equals(AllItems.WRENCH.get())) { - DeployerTileEntity.Mode mode = NBTHelper.readEnum(ctx.tileData, "Mode", DeployerTileEntity.Mode.class); - NBTHelper.writeEnum(ctx.tileData, "Mode", - mode == DeployerTileEntity.Mode.PUNCH ? DeployerTileEntity.Mode.USE : DeployerTileEntity.Mode.PUNCH); - - } else { - if (ctx.world.isClientSide) - return true; // we'll try again on the server side - DeployerFakePlayer fake = null; - - if (!(ctx.temporaryData instanceof DeployerFakePlayer) && ctx.world instanceof ServerLevel) { - DeployerFakePlayer deployerFakePlayer = new DeployerFakePlayer((ServerLevel) ctx.world); - deployerFakePlayer.onMinecartContraption = ctx.contraption instanceof MountedContraption; - deployerFakePlayer.getInventory() - .load(ctx.tileData.getList("Inventory", Tag.TAG_COMPOUND)); - ctx.temporaryData = fake = deployerFakePlayer; - ctx.tileData.remove("Inventory"); - } else - fake = (DeployerFakePlayer) ctx.temporaryData; - - if (fake == null) - return false; - - ItemStack deployerItem = fake.getMainHandItem(); - player.setItemInHand(activeHand, deployerItem.copy()); - fake.setItemInHand(InteractionHand.MAIN_HAND, heldStack.copy()); - ctx.tileData.put("HeldItem", heldStack.serializeNBT()); - ctx.data.put("HeldItem", heldStack.serializeNBT()); - } - if (index >= 0) - setContraptionActorData(contraptionEntity, index, info, ctx); - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java deleted file mode 100644 index a2374ced20..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRenderer.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.util.Mth; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class DeployerRenderer extends SafeTileEntityRenderer { - - public DeployerRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(DeployerTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - renderItem(te, partialTicks, ms, buffer, light, overlay); - FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) return; - - renderComponents(te, partialTicks, ms, buffer, light, overlay); - } - - protected void renderItem(DeployerTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (te.heldItem.isEmpty()) return; - - BlockState deployerState = te.getBlockState(); - Vec3 offset = getHandOffset(te, partialTicks, deployerState).add(VecHelper.getCenterOf(BlockPos.ZERO)); - ms.pushPose(); - ms.translate(offset.x, offset.y, offset.z); - - Direction facing = deployerState.getValue(FACING); - boolean punching = te.mode == Mode.PUNCH; - - float yRot = AngleHelper.horizontalAngle(facing) + 180; - float xRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; - boolean displayMode = facing == Direction.UP && te.getSpeed() == 0 && !punching; - - ms.mulPose(Vector3f.YP.rotationDegrees(yRot)); - if (!displayMode) { - ms.mulPose(Vector3f.XP.rotationDegrees(xRot)); - ms.translate(0, 0, -11 / 16f); - } - - if (punching) - ms.translate(0, 1 / 8f, -1 / 16f); - - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - - TransformType transform = TransformType.NONE; - boolean isBlockItem = (te.heldItem.getItem() instanceof BlockItem) - && itemRenderer.getModel(te.heldItem, te.getLevel(), null, 0) - .isGui3d(); - - if (displayMode) { - float scale = isBlockItem ? 1.25f : 1; - ms.translate(0, isBlockItem ? 9 / 16f : 11 / 16f, 0); - ms.scale(scale, scale, scale); - transform = TransformType.GROUND; - ms.mulPose(Vector3f.YP.rotationDegrees(WorldTickHolder.getRenderTime(te.getLevel()))); - - } else { - float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f; - ms.scale(scale, scale, scale); - transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED; - } - - itemRenderer.renderStatic(te.heldItem, transform, light, overlay, ms, buffer, 0); - ms.popPose(); - } - - protected void renderComponents(DeployerTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - if (!Backend.canUseInstancing(te.getLevel())) { - KineticTileEntityRenderer.renderRotatingKineticBlock(te, getRenderedBlockState(te), ms, vb, light); - } - - BlockState blockState = te.getBlockState(); - Vec3 offset = getHandOffset(te, partialTicks, blockState); - - SuperByteBuffer pole = CachedPartialBuffers.partial(AllBlockPartials.DEPLOYER_POLE, blockState); - SuperByteBuffer hand = CachedPartialBuffers.partial(te.getHandPose(), blockState); - - transform(pole.translate(offset.x, offset.y, offset.z), blockState, true) - .light(light) - .renderInto(ms, vb); - transform(hand.translate(offset.x, offset.y, offset.z), blockState, false) - .light(light) - .renderInto(ms, vb); - } - - protected Vec3 getHandOffset(DeployerTileEntity te, float partialTicks, BlockState blockState) { - float distance = te.getHandOffset(partialTicks); - return Vec3.atLowerCornerOf(blockState.getValue(FACING).getNormal()).scale(distance); - } - - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)); - } - - private static SuperByteBuffer transform(SuperByteBuffer buffer, BlockState deployerState, boolean axisDirectionMatters) { - Direction facing = deployerState.getValue(FACING); - - float yRot = AngleHelper.horizontalAngle(facing); - float xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; - float zRot = - axisDirectionMatters && (deployerState.getValue(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Axis.Z) ? 90 - : 0; - - buffer.rotateCentered(Direction.UP, (float) ((yRot) / 180 * Math.PI)); - buffer.rotateCentered(Direction.EAST, (float) ((xRot) / 180 * Math.PI)); - buffer.rotateCentered(Direction.SOUTH, (float) ((zRot) / 180 * Math.PI)); - return buffer; - } - - public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - VertexConsumer builder = buffer.getBuffer(RenderType.solid()); - BlockState blockState = context.state; - Mode mode = NBTHelper.readEnum(context.tileData, "Mode", Mode.class); - PartialModel handPose = getHandPose(mode); - - float speed = (float) context.getAnimationSpeed(); - if (context.contraption.stalled) - speed = 0; - - SuperByteBuffer shaft = CachedBlockBuffers.block(AllBlocks.SHAFT.getDefaultState()); - SuperByteBuffer pole = CachedPartialBuffers.partial(AllBlockPartials.DEPLOYER_POLE, blockState); - SuperByteBuffer hand = CachedPartialBuffers.partial(handPose, blockState); - - double factor; - if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { - factor = Mth.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f; - } else { - Vec3 center = VecHelper.getCenterOf(new BlockPos(context.position)); - double distance = context.position.distanceTo(center); - double nextDistance = context.position.add(context.motion) - .distanceTo(center); - factor = .5f - Mth.clamp(Mth.lerp(AnimationTickHolder.getPartialTicks(), distance, nextDistance), 0, 1); - } - - Vec3 offset = Vec3.atLowerCornerOf(blockState.getValue(FACING) - .getNormal()).scale(factor); - - PoseStack m = matrices.getModel(); - m.pushPose(); - - m.pushPose(); - Axis axis = Axis.Y; - if (context.state.getBlock() instanceof IRotate) { - IRotate def = (IRotate) context.state.getBlock(); - axis = def.getRotationAxis(context.state); - } - - float time = WorldTickHolder.getRenderTime(context.world) / 20; - float angle = (time * speed) % 360; - - TransformStack.cast(m) - .centre() - .rotateY(axis == Axis.Z ? 90 : 0) - .rotateZ(axis.isHorizontal() ? 90 : 0) - .unCentre(); - shaft.transform(m); - shaft.rotateCentered(Direction.get(AxisDirection.POSITIVE, Axis.Y), angle); - m.popPose(); - - m.translate(offset.x, offset.y, offset.z); - pole.transform(m); - hand.transform(m); - - transform(pole, blockState, true); - transform(hand, blockState, false); - - shaft.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), builder); - pole.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), builder); - hand.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), builder); - - m.popPose(); - } - - static PartialModel getHandPose(DeployerTileEntity.Mode mode) { - return mode == DeployerTileEntity.Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING : AllBlockPartials.DEPLOYER_HAND_POINTING; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java deleted file mode 100644 index 1ad174c670..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ /dev/null @@ -1,555 +0,0 @@ -package com.simibubi.create.content.contraptions.components.deployer; - -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.content.curiosities.tools.SandPaperItem; -import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe.SandPaperInv; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.Container; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.ClipContext.Block; -import net.minecraft.world.level.ClipContext.Fluid; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class DeployerTileEntity extends KineticTileEntity { - - protected State state; - protected Mode mode; - protected ItemStack heldItem = ItemStack.EMPTY; - protected DeployerFakePlayer player; - protected int timer; - protected float reach; - protected boolean fistBump = false; - protected List overflowItems = new ArrayList<>(); - protected FilteringBehaviour filtering; - protected boolean redstoneLocked; - private LazyOptional invHandler; - private ListTag deferredInventoryList; - - private LerpedFloat animatedOffset; - - public BeltProcessingBehaviour processingBehaviour; - - enum State { - WAITING, EXPANDING, RETRACTING, DUMPING; - } - - enum Mode { - PUNCH, USE - } - - public DeployerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - this.state = State.WAITING; - mode = Mode.USE; - heldItem = ItemStack.EMPTY; - redstoneLocked = false; - animatedOffset = LerpedFloat.linear() - .startWithValue(0); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - filtering = new FilteringBehaviour(this, new DeployerFilterSlot()); - behaviours.add(filtering); - processingBehaviour = - new BeltProcessingBehaviour(this).whenItemEnters((s, i) -> BeltDeployerCallbacks.onItemReceived(s, i, this)) - .whileItemHeld((s, i) -> BeltDeployerCallbacks.whenItemHeld(s, i, this)); - behaviours.add(processingBehaviour); - - registerAwardables(behaviours, AllAdvancements.TRAIN_CASING, AllAdvancements.ANDESITE_CASING, - AllAdvancements.BRASS_CASING, AllAdvancements.COPPER_CASING, AllAdvancements.FIST_BUMP, - AllAdvancements.DEPLOYER, AllAdvancements.SELF_DEPLOYING); - } - - @Override - public void initialize() { - super.initialize(); - initHandler(); - } - - private void initHandler() { - if (invHandler != null) - return; - if (level instanceof ServerLevel sLevel) { - player = new DeployerFakePlayer(sLevel); - if (deferredInventoryList != null) { - player.getInventory() - .load(deferredInventoryList); - deferredInventoryList = null; - heldItem = player.getMainHandItem(); - sendData(); - } - Vec3 initialPos = VecHelper.getCenterOf(worldPosition.relative(getBlockState().getValue(FACING))); - player.setPos(initialPos.x, initialPos.y, initialPos.z); - } - invHandler = LazyOptional.of(this::createHandler); - } - - protected void onExtract(ItemStack stack) { - player.setItemInHand(InteractionHand.MAIN_HAND, stack.copy()); - sendData(); - setChanged(); - } - - protected int getTimerSpeed() { - return (int) (getSpeed() == 0 ? 0 : Mth.clamp(Math.abs(getSpeed() * 2), 8, 512)); - } - - @Override - public void tick() { - super.tick(); - - if (getSpeed() == 0) - return; - if (!level.isClientSide && player != null && player.blockBreakingProgress != null) { - if (level.isEmptyBlock(player.blockBreakingProgress.getKey())) { - level.destroyBlockProgress(player.getId(), player.blockBreakingProgress.getKey(), -1); - player.blockBreakingProgress = null; - } - } - if (timer > 0) { - timer -= getTimerSpeed(); - return; - } - if (level.isClientSide) - return; - - ItemStack stack = player.getMainHandItem(); - if (state == State.WAITING) { - if (!overflowItems.isEmpty()) { - timer = getTimerSpeed() * 10; - return; - } - - boolean changed = false; - Inventory inventory = player.getInventory(); - for (int i = 0; i < inventory.getContainerSize(); i++) { - if (overflowItems.size() > 10) - break; - ItemStack item = inventory.getItem(i); - if (item.isEmpty()) - continue; - if (item != stack || !filtering.test(item)) { - overflowItems.add(item); - inventory.setItem(i, ItemStack.EMPTY); - changed = true; - } - } - - if (changed) { - sendData(); - timer = getTimerSpeed() * 10; - return; - } - - Direction facing = getBlockState().getValue(FACING); - if (mode == Mode.USE - && !DeployerHandler.shouldActivate(stack, level, worldPosition.relative(facing, 2), facing)) { - timer = getTimerSpeed() * 10; - return; - } - - // Check for advancement conditions - if (mode == Mode.PUNCH && !fistBump && startFistBump(facing)) - return; - if (redstoneLocked) - return; - - start(); - return; - } - - if (state == State.EXPANDING) { - if (fistBump) - triggerFistBump(); - activate(); - - state = State.RETRACTING; - timer = 1000; - sendData(); - return; - } - - if (state == State.RETRACTING) { - state = State.WAITING; - timer = 500; - sendData(); - return; - } - - } - - protected void start() { - state = State.EXPANDING; - Vec3 movementVector = getMovementVector(); - Vec3 rayOrigin = VecHelper.getCenterOf(worldPosition) - .add(movementVector.scale(3 / 2f)); - Vec3 rayTarget = VecHelper.getCenterOf(worldPosition) - .add(movementVector.scale(5 / 2f)); - ClipContext rayTraceContext = new ClipContext(rayOrigin, rayTarget, Block.OUTLINE, Fluid.NONE, player); - BlockHitResult result = level.clip(rayTraceContext); - reach = (float) (.5f + Math.min(result.getLocation() - .subtract(rayOrigin) - .length(), .75f)); - timer = 1000; - sendData(); - } - - public boolean startFistBump(Direction facing) { - int i = 0; - DeployerTileEntity partner = null; - - for (i = 2; i < 5; i++) { - BlockPos otherDeployer = worldPosition.relative(facing, i); - if (!level.isLoaded(otherDeployer)) - return false; - BlockEntity otherTile = level.getBlockEntity(otherDeployer); - if (otherTile instanceof DeployerTileEntity dpe) { - partner = dpe; - break; - } - } - - if (partner == null) - return false; - - if (level.getBlockState(partner.getBlockPos()) - .getValue(FACING) - .getOpposite() != facing || partner.mode != Mode.PUNCH) - return false; - if (partner.getSpeed() == 0) - return false; - - for (DeployerTileEntity te : Arrays.asList(this, partner)) { - te.fistBump = true; - te.reach = ((i - 2)) * .5f; - te.timer = 1000; - te.state = State.EXPANDING; - te.sendData(); - } - - return true; - } - - public void triggerFistBump() { - int i = 0; - DeployerTileEntity deployerTile = null; - for (i = 2; i < 5; i++) { - BlockPos pos = worldPosition.relative(getBlockState().getValue(FACING), i); - if (!level.isLoaded(pos)) - return; - if (level.getBlockEntity(pos) instanceof DeployerTileEntity dpe) { - deployerTile = dpe; - break; - } - } - - if (deployerTile == null) - return; - if (!deployerTile.fistBump || deployerTile.state != State.EXPANDING) - return; - if (deployerTile.timer > 0) - return; - - fistBump = false; - deployerTile.fistBump = false; - deployerTile.state = State.RETRACTING; - deployerTile.timer = 1000; - deployerTile.sendData(); - award(AllAdvancements.FIST_BUMP); - - BlockPos soundLocation = new BlockPos(Vec3.atCenterOf(worldPosition) - .add(Vec3.atCenterOf(deployerTile.getBlockPos())) - .scale(.5f)); - level.playSound(null, soundLocation, SoundEvents.PLAYER_ATTACK_NODAMAGE, SoundSource.BLOCKS, .75f, .75f); - } - - protected void activate() { - Vec3 movementVector = getMovementVector(); - Direction direction = getBlockState().getValue(FACING); - Vec3 center = VecHelper.getCenterOf(worldPosition); - BlockPos clickedPos = worldPosition.relative(direction, 2); - player.setXRot(direction == Direction.UP ? -90 : direction == Direction.DOWN ? 90 : 0); - player.setYRot(direction.toYRot()); - - if (direction == Direction.DOWN - && TileEntityBehaviour.get(level, clickedPos, TransportedItemStackHandlerBehaviour.TYPE) != null) - return; // Belt processing handled in BeltDeployerCallbacks - - DeployerHandler.activate(player, center, clickedPos, movementVector, mode); - award(AllAdvancements.DEPLOYER); - - if (player != null) - heldItem = player.getMainHandItem(); - } - - protected Vec3 getMovementVector() { - if (!AllBlocks.DEPLOYER.has(getBlockState())) - return Vec3.ZERO; - return Vec3.atLowerCornerOf(getBlockState().getValue(FACING) - .getNormal()); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - state = NBTHelper.readEnum(compound, "State", State.class); - mode = NBTHelper.readEnum(compound, "Mode", Mode.class); - timer = compound.getInt("Timer"); - redstoneLocked = compound.getBoolean("Powered"); - - deferredInventoryList = compound.getList("Inventory", Tag.TAG_COMPOUND); - overflowItems = NBTHelper.readItemList(compound.getList("Overflow", Tag.TAG_COMPOUND)); - if (compound.contains("HeldItem")) - heldItem = ItemStack.of(compound.getCompound("HeldItem")); - super.read(compound, clientPacket); - - if (!clientPacket) - return; - fistBump = compound.getBoolean("Fistbump"); - reach = compound.getFloat("Reach"); - if (compound.contains("Particle")) { - ItemStack particleStack = ItemStack.of(compound.getCompound("Particle")); - SandPaperItem.spawnParticles(VecHelper.getCenterOf(worldPosition) - .add(getMovementVector().scale(reach + 1)), particleStack, this.level); - } - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - NBTHelper.writeEnum(compound, "Mode", mode); - NBTHelper.writeEnum(compound, "State", state); - compound.putInt("Timer", timer); - compound.putBoolean("Powered", redstoneLocked); - - if (player != null) { - ListTag invNBT = new ListTag(); - player.getInventory() - .save(invNBT); - compound.put("Inventory", invNBT); - compound.put("HeldItem", player.getMainHandItem() - .serializeNBT()); - compound.put("Overflow", NBTHelper.writeItemList(overflowItems)); - } else if (deferredInventoryList != null) { - compound.put("Inventory", deferredInventoryList); - } - - super.write(compound, clientPacket); - - if (!clientPacket) - return; - compound.putBoolean("Fistbump", fistBump); - compound.putFloat("Reach", reach); - if (player == null) - return; - compound.put("HeldItem", player.getMainHandItem() - .serializeNBT()); - if (player.spawnedItemEffects != null) { - compound.put("Particle", player.spawnedItemEffects.serializeNBT()); - player.spawnedItemEffects = null; - } - } - - @Override - public void writeSafe(CompoundTag tag) { - NBTHelper.writeEnum(tag, "Mode", mode); - super.writeSafe(tag); - } - - private IItemHandlerModifiable createHandler() { - return new DeployerItemHandler(this); - } - - public void redstoneUpdate() { - if (level.isClientSide) - return; - boolean blockPowered = level.hasNeighborSignal(worldPosition); - if (blockPowered == redstoneLocked) - return; - redstoneLocked = blockPowered; - sendData(); - } - - @OnlyIn(Dist.CLIENT) - public PartialModel getHandPose() { - return mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING - : heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING; - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(3); - } - - @Override - public void setRemoved() { - super.setRemoved(); - if (invHandler != null) - invHandler.invalidate(); - } - - public void changeMode() { - mode = mode == Mode.PUNCH ? Mode.USE : Mode.PUNCH; - setChanged(); - sendData(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) { - if (invHandler == null) - initHandler(); - return invHandler.cast(); - } - return super.getCapability(cap, side); - } - - @Override - public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { - if (super.addToTooltip(tooltip, isPlayerSneaking)) - return true; - if (getSpeed() == 0) - return false; - if (overflowItems.isEmpty()) - return false; - TooltipHelper.addHint(tooltip, "hint.full_deployer"); - return true; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - CreateLang.translate("tooltip.deployer.header") - .forGoggles(tooltip); - - CreateLang.translate("tooltip.deployer." + (mode == Mode.USE ? "using" : "punching")) - .style(ChatFormatting.YELLOW) - .forGoggles(tooltip); - - if (!heldItem.isEmpty()) - CreateLang.translate("tooltip.deployer.contains", - Components.translatable(heldItem.getDescriptionId()).getString(), heldItem.getCount()) - .style(ChatFormatting.GREEN) - .forGoggles(tooltip); - - float stressAtBase = calculateStressApplied(); - if (StressImpact.isEnabled() && !Mth.equal(stressAtBase, 0)) { - tooltip.add(Components.immutableEmpty()); - addStressImpactStats(tooltip, stressAtBase); - } - - return true; - } - - @OnlyIn(Dist.CLIENT) - public float getHandOffset(float partialTicks) { - if (isVirtual()) - return animatedOffset.getValue(partialTicks); - - float progress = 0; - int timerSpeed = getTimerSpeed(); - PartialModel handPose = getHandPose(); - - if (state == State.EXPANDING) { - progress = 1 - (timer - partialTicks * timerSpeed) / 1000f; - if (fistBump) - progress *= progress; - } - if (state == State.RETRACTING) - progress = (timer - partialTicks * timerSpeed) / 1000f; - float handLength = handPose == AllBlockPartials.DEPLOYER_HAND_POINTING ? 0 - : handPose == AllBlockPartials.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; - float distance = Math.min(Mth.clamp(progress, 0, 1) * (reach + handLength), 21 / 16f); - - return distance; - } - - public void setAnimatedOffset(float offset) { - animatedOffset.setValue(offset); - } - - RecipeWrapper recipeInv = new RecipeWrapper(new ItemStackHandler(2)); - SandPaperInv sandpaperInv = new SandPaperInv(ItemStack.EMPTY); - - @Nullable - public Recipe getRecipe(ItemStack stack) { - if (player == null || level == null) - return null; - - ItemStack heldItemMainhand = player.getMainHandItem(); - if (heldItemMainhand.getItem() instanceof SandPaperItem) { - sandpaperInv.setItem(0, stack); - return AllRecipeTypes.SANDPAPER_POLISHING.find(sandpaperInv, level) - .orElse(null); - } - - recipeInv.setItem(0, stack); - recipeInv.setItem(1, heldItemMainhand); - - DeployerRecipeSearchEvent event = new DeployerRecipeSearchEvent(this, recipeInv); - - event.addRecipe(() -> SequencedAssemblyRecipe.getRecipe(level, event.getInventory(), - AllRecipeTypes.DEPLOYING.getType(), DeployerApplicationRecipe.class), 100); - event.addRecipe(() -> AllRecipeTypes.DEPLOYING.find(event.getInventory(), level), 50); - event.addRecipe(() -> AllRecipeTypes.ITEM_APPLICATION.find(event.getInventory(), level), 50); - - MinecraftForge.EVENT_BUS.post(event); - return event.getRecipe(); - } - - public DeployerFakePlayer getPlayer() { - return player; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanBlock.java deleted file mode 100644 index 3fc85edb6d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanBlock.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock; -import com.simibubi.create.foundation.block.ITE; - -import net.createmod.catnip.utility.worldWrappers.WrappedWorld; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class EncasedFanBlock extends DirectionalKineticBlock implements ITE { - - public EncasedFanBlock(Properties properties) { - super(properties); - } - - @Override - public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, worldIn, pos, oldState, isMoving); - blockUpdate(state, worldIn, pos); - } - - @Override - public void updateIndirectNeighbourShapes(BlockState stateIn, LevelAccessor worldIn, BlockPos pos, int flags, int count) { - super.updateIndirectNeighbourShapes(stateIn, worldIn, pos, flags, count); - blockUpdate(stateIn, worldIn, pos); - } - - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState p_196243_4_, boolean p_196243_5_) { - if (state.hasBlockEntity() && (state.getBlock() != p_196243_4_.getBlock() || !p_196243_4_.hasBlockEntity())) { - withTileEntityDo(world, pos, EncasedFanTileEntity::updateChute); - world.removeBlockEntity(pos); - } - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - blockUpdate(state, worldIn, pos); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - Level world = context.getLevel(); - BlockPos pos = context.getClickedPos(); - Direction face = context.getClickedFace(); - - BlockState placedOn = world.getBlockState(pos.relative(face.getOpposite())); - BlockState placedOnOpposite = world.getBlockState(pos.relative(face)); - if (AbstractChuteBlock.isChute(placedOn)) - return defaultBlockState().setValue(FACING, face.getOpposite()); - if (AbstractChuteBlock.isChute(placedOnOpposite)) - return defaultBlockState().setValue(FACING, face); - - Direction preferredFacing = getPreferredFacing(context); - if (preferredFacing == null) - preferredFacing = context.getNearestLookingDirection(); - return defaultBlockState().setValue(FACING, context.getPlayer() != null && context.getPlayer() - .isShiftKeyDown() ? preferredFacing : preferredFacing.getOpposite()); - } - - protected void blockUpdate(BlockState state, LevelAccessor worldIn, BlockPos pos) { - if (worldIn instanceof WrappedWorld) - return; - notifyFanTile(worldIn, pos); - } - - protected void notifyFanTile(LevelAccessor world, BlockPos pos) { - withTileEntityDo(world, pos, EncasedFanTileEntity::blockInFrontChanged); - } - - @Override - public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { - blockUpdate(newState, context.getLevel(), context.getClickedPos()); - return newState; - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(FACING) - .getAxis(); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face == state.getValue(FACING) - .getOpposite(); - } - - @Override - public Class getTileEntityClass() { - return EncasedFanTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ENCASED_FAN.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java deleted file mode 100644 index 136ea476fb..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanRenderer.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; - -public class EncasedFanRenderer extends KineticTileEntityRenderer { - - public EncasedFanRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) return; - - Direction direction = te.getBlockState() - .getValue(FACING); - VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - - int lightBehind = LevelRenderer.getLightColor(te.getLevel(), te.getBlockPos().relative(direction.getOpposite())); - int lightInFront = LevelRenderer.getLightColor(te.getLevel(), te.getBlockPos().relative(direction)); - - SuperByteBuffer shaftHalf = - CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, te.getBlockState(), direction.getOpposite()); - SuperByteBuffer fanInner = - CachedPartialBuffers.partialFacing(AllBlockPartials.ENCASED_FAN_INNER, te.getBlockState(), direction.getOpposite()); - - float time = WorldTickHolder.getRenderTime(te.getLevel()); - float speed = te.getSpeed() * 5; - if (speed > 0) - speed = Mth.clamp(speed, 80, 64 * 20); - if (speed < 0) - speed = Mth.clamp(speed, -64 * 20, -80); - float angle = (time * speed * 3 / 10f) % 360; - angle = angle / 180f * (float) Math.PI; - - standardKineticRotationTransform(shaftHalf, te, lightBehind).renderInto(ms, vb); - kineticRotationTransform(fanInner, te, direction.getAxis(), angle, lightInFront).renderInto(ms, vb); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java deleted file mode 100644 index e93c63f5e9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import java.util.List; - -import javax.annotation.Nullable; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -@MethodsReturnNonnullByDefault -public class EncasedFanTileEntity extends KineticTileEntity implements IAirCurrentSource { - - public AirCurrent airCurrent; - protected int airCurrentUpdateCooldown; - protected int entitySearchCooldown; - protected boolean updateAirFlow; - - public EncasedFanTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - airCurrent = new AirCurrent(this); - updateAirFlow = true; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.ENCASED_FAN, AllAdvancements.FAN_PROCESSING); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (clientPacket) - airCurrent.rebuild(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - } - - @Override - public AirCurrent getAirCurrent() { - return airCurrent; - } - - @Nullable - @Override - public Level getAirCurrentWorld() { - return level; - } - - @Override - public BlockPos getAirCurrentPos() { - return worldPosition; - } - - @Override - public Direction getAirflowOriginSide() { - return this.getBlockState() - .getValue(EncasedFanBlock.FACING); - } - - @Override - public Direction getAirFlowDirection() { - float speed = getSpeed(); - if (speed == 0) - return null; - Direction facing = getBlockState().getValue(BlockStateProperties.FACING); - speed = convertToDirection(speed, facing); - return speed > 0 ? facing : facing.getOpposite(); - } - - @Override - public boolean isSourceRemoved() { - return remove; - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - updateAirFlow = true; - updateChute(); - } - - public void updateChute() { - Direction direction = getBlockState().getValue(EncasedFanBlock.FACING); - if (!direction.getAxis() - .isVertical()) - return; - BlockEntity poweredChute = level.getBlockEntity(worldPosition.relative(direction)); - if (!(poweredChute instanceof ChuteTileEntity)) - return; - ChuteTileEntity chuteTE = (ChuteTileEntity) poweredChute; - if (direction == Direction.DOWN) - chuteTE.updatePull(); - else - chuteTE.updatePush(1); - } - - public void blockInFrontChanged() { - updateAirFlow = true; - } - - @Override - public void tick() { - super.tick(); - - boolean server = !level.isClientSide || isVirtual(); - - if (server && airCurrentUpdateCooldown-- <= 0) { - airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get(); - updateAirFlow = true; - } - - if (updateAirFlow) { - updateAirFlow = false; - airCurrent.rebuild(); - if (airCurrent.maxDistance > 0) - award(AllAdvancements.ENCASED_FAN); - sendData(); - } - - if (getSpeed() == 0) - return; - - if (entitySearchCooldown-- <= 0) { - entitySearchCooldown = 5; - airCurrent.findEntities(); - } - - airCurrent.tick(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java deleted file mode 100644 index 9a7dfa93be..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/FanInstance.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.foundation.render.AllMaterialSpecs; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; - -public class FanInstance extends KineticTileInstance { - - protected final RotatingData shaft; - protected final RotatingData fan; - final Direction direction; - private final Direction opposite; - - public FanInstance(MaterialManager modelManager, EncasedFanTileEntity tile) { - super(modelManager, tile); - - direction = blockState.getValue(FACING); - - opposite = direction.getOpposite(); - shaft = getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, opposite).createInstance(); - fan = modelManager.defaultCutout() - .material(AllMaterialSpecs.ROTATING) - .getModel(AllBlockPartials.ENCASED_FAN_INNER, blockState, opposite) - .createInstance(); - - setup(shaft); - setup(fan, getFanSpeed()); - } - - private float getFanSpeed() { - float speed = blockEntity.getSpeed() * 5; - if (speed > 0) - speed = Mth.clamp(speed, 80, 64 * 20); - if (speed < 0) - speed = Mth.clamp(speed, -64 * 20, -80); - return speed; - } - - @Override - public void update() { - updateRotation(shaft); - updateRotation(fan, getFanSpeed()); - } - - @Override - public void updateLight() { - BlockPos behind = pos.relative(opposite); - relight(behind, shaft); - - BlockPos inFront = pos.relative(direction); - relight(inFront, fan); - } - - @Override - public void remove() { - shaft.delete(); - fan.delete(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/HauntingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/HauntingRecipe.java deleted file mode 100644 index 443642a5d9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/HauntingRecipe.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; - -import net.minecraft.world.level.Level; - -@ParametersAreNonnullByDefault -public class HauntingRecipe extends ProcessingRecipe { - - public HauntingRecipe(ProcessingRecipeParams params) { - super(AllRecipeTypes.HAUNTING, params); - } - - @Override - public boolean matches(InWorldProcessing.HauntingWrapper inv, Level worldIn) { - if (inv.isEmpty()) - return false; - return ingredients.get(0) - .test(inv.getItem(0)); - } - - @Override - protected int getMaxInputCount() { - return 1; - } - - @Override - protected int getMaxOutputCount() { - return 12; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java deleted file mode 100644 index 5f8da35166..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.ClipContext.Block; -import net.minecraft.world.level.ClipContext.Fluid; -import net.minecraft.world.level.Explosion.BlockInteraction; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class NozzleTileEntity extends SmartTileEntity { - - private List pushingEntities = new ArrayList<>(); - private float range; - private boolean pushing; - private BlockPos fanPos; - - public NozzleTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(5); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - if (!clientPacket) - return; - compound.putFloat("Range", range); - compound.putBoolean("Pushing", pushing); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (!clientPacket) - return; - range = compound.getFloat("Range"); - pushing = compound.getBoolean("Pushing"); - } - - @Override - public void initialize() { - fanPos = worldPosition.relative(getBlockState().getValue(NozzleBlock.FACING) - .getOpposite()); - super.initialize(); - } - - @Override - public void tick() { - super.tick(); - - float range = calcRange(); - if (this.range != range) - setRange(range); - - Vec3 center = VecHelper.getCenterOf(worldPosition); - if (level.isClientSide && range != 0) { - if (level.random.nextInt( - Mth.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) { - Vec3 start = VecHelper.offsetRandomly(center, level.random, pushing ? 1 : range / 2); - Vec3 motion = center.subtract(start) - .normalize() - .scale(Mth.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1)); - level.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z); - } - } - - for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { - Entity entity = iterator.next(); - Vec3 diff = entity.position() - .subtract(center); - - if (!(entity instanceof Player) && level.isClientSide) - continue; - - double distance = diff.length(); - if (distance > range || entity.isShiftKeyDown() || AirCurrent.isPlayerCreativeFlying(entity)) { - iterator.remove(); - continue; - } - - if (!pushing && distance < 1.5f) - continue; - - float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f; - Vec3 pushVec = diff.normalize() - .scale((range - distance) * (pushing ? 1 : -1)); - entity.setDeltaMovement(entity.getDeltaMovement() - .add(pushVec.scale(factor))); - entity.fallDistance = 0; - entity.hurtMarked = true; - } - - } - - public void setRange(float range) { - this.range = range; - if (range == 0) - pushingEntities.clear(); - sendData(); - } - - private float calcRange() { - BlockEntity te = level.getBlockEntity(fanPos); - if (!(te instanceof IAirCurrentSource)) - return 0; - - IAirCurrentSource source = (IAirCurrentSource) te; - if (source.getAirCurrent() == null) - return 0; - if (source.getSpeed() == 0) - return 0; - pushing = source.getAirFlowDirection() == source.getAirflowOriginSide(); - return source.getMaxDistance(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - - if (range == 0) - return; - - Vec3 center = VecHelper.getCenterOf(worldPosition); - AABB bb = new AABB(center, center).inflate(range / 2f); - - for (Entity entity : level.getEntitiesOfClass(Entity.class, bb)) { - Vec3 diff = entity.position() - .subtract(center); - - double distance = diff.length(); - if (distance > range || entity.isShiftKeyDown() || AirCurrent.isPlayerCreativeFlying(entity)) - continue; - - boolean canSee = canSee(entity); - if (!canSee) { - pushingEntities.remove(entity); - continue; - } - - if (!pushingEntities.contains(entity)) - pushingEntities.add(entity); - } - - for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { - Entity entity = iterator.next(); - if (entity.isAlive()) - continue; - iterator.remove(); - } - - if (!pushing && pushingEntities.size() > 256 && !level.isClientSide) { - level.explode(null, center.x, center.y, center.z, 2, BlockInteraction.NONE); - for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { - Entity entity = iterator.next(); - entity.discard(); - iterator.remove(); - } - } - - } - - private boolean canSee(Entity entity) { - ClipContext context = new ClipContext(entity.position(), VecHelper.getCenterOf(worldPosition), - Block.COLLIDER, Fluid.NONE, entity); - return worldPosition.equals(level.clip(context) - .getBlockPos()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/SplashingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/SplashingRecipe.java deleted file mode 100644 index 4918ddb82e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/SplashingRecipe.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.simibubi.create.content.contraptions.components.fan; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing.SplashingWrapper; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; - -import net.minecraft.world.level.Level; - -@ParametersAreNonnullByDefault -public class SplashingRecipe extends ProcessingRecipe { - - public SplashingRecipe(ProcessingRecipeParams params) { - super(AllRecipeTypes.SPLASHING, params); - } - - @Override - public boolean matches(SplashingWrapper inv, Level worldIn) { - if (inv.isEmpty()) - return false; - return ingredients.get(0) - .test(inv.getItem(0)); - } - - @Override - protected int getMaxInputCount() { - return 1; - } - - @Override - protected int getMaxOutputCount() { - return 12; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java deleted file mode 100644 index 33dfc93ca5..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlyWheelInstance.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.simibubi.create.content.contraptions.components.flywheel; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; - -public class FlyWheelInstance extends KineticTileInstance implements DynamicInstance { - - protected final RotatingData shaft; - protected final ModelData wheel; - protected float lastAngle = Float.NaN; - - public FlyWheelInstance(MaterialManager modelManager, FlywheelTileEntity tile) { - super(modelManager, tile); - - shaft = setup(getRotatingMaterial().getModel(shaft()) - .createInstance()); - wheel = getTransformMaterial().getModel(blockState) - .createInstance(); - - animate(tile.angle); - } - - @Override - public void beginFrame() { - - float partialTicks = AnimationTickHolder.getPartialTicks(); - - float speed = blockEntity.visualSpeed.getValue(partialTicks) * 3 / 10f; - float angle = blockEntity.angle + speed * partialTicks; - - if (Math.abs(angle - lastAngle) < 0.001) - return; - - animate(angle); - - lastAngle = angle; - } - - private void animate(float angle) { - PoseStack ms = new PoseStack(); - TransformStack msr = TransformStack.cast(ms); - - msr.translate(getInstancePosition()); - msr.centre() - .rotate(Direction.get(Direction.AxisDirection.POSITIVE, axis), AngleHelper.rad(angle)) - .unCentre(); - - wheel.setTransform(ms); - } - - @Override - public void update() { - updateRotation(shaft); - } - - @Override - public void updateLight() { - relight(pos, shaft, wheel); - } - - @Override - public void remove() { - shaft.delete(); - wheel.delete(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelBlock.java deleted file mode 100644 index 47c9613340..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelBlock.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.contraptions.components.flywheel; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -public class FlywheelBlock extends RotatedPillarKineticBlock implements ITE { - - public FlywheelBlock(Properties properties) { - super(properties); - } - - @Override - public Class getTileEntityClass() { - return FlywheelTileEntity.class; - } - - @Override - public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { - return AllShapes.LARGE_GEAR.get(pState.getValue(AXIS)); - } - - @Override - public RenderShape getRenderShape(BlockState pState) { - return RenderShape.ENTITYBLOCK_ANIMATED; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.FLYWHEEL.get(); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face.getAxis() == getRotationAxis(state); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(AXIS); - } - - @Override - public float getParticleTargetRadius() { - return 2f; - } - - @Override - public float getParticleInitialRadius() { - return 1.75f; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java deleted file mode 100644 index b3a40ddae1..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelRenderer.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.contraptions.components.flywheel; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class FlywheelRenderer extends KineticTileEntityRenderer { - - public FlywheelRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) - return; - - BlockState blockState = te.getBlockState(); - FlywheelTileEntity wte = (FlywheelTileEntity) te; - - float speed = wte.visualSpeed.getValue(partialTicks) * 3 / 10f; - float angle = wte.angle + speed * partialTicks; - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - renderFlywheel(te, ms, light, blockState, angle, vb); - } - - private void renderFlywheel(KineticTileEntity te, PoseStack ms, int light, BlockState blockState, float angle, - VertexConsumer vb) { - SuperByteBuffer wheel = CachedBlockBuffers.block(blockState); - kineticRotationTransform(wheel, te, getRotationAxisOf(te), AngleHelper.rad(angle), light); - wheel.renderInto(ms, vb); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java deleted file mode 100644 index 4ebaa2f6f0..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.contraptions.components.flywheel; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class FlywheelTileEntity extends KineticTileEntity { - - LerpedFloat visualSpeed = LerpedFloat.linear(); - float angle; - - public FlywheelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (clientPacket) - visualSpeed.chase(getGeneratedSpeed(), 1 / 64f, Chaser.EXP); - } - - @Override - public void tick() { - super.tick(); - - if (!level.isClientSide) - return; - - float targetSpeed = getSpeed(); - visualSpeed.updateChaseTarget(targetSpeed); - visualSpeed.tickChaser(); - angle += visualSpeed.getValue() * 3 / 10f; - angle %= 360; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java deleted file mode 100644 index 1e88312613..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillStoneCogInstance.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.contraptions.components.millstone; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -public class MillStoneCogInstance extends SingleRotatingInstance { - - public MillStoneCogInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - return getRotatingMaterial().getModel(AllBlockPartials.MILLSTONE_COG, blockEntity.getBlockState()); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillingRecipe.java deleted file mode 100644 index 849154b040..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillingRecipe.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.simibubi.create.content.contraptions.components.millstone; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.components.crusher.AbstractCrushingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; - -import net.minecraft.world.level.Level; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -@ParametersAreNonnullByDefault -public class MillingRecipe extends AbstractCrushingRecipe { - - public MillingRecipe(ProcessingRecipeParams params) { - super(AllRecipeTypes.MILLING, params); - } - - @Override - public boolean matches(RecipeWrapper inv, Level worldIn) { - if (inv.isEmpty()) - return false; - return ingredients.get(0) - .test(inv.getItem(0)); - } - - @Override - protected int getMaxOutputCount() { - return 4; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java deleted file mode 100644 index 3f6ab496f2..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneRenderer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.simibubi.create.content.contraptions.components.millstone; - -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class MillstoneRenderer extends KineticTileEntityRenderer { - - public MillstoneRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partial(AllBlockPartials.MILLSTONE_COG, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java deleted file mode 100644 index 9594928721..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java +++ /dev/null @@ -1,230 +0,0 @@ -package com.simibubi.create.content.contraptions.components.millstone; - -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.sound.SoundScapes; -import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.CombinedInvWrapper; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class MillstoneTileEntity extends KineticTileEntity { - - public ItemStackHandler inputInv; - public ItemStackHandler outputInv; - public LazyOptional capability; - public int timer; - private MillingRecipe lastRecipe; - - public MillstoneTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inputInv = new ItemStackHandler(1); - outputInv = new ItemStackHandler(9); - capability = LazyOptional.of(MillstoneInventoryHandler::new); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(this)); - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.MILLSTONE); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - super.tickAudio(); - - if (getSpeed() == 0) - return; - if (inputInv.getStackInSlot(0) - .isEmpty()) - return; - - float pitch = Mth.clamp((Math.abs(getSpeed()) / 256f) + .45f, .85f, 1f); - SoundScapes.play(AmbienceGroup.MILLING, worldPosition, pitch); - } - - @Override - public void tick() { - super.tick(); - - if (getSpeed() == 0) - return; - for (int i = 0; i < outputInv.getSlots(); i++) - if (outputInv.getStackInSlot(i) - .getCount() == outputInv.getSlotLimit(i)) - return; - - if (timer > 0) { - timer -= getProcessingSpeed(); - - if (level.isClientSide) { - spawnParticles(); - return; - } - if (timer <= 0) - process(); - return; - } - - if (inputInv.getStackInSlot(0) - .isEmpty()) - return; - - RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); - if (lastRecipe == null || !lastRecipe.matches(inventoryIn, level)) { - Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, level); - if (!recipe.isPresent()) { - timer = 100; - sendData(); - } else { - lastRecipe = recipe.get(); - timer = lastRecipe.getProcessingDuration(); - sendData(); - } - return; - } - - timer = lastRecipe.getProcessingDuration(); - sendData(); - } - - @Override - public void setRemoved() { - super.setRemoved(); - capability.invalidate(); - } - - private void process() { - RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); - - if (lastRecipe == null || !lastRecipe.matches(inventoryIn, level)) { - Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, level); - if (!recipe.isPresent()) - return; - lastRecipe = recipe.get(); - } - - ItemStack stackInSlot = inputInv.getStackInSlot(0); - stackInSlot.shrink(1); - inputInv.setStackInSlot(0, stackInSlot); - lastRecipe.rollResults() - .forEach(stack -> ItemHandlerHelper.insertItemStacked(outputInv, stack, false)); - award(AllAdvancements.MILLSTONE); - - sendData(); - setChanged(); - } - - public void spawnParticles() { - ItemStack stackInSlot = inputInv.getStackInSlot(0); - if (stackInSlot.isEmpty()) - return; - - ItemParticleOption data = new ItemParticleOption(ParticleTypes.ITEM, stackInSlot); - float angle = level.random.nextFloat() * 360; - Vec3 offset = new Vec3(0, 0, 0.5f); - offset = VecHelper.rotate(offset, angle, Axis.Y); - Vec3 target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y); - - Vec3 center = offset.add(VecHelper.getCenterOf(worldPosition)); - target = VecHelper.offsetRandomly(target.subtract(offset), level.random, 1 / 128f); - level.addParticle(data, center.x, center.y, center.z, target.x, target.y, target.z); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("Timer", timer); - compound.put("InputInventory", inputInv.serializeNBT()); - compound.put("OutputInventory", outputInv.serializeNBT()); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - timer = compound.getInt("Timer"); - inputInv.deserializeNBT(compound.getCompound("InputInventory")); - outputInv.deserializeNBT(compound.getCompound("OutputInventory")); - super.read(compound, clientPacket); - } - - public int getProcessingSpeed() { - return Mth.clamp((int) Math.abs(getSpeed() / 16f), 1, 512); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return capability.cast(); - return super.getCapability(cap, side); - } - - private boolean canProcess(ItemStack stack) { - ItemStackHandler tester = new ItemStackHandler(1); - tester.setStackInSlot(0, stack); - RecipeWrapper inventoryIn = new RecipeWrapper(tester); - - if (lastRecipe != null && lastRecipe.matches(inventoryIn, level)) - return true; - return AllRecipeTypes.MILLING.find(inventoryIn, level) - .isPresent(); - } - - private class MillstoneInventoryHandler extends CombinedInvWrapper { - - public MillstoneInventoryHandler() { - super(inputInv, outputInv); - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - if (outputInv == getHandlerFromIndex(getIndexForSlot(slot))) - return false; - return canProcess(stack) && super.isItemValid(slot, stack); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (outputInv == getHandlerFromIndex(getIndexForSlot(slot))) - return stack; - if (!isItemValid(slot, stack)) - return stack; - return super.insertItem(slot, stack, simulate); - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (inputInv == getHandlerFromIndex(getIndexForSlot(slot))) - return ItemStack.EMPTY; - return super.extractItem(slot, amount, simulate); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java deleted file mode 100644 index 7e25e410e9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/CompactingRecipe.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.simibubi.create.content.contraptions.components.mixer; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; - -public class CompactingRecipe extends BasinRecipe { - - public CompactingRecipe(ProcessingRecipeParams params) { - super(AllRecipeTypes.COMPACTING, params); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java deleted file mode 100644 index b3882edde4..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerRenderer.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.simibubi.create.content.contraptions.components.mixer; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; - -public class MechanicalMixerRenderer extends KineticTileEntityRenderer { - - public MechanicalMixerRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - public boolean shouldRenderOffScreen(KineticTileEntity te) { - return true; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState blockState = te.getBlockState(); - MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) te; - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllBlockPartials.SHAFTLESS_COGWHEEL, blockState); - standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb); - - float renderedHeadOffset = mixer.getRenderedHeadOffset(partialTicks); - float speed = mixer.getRenderedHeadRotationSpeed(partialTicks); - float time = WorldTickHolder.getRenderTime(te.getLevel()); - float angle = ((time * speed * 6 / 10f) % 360) / 180 * (float) Math.PI; - - SuperByteBuffer poleRender = CachedPartialBuffers.partial(AllBlockPartials.MECHANICAL_MIXER_POLE, blockState); - poleRender.translate(0, -renderedHeadOffset, 0) - .light(light) - .renderInto(ms, vb); - - SuperByteBuffer headRender = CachedPartialBuffers.partial(AllBlockPartials.MECHANICAL_MIXER_HEAD, blockState); - headRender.rotateCentered(Direction.UP, angle) - .translate(0, -renderedHeadOffset, 0) - .light(light) - .renderInto(ms, vb); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java deleted file mode 100644 index 09645eb47a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java +++ /dev/null @@ -1,314 +0,0 @@ -package com.simibubi.create.content.contraptions.components.mixer; - -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; -import com.simibubi.create.content.contraptions.fluids.FluidFX; -import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipes; -import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEntity; -import com.simibubi.create.content.contraptions.processing.BasinTileEntity; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.advancement.CreateAdvancement; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.Container; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingRecipe; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.crafting.IShapedRecipe; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { - - private static final Object shapelessOrMixingRecipesKey = new Object(); - - public int runningTicks; - public int processingTicks; - public boolean running; - - public MechanicalMixerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - public float getRenderedHeadOffset(float partialTicks) { - int localTick; - float offset = 0; - if (running) { - if (runningTicks < 20) { - localTick = runningTicks; - float num = (localTick + partialTicks) / 20f; - num = ((2 - Mth.cos((float) (num * Math.PI))) / 2); - offset = num - .5f; - } else if (runningTicks <= 20) { - offset = 1; - } else { - localTick = 40 - runningTicks; - float num = (localTick - partialTicks) / 20f; - num = ((2 - Mth.cos((float) (num * Math.PI))) / 2); - offset = num - .5f; - } - } - return offset + 7 / 16f; - } - - public float getRenderedHeadRotationSpeed(float partialTicks) { - float speed = getSpeed(); - if (running) { - if (runningTicks < 15) { - return speed; - } - if (runningTicks <= 20) { - return speed * 2; - } - return speed; - } - return speed / 2; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.MIXER); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).expandTowards(0, -1.5, 0); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - running = compound.getBoolean("Running"); - runningTicks = compound.getInt("Ticks"); - super.read(compound, clientPacket); - - if (clientPacket && hasLevel()) - getBasin().ifPresent(bte -> bte.setAreFluidsMoving(running && runningTicks <= 20)); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Running", running); - compound.putInt("Ticks", runningTicks); - super.write(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - - if (runningTicks >= 40) { - running = false; - runningTicks = 0; - basinChecker.scheduleUpdate(); - return; - } - - float speed = Math.abs(getSpeed()); - if (running && level != null) { - if (level.isClientSide && runningTicks == 20) - renderParticles(); - - if ((!level.isClientSide || isVirtual()) && runningTicks == 20) { - if (processingTicks < 0) { - float recipeSpeed = 1; - if (currentRecipe instanceof ProcessingRecipe) { - int t = ((ProcessingRecipe) currentRecipe).getProcessingDuration(); - if (t != 0) - recipeSpeed = t / 100f; - } - - processingTicks = Mth.clamp((Mth.log2((int) (512 / speed))) * Mth.ceil(recipeSpeed * 15) + 1, 1, 512); - - Optional basin = getBasin(); - if (basin.isPresent()) { - Couple tanks = basin.get() - .getTanks(); - if (!tanks.getFirst() - .isEmpty() - || !tanks.getSecond() - .isEmpty()) - level.playSound(null, worldPosition, SoundEvents.BUBBLE_COLUMN_WHIRLPOOL_AMBIENT, - SoundSource.BLOCKS, .75f, speed < 65 ? .75f : 1.5f); - } - - } else { - processingTicks--; - if (processingTicks == 0) { - runningTicks++; - processingTicks = -1; - applyBasinRecipe(); - sendData(); - } - } - } - - if (runningTicks != 20) - runningTicks++; - } - } - - public void renderParticles() { - Optional basin = getBasin(); - if (!basin.isPresent() || level == null) - return; - - for (SmartInventory inv : basin.get() - .getInvs()) { - for (int slot = 0; slot < inv.getSlots(); slot++) { - ItemStack stackInSlot = inv.getItem(slot); - if (stackInSlot.isEmpty()) - continue; - ItemParticleOption data = new ItemParticleOption(ParticleTypes.ITEM, stackInSlot); - spillParticle(data); - } - } - - for (SmartFluidTankBehaviour behaviour : basin.get() - .getTanks()) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) { - if (tankSegment.isEmpty(0)) - continue; - spillParticle(FluidFX.getFluidParticle(tankSegment.getRenderedFluid())); - } - } - } - - protected void spillParticle(ParticleOptions data) { - float angle = level.random.nextFloat() * 360; - Vec3 offset = new Vec3(0, 0, 0.25f); - offset = VecHelper.rotate(offset, angle, Axis.Y); - Vec3 target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y) - .add(0, .25f, 0); - Vec3 center = offset.add(VecHelper.getCenterOf(worldPosition)); - target = VecHelper.offsetRandomly(target.subtract(offset), level.random, 1 / 128f); - level.addParticle(data, center.x, center.y - 1.75f, center.z, target.x, target.y, target.z); - } - - @Override - protected List> getMatchingRecipes() { - List> matchingRecipes = super.getMatchingRecipes(); - - if (!AllConfigs.SERVER.recipes.allowBrewingInMixer.get()) - return matchingRecipes; - - Optional basin = getBasin(); - if (!basin.isPresent()) - return matchingRecipes; - - BasinTileEntity basinTileEntity = basin.get(); - if (basin.isEmpty()) - return matchingRecipes; - - IItemHandler availableItems = basinTileEntity - .getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - .orElse(null); - if (availableItems == null) - return matchingRecipes; - - for (int i = 0; i < availableItems.getSlots(); i++) { - ItemStack stack = availableItems.getStackInSlot(i); - if (stack.isEmpty()) - continue; - - List list = PotionMixingRecipes.BY_ITEM.get(stack.getItem()); - if (list == null) - continue; - for (MixingRecipe mixingRecipe : list) - if (matchBasinRecipe(mixingRecipe)) - matchingRecipes.add(mixingRecipe); - } - - return matchingRecipes; - } - - @Override - protected boolean matchStaticFilters(Recipe r) { - return ((r instanceof CraftingRecipe && !(r instanceof IShapedRecipe) - && AllConfigs.SERVER.recipes.allowShapelessInMixer.get() && r.getIngredients() - .size() > 1 - && !MechanicalPressTileEntity.canCompress(r)) && !AllRecipeTypes.shouldIgnoreInAutomation(r) - || r.getType() == AllRecipeTypes.MIXING.getType()); - } - - @Override - public void startProcessingBasin() { - if (running && runningTicks <= 20) - return; - super.startProcessingBasin(); - running = true; - runningTicks = 0; - } - - @Override - public boolean continueWithPreviousRecipe() { - runningTicks = 20; - return true; - } - - @Override - protected void onBasinRemoved() { - if (!running) - return; - runningTicks = 40; - running = false; - } - - @Override - protected Object getRecipeCacheKey() { - return shapelessOrMixingRecipesKey; - } - - @Override - protected boolean isRunning() { - return running; - } - - @Override - protected Optional getProcessedRecipeTrigger() { - return Optional.of(AllAdvancements.MIXER); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - super.tickAudio(); - - // SoundEvents.BLOCK_STONE_BREAK - boolean slow = Math.abs(getSpeed()) < 65; - if (slow && AnimationTickHolder.getTicks() % 2 == 0) - return; - if (runningTicks == 20) - AllSoundEvents.MIXING.playAt(level, worldPosition, .75f, 1, true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java deleted file mode 100644 index 11bb3df77c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixerInstance.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.simibubi.create.content.contraptions.components.mixer; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogInstance; -import com.simibubi.create.foundation.render.AllMaterialSpecs; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.core.Direction; - -public class MixerInstance extends EncasedCogInstance implements DynamicInstance { - - private final RotatingData mixerHead; - private final OrientedData mixerPole; - private final MechanicalMixerTileEntity mixer; - - public MixerInstance(MaterialManager dispatcher, MechanicalMixerTileEntity tile) { - super(dispatcher, tile, false); - this.mixer = tile; - - mixerHead = getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_MIXER_HEAD, blockState) - .createInstance(); - - mixerHead.setRotationAxis(Direction.Axis.Y); - - mixerPole = getOrientedMaterial() - .getModel(AllBlockPartials.MECHANICAL_MIXER_POLE, blockState) - .createInstance(); - - - float renderedHeadOffset = getRenderedHeadOffset(); - - transformPole(renderedHeadOffset); - transformHead(renderedHeadOffset); - } - - @Override - protected Instancer getCogModel() { - return materialManager.defaultSolid() - .material(AllMaterialSpecs.ROTATING) - .getModel(AllBlockPartials.SHAFTLESS_COGWHEEL, blockEntity.getBlockState()); - } - - @Override - public void beginFrame() { - - float renderedHeadOffset = getRenderedHeadOffset(); - - transformPole(renderedHeadOffset); - transformHead(renderedHeadOffset); - } - - private void transformHead(float renderedHeadOffset) { - float speed = mixer.getRenderedHeadRotationSpeed(AnimationTickHolder.getPartialTicks()); - - mixerHead.setPosition(getInstancePosition()) - .nudge(0, -renderedHeadOffset, 0) - .setRotationalSpeed(speed * 2); - } - - private void transformPole(float renderedHeadOffset) { - mixerPole.setPosition(getInstancePosition()) - .nudge(0, -renderedHeadOffset, 0); - } - - private float getRenderedHeadOffset() { - return mixer.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()); - } - - @Override - public void updateLight() { - super.updateLight(); - - relight(pos.below(), mixerHead); - relight(pos, mixerPole); - } - - @Override - public void remove() { - super.remove(); - mixerHead.delete(); - mixerPole.delete(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java deleted file mode 100644 index 12e1d7b0f4..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MixingRecipe.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.simibubi.create.content.contraptions.components.mixer; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.BasinRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; - -public class MixingRecipe extends BasinRecipe { - - public MixingRecipe(ProcessingRecipeParams params) { - super(AllRecipeTypes.MIXING, params); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java deleted file mode 100644 index 68ab979ee8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorRenderer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.simibubi.create.content.contraptions.components.motor; - -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class CreativeMotorRenderer extends KineticTileEntityRenderer { - - public CreativeMotorRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorTileEntity.java deleted file mode 100644 index 0d64ed497b..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorTileEntity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.simibubi.create.content.contraptions.components.motor; - -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class CreativeMotorTileEntity extends GeneratingKineticTileEntity { - - public static final int DEFAULT_SPEED = 16; - protected ScrollValueBehaviour generatedSpeed; - - public CreativeMotorTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - Integer max = AllConfigs.SERVER.kinetics.maxMotorSpeed.get(); - - CenteredSideValueBoxTransform slot = new CenteredSideValueBoxTransform( - (motor, side) -> motor.getValue(CreativeMotorBlock.FACING) == side.getOpposite()); - - generatedSpeed = new ScrollValueBehaviour(CreateLang.translateDirect("generic.speed"), this, slot); - generatedSpeed.between(-max, max); - generatedSpeed.value = DEFAULT_SPEED; - generatedSpeed.scrollableValue = DEFAULT_SPEED; - generatedSpeed.withUnit(i -> CreateLang.translateDirect("generic.unit.rpm")); - generatedSpeed.withCallback(i -> this.updateGeneratedRotation()); - generatedSpeed.withStepFunction(CreativeMotorTileEntity::step); - behaviours.add(generatedSpeed); - } - - @Override - public void initialize() { - super.initialize(); - if (!hasSource() || getGeneratedSpeed() > getTheoreticalSpeed()) - updateGeneratedRotation(); - } - - @Override - public float getGeneratedSpeed() { - if (!AllBlocks.CREATIVE_MOTOR.has(getBlockState())) - return 0; - return convertToDirection(generatedSpeed.getValue(), getBlockState().getValue(CreativeMotorBlock.FACING)); - } - - public static int step(StepContext context) { - int current = context.currentValue; - int step = 1; - - if (!context.shift) { - int magnitude = Math.abs(current) - (context.forward == current > 0 ? 0 : 1); - - if (magnitude >= 4) - step *= 4; - if (magnitude >= 32) - step *= 4; - if (magnitude >= 128) - step *= 4; - } - - return (int) (current + (context.forward ? step : -step) == 0 ? step + 1 : step); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java deleted file mode 100644 index def61353db..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/BeltPressingCallbacks.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.simibubi.create.content.contraptions.components.press; - -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.HOLD; -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.PASS; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; - -import net.minecraft.world.item.ItemStack; - -public class BeltPressingCallbacks { - - static ProcessingResult onItemReceived(TransportedItemStack transported, - TransportedItemStackHandlerBehaviour handler, PressingBehaviour behaviour) { - if (behaviour.specifics.getKineticSpeed() == 0) - return PASS; - if (behaviour.running) - return HOLD; - if (!behaviour.specifics.tryProcessOnBelt(transported, null, true)) - return PASS; - - behaviour.start(Mode.BELT); - return HOLD; - } - - static ProcessingResult whenItemHeld(TransportedItemStack transported, TransportedItemStackHandlerBehaviour handler, - PressingBehaviour behaviour) { - - if (behaviour.specifics.getKineticSpeed() == 0) - return PASS; - if (!behaviour.running) - return PASS; - if (behaviour.runningTicks != PressingBehaviour.CYCLE / 2) - return HOLD; - - behaviour.particleItems.clear(); - ArrayList results = new ArrayList<>(); - if (!behaviour.specifics.tryProcessOnBelt(transported, results, false)) - return PASS; - - boolean bulk = behaviour.specifics.canProcessInBulk() || transported.stack.getCount() == 1; - - List collect = results.stream() - .map(stack -> { - TransportedItemStack copy = transported.copy(); - boolean centered = BeltHelper.isItemUpright(stack); - copy.stack = stack; - copy.locked = true; - copy.angle = centered ? 180 : Create.RANDOM.nextInt(360); - return copy; - }) - .collect(Collectors.toList()); - - if (bulk) { - if (collect.isEmpty()) - handler.handleProcessingOnItem(transported, TransportedResult.removeItem()); - else - handler.handleProcessingOnItem(transported, TransportedResult.convertTo(collect)); - - } else { - TransportedItemStack left = transported.copy(); - left.stack.shrink(1); - - if (collect.isEmpty()) - handler.handleProcessingOnItem(transported, TransportedResult.convertTo(left)); - else - handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(collect, left)); - } - - behaviour.tileEntity.sendData(); - return HOLD; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java deleted file mode 100644 index 2911b6193a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressRenderer.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.contraptions.components.press; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class MechanicalPressRenderer extends KineticTileEntityRenderer { - - public MechanicalPressRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - public boolean shouldRenderOffScreen(KineticTileEntity te) { - return true; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) - return; - - BlockState blockState = te.getBlockState(); - PressingBehaviour pressingBehaviour = ((MechanicalPressTileEntity) te).getPressingBehaviour(); - float renderedHeadOffset = - pressingBehaviour.getRenderedHeadOffset(partialTicks) * pressingBehaviour.mode.headOffset; - - SuperByteBuffer headRender = CachedPartialBuffers.partialFacing(AllBlockPartials.MECHANICAL_PRESS_HEAD, blockState, - blockState.getValue(HORIZONTAL_FACING)); - headRender.translate(0, -renderedHeadOffset, 0) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java deleted file mode 100644 index 4ed5244a2e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.simibubi.create.content.contraptions.components.press; - -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe; -import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode; -import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.PressingBehaviourSpecifics; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEntity; -import com.simibubi.create.content.contraptions.processing.BasinTileEntity; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.advancement.CreateAdvancement; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingRecipe; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class MechanicalPressTileEntity extends BasinOperatingTileEntity implements PressingBehaviourSpecifics { - - private static final Object compressingRecipesKey = new Object(); - - public PressingBehaviour pressingBehaviour; - private int tracksCreated; - - public MechanicalPressTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).expandTowards(0, -1.5, 0) - .expandTowards(0, 1, 0); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - pressingBehaviour = new PressingBehaviour(this); - behaviours.add(pressingBehaviour); - - registerAwardables(behaviours, AllAdvancements.PRESS, AllAdvancements.COMPACTING, - AllAdvancements.TRACK_CRAFTING); - } - - public void onItemPressed(ItemStack result) { - award(AllAdvancements.PRESS); - if (AllBlocks.TRACK.isIn(result)) - tracksCreated += result.getCount(); - if (tracksCreated >= 1000) { - award(AllAdvancements.TRACK_CRAFTING); - tracksCreated = 0; - } - } - - public PressingBehaviour getPressingBehaviour() { - return pressingBehaviour; - } - - @Override - public boolean tryProcessInBasin(boolean simulate) { - applyBasinRecipe(); - - Optional basin = getBasin(); - if (basin.isPresent()) { - SmartInventory inputs = basin.get() - .getInputInventory(); - for (int slot = 0; slot < inputs.getSlots(); slot++) { - ItemStack stackInSlot = inputs.getItem(slot); - if (stackInSlot.isEmpty()) - continue; - pressingBehaviour.particleItems.add(stackInSlot); - } - } - - return true; - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - if (getBehaviour(AdvancementBehaviour.TYPE).isOwnerPresent()) - compound.putInt("TracksCreated", tracksCreated); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - tracksCreated = compound.getInt("TracksCreated"); - } - - @Override - public boolean tryProcessInWorld(ItemEntity itemEntity, boolean simulate) { - ItemStack item = itemEntity.getItem(); - Optional recipe = getRecipe(item); - if (!recipe.isPresent()) - return false; - if (simulate) - return true; - - ItemStack itemCreated = ItemStack.EMPTY; - pressingBehaviour.particleItems.add(item); - if (canProcessInBulk() || item.getCount() == 1) { - InWorldProcessing.applyRecipeOn(itemEntity, recipe.get()); - itemCreated = itemEntity.getItem() - .copy(); - } else { - for (ItemStack result : InWorldProcessing.applyRecipeOn(ItemHandlerHelper.copyStackWithSize(item, 1), - recipe.get())) { - if (itemCreated.isEmpty()) - itemCreated = result.copy(); - ItemEntity created = - new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), result); - created.setDefaultPickUpDelay(); - created.setDeltaMovement(VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, .05f)); - level.addFreshEntity(created); - } - item.shrink(1); - } - - if (!itemCreated.isEmpty()) - onItemPressed(itemCreated); - return true; - } - - @Override - public boolean tryProcessOnBelt(TransportedItemStack input, List outputList, boolean simulate) { - Optional recipe = getRecipe(input.stack); - if (!recipe.isPresent()) - return false; - if (simulate) - return true; - pressingBehaviour.particleItems.add(input.stack); - List outputs = InWorldProcessing.applyRecipeOn( - canProcessInBulk() ? input.stack : ItemHandlerHelper.copyStackWithSize(input.stack, 1), recipe.get()); - - for (ItemStack created : outputs) { - if (!created.isEmpty()) { - onItemPressed(created); - break; - } - } - - outputList.addAll(outputs); - return true; - } - - @Override - public void onPressingCompleted() { - if (pressingBehaviour.onBasin() && matchBasinRecipe(currentRecipe) - && getBasin().filter(BasinTileEntity::canContinueProcessing) - .isPresent()) - startProcessingBasin(); - else - basinChecker.scheduleUpdate(); - } - - private static final RecipeWrapper pressingInv = new RecipeWrapper(new ItemStackHandler(1)); - - public Optional getRecipe(ItemStack item) { - Optional assemblyRecipe = - SequencedAssemblyRecipe.getRecipe(level, item, AllRecipeTypes.PRESSING.getType(), PressingRecipe.class); - if (assemblyRecipe.isPresent()) - return assemblyRecipe; - - pressingInv.setItem(0, item); - return AllRecipeTypes.PRESSING.find(pressingInv, level); - } - - public static boolean canCompress(Recipe recipe) { - if (!(recipe instanceof CraftingRecipe) || !AllConfigs.SERVER.recipes.allowShapedSquareInPress.get()) - return false; - NonNullList ingredients = recipe.getIngredients(); - return (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.matchAllIngredients(ingredients); - } - - @Override - protected boolean matchStaticFilters(Recipe recipe) { - return (recipe instanceof CraftingRecipe && !(recipe instanceof MechanicalCraftingRecipe) && canCompress(recipe) - && !AllRecipeTypes.shouldIgnoreInAutomation(recipe)) - || recipe.getType() == AllRecipeTypes.COMPACTING.getType(); - } - - @Override - public float getKineticSpeed() { - return getSpeed(); - } - - @Override - public boolean canProcessInBulk() { - return AllConfigs.SERVER.recipes.bulkPressing.get(); - } - - @Override - protected Object getRecipeCacheKey() { - return compressingRecipesKey; - } - - @Override - public int getParticleAmount() { - return 15; - } - - @Override - public void startProcessingBasin() { - if (pressingBehaviour.running && pressingBehaviour.runningTicks <= PressingBehaviour.CYCLE / 2) - return; - super.startProcessingBasin(); - pressingBehaviour.start(Mode.BASIN); - } - - @Override - protected void onBasinRemoved() { - pressingBehaviour.particleItems.clear(); - pressingBehaviour.running = false; - pressingBehaviour.runningTicks = 0; - sendData(); - } - - @Override - protected boolean isRunning() { - return pressingBehaviour.running; - } - - @Override - protected Optional getProcessedRecipeTrigger() { - return Optional.of(AllAdvancements.COMPACTING); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java deleted file mode 100644 index 8d1afbfb76..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressInstance.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.contraptions.components.press; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.mojang.math.Quaternion; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; - -public class PressInstance extends ShaftInstance implements DynamicInstance { - - private final OrientedData pressHead; - private final MechanicalPressTileEntity press; - - public PressInstance(MaterialManager dispatcher, MechanicalPressTileEntity tile) { - super(dispatcher, tile); - press = tile; - - pressHead = dispatcher.defaultSolid() - .material(Materials.ORIENTED) - .getModel(AllBlockPartials.MECHANICAL_PRESS_HEAD, blockState) - .createInstance(); - - Quaternion q = Vector3f.YP - .rotationDegrees(AngleHelper.horizontalAngle(blockState.getValue(MechanicalPressBlock.HORIZONTAL_FACING))); - - pressHead.setRotation(q); - - transformModels(); - } - - @Override - public void beginFrame() { - transformModels(); - } - - private void transformModels() { - float renderedHeadOffset = getRenderedHeadOffset(press); - - pressHead.setPosition(getInstancePosition()) - .nudge(0, -renderedHeadOffset, 0); - } - - private float getRenderedHeadOffset(MechanicalPressTileEntity press) { - PressingBehaviour pressingBehaviour = press.getPressingBehaviour(); - return pressingBehaviour.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()) - * pressingBehaviour.mode.headOffset; - } - - @Override - public void updateLight() { - super.updateLight(); - - relight(pos, pressHead); - } - - @Override - public void remove() { - super.remove(); - pressHead.delete(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawBlock.java deleted file mode 100644 index 4054b8d869..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawBlock.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.simibubi.create.content.contraptions.components.saw; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.components.actors.DrillBlock; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.PushReaction; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class SawBlock extends DirectionalAxisKineticBlock implements ITE { - public static DamageSource damageSourceSaw = new DamageSource("create.mechanical_saw").bypassArmor(); - - public SawBlock(Properties properties) { - super(properties); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState stateForPlacement = super.getStateForPlacement(context); - Direction facing = stateForPlacement.getValue(FACING); - if (facing.getAxis().isVertical()) - return stateForPlacement; - return stateForPlacement.setValue(AXIS_ALONG_FIRST_COORDINATE, facing.getAxis() == Axis.X); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return AllShapes.CASING_12PX.get(state.getValue(FACING)); - } - - @Override - public void entityInside(BlockState state, Level worldIn, BlockPos pos, Entity entityIn) { - if (entityIn instanceof ItemEntity) - return; - if (!new AABB(pos).deflate(.1f).intersects(entityIn.getBoundingBox())) - return; - withTileEntityDo(worldIn, pos, te -> { - if (te.getSpeed() == 0) - return; - entityIn.hurt(damageSourceSaw, (float) DrillBlock.getDamage(te.getSpeed())); - }); - } - - @Override - public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { - super.updateEntityAfterFallOn(worldIn, entityIn); - if (!(entityIn instanceof ItemEntity)) - return; - if (entityIn.level.isClientSide) - return; - - BlockPos pos = entityIn.blockPosition(); - withTileEntityDo(entityIn.level, pos, te -> { - if (te.getSpeed() == 0) - return; - te.insertItem((ItemEntity) entityIn); - }); - } - - @Override - public PushReaction getPistonPushReaction(BlockState state) { - return PushReaction.NORMAL; - } - - public static boolean isHorizontal(BlockState state) { - return state.getValue(FACING).getAxis().isHorizontal(); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return isHorizontal(state) ? state.getValue(FACING).getAxis() : super.getRotationAxis(state); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return isHorizontal(state) ? face == state.getValue(FACING).getOpposite() - : super.hasShaftTowards(world, pos, state, face); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) - return; - - withTileEntityDo(worldIn, pos, te -> ItemHelper.dropContents(worldIn, pos, te.inventory)); - TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE); - worldIn.removeBlockEntity(pos); - } - - @Override - public Class getTileEntityClass() { - return SawTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SAW.get(); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawFilterSlot.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawFilterSlot.java deleted file mode 100644 index bab4a34961..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawFilterSlot.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.simibubi.create.content.contraptions.components.saw; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class SawFilterSlot extends ValueBoxTransform { - - @Override - protected Vec3 getLocalOffset(BlockState state) { - if (state.getValue(SawBlock.FACING) != Direction.UP) - return null; - Vec3 x = VecHelper.voxelSpace(8f, 12.5f, 12.25f); - Vec3 z = VecHelper.voxelSpace(12.25f, 12.5f, 8f); - return state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? z : x; - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - int yRot = state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? 270 : 180; - TransformStack.cast(ms) - .rotateY(yRot) - .rotateX(90); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java deleted file mode 100644 index bba424cbf4..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawInstance.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.simibubi.create.content.contraptions.components.saw; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class SawInstance extends SingleRotatingInstance { - - public SawInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - if (blockState.getValue(BlockStateProperties.FACING) - .getAxis() - .isHorizontal()) { - BlockState referenceState = blockState.rotate(blockEntity.getLevel(), blockEntity.getBlockPos(), Rotation.CLOCKWISE_180); - Direction facing = referenceState.getValue(BlockStateProperties.FACING); - return getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, referenceState, facing); - } else { - return getRotatingMaterial().getModel(shaft()); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java deleted file mode 100644 index 476c55bb0e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawRenderer.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.simibubi.create.content.contraptions.components.saw; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class SawRenderer extends SafeTileEntityRenderer { - - public SawRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(SawTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, - int overlay) { - renderBlade(te, ms, buffer, light); - renderItems(te, partialTicks, ms, buffer, light, overlay); - FilteringRenderer.renderOnTileEntity(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) - return; - - renderShaft(te, ms, buffer, light, overlay); - } - - protected void renderBlade(SawTileEntity te, PoseStack ms, MultiBufferSource buffer, int light) { - BlockState blockState = te.getBlockState(); - PartialModel partial; - float speed = te.getSpeed(); - boolean rotate = false; - - if (SawBlock.isHorizontal(blockState)) { - if (speed > 0) { - partial = AllBlockPartials.SAW_BLADE_HORIZONTAL_ACTIVE; - } else if (speed < 0) { - partial = AllBlockPartials.SAW_BLADE_HORIZONTAL_REVERSED; - } else { - partial = AllBlockPartials.SAW_BLADE_HORIZONTAL_INACTIVE; - } - } else { - if (te.getSpeed() > 0) { - partial = AllBlockPartials.SAW_BLADE_VERTICAL_ACTIVE; - } else if (speed < 0) { - partial = AllBlockPartials.SAW_BLADE_VERTICAL_REVERSED; - } else { - partial = AllBlockPartials.SAW_BLADE_VERTICAL_INACTIVE; - } - - if (blockState.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE)) - rotate = true; - } - - SuperByteBuffer superBuffer = CachedPartialBuffers.partialFacing(partial, blockState); - if (rotate) { - superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(90)); - } - superBuffer.color(0xFFFFFF) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); - } - - protected void renderShaft(SawTileEntity te, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - KineticTileEntityRenderer.renderRotatingBuffer(te, getRotatedModel(te), ms, - buffer.getBuffer(RenderType.solid()), light); - } - - protected void renderItems(SawTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - boolean processingMode = te.getBlockState() - .getValue(SawBlock.FACING) == Direction.UP; - if (processingMode && !te.inventory.isEmpty()) { - boolean alongZ = !te.getBlockState() - .getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE); - ms.pushPose(); - - boolean moving = te.inventory.recipeDuration != 0; - float offset = moving ? (float) (te.inventory.remainingTime) / te.inventory.recipeDuration : 0; - float processingSpeed = Mth.clamp(Math.abs(te.getSpeed()) / 32, 1, 128); - if (moving) { - offset = Mth - .clamp(offset + ((-partialTicks + .5f) * processingSpeed) / te.inventory.recipeDuration, 0.125f, 1f); - if (!te.inventory.appliedRecipe) - offset += 1; - offset /= 2; - } - - if (te.getSpeed() == 0) - offset = .5f; - if (te.getSpeed() < 0 ^ alongZ) - offset = 1 - offset; - - for (int i = 0; i < te.inventory.getSlots(); i++) { - ItemStack stack = te.inventory.getStackInSlot(i); - if (stack.isEmpty()) - continue; - - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - BakedModel modelWithOverrides = itemRenderer.getModel(stack, te.getLevel(), null, 0); - boolean blockItem = modelWithOverrides.isGui3d(); - - ms.translate(alongZ ? offset : .5, blockItem ? .925f : 13f / 16f, alongZ ? .5 : offset); - - ms.scale(.5f, .5f, .5f); - if (alongZ) - ms.mulPose(Vector3f.YP.rotationDegrees(90)); - ms.mulPose(Vector3f.XP.rotationDegrees(90)); - itemRenderer.renderStatic(stack, ItemTransforms.TransformType.FIXED, light, overlay, ms, buffer, 0); - break; - } - - ms.popPose(); - } - } - - protected SuperByteBuffer getRotatedModel(KineticTileEntity te) { - BlockState state = te.getBlockState(); - if (state.getValue(FACING) - .getAxis() - .isHorizontal()) - return CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, - state.rotate(te.getLevel(), te.getBlockPos(), Rotation.CLOCKWISE_180)); - return CachedBlockBuffers.block(KineticTileEntityRenderer.KINETIC_TILE, - getRenderedBlockState(te)); - } - - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)); - } - - public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) { - BlockState state = context.state; - Direction facing = state.getValue(SawBlock.FACING); - - Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING) - .getNormal()); - facingVec = context.rotation.apply(facingVec); - - Direction closestToFacing = Direction.getNearest(facingVec.x, facingVec.y, facingVec.z); - - boolean horizontal = closestToFacing.getAxis() - .isHorizontal(); - boolean backwards = VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()); - boolean moving = context.getAnimationSpeed() != 0; - boolean shouldAnimate = - (context.contraption.stalled && horizontal) || (!context.contraption.stalled && !backwards && moving); - - SuperByteBuffer sBuffer; - if (SawBlock.isHorizontal(state)) { - if (shouldAnimate) - sBuffer = CachedPartialBuffers.partial(AllBlockPartials.SAW_BLADE_HORIZONTAL_ACTIVE, state); - else - sBuffer = CachedPartialBuffers.partial(AllBlockPartials.SAW_BLADE_HORIZONTAL_INACTIVE, state); - } else { - if (shouldAnimate) - sBuffer = CachedPartialBuffers.partial(AllBlockPartials.SAW_BLADE_VERTICAL_ACTIVE, state); - else - sBuffer = CachedPartialBuffers.partial(AllBlockPartials.SAW_BLADE_VERTICAL_INACTIVE, state); - } - - sBuffer.transform(matrices.getModel()) - .centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(AngleHelper.verticalAngle(facing)); - - if (!SawBlock.isHorizontal(state)) { - sBuffer.rotateZ(state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? 90 : 0); - } - - sBuffer.unCentre() - .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.cutoutMipped())); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java deleted file mode 100644 index b62cb60201..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ /dev/null @@ -1,502 +0,0 @@ -package com.simibubi.create.content.contraptions.components.saw; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableList; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.actors.BlockBreakingKineticTileEntity; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingInventory; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue; -import com.simibubi.create.foundation.utility.TreeCutter; -import com.simibubi.create.foundation.utility.recipe.RecipeConditions; -import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Registry; -import net.minecraft.core.particles.BlockParticleOption; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.BlockTags; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraft.world.item.crafting.StonecutterRecipe; -import net.minecraft.world.level.block.BambooBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.CactusBlock; -import net.minecraft.world.level.block.ChorusPlantBlock; -import net.minecraft.world.level.block.KelpBlock; -import net.minecraft.world.level.block.KelpPlantBlock; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.StemGrownBlock; -import net.minecraft.world.level.block.SugarCaneBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class SawTileEntity extends BlockBreakingKineticTileEntity { - - private static final Object cuttingRecipesKey = new Object(); - public static final Supplier> woodcuttingRecipeType = - Suppliers.memoize(() -> Registry.RECIPE_TYPE.get(new ResourceLocation("druidcraft", "woodcutting"))); - - public ProcessingInventory inventory; - private int recipeIndex; - private final LazyOptional invProvider; - private FilteringBehaviour filtering; - - private ItemStack playEvent; - - public SawTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inventory = new ProcessingInventory(this::start).withSlotLimit(!AllConfigs.SERVER.recipes.bulkCutting.get()); - inventory.remainingTime = -1; - recipeIndex = 0; - invProvider = LazyOptional.of(() -> inventory); - playEvent = ItemStack.EMPTY; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - filtering = new FilteringBehaviour(this, new SawFilterSlot()).forRecipes(); - behaviours.add(filtering); - behaviours.add(new DirectBeltInputBehaviour(this).allowingBeltFunnelsWhen(this::canProcess)); - registerAwardables(behaviours, AllAdvancements.SAW_PROCESSING); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.put("Inventory", inventory.serializeNBT()); - compound.putInt("RecipeIndex", recipeIndex); - super.write(compound, clientPacket); - - if (!clientPacket || playEvent.isEmpty()) - return; - compound.put("PlayEvent", playEvent.serializeNBT()); - playEvent = ItemStack.EMPTY; - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - inventory.deserializeNBT(compound.getCompound("Inventory")); - recipeIndex = compound.getInt("RecipeIndex"); - if (compound.contains("PlayEvent")) - playEvent = ItemStack.of(compound.getCompound("PlayEvent")); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).inflate(.125f); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void tickAudio() { - super.tickAudio(); - if (getSpeed() == 0) - return; - - if (!playEvent.isEmpty()) { - boolean isWood = false; - Item item = playEvent.getItem(); - if (item instanceof BlockItem) { - Block block = ((BlockItem) item).getBlock(); - isWood = block.getSoundType(block.defaultBlockState(), level, worldPosition, null) == SoundType.WOOD; - } - spawnEventParticles(playEvent); - playEvent = ItemStack.EMPTY; - if (!isWood) - AllSoundEvents.SAW_ACTIVATE_STONE.playAt(level, worldPosition, 3, 1, true); - else - AllSoundEvents.SAW_ACTIVATE_WOOD.playAt(level, worldPosition, 3, 1, true); - return; - } - } - - @Override - public void tick() { - if (shouldRun() && ticksUntilNextProgress < 0) - destroyNextTick(); - super.tick(); - - if (!canProcess()) - return; - if (getSpeed() == 0) - return; - if (inventory.remainingTime == -1) { - if (!inventory.isEmpty() && !inventory.appliedRecipe) - start(inventory.getStackInSlot(0)); - return; - } - - float processingSpeed = Mth.clamp(Math.abs(getSpeed()) / 24, 1, 128); - inventory.remainingTime -= processingSpeed; - - if (inventory.remainingTime > 0) - spawnParticles(inventory.getStackInSlot(0)); - - if (inventory.remainingTime < 5 && !inventory.appliedRecipe) { - if (level.isClientSide && !isVirtual()) - return; - playEvent = inventory.getStackInSlot(0); - applyRecipe(); - inventory.appliedRecipe = true; - inventory.recipeDuration = 20; - inventory.remainingTime = 20; - sendData(); - return; - } - - Vec3 itemMovement = getItemMovementVec(); - Direction itemMovementFacing = Direction.getNearest(itemMovement.x, itemMovement.y, itemMovement.z); - if (inventory.remainingTime > 0) - return; - inventory.remainingTime = 0; - - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stack = inventory.getStackInSlot(slot); - if (stack.isEmpty()) - continue; - ItemStack tryExportingToBeltFunnel = getBehaviour(DirectBeltInputBehaviour.TYPE) - .tryExportingToBeltFunnel(stack, itemMovementFacing.getOpposite(), false); - if (tryExportingToBeltFunnel != null) { - if (tryExportingToBeltFunnel.getCount() != stack.getCount()) { - inventory.setStackInSlot(slot, tryExportingToBeltFunnel); - notifyUpdate(); - return; - } - if (!tryExportingToBeltFunnel.isEmpty()) - return; - } - } - - BlockPos nextPos = worldPosition.offset(itemMovement.x, itemMovement.y, itemMovement.z); - DirectBeltInputBehaviour behaviour = TileEntityBehaviour.get(level, nextPos, DirectBeltInputBehaviour.TYPE); - if (behaviour != null) { - boolean changed = false; - if (!behaviour.canInsertFromSide(itemMovementFacing)) - return; - if (level.isClientSide && !isVirtual()) - return; - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stack = inventory.getStackInSlot(slot); - if (stack.isEmpty()) - continue; - ItemStack remainder = behaviour.handleInsertion(stack, itemMovementFacing, false); - if (remainder.equals(stack, false)) - continue; - inventory.setStackInSlot(slot, remainder); - changed = true; - } - if (changed) { - setChanged(); - sendData(); - } - return; - } - - // Eject Items - Vec3 outPos = VecHelper.getCenterOf(worldPosition) - .add(itemMovement.scale(.5f) - .add(0, .5, 0)); - Vec3 outMotion = itemMovement.scale(.0625) - .add(0, .125, 0); - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stack = inventory.getStackInSlot(slot); - if (stack.isEmpty()) - continue; - ItemEntity entityIn = new ItemEntity(level, outPos.x, outPos.y, outPos.z, stack); - entityIn.setDeltaMovement(outMotion); - level.addFreshEntity(entityIn); - } - inventory.clear(); - level.updateNeighbourForOutputSignal(worldPosition, getBlockState().getBlock()); - inventory.remainingTime = -1; - sendData(); - } - - @Override - public void setRemoved() { - invProvider.invalidate(); - super.setRemoved(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && side != Direction.DOWN) - return invProvider.cast(); - return super.getCapability(cap, side); - } - - protected void spawnEventParticles(ItemStack stack) { - if (stack == null || stack.isEmpty()) - return; - - ParticleOptions particleData = null; - if (stack.getItem() instanceof BlockItem) - particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() - .defaultBlockState()); - else - particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); - - Random r = level.random; - Vec3 v = VecHelper.getCenterOf(this.worldPosition) - .add(0, 5 / 16f, 0); - for (int i = 0; i < 10; i++) { - Vec3 m = VecHelper.offsetRandomly(new Vec3(0, 0.25f, 0), r, .125f); - level.addParticle(particleData, v.x, v.y, v.z, m.x, m.y, m.y); - } - } - - protected void spawnParticles(ItemStack stack) { - if (stack == null || stack.isEmpty()) - return; - - ParticleOptions particleData = null; - float speed = 1; - if (stack.getItem() instanceof BlockItem) - particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() - .defaultBlockState()); - else { - particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); - speed = .125f; - } - - Random r = level.random; - Vec3 vec = getItemMovementVec(); - Vec3 pos = VecHelper.getCenterOf(this.worldPosition); - float offset = inventory.recipeDuration != 0 ? (float) (inventory.remainingTime) / inventory.recipeDuration : 0; - offset /= 2; - if (inventory.appliedRecipe) - offset -= .5f; - level.addParticle(particleData, pos.x() + -vec.x * offset, pos.y() + .45f, pos.z() + -vec.z * offset, - -vec.x * speed, r.nextFloat() * speed, -vec.z * speed); - } - - public Vec3 getItemMovementVec() { - boolean alongX = !getBlockState().getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE); - int offset = getSpeed() < 0 ? -1 : 1; - return new Vec3(offset * (alongX ? 1 : 0), 0, offset * (alongX ? 0 : -1)); - } - - private void applyRecipe() { - List> recipes = getRecipes(); - if (recipes.isEmpty()) - return; - if (recipeIndex >= recipes.size()) - recipeIndex = 0; - - Recipe recipe = recipes.get(recipeIndex); - - int rolls = inventory.getStackInSlot(0) - .getCount(); - inventory.clear(); - - List list = new ArrayList<>(); - for (int roll = 0; roll < rolls; roll++) { - List results = new LinkedList(); - if (recipe instanceof CuttingRecipe) - results = ((CuttingRecipe) recipe).rollResults(); - else if (recipe instanceof StonecutterRecipe || recipe.getType() == woodcuttingRecipeType.get()) - results.add(recipe.getResultItem() - .copy()); - - for (int i = 0; i < results.size(); i++) { - ItemStack stack = results.get(i); - ItemHelper.addToList(stack, list); - } - } - - for (int slot = 0; slot < list.size() && slot + 1 < inventory.getSlots(); slot++) - inventory.setStackInSlot(slot + 1, list.get(slot)); - - award(AllAdvancements.SAW_PROCESSING); - } - - private List> getRecipes() { - Optional assemblyRecipe = SequencedAssemblyRecipe.getRecipe(level, inventory.getStackInSlot(0), - AllRecipeTypes.CUTTING.getType(), CuttingRecipe.class); - if (assemblyRecipe.isPresent() && filtering.test(assemblyRecipe.get() - .getResultItem())) - return ImmutableList.of(assemblyRecipe.get()); - - Predicate> types = RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType(), - AllConfigs.SERVER.recipes.allowStonecuttingOnSaw.get() ? RecipeType.STONECUTTING : null, - AllConfigs.SERVER.recipes.allowWoodcuttingOnSaw.get() ? woodcuttingRecipeType.get() : null); - - List> startedSearch = RecipeFinder.get(cuttingRecipesKey, level, types); - return startedSearch.stream() - .filter(RecipeConditions.outputMatchesFilter(filtering)) - .filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))) - .filter(r -> !AllRecipeTypes.shouldIgnoreInAutomation(r)) - .collect(Collectors.toList()); - } - - public void insertItem(ItemEntity entity) { - if (!canProcess()) - return; - if (!inventory.isEmpty()) - return; - if (!entity.isAlive()) - return; - if (level.isClientSide) - return; - - inventory.clear(); - ItemStack remainder = inventory.insertItem(0, entity.getItem() - .copy(), false); - if (remainder.isEmpty()) - entity.discard(); - else - entity.setItem(remainder); - } - - public void start(ItemStack inserted) { - if (!canProcess()) - return; - if (inventory.isEmpty()) - return; - if (level.isClientSide && !isVirtual()) - return; - - List> recipes = getRecipes(); - boolean valid = !recipes.isEmpty(); - int time = 50; - - if (recipes.isEmpty()) { - inventory.remainingTime = inventory.recipeDuration = 10; - inventory.appliedRecipe = false; - sendData(); - return; - } - - if (valid) { - recipeIndex++; - if (recipeIndex >= recipes.size()) - recipeIndex = 0; - } - - Recipe recipe = recipes.get(recipeIndex); - if (recipe instanceof CuttingRecipe) { - time = ((CuttingRecipe) recipe).getProcessingDuration(); - } - - inventory.remainingTime = time * Math.max(1, (inserted.getCount() / 5)); - inventory.recipeDuration = inventory.remainingTime; - inventory.appliedRecipe = false; - sendData(); - } - - protected boolean canProcess() { - return getBlockState().getValue(SawBlock.FACING) == Direction.UP; - } - - // Block Breaker - - @Override - protected boolean shouldRun() { - return getBlockState().getValue(SawBlock.FACING) - .getAxis() - .isHorizontal(); - } - - @Override - protected BlockPos getBreakingPos() { - return getBlockPos().relative(getBlockState().getValue(SawBlock.FACING)); - } - - @Override - public void onBlockBroken(BlockState stateToBreak) { - Optional dynamicTree = - TreeCutter.findDynamicTree(stateToBreak.getBlock(), breakingPos); - if (dynamicTree.isPresent()) { - dynamicTree.get() - .destroyBlocks(level, null, this::dropItemFromCutTree); - return; - } - - super.onBlockBroken(stateToBreak); - TreeCutter.findTree(level, breakingPos) - .destroyBlocks(level, null, this::dropItemFromCutTree); - } - - public void dropItemFromCutTree(BlockPos pos, ItemStack stack) { - float distance = (float) Math.sqrt(pos.distSqr(breakingPos)); - Vec3 dropPos = VecHelper.getCenterOf(pos); - ItemEntity entity = new ItemEntity(level, dropPos.x, dropPos.y, dropPos.z, stack); - entity.setDeltaMovement(Vec3.atLowerCornerOf(breakingPos.subtract(this.worldPosition)) - .scale(distance / 20f)); - level.addFreshEntity(entity); - } - - @Override - public boolean canBreak(BlockState stateToBreak, float blockHardness) { - boolean sawable = isSawable(stateToBreak); - return super.canBreak(stateToBreak, blockHardness) && sawable; - } - - public static boolean isSawable(BlockState stateToBreak) { - if (stateToBreak.is(BlockTags.SAPLINGS)) - return false; - if (TreeCutter.isLog(stateToBreak) || (stateToBreak.is(BlockTags.LEAVES))) - return true; - Block block = stateToBreak.getBlock(); - if (block instanceof BambooBlock) - return true; - if (block instanceof StemGrownBlock) - return true; - if (block instanceof CactusBlock) - return true; - if (block instanceof SugarCaneBlock) - return true; - if (block instanceof KelpPlantBlock) - return true; - if (block instanceof KelpBlock) - return true; - if (block instanceof ChorusPlantBlock) - return true; - if (TreeCutter.canDynamicTreeCutFrom(block)) - return true; - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftTileEntity.java deleted file mode 100644 index 281fe05d6c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftTileEntity.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.foundation.block.BlockStressValues; - -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.registries.ForgeRegistries; - -public class PoweredShaftTileEntity extends GeneratingKineticTileEntity { - - public BlockPos enginePos; - public float engineEfficiency; - public int movementDirection; - public int initialTicks; - public Block capacityKey; - - public PoweredShaftTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - movementDirection = 1; - initialTicks = 3; - } - - @Override - public void tick() { - super.tick(); - if (initialTicks > 0) - initialTicks--; - } - - public void update(BlockPos sourcePos, int direction, float efficiency) { - BlockPos key = worldPosition.subtract(sourcePos); - enginePos = key; - float prev = engineEfficiency; - engineEfficiency = efficiency; - int prevDirection = this.movementDirection; - if (Mth.equal(efficiency, prev) && prevDirection == direction) - return; - - capacityKey = level.getBlockState(sourcePos) - .getBlock(); - this.movementDirection = direction; - updateGeneratedRotation(); - } - - public void remove(BlockPos sourcePos) { - if (!isPoweredBy(sourcePos)) - return; - - enginePos = null; - engineEfficiency = 0; - movementDirection = 0; - capacityKey = null; - updateGeneratedRotation(); - } - - public boolean canBePoweredBy(BlockPos globalPos) { - return initialTicks == 0 && (enginePos == null || isPoweredBy(globalPos)); - } - - public boolean isPoweredBy(BlockPos globalPos) { - BlockPos key = worldPosition.subtract(globalPos); - return key.equals(enginePos); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("Direction", movementDirection); - if (initialTicks > 0) - compound.putInt("Warmup", initialTicks); - if (enginePos != null && capacityKey != null) { - compound.put("EnginePos", NbtUtils.writeBlockPos(enginePos)); - compound.putFloat("EnginePower", engineEfficiency); - compound.putString("EngineType", CatnipServices.REGISTRIES.getKeyOrThrow(capacityKey) - .toString()); - } - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - movementDirection = compound.getInt("Direction"); - initialTicks = compound.getInt("Warmup"); - enginePos = null; - engineEfficiency = 0; - if (compound.contains("EnginePos")) { - enginePos = NbtUtils.readBlockPos(compound.getCompound("EnginePos")); - engineEfficiency = compound.getFloat("EnginePower"); - capacityKey = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(compound.getString("EngineType"))); - } - } - - @Override - public float getGeneratedSpeed() { - return getCombinedCapacity() > 0 ? movementDirection * 16 * getSpeedModifier() : 0; - } - - private float getCombinedCapacity() { - return capacityKey == null ? 0 : (float) (engineEfficiency * BlockStressValues.getCapacity(capacityKey)); - } - - private int getSpeedModifier() { - return (int) (1 + (engineEfficiency >= 1 ? 3 : Math.min(2, Math.floor(engineEfficiency * 4)))); - } - - @Override - public float calculateAddedStressCapacity() { - float capacity = getCombinedCapacity() / getSpeedModifier(); - this.lastCapacityProvided = capacity; - return capacity; - } - - @Override - public int getRotationAngleOffset(Axis axis) { - int combinedCoords = axis.choose(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ()); - return super.getRotationAngleOffset(axis) + (combinedCoords % 2 == 0 ? 180 : 0); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - return false; - } - - public boolean addToEngineTooltip(List tooltip, boolean isPlayerSneaking) { - return super.addToGoggleTooltip(tooltip, isPlayerSneaking); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineRenderer.java deleted file mode 100644 index c979afe6fc..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineRenderer.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class SteamEngineRenderer extends SafeTileEntityRenderer { - - public SteamEngineRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(SteamEngineTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - BlockState blockState = te.getBlockState(); - Direction facing = SteamEngineBlock.getFacing(blockState); - Axis facingAxis = facing.getAxis(); - Axis axis = Axis.Y; - - PoweredShaftTileEntity shaft = te.getShaft(); - if (shaft != null) - axis = KineticTileEntityRenderer.getRotationAxisOf(shaft); - - Float angle = te.getTargetAngle(); - if (angle == null) - return; - - float sine = Mth.sin(angle); - float sine2 = Mth.sin(angle - Mth.HALF_PI); - float piston = ((1 - sine) / 4) * 24 / 16f; - boolean roll90 = facingAxis.isHorizontal() && axis == Axis.Y || facingAxis.isVertical() && axis == Axis.Z; - - transformed(AllBlockPartials.ENGINE_PISTON, blockState, facing).rotateY(roll90 ? -90 : 0) - .unCentre() - .light(light) - .translate(0, piston, 0) - .renderInto(ms, vb); - - transformed(AllBlockPartials.ENGINE_LINKAGE, blockState, facing).rotateY(roll90 ? -90 : 0) - .translate(0, 1, 0) - .unCentre() - .translate(0, piston, 0) - .translate(0, 4 / 16f, 8 / 16f) - .rotateX(sine2 * 23f) - .translate(0, -4 / 16f, -8 / 16f) - .light(light) - .renderInto(ms, vb); - - transformed(AllBlockPartials.ENGINE_CONNECTOR, blockState, facing).rotateY(roll90 ? -90 : 0) - .unCentre() - .light(light) - .translate(0, 2, 0) - .centre() - .rotateXRadians(-angle + Mth.HALF_PI) - .unCentre() - .renderInto(ms, vb); - } - - private SuperByteBuffer transformed(PartialModel model, BlockState blockState, Direction facing) { - return CachedPartialBuffers.partial(model, blockState) - .centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(AngleHelper.verticalAngle(facing) + 90); - } - - @Override - public int getViewDistance() { - return 128; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java deleted file mode 100644 index d37c3d3bd8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java +++ /dev/null @@ -1,272 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam; - -import java.lang.ref.WeakReference; -import java.util.List; - -import javax.annotation.Nullable; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.WindmillBearingTileEntity.RotationDirection; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; - -public class SteamEngineTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - protected ScrollOptionBehaviour movementDirection; - - public WeakReference target; - public WeakReference source; - - public SteamEngineTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - source = new WeakReference<>(null); - target = new WeakReference<>(null); - } - - @Override - public void addBehaviours(List behaviours) { - movementDirection = new ScrollOptionBehaviour<>(RotationDirection.class, - CreateLang.translateDirect("contraptions.windmill.rotation_direction"), this, new SteamEngineValueBox()); - movementDirection.requiresWrench(); - movementDirection.onlyActiveWhen(() -> { - PoweredShaftTileEntity shaft = getShaft(); - return shaft == null || !shaft.hasSource(); - }); - movementDirection.withCallback($ -> onDirectionChanged()); - behaviours.add(movementDirection); - - registerAwardables(behaviours, AllAdvancements.STEAM_ENGINE); - } - - private void onDirectionChanged() {} - - @Override - public void tick() { - super.tick(); - FluidTankTileEntity tank = getTank(); - PoweredShaftTileEntity shaft = getShaft(); - - if (tank == null || shaft == null) { - if (level.isClientSide()) - return; - if (shaft == null) - return; - if (!shaft.getBlockPos() - .subtract(worldPosition) - .equals(shaft.enginePos)) - return; - if (shaft.engineEfficiency == 0) - return; - Direction facing = SteamEngineBlock.getFacing(getBlockState()); - if (level.isLoaded(worldPosition.relative(facing.getOpposite()))) - shaft.update(worldPosition, 0, 0); - return; - } - - boolean verticalTarget = false; - BlockState shaftState = shaft.getBlockState(); - Axis targetAxis = Axis.X; - if (shaftState.getBlock()instanceof IRotate ir) - targetAxis = ir.getRotationAxis(shaftState); - verticalTarget = targetAxis == Axis.Y; - - BlockState blockState = getBlockState(); - if (!AllBlocks.STEAM_ENGINE.has(blockState)) - return; - Direction facing = SteamEngineBlock.getFacing(blockState); - if (facing.getAxis() == Axis.Y) - facing = blockState.getValue(SteamEngineBlock.FACING); - - float efficiency = Mth.clamp(tank.boiler.getEngineEfficiency(tank.getTotalTankSize()), 0, 1); - if (efficiency > 0) - - award(AllAdvancements.STEAM_ENGINE); - - int conveyedSpeedLevel = - efficiency == 0 ? 1 : verticalTarget ? 1 : (int) GeneratingKineticTileEntity.convertToDirection(1, facing); - if (targetAxis == Axis.Z) - conveyedSpeedLevel *= -1; - if (movementDirection.get() == RotationDirection.COUNTER_CLOCKWISE) - conveyedSpeedLevel *= -1; - - float shaftSpeed = shaft.getTheoreticalSpeed(); - if (shaft.hasSource() && shaftSpeed != 0 && conveyedSpeedLevel != 0 - && (shaftSpeed > 0) != (conveyedSpeedLevel > 0)) { - movementDirection.setValue(1 - movementDirection.get() - .ordinal()); - conveyedSpeedLevel *= -1; - } - - shaft.update(worldPosition, conveyedSpeedLevel, efficiency); - - if (!level.isClientSide) - return; - - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::spawnParticles); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - PoweredShaftTileEntity shaft = getShaft(); - if (shaft != null) - shaft.remove(worldPosition); - super.setRemovedNotDueToChunkUnload(); - } - - @Override - @OnlyIn(Dist.CLIENT) - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); - } - - public PoweredShaftTileEntity getShaft() { - PoweredShaftTileEntity shaft = target.get(); - if (shaft == null || shaft.isRemoved() || !shaft.canBePoweredBy(worldPosition)) { - if (shaft != null) - target = new WeakReference<>(null); - Direction facing = SteamEngineBlock.getFacing(getBlockState()); - BlockEntity anyShaftAt = level.getBlockEntity(worldPosition.relative(facing, 2)); - if (anyShaftAt instanceof PoweredShaftTileEntity ps && ps.canBePoweredBy(worldPosition)) - target = new WeakReference<>(shaft = ps); - } - return shaft; - } - - public FluidTankTileEntity getTank() { - FluidTankTileEntity tank = source.get(); - if (tank == null || tank.isRemoved()) { - if (tank != null) - source = new WeakReference<>(null); - Direction facing = SteamEngineBlock.getFacing(getBlockState()); - BlockEntity be = level.getBlockEntity(worldPosition.relative(facing.getOpposite())); - if (be instanceof FluidTankTileEntity tankTe) - source = new WeakReference<>(tank = tankTe); - } - if (tank == null) - return null; - return tank.getControllerTE(); - } - - float prevAngle = 0; - - @OnlyIn(Dist.CLIENT) - private void spawnParticles() { - Float targetAngle = getTargetAngle(); - PoweredShaftTileEntity ste = target.get(); - if (ste == null) - return; - if (!ste.isPoweredBy(worldPosition) || ste.engineEfficiency == 0) - return; - if (targetAngle == null) - return; - - float angle = AngleHelper.deg(targetAngle); - angle += (angle < 0) ? -180 + 75 : 360 - 75; - angle %= 360; - - PoweredShaftTileEntity shaft = getShaft(); - if (shaft == null || shaft.getSpeed() == 0) - return; - - if (angle >= 0 && !(prevAngle > 180 && angle < 180)) { - prevAngle = angle; - return; - } - if (angle < 0 && !(prevAngle < -180 && angle > -180)) { - prevAngle = angle; - return; - } - - FluidTankTileEntity sourceTE = source.get(); - if (sourceTE != null) { - FluidTankTileEntity controller = sourceTE.getControllerTE(); - if (controller != null && controller.boiler != null) { - float volume = 3f / Math.max(2, controller.boiler.attachedEngines / 6); - float pitch = 1.18f - level.random.nextFloat() * .25f; - level.playLocalSound(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), - SoundEvents.CANDLE_EXTINGUISH, SoundSource.BLOCKS, volume, pitch, false); - AllSoundEvents.STEAM.playAt(level, worldPosition, volume / 16, .8f, false); - } - } - - Direction facing = SteamEngineBlock.getFacing(getBlockState()); - - for (int i = 0; i < 2; i++) { - Vec3 offset = VecHelper.rotate(new Vec3(0, 0, 1).add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) - .multiply(1, 1, 0) - .normalize() - .scale(.5f)), AngleHelper.verticalAngle(facing), Axis.X); - offset = VecHelper.rotate(offset, AngleHelper.horizontalAngle(facing), Axis.Y); - Vec3 v = offset.scale(.5f) - .add(Vec3.atCenterOf(worldPosition)); - Vec3 m = offset.subtract(Vec3.atLowerCornerOf(facing.getNormal()) - .scale(.75f)); - level.addParticle(new SteamJetParticleData(1), v.x, v.y, v.z, m.x, m.y, m.z); - } - - prevAngle = angle; - } - - @Nullable - @OnlyIn(Dist.CLIENT) - public Float getTargetAngle() { - float angle = 0; - BlockState blockState = getBlockState(); - if (!AllBlocks.STEAM_ENGINE.has(blockState)) - return null; - - Direction facing = SteamEngineBlock.getFacing(blockState); - PoweredShaftTileEntity shaft = getShaft(); - Axis facingAxis = facing.getAxis(); - Axis axis = Axis.Y; - - if (shaft == null) - return null; - - axis = KineticTileEntityRenderer.getRotationAxisOf(shaft); - angle = KineticTileEntityRenderer.getAngleForTe(shaft, shaft.getBlockPos(), axis); - - if (axis == facingAxis) - return null; - if (axis.isHorizontal() && (facingAxis == Axis.X ^ facing.getAxisDirection() == AxisDirection.POSITIVE)) - angle *= -1; - if (axis == Axis.X && facing == Direction.DOWN) - angle *= -1; - return angle; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - PoweredShaftTileEntity shaft = getShaft(); - return shaft == null ? false : shaft.addToEngineTooltip(tooltip, isPlayerSneaking); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineValueBox.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineValueBox.java deleted file mode 100644 index 98443a457f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineValueBox.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.Pointing; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class SteamEngineValueBox extends ValueBoxTransform.Sided { - - @Override - protected boolean isSideActive(BlockState state, Direction direction) { - return SteamEngineBlock.getFacing(state) - .getAxis() != direction.getAxis(); - } - - @Override - protected Vec3 getLocalOffset(BlockState state) { - Direction side = getSide(); - Direction engineFacing = SteamEngineBlock.getFacing(state); - - float roll = 0; - for (Pointing p : Pointing.values()) { - if (p.getCombinedDirection(engineFacing) == side) - roll = p.getXRotation(); - } - if (engineFacing == Direction.UP) - roll += 180; - - float horizontalAngle = AngleHelper.horizontalAngle(engineFacing); - float verticalAngle = AngleHelper.verticalAngle(engineFacing); - - boolean recessed = roll % 180 == 0; - if (engineFacing.getAxis() == Axis.Y) - recessed ^= state.getValue(SteamEngineBlock.FACING).getAxis() == Axis.X; - - Vec3 local = VecHelper.voxelSpace(8, recessed ? 13 : 15, 9); - - local = VecHelper.rotateCentered(local, roll, Axis.Z); - local = VecHelper.rotateCentered(local, horizontalAngle, Axis.Y); - local = VecHelper.rotateCentered(local, verticalAngle, Axis.X); - - return local; - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - Direction facing = SteamEngineBlock.getFacing(state); - - if (facing.getAxis() == Axis.Y) { - super.rotate(state, ms); - return; - } - - float roll = 0; - for (Pointing p : Pointing.values()) { - if (p.getCombinedDirection(facing) == getSide()) - roll = p.getXRotation(); - } - - float yRot = AngleHelper.horizontalAngle(facing) + (facing == Direction.DOWN ? 180 : 0); - TransformStack.cast(ms) - .rotateY(yRot) - .rotateX(facing == Direction.DOWN ? -90 : 90) - .rotateY(roll); - } - - @Override - protected Vec3 getSouthLocation() { - return Vec3.ZERO; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleRenderer.java deleted file mode 100644 index 1062f9b968..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleRenderer.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class WhistleRenderer extends SafeTileEntityRenderer { - - public WhistleRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(WhistleTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - if (!(blockState.getBlock() instanceof WhistleBlock)) - return; - - Direction direction = blockState.getValue(WhistleBlock.FACING); - WhistleSize size = blockState.getValue(WhistleBlock.SIZE); - - PartialModel mouth = size == WhistleSize.LARGE ? AllBlockPartials.WHISTLE_MOUTH_LARGE - : size == WhistleSize.MEDIUM ? AllBlockPartials.WHISTLE_MOUTH_MEDIUM : AllBlockPartials.WHISTLE_MOUTH_SMALL; - - float offset = te.animation.getValue(partialTicks); - if (te.animation.getChaseTarget() > 0 && te.animation.getValue() > 0.5f) { - float wiggleProgress = (WorldTickHolder.getTicks(te.getLevel()) + partialTicks) / 8f; - offset -= Math.sin(wiggleProgress * (2 * Mth.PI) * (4 - size.ordinal())) / 16f; - } - - CachedPartialBuffers.partial(mouth, blockState) - .rotateCentered(Direction.Axis.Y, Mth.DEG_TO_RAD * AngleHelper.horizontalAngle(direction)) - .translate(0, offset * 4 / 16f, 0) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleTileEntity.java deleted file mode 100644 index dc0e9c811f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleTileEntity.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; - -import java.lang.ref.WeakReference; -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.steam.SteamJetParticleData; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock.WhistleExtenderShape; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; - -public class WhistleTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - public WeakReference source; - public LerpedFloat animation; - protected int pitch; - - public WhistleTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - source = new WeakReference<>(null); - animation = LerpedFloat.linear(); - } - - @Override - public void addBehaviours(List behaviours) { - registerAwardables(behaviours, AllAdvancements.STEAM_WHISTLE); - } - - public void updatePitch() { - BlockPos currentPos = worldPosition.above(); - int prevPitch = pitch; - for (pitch = 0; pitch <= 24; pitch += 2) { - BlockState blockState = level.getBlockState(currentPos); - if (!AllBlocks.STEAM_WHISTLE_EXTENSION.has(blockState)) - break; - if (blockState.getValue(WhistleExtenderBlock.SHAPE) == WhistleExtenderShape.SINGLE) { - pitch++; - break; - } - currentPos = currentPos.above(); - } - if (prevPitch == pitch) - return; - - notifyUpdate(); - - FluidTankTileEntity tank = getTank(); - if (tank != null && tank.boiler != null) - tank.boiler.checkPipeOrganAdvancement(tank); - } - - @Override - public void tick() { - super.tick(); - if (!level.isClientSide()) { - if (isPowered()) - award(AllAdvancements.STEAM_WHISTLE); - return; - } - - FluidTankTileEntity tank = getTank(); - boolean powered = isPowered() - && (tank != null && tank.boiler.isActive() && (tank.boiler.passiveHeat || tank.boiler.activeHeat > 0) - || isVirtual()); - animation.chase(powered ? 1 : 0, powered ? .5f : .4f, powered ? Chaser.EXP : Chaser.LINEAR); - animation.tickChaser(); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio(getOctave(), powered)); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - tag.putInt("Pitch", pitch); - super.write(tag, clientPacket); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - pitch = tag.getInt("Pitch"); - super.read(tag, clientPacket); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - String[] pitches = CreateLang.translateDirect("generic.notes") - .getString() - .split(";"); - MutableComponent textComponent = Components.literal(spacing); - tooltip.add(textComponent.append(CreateLang.translateDirect("generic.pitch", pitches[pitch % pitches.length]))); - return true; - } - - protected boolean isPowered() { - return getBlockState().getOptionalValue(WhistleBlock.POWERED) - .orElse(false); - } - - protected WhistleSize getOctave() { - return getBlockState().getOptionalValue(WhistleBlock.SIZE) - .orElse(WhistleSize.MEDIUM); - } - - @OnlyIn(Dist.CLIENT) - protected WhistleSoundInstance soundInstance; - - @OnlyIn(Dist.CLIENT) - protected void tickAudio(WhistleSize size, boolean powered) { - if (!powered) { - if (soundInstance != null) { - soundInstance.fadeOut(); - soundInstance = null; - } - return; - } - - float f = (float) Math.pow(2, -pitch / 12.0); - boolean particle = level.getGameTime() % 8 == 0; - Vec3 eyePosition = Minecraft.getInstance().cameraEntity.getEyePosition(); - float maxVolume = (float) Mth.clamp((64 - eyePosition.distanceTo(Vec3.atCenterOf(worldPosition))) / 64, 0, 1); - - if (soundInstance == null || soundInstance.isStopped() || soundInstance.getOctave() != size) { - Minecraft.getInstance() - .getSoundManager() - .play(soundInstance = new WhistleSoundInstance(size, worldPosition)); - AllSoundEvents.WHISTLE_CHIFF.playAt(level, worldPosition, maxVolume * .175f, - size == WhistleSize.SMALL ? f + .75f : f, false); - particle = true; - } - - soundInstance.keepAlive(); - soundInstance.setPitch(f); - - if (!particle) - return; - - Direction facing = getBlockState().getOptionalValue(WhistleBlock.FACING) - .orElse(Direction.SOUTH); - float angle = 180 + AngleHelper.horizontalAngle(facing); - Vec3 sizeOffset = VecHelper.rotate(new Vec3(0, -0.4f, 1 / 16f * size.ordinal()), angle, Axis.Y); - Vec3 offset = VecHelper.rotate(new Vec3(0, 1, 0.75f), angle, Axis.Y); - Vec3 v = offset.scale(.45f) - .add(sizeOffset) - .add(Vec3.atCenterOf(worldPosition)); - Vec3 m = offset.subtract(Vec3.atLowerCornerOf(facing.getNormal()) - .scale(.75f)); - level.addParticle(new SteamJetParticleData(1), v.x, v.y, v.z, m.x, m.y, m.z); - } - - public int getPitchId() { - return pitch + 100 * getBlockState().getOptionalValue(WhistleBlock.SIZE) - .orElse(WhistleSize.MEDIUM) - .ordinal(); - } - - public FluidTankTileEntity getTank() { - FluidTankTileEntity tank = source.get(); - if (tank == null || tank.isRemoved()) { - if (tank != null) - source = new WeakReference<>(null); - Direction facing = WhistleBlock.getAttachedDirection(getBlockState()); - BlockEntity be = level.getBlockEntity(worldPosition.relative(facing)); - if (be instanceof FluidTankTileEntity tankTe) - source = new WeakReference<>(tank = tankTe); - } - if (tank == null) - return null; - return tank.getControllerTE(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java deleted file mode 100644 index b66d4a2c90..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionBlockChangedPacket extends SimplePacketBase { - - int entityID; - BlockPos localPos; - BlockState newState; - - public ContraptionBlockChangedPacket(int id, BlockPos pos, BlockState state) { - entityID = id; - localPos = pos; - newState = state; - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - buffer.writeBlockPos(localPos); - buffer.writeNbt(NbtUtils.writeBlockState(newState)); - } - - public ContraptionBlockChangedPacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - localPos = buffer.readBlockPos(); - newState = NbtUtils.readBlockState(buffer.readNbt()); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> AbstractContraptionEntity.handleBlockChangedPacket(this))); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionDisassemblyPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionDisassemblyPacket.java deleted file mode 100644 index 1020cfebcd..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionDisassemblyPacket.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionDisassemblyPacket extends SimplePacketBase { - - int entityID; - StructureTransform transform; - - public ContraptionDisassemblyPacket(int entityID, StructureTransform transform) { - this.entityID = entityID; - this.transform = transform; - } - - public ContraptionDisassemblyPacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - transform = StructureTransform.fromBuffer(buffer); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - transform.writeToBuffer(buffer); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> AbstractContraptionEntity.handleDisassemblyPacket(this))); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRelocationPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRelocationPacket.java deleted file mode 100644 index 5ff0fa20bf..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRelocationPacket.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionRelocationPacket extends SimplePacketBase { - - int entityID; - - public ContraptionRelocationPacket(int entityID) { - this.entityID = entityID; - } - - public ContraptionRelocationPacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> OrientedContraptionEntity.handleRelocationPacket(this))); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java deleted file mode 100644 index 79d9ddb86c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionStallPacket extends SimplePacketBase { - - int entityID; - float x; - float y; - float z; - float angle; - - public ContraptionStallPacket(int entityID, double posX, double posY, double posZ, float angle) { - this.entityID = entityID; - this.x = (float) posX; - this.y = (float) posY; - this.z = (float) posZ; - this.angle = angle; - } - - public ContraptionStallPacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - x = buffer.readFloat(); - y = buffer.readFloat(); - z = buffer.readFloat(); - angle = buffer.readFloat(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - writeAll(buffer, x, y, z, angle); - } - - @Override - public void handle(Supplier context) { - context.get().enqueueWork( - () -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> AbstractContraptionEntity.handleStallPacket(this))); - context.get().setPacketHandled(true); - } - - private void writeAll(FriendlyByteBuf buffer, float... floats) { - for (float f : floats) - buffer.writeFloat(f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionType.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionType.java deleted file mode 100644 index 4b5d8fcd02..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionType.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; - -public class ContraptionType { - - public static Map entries = new HashMap<>(); - public static ContraptionType - PISTON = register("piston", PistonContraption::new), - BEARING = register("bearing", BearingContraption::new), - PULLEY = register("pulley", PulleyContraption::new), - CLOCKWORK = register("clockwork", ClockworkContraption::new), - MOUNTED = register("mounted", MountedContraption::new), - STABILIZED = register("stabilized", StabilizedContraption::new), - GANTRY = register("gantry", GantryContraption::new), - CARRIAGE = register("carriage", CarriageContraption::new); - - Supplier factory; - String id; - - public static ContraptionType register(String id, Supplier factory) { - ContraptionType value = new ContraptionType(id, factory); - entries.put(id, value); - return value; - } - - private ContraptionType(String id, Supplier factory) { - this.factory = factory; - this.id = id; - } - - public static Contraption fromType(String type) { - for (Entry allContraptionTypes : entries.entrySet()) - if (type.equals(allContraptionTypes.getKey())) - return allContraptionTypes.getValue().factory.get(); - return null; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionWorld.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionWorld.java deleted file mode 100644 index e9e945e69c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionWorld.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import net.createmod.catnip.utility.worldWrappers.WrappedWorld; -import net.minecraft.core.BlockPos; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraft.world.phys.Vec3; - -public class ContraptionWorld extends WrappedWorld { - final Contraption contraption; - private final int minY; - private final int height; - - public ContraptionWorld(Level world, Contraption contraption) { - super(world); - - this.contraption = contraption; - - // Include 1 block above/below contraption height range to avoid certain edge-case Starlight crashes with - // downward-facing mechanical pistons. - minY = nextMultipleOf16(contraption.bounds.minY - 1); - height = nextMultipleOf16(contraption.bounds.maxY + 1) - minY; - } - - // https://math.stackexchange.com/questions/291468 - private static int nextMultipleOf16(double a) { - return (((Math.abs((int) a) - 1) | 15) + 1) * Mth.sign(a); - } - - @Override - public BlockState getBlockState(BlockPos pos) { - StructureTemplate.StructureBlockInfo blockInfo = contraption.getBlocks().get(pos); - - if (blockInfo != null) - return blockInfo.state; - - return Blocks.AIR.defaultBlockState(); - } - - @Override - public void playSound(Player player, double x, double y, double z, SoundEvent soundIn, SoundSource category, float volume, float pitch) { - - Vec3 worldPos = ContraptionCollider.getWorldToLocalTranslation(new Vec3(x, y, z), this.contraption.entity); - - worldPos = worldPos.add(x, y, z); - - world.playSound(player, worldPos.x, worldPos.y, worldPos.z, soundIn, category, volume, pitch); - } - - @Override - public void playLocalSound(double x, double y, double z, SoundEvent p_184134_7_, SoundSource p_184134_8_, float p_184134_9_, float p_184134_10_, boolean p_184134_11_) { - world.playLocalSound(x, y, z, p_184134_7_, p_184134_8_, p_184134_9_, p_184134_10_, p_184134_11_); - } - - // Ensure that we provide accurate information about ContraptionWorld height to mods (such as Starlight) which - // expect Levels to only have blocks located in chunks within their height range. - - @Override - public int getHeight() { - return height; - } - - @Override - public int getMinBuildHeight() { - return minY; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java deleted file mode 100644 index c5d5b71c06..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.Arrays; -import java.util.List; - -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.FontHelper; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; - -public interface IDisplayAssemblyExceptions { - - default boolean addExceptionToTooltip(List tooltip) { - AssemblyException e = getLastAssemblyException(); - if (e == null) - return false; - - if (!tooltip.isEmpty()) - tooltip.add(Components.immutableEmpty()); - - tooltip.add(IHaveGoggleInformation.componentSpacing.plainCopy() - .append(CreateLang.translateDirect("gui.assembly.exception") - .withStyle(ChatFormatting.GOLD))); - - String text = e.component.getString(); - Arrays.stream(text.split("\n")) - .forEach(l -> FontHelper.cutStringTextComponent(l, ChatFormatting.GRAY, ChatFormatting.WHITE) - .forEach(c -> tooltip.add(IHaveGoggleInformation.componentSpacing.plainCopy() - .append(c)))); - - return true; - } - - AssemblyException getLastAssemblyException(); - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java deleted file mode 100644 index 3e5fc78eb4..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import net.minecraft.world.level.block.state.BlockState; - -public interface ITransformableBlock { - BlockState transform(BlockState state, StructureTransform transform); -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableTE.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableTE.java deleted file mode 100644 index 64d77b4975..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableTE.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -public interface ITransformableTE { - - void transform(StructureTransform transform); - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java deleted file mode 100644 index d372a7a28f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionFluidPacket; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.foundation.fluid.SmartFluidTank; -import com.simibubi.create.foundation.networking.AllPackets; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.network.PacketDistributor; - -public class MountedFluidStorage { - - SmartFluidTank tank; - private boolean valid; - private BlockEntity te; - - private int packetCooldown = 0; - private boolean sendPacket = false; - - public static boolean canUseAsStorage(BlockEntity te) { - if (te instanceof FluidTankTileEntity) - return ((FluidTankTileEntity) te).isController(); - return false; - } - - public MountedFluidStorage(BlockEntity te) { - assignTileEntity(te); - } - - public void assignTileEntity(BlockEntity te) { - this.te = te; - tank = createMountedTank(te); - } - - private SmartFluidTank createMountedTank(BlockEntity te) { - if (te instanceof CreativeFluidTankTileEntity) - return new CreativeSmartFluidTank( - ((FluidTankTileEntity) te).getTotalTankSize() * FluidTankTileEntity.getCapacityMultiplier(), $ -> { - }); - if (te instanceof FluidTankTileEntity) - return new SmartFluidTank( - ((FluidTankTileEntity) te).getTotalTankSize() * FluidTankTileEntity.getCapacityMultiplier(), - this::onFluidStackChanged); - return null; - } - - public void tick(Entity entity, BlockPos pos, boolean isRemote) { - if (!isRemote) { - if (packetCooldown > 0) - packetCooldown--; - else if (sendPacket) { - sendPacket = false; - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), - new ContraptionFluidPacket(entity.getId(), pos, tank.getFluid())); - packetCooldown = 8; - } - return; - } - - if (!(te instanceof FluidTankTileEntity)) - return; - FluidTankTileEntity tank = (FluidTankTileEntity) te; - tank.getFluidLevel() - .tickChaser(); - } - - public void updateFluid(FluidStack fluid) { - tank.setFluid(fluid); - if (!(te instanceof FluidTankTileEntity)) - return; - float fillState = tank.getFluidAmount() / (float) tank.getCapacity(); - FluidTankTileEntity tank = (FluidTankTileEntity) te; - if (tank.getFluidLevel() == null) - tank.setFluidLevel(LerpedFloat.linear() - .startWithValue(fillState)); - tank.getFluidLevel() - .chase(fillState, 0.5, Chaser.EXP); - IFluidTank tankInventory = tank.getTankInventory(); - if (tankInventory instanceof SmartFluidTank) - ((SmartFluidTank) tankInventory).setFluid(fluid); - } - - public void removeStorageFromWorld() { - valid = false; - if (te == null) - return; - - IFluidHandler teHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) - .orElse(null); - if (!(teHandler instanceof SmartFluidTank)) - return; - SmartFluidTank smartTank = (SmartFluidTank) teHandler; - tank.setFluid(smartTank.getFluid()); - sendPacket = false; - valid = true; - } - - private void onFluidStackChanged(FluidStack fs) { - sendPacket = true; - } - - public void addStorageToWorld(BlockEntity te) { - if (tank instanceof CreativeSmartFluidTank) - return; - - LazyOptional capability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); - IFluidHandler teHandler = capability.orElse(null); - if (!(teHandler instanceof SmartFluidTank)) - return; - - SmartFluidTank inv = (SmartFluidTank) teHandler; - inv.setFluid(tank.getFluid() - .copy()); - } - - public IFluidHandler getFluidHandler() { - return tank; - } - - public CompoundTag serialize() { - if (!valid) - return null; - CompoundTag tag = tank.writeToNBT(new CompoundTag()); - tag.putInt("Capacity", tank.getCapacity()); - - if (tank instanceof CreativeSmartFluidTank) { - NBTHelper.putMarker(tag, "Bottomless"); - tag.put("ProvidedStack", tank.getFluid() - .writeToNBT(new CompoundTag())); - } - return tag; - } - - public static MountedFluidStorage deserialize(CompoundTag nbt) { - MountedFluidStorage storage = new MountedFluidStorage(null); - if (nbt == null) - return storage; - - int capacity = nbt.getInt("Capacity"); - storage.tank = new SmartFluidTank(capacity, storage::onFluidStackChanged); - storage.valid = true; - - if (nbt.contains("Bottomless")) { - FluidStack providedStack = FluidStack.loadFluidStackFromNBT(nbt.getCompound("ProvidedStack")); - CreativeSmartFluidTank creativeSmartFluidTank = new CreativeSmartFluidTank(capacity, $ -> { - }); - creativeSmartFluidTank.setContainedFluid(providedStack); - storage.tank = creativeSmartFluidTank; - return storage; - } - - storage.tank.readFromNBT(nbt); - return storage; - } - - public boolean isValid() { - return valid; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java deleted file mode 100644 index ba39c3687a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; -import com.simibubi.create.content.contraptions.processing.ProcessingInventory; -import com.simibubi.create.content.logistics.block.inventories.BottomlessItemHandler; -import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BarrelBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.ChestBlockEntity; -import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; - -public class MountedStorage { - - private static final ItemStackHandler dummyHandler = new ItemStackHandler(); - - ItemStackHandler handler; - boolean noFuel; - boolean valid; - - private BlockEntity te; - - public static boolean canUseAsStorage(BlockEntity te) { - if (te == null) - return false; - if (te instanceof MechanicalCrafterTileEntity) - return false; - if (AllTileEntities.CREATIVE_CRATE.is(te)) - return true; - if (te instanceof ShulkerBoxBlockEntity) - return true; - if (te instanceof ChestBlockEntity) - return true; - if (te instanceof BarrelBlockEntity) - return true; - if (te instanceof ItemVaultTileEntity) - return true; - - LazyOptional capability = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - IItemHandler handler = capability.orElse(null); - return handler instanceof ItemStackHandler && !(handler instanceof ProcessingInventory); - } - - public MountedStorage(BlockEntity te) { - this.te = te; - handler = dummyHandler; - noFuel = te instanceof ItemVaultTileEntity; - } - - public void removeStorageFromWorld() { - valid = false; - if (te == null) - return; - - if (te instanceof ChestBlockEntity) { - CompoundTag tag = te.saveWithFullMetadata(); - if (tag.contains("LootTable", 8)) - return; - - handler = new ItemStackHandler(((ChestBlockEntity) te).getContainerSize()); - NonNullList items = NonNullList.withSize(handler.getSlots(), ItemStack.EMPTY); - ContainerHelper.loadAllItems(tag, items); - for (int i = 0; i < items.size(); i++) - handler.setStackInSlot(i, items.get(i)); - valid = true; - return; - } - - IItemHandler teHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - .orElse(dummyHandler); - if (teHandler == dummyHandler) - return; - - // multiblock vaults need to provide individual invs - if (te instanceof ItemVaultTileEntity) { - handler = ((ItemVaultTileEntity) te).getInventoryOfBlock(); - valid = true; - return; - } - - // te uses ItemStackHandler - if (teHandler instanceof ItemStackHandler) { - handler = (ItemStackHandler) teHandler; - valid = true; - return; - } - - // serialization not accessible -> fill into a serializable handler - if (teHandler instanceof IItemHandlerModifiable) { - IItemHandlerModifiable inv = (IItemHandlerModifiable) teHandler; - handler = new ItemStackHandler(teHandler.getSlots()); - for (int slot = 0; slot < handler.getSlots(); slot++) { - handler.setStackInSlot(slot, inv.getStackInSlot(slot)); - inv.setStackInSlot(slot, ItemStack.EMPTY); - } - valid = true; - return; - } - - } - - public void addStorageToWorld(BlockEntity te) { - // FIXME: More dynamic mounted storage in .4 - if (handler instanceof BottomlessItemHandler) - return; - - if (te instanceof ChestBlockEntity) { - CompoundTag tag = te.saveWithFullMetadata(); - tag.remove("Items"); - NonNullList items = NonNullList.withSize(handler.getSlots(), ItemStack.EMPTY); - for (int i = 0; i < items.size(); i++) - items.set(i, handler.getStackInSlot(i)); - ContainerHelper.saveAllItems(tag, items); - te.load(tag); - return; - } - - if (te instanceof ItemVaultTileEntity) { - ((ItemVaultTileEntity) te).applyInventoryToBlock(handler); - return; - } - - LazyOptional capability = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - IItemHandler teHandler = capability.orElse(null); - if (!(teHandler instanceof IItemHandlerModifiable)) - return; - - IItemHandlerModifiable inv = (IItemHandlerModifiable) teHandler; - for (int slot = 0; slot < Math.min(inv.getSlots(), handler.getSlots()); slot++) - inv.setStackInSlot(slot, handler.getStackInSlot(slot)); - } - - public IItemHandlerModifiable getItemHandler() { - return handler; - } - - public CompoundTag serialize() { - if (!valid) - return null; - - CompoundTag tag = handler.serializeNBT(); - if (noFuel) - NBTHelper.putMarker(tag, "NoFuel"); - if (!(handler instanceof BottomlessItemHandler)) - return tag; - - NBTHelper.putMarker(tag, "Bottomless"); - tag.put("ProvidedStack", handler.getStackInSlot(0) - .serializeNBT()); - return tag; - } - - public static MountedStorage deserialize(CompoundTag nbt) { - MountedStorage storage = new MountedStorage(null); - storage.handler = new ItemStackHandler(); - if (nbt == null) - return storage; - storage.valid = true; - storage.noFuel = nbt.contains("NoFuel"); - - if (nbt.contains("Bottomless")) { - ItemStack providedStack = ItemStack.of(nbt.getCompound("ProvidedStack")); - storage.handler = new BottomlessItemHandler(() -> providedStack); - return storage; - } - - storage.handler.deserializeNBT(nbt); - return storage; - } - - public boolean isValid() { - return valid; - } - - public boolean canUseForFuel() { - return !noFuel; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java deleted file mode 100644 index aa01f46270..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorageManager.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption.ContraptionInvWrapper; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.foundation.fluid.CombinedTankWrapper; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.nbt.Tag; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.fluids.capability.templates.FluidTank; -import net.minecraftforge.items.IItemHandlerModifiable; - -public class MountedStorageManager { - - protected ContraptionInvWrapper inventory; - protected ContraptionInvWrapper fuelInventory; - protected CombinedTankWrapper fluidInventory; - protected Map storage; - protected Map fluidStorage; - - public MountedStorageManager() { - storage = new HashMap<>(); - fluidStorage = new HashMap<>(); - } - - public void entityTick(AbstractContraptionEntity entity) { - fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, entity.level.isClientSide)); - } - - public void createHandlers() { - Collection itemHandlers = storage.values(); - - inventory = wrapItems(itemHandlers.stream() - .map(MountedStorage::getItemHandler) - .toList(), false); - - fuelInventory = wrapItems(itemHandlers.stream() - .filter(MountedStorage::canUseForFuel) - .map(MountedStorage::getItemHandler) - .toList(), true); - - fluidInventory = wrapFluids(fluidStorage.values() - .stream() - .map(MountedFluidStorage::getFluidHandler) - .collect(Collectors.toList())); - } - - protected ContraptionInvWrapper wrapItems(Collection list, boolean fuel) { - return new ContraptionInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); - } - - protected CombinedTankWrapper wrapFluids(Collection list) { - return new CombinedTankWrapper(Arrays.copyOf(list.toArray(), list.size(), IFluidHandler[].class)); - } - - public void addBlock(BlockPos localPos, BlockEntity te) { - if (te != null && MountedStorage.canUseAsStorage(te)) - storage.put(localPos, new MountedStorage(te)); - if (te != null && MountedFluidStorage.canUseAsStorage(te)) - fluidStorage.put(localPos, new MountedFluidStorage(te)); - } - - public void read(CompoundTag nbt, Map presentTileEntities, boolean clientPacket) { - storage.clear(); - NBTHelper.iterateCompoundList(nbt.getList("Storage", Tag.TAG_COMPOUND), c -> storage - .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedStorage.deserialize(c.getCompound("Data")))); - - fluidStorage.clear(); - NBTHelper.iterateCompoundList(nbt.getList("FluidStorage", Tag.TAG_COMPOUND), c -> fluidStorage - .put(NbtUtils.readBlockPos(c.getCompound("Pos")), MountedFluidStorage.deserialize(c.getCompound("Data")))); - - if (clientPacket && presentTileEntities != null) - bindTanks(presentTileEntities); - - List handlers = new ArrayList<>(); - List fuelHandlers = new ArrayList<>(); - for (MountedStorage mountedStorage : storage.values()) { - IItemHandlerModifiable itemHandler = mountedStorage.getItemHandler(); - handlers.add(itemHandler); - if (mountedStorage.canUseForFuel()) - fuelHandlers.add(itemHandler); - } - - inventory = wrapItems(handlers, false); - fuelInventory = wrapItems(fuelHandlers, true); - fluidInventory = wrapFluids(fluidStorage.values() - .stream() - .map(MountedFluidStorage::getFluidHandler) - .toList()); - } - - public void bindTanks(Map presentTileEntities) { - fluidStorage.forEach((pos, mfs) -> { - BlockEntity tileEntity = presentTileEntities.get(pos); - if (!(tileEntity instanceof FluidTankTileEntity)) - return; - FluidTankTileEntity tank = (FluidTankTileEntity) tileEntity; - IFluidTank tankInventory = tank.getTankInventory(); - if (tankInventory instanceof FluidTank) - ((FluidTank) tankInventory).setFluid(mfs.tank.getFluid()); - tank.getFluidLevel() - .startWithValue(tank.getFillState()); - mfs.assignTileEntity(tank); - }); - } - - public void write(CompoundTag nbt, boolean clientPacket) { - ListTag storageNBT = new ListTag(); - if (!clientPacket) - for (BlockPos pos : storage.keySet()) { - CompoundTag c = new CompoundTag(); - MountedStorage mountedStorage = storage.get(pos); - if (!mountedStorage.isValid()) - continue; - c.put("Pos", NbtUtils.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - storageNBT.add(c); - } - - ListTag fluidStorageNBT = new ListTag(); - for (BlockPos pos : fluidStorage.keySet()) { - CompoundTag c = new CompoundTag(); - MountedFluidStorage mountedStorage = fluidStorage.get(pos); - if (!mountedStorage.isValid()) - continue; - c.put("Pos", NbtUtils.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - fluidStorageNBT.add(c); - } - - nbt.put("Storage", storageNBT); - nbt.put("FluidStorage", fluidStorageNBT); - } - - public void removeStorageFromWorld() { - storage.values() - .forEach(MountedStorage::removeStorageFromWorld); - fluidStorage.values() - .forEach(MountedFluidStorage::removeStorageFromWorld); - } - - public void addStorageToWorld(StructureBlockInfo block, BlockEntity tileEntity) { - if (storage.containsKey(block.pos)) { - MountedStorage mountedStorage = storage.get(block.pos); - if (mountedStorage.isValid()) - mountedStorage.addStorageToWorld(tileEntity); - } - - if (fluidStorage.containsKey(block.pos)) { - MountedFluidStorage mountedStorage = fluidStorage.get(block.pos); - if (mountedStorage.isValid()) - mountedStorage.addStorageToWorld(tileEntity); - } - } - - public void clear() { - for (int i = 0; i < inventory.getSlots(); i++) - if (!inventory.isSlotExternal(i)) - inventory.setStackInSlot(i, ItemStack.EMPTY); - for (int i = 0; i < fluidInventory.getTanks(); i++) - fluidInventory.drain(fluidInventory.getFluidInTank(i), FluidAction.EXECUTE); - } - - public void updateContainedFluid(BlockPos localPos, FluidStack containedFluid) { - MountedFluidStorage mountedFluidStorage = fluidStorage.get(localPos); - if (mountedFluidStorage != null) - mountedFluidStorage.updateFluid(containedFluid); - } - - public void attachExternal(IItemHandlerModifiable externalStorage) { - inventory = new ContraptionInvWrapper(externalStorage, inventory); - fuelInventory = new ContraptionInvWrapper(externalStorage, fuelInventory); - } - - public IItemHandlerModifiable getItems() { - return inventory; - } - - public IItemHandlerModifiable getFuelItems() { - return fuelInventory; - } - - public IFluidHandler getFluids() { - return fluidInventory; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java deleted file mode 100644 index 642e7da4f1..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementBehaviour.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.foundation.config.AllConfigs; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.items.ItemHandlerHelper; - -public interface MovementBehaviour { - - default boolean isActive(MovementContext context) { - return true; - } - - default void tick(MovementContext context) {} - - default void startMoving(MovementContext context) {} - - default void visitNewPosition(MovementContext context, BlockPos pos) {} - - default Vec3 getActiveAreaOffset(MovementContext context) { - return Vec3.ZERO; - } - - default void dropItem(MovementContext context, ItemStack stack) { - ItemStack remainder; - if (AllConfigs.SERVER.kinetics.moveItemsToStorage.get()) - remainder = ItemHandlerHelper.insertItem(context.contraption.getSharedInventory(), stack, false); - else - remainder = stack; - if (remainder.isEmpty()) - return; - - Vec3 vec = context.position; - ItemEntity itemEntity = new ItemEntity(context.world, vec.x, vec.y, vec.z, remainder); - itemEntity.setDeltaMovement(context.motion.add(0, 0.5f, 0) - .scale(context.world.random.nextFloat() * .3f)); - context.world.addFreshEntity(itemEntity); - } - - default void onSpeedChanged(MovementContext context, Vec3 oldMotion, Vec3 motion) {} - - default void stopMoving(MovementContext context) {} - - default void cancelStall(MovementContext context) { - context.stall = false; - } - - default void writeExtraData(MovementContext context) {} - - default boolean renderAsNormalTileEntity() { - return false; - } - - default boolean hasSpecialInstancedRendering() { - return false; - } - - @OnlyIn(Dist.CLIENT) - default void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, - ContraptionMatrices matrices, MultiBufferSource buffer) {} - - @OnlyIn(Dist.CLIENT) - @Nullable - default ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, - MovementContext context) { - return null; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java deleted file mode 100644 index 3c66e2c602..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/NonStationaryLighter.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import com.jozufozu.flywheel.light.TickingLightListener; -import com.jozufozu.flywheel.util.box.GridAlignedBB; -import com.jozufozu.flywheel.util.box.ImmutableBox; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; -import com.simibubi.create.foundation.config.AllConfigs; - -public class NonStationaryLighter extends ContraptionLighter implements TickingLightListener { - public NonStationaryLighter(C contraption) { - super(contraption); - } - - @Override - public boolean tickLightListener() { - if (getVolume().volume() > AllConfigs.CLIENT.maxContraptionLightVolume.get()) - return false; - - ImmutableBox contraptionBounds = getContraptionBounds(); - - if (bounds.sameAs(contraptionBounds, 2)) { - return false; - } - bounds.assign(contraptionBounds); - growBoundsForEdgeData(bounds); - - lightVolume.move(bounds); - - return true; - } - - @Override - public GridAlignedBB getContraptionBounds() { - GridAlignedBB bb = GridAlignedBB.from(contraption.bounds); - - bb.translate(contraption.entity.blockPosition()); - - return bb; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java deleted file mode 100644 index b3a2c616c6..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; - -public abstract class TranslatingContraption extends Contraption { - - protected Set cachedColliders; - protected Direction cachedColliderDirection; - - public Set getColliders(Level world, Direction movementDirection) { - if (getBlocks() == null) - return Collections.emptySet(); - if (cachedColliders == null || cachedColliderDirection != movementDirection) { - cachedColliders = new HashSet<>(); - cachedColliderDirection = movementDirection; - - for (StructureBlockInfo info : getBlocks().values()) { - BlockPos offsetPos = info.pos.relative(movementDirection); - if (info.state.getCollisionShape(world, offsetPos) - .isEmpty()) - continue; - if (getBlocks().containsKey(offsetPos) - && !getBlocks().get(offsetPos).state.getCollisionShape(world, offsetPos) - .isEmpty()) - continue; - cachedColliders.add(info.pos); - } - - } - return cachedColliders; - } - - @Override - public void removeBlocksFromWorld(Level world, BlockPos offset) { - int count = blocks.size(); - super.removeBlocksFromWorld(world, offset); - if (count != blocks.size()) { - cachedColliders = null; - } - } - - @Override - public boolean canBeStabilized(Direction facing, BlockPos localPos) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java deleted file mode 100644 index e195ae9b3a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/AnchoredLighter.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.jozufozu.flywheel.util.box.GridAlignedBB; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; - -public class AnchoredLighter extends ContraptionLighter { - - public AnchoredLighter(Contraption contraption) { - super(contraption); - } - - @Override - public GridAlignedBB getContraptionBounds() { - GridAlignedBB bb = GridAlignedBB.from(contraption.bounds); - bb.translate(contraption.anchor); - return bb; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java deleted file mode 100644 index 788b111b78..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.AllTags.AllBlockTags; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; -import com.simibubi.create.foundation.config.AllConfigs; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class BearingContraption extends Contraption { - - protected int sailBlocks; - protected Direction facing; - - private boolean isWindmill; - - public BearingContraption() {} - - public BearingContraption(boolean isWindmill, Direction facing) { - this.isWindmill = isWindmill; - this.facing = facing; - } - - @Override - public boolean assemble(Level world, BlockPos pos) throws AssemblyException { - BlockPos offset = pos.relative(facing); - if (!searchMovedStructure(world, offset, null)) - return false; - startMoving(world); - expandBoundsAroundAxis(facing.getAxis()); - if (isWindmill && sailBlocks < AllConfigs.SERVER.kinetics.minimumWindmillSails.get()) - throw AssemblyException.notEnoughSails(sailBlocks); - if (blocks.isEmpty()) - return false; - return true; - } - - @Override - protected ContraptionType getType() { - return ContraptionType.BEARING; - } - - @Override - protected boolean isAnchoringBlockAt(BlockPos pos) { - return pos.equals(anchor.relative(facing.getOpposite())); - } - - @Override - public void addBlock(BlockPos pos, Pair capture) { - BlockPos localPos = pos.subtract(anchor); - if (!getBlocks().containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state)) - sailBlocks++; - super.addBlock(pos, capture); - } - - @Override - public CompoundTag writeNBT(boolean spawnPacket) { - CompoundTag tag = super.writeNBT(spawnPacket); - tag.putInt("Sails", sailBlocks); - tag.putInt("Facing", facing.get3DDataValue()); - return tag; - } - - @Override - public void readNBT(Level world, CompoundTag tag, boolean spawnData) { - sailBlocks = tag.getInt("Sails"); - facing = Direction.from3DDataValue(tag.getInt("Facing")); - super.readNBT(world, tag, spawnData); - } - - public int getSailBlocks() { - return sailBlocks; - } - - public Direction getFacing() { - return facing; - } - - @Override - public boolean canBeStabilized(Direction facing, BlockPos localPos) { - if (facing.getOpposite() == this.facing && BlockPos.ZERO.equals(localPos)) - return false; - return facing.getAxis() == this.facing.getAxis(); - } - - @OnlyIn(Dist.CLIENT) - @Override - public ContraptionLighter makeLighter() { - return new AnchoredLighter(this); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java deleted file mode 100644 index 78af1e8c82..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingInstance.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.mojang.math.Quaternion; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.BackHalfShaftInstance; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class BearingInstance extends BackHalfShaftInstance implements DynamicInstance { - final B bearing; - - final OrientedData topInstance; - - final Vector3f rotationAxis; - final Quaternion blockOrientation; - - public BearingInstance(MaterialManager modelManager, B tile) { - super(modelManager, tile); - this.bearing = tile; - - Direction facing = blockState.getValue(BlockStateProperties.FACING); - rotationAxis = Direction.get(Direction.AxisDirection.POSITIVE, axis).step(); - - blockOrientation = getBlockStateOrientation(facing); - - PartialModel top = - bearing.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP; - - topInstance = getOrientedMaterial().getModel(top, blockState).createInstance(); - - topInstance.setPosition(getInstancePosition()).setRotation(blockOrientation); - } - - @Override - public void beginFrame() { - - float interpolatedAngle = bearing.getInterpolatedAngle(AnimationTickHolder.getPartialTicks() - 1); - Quaternion rot = rotationAxis.rotationDegrees(interpolatedAngle); - - rot.mul(blockOrientation); - - topInstance.setRotation(rot); - } - - @Override - public void updateLight() { - super.updateLight(); - relight(pos, topInstance); - } - - @Override - public void remove() { - super.remove(); - topInstance.delete(); - } - - static Quaternion getBlockStateOrientation(Direction facing) { - Quaternion orientation; - - if (facing.getAxis().isHorizontal()) { - orientation = Vector3f.YP.rotationDegrees(AngleHelper.horizontalAngle(facing.getOpposite())); - } else { - orientation = Quaternion.ONE.copy(); - } - - orientation.mul(Vector3f.XP.rotationDegrees(-90 - AngleHelper.verticalAngle(facing))); - return orientation; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java deleted file mode 100644 index f73161d229..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingRenderer.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class BearingRenderer extends KineticTileEntityRenderer { - - public BearingRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) return; - - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - IBearingTileEntity bearingTe = (IBearingTileEntity) te; - final Direction facing = te.getBlockState() - .getValue(BlockStateProperties.FACING); - PartialModel top = - bearingTe.isWoodenTop() ? AllBlockPartials.BEARING_TOP_WOODEN : AllBlockPartials.BEARING_TOP; - SuperByteBuffer superBuffer = CachedPartialBuffers.partial(top, te.getBlockState()); - - float interpolatedAngle = bearingTe.getInterpolatedAngle(partialTicks - 1); - kineticRotationTransform(superBuffer, te, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI), light); - - if (facing.getAxis() - .isHorizontal()) - superBuffer.rotateCentered(Direction.UP, - AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite()))); - superBuffer.rotateCentered(Direction.EAST, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing))); - superBuffer.renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, state, state - .getValue(BearingBlock.FACING) - .getOpposite()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java deleted file mode 100644 index 0b59b1f716..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingBlock.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; - -public class ClockworkBearingBlock extends BearingBlock implements ITE { - - public ClockworkBearingBlock(Properties properties) { - super(properties); - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, - Player player, InteractionHand handIn, BlockHitResult hit) { - if (!player.mayBuild()) - return InteractionResult.FAIL; - if (player.isShiftKeyDown()) - return InteractionResult.FAIL; - if (player.getItemInHand(handIn).isEmpty()) { - if (!worldIn.isClientSide) { - withTileEntityDo(worldIn, pos, te -> { - if (te.running) { - te.disassemble(); - return; - } - te.assembleNextTick = true; - }); - } - return InteractionResult.SUCCESS; - } - return InteractionResult.PASS; - } - - @Override - public Class getTileEntityClass() { - return ClockworkBearingTileEntity.class; - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - InteractionResult resultType = super.onWrenched(state, context); - if (!context.getLevel().isClientSide && resultType.consumesAction()) - withTileEntityDo(context.getLevel(), context.getClickedPos(), ClockworkBearingTileEntity::disassemble); - return resultType; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CLOCKWORK_BEARING.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java deleted file mode 100644 index d753580b07..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ /dev/null @@ -1,438 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption.HandType; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.createmod.catnip.utility.lang.Lang; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class ClockworkBearingTileEntity extends KineticTileEntity - implements IBearingTileEntity, IDisplayAssemblyExceptions { - - protected ControlledContraptionEntity hourHand; - protected ControlledContraptionEntity minuteHand; - protected float hourAngle; - protected float minuteAngle; - protected float clientHourAngleDiff; - protected float clientMinuteAngleDiff; - - protected boolean running; - protected boolean assembleNextTick; - protected AssemblyException lastException; - protected ScrollOptionBehaviour operationMode; - - private float prevForcedAngle; - - public ClockworkBearingTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(3); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - operationMode = new ScrollOptionBehaviour<>(ClockHands.class, - CreateLang.translateDirect("contraptions.clockwork.clock_hands"), this, getMovementModeSlot()); - operationMode.requiresWrench(); - behaviours.add(operationMode); - registerAwardables(behaviours, AllAdvancements.CLOCKWORK_BEARING); - } - - @Override - public boolean isWoodenTop() { - return false; - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) { - prevForcedAngle = hourAngle; - clientMinuteAngleDiff /= 2; - clientHourAngleDiff /= 2; - } - - if (!level.isClientSide && assembleNextTick) { - assembleNextTick = false; - if (running) { - boolean canDisassemble = true; - if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption() - .getBlocks() - .isEmpty())) { - if (hourHand != null) - hourHand.getContraption() - .stop(level); - if (minuteHand != null) - minuteHand.getContraption() - .stop(level); - disassemble(); - } - return; - } else - assemble(); - return; - } - - if (!running) - return; - - if (!(hourHand != null && hourHand.isStalled())) { - float newAngle = hourAngle + getHourArmSpeed(); - hourAngle = (float) (newAngle % 360); - } - - if (!(minuteHand != null && minuteHand.isStalled())) { - float newAngle = minuteAngle + getMinuteArmSpeed(); - minuteAngle = (float) (newAngle % 360); - } - - applyRotations(); - } - - @Override - public AssemblyException getLastAssemblyException() { - return lastException; - } - - protected void applyRotations() { - BlockState blockState = getBlockState(); - Axis axis = Axis.X; - - if (blockState.hasProperty(BlockStateProperties.FACING)) - axis = blockState.getValue(BlockStateProperties.FACING) - .getAxis(); - - if (hourHand != null) { - hourHand.setAngle(hourAngle); - hourHand.setRotationAxis(axis); - } - if (minuteHand != null) { - minuteHand.setAngle(minuteAngle); - minuteHand.setRotationAxis(axis); - } - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (hourHand != null && !level.isClientSide) - sendData(); - } - - public float getHourArmSpeed() { - float speed = getAngularSpeed() / 2f; - - if (speed != 0) { - ClockHands mode = ClockHands.values()[operationMode.getValue()]; - float hourTarget = mode == ClockHands.HOUR_FIRST ? getHourTarget(false) - : mode == ClockHands.MINUTE_FIRST ? getMinuteTarget() : getHourTarget(true); - float shortestAngleDiff = AngleHelper.getShortestAngleDiff(hourAngle, hourTarget); - if (shortestAngleDiff < 0) { - speed = Math.max(speed, shortestAngleDiff); - } else { - speed = Math.min(-speed, shortestAngleDiff); - } - } - - return speed + clientHourAngleDiff / 3f; - } - - public float getMinuteArmSpeed() { - float speed = getAngularSpeed(); - - if (speed != 0) { - ClockHands mode = ClockHands.values()[operationMode.getValue()]; - float minuteTarget = mode == ClockHands.MINUTE_FIRST ? getHourTarget(false) : getMinuteTarget(); - float shortestAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngle, minuteTarget); - if (shortestAngleDiff < 0) { - speed = Math.max(speed, shortestAngleDiff); - } else { - speed = Math.min(-speed, shortestAngleDiff); - } - } - - return speed + clientMinuteAngleDiff / 3f; - } - - protected float getHourTarget(boolean cycle24) { - boolean isNatural = level.dimensionType() - .natural(); - int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); - int hours = (dayTime / 1000 + 6) % 24; - int offset = getBlockState().getValue(ClockworkBearingBlock.FACING) - .getAxisDirection() - .getStep(); - float hourTarget = (float) (offset * -360 / (cycle24 ? 24f : 12f) * (hours % (cycle24 ? 24 : 12))); - return hourTarget; - } - - protected float getMinuteTarget() { - boolean isNatural = level.dimensionType() - .natural(); - int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); - int minutes = (dayTime % 1000) * 60 / 1000; - int offset = getBlockState().getValue(ClockworkBearingBlock.FACING) - .getAxisDirection() - .getStep(); - float minuteTarget = (float) (offset * -360 / 60f * (minutes)); - return minuteTarget; - } - - public float getAngularSpeed() { - float speed = -Math.abs(getSpeed() * 3 / 10f); - if (level.isClientSide) - speed *= ServerSpeedProvider.get(); - return speed; - } - - public void assemble() { - if (!(level.getBlockState(worldPosition) - .getBlock() instanceof ClockworkBearingBlock)) - return; - - Direction direction = getBlockState().getValue(BlockStateProperties.FACING); - - // Collect Construct - Pair contraption; - try { - contraption = ClockworkContraption.assembleClockworkAt(level, worldPosition, direction); - lastException = null; - } catch (AssemblyException e) { - lastException = e; - sendData(); - return; - } - if (contraption == null) - return; - if (contraption.getLeft() == null) - return; - if (contraption.getLeft() - .getBlocks() - .isEmpty()) - return; - BlockPos anchor = worldPosition.relative(direction); - - contraption.getLeft() - .removeBlocksFromWorld(level, BlockPos.ZERO); - hourHand = ControlledContraptionEntity.create(level, this, contraption.getLeft()); - hourHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - hourHand.setRotationAxis(direction.getAxis()); - level.addFreshEntity(hourHand); - - if (contraption.getLeft() - .containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - - if (contraption.getRight() != null) { - anchor = worldPosition.relative(direction, contraption.getRight().offset + 1); - contraption.getRight() - .removeBlocksFromWorld(level, BlockPos.ZERO); - minuteHand = ControlledContraptionEntity.create(level, this, contraption.getRight()); - minuteHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - minuteHand.setRotationAxis(direction.getAxis()); - level.addFreshEntity(minuteHand); - - if (contraption.getRight() - .containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - } - - award(AllAdvancements.CLOCKWORK_BEARING); - - // Run - running = true; - hourAngle = 0; - minuteAngle = 0; - sendData(); - } - - public void disassemble() { - if (!running && hourHand == null && minuteHand == null) - return; - - hourAngle = 0; - minuteAngle = 0; - applyRotations(); - - if (hourHand != null) { - hourHand.disassemble(); - } - if (minuteHand != null) - minuteHand.disassemble(); - - hourHand = null; - minuteHand = null; - running = false; - sendData(); - } - - @Override - public void attach(ControlledContraptionEntity contraption) { - if (!(contraption.getContraption() instanceof ClockworkContraption)) - return; - - ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); - setChanged(); - Direction facing = getBlockState().getValue(BlockStateProperties.FACING); - BlockPos anchor = worldPosition.relative(facing, cc.offset + 1); - if (cc.handType == HandType.HOUR) { - this.hourHand = contraption; - hourHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - } else { - this.minuteHand = contraption; - minuteHand.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - } - if (!level.isClientSide) { - this.running = true; - sendData(); - } - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Running", running); - compound.putFloat("HourAngle", hourAngle); - compound.putFloat("MinuteAngle", minuteAngle); - AssemblyException.write(compound, lastException); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - float hourAngleBefore = hourAngle; - float minuteAngleBefore = minuteAngle; - - running = compound.getBoolean("Running"); - hourAngle = compound.getFloat("HourAngle"); - minuteAngle = compound.getFloat("MinuteAngle"); - lastException = AssemblyException.read(compound); - super.read(compound, clientPacket); - - if (!clientPacket) - return; - - if (running) { - clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle); - clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle); - hourAngle = hourAngleBefore; - minuteAngle = minuteAngleBefore; - } else { - hourHand = null; - minuteHand = null; - } - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - assembleNextTick = true; - } - - @Override - public boolean isValid() { - return !isRemoved(); - } - - @Override - public float getInterpolatedAngle(float partialTicks) { - if (isVirtual()) - return Mth.lerp(partialTicks, prevForcedAngle, hourAngle); - if (hourHand == null || hourHand.isStalled()) - partialTicks = 0; - return Mth.lerp(partialTicks, hourAngle, hourAngle + getHourArmSpeed()); - } - - @Override - public void onStall() { - if (!level.isClientSide) - sendData(); - } - - @Override - public void setRemoved() { - super.setRemoved(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - if (!level.isClientSide) - disassemble(); - super.setRemovedNotDueToChunkUnload(); - } - - @Override - public boolean isAttachedTo(AbstractContraptionEntity contraption) { - if (!(contraption.getContraption() instanceof ClockworkContraption)) - return false; - ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); - if (cc.handType == HandType.HOUR) - return this.hourHand == contraption; - else - return this.minuteHand == contraption; - } - - public boolean isRunning() { - return running; - } - - static enum ClockHands implements INamedIconOptions { - - HOUR_FIRST(AllIcons.I_HOUR_HAND_FIRST), - MINUTE_FIRST(AllIcons.I_MINUTE_HAND_FIRST), - HOUR_FIRST_24(AllIcons.I_HOUR_HAND_FIRST_24), - - ; - - private String translationKey; - private AllIcons icon; - - private ClockHands(AllIcons icon) { - this.icon = icon; - translationKey = "contraptions.clockwork." + Lang.asId(name()); - } - - @Override - public AllIcons getIcon() { - return icon; - } - - @Override - public String getTranslationKey() { - return translationKey; - } - - } - - @Override - public BlockPos getBlockPosition() { - return worldPosition; - } - - public void setAngle(float forcedAngle) { - hourAngle = forcedAngle; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java deleted file mode 100644 index 8d7b04e165..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/IBearingTileEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot; -import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.minecraft.core.Direction.Axis; - -public interface IBearingTileEntity extends IControlContraption { - - float getInterpolatedAngle(float partialTicks); - - boolean isWoodenTop(); - - default ValueBoxTransform getMovementModeSlot() { - return new DirectionalExtenderScrollOptionSlot((state, d) -> { - Axis axis = d.getAxis(); - Axis bearingAxis = state.getValue(BearingBlock.FACING) - .getAxis(); - return bearingAxis != axis; - }); - } - - void setAngle(float forcedAngle); - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlock.java deleted file mode 100644 index 702b54bac7..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingBlock.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; - -public class MechanicalBearingBlock extends BearingBlock implements ITE { - - public MechanicalBearingBlock(Properties properties) { - super(properties); - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - if (!player.mayBuild()) - return InteractionResult.FAIL; - if (player.isShiftKeyDown()) - return InteractionResult.FAIL; - if (player.getItemInHand(handIn) - .isEmpty()) { - if (worldIn.isClientSide) - return InteractionResult.SUCCESS; - withTileEntityDo(worldIn, pos, te -> { - if (te.running) { - te.disassemble(); - return; - } - te.assembleNextTick = true; - }); - return InteractionResult.SUCCESS; - } - return InteractionResult.PASS; - } - - @Override - public Class getTileEntityClass() { - return MechanicalBearingTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_BEARING.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java deleted file mode 100644 index 329296ae18..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ /dev/null @@ -1,334 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import java.util.List; - -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity - implements IBearingTileEntity, IDisplayAssemblyExceptions { - - protected ScrollOptionBehaviour movementMode; - protected ControlledContraptionEntity movedContraption; - protected float angle; - protected boolean running; - protected boolean assembleNextTick; - protected float clientAngleDiff; - protected AssemblyException lastException; - - private float prevAngle; - - public MechanicalBearingTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(3); - } - - @Override - public boolean isWoodenTop() { - return false; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - movementMode = new ScrollOptionBehaviour<>(RotationMode.class, CreateLang.translateDirect("contraptions.movement_mode"), - this, getMovementModeSlot()); - movementMode.requiresWrench(); - behaviours.add(movementMode); - registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); - } - - @Override - public void setRemoved() { - super.setRemoved(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - if (!level.isClientSide) - disassemble(); - super.setRemovedNotDueToChunkUnload(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Running", running); - compound.putFloat("Angle", angle); - AssemblyException.write(compound, lastException); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - if (wasMoved) { - super.read(compound, clientPacket); - return; - } - - float angleBefore = angle; - running = compound.getBoolean("Running"); - angle = compound.getFloat("Angle"); - lastException = AssemblyException.read(compound); - super.read(compound, clientPacket); - if (!clientPacket) - return; - if (running) { - if (movedContraption == null || !movedContraption.isStalled()) { - clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle); - angle = angleBefore; - } - } else - movedContraption = null; - } - - @Override - public float getInterpolatedAngle(float partialTicks) { - if (isVirtual()) - return Mth.lerp(partialTicks + .5f, prevAngle, angle); - if (movedContraption == null || movedContraption.isStalled() || !running) - partialTicks = 0; - return Mth.lerp(partialTicks, angle, angle + getAngularSpeed()); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - assembleNextTick = true; - - if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { - movedContraption.getContraption() - .stop(level); - } - } - - public float getAngularSpeed() { - float speed = convertToAngular(isWindmill() ? getGeneratedSpeed() : getSpeed()); - if (getSpeed() == 0) - speed = 0; - if (level.isClientSide) { - speed *= ServerSpeedProvider.get(); - speed += clientAngleDiff / 3f; - } - return speed; - } - - @Override - public AssemblyException getLastAssemblyException() { - return lastException; - } - - protected boolean isWindmill() { - return false; - } - - @Override - public BlockPos getBlockPosition() { - return worldPosition; - } - - public void assemble() { - if (!(level.getBlockState(worldPosition) - .getBlock() instanceof BearingBlock)) - return; - - Direction direction = getBlockState().getValue(BearingBlock.FACING); - BearingContraption contraption = new BearingContraption(isWindmill(), direction); - try { - if (!contraption.assemble(level, worldPosition)) - return; - - lastException = null; - } catch (AssemblyException e) { - lastException = e; - sendData(); - return; - } - - if (isWindmill()) - award(AllAdvancements.WINDMILL); - if (contraption.getSailBlocks() >= 16 * 8) - award(AllAdvancements.WINDMILL_MAXED); - - contraption.removeBlocksFromWorld(level, BlockPos.ZERO); - movedContraption = ControlledContraptionEntity.create(level, this, contraption); - BlockPos anchor = worldPosition.relative(direction); - movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - movedContraption.setRotationAxis(direction.getAxis()); - level.addFreshEntity(movedContraption); - - AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); - - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - - running = true; - angle = 0; - sendData(); - updateGeneratedRotation(); - } - - public void disassemble() { - if (!running && movedContraption == null) - return; - angle = 0; - if (isWindmill()) - applyRotation(); - if (movedContraption != null) { - movedContraption.disassemble(); - AllSoundEvents.CONTRAPTION_DISASSEMBLE.playOnServer(level, worldPosition); - } - - movedContraption = null; - running = false; - updateGeneratedRotation(); - assembleNextTick = false; - sendData(); - } - - @Override - public void tick() { - super.tick(); - - prevAngle = angle; - if (level.isClientSide) - clientAngleDiff /= 2; - - if (!level.isClientSide && assembleNextTick) { - assembleNextTick = false; - if (running) { - boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE - || (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED); - if (speed == 0 && (canDisassemble || movedContraption == null || movedContraption.getContraption() - .getBlocks() - .isEmpty())) { - if (movedContraption != null) - movedContraption.getContraption() - .stop(level); - disassemble(); - return; - } - } else { - if (speed == 0 && !isWindmill()) - return; - assemble(); - } - } - - if (!running) - return; - - if (!(movedContraption != null && movedContraption.isStalled())) { - float angularSpeed = getAngularSpeed(); - float newAngle = angle + angularSpeed; - angle = (float) (newAngle % 360); - } - - applyRotation(); - } - - public boolean isNearInitialAngle() { - return Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45; - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (movedContraption != null && !level.isClientSide) - sendData(); - } - - protected void applyRotation() { - if (movedContraption == null) - return; - movedContraption.setAngle(angle); - BlockState blockState = getBlockState(); - if (blockState.hasProperty(BlockStateProperties.FACING)) - movedContraption.setRotationAxis(blockState.getValue(BlockStateProperties.FACING) - .getAxis()); - } - - @Override - public void attach(ControlledContraptionEntity contraption) { - BlockState blockState = getBlockState(); - if (!(contraption.getContraption() instanceof BearingContraption)) - return; - if (!blockState.hasProperty(BearingBlock.FACING)) - return; - - this.movedContraption = contraption; - setChanged(); - BlockPos anchor = worldPosition.relative(blockState.getValue(BearingBlock.FACING)); - movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - if (!level.isClientSide) { - this.running = true; - sendData(); - } - } - - @Override - public void onStall() { - if (!level.isClientSide) - sendData(); - } - - @Override - public boolean isValid() { - return !isRemoved(); - } - - @Override - public boolean isAttachedTo(AbstractContraptionEntity contraption) { - return movedContraption == contraption; - } - - public boolean isRunning() { - return running; - } - - @Override - public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { - if (super.addToTooltip(tooltip, isPlayerSneaking)) - return true; - if (isPlayerSneaking) - return false; - if (!isWindmill() && getSpeed() == 0) - return false; - if (running) - return false; - BlockState state = getBlockState(); - if (!(state.getBlock() instanceof BearingBlock)) - return false; - - BlockState attachedState = level.getBlockState(worldPosition.relative(state.getValue(BearingBlock.FACING))); - if (attachedState.getMaterial() - .isReplaceable()) - return false; - TooltipHelper.addHint(tooltip, "hint.empty_bearing"); - return true; - } - - public void setAngle(float forcedAngle) { - angle = forcedAngle; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java deleted file mode 100644 index ca4526b8da..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class StabilizedContraption extends Contraption { - - private Direction facing; - - public StabilizedContraption() {} - - public StabilizedContraption(Direction facing) { - this.facing = facing; - } - - @Override - public boolean assemble(Level world, BlockPos pos) throws AssemblyException { - BlockPos offset = pos.relative(facing); - if (!searchMovedStructure(world, offset, null)) - return false; - startMoving(world); - if (blocks.isEmpty()) - return false; - return true; - } - - @Override - protected boolean isAnchoringBlockAt(BlockPos pos) { - return false; - } - - @Override - protected ContraptionType getType() { - return ContraptionType.STABILIZED; - } - - @Override - public CompoundTag writeNBT(boolean spawnPacket) { - CompoundTag tag = super.writeNBT(spawnPacket); - tag.putInt("Facing", facing.get3DDataValue()); - return tag; - } - - @Override - public void readNBT(Level world, CompoundTag tag, boolean spawnData) { - facing = Direction.from3DDataValue(tag.getInt("Facing")); - super.readNBT(world, tag, spawnData); - } - - @Override - public boolean canBeStabilized(Direction facing, BlockPos localPos) { - return false; - } - - public Direction getFacing() { - return facing; - } - - @Override - @OnlyIn(Dist.CLIENT) - public ContraptionLighter makeLighter() { - return new NonStationaryLighter<>(this); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingBlock.java deleted file mode 100644 index da97e6dcf1..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingBlock.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; - -import net.createmod.catnip.utility.Couple; -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; - -public class WindmillBearingBlock extends BearingBlock implements ITE { - - public WindmillBearingBlock(Properties properties) { - super(properties); - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - if (!player.mayBuild()) - return InteractionResult.FAIL; - if (player.isShiftKeyDown()) - return InteractionResult.FAIL; - if (player.getItemInHand(handIn) - .isEmpty()) { - if (worldIn.isClientSide) - return InteractionResult.SUCCESS; - withTileEntityDo(worldIn, pos, te -> { - if (te.running) { - te.disassemble(); - return; - } - te.assembleNextTick = true; - }); - return InteractionResult.SUCCESS; - } - return InteractionResult.PASS; - } - - @Override - public Class getTileEntityClass() { - return WindmillBearingTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.WINDMILL_BEARING.get(); - } - - public static Couple getSpeedRange() { - return Couple.create(1, 16); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingTileEntity.java deleted file mode 100644 index 89af1936a6..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/WindmillBearingTileEntity.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.bearing; - -import java.util.List; - -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class WindmillBearingTileEntity extends MechanicalBearingTileEntity { - - protected ScrollOptionBehaviour movementDirection; - protected float lastGeneratedSpeed; - - protected boolean queuedReassembly; - - public WindmillBearingTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void updateGeneratedRotation() { - super.updateGeneratedRotation(); - lastGeneratedSpeed = getGeneratedSpeed(); - queuedReassembly = false; - } - - @Override - public void onSpeedChanged(float prevSpeed) { - boolean cancelAssembly = assembleNextTick; - super.onSpeedChanged(prevSpeed); - assembleNextTick = cancelAssembly; - } - - @Override - public void tick() { - super.tick(); - if (level.isClientSide()) - return; - if (!queuedReassembly) - return; - queuedReassembly = false; - if (!running) - assembleNextTick = true; - } - - public void disassembleForMovement() { - if (!running) - return; - disassemble(); - queuedReassembly = true; - } - - @Override - public float getGeneratedSpeed() { - if (!running) - return 0; - if (movedContraption == null) - return lastGeneratedSpeed; - int sails = ((BearingContraption) movedContraption.getContraption()).getSailBlocks() - / AllConfigs.SERVER.kinetics.windmillSailsPerRPM.get(); - return Mth.clamp(sails, 1, 16) * getAngleSpeedDirection(); - } - - @Override - protected boolean isWindmill() { - return true; - } - - protected float getAngleSpeedDirection() { - RotationDirection rotationDirection = RotationDirection.values()[movementDirection.getValue()]; - return (rotationDirection == RotationDirection.CLOCKWISE ? 1 : -1); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putFloat("LastGenerated", lastGeneratedSpeed); - compound.putBoolean("QueueAssembly", queuedReassembly); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - if (!wasMoved) - lastGeneratedSpeed = compound.getFloat("LastGenerated"); - queuedReassembly = compound.getBoolean("QueueAssembly"); - super.read(compound, clientPacket); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - behaviours.remove(movementMode); - movementDirection = new ScrollOptionBehaviour<>(RotationDirection.class, - CreateLang.translateDirect("contraptions.windmill.rotation_direction"), this, getMovementModeSlot()); - movementDirection.requiresWrench(); - movementDirection.withCallback($ -> onDirectionChanged()); - behaviours.add(movementDirection); - registerAwardables(behaviours, AllAdvancements.WINDMILL, AllAdvancements.WINDMILL_MAXED); - } - - private void onDirectionChanged() { - if (!running) - return; - if (!level.isClientSide) - updateGeneratedRotation(); - } - - @Override - public boolean isWoodenTop() { - return true; - } - - public static enum RotationDirection implements INamedIconOptions { - - CLOCKWISE(AllIcons.I_REFRESH), COUNTER_CLOCKWISE(AllIcons.I_ROTATE_CCW), - - ; - - private String translationKey; - private AllIcons icon; - - private RotationDirection(AllIcons icon) { - this.icon = icon; - translationKey = "generic." + Lang.asId(name()); - } - - @Override - public AllIcons getIcon() { - return icon; - } - - @Override - public String getTranslationKey() { - return translationKey; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisRangeDisplay.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisRangeDisplay.java deleted file mode 100644 index 13cbbffe6e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisRangeDisplay.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.mojang.datafixers.util.Pair; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllKeys; -import com.simibubi.create.AllSpecialTextures; - -import net.createmod.catnip.CatnipClient; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; - -public class ChassisRangeDisplay { - - private static final int DISPLAY_TIME = 200; - private static GroupEntry lastHoveredGroup = null; - - private static class Entry { - ChassisTileEntity te; - int timer; - - public Entry(ChassisTileEntity te) { - this.te = te; - timer = DISPLAY_TIME; - CatnipClient.OUTLINER.showCluster(getOutlineKey(), createSelection(te)) - .colored(0xFFFFFF) - .disableNormals() - .lineWidth(1 / 16f) - .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED); - } - - protected Object getOutlineKey() { - return Pair.of(te.getBlockPos(), 1); - } - - protected Set createSelection(ChassisTileEntity chassis) { - Set positions = new HashSet<>(); - List includedBlockPositions = chassis.getIncludedBlockPositions(null, true); - if (includedBlockPositions == null) - return Collections.emptySet(); - positions.addAll(includedBlockPositions); - return positions; - } - - } - - private static class GroupEntry extends Entry { - - List includedTEs; - - public GroupEntry(ChassisTileEntity te) { - super(te); - } - - @Override - protected Object getOutlineKey() { - return this; - } - - @Override - protected Set createSelection(ChassisTileEntity chassis) { - Set list = new HashSet<>(); - includedTEs = te.collectChassisGroup(); - if (includedTEs == null) - return list; - for (ChassisTileEntity chassisTileEntity : includedTEs) - list.addAll(super.createSelection(chassisTileEntity)); - return list; - } - - } - - static Map entries = new HashMap<>(); - static List groupEntries = new ArrayList<>(); - - public static void tick() { - Player player = Minecraft.getInstance().player; - Level world = Minecraft.getInstance().level; - boolean hasWrench = AllItems.WRENCH.isIn(player.getMainHandItem()); - - for (Iterator iterator = entries.keySet() - .iterator(); iterator.hasNext();) { - BlockPos pos = iterator.next(); - Entry entry = entries.get(pos); - if (tickEntry(entry, hasWrench)) - iterator.remove(); - CatnipClient.OUTLINER.keep(entry.getOutlineKey()); - } - - for (Iterator iterator = groupEntries.iterator(); iterator.hasNext();) { - GroupEntry group = iterator.next(); - if (tickEntry(group, hasWrench)) { - iterator.remove(); - if (group == lastHoveredGroup) - lastHoveredGroup = null; - } - CatnipClient.OUTLINER.keep(group.getOutlineKey()); - } - - if (!hasWrench) - return; - - HitResult over = Minecraft.getInstance().hitResult; - if (!(over instanceof BlockHitResult)) - return; - BlockHitResult ray = (BlockHitResult) over; - BlockPos pos = ray.getBlockPos(); - BlockEntity tileEntity = world.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) - return; - if (!(tileEntity instanceof ChassisTileEntity)) - return; - - boolean ctrl = AllKeys.ctrlDown(); - ChassisTileEntity chassisTileEntity = (ChassisTileEntity) tileEntity; - - if (ctrl) { - GroupEntry existingGroupForPos = getExistingGroupForPos(pos); - if (existingGroupForPos != null) { - for (ChassisTileEntity included : existingGroupForPos.includedTEs) - entries.remove(included.getBlockPos()); - existingGroupForPos.timer = DISPLAY_TIME; - return; - } - } - - if (!entries.containsKey(pos) || ctrl) - display(chassisTileEntity); - else { - if (!ctrl) - entries.get(pos).timer = DISPLAY_TIME; - } - } - - private static boolean tickEntry(Entry entry, boolean hasWrench) { - ChassisTileEntity chassisTileEntity = entry.te; - Level teWorld = chassisTileEntity.getLevel(); - Level world = Minecraft.getInstance().level; - - if (chassisTileEntity.isRemoved() || teWorld == null || teWorld != world - || !world.isLoaded(chassisTileEntity.getBlockPos())) { - return true; - } - - if (!hasWrench && entry.timer > 20) { - entry.timer = 20; - return false; - } - - entry.timer--; - if (entry.timer == 0) - return true; - return false; - } - - public static void display(ChassisTileEntity chassis) { - - // Display a group and kill any selections of its contained chassis blocks - if (AllKeys.ctrlDown()) { - GroupEntry hoveredGroup = new GroupEntry(chassis); - - for (ChassisTileEntity included : hoveredGroup.includedTEs) - CatnipClient.OUTLINER.remove(included.getBlockPos()); - - groupEntries.forEach(entry -> CatnipClient.OUTLINER.remove(entry.getOutlineKey())); - groupEntries.clear(); - entries.clear(); - groupEntries.add(hoveredGroup); - return; - } - - // Display an individual chassis and kill any group selections that contained it - BlockPos pos = chassis.getBlockPos(); - GroupEntry entry = getExistingGroupForPos(pos); - if (entry != null) - CatnipClient.OUTLINER.remove(entry.getOutlineKey()); - - groupEntries.clear(); - entries.clear(); - entries.put(pos, new Entry(chassis)); - - } - - private static GroupEntry getExistingGroupForPos(BlockPos pos) { - for (GroupEntry groupEntry : groupEntries) - for (ChassisTileEntity chassis : groupEntry.includedTEs) - if (pos.equals(chassis.getBlockPos())) - return groupEntry; - return null; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java deleted file mode 100644 index 37d1823054..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.Set; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.BulkScrollValueBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - -public class ChassisTileEntity extends SmartTileEntity { - - ScrollValueBehaviour range; - - public ChassisTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - int max = AllConfigs.SERVER.kinetics.maxChassisRange.get(); - range = new BulkScrollValueBehaviour(CreateLang.translateDirect("generic.range"), this, new CenteredSideValueBoxTransform(), - te -> ((ChassisTileEntity) te).collectChassisGroup()); - range.requiresWrench(); - range.between(1, max); - range - .withClientCallback( - i -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ChassisRangeDisplay.display(this))); - range.value = max / 2; - behaviours.add(range); - } - - @Override - public void initialize() { - super.initialize(); - if (getBlockState().getBlock() instanceof RadialChassisBlock) - range.setLabel(CreateLang.translateDirect("generic.radius")); - } - - public int getRange() { - return range.getValue(); - } - - public List getIncludedBlockPositions(Direction forcedMovement, boolean visualize) { - if (!(getBlockState().getBlock() instanceof AbstractChassisBlock)) - return Collections.emptyList(); - return isRadial() ? getIncludedBlockPositionsRadial(forcedMovement, visualize) - : getIncludedBlockPositionsLinear(forcedMovement, visualize); - } - - protected boolean isRadial() { - return level.getBlockState(worldPosition).getBlock() instanceof RadialChassisBlock; - } - - public List collectChassisGroup() { - Queue frontier = new LinkedList<>(); - List collected = new ArrayList<>(); - Set visited = new HashSet<>(); - frontier.add(worldPosition); - while (!frontier.isEmpty()) { - BlockPos current = frontier.poll(); - if (visited.contains(current)) - continue; - visited.add(current); - BlockEntity tileEntity = level.getBlockEntity(current); - if (tileEntity instanceof ChassisTileEntity) { - ChassisTileEntity chassis = (ChassisTileEntity) tileEntity; - collected.add(chassis); - visited.add(current); - chassis.addAttachedChasses(frontier, visited); - } - } - return collected; - } - - public boolean addAttachedChasses(Queue frontier, Set visited) { - BlockState state = getBlockState(); - if (!(state.getBlock() instanceof AbstractChassisBlock)) - return false; - Axis axis = state.getValue(AbstractChassisBlock.AXIS); - if (isRadial()) { - - // Collect chain of radial chassis - for (int offset : new int[] { -1, 1 }) { - Direction direction = Direction.get(AxisDirection.POSITIVE, axis); - BlockPos currentPos = worldPosition.relative(direction, offset); - if (!level.isLoaded(currentPos)) - return false; - - BlockState neighbourState = level.getBlockState(currentPos); - if (!AllBlocks.RADIAL_CHASSIS.has(neighbourState)) - continue; - if (axis != neighbourState.getValue(BlockStateProperties.AXIS)) - continue; - if (!visited.contains(currentPos)) - frontier.add(currentPos); - } - - return true; - } - - // Collect group of connected linear chassis - for (Direction offset : Iterate.directions) { - BlockPos current = worldPosition.relative(offset); - if (visited.contains(current)) - continue; - if (!level.isLoaded(current)) - return false; - - BlockState neighbourState = level.getBlockState(current); - if (!LinearChassisBlock.isChassis(neighbourState)) - continue; - if (!LinearChassisBlock.sameKind(state, neighbourState)) - continue; - if (neighbourState.getValue(LinearChassisBlock.AXIS) != axis) - continue; - - frontier.add(current); - } - - return true; - } - - private List getIncludedBlockPositionsLinear(Direction forcedMovement, boolean visualize) { - List positions = new ArrayList<>(); - BlockState state = getBlockState(); - AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); - Axis axis = state.getValue(AbstractChassisBlock.AXIS); - Direction facing = Direction.get(AxisDirection.POSITIVE, axis); - int chassisRange = visualize ? range.scrollableValue : getRange(); - - for (int offset : new int[] { 1, -1 }) { - if (offset == -1) - facing = facing.getOpposite(); - boolean sticky = state.getValue(block.getGlueableSide(state, facing)); - for (int i = 1; i <= chassisRange; i++) { - BlockPos current = worldPosition.relative(facing, i); - BlockState currentState = level.getBlockState(current); - - if (forcedMovement != facing && !sticky) - break; - - // Ignore replaceable Blocks and Air-like - if (!BlockMovementChecks.isMovementNecessary(currentState, level, current)) - break; - if (BlockMovementChecks.isBrittle(currentState)) - break; - - positions.add(current); - - if (BlockMovementChecks.isNotSupportive(currentState, facing)) - break; - } - } - - return positions; - } - - private List getIncludedBlockPositionsRadial(Direction forcedMovement, boolean visualize) { - List positions = new ArrayList<>(); - BlockState state = level.getBlockState(worldPosition); - Axis axis = state.getValue(AbstractChassisBlock.AXIS); - AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); - int chassisRange = visualize ? range.scrollableValue : getRange(); - - for (Direction facing : Iterate.directions) { - if (facing.getAxis() == axis) - continue; - if (!state.getValue(block.getGlueableSide(state, facing))) - continue; - - BlockPos startPos = worldPosition.relative(facing); - List localFrontier = new LinkedList<>(); - Set localVisited = new HashSet<>(); - localFrontier.add(startPos); - - while (!localFrontier.isEmpty()) { - BlockPos searchPos = localFrontier.remove(0); - BlockState searchedState = level.getBlockState(searchPos); - - if (localVisited.contains(searchPos)) - continue; - if (!searchPos.closerThan(worldPosition, chassisRange + .5f)) - continue; - if (!BlockMovementChecks.isMovementNecessary(searchedState, level, searchPos)) - continue; - if (BlockMovementChecks.isBrittle(searchedState)) - continue; - - localVisited.add(searchPos); - if (!searchPos.equals(worldPosition)) - positions.add(searchPos); - - for (Direction offset : Iterate.directions) { - if (offset.getAxis() == axis) - continue; - if (searchPos.equals(worldPosition) && offset != facing) - continue; - if (BlockMovementChecks.isNotSupportive(searchedState, offset)) - continue; - - localFrontier.add(searchPos.relative(offset)); - } - } - } - - return positions; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java deleted file mode 100644 index d3e8e1a5e8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerRenderer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; - -public class StickerRenderer extends SafeTileEntityRenderer { - - public StickerRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(StickerTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState state = te.getBlockState(); - SuperByteBuffer head = CachedPartialBuffers.partial(AllBlockPartials.STICKER_HEAD, state); - float offset; - - if (te.getLevel() != Minecraft.getInstance().level && !te.isVirtual()) - offset = state.getValue(StickerBlock.EXTENDED) ? 1 : 0; - else - offset = te.piston.getValue(WorldTickHolder.getPartialTicks(te.getLevel())); - - Direction facing = state.getValue(StickerBlock.FACING); - head.nudge(te.hashCode()) - .centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(AngleHelper.verticalAngle(facing) + 90) - .unCentre() - .translate(0, (offset * offset) * 4 / 16f, 0) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java deleted file mode 100644 index 413ef22d40..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/StickerTileEntity.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.chassis; - -import java.util.List; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueItem; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; - -public class StickerTileEntity extends SmartTileEntity { - - LerpedFloat piston; - boolean update; - - public StickerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - piston = LerpedFloat.linear(); - update = false; - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void initialize() { - super.initialize(); - if (!level.isClientSide) - return; - piston.startWithValue(isBlockStateExtended() ? 1 : 0); - } - - public boolean isBlockStateExtended() { - BlockState blockState = getBlockState(); - boolean extended = AllBlocks.STICKER.has(blockState) && blockState.getValue(StickerBlock.EXTENDED); - return extended; - } - - @Override - public void tick() { - super.tick(); - if (!level.isClientSide) - return; - piston.tickChaser(); - - if (isAttachedToBlock() && piston.getValue(0) != piston.getValue() && piston.getValue() == 1) { - SuperGlueItem.spawnParticles(level, worldPosition, getBlockState().getValue(StickerBlock.FACING), true); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(true)); - } - - if (!update) - return; - update = false; - int target = isBlockStateExtended() ? 1 : 0; - if (isAttachedToBlock() && target == 0 && piston.getChaseTarget() == 1) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(false)); - piston.chase(target, .4f, Chaser.LINEAR); - - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - } - - public boolean isAttachedToBlock() { - BlockState blockState = getBlockState(); - if (!AllBlocks.STICKER.has(blockState)) - return false; - Direction direction = blockState.getValue(StickerBlock.FACING); - return SuperGlueEntity.isValidFace(level, worldPosition.relative(direction), direction.getOpposite()); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (clientPacket) - update = true; - } - - @OnlyIn(Dist.CLIENT) - public void playSound(boolean attach) { - AllSoundEvents.SLIME_ADDED.play(level, Minecraft.getInstance().player, worldPosition, 0.35f, attach ? 0.75f : 0.2f); - } - - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java deleted file mode 100644 index 626854d9c8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageInstance.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; - -public class GantryCarriageInstance extends ShaftInstance implements DynamicInstance { - - private final ModelData gantryCogs; - - final Direction facing; - final Boolean alongFirst; - final Direction.Axis rotationAxis; - final float rotationMult; - final BlockPos visualPos; - - private float lastAngle = Float.NaN; - - public GantryCarriageInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); - - gantryCogs = getTransformMaterial() - .getModel(AllBlockPartials.GANTRY_COGS, blockState) - .createInstance(); - - facing = blockState.getValue(GantryCarriageBlock.FACING); - alongFirst = blockState.getValue(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); - rotationAxis = KineticTileEntityRenderer.getRotationAxisOf(tile); - - rotationMult = getRotationMultiplier(getGantryAxis(), facing); - - visualPos = facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? tile.getBlockPos() - : tile.getBlockPos() - .relative(facing.getOpposite()); - - animateCogs(getCogAngle()); - } - - @Override - public void beginFrame() { - float cogAngle = getCogAngle(); - - if (Mth.equal(cogAngle, lastAngle)) return; - - animateCogs(cogAngle); - } - - private float getCogAngle() { - return GantryCarriageRenderer.getAngleForTe(blockEntity, visualPos, rotationAxis) * rotationMult; - } - - private void animateCogs(float cogAngle) { - gantryCogs.loadIdentity() - .translate(getInstancePosition()) - .centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .rotateY(alongFirst ^ facing.getAxis() == Direction.Axis.X ? 0 : 90) - .translate(0, -9 / 16f, 0) - .rotateX(-cogAngle) - .translate(0, 9 / 16f, 0) - .unCentre(); - } - - static float getRotationMultiplier(Direction.Axis gantryAxis, Direction facing) { - float multiplier = 1; - if (gantryAxis == Direction.Axis.X) - if (facing == Direction.UP) - multiplier *= -1; - if (gantryAxis == Direction.Axis.Y) - if (facing == Direction.NORTH || facing == Direction.EAST) - multiplier *= -1; - - return multiplier; - } - - private Direction.Axis getGantryAxis() { - Direction.Axis gantryAxis = Direction.Axis.X; - for (Direction.Axis axis : Iterate.axes) - if (axis != rotationAxis && axis != facing.getAxis()) - gantryAxis = axis; - return gantryAxis; - } - - @Override - public void updateLight() { - relight(pos, gantryCogs, rotatingModel); - } - - @Override - public void remove() { - super.remove(); - gantryCogs.delete(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java deleted file mode 100644 index 9a8741ba57..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageRenderer.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.block.state.BlockState; - -public class GantryCarriageRenderer extends KineticTileEntityRenderer { - - public GantryCarriageRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState state = te.getBlockState(); - Direction facing = state.getValue(GantryCarriageBlock.FACING); - Boolean alongFirst = state.getValue(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); - Axis rotationAxis = getRotationAxisOf(te); - BlockPos visualPos = facing.getAxisDirection() == AxisDirection.POSITIVE ? te.getBlockPos() - : te.getBlockPos() - .relative(facing.getOpposite()); - float angleForTe = getAngleForTe(te, visualPos, rotationAxis); - - Axis gantryAxis = Axis.X; - for (Axis axis : Iterate.axes) - if (axis != rotationAxis && axis != facing.getAxis()) - gantryAxis = axis; - - if (gantryAxis == Axis.X) - if (facing == Direction.UP) - angleForTe *= -1; - if (gantryAxis == Axis.Y) - if (facing == Direction.NORTH || facing == Direction.EAST) - angleForTe *= -1; - - SuperByteBuffer cogs = CachedPartialBuffers.partial(AllBlockPartials.GANTRY_COGS, state); - float finalAngleForTe = angleForTe; - cogs.centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .rotateY(alongFirst ^ facing.getAxis() == Axis.X ? 0 : 90) - .translate(0, -9 / 16f, 0) - .rotateX(-finalAngleForTe) - .translate(0, 9 / 16f, 0) - .unCentre(); - - cogs.light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - - } - - public static float getAngleForTe(KineticTileEntity te, final BlockPos pos, Axis axis) { - float time = WorldTickHolder.getRenderTime(te.getLevel()); - float offset = getRotationOffsetForPosition(te, pos, axis); - return (time * te.getSpeed() * 3f / 20 + offset) % 360; - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java deleted file mode 100644 index 79e7c7c720..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageTileEntity.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class GantryCarriageTileEntity extends KineticTileEntity implements IDisplayAssemblyExceptions { - - boolean assembleNextTick; - protected AssemblyException lastException; - - public GantryCarriageTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - } - - public void checkValidGantryShaft() { - if (shouldAssemble()) - queueAssembly(); - } - - @Override - public void initialize() { - super.initialize(); - if (!getBlockState().canSurvive(level, worldPosition)) - level.destroyBlock(worldPosition, true); - } - - public void queueAssembly() { - assembleNextTick = true; - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) - return; - - if (assembleNextTick) { - tryAssemble(); - assembleNextTick = false; - } - } - - @Override - public AssemblyException getLastAssemblyException() { - return lastException; - } - - private void tryAssemble() { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof GantryCarriageBlock)) - return; - - Direction direction = blockState.getValue(GantryCarriageBlock.FACING); - GantryContraption contraption = new GantryContraption(direction); - - BlockEntity shaftTe = level.getBlockEntity(worldPosition.relative(direction.getOpposite())); - if (!(shaftTe instanceof GantryShaftTileEntity)) - return; - BlockState shaftState = shaftTe.getBlockState(); - if (!AllBlocks.GANTRY_SHAFT.has(shaftState)) - return; - - float pinionMovementSpeed = ((GantryShaftTileEntity) shaftTe).getPinionMovementSpeed(); - Direction shaftOrientation = shaftState.getValue(GantryShaftBlock.FACING); - Direction movementDirection = shaftOrientation; - if (pinionMovementSpeed < 0) - movementDirection = movementDirection.getOpposite(); - - try { - lastException = null; - if (!contraption.assemble(level, worldPosition)) - return; - - sendData(); - } catch (AssemblyException e) { - lastException = e; - sendData(); - return; - } - if (ContraptionCollider.isCollidingWithWorld(level, contraption, worldPosition.relative(movementDirection), - movementDirection)) - return; - - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - - contraption.removeBlocksFromWorld(level, BlockPos.ZERO); - GantryContraptionEntity movedContraption = - GantryContraptionEntity.create(level, contraption, shaftOrientation); - BlockPos anchor = worldPosition; - movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); - level.addFreshEntity(movedContraption); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - AssemblyException.write(compound, lastException); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - lastException = AssemblyException.read(compound); - super.read(compound, clientPacket); - } - - @Override - public float propagateRotationTo(KineticTileEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, - boolean connectedViaAxes, boolean connectedViaCogs) { - float defaultModifier = - super.propagateRotationTo(target, stateFrom, stateTo, diff, connectedViaAxes, connectedViaCogs); - - if (connectedViaAxes) - return defaultModifier; - if (!AllBlocks.GANTRY_SHAFT.has(stateTo)) - return defaultModifier; - if (!stateTo.getValue(GantryShaftBlock.POWERED)) - return defaultModifier; - - Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); - if (stateFrom.getValue(GantryCarriageBlock.FACING) != direction.getOpposite()) - return defaultModifier; - return getGantryPinionModifier(stateTo.getValue(GantryShaftBlock.FACING), stateFrom.getValue(GantryCarriageBlock.FACING)); - } - - public static float getGantryPinionModifier(Direction shaft, Direction pinionDirection) { - Axis shaftAxis = shaft.getAxis(); - float directionModifier = shaft.getAxisDirection() - .getStep(); - if (shaftAxis == Axis.Y) - if (pinionDirection == Direction.NORTH || pinionDirection == Direction.EAST) - return -directionModifier; - if (shaftAxis == Axis.X) - if (pinionDirection == Direction.DOWN || pinionDirection == Direction.SOUTH) - return -directionModifier; - if (shaftAxis == Axis.Z) - if (pinionDirection == Direction.UP || pinionDirection == Direction.WEST) - return -directionModifier; - return directionModifier; - } - - private boolean shouldAssemble() { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof GantryCarriageBlock)) - return false; - Direction facing = blockState.getValue(GantryCarriageBlock.FACING) - .getOpposite(); - BlockState shaftState = level.getBlockState(worldPosition.relative(facing)); - if (!(shaftState.getBlock() instanceof GantryShaftBlock)) - return false; - if (shaftState.getValue(GantryShaftBlock.POWERED)) - return false; - BlockEntity te = level.getBlockEntity(worldPosition.relative(facing)); - return te instanceof GantryShaftTileEntity && ((GantryShaftTileEntity) te).canAssembleOn(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java deleted file mode 100644 index bbb995b662..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class GantryContraption extends TranslatingContraption { - - protected Direction facing; - - public GantryContraption() {} - - public GantryContraption(Direction facing) { - this.facing = facing; - } - - @Override - public boolean assemble(Level world, BlockPos pos) throws AssemblyException { - if (!searchMovedStructure(world, pos, null)) - return false; - startMoving(world); - return true; - } - - @Override - public CompoundTag writeNBT(boolean spawnPacket) { - CompoundTag tag = super.writeNBT(spawnPacket); - tag.putInt("Facing", facing.get3DDataValue()); - return tag; - } - - @Override - public void readNBT(Level world, CompoundTag tag, boolean spawnData) { - facing = Direction.from3DDataValue(tag.getInt("Facing")); - super.readNBT(world, tag, spawnData); - } - - @Override - protected boolean isAnchoringBlockAt(BlockPos pos) { - return super.isAnchoringBlockAt(pos.relative(facing)); - } - - @Override - protected ContraptionType getType() { - return ContraptionType.GANTRY; - } - - public Direction getFacing() { - return facing; - } - - @Override - protected boolean shouldUpdateAfterMovement(StructureBlockInfo info) { - return super.shouldUpdateAfterMovement(info) && !AllBlocks.GANTRY_CARRIAGE.has(info.state); - } - - @Override - @OnlyIn(Dist.CLIENT) - public ContraptionLighter makeLighter() { - return new NonStationaryLighter<>(this); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java deleted file mode 100644 index 51c162dec8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionEntity.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllEntityTypes; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileEntity; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.network.PacketDistributor; - -public class GantryContraptionEntity extends AbstractContraptionEntity { - - Direction movementAxis; - double clientOffsetDiff; - double axisMotion; - - public GantryContraptionEntity(EntityType entityTypeIn, Level worldIn) { - super(entityTypeIn, worldIn); - } - - public static GantryContraptionEntity create(Level world, Contraption contraption, Direction movementAxis) { - GantryContraptionEntity entity = new GantryContraptionEntity(AllEntityTypes.GANTRY_CONTRAPTION.get(), world); - entity.setContraption(contraption); - entity.movementAxis = movementAxis; - return entity; - } - - @Override - protected void tickContraption() { - if (!(contraption instanceof GantryContraption)) - return; - - double prevAxisMotion = axisMotion; - if (level.isClientSide) { - clientOffsetDiff *= .75f; - updateClientMotion(); - } - - checkPinionShaft(); - tickActors(); - Vec3 movementVec = getDeltaMovement(); - - if (ContraptionCollider.collideBlocks(this)) { - if (!level.isClientSide) - disassemble(); - return; - } - - if (!isStalled() && tickCount > 2) - move(movementVec.x, movementVec.y, movementVec.z); - - if (Math.signum(prevAxisMotion) != Math.signum(axisMotion) && prevAxisMotion != 0) - contraption.stop(level); - if (!level.isClientSide && (prevAxisMotion != axisMotion || tickCount % 3 == 0)) - sendPacket(); - } - - protected void checkPinionShaft() { - Vec3 movementVec; - Direction facing = ((GantryContraption) contraption).getFacing(); - Vec3 currentPosition = getAnchorVec().add(.5, .5, .5); - BlockPos gantryShaftPos = new BlockPos(currentPosition).relative(facing.getOpposite()); - - BlockEntity te = level.getBlockEntity(gantryShaftPos); - if (!(te instanceof GantryShaftTileEntity) || !AllBlocks.GANTRY_SHAFT.has(te.getBlockState())) { - if (!level.isClientSide) { - setContraptionMotion(Vec3.ZERO); - disassemble(); - } - return; - } - - BlockState blockState = te.getBlockState(); - Direction direction = blockState.getValue(GantryShaftBlock.FACING); - GantryShaftTileEntity gantryShaftTileEntity = (GantryShaftTileEntity) te; - - float pinionMovementSpeed = gantryShaftTileEntity.getPinionMovementSpeed(); - movementVec = Vec3.atLowerCornerOf(direction.getNormal()).scale(pinionMovementSpeed); - - if (blockState.getValue(GantryShaftBlock.POWERED) || pinionMovementSpeed == 0) { - setContraptionMotion(Vec3.ZERO); - if (!level.isClientSide) - disassemble(); - return; - } - - Vec3 nextPosition = currentPosition.add(movementVec); - double currentCoord = direction.getAxis() - .choose(currentPosition.x, currentPosition.y, currentPosition.z); - double nextCoord = direction.getAxis() - .choose(nextPosition.x, nextPosition.y, nextPosition.z); - - if ((Mth.floor(currentCoord) + .5f < nextCoord != (pinionMovementSpeed * direction.getAxisDirection() - .getStep() < 0))) - if (!gantryShaftTileEntity.canAssembleOn()) { - setContraptionMotion(Vec3.ZERO); - if (!level.isClientSide) - disassemble(); - return; - } - - if (level.isClientSide) - return; - - axisMotion = pinionMovementSpeed; - setContraptionMotion(movementVec); - } - - @Override - protected void writeAdditional(CompoundTag compound, boolean spawnPacket) { - NBTHelper.writeEnum(compound, "GantryAxis", movementAxis); - super.writeAdditional(compound, spawnPacket); - } - - protected void readAdditional(CompoundTag compound, boolean spawnData) { - movementAxis = NBTHelper.readEnum(compound, "GantryAxis", Direction.class); - super.readAdditional(compound, spawnData); - } - - @Override - public Vec3 applyRotation(Vec3 localPos, float partialTicks) { - return localPos; - } - - @Override - public Vec3 reverseRotation(Vec3 localPos, float partialTicks) { - return localPos; - } - - @Override - protected StructureTransform makeStructureTransform() { - return new StructureTransform(new BlockPos(getAnchorVec().add(.5, .5, .5)), 0, 0, 0); - } - - @Override - protected float getStalledAngle() { - return 0; - } - - @Override - public void teleportTo(double p_70634_1_, double p_70634_3_, double p_70634_5_) {} - - @Override - @OnlyIn(Dist.CLIENT) - public void lerpTo(double x, double y, double z, float yw, float pt, int inc, boolean t) {} - - @Override - protected void handleStallInformation(float x, float y, float z, float angle) { - setPosRaw(x, y, z); - clientOffsetDiff = 0; - } - - @Override - public ContraptionRotationState getRotationState() { - return ContraptionRotationState.NONE; - } - - @Override - public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) { } - - public void updateClientMotion() { - float modifier = movementAxis.getAxisDirection() - .getStep(); - setContraptionMotion(Vec3.atLowerCornerOf(movementAxis.getNormal()) - .scale((axisMotion + clientOffsetDiff * modifier / 2f) * ServerSpeedProvider.get())); - } - - public double getAxisCoord() { - Vec3 anchorVec = getAnchorVec(); - return movementAxis.getAxis() - .choose(anchorVec.x, anchorVec.y, anchorVec.z); - } - - public void sendPacket() { - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new GantryContraptionUpdatePacket(getId(), getAxisCoord(), axisMotion)); - } - - @OnlyIn(Dist.CLIENT) - public static void handlePacket(GantryContraptionUpdatePacket packet) { - Entity entity = Minecraft.getInstance().level.getEntity(packet.entityID); - if (!(entity instanceof GantryContraptionEntity)) - return; - GantryContraptionEntity ce = (GantryContraptionEntity) entity; - ce.axisMotion = packet.motion; - ce.clientOffsetDiff = packet.coord - ce.getAxisCoord(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java deleted file mode 100644 index 2fb4b9af28..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraptionUpdatePacket.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class GantryContraptionUpdatePacket extends SimplePacketBase { - - int entityID; - double coord; - double motion; - - public GantryContraptionUpdatePacket(int entityID, double coord, double motion) { - this.entityID = entityID; - this.coord = coord; - this.motion = motion; - } - - public GantryContraptionUpdatePacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - coord = buffer.readFloat(); - motion = buffer.readFloat(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - buffer.writeFloat((float) coord); - buffer.writeFloat((float) motion); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork( - () -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> GantryContraptionEntity.handlePacket(this))); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueEffectPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueEffectPacket.java deleted file mode 100644 index ddbce17e02..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueEffectPacket.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class GlueEffectPacket extends SimplePacketBase { - - private BlockPos pos; - private Direction direction; - private boolean fullBlock; - - public GlueEffectPacket(BlockPos pos, Direction direction, boolean fullBlock) { - this.pos = pos; - this.direction = direction; - this.fullBlock = fullBlock; - } - - public GlueEffectPacket(FriendlyByteBuf buffer) { - pos = buffer.readBlockPos(); - direction = Direction.from3DDataValue(buffer.readByte()); - fullBlock = buffer.readBoolean(); - } - - public void write(FriendlyByteBuf buffer) { - buffer.writeBlockPos(pos); - buffer.writeByte(direction.get3DDataValue()); - buffer.writeBoolean(fullBlock); - } - - @OnlyIn(Dist.CLIENT) - public void handle(Supplier context) { - context.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - Minecraft mc = Minecraft.getInstance(); - if (!mc.player.blockPosition().closerThan(pos, 100)) - return; - SuperGlueItem.spawnParticles(mc.level, pos, direction, fullBlock); - })); - context.get().setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsRenderer.java deleted file mode 100644 index 67deebf708..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsRenderer.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; - -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class ControlsRenderer { - - public static void render(MovementContext context, VirtualRenderWorld renderWorld, ContraptionMatrices matrices, - MultiBufferSource buffer, float equipAnimation, float firstLever, float secondLever) { - BlockState state = context.state; - Direction facing = state.getValue(ControlsBlock.FACING); - - SuperByteBuffer cover = CachedPartialBuffers.partial(AllBlockPartials.TRAIN_CONTROLS_COVER, state); - float hAngle = 180 + AngleHelper.horizontalAngle(facing); - PoseStack ms = matrices.getModel(); - cover.transform(ms) - .rotateCentered(Direction.Axis.Y, Mth.DEG_TO_RAD * hAngle) - .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.cutoutMipped())); - - double yOffset = Mth.lerp(equipAnimation * equipAnimation, -0.15f, 0.05f); - - for (boolean first : Iterate.trueAndFalse) { - float vAngle = (float) Mth.clamp(first ? firstLever * 70 - 25 : secondLever * 15, -45, 45); - SuperByteBuffer lever = CachedPartialBuffers.partial(AllBlockPartials.TRAIN_CONTROLS_LEVER, state); - ms.pushPose(); - TransformStack.cast(ms) - .centre() - .rotateY(hAngle) - .translate(0, 0, 4 / 16f) - .rotateX(vAngle - 45) - .translate(0, yOffset, 0) - .rotateX(45) - .unCentre() - .translate(0, -2 / 16f, -3 / 16f) - .translate(first ? 0 : 6 / 16f, 0, 0); - lever.transform(ms) - .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) - .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); - ms.popPose(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsStopControllingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsStopControllingPacket.java deleted file mode 100644 index 088f8bb50d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsStopControllingPacket.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ControlsStopControllingPacket extends SimplePacketBase { - - public ControlsStopControllingPacket() {} - - public ControlsStopControllingPacket(FriendlyByteBuf buffer) {} - - @Override - public void write(FriendlyByteBuf buffer) {} - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(ControlsHandler::stopControlling); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/HonkPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/HonkPacket.java deleted file mode 100644 index 4dac38aa90..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/HonkPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; - -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent.Context; -import net.minecraftforge.network.PacketDistributor; - -public class HonkPacket extends SimplePacketBase { - - UUID trainId; - boolean isHonk; - - public HonkPacket() {} - - public HonkPacket(Train train, boolean isHonk) { - trainId = train.id; - this.isHonk = isHonk; - } - - public HonkPacket(FriendlyByteBuf buffer) { - trainId = buffer.readUUID(); - isHonk = buffer.readBoolean(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeUUID(trainId); - buffer.writeBoolean(isHonk); - } - - @Override - public void handle(Supplier context) { - Context c = context.get(); - c.enqueueWork(() -> { - ServerPlayer sender = c.getSender(); - boolean clientSide = sender == null; - Train train = Create.RAILWAYS.sided(clientSide ? null : sender.level).trains.get(trainId); - if (train == null) - return; - - if (clientSide) { - if (isHonk) - train.honkTicks = train.honkTicks == 0 ? 20 : 13; - else - train.honkTicks = train.honkTicks > 5 ? 6 : 0; - } else { - AllAdvancements.TRAIN_WHISTLE.awardTo(sender); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new HonkPacket(train, isHonk)); - } - - }); - c.setPacketHandled(true); - } - - public static class Serverbound extends HonkPacket { - - public Serverbound(FriendlyByteBuf buffer) { - super(buffer); - } - - public Serverbound(Train train, boolean isHonk) { - super(train, isHonk); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java deleted file mode 100644 index 8dad06ae63..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java +++ /dev/null @@ -1,326 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; - -import java.util.List; -import java.util.UUID; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; -import com.simibubi.create.content.contraptions.components.tracks.ControllerRailBlock; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.entity.vehicle.MinecartFurnace; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.RailShape; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber -public class CartAssemblerTileEntity extends SmartTileEntity implements IDisplayAssemblyExceptions { - private static final int assemblyCooldown = 8; - - protected ScrollOptionBehaviour movementMode; - private int ticksSinceMinecartUpdate; - protected AssemblyException lastException; - protected AbstractMinecart cartToAssemble; - - public CartAssemblerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - ticksSinceMinecartUpdate = assemblyCooldown; - } - - @Override - public void tick() { - super.tick(); - if (ticksSinceMinecartUpdate < assemblyCooldown) { - ticksSinceMinecartUpdate++; - } - - tryAssemble(cartToAssemble); - cartToAssemble = null; - } - - public void tryAssemble(AbstractMinecart cart) { - if (cart == null) - return; - - if (!isMinecartUpdateValid()) - return; - resetTicksSinceMinecartUpdate(); - - BlockState state = level.getBlockState(worldPosition); - if (!AllBlocks.CART_ASSEMBLER.has(state)) - return; - CartAssemblerBlock block = (CartAssemblerBlock) state.getBlock(); - - CartAssemblerBlock.CartAssemblerAction action = CartAssemblerBlock.getActionForCart(state, cart); - if (action.shouldAssemble()) - assemble(level, worldPosition, cart); - if (action.shouldDisassemble()) - disassemble(level, worldPosition, cart); - if (action == CartAssemblerBlock.CartAssemblerAction.ASSEMBLE_ACCELERATE) { - if (cart.getDeltaMovement() - .length() > 1 / 128f) { - Direction facing = cart.getMotionDirection(); - RailShape railShape = state.getValue(CartAssemblerBlock.RAIL_SHAPE); - for (Direction d : Iterate.directionsInAxis(railShape == RailShape.EAST_WEST ? Axis.X : Axis.Z)) - if (level.getBlockState(worldPosition.relative(d)) - .isRedstoneConductor(level, worldPosition.relative(d))) - facing = d.getOpposite(); - - float speed = block.getRailMaxSpeed(state, level, worldPosition, cart); - cart.setDeltaMovement(facing.getStepX() * speed, facing.getStepY() * speed, facing.getStepZ() * speed); - } - } - if (action == CartAssemblerBlock.CartAssemblerAction.ASSEMBLE_ACCELERATE_DIRECTIONAL) { - Vec3i accelerationVector = - ControllerRailBlock.getAccelerationVector(AllBlocks.CONTROLLER_RAIL.getDefaultState() - .setValue(ControllerRailBlock.SHAPE, state.getValue(CartAssemblerBlock.RAIL_SHAPE)) - .setValue(ControllerRailBlock.BACKWARDS, state.getValue(CartAssemblerBlock.BACKWARDS))); - float speed = block.getRailMaxSpeed(state, level, worldPosition, cart); - cart.setDeltaMovement(Vec3.atLowerCornerOf(accelerationVector) - .scale(speed)); - } - if (action == CartAssemblerBlock.CartAssemblerAction.DISASSEMBLE_BRAKE) { - Vec3 diff = VecHelper.getCenterOf(worldPosition) - .subtract(cart.position()); - cart.setDeltaMovement(diff.x / 16f, 0, diff.z / 16f); - } - } - - protected void assemble(Level world, BlockPos pos, AbstractMinecart cart) { - if (!cart.getPassengers() - .isEmpty()) - return; - - LazyOptional optional = - cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); - if (optional.isPresent() && optional.orElse(null) - .isCoupledThroughContraption()) - return; - - CartMovementMode mode = CartMovementMode.values()[movementMode.value]; - - MountedContraption contraption = new MountedContraption(mode); - try { - if (!contraption.assemble(world, pos)) - return; - - lastException = null; - sendData(); - } catch (AssemblyException e) { - lastException = e; - sendData(); - return; - } - - boolean couplingFound = contraption.connectedCart != null; - Direction initialOrientation = CartAssemblerBlock.getHorizontalDirection(getBlockState()); - - if (couplingFound) { - cart.setPos(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f); - if (!CouplingHandler.tryToCoupleCarts(null, world, cart.getId(), - contraption.connectedCart.getId())) - return; - } - - contraption.removeBlocksFromWorld(world, BlockPos.ZERO); - contraption.startMoving(world); - contraption.expandBoundsAroundAxis(Axis.Y); - - if (couplingFound) { - Vec3 diff = contraption.connectedCart.position() - .subtract(cart.position()); - initialOrientation = Direction.fromYRot(Mth.atan2(diff.z, diff.x) * 180 / Math.PI); - } - - OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation); - if (couplingFound) - entity.setCouplingId(cart.getUUID()); - entity.setPos(pos.getX() + .5, pos.getY(), pos.getZ() + .5); - world.addFreshEntity(entity); - entity.startRiding(cart); - - if (cart instanceof MinecartFurnace) { - CompoundTag nbt = cart.serializeNBT(); - nbt.putDouble("PushZ", 0); - nbt.putDouble("PushX", 0); - cart.deserializeNBT(nbt); - } - - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - } - - protected void disassemble(Level world, BlockPos pos, AbstractMinecart cart) { - if (cart.getPassengers() - .isEmpty()) - return; - Entity entity = cart.getPassengers() - .get(0); - if (!(entity instanceof OrientedContraptionEntity)) - return; - OrientedContraptionEntity contraption = (OrientedContraptionEntity) entity; - UUID couplingId = contraption.getCouplingId(); - - if (couplingId == null) { - contraption.yaw = CartAssemblerBlock.getHorizontalDirection(getBlockState()) - .toYRot(); - disassembleCart(cart); - return; - } - - Couple coupledCarts = contraption.getCoupledCartsIfPresent(); - if (coupledCarts == null) - return; - - // Make sure connected cart is present and being disassembled - for (boolean current : Iterate.trueAndFalse) { - MinecartController minecartController = coupledCarts.get(current); - if (minecartController.cart() == cart) - continue; - BlockPos otherPos = minecartController.cart() - .blockPosition(); - BlockState blockState = world.getBlockState(otherPos); - if (!AllBlocks.CART_ASSEMBLER.has(blockState)) - return; - if (!CartAssemblerBlock.getActionForCart(blockState, minecartController.cart()) - .shouldDisassemble()) - return; - } - - for (boolean current : Iterate.trueAndFalse) - coupledCarts.get(current) - .removeConnection(current); - disassembleCart(cart); - } - - protected void disassembleCart(AbstractMinecart cart) { - cart.ejectPassengers(); - if (cart instanceof MinecartFurnace) { - CompoundTag nbt = cart.serializeNBT(); - nbt.putDouble("PushZ", cart.getDeltaMovement().x); - nbt.putDouble("PushX", cart.getDeltaMovement().z); - cart.deserializeNBT(nbt); - } - } - - @Override - public void addBehaviours(List behaviours) { - movementMode = new ScrollOptionBehaviour<>(CartMovementMode.class, - CreateLang.translateDirect("contraptions.cart_movement_mode"), this, getMovementModeSlot()); - movementMode.requiresWrench(); - behaviours.add(movementMode); - registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - AssemblyException.write(compound, lastException); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - lastException = AssemblyException.read(compound); - super.read(compound, clientPacket); - } - - @Override - public AssemblyException getLastAssemblyException() { - return lastException; - } - - protected ValueBoxTransform getMovementModeSlot() { - return new CartAssemblerValueBoxTransform(); - } - - private class CartAssemblerValueBoxTransform extends CenteredSideValueBoxTransform { - - public CartAssemblerValueBoxTransform() { - super((state, d) -> { - if (d.getAxis() - .isVertical()) - return false; - if (!state.hasProperty(CartAssemblerBlock.RAIL_SHAPE)) - return false; - RailShape railShape = state.getValue(CartAssemblerBlock.RAIL_SHAPE); - return (d.getAxis() == Axis.X) == (railShape == RailShape.NORTH_SOUTH); - }); - } - - @Override - protected Vec3 getSouthLocation() { - return VecHelper.voxelSpace(8, 8, 18); - } - - } - - public enum CartMovementMode implements INamedIconOptions { - - ROTATE(AllIcons.I_CART_ROTATE), - ROTATE_PAUSED(AllIcons.I_CART_ROTATE_PAUSED), - ROTATION_LOCKED(AllIcons.I_CART_ROTATE_LOCKED), - - ; - - private String translationKey; - private AllIcons icon; - - CartMovementMode(AllIcons icon) { - this.icon = icon; - translationKey = "contraptions.cart_movement_mode." + Lang.asId(name()); - } - - @Override - public AllIcons getIcon() { - return icon; - } - - @Override - public String getTranslationKey() { - return translationKey; - } - } - - public void resetTicksSinceMinecartUpdate() { - ticksSinceMinecartUpdate = 0; - } - - public void assembleNextTick(AbstractMinecart cart) { - if (cartToAssemble == null) - cartToAssemble = cart; - } - - public boolean isMinecartUpdateValid() { - return ticksSinceMinecartUpdate >= assemblyCooldown; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java deleted file mode 100644 index fce8b9cceb..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java +++ /dev/null @@ -1,344 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public abstract class LinearActuatorTileEntity extends KineticTileEntity - implements IControlContraption, IDisplayAssemblyExceptions { - - public float offset; - public boolean running; - public boolean assembleNextTick; - public boolean needsContraption; - public AbstractContraptionEntity movedContraption; - protected boolean forceMove; - protected ScrollOptionBehaviour movementMode; - protected boolean waitingForSpeedChange; - protected AssemblyException lastException; - - // Custom position sync - protected float clientOffsetDiff; - - public LinearActuatorTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - setLazyTickRate(3); - forceMove = true; - needsContraption = true; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - movementMode = new ScrollOptionBehaviour<>(MovementMode.class, CreateLang.translateDirect("contraptions.movement_mode"), - this, getMovementModeSlot()); - movementMode.requiresWrench(); - movementMode.withCallback(t -> waitingForSpeedChange = false); - behaviours.add(movementMode); - registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); - } - - @Override - public void tick() { - super.tick(); - - if (movedContraption != null) { - if (!movedContraption.isAlive()) - movedContraption = null; - } - - if (level.isClientSide) - clientOffsetDiff *= .75f; - - if (waitingForSpeedChange) { - if (movedContraption != null) { - if (level.isClientSide) { - float syncSpeed = clientOffsetDiff / 2f; - offset += syncSpeed; - movedContraption.setContraptionMotion(toMotionVector(syncSpeed)); - return; - } - movedContraption.setContraptionMotion(Vec3.ZERO); - } - return; - } - - if (!level.isClientSide && assembleNextTick) { - assembleNextTick = false; - if (running) { - if (getSpeed() == 0) - tryDisassemble(); - else - sendData(); - return; - } else { - if (getSpeed() != 0) - try { - assemble(); - lastException = null; - } catch (AssemblyException e) { - lastException = e; - } - sendData(); - } - return; - } - - if (!running) - return; - - boolean contraptionPresent = movedContraption != null; - if (needsContraption && !contraptionPresent) - return; - - float movementSpeed = getMovementSpeed(); - float newOffset = offset + movementSpeed; - if ((int) newOffset != (int) offset) - visitNewPosition(); - - if (contraptionPresent) { - if (moveAndCollideContraption()) { - movedContraption.setContraptionMotion(Vec3.ZERO); - offset = getGridOffset(offset); - resetContraptionToOffset(); - collided(); - return; - } - } - - if (!contraptionPresent || !movedContraption.isStalled()) - offset = newOffset; - - int extensionRange = getExtensionRange(); - if (offset <= 0 || offset >= extensionRange) { - offset = offset <= 0 ? 0 : extensionRange; - if (!level.isClientSide) { - moveAndCollideContraption(); - resetContraptionToOffset(); - tryDisassemble(); - if (waitingForSpeedChange) { - forceMove = true; - sendData(); - } - } - return; - } - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (movedContraption != null && !level.isClientSide) - sendData(); - } - - protected int getGridOffset(float offset) { - return Mth.clamp((int) (offset + .5f), 0, getExtensionRange()); - } - - public float getInterpolatedOffset(float partialTicks) { - float interpolatedOffset = - Mth.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, getExtensionRange()); - return interpolatedOffset; - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - assembleNextTick = true; - waitingForSpeedChange = false; - - if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { - movedContraption.getContraption() - .stop(level); - } - } - - @Override - public void setRemoved() { - super.setRemoved(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - this.remove = true; - if (!level.isClientSide) - disassemble(); - super.setRemovedNotDueToChunkUnload(); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Running", running); - compound.putBoolean("Waiting", waitingForSpeedChange); - compound.putFloat("Offset", offset); - AssemblyException.write(compound, lastException); - super.write(compound, clientPacket); - - if (clientPacket && forceMove) { - compound.putBoolean("ForceMovement", forceMove); - forceMove = false; - } - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - boolean forceMovement = compound.contains("ForceMovement"); - float offsetBefore = offset; - - running = compound.getBoolean("Running"); - waitingForSpeedChange = compound.getBoolean("Waiting"); - offset = compound.getFloat("Offset"); - lastException = AssemblyException.read(compound); - super.read(compound, clientPacket); - - if (!clientPacket) - return; - if (forceMovement) - resetContraptionToOffset(); - else if (running) { - clientOffsetDiff = offset - offsetBefore; - offset = offsetBefore; - } - if (!running) - movedContraption = null; - } - - @Override - public AssemblyException getLastAssemblyException() { - return lastException; - } - - public abstract void disassemble(); - - protected abstract void assemble() throws AssemblyException; - - protected abstract int getExtensionRange(); - - protected abstract int getInitialOffset(); - - protected abstract ValueBoxTransform getMovementModeSlot(); - - protected abstract Vec3 toMotionVector(float speed); - - protected abstract Vec3 toPosition(float offset); - - protected void visitNewPosition() {} - - protected void tryDisassemble() { - if (remove) { - disassemble(); - return; - } - if (movementMode.get() == MovementMode.MOVE_NEVER_PLACE) { - waitingForSpeedChange = true; - return; - } - int initial = getInitialOffset(); - if ((int) (offset + .5f) != initial && movementMode.get() == MovementMode.MOVE_PLACE_RETURNED) { - waitingForSpeedChange = true; - return; - } - disassemble(); - } - - protected boolean moveAndCollideContraption() { - if (movedContraption == null) - return false; - if (movedContraption.isStalled()) { - movedContraption.setContraptionMotion(Vec3.ZERO); - return false; - } - - Vec3 motion = getMotionVector(); - movedContraption.setContraptionMotion(getMotionVector()); - movedContraption.move(motion.x, motion.y, motion.z); - return ContraptionCollider.collideBlocks(movedContraption); - } - - protected void collided() { - if (level.isClientSide) { - waitingForSpeedChange = true; - return; - } - offset = getGridOffset(offset - getMovementSpeed()); - resetContraptionToOffset(); - tryDisassemble(); - } - - protected void resetContraptionToOffset() { - if (movedContraption == null) - return; - Vec3 vec = toPosition(offset); - movedContraption.setPos(vec.x, vec.y, vec.z); - if (getSpeed() == 0 || waitingForSpeedChange) - movedContraption.setContraptionMotion(Vec3.ZERO); - } - - public float getMovementSpeed() { - float movementSpeed = Mth.clamp(convertToLinear(getSpeed()), -.49f, .49f) + clientOffsetDiff / 2f; - if (level.isClientSide) - movementSpeed *= ServerSpeedProvider.get(); - return movementSpeed; - } - - public Vec3 getMotionVector() { - return toMotionVector(getMovementSpeed()); - } - - @Override - public void onStall() { - if (!level.isClientSide) { - forceMove = true; - sendData(); - } - } - - public void onLengthBroken() { - offset = 0; - sendData(); - } - - @Override - public boolean isValid() { - return !isRemoved(); - } - - @Override - public void attach(ControlledContraptionEntity contraption) { - this.movedContraption = contraption; - if (!level.isClientSide) { - this.running = true; - sendData(); - } - } - - @Override - public boolean isAttachedTo(AbstractContraptionEntity contraption) { - return movedContraption == contraption; - } - - @Override - public BlockPos getBlockPosition() { - return worldPosition; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonRenderer.java deleted file mode 100644 index 65c327ccbd..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonRenderer.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; - -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class MechanicalPistonRenderer extends KineticTileEntityRenderer { - - public MechanicalPistonRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java deleted file mode 100644 index 0492ee77cc..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.Vec3; - -public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { - - protected boolean hadCollisionWithOtherPiston; - protected int extensionLength; - - public MechanicalPistonTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - extensionLength = compound.getInt("ExtensionLength"); - super.read(compound, clientPacket); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - tag.putInt("ExtensionLength", extensionLength); - super.write(tag, clientPacket); - } - - @Override - public void assemble() throws AssemblyException { - if (!(level.getBlockState(worldPosition) - .getBlock() instanceof MechanicalPistonBlock)) - return; - - Direction direction = getBlockState().getValue(BlockStateProperties.FACING); - - // Collect Construct - PistonContraption contraption = new PistonContraption(direction, getMovementSpeed() < 0); - if (!contraption.assemble(level, worldPosition)) - return; - - Direction positive = Direction.get(AxisDirection.POSITIVE, direction.getAxis()); - Direction movementDirection = - getSpeed() > 0 ^ direction.getAxis() != Axis.Z ? positive : positive.getOpposite(); - - BlockPos anchor = contraption.anchor.relative(direction, contraption.initialExtensionProgress); - if (ContraptionCollider.isCollidingWithWorld(level, contraption, anchor.relative(movementDirection), - movementDirection)) - return; - - // Check if not at limit already - extensionLength = contraption.extensionLength; - float resultingOffset = contraption.initialExtensionProgress + Math.signum(getMovementSpeed()) * .5f; - if (resultingOffset <= 0 || resultingOffset >= extensionLength) { - return; - } - - // Run - running = true; - offset = contraption.initialExtensionProgress; - sendData(); - clientOffsetDiff = 0; - - BlockPos startPos = BlockPos.ZERO.relative(direction, contraption.initialExtensionProgress); - contraption.removeBlocksFromWorld(level, startPos); - movedContraption = ControlledContraptionEntity.create(getLevel(), this, contraption); - resetContraptionToOffset(); - forceMove = true; - level.addFreshEntity(movedContraption); - - AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); - - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - } - - @Override - public void disassemble() { - if (!running && movedContraption == null) - return; - if (!remove) - getLevel().setBlock(worldPosition, getBlockState().setValue(MechanicalPistonBlock.STATE, PistonState.EXTENDED), - 3 | 16); - if (movedContraption != null) { - resetContraptionToOffset(); - movedContraption.disassemble(); - AllSoundEvents.CONTRAPTION_DISASSEMBLE.playOnServer(level, worldPosition); - } - running = false; - movedContraption = null; - sendData(); - - if (remove) - AllBlocks.MECHANICAL_PISTON.get() - .playerWillDestroy(level, worldPosition, getBlockState(), null); - } - - @Override - protected void collided() { - super.collided(); - if (!running && getMovementSpeed() > 0) - assembleNextTick = true; - } - - @Override - public float getMovementSpeed() { - float movementSpeed = Mth.clamp(convertToLinear(getSpeed()), -.49f, .49f); - if (level.isClientSide) - movementSpeed *= ServerSpeedProvider.get(); - Direction pistonDirection = getBlockState().getValue(BlockStateProperties.FACING); - int movementModifier = pistonDirection.getAxisDirection() - .getStep() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1); - movementSpeed = movementSpeed * -movementModifier + clientOffsetDiff / 2f; - - int extensionRange = getExtensionRange(); - movementSpeed = Mth.clamp(movementSpeed, 0 - offset, extensionRange - offset); - return movementSpeed; - } - - @Override - protected int getExtensionRange() { - return extensionLength; - } - - @Override - protected void visitNewPosition() {} - - @Override - protected Vec3 toMotionVector(float speed) { - Direction pistonDirection = getBlockState().getValue(BlockStateProperties.FACING); - return Vec3.atLowerCornerOf(pistonDirection.getNormal()) - .scale(speed); - } - - @Override - protected Vec3 toPosition(float offset) { - Vec3 position = Vec3.atLowerCornerOf(getBlockState().getValue(BlockStateProperties.FACING) - .getNormal()) - .scale(offset); - return position.add(Vec3.atLowerCornerOf(movedContraption.getContraption().anchor)); - } - - @Override - protected ValueBoxTransform getMovementModeSlot() { - return new DirectionalExtenderScrollOptionSlot((state, d) -> { - Axis axis = d.getAxis(); - Axis extensionAxis = state.getValue(MechanicalPistonBlock.FACING) - .getAxis(); - Axis shaftAxis = ((IRotate) state.getBlock()).getRotationAxis(state); - return extensionAxis != axis && shaftAxis != axis; - }); - } - - @Override - protected int getInitialOffset() { - return movedContraption == null ? 0 - : ((PistonContraption) movedContraption.getContraption()).initialExtensionProgress; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java deleted file mode 100644 index 52eaaa7294..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyRenderer.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class AbstractPulleyRenderer extends KineticTileEntityRenderer { - - private PartialModel halfRope; - private PartialModel halfMagnet; - - public AbstractPulleyRenderer(BlockEntityRendererProvider.Context context, PartialModel halfRope, - PartialModel halfMagnet) { - super(context); - this.halfRope = halfRope; - this.halfMagnet = halfMagnet; - } - - @Override - public boolean shouldRenderOffScreen(KineticTileEntity p_188185_1_) { - return true; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) - return; - - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - float offset = getOffset(te, partialTicks); - boolean running = isRunning(te); - - Axis rotationAxis = ((IRotate) te.getBlockState() - .getBlock()).getRotationAxis(te.getBlockState()); - kineticRotationTransform(getRotatedCoil(te), te, rotationAxis, AngleHelper.rad(offset * 180), light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - - Level world = te.getLevel(); - BlockState blockState = te.getBlockState(); - BlockPos pos = te.getBlockPos(); - - SuperByteBuffer halfMagnet = CachedPartialBuffers.partial(this.halfMagnet, blockState); - SuperByteBuffer halfRope = CachedPartialBuffers.partial(this.halfRope, blockState); - SuperByteBuffer magnet = renderMagnet(te); - SuperByteBuffer rope = renderRope(te); - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - if (running || offset == 0) - renderAt(world, offset > .25f ? magnet : halfMagnet, offset, pos, ms, vb); - - float f = offset % 1; - if (offset > .75f && (f < .25f || f > .75f)) - renderAt(world, halfRope, f > .75f ? f - 1 : f, pos, ms, vb); - - if (!running) - return; - - for (int i = 0; i < offset - 1.25f; i++) - renderAt(world, rope, offset - i - 1, pos, ms, vb); - } - - private void renderAt(LevelAccessor world, SuperByteBuffer partial, float offset, BlockPos pulleyPos, PoseStack ms, - VertexConsumer buffer) { - BlockPos actualPos = pulleyPos.below((int) offset); - int light = LevelRenderer.getLightColor(world, world.getBlockState(actualPos), actualPos); - partial.translate(0, -offset, 0) - .light(light) - .renderInto(ms, buffer); - } - - protected abstract Axis getShaftAxis(KineticTileEntity te); - - protected abstract PartialModel getCoil(); - - protected abstract SuperByteBuffer renderRope(KineticTileEntity te); - - protected abstract SuperByteBuffer renderMagnet(KineticTileEntity te); - - protected abstract float getOffset(KineticTileEntity te, float partialTicks); - - protected abstract boolean isRunning(KineticTileEntity te); - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getShaftAxis(te)); - } - - protected SuperByteBuffer getRotatedCoil(KineticTileEntity te) { - BlockState blockState = te.getBlockState(); - return CachedPartialBuffers.partialFacing(getCoil(), blockState, - Direction.get(AxisDirection.POSITIVE, getShaftAxis(te))); - } - - @Override - public int getViewDistance() { - return 256; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/HosePulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/HosePulleyInstance.java deleted file mode 100644 index 607b7ee6d6..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/HosePulleyInstance.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyTileEntity; - -import net.createmod.catnip.utility.AnimationTickHolder; - -public class HosePulleyInstance extends AbstractPulleyInstance { - - public HosePulleyInstance(MaterialManager dispatcher, HosePulleyTileEntity tile) { - super(dispatcher, tile); - } - - protected Instancer getRopeModel() { - return getOrientedMaterial().getModel(AllBlockPartials.HOSE, blockState); - } - - protected Instancer getMagnetModel() { - return materialManager.defaultCutout() - .material(Materials.ORIENTED) - .getModel(AllBlockPartials.HOSE_MAGNET, blockState); - } - - protected Instancer getHalfMagnetModel() { - return materialManager.defaultCutout() - .material(Materials.ORIENTED) - .getModel(AllBlockPartials.HOSE_HALF_MAGNET, blockState); - } - - protected Instancer getCoilModel() { - return getOrientedMaterial().getModel(AllBlockPartials.HOSE_COIL, blockState, rotatingAbout); - } - - protected Instancer getHalfRopeModel() { - return getOrientedMaterial().getModel(AllBlockPartials.HOSE_HALF, blockState); - } - - protected float getOffset() { - return ((HosePulleyTileEntity) blockEntity).getInterpolatedOffset(AnimationTickHolder.getPartialTicks()); - } - - protected boolean isRunning() { - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java deleted file mode 100644 index ee53dfc949..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class PulleyContraption extends TranslatingContraption { - - int initialOffset; - - @Override - protected ContraptionType getType() { - return ContraptionType.PULLEY; - } - - public PulleyContraption() {} - - public PulleyContraption(int initialOffset) { - this.initialOffset = initialOffset; - } - - @Override - public boolean assemble(Level world, BlockPos pos) throws AssemblyException { - if (!searchMovedStructure(world, pos, null)) - return false; - startMoving(world); - return true; - } - - @Override - protected boolean isAnchoringBlockAt(BlockPos pos) { - if (pos.getX() != anchor.getX() || pos.getZ() != anchor.getZ()) - return false; - int y = pos.getY(); - if (y <= anchor.getY() || y > anchor.getY() + initialOffset + 1) - return false; - return true; - } - - @Override - public CompoundTag writeNBT(boolean spawnPacket) { - CompoundTag tag = super.writeNBT(spawnPacket); - tag.putInt("InitialOffset", initialOffset); - return tag; - } - - @Override - public void readNBT(Level world, CompoundTag nbt, boolean spawnData) { - initialOffset = nbt.getInt("InitialOffset"); - super.readNBT(world, nbt, spawnData); - } - - @Override - @OnlyIn(Dist.CLIENT) - public ContraptionLighter makeLighter() { - return new PulleyLighter(this); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java deleted file mode 100644 index 0948d02278..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; - -public class PulleyRenderer extends AbstractPulleyRenderer { - - public PulleyRenderer(BlockEntityRendererProvider.Context context) { - super(context, AllBlockPartials.ROPE_HALF, AllBlockPartials.ROPE_HALF_MAGNET); - } - - @Override - protected Axis getShaftAxis(KineticTileEntity te) { - return te.getBlockState() - .getValue(PulleyBlock.HORIZONTAL_AXIS); - } - - @Override - protected PartialModel getCoil() { - return AllBlockPartials.ROPE_COIL; - } - - @Override - protected SuperByteBuffer renderRope(KineticTileEntity te) { - return CachedBlockBuffers.block(AllBlocks.ROPE.getDefaultState()); - } - - @Override - protected SuperByteBuffer renderMagnet(KineticTileEntity te) { - return CachedBlockBuffers.block(AllBlocks.PULLEY_MAGNET.getDefaultState()); - } - - @Override - protected float getOffset(KineticTileEntity te, float partialTicks) { - PulleyTileEntity pulley = (PulleyTileEntity) te; - return getTileOffset(partialTicks, pulley); - } - - @Override - protected boolean isRunning(KineticTileEntity te) { - return ((PulleyTileEntity) te).running || te.isVirtual(); - } - - - static float getTileOffset(float partialTicks, PulleyTileEntity tile) { - float offset = tile.getInterpolatedOffset(partialTicks); - - if (tile.movedContraption != null) { - AbstractContraptionEntity e = tile.movedContraption; - PulleyContraption c = (PulleyContraption) tile.movedContraption.getContraption(); - double entityPos = Mth.lerp(partialTicks, e.yOld, e.getY()); - offset = (float) -(entityPos - c.anchor.getY() - c.initialOffset); - } - - return offset; - } - - @Override - public int getViewDistance() { - return 128; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java deleted file mode 100644 index a71661c893..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.LinearActuatorTileEntity; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchObservable; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SimpleWaterloggedBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class PulleyTileEntity extends LinearActuatorTileEntity implements StockpileSwitchObservable { - - protected int initialOffset; - private float prevAnimatedOffset; - - public PulleyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().expandTowards(0, -offset, 0); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.PULLEY_MAXED); - } - - @Override - public void tick() { - float prevOffset = offset; - super.tick(); - if (isVirtual()) - prevAnimatedOffset = offset; - invalidateRenderBoundingBox(); - - if (prevOffset < 200 && offset >= 200) - award(AllAdvancements.PULLEY_MAXED); - } - - @Override - protected void assemble() throws AssemblyException { - if (!(level.getBlockState(worldPosition) - .getBlock() instanceof PulleyBlock)) - return; - if (speed == 0) - return; - int maxLength = AllConfigs.SERVER.kinetics.maxRopeLength.get(); - int i = 1; - while (i <= maxLength) { - BlockPos ropePos = worldPosition.below(i); - BlockState ropeState = level.getBlockState(ropePos); - if (!AllBlocks.ROPE.has(ropeState) && !AllBlocks.PULLEY_MAGNET.has(ropeState)) { - break; - } - ++i; - } - offset = i - 1; - if (offset >= getExtensionRange() && getSpeed() > 0) - return; - if (offset <= 0 && getSpeed() < 0) - return; - - // Collect Construct - if (!level.isClientSide) { - needsContraption = false; - BlockPos anchor = worldPosition.below(Mth.floor(offset + 1)); - initialOffset = Mth.floor(offset); - PulleyContraption contraption = new PulleyContraption(initialOffset); - boolean canAssembleStructure = contraption.assemble(level, anchor); - - if (canAssembleStructure) { - Direction movementDirection = getSpeed() > 0 ? Direction.DOWN : Direction.UP; - if (ContraptionCollider.isCollidingWithWorld(level, contraption, anchor.relative(movementDirection), - movementDirection)) - canAssembleStructure = false; - } - - if (!canAssembleStructure && getSpeed() > 0) - return; - - for (i = ((int) offset); i > 0; i--) { - BlockPos offset = worldPosition.below(i); - BlockState oldState = level.getBlockState(offset); - if (oldState.getBlock() instanceof SimpleWaterloggedBlock - && oldState.hasProperty(BlockStateProperties.WATERLOGGED) - && oldState.getValue(BlockStateProperties.WATERLOGGED)) { - level.setBlock(offset, Blocks.WATER.defaultBlockState(), 66); - continue; - } - level.setBlock(offset, Blocks.AIR.defaultBlockState(), 66); - } - - if (!contraption.getBlocks() - .isEmpty()) { - contraption.removeBlocksFromWorld(level, BlockPos.ZERO); - movedContraption = ControlledContraptionEntity.create(level, this, contraption); - movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); - level.addFreshEntity(movedContraption); - forceMove = true; - needsContraption = true; - - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - } - } - - clientOffsetDiff = 0; - running = true; - sendData(); - } - - @Override - public void disassemble() { - if (!running && movedContraption == null) - return; - offset = getGridOffset(offset); - if (movedContraption != null) - resetContraptionToOffset(); - - if (!level.isClientSide) { - if (!remove) { - if (offset > 0) { - BlockPos magnetPos = worldPosition.below((int) offset); - FluidState ifluidstate = level.getFluidState(magnetPos); - level.destroyBlock(magnetPos, level.getBlockState(magnetPos) - .getCollisionShape(level, magnetPos) - .isEmpty()); - level.setBlock(magnetPos, AllBlocks.PULLEY_MAGNET.getDefaultState() - .setValue(BlockStateProperties.WATERLOGGED, - Boolean.valueOf(ifluidstate.getType() == Fluids.WATER)), - 66); - } - - boolean[] waterlog = new boolean[(int) offset]; - - for (int i = 1; i <= ((int) offset) - 1; i++) { - BlockPos ropePos = worldPosition.below(i); - FluidState ifluidstate = level.getFluidState(ropePos); - waterlog[i] = ifluidstate.getType() == Fluids.WATER; - level.destroyBlock(ropePos, level.getBlockState(ropePos) - .getCollisionShape(level, ropePos) - .isEmpty()); - } - for (int i = 1; i <= ((int) offset) - 1; i++) - level.setBlock(worldPosition.below(i), AllBlocks.ROPE.getDefaultState() - .setValue(BlockStateProperties.WATERLOGGED, waterlog[i]), 66); - } - - if (movedContraption != null) - movedContraption.disassemble(); - } - - if (movedContraption != null) - movedContraption.discard(); - movedContraption = null; - initialOffset = 0; - running = false; - sendData(); - } - - @Override - protected Vec3 toPosition(float offset) { - if (movedContraption.getContraption() instanceof PulleyContraption) { - PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption(); - return Vec3.atLowerCornerOf(contraption.anchor) - .add(0, contraption.initialOffset - offset, 0); - - } - return Vec3.ZERO; - } - - @Override - protected void visitNewPosition() { - super.visitNewPosition(); - if (level.isClientSide) - return; - if (movedContraption != null) - return; - if (getSpeed() <= 0) - return; - - BlockPos posBelow = worldPosition.below((int) (offset + getMovementSpeed()) + 1); - BlockState state = level.getBlockState(posBelow); - if (!BlockMovementChecks.isMovementNecessary(state, level, posBelow)) - return; - if (BlockMovementChecks.isBrittle(state)) - return; - - disassemble(); - assembleNextTick = true; - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - initialOffset = compound.getInt("InitialOffset"); - needsContraption = compound.getBoolean("NeedsContraption"); - super.read(compound, clientPacket); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("InitialOffset", initialOffset); - super.write(compound, clientPacket); - } - - @Override - protected int getExtensionRange() { - return Math.max(0, Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), - (worldPosition.getY() - 1) - level.getMinBuildHeight())); - } - - @Override - protected int getInitialOffset() { - return initialOffset; - } - - @Override - protected Vec3 toMotionVector(float speed) { - return new Vec3(0, -speed, 0); - } - - @Override - protected ValueBoxTransform getMovementModeSlot() { - return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); - } - - @Override - public float getInterpolatedOffset(float partialTicks) { - if (isVirtual()) - return Mth.lerp(partialTicks, prevAnimatedOffset, offset); - boolean moving = running && (movedContraption == null || !movedContraption.isStalled()); - return super.getInterpolatedOffset(moving ? partialTicks : 0.5f); - } - - public void animateOffset(float forcedOffset) { - offset = forcedOffset; - } - - @Override - public float getPercent() { - int distance = worldPosition.getY() - level.getMinBuildHeight(); - if (distance <= 0) - return 100; - return 100 * getInterpolatedOffset(.5f) / distance; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/RopePulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/RopePulleyInstance.java deleted file mode 100644 index 95e5efcc89..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/RopePulleyInstance.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; - - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.materials.oriented.OrientedData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; - -import net.createmod.catnip.utility.AnimationTickHolder; - -public class RopePulleyInstance extends AbstractPulleyInstance { - public RopePulleyInstance(MaterialManager dispatcher, PulleyTileEntity tile) { - super(dispatcher, tile); - } - - protected Instancer getRopeModel() { - return getOrientedMaterial().getModel(AllBlocks.ROPE.getDefaultState()); - } - - protected Instancer getMagnetModel() { - return getOrientedMaterial().getModel(AllBlocks.PULLEY_MAGNET.getDefaultState()); - } - - protected Instancer getHalfMagnetModel() { - return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF_MAGNET, blockState); - } - - protected Instancer getCoilModel() { - return getOrientedMaterial().getModel(AllBlockPartials.ROPE_COIL, blockState, rotatingAbout); - } - - protected Instancer getHalfRopeModel() { - return getOrientedMaterial().getModel(AllBlockPartials.ROPE_HALF, blockState); - } - - protected float getOffset() { - float partialTicks = AnimationTickHolder.getPartialTicks(); - return PulleyRenderer.getTileOffset(partialTicks, (PulleyTileEntity) blockEntity); - } - - protected boolean isRunning() { - return ((PulleyTileEntity) blockEntity).running || blockEntity.isVirtual(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/EmptyLighter.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/EmptyLighter.java deleted file mode 100644 index c223dea3b7..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/EmptyLighter.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -import com.jozufozu.flywheel.util.box.GridAlignedBB; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; - -// so other contraptions don't crash before they have a lighter -public class EmptyLighter extends ContraptionLighter { - public EmptyLighter(Contraption contraption) { - super(contraption); - } - - @Override - public GridAlignedBB getContraptionBounds() { - return new GridAlignedBB(0, 0, 0, 1, 1, 1); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java deleted file mode 100644 index 3fe3181e18..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/SBBContraptionManager.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.jozufozu.flywheel.event.RenderLayerEvent; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.render.SuperByteBufferCache; -import net.createmod.catnip.utility.Pair; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.world.level.LevelAccessor; - -public class SBBContraptionManager extends ContraptionRenderingWorld { - public static final SuperByteBufferCache.Compartment> CONTRAPTION = new SuperByteBufferCache.Compartment<>(); - - public SBBContraptionManager(LevelAccessor world) { - super(world); - } - - @Override - public void renderLayer(RenderLayerEvent event) { - super.renderLayer(event); - RenderType type = event.getType(); - VertexConsumer consumer = event.buffers.bufferSource() - .getBuffer(type); - visible.forEach(info -> renderContraptionLayerSBB(info, type, consumer)); - - event.buffers.bufferSource().endBatch(type); - } - - @Override - public boolean invalidate(Contraption contraption) { - for (RenderType chunkBufferLayer : RenderType.chunkBufferLayers()) { - SuperByteBufferCache.getInstance().invalidate(CONTRAPTION, Pair.of(contraption, chunkBufferLayer)); - } - return super.invalidate(contraption); - } - - @Override - protected ContraptionRenderInfo create(Contraption c) { - VirtualRenderWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); - return new ContraptionRenderInfo(c, renderWorld); - } - - private void renderContraptionLayerSBB(ContraptionRenderInfo renderInfo, RenderType layer, VertexConsumer consumer) { - if (!renderInfo.isVisible()) return; - - SuperByteBuffer superBuffer = SuperByteBufferCache.getInstance().get(CONTRAPTION, Pair.of(renderInfo.contraption, layer), () -> ContraptionRenderDispatcher.buildStructureBuffer(renderInfo.renderWorld, renderInfo.contraption, layer)); - - if (superBuffer.isEmpty()) - return; - - ContraptionMatrices matrices = renderInfo.getMatrices(); - - superBuffer.transform(matrices.getModel()) - .light(matrices.getWorld()) - .hybridLight() - .renderInto(matrices.getViewProjection(), consumer); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/package-info.java deleted file mode 100644 index 08edd5958e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.simibubi.create.content.contraptions.components.structureMovement.render; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java deleted file mode 100644 index d8db6597da..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ClientMotionPacket.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.sync; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkEvent.Context; -import net.minecraftforge.network.PacketDistributor; - -public class ClientMotionPacket extends SimplePacketBase { - - private Vec3 motion; - private boolean onGround; - private float limbSwing; - - public ClientMotionPacket(Vec3 motion, boolean onGround, float limbSwing) { - this.motion = motion; - this.onGround = onGround; - this.limbSwing = limbSwing; - } - - public ClientMotionPacket(FriendlyByteBuf buffer) { - motion = new Vec3(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); - onGround = buffer.readBoolean(); - limbSwing = buffer.readFloat(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeFloat((float) motion.x); - buffer.writeFloat((float) motion.y); - buffer.writeFloat((float) motion.z); - buffer.writeBoolean(onGround); - buffer.writeFloat(limbSwing); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer sender = context.get() - .getSender(); - if (sender == null) - return; - sender.setDeltaMovement(motion); - sender.setOnGround(onGround); - if (onGround) { - sender.causeFallDamage(sender.fallDistance, 1, DamageSource.FALL); - sender.fallDistance = 0; - sender.connection.aboveGroundTickCount = 0; - } - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> sender), - new LimbSwingUpdatePacket(sender.getId(), sender.position(), limbSwing)); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java deleted file mode 100644 index 5624adc33a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionFluidPacket.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.sync; - -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionFluidPacket extends SimplePacketBase { - - private int entityId; - private BlockPos localPos; - private FluidStack containedFluid; - - public ContraptionFluidPacket(int entityId, BlockPos localPos, FluidStack containedFluid) { - this.entityId = entityId; - this.localPos = localPos; - this.containedFluid = containedFluid; - } - - public ContraptionFluidPacket(FriendlyByteBuf buffer) { - entityId = buffer.readInt(); - localPos = buffer.readBlockPos(); - containedFluid = FluidStack.readFromPacket(buffer); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityId); - buffer.writeBlockPos(localPos); - containedFluid.writeToPacket(buffer); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - Entity entityByID = Minecraft.getInstance().level.getEntity(entityId); - if (!(entityByID instanceof AbstractContraptionEntity)) - return; - AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; - contraptionEntity.getContraption().handleContraptionFluidPacket(localPos, containedFluid); - }); - context.get() - .setPacketHandled(true); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java deleted file mode 100644 index ad63b3b73e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.sync; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ContraptionSeatMappingPacket extends SimplePacketBase { - - private Map mapping; - private int entityID; - private int dismountedID; - - public ContraptionSeatMappingPacket(int entityID, Map mapping) { - this(entityID, mapping, -1); - } - - public ContraptionSeatMappingPacket(int entityID, Map mapping, int dismountedID) { - this.entityID = entityID; - this.mapping = mapping; - this.dismountedID = dismountedID; - } - - public ContraptionSeatMappingPacket(FriendlyByteBuf buffer) { - entityID = buffer.readInt(); - dismountedID = buffer.readInt(); - mapping = new HashMap<>(); - short size = buffer.readShort(); - for (int i = 0; i < size; i++) - mapping.put(buffer.readUUID(), (int) buffer.readShort()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityID); - buffer.writeInt(dismountedID); - buffer.writeShort(mapping.size()); - mapping.forEach((k, v) -> { - buffer.writeUUID(k); - buffer.writeShort(v); - }); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - Entity entityByID = Minecraft.getInstance().level.getEntity(entityID); - if (!(entityByID instanceof AbstractContraptionEntity)) - return; - AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; - - if (dismountedID != -1) { - Entity dismountedByID = Minecraft.getInstance().level.getEntity(dismountedID); - if (Minecraft.getInstance().player != dismountedByID) - return; - Vec3 transformedVector = contraptionEntity.getPassengerPosition(dismountedByID, 1); - if (transformedVector != null) - dismountedByID.getPersistentData() - .put("ContraptionDismountLocation", VecHelper.writeNBT(transformedVector)); - } - - contraptionEntity.getContraption() - .setSeatMapping(mapping); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java deleted file mode 100644 index 38fc0f776b..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/LimbSwingUpdatePacket.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.sync; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkEvent.Context; - -public class LimbSwingUpdatePacket extends SimplePacketBase { - - private int entityId; - private Vec3 position; - private float limbSwing; - - public LimbSwingUpdatePacket(int entityId, Vec3 position, float limbSwing) { - this.entityId = entityId; - this.position = position; - this.limbSwing = limbSwing; - } - - public LimbSwingUpdatePacket(FriendlyByteBuf buffer) { - entityId = buffer.readInt(); - position = new Vec3(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); - limbSwing = buffer.readFloat(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(entityId); - buffer.writeFloat((float) position.x); - buffer.writeFloat((float) position.y); - buffer.writeFloat((float) position.z); - buffer.writeFloat(limbSwing); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ClientLevel world = Minecraft.getInstance().level; - if (world == null) - return; - Entity entity = world.getEntity(entityId); - if (entity == null) - return; - CompoundTag data = entity.getPersistentData(); - data.putInt("LastOverrideLimbSwingUpdate", 0); - data.putFloat("OverrideLimbSwing", limbSwing); - entity.lerpTo(position.x, position.y, position.z, entity.getYRot(), - entity.getXRot(), 2, false); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingCreationPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingCreationPacket.java deleted file mode 100644 index 7fbaf3479c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingCreationPacket.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraftforge.network.NetworkEvent.Context; - -public class CouplingCreationPacket extends SimplePacketBase { - - int id1, id2; - - public CouplingCreationPacket(AbstractMinecart cart1, AbstractMinecart cart2) { - id1 = cart1.getId(); - id2 = cart2.getId(); - } - - public CouplingCreationPacket(FriendlyByteBuf buffer) { - id1 = buffer.readInt(); - id2 = buffer.readInt(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(id1); - buffer.writeInt(id2); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer sender = context.get() - .getSender(); - if (sender != null) - CouplingHandler.tryToCoupleCarts(sender, sender.level, id1, id2); - }); - context.get() - .setPacketHandled(true); - } - -} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java deleted file mode 100644 index f34f3c7369..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; - -import static net.minecraft.util.Mth.lerp; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.CatnipClient; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class CouplingRenderer { - - public static void renderAll(PoseStack ms, MultiBufferSource buffer) { - CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().level, - c -> { - if (c.getFirst().hasContraptionCoupling(true)) - return; - CouplingRenderer.renderCoupling(ms, buffer, c.map(MinecartController::cart)); - }); - } - - public static void tickDebugModeRenders() { - if (KineticDebugger.isActive()) - CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().level, CouplingRenderer::doDebugRender); - } - - public static void renderCoupling(PoseStack ms, MultiBufferSource buffer, Couple carts) { - ClientLevel world = Minecraft.getInstance().level; - - if (carts.getFirst() == null || carts.getSecond() == null) - return; - - Couple lightValues = - carts.map(c -> LevelRenderer.getLightColor(world, new BlockPos(c.getBoundingBox() - .getCenter()))); - - Vec3 center = carts.getFirst() - .position() - .add(carts.getSecond() - .position()) - .scale(.5f); - - Couple transforms = carts.map(c -> getSuitableCartEndpoint(c, center)); - - BlockState renderState = Blocks.AIR.defaultBlockState(); - VertexConsumer builder = buffer.getBuffer(RenderType.solid()); - SuperByteBuffer attachment = CachedPartialBuffers.partial(AllBlockPartials.COUPLING_ATTACHMENT, renderState); - SuperByteBuffer ring = CachedPartialBuffers.partial(AllBlockPartials.COUPLING_RING, renderState); - SuperByteBuffer connector = CachedPartialBuffers.partial(AllBlockPartials.COUPLING_CONNECTOR, renderState); - - Vec3 zero = Vec3.ZERO; - Vec3 firstEndpoint = transforms.getFirst() - .apply(zero); - Vec3 secondEndpoint = transforms.getSecond() - .apply(zero); - Vec3 endPointDiff = secondEndpoint.subtract(firstEndpoint); - double connectorYaw = -Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI; - double connectorPitch = Math.atan2(endPointDiff.y, endPointDiff.multiply(1, 0, 1) - .length()) * 180 / Math.PI; - - TransformStack msr = TransformStack.cast(ms); - carts.forEachWithContext((cart, isFirst) -> { - CartEndpoint cartTransform = transforms.get(isFirst); - - ms.pushPose(); - cartTransform.apply(ms); - attachment.light(lightValues.get(isFirst)) - .renderInto(ms, builder); - msr.rotateY(connectorYaw - cartTransform.yaw); - ring.light(lightValues.get(isFirst)) - .renderInto(ms, builder); - ms.popPose(); - }); - - int l1 = lightValues.getFirst(); - int l2 = lightValues.getSecond(); - int meanBlockLight = (((l1 >> 4) & 0xf) + ((l2 >> 4) & 0xf)) / 2; - int meanSkyLight = (((l1 >> 20) & 0xf) + ((l2 >> 20) & 0xf)) / 2; - - ms.pushPose(); - msr.translate(firstEndpoint) - .rotateY(connectorYaw) - .rotateZ(connectorPitch); - ms.scale((float) endPointDiff.length(), 1, 1); - - connector.light(meanSkyLight << 20 | meanBlockLight << 4) - .renderInto(ms, builder); - ms.popPose(); - } - - private static CartEndpoint getSuitableCartEndpoint(AbstractMinecart cart, Vec3 centerOfCoupling) { - long i = cart.getId() * 493286711L; - i = i * i * 4392167121L + i * 98761L; - float x = (((float) (i >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; - float y = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F + 0.375F; - float z = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; - - float pt = AnimationTickHolder.getPartialTicks(); - - double xIn = lerp(pt, cart.xOld, cart.getX()); - double yIn = lerp(pt, cart.yOld, cart.getY()); - double zIn = lerp(pt, cart.zOld, cart.getZ()); - - float yaw = lerp(pt, cart.yRotO, cart.getYRot()); - float pitch = lerp(pt, cart.xRotO, cart.getXRot()); - float roll = cart.getHurtTime() - pt; - - float rollAmplifier = cart.getDamage() - pt; - if (rollAmplifier < 0.0F) - rollAmplifier = 0.0F; - roll = roll > 0 ? Mth.sin(roll) * roll * rollAmplifier / 10.0F * cart.getHurtDir() : 0; - - Vec3 positionVec = new Vec3(xIn, yIn, zIn); - Vec3 frontVec = positionVec.add(VecHelper.rotate(new Vec3(.5, 0, 0), 180 - yaw, Axis.Y)); - Vec3 backVec = positionVec.add(VecHelper.rotate(new Vec3(-.5, 0, 0), 180 - yaw, Axis.Y)); - - Vec3 railVecOfPos = cart.getPos(xIn, yIn, zIn); - boolean flip = false; - - if (railVecOfPos != null) { - frontVec = cart.getPosOffs(xIn, yIn, zIn, (double) 0.3F); - backVec = cart.getPosOffs(xIn, yIn, zIn, (double) -0.3F); - if (frontVec == null) - frontVec = railVecOfPos; - if (backVec == null) - backVec = railVecOfPos; - - x += railVecOfPos.x; - y += (frontVec.y + backVec.y) / 2; - z += railVecOfPos.z; - - Vec3 endPointDiff = backVec.add(-frontVec.x, -frontVec.y, -frontVec.z); - if (endPointDiff.length() != 0.0D) { - endPointDiff = endPointDiff.normalize(); - yaw = (float) (Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI); - pitch = (float) (Math.atan(endPointDiff.y) * 73.0D); - } - } else { - x += xIn; - y += yIn; - z += zIn; - } - - final float offsetMagnitude = 13 / 16f; - boolean isBackFaceCloser = - frontVec.distanceToSqr(centerOfCoupling) > backVec.distanceToSqr(centerOfCoupling); - flip = isBackFaceCloser; - float offset = isBackFaceCloser ? -offsetMagnitude : offsetMagnitude; - - return new CartEndpoint(x, y + 2 / 16f, z, 180 - yaw, -pitch, roll, offset, flip); - } - - static class CartEndpoint { - - float x; - float y; - float z; - float yaw; - float pitch; - float roll; - float offset; - boolean flip; - - public CartEndpoint(float x, float y, float z, float yaw, float pitch, float roll, float offset, boolean flip) { - this.x = x; - this.y = y; - this.z = z; - this.yaw = yaw; - this.pitch = pitch; - this.roll = roll; - this.offset = offset; - this.flip = flip; - } - - public Vec3 apply(Vec3 vec) { - vec = vec.add(offset, 0, 0); - vec = VecHelper.rotate(vec, roll, Axis.X); - vec = VecHelper.rotate(vec, pitch, Axis.Z); - vec = VecHelper.rotate(vec, yaw, Axis.Y); - return vec.add(x, y, z); - } - - public void apply(PoseStack ms) { - ms.translate(x, y, z); - ms.mulPose(Vector3f.YP.rotationDegrees(yaw)); - ms.mulPose(Vector3f.ZP.rotationDegrees(pitch)); - ms.mulPose(Vector3f.XP.rotationDegrees(roll)); - ms.translate(offset, 0, 0); - if (flip) - ms.mulPose(Vector3f.YP.rotationDegrees(180)); - } - - } - - public static void doDebugRender(Couple c) { - int yOffset = 1; - MinecartController first = c.getFirst(); - AbstractMinecart mainCart = first.cart(); - Vec3 mainCenter = mainCart.position() - .add(0, yOffset, 0); - Vec3 connectedCenter = c.getSecond() - .cart() - .position() - .add(0, yOffset, 0); - - int color = Color.mixColors(0xabf0e9, 0xee8572, (float) Mth - .clamp(Math.abs(first.getCouplingLength(true) - connectedCenter.distanceTo(mainCenter)) * 8, 0, 1)); - - CatnipClient.OUTLINER.showLine(mainCart.getId() + "", mainCenter, connectedCenter) - .colored(color) - .lineWidth(1 / 8f); - - Vec3 point = mainCart.position() - .add(0, yOffset, 0); - CatnipClient.OUTLINER.showLine(mainCart.getId() + "_dot", point, point.add(0, 1 / 128f, 0)) - .colored(0xffffff) - .lineWidth(1 / 4f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableTileEntity.java deleted file mode 100644 index eae84a2da7..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableTileEntity.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.simibubi.create.content.contraptions.components.turntable; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class TurntableTileEntity extends KineticTileEntity { - - public TurntableTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelBlock.java deleted file mode 100644 index ce9a4baeef..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelBlock.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.simibubi.create.content.contraptions.components.waterwheel; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.fluid.FluidHelper; - -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.worldWrappers.WrappedWorld; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.BubbleColumnBlock; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.Vec3; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class WaterWheelBlock extends DirectionalKineticBlock implements ITE { - - public WaterWheelBlock(Properties properties) { - super(properties); - } - - @Override - public RenderShape getRenderShape(BlockState state) { - return RenderShape.ENTITYBLOCK_ANIMATED; - } - - @Override - public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { - for (Direction direction : Iterate.directions) { - BlockPos neighbourPos = pos.relative(direction); - BlockState neighbourState = worldIn.getBlockState(neighbourPos); - if (!AllBlocks.WATER_WHEEL.has(neighbourState)) - continue; - if (neighbourState.getValue(FACING) - .getAxis() != state.getValue(FACING) - .getAxis() - || state.getValue(FACING) - .getAxis() != direction.getAxis()) - return false; - } - - return true; - } - - @Override - public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn, - BlockPos currentPos, BlockPos facingPos) { - if (worldIn instanceof WrappedWorld) - return stateIn; - updateFlowAt(stateIn, worldIn, currentPos, facing); - updateWheelSpeed(worldIn, currentPos); - return stateIn; - } - - @Override - public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, worldIn, pos, oldState, isMoving); - updateAllSides(state, worldIn, pos); - } - - public void updateAllSides(BlockState state, Level worldIn, BlockPos pos) { - for (Direction d : Iterate.directions) - updateFlowAt(state, worldIn, pos, d); - updateWheelSpeed(worldIn, pos); - } - - private void updateFlowAt(BlockState state, LevelAccessor world, BlockPos pos, Direction side) { - if (side.getAxis() == state.getValue(FACING) - .getAxis()) - return; - - FluidState fluid = world.getFluidState(pos.relative(side)); - Direction wf = state.getValue(FACING); - boolean clockwise = wf.getAxisDirection() == AxisDirection.POSITIVE; - int clockwiseMultiplier = 2; - - Vec3 vec = fluid.getFlow(world, pos.relative(side)); - if (side.getAxis() - .isHorizontal()) { - BlockState adjacentBlock = world.getBlockState(pos.relative(side)); - if (adjacentBlock.getBlock() == Blocks.BUBBLE_COLUMN) - vec = new Vec3(0, adjacentBlock.getValue(BubbleColumnBlock.DRAG_DOWN) ? -1 : 1, 0); - } - - vec = vec.scale(side.getAxisDirection() - .getStep()); - vec = new Vec3(Math.signum(vec.x), Math.signum(vec.y), Math.signum(vec.z)); - Vec3 flow = vec; - - withTileEntityDo(world, pos, te -> { - double flowStrength = 0; - - if (wf.getAxis() == Axis.Z) { - if (side.getAxis() == Axis.Y) - flowStrength = flow.x > 0 ^ !clockwise ? -flow.x * clockwiseMultiplier : -flow.x; - if (side.getAxis() == Axis.X) - flowStrength = flow.y < 0 ^ !clockwise ? flow.y * clockwiseMultiplier : flow.y; - } - - if (wf.getAxis() == Axis.X) { - if (side.getAxis() == Axis.Y) - flowStrength = flow.z < 0 ^ !clockwise ? flow.z * clockwiseMultiplier : flow.z; - if (side.getAxis() == Axis.Z) - flowStrength = flow.y > 0 ^ !clockwise ? -flow.y * clockwiseMultiplier : -flow.y; - } - - if (wf.getAxis() == Axis.Y) { - if (side.getAxis() == Axis.Z) - flowStrength = flow.x < 0 ^ !clockwise ? flow.x * clockwiseMultiplier : flow.x; - if (side.getAxis() == Axis.X) - flowStrength = flow.z > 0 ^ !clockwise ? -flow.z * clockwiseMultiplier : -flow.z; - } - - if (te.getSpeed() == 0 && flowStrength != 0 && !world.isClientSide()) - te.award( - FluidHelper.isLava(fluid.getType()) ? AllAdvancements.LAVA_WHEEL : AllAdvancements.WATER_WHEEL); - - Integer flowModifier = AllConfigs.SERVER.kinetics.waterWheelFlowSpeed.get(); - te.setFlow(side, (float) (flowStrength * flowModifier / 2f)); - }); - } - - private void updateWheelSpeed(LevelAccessor world, BlockPos pos) { - withTileEntityDo(world, pos, WaterWheelTileEntity::updateGeneratedRotation); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - Direction face = context.getClickedFace(); - Direction horizontalFacing = context.getHorizontalDirection(); - BlockPos pos = context.getClickedPos(); - Level world = context.getLevel(); - Player player = context.getPlayer(); - - BlockState placedOn = world.getBlockState(pos.relative(face.getOpposite())); - if (AllBlocks.WATER_WHEEL.has(placedOn)) - return defaultBlockState().setValue(FACING, placedOn.getValue(FACING)); - - Direction facing = face; - boolean sneaking = player != null && player.isShiftKeyDown(); - if (player != null) { - - Vec3 lookVec = player.getLookAngle(); - double tolerance = 0.985; - - if (!canSurvive(defaultBlockState().setValue(FACING, Direction.UP), world, pos)) - facing = horizontalFacing; - else if (Vec3.atLowerCornerOf(Direction.DOWN.getNormal()) - .dot(lookVec.normalize()) > tolerance) - facing = Direction.DOWN; - else if (Vec3.atLowerCornerOf(Direction.UP.getNormal()) - .dot(lookVec.normalize()) > tolerance) - facing = Direction.UP; - else - facing = horizontalFacing; - - } - - return defaultBlockState().setValue(FACING, sneaking ? facing.getOpposite() : facing); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return state.getValue(FACING) - .getAxis() == face.getAxis(); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(FACING) - .getAxis(); - } - - @Override - public float getParticleTargetRadius() { - return 1.125f; - } - - @Override - public float getParticleInitialRadius() { - return 1f; - } - - @Override - public boolean hideStressImpact() { - return true; - } - - @Override - public Class getTileEntityClass() { - return WaterWheelTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.WATER_WHEEL.get(); - } - - public static Couple getSpeedRange() { - Integer base = AllConfigs.SERVER.kinetics.waterWheelBaseSpeed.get(); - Integer flow = AllConfigs.SERVER.kinetics.waterWheelFlowSpeed.get(); - return Couple.create(base, base + 4 * flow); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java deleted file mode 100644 index 78dc298047..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.simibubi.create.content.contraptions.components.waterwheel; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class WaterWheelTileEntity extends GeneratingKineticTileEntity { - - private Map flows; - - public WaterWheelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - flows = new HashMap<>(); - for (Direction d : Iterate.directions) - setFlow(d, 0); - setLazyTickRate(20); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.LAVA_WHEEL, AllAdvancements.WATER_WHEEL); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (compound.contains("Flows")) { - for (Direction d : Iterate.directions) - setFlow(d, compound.getCompound("Flows") - .getFloat(d.getSerializedName())); - } - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).inflate(1); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - CompoundTag flows = new CompoundTag(); - for (Direction d : Iterate.directions) - flows.putFloat(d.getSerializedName(), this.flows.get(d)); - compound.put("Flows", flows); - - super.write(compound, clientPacket); - } - - public void setFlow(Direction direction, float speed) { - flows.put(direction, speed); - setChanged(); - } - - @Override - public float getGeneratedSpeed() { - float speed = 0; - for (Float f : flows.values()) - speed += f; - if (speed != 0) - speed += AllConfigs.SERVER.kinetics.waterWheelBaseSpeed.get() * Math.signum(speed); - return speed; - } - - @Override - public void lazyTick() { - super.lazyTick(); - AllBlocks.WATER_WHEEL.get() - .updateAllSides(getBlockState(), level, worldPosition); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorColumn.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorColumn.java new file mode 100644 index 0000000000..f6041ce56b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorColumn.java @@ -0,0 +1,226 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.IntAttached; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.WorldAttached; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class ElevatorColumn { + + public static WorldAttached> LOADED_COLUMNS = + new WorldAttached<>($ -> new HashMap<>()); + + protected LevelAccessor level; + protected ColumnCoords coords; + protected List contacts; + protected int targetedYLevel; + protected boolean isActive; + + @Nullable + public static ElevatorColumn get(LevelAccessor level, ColumnCoords coords) { + return LOADED_COLUMNS.get(level) + .get(coords); + } + + public static ElevatorColumn getOrCreate(LevelAccessor level, ColumnCoords coords) { + return LOADED_COLUMNS.get(level) + .computeIfAbsent(coords, c -> new ElevatorColumn(level, c)); + } + + public ElevatorColumn(LevelAccessor level, ColumnCoords coords) { + this.level = level; + this.coords = coords; + contacts = new ArrayList<>(); + } + + public void markDirty() { + for (BlockPos pos : getContacts()) { + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof ElevatorContactBlockEntity ecbe) + ecbe.setChanged(); + } + } + + public void floorReached(LevelAccessor level, String name) { + getContacts().stream() + .forEach(p -> { + if (level.getBlockEntity(p) instanceof ElevatorContactBlockEntity ecbe) + ecbe.updateDisplayedFloor(name); + }); + } + + public int namesListVersion; + + public List>> compileNamesList() { + return getContacts().stream() + .map(p -> { + if (level.getBlockEntity(p) instanceof ElevatorContactBlockEntity ecbe) + return IntAttached.with(p.getY(), ecbe.getNames()); + return null; + }) + .filter(Objects::nonNull) + .toList(); + } + + public void namesChanged() { + namesListVersion++; + } + + public Collection getContacts() { + return contacts.stream() + .map(this::contactAt) + .toList(); + } + + public void gatherAll() { + BlockPos.betweenClosedStream(contactAt(level.getMinBuildHeight()), contactAt(level.getMaxBuildHeight())) + .filter(p -> coords.equals(ElevatorContactBlock.getColumnCoords(level, p))) + .forEach(p -> level.setBlock(p, + BlockHelper.copyProperties(level.getBlockState(p), AllBlocks.ELEVATOR_CONTACT.getDefaultState()), 3)); + } + + public BlockPos contactAt(int y) { + return new BlockPos(coords.x, y, coords.z); + } + + public void setActive(boolean isActive) { + this.isActive = isActive; + markDirty(); + checkEmpty(); + } + + public boolean isActive() { + return isActive; + } + + public void target(int yLevel) { + targetedYLevel = yLevel; + } + + public int getTargetedYLevel() { + return targetedYLevel; + } + + public void initNames(Level level) { + Integer prevLevel = null; + + for (int i = 0; i < contacts.size(); i++) { + Integer y = contacts.get(i); + + BlockPos pos = contactAt(y); + if (!(level.getBlockEntity(pos) instanceof ElevatorContactBlockEntity ecbe)) + continue; + + Integer currentLevel = null; + + if (!ecbe.shortName.isBlank()) { + Integer tryValueOf = tryValueOf(ecbe.shortName); + if (tryValueOf != null) + currentLevel = tryValueOf; + if (currentLevel == null) + continue; + } + + if (prevLevel != null) + currentLevel = prevLevel + 1; + + Integer nextLevel = null; + + for (int peekI = i + 1; peekI < contacts.size(); peekI++) { + BlockPos peekPos = contactAt(contacts.get(peekI)); + if (!(level.getBlockEntity(peekPos) instanceof ElevatorContactBlockEntity peekEcbe)) + continue; + Integer tryValueOf = tryValueOf(peekEcbe.shortName); + if (tryValueOf == null) + continue; + if (currentLevel != null && currentLevel >= tryValueOf) { + peekEcbe.shortName = ""; + break; + } + nextLevel = tryValueOf; + break; + } + + if (currentLevel == null) + currentLevel = nextLevel != null ? nextLevel - 1 : 0; + + ecbe.updateName(String.valueOf(currentLevel), ecbe.longName); + prevLevel = currentLevel; + } + + } + + private static Integer tryValueOf(String floorName) { + try { + return Integer.valueOf(floorName, 10); + } catch (NumberFormatException nfe) { + return null; + } + } + + public void add(BlockPos contactPos) { + int coord = contactPos.getY(); + if (contacts.contains(coord)) + return; + int index = 0; + for (; index < contacts.size(); index++) + if (contacts.get(index) > coord) + break; + contacts.add(index, coord); + namesChanged(); + } + + public void remove(BlockPos contactPos) { + contacts.remove((Object) contactPos.getY()); + checkEmpty(); + namesChanged(); + } + + private void checkEmpty() { + if (contacts.isEmpty() && !isActive()) + LOADED_COLUMNS.get(level) + .remove(coords); + } + + public static record ColumnCoords(int x, int z, Direction side) { + + public ColumnCoords relative(BlockPos anchor) { + return new ColumnCoords(x + anchor.getX(), z + anchor.getZ(), side); + } + + public CompoundTag write() { + CompoundTag tag = new CompoundTag(); + tag.putInt("X", x); + tag.putInt("Z", z); + NBTHelper.writeEnum(tag, "Side", side); + return tag; + } + + public static ColumnCoords read(CompoundTag tag) { + int x = tag.getInt("X"); + int z = tag.getInt("Z"); + Direction side = NBTHelper.readEnum(tag, "Side", Direction.class); + return new ColumnCoords(x, z, side); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlock.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlock.java new file mode 100644 index 0000000000..12eea7c66b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlock.java @@ -0,0 +1,254 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.Optional; +import java.util.Random; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.content.redstone.contact.RedstoneContactBlock; +import com.simibubi.create.content.redstone.diodes.BrassDiodeBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.createmod.catnip.gui.ScreenOpener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.NonNullList; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class ElevatorContactBlock extends WrenchableDirectionalBlock + implements IBE, ISpecialBlockItemRequirement { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + public static final BooleanProperty CALLING = BooleanProperty.create("calling"); + public static final BooleanProperty POWERING = BrassDiodeBlock.POWERING; + + public ElevatorContactBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(CALLING, false) + .setValue(POWERING, false) + .setValue(POWERED, false) + .setValue(FACING, Direction.SOUTH)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(CALLING, POWERING, POWERED)); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + InteractionResult onWrenched = super.onWrenched(state, context); + if (onWrenched != InteractionResult.SUCCESS) + return onWrenched; + + Level level = context.getLevel(); + if (level.isClientSide()) + return onWrenched; + + BlockPos pos = context.getClickedPos(); + state = level.getBlockState(pos); + Direction facing = state.getValue(RedstoneContactBlock.FACING); + if (facing.getAxis() != Axis.Y + && ElevatorColumn.get(level, new ColumnCoords(pos.getX(), pos.getZ(), facing)) != null) + return onWrenched; + + level.setBlockAndUpdate(pos, BlockHelper.copyProperties(state, AllBlocks.REDSTONE_CONTACT.getDefaultState())); + + return onWrenched; + } + + @Nullable + public static ColumnCoords getColumnCoords(LevelAccessor level, BlockPos pos) { + BlockState blockState = level.getBlockState(pos); + if (!AllBlocks.ELEVATOR_CONTACT.has(blockState) && !AllBlocks.REDSTONE_CONTACT.has(blockState)) + return null; + Direction facing = blockState.getValue(FACING); + BlockPos target = pos; + return new ColumnCoords(target.getX(), target.getZ(), facing); + } + + @Override + public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos, + boolean pIsMoving) { + if (pLevel.isClientSide) + return; + + boolean isPowered = pState.getValue(POWERED); + if (isPowered == pLevel.hasNeighborSignal(pPos)) + return; + + pLevel.setBlock(pPos, pState.cycle(POWERED), 2); + + if (isPowered) + return; + if (pState.getValue(CALLING)) + return; + + ElevatorColumn elevatorColumn = ElevatorColumn.getOrCreate(pLevel, getColumnCoords(pLevel, pPos)); + callToContactAndUpdate(elevatorColumn, pState, pLevel, pPos, true); + } + + public void callToContactAndUpdate(ElevatorColumn elevatorColumn, BlockState pState, Level pLevel, BlockPos pPos, + boolean powered) { + pLevel.setBlock(pPos, pState.cycle(CALLING), 2); + + for (BlockPos otherPos : elevatorColumn.getContacts()) { + if (otherPos.equals(pPos)) + continue; + BlockState otherState = pLevel.getBlockState(otherPos); + if (!AllBlocks.ELEVATOR_CONTACT.has(otherState)) + continue; + pLevel.setBlock(otherPos, otherState.setValue(CALLING, false), 2 | 16); + scheduleActivation(pLevel, otherPos); + } + + if (powered) + pState = pState.setValue(POWERED, true); + pLevel.setBlock(pPos, pState.setValue(CALLING, true), 2); + pLevel.updateNeighborsAt(pPos, this); + + elevatorColumn.target(pPos.getY()); + elevatorColumn.markDirty(); + } + + public void scheduleActivation(LevelAccessor pLevel, BlockPos pPos) { + if (!pLevel.getBlockTicks() + .hasScheduledTick(pPos, this)) + pLevel.scheduleTick(pPos, this, 1); + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRand) { + boolean wasPowering = pState.getValue(POWERING); + + Optional optionalBE = getBlockEntityOptional(pLevel, pPos); + boolean shouldBePowering = optionalBE.map(be -> { + boolean activateBlock = be.activateBlock; + be.activateBlock = false; + be.setChanged(); + return activateBlock; + }) + .orElse(false); + + shouldBePowering |= RedstoneContactBlock.hasValidContact(pLevel, pPos, pState.getValue(FACING)); + + if (wasPowering || shouldBePowering) + pLevel.setBlock(pPos, pState.setValue(POWERING, shouldBePowering), 2 | 16); + + pLevel.updateNeighborsAt(pPos, this); + } + + @Override + public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn, + BlockPos currentPos, BlockPos facingPos) { + if (facing != stateIn.getValue(FACING)) + return stateIn; + boolean hasValidContact = RedstoneContactBlock.hasValidContact(worldIn, currentPos, facing); + if (stateIn.getValue(POWERING) != hasValidContact) + scheduleActivation(worldIn, currentPos); + return stateIn; + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, LevelReader level, BlockPos pos, Direction side) { + return false; + } + + @Override + public boolean isSignalSource(BlockState state) { + return state.getValue(POWERING); + } + + @Override + public ItemStack getCloneItemStack(BlockGetter pLevel, BlockPos pPos, BlockState pState) { + return AllBlocks.REDSTONE_CONTACT.asStack(); + } + + @Override + public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { + if (side == null) + return true; + return state.getValue(FACING) != side.getOpposite(); + } + + @Override + public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) { + if (side == null) + return 0; + BlockState toState = blockAccess.getBlockState(pos.relative(side.getOpposite())); + if (toState.is(this)) + return 0; + return state.getValue(POWERING) ? 15 : 0; + } + + @Override + public Class getBlockEntityClass() { + return ElevatorContactBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ELEVATOR_CONTACT.get(); + } + + @Override + public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement.of(AllBlocks.REDSTONE_CONTACT.getDefaultState(), be); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (player != null && AllItems.WRENCH.isIn(player.getItemInHand(handIn))) + return InteractionResult.PASS; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> withBlockEntityDo(worldIn, pos, be -> this.displayScreen(be, player))); + return InteractionResult.SUCCESS; + } + + @OnlyIn(value = Dist.CLIENT) + protected void displayScreen(ElevatorContactBlockEntity be, Player player) { + if (player instanceof LocalPlayer) + ScreenOpener + .open(new ElevatorContactScreen(be.getBlockPos(), be.shortName, be.longName, be.doorControls.mode)); + } + + public static int getLight(BlockState state) { + return state.getValue(POWERING) ? 10 : 0; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlockEntity.java new file mode 100644 index 0000000000..52b97dbf93 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactBlockEntity.java @@ -0,0 +1,158 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.List; + +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.content.decoration.slidingDoor.DoorControlBehaviour; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class ElevatorContactBlockEntity extends SmartBlockEntity { + + public DoorControlBehaviour doorControls; + public ColumnCoords columnCoords; + public boolean activateBlock; + + public String shortName; + public String longName; + + public String lastReportedCurrentFloor; + + private int yTargetFromNBT = Integer.MIN_VALUE; + private boolean deferNameGenerator; + + public ElevatorContactBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + shortName = ""; + longName = ""; + deferNameGenerator = false; + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(doorControls = new DoorControlBehaviour(this)); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + + tag.putString("ShortName", shortName); + tag.putString("LongName", longName); + + if (lastReportedCurrentFloor != null) + tag.putString("LastReportedCurrentFloor", lastReportedCurrentFloor); + + if (clientPacket) + return; + tag.putBoolean("Activate", activateBlock); + if (columnCoords == null) + return; + + ElevatorColumn column = ElevatorColumn.get(level, columnCoords); + if (column == null) + return; + tag.putInt("ColumnTarget", column.getTargetedYLevel()); + if (column.isActive()) + NBTHelper.putMarker(tag, "ColumnActive"); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + + shortName = tag.getString("ShortName"); + longName = tag.getString("LongName"); + + if (tag.contains("LastReportedCurrentFloor")) + lastReportedCurrentFloor = tag.getString("LastReportedCurrentFloor"); + + if (clientPacket) + return; + activateBlock = tag.getBoolean("Activate"); + if (!tag.contains("ColumnTarget")) + return; + + int target = tag.getInt("ColumnTarget"); + boolean active = tag.contains("ColumnActive"); + + if (columnCoords == null) { + yTargetFromNBT = target; + return; + } + + ElevatorColumn column = ElevatorColumn.getOrCreate(level, columnCoords); + column.target(target); + column.setActive(active); + } + + public void updateDisplayedFloor(String floor) { + if (floor.equals(lastReportedCurrentFloor)) + return; + lastReportedCurrentFloor = floor; + DisplayLinkBlock.notifyGatherers(level, worldPosition); + } + + @Override + public void initialize() { + super.initialize(); + if (level.isClientSide()) + return; + columnCoords = ElevatorContactBlock.getColumnCoords(level, worldPosition); + if (columnCoords == null) + return; + ElevatorColumn column = ElevatorColumn.getOrCreate(level, columnCoords); + column.add(worldPosition); + if (shortName.isBlank()) + deferNameGenerator = true; + if (yTargetFromNBT == Integer.MIN_VALUE) + return; + column.target(yTargetFromNBT); + yTargetFromNBT = Integer.MIN_VALUE; + } + + @Override + public void tick() { + super.tick(); + if (!deferNameGenerator) + return; + if (columnCoords != null) + ElevatorColumn.getOrCreate(level, columnCoords) + .initNames(level); + deferNameGenerator = false; + } + + @Override + public void invalidate() { + if (columnCoords != null) { + ElevatorColumn column = ElevatorColumn.get(level, columnCoords); + if (column != null) + column.remove(worldPosition); + } + super.invalidate(); + } + + public void updateName(String shortName, String longName) { + this.shortName = shortName; + this.longName = longName; + this.deferNameGenerator = false; + notifyUpdate(); + + ElevatorColumn column = ElevatorColumn.get(level, columnCoords); + if (column != null) + column.namesChanged(); + } + + public Couple getNames() { + return Couple.create(shortName, longName); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactEditPacket.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactEditPacket.java new file mode 100644 index 0000000000..81d331d54a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactEditPacket.java @@ -0,0 +1,47 @@ +package com.simibubi.create.content.contraptions.elevator; + +import com.simibubi.create.content.decoration.slidingDoor.DoorControl; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.Mth; + +public class ElevatorContactEditPacket extends BlockEntityConfigurationPacket { + + private String shortName; + private String longName; + private DoorControl doorControl; + + public ElevatorContactEditPacket(BlockPos pos, String shortName, String longName, DoorControl doorControl) { + super(pos); + this.shortName = shortName; + this.longName = longName; + this.doorControl = doorControl; + } + + public ElevatorContactEditPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeUtf(shortName, 4); + buffer.writeUtf(longName, 30); + buffer.writeVarInt(doorControl.ordinal()); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + shortName = buffer.readUtf(4); + longName = buffer.readUtf(30); + doorControl = DoorControl.values()[Mth.clamp(buffer.readVarInt(), 0, DoorControl.values().length)]; + } + + @Override + protected void applySettings(ElevatorContactBlockEntity be) { + be.updateName(shortName, longName); + be.doorControls.set(doorControl); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactScreen.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactScreen.java new file mode 100644 index 0000000000..b8ba3aaa52 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContactScreen.java @@ -0,0 +1,183 @@ +package com.simibubi.create.content.contraptions.elevator; + +import org.lwjgl.glfw.GLFW; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.decoration.slidingDoor.DoorControl; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.gui.widget.TooltipArea; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; + +public class ElevatorContactScreen extends AbstractSimiScreen { + + private AllGuiTextures background; + + private EditBox shortNameInput; + private EditBox longNameInput; + private IconButton confirm; + + private String shortName; + private String longName; + private DoorControl doorControl; + + private BlockPos pos; + + public ElevatorContactScreen(BlockPos pos, String prevShortName, String prevLongName, DoorControl prevDoorControl) { + super(CreateLang.translateDirect("elevator_contact.title")); + this.pos = pos; + this.doorControl = prevDoorControl; + background = AllGuiTextures.ELEVATOR_CONTACT; + this.shortName = prevShortName; + this.longName = prevLongName; + } + + @Override + public void init() { + setWindowSize(background.getWidth() + 30, background.getHeight()); + super.init(); + + int x = guiLeft; + int y = guiTop; + + confirm = new IconButton(x + 200, y + 58, AllIcons.I_CONFIRM); + confirm.withCallback(this::confirm); + addRenderableWidget(confirm); + + shortNameInput = editBox(33, 30, 4); + shortNameInput.setValue(shortName); + centerInput(x); + shortNameInput.setResponder(s -> { + shortName = s; + centerInput(x); + }); + shortNameInput.changeFocus(true); + setFocused(shortNameInput); + shortNameInput.setHighlightPos(0); + + longNameInput = editBox(63, 140, 30); + longNameInput.setValue(longName); + longNameInput.setResponder(s -> longName = s); + + MutableComponent rmbToEdit = CreateLang.translate("gui.schedule.lmb_edit") + .style(ChatFormatting.DARK_GRAY) + .style(ChatFormatting.ITALIC) + .component(); + + addRenderableOnly(new TooltipArea(x + 21, y + 23, 30, 18) + .withTooltip(ImmutableList.of(CreateLang.translate("elevator_contact.floor_identifier") + .color(0x5391E1) + .component(), rmbToEdit))); + + addRenderableOnly(new TooltipArea(x + 57, y + 23, 147, 18).withTooltip(ImmutableList.of( + CreateLang.translate("elevator_contact.floor_description") + .color(0x5391E1) + .component(), + CreateLang.translate("crafting_blueprint.optional") + .style(ChatFormatting.GRAY) + .component(), + rmbToEdit))); + + Pair doorControlWidgets = + DoorControl.createWidget(x + 58, y + 57, mode -> doorControl = mode, doorControl); + addRenderableWidget(doorControlWidgets.getFirst()); + addRenderableWidget(doorControlWidgets.getSecond()); + } + + private int centerInput(int x) { + return shortNameInput.x = x + (shortName.isEmpty() ? 34 : 36 - font.width(shortName) / 2); + } + + private EditBox editBox(int x, int width, int chars) { + EditBox editBox = new EditBox(font, guiLeft + x, guiTop + 30, width, 10, Components.immutableEmpty()); + editBox.setTextColor(-1); + editBox.setTextColorUneditable(-1); + editBox.setBordered(false); + editBox.setMaxLength(chars); + editBox.changeFocus(false); + editBox.mouseClicked(0, 0, 0); + addRenderableWidget(editBox); + return editBox; + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + + FormattedCharSequence formattedcharsequence = title.getVisualOrderText(); + font.draw(ms, formattedcharsequence, + (float) (x + (background.getWidth() - 8) / 2 - font.width(formattedcharsequence) / 2), (float) y + 6, 0x2F3738); + + GuiGameElement.of(AllBlocks.ELEVATOR_CONTACT.asStack()).at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200) + .scale(5) + .render(ms); + + itemRenderer.renderGuiItem(AllBlocks.TRAIN_DOOR.asStack(), x + 37, y + 58); + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { + boolean consumed = super.mouseClicked(pMouseX, pMouseY, pButton); + + if (!shortNameInput.isFocused()) { + int length = shortNameInput.getValue() + .length(); + shortNameInput.setHighlightPos(length); + shortNameInput.setCursorPosition(length); + } + + if (shortNameInput.isHoveredOrFocused()) + longNameInput.mouseClicked(0, 0, 0); + + if (!consumed && pMouseX > guiLeft + 22 && pMouseY > guiTop + 24 && pMouseX < guiLeft + 50 + && pMouseY < guiTop + 40) { + setFocused(shortNameInput); + shortNameInput.changeFocus(true); + return true; + } + + return consumed; + } + + @Override + public boolean keyPressed(int keyCode, int p_keyPressed_2_, int p_keyPressed_3_) { + if (super.keyPressed(keyCode, p_keyPressed_2_, p_keyPressed_3_)) + return true; + if (keyCode == GLFW.GLFW_KEY_ENTER) { + confirm(); + return true; + } + if (keyCode == 256 && this.shouldCloseOnEsc()) { + this.onClose(); + return true; + } + return false; + } + + private void confirm() { + AllPackets.getChannel() + .sendToServer(new ElevatorContactEditPacket(pos, shortName, longName, doorControl)); + onClose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContraption.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContraption.java new file mode 100644 index 0000000000..fe2454a37b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorContraption.java @@ -0,0 +1,199 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.List; + +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.content.contraptions.pulley.PulleyContraption; +import com.simibubi.create.content.redstone.contact.RedstoneContactBlock; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.IntAttached; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraftforge.network.PacketDistributor; + +public class ElevatorContraption extends PulleyContraption { + + protected ColumnCoords column; + protected int contactYOffset; + public boolean arrived; + + private int namesListVersion = -1; + public List>> namesList = ImmutableList.of(); + public int clientYTarget; + + public int maxContactY; + public int minContactY; + + // during assembly only + private int contacts; + + public ElevatorContraption() { + super(); + } + + public ElevatorContraption(int initialOffset) { + super(initialOffset); + } + + @Override + public void tickStorage(AbstractContraptionEntity entity) { + super.tickStorage(entity); + + if (entity.tickCount % 10 != 0) + return; + + ColumnCoords coords = getGlobalColumn(); + ElevatorColumn column = ElevatorColumn.get(entity.level, coords); + + if (column == null) + return; + if (column.namesListVersion == namesListVersion) + return; + + namesList = column.compileNamesList(); + namesListVersion = column.namesListVersion; + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), + new ElevatorFloorListPacket(entity, namesList)); + } + + @Override + protected void disableActorOnStart(MovementContext context) {} + + public ColumnCoords getGlobalColumn() { + return column.relative(anchor); + } + + public Integer getCurrentTargetY(Level level) { + ColumnCoords coords = getGlobalColumn(); + ElevatorColumn column = ElevatorColumn.get(level, coords); + if (column == null) + return null; + int targetedYLevel = column.targetedYLevel; + if (isTargetUnreachable(targetedYLevel)) + return null; + return targetedYLevel; + } + + public boolean isTargetUnreachable(int contactY) { + return contactY < minContactY || contactY > maxContactY; + } + + @Override + public boolean assemble(Level world, BlockPos pos) throws AssemblyException { + if (!searchMovedStructure(world, pos, null)) + return false; + if (blocks.size() <= 0) + return false; + if (contacts == 0) + throw new AssemblyException(CreateLang.translateDirect("gui.assembly.exception.no_contacts")); + if (contacts > 1) + throw new AssemblyException(CreateLang.translateDirect("gui.assembly.exception.too_many_contacts")); + + ElevatorColumn column = ElevatorColumn.get(world, getGlobalColumn()); + if (column != null && column.isActive()) + throw new AssemblyException(CreateLang.translateDirect("gui.assembly.exception.column_conflict")); + + startMoving(world); + return true; + } + + @Override + protected Pair capture(Level world, BlockPos pos) { + BlockState blockState = world.getBlockState(pos); + + if (!AllBlocks.REDSTONE_CONTACT.has(blockState)) + return super.capture(world, pos); + + Direction facing = blockState.getValue(RedstoneContactBlock.FACING); + if (facing.getAxis() == Axis.Y) + return super.capture(world, pos); + + contacts++; + BlockPos local = toLocalPos(pos.relative(facing)); + column = new ColumnCoords(local.getX(), local.getZ(), facing.getOpposite()); + contactYOffset = local.getY(); + + return super.capture(world, pos); + } + + public int getContactYOffset() { + return contactYOffset; + } + + public void broadcastFloorData(Level level, BlockPos contactPos) { + ElevatorColumn column = ElevatorColumn.get(level, getGlobalColumn()); + if (!(world.getBlockEntity(contactPos) instanceof ElevatorContactBlockEntity ecbe)) + return; + if (column != null) + column.floorReached(level, ecbe.shortName); + } + + @Override + public CompoundTag writeNBT(boolean spawnPacket) { + CompoundTag tag = super.writeNBT(spawnPacket); + tag.putBoolean("Arrived", arrived); + tag.put("Column", column.write()); + tag.putInt("ContactY", contactYOffset); + tag.putInt("MaxContactY", maxContactY); + tag.putInt("MinContactY", minContactY); + return tag; + } + + @Override + public void readNBT(Level world, CompoundTag nbt, boolean spawnData) { + arrived = nbt.getBoolean("Arrived"); + column = ColumnCoords.read(nbt.getCompound("Column")); + contactYOffset = nbt.getInt("ContactY"); + maxContactY = nbt.getInt("MaxContactY"); + minContactY = nbt.getInt("MinContactY"); + super.readNBT(world, nbt, spawnData); + } + + @Override + public ContraptionType getType() { + return ContraptionType.ELEVATOR; + } + + public void setClientYTarget(int clientYTarget) { + if (this.clientYTarget == clientYTarget) + return; + + this.clientYTarget = clientYTarget; + syncControlDisplays(); + } + + public void syncControlDisplays() { + if (namesList.isEmpty()) + return; + for (int i = 0; i < namesList.size(); i++) + if (namesList.get(i) + .getFirst() == clientYTarget) + setAllControlsToFloor(i); + } + + public void setAllControlsToFloor(int floorIndex) { + for (MutablePair pair : actors) + if (pair.right != null && pair.right.temporaryData instanceof ElevatorFloorSelection efs) + efs.currentIndex = floorIndex; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorControlsHandler.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorControlsHandler.java new file mode 100644 index 0000000000..8bdab7e794 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorControlsHandler.java @@ -0,0 +1,130 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.lang.ref.WeakReference; +import java.util.Collection; + +import org.apache.commons.lang3.tuple.MutablePair; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionHandler; +import com.simibubi.create.content.contraptions.ContraptionHandlerClient; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlockEntity; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlockEntity.ControlsSlot; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement; +import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class ElevatorControlsHandler { + + private static ControlsSlot slot = new ElevatorControlsSlot(); + + private static class ElevatorControlsSlot extends ContraptionControlsBlockEntity.ControlsSlot { + + @Override + public boolean testHit(BlockState state, Vec3 localHit) { + Vec3 offset = getLocalOffset(state); + if (offset == null) + return false; + return localHit.distanceTo(offset) < scale * .85; + } + + } + + @OnlyIn(Dist.CLIENT) + public static boolean onScroll(double delta) { + Minecraft mc = Minecraft.getInstance(); + LocalPlayer player = mc.player; + + if (player == null) + return false; + if (player.isSpectator()) + return false; + if (mc.level == null) + return false; + + Couple rayInputs = ContraptionHandlerClient.getRayInputs(player); + Vec3 origin = rayInputs.getFirst(); + Vec3 target = rayInputs.getSecond(); + AABB aabb = new AABB(origin, target).inflate(16); + + Collection> contraptions = + ContraptionHandler.loadedContraptions.get(mc.level) + .values(); + + for (WeakReference ref : contraptions) { + AbstractContraptionEntity contraptionEntity = ref.get(); + if (contraptionEntity == null) + continue; + + Contraption contraption = contraptionEntity.getContraption(); + if (!(contraption instanceof ElevatorContraption ec)) + continue; + + if (!contraptionEntity.getBoundingBox() + .intersects(aabb)) + continue; + + BlockHitResult rayTraceResult = + ContraptionHandlerClient.rayTraceContraption(origin, target, contraptionEntity); + if (rayTraceResult == null) + continue; + + BlockPos pos = rayTraceResult.getBlockPos(); + StructureBlockInfo info = contraption.getBlocks() + .get(pos); + + if (info == null) + continue; + if (!AllBlocks.CONTRAPTION_CONTROLS.has(info.state)) + continue; + + if (!slot.testHit(info.state, rayTraceResult.getLocation() + .subtract(Vec3.atLowerCornerOf(pos)))) + continue; + + MovementContext ctx = null; + for (MutablePair pair : contraption.getActors()) { + if (info.equals(pair.left)) { + ctx = pair.right; + break; + } + } + + if (!(ctx.temporaryData instanceof ElevatorFloorSelection)) + ctx.temporaryData = new ElevatorFloorSelection(); + + ElevatorFloorSelection efs = (ElevatorFloorSelection) ctx.temporaryData; + int prev = efs.currentIndex; + efs.currentIndex += delta; + ContraptionControlsMovement.tickFloorSelection(efs, ec); + + if (prev != efs.currentIndex && !ec.namesList.isEmpty()) { + float pitch = (efs.currentIndex) / (float) (ec.namesList.size()); + pitch = Mth.lerp(pitch, 1f, 1.5f); + AllSoundEvents.SCROLL_VALUE.play(mc.player.level, mc.player, + new BlockPos(contraptionEntity.toGlobalVector(rayTraceResult.getLocation(), 1)), 1, pitch); + } + + return true; + } + + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorFloorListPacket.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorFloorListPacket.java new file mode 100644 index 0000000000..5a294d3d29 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorFloorListPacket.java @@ -0,0 +1,98 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.IntAttached; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +public class ElevatorFloorListPacket extends SimplePacketBase { + + private int entityId; + private List>> floorsList; + + public ElevatorFloorListPacket(AbstractContraptionEntity entity, List>> floorsList) { + this.entityId = entity.getId(); + this.floorsList = floorsList; + } + + public ElevatorFloorListPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + int size = buffer.readInt(); + floorsList = new ArrayList<>(); + for (int i = 0; i < size; i++) + floorsList.add(IntAttached.with(buffer.readInt(), Couple.create(buffer.readUtf(), buffer.readUtf()))); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeInt(floorsList.size()); + for (IntAttached> entry : floorsList) { + buffer.writeInt(entry.getFirst()); + entry.getSecond() + .forEach(buffer::writeUtf); + } + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityId); + if (!(entityByID instanceof AbstractContraptionEntity ace)) + return; + if (!(ace.getContraption()instanceof ElevatorContraption ec)) + return; + + ec.namesList = floorsList; + ec.syncControlDisplays(); + }); + return true; + } + + public static class RequestFloorList extends SimplePacketBase { + + private int entityId; + + public RequestFloorList(AbstractContraptionEntity entity) { + this.entityId = entity.getId(); + } + + public RequestFloorList(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + Entity entityByID = sender.getLevel() + .getEntity(entityId); + if (!(entityByID instanceof AbstractContraptionEntity ace)) + return; + if (!(ace.getContraption()instanceof ElevatorContraption ec)) + return; + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> sender), + new ElevatorFloorListPacket(ace, ec.namesList)); + }); + return true; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlock.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlock.java new file mode 100644 index 0000000000..03e64c0273 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlock.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.contraptions.elevator; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class ElevatorPulleyBlock extends HorizontalKineticBlock implements IBE { + + public ElevatorPulleyBlock(Properties properties) { + super(properties); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (!player.mayBuild()) + return InteractionResult.FAIL; + if (player.isShiftKeyDown()) + return InteractionResult.FAIL; + if (!player.getItemInHand(handIn) + .isEmpty()) + return InteractionResult.PASS; + if (worldIn.isClientSide) + return InteractionResult.SUCCESS; + return onBlockEntityUse(worldIn, pos, be -> { + be.clicked(); + return InteractionResult.SUCCESS; + }); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ELEVATOR_PULLEY.get(); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(HORIZONTAL_FACING) + .getClockWise() + .getAxis(); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.ELEVATOR_PULLEY.get(state.getValue(HORIZONTAL_FACING)); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return getRotationAxis(state) == face.getAxis(); + } + + @Override + public Class getBlockEntityClass() { + return ElevatorPulleyBlockEntity.class; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlockEntity.java new file mode 100644 index 0000000000..faa722ffd1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyBlockEntity.java @@ -0,0 +1,325 @@ +package com.simibubi.create.content.contraptions.elevator; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.content.contraptions.pulley.PulleyBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class ElevatorPulleyBlockEntity extends PulleyBlockEntity { + + private float prevSpeed; + private boolean arrived; + private int clientOffsetTarget; + private boolean initialOffsetReceived; + + public ElevatorPulleyBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + prevSpeed = 0; + arrived = true; + initialOffsetReceived = false; + } + + private int getTargetOffset() { + if (level.isClientSide) + return clientOffsetTarget; + if (movedContraption == null || !(movedContraption.getContraption()instanceof ElevatorContraption ec)) + return (int) offset; + + Integer target = ec.getCurrentTargetY(level); + if (target == null) + return (int) offset; + + return worldPosition.getY() - target + ec.contactYOffset - 1; + } + + @Override + public void attach(ControlledContraptionEntity contraption) { + super.attach(contraption); + if (offset >= 0) + resetContraptionToOffset(); + if (level.isClientSide) { + AllPackets.getChannel().sendToServer(new ElevatorFloorListPacket.RequestFloorList(contraption)); + return; + } + + if (contraption.getContraption()instanceof ElevatorContraption ec) + ElevatorColumn.getOrCreate(level, ec.getGlobalColumn()) + .setActive(true); + } + + @Override + public void tick() { + boolean wasArrived = arrived; + super.tick(); + + if (movedContraption == null) + return; + if (!(movedContraption.getContraption()instanceof ElevatorContraption ec)) + return; + if (level.isClientSide()) + ec.setClientYTarget(worldPosition.getY() - clientOffsetTarget + ec.contactYOffset - 1); + + waitingForSpeedChange = false; + ec.arrived = wasArrived; + + if (!arrived) + return; + + double y = movedContraption.getY(); + int targetLevel = Mth.floor(0.5f + y) + ec.contactYOffset; + + Integer ecCurrentTargetY = ec.getCurrentTargetY(level); + if (ecCurrentTargetY != null) + targetLevel = ecCurrentTargetY; + if (level.isClientSide()) + targetLevel = ec.clientYTarget; + if (!wasArrived && !level.isClientSide()) { + triggerContact(ec, targetLevel); + AllSoundEvents.CONTRAPTION_DISASSEMBLE.play(level, null, worldPosition.below((int) offset), 0.75f, 0.8f); + } + + double diff = targetLevel - y - ec.contactYOffset; + if (Math.abs(diff) > 1f / 128) + diff *= 0.25f; + movedContraption.setPos(movedContraption.position() + .add(0, diff, 0)); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (level.isClientSide() || !arrived) + return; + if (movedContraption == null || !movedContraption.isAlive()) + return; + if (!(movedContraption.getContraption()instanceof ElevatorContraption ec)) + return; + if (getTargetOffset() != (int) offset) + return; + + double y = movedContraption.getY(); + int targetLevel = Mth.floor(0.5f + y); + triggerContact(ec, targetLevel); + } + + private void triggerContact(ElevatorContraption ec, int targetLevel) { + ColumnCoords coords = ec.getGlobalColumn(); + ElevatorColumn column = ElevatorColumn.get(level, coords); + if (column == null) + return; + + BlockPos contactPos = column.contactAt(targetLevel + ec.contactYOffset); + if (!level.isLoaded(contactPos)) + return; + BlockState contactState = level.getBlockState(contactPos); + if (!AllBlocks.ELEVATOR_CONTACT.has(contactState)) + return; + if (contactState.getValue(ElevatorContactBlock.POWERING)) + return; + + ElevatorContactBlock ecb = AllBlocks.ELEVATOR_CONTACT.get(); + ecb.withBlockEntityDo(level, contactPos, be -> be.activateBlock = true); + ecb.scheduleActivation(level, contactPos); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + if (clientPacket) + compound.putInt("ClientTarget", clientOffsetTarget); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (!clientPacket) + return; + + clientOffsetTarget = compound.getInt("ClientTarget"); + if (initialOffsetReceived) + return; + + offset = compound.getFloat("Offset"); + initialOffsetReceived = true; + resetContraptionToOffset(); + } + + @Override + public float getMovementSpeed() { + int currentTarget = getTargetOffset(); + + if (!level.isClientSide() && currentTarget != clientOffsetTarget) { + clientOffsetTarget = currentTarget; + sendData(); + } + + float diff = currentTarget - offset; + float movementSpeed = Mth.clamp(convertToLinear(getSpeed() * 2), -1.99f, 1.99f); + float rpmLimit = Math.abs(movementSpeed); + + float configacc = Mth.lerp(Math.abs(movementSpeed), 0.0075f, 0.0175f); + float decelleration = (float) Math.sqrt(2 * Math.abs(diff) * configacc); + + float speed = diff; + speed = Mth.clamp(speed, -rpmLimit, rpmLimit); + speed = Mth.clamp(speed, prevSpeed - configacc, prevSpeed + configacc); + speed = Mth.clamp(speed, -decelleration, decelleration); + + arrived = Math.abs(diff) < 0.5f; + + if (speed > 1 / 1024f && !level.isClientSide()) + setChanged(); + + return prevSpeed = speed; + } + + @Override + protected boolean shouldCreateRopes() { + return false; + } + + @Override + public void disassemble() { + if (movedContraption != null && movedContraption.getContraption()instanceof ElevatorContraption ec) { + ElevatorColumn column = ElevatorColumn.get(level, ec.getGlobalColumn()); + if (column != null) + column.setActive(false); + } + + super.disassemble(); + offset = -1; + sendData(); + } + + public void clicked() { + if (isPassive() && level.getBlockEntity(mirrorParent)instanceof ElevatorPulleyBlockEntity parent) { + parent.clicked(); + return; + } + + if (running) + disassemble(); + else + assembleNextTick = true; + } + + @Override + protected boolean moveAndCollideContraption() { + if (arrived) + return false; + super.moveAndCollideContraption(); + return false; + } + + @Override + public void addBehaviours(List behaviours) { + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + protected void assemble() throws AssemblyException { + if (!(level.getBlockState(worldPosition) + .getBlock() instanceof ElevatorPulleyBlock)) + return; + if (getSpeed() == 0) + return; + + int maxLength = AllConfigs.server().kinetics.maxRopeLength.get(); + int i = 1; + while (i <= maxLength) { + BlockPos ropePos = worldPosition.below(i); + BlockState ropeState = level.getBlockState(ropePos); + if (!ropeState.getCollisionShape(level, ropePos) + .isEmpty() + && !ropeState.getMaterial() + .isReplaceable()) { + break; + } + ++i; + } + + offset = i - 1; + forceMove = true; + + // Collect Construct + if (!level.isClientSide && mirrorParent == null) { + needsContraption = false; + BlockPos anchor = worldPosition.below(Mth.floor(offset + 1)); + offset = Mth.floor(offset); + ElevatorContraption contraption = new ElevatorContraption((int) offset); + + float offsetOnSucess = offset; + offset = 0; + + boolean canAssembleStructure = contraption.assemble(level, anchor); + if (!canAssembleStructure && getSpeed() > 0) + return; + + if (!contraption.getBlocks() + .isEmpty()) { + offset = offsetOnSucess; + contraption.removeBlocksFromWorld(level, BlockPos.ZERO); + movedContraption = ControlledContraptionEntity.create(level, this, contraption); + movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + contraption.maxContactY = worldPosition.getY() + contraption.contactYOffset - 1; + contraption.minContactY = contraption.maxContactY - maxLength; + level.addFreshEntity(movedContraption); + forceMove = true; + needsContraption = true; + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + + for (BlockPos pos : contraption.createColliders(level, Direction.UP)) { + if (pos.getY() != 0) + continue; + pos = pos.offset(anchor); + if (level.getBlockEntity(new BlockPos(pos.getX(), worldPosition.getY(), + pos.getZ())) instanceof ElevatorPulleyBlockEntity pbe) + pbe.startMirroringOther(worldPosition); + } + + ElevatorColumn column = ElevatorColumn.getOrCreate(level, contraption.getGlobalColumn()); + int target = (int) (worldPosition.getY() + contraption.contactYOffset - 1 - offset); + column.target(target); + column.gatherAll(); + column.setActive(true); + column.markDirty(); + + contraption.broadcastFloorData(level, column.contactAt(target)); + clientOffsetTarget = column.getTargetedYLevel(); + arrived = true; + } + } + + clientOffsetDiff = 0; + running = true; + sendData(); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + setChanged(); + } + + @Override + protected MovementMode getMovementMode() { + return MovementMode.MOVE_NEVER_PLACE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyInstance.java new file mode 100644 index 0000000000..ac5e07f786 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyInstance.java @@ -0,0 +1,24 @@ +package com.simibubi.create.content.contraptions.elevator; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.light.TickingLightListener; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +// TODO +public class ElevatorPulleyInstance extends ShaftInstance implements DynamicInstance, TickingLightListener { + + public ElevatorPulleyInstance(MaterialManager materialManager, ElevatorPulleyBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + public boolean tickLightListener() { + return false; + } + + @Override + public void beginFrame() { + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyRenderer.java new file mode 100644 index 0000000000..9add3a291b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorPulleyRenderer.java @@ -0,0 +1,127 @@ +package com.simibubi.create.content.contraptions.elevator; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.AllSpriteShifts; +import com.simibubi.create.content.contraptions.pulley.AbstractPulleyRenderer; +import com.simibubi.create.content.contraptions.pulley.PulleyRenderer; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SpriteShiftEntry; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class ElevatorPulleyRenderer extends KineticBlockEntityRenderer { + + public ElevatorPulleyRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(ElevatorPulleyBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + +// if (Backend.canUseInstancing(be.getLevel())) +// return; + + // from KBE. replace with super call when flw instance is implemented + BlockState state = getRenderedBlockState(be); + RenderType type = getRenderType(be, state); + if (type != null) + renderRotatingBuffer(be, getRotatedModel(be, state), ms, buffer.getBuffer(type), light); + // + + float offset = PulleyRenderer.getBlockEntityOffset(partialTicks, be); + boolean running = PulleyRenderer.isPulleyRunning(be); + + SpriteShiftEntry beltShift = AllSpriteShifts.ELEVATOR_BELT; + SpriteShiftEntry coilShift = AllSpriteShifts.ELEVATOR_COIL; + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + Level world = be.getLevel(); + BlockState blockState = be.getBlockState(); + BlockPos pos = be.getBlockPos(); + + float blockStateAngle = + 180 + AngleHelper.horizontalAngle(blockState.getValue(ElevatorPulleyBlock.HORIZONTAL_FACING)); + + SuperByteBuffer magnet = CachedPartialBuffers.partial(AllPartialModels.ELEVATOR_MAGNET, blockState); + if (running || offset == 0) + AbstractPulleyRenderer.renderAt(world, magnet.centre() + .rotateY(blockStateAngle) + .unCentre(), offset, pos, ms, vb); + + SuperByteBuffer rotatedCoil = getRotatedCoil(be); + if (offset == 0) { + rotatedCoil.light(light) + .renderInto(ms, vb); + return; + } + + float spriteSize = beltShift.getTarget() + .getV1() + - beltShift.getTarget() + .getV0(); + + double coilScroll = -(offset + 3 / 16f) - Math.floor((offset + 3 / 16f) * -2) / 2; + double beltScroll = (-(offset + .5) - Math.floor(-(offset + .5))) / 2; + + rotatedCoil.shiftUVScrolling(coilShift, (float) coilScroll * spriteSize) + .light(light) + .renderInto(ms, vb); + + SuperByteBuffer halfRope = CachedPartialBuffers.partial(AllPartialModels.ELEVATOR_BELT_HALF, blockState); + SuperByteBuffer rope = CachedPartialBuffers.partial(AllPartialModels.ELEVATOR_BELT, blockState); + + float f = offset % 1; + if (f < .25f || f > .75f) { + halfRope.centre() + .rotateY(blockStateAngle) + .unCentre(); + AbstractPulleyRenderer.renderAt(world, + halfRope.shiftUVScrolling(beltShift, (float) beltScroll * spriteSize), f > .75f ? f - 1 : f, pos, ms, + vb); + } + + if (!running) + return; + + for (int i = 0; i < offset - .25f; i++) { + rope.centre() + .rotateY(blockStateAngle) + .unCentre(); + AbstractPulleyRenderer.renderAt(world, rope.shiftUVScrolling(beltShift, (float) beltScroll * spriteSize), + offset - i, pos, ms, vb); + } + } + + @Override + protected BlockState getRenderedBlockState(ElevatorPulleyBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + + protected SuperByteBuffer getRotatedCoil(KineticBlockEntity be) { + BlockState blockState = be.getBlockState(); + return CachedPartialBuffers.partialFacing(AllPartialModels.ELEVATOR_COIL, blockState, + blockState.getValue(ElevatorPulleyBlock.HORIZONTAL_FACING)); + } + + @Override + public int getViewDistance() { + return 128; + } + + @Override + public boolean shouldRenderOffScreen(ElevatorPulleyBlockEntity p_188185_1_) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorTargetFloorPacket.java b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorTargetFloorPacket.java new file mode 100644 index 0000000000..1e6ec3afc7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/elevator/ElevatorTargetFloorPacket.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.contraptions.elevator; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ElevatorTargetFloorPacket extends SimplePacketBase { + + private int entityId; + private int targetY; + + public ElevatorTargetFloorPacket(AbstractContraptionEntity entity, int targetY) { + this.targetY = targetY; + this.entityId = entity.getId(); + } + + public ElevatorTargetFloorPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + targetY = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeInt(targetY); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + Entity entityByID = sender.getLevel() + .getEntity(entityId); + if (!(entityByID instanceof AbstractContraptionEntity ace)) + return; + if (!(ace.getContraption() instanceof ElevatorContraption ec)) + return; + if (ace.distanceToSqr(sender) > 50 * 50) + return; + + Level level = sender.level; + ElevatorColumn elevatorColumn = ElevatorColumn.get(level, ec.getGlobalColumn()); + if (!elevatorColumn.contacts.contains(targetY)) + return; + if (ec.isTargetUnreachable(targetY)) + return; + + BlockPos pos = elevatorColumn.contactAt(targetY); + BlockState blockState = level.getBlockState(pos); + if (!(blockState.getBlock() instanceof ElevatorContactBlock ecb)) + return; + + ecb.callToContactAndUpdate(elevatorColumn, blockState, level, pos, false); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java deleted file mode 100644 index f0b6225d08..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes.ComponentPartials; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.data.ModelDataMap.Builder; -import net.minecraftforge.client.model.data.ModelProperty; - -public class PipeAttachmentModel extends BakedModelWrapperWithData { - - private static final ModelProperty PIPE_PROPERTY = new ModelProperty<>(); - - public PipeAttachmentModel(BakedModel template) { - super(template); - } - - @Override - protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) { - PipeModelData data = new PipeModelData(); - FluidTransportBehaviour transport = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); - BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); - - if (transport != null) - for (Direction d : Iterate.directions) - data.putAttachment(d, transport.getRenderedRimAttachment(world, pos, state, d)); - if (bracket != null) - data.putBracket(bracket.getBracket()); - - data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state)); - return builder.withInitial(PIPE_PROPERTY, data); - } - - @Override - public List getQuads(BlockState state, Direction side, Random rand, IModelData data) { - List quads = super.getQuads(state, side, rand, data); - if (data.hasProperty(PIPE_PROPERTY)) { - PipeModelData pipeData = data.getData(PIPE_PROPERTY); - quads = new ArrayList<>(quads); - addQuads(quads, state, side, rand, data, pipeData); - } - return quads; - } - - private void addQuads(List quads, BlockState state, Direction side, Random rand, IModelData data, - PipeModelData pipeData) { - BakedModel bracket = pipeData.getBracket(); - if (bracket != null) - quads.addAll(bracket.getQuads(state, side, rand, data)); - for (Direction d : Iterate.directions) { - AttachmentTypes type = pipeData.getAttachment(d); - for (ComponentPartials partial : type.partials) { - quads.addAll(AllBlockPartials.PIPE_ATTACHMENTS.get(partial) - .get(d) - .get() - .getQuads(state, side, rand, data)); - } - } - if (pipeData.isEncased()) - quads.addAll(AllBlockPartials.FLUID_PIPE_CASING.get() - .getQuads(state, side, rand, data)); - } - - private static class PipeModelData { - private AttachmentTypes[] attachments; - private boolean encased; - private BakedModel bracket; - - public PipeModelData() { - attachments = new AttachmentTypes[6]; - Arrays.fill(attachments, AttachmentTypes.NONE); - } - - public void putBracket(BlockState state) { - if (state != null) { - this.bracket = Minecraft.getInstance() - .getBlockRenderer() - .getBlockModel(state); - } - } - - public BakedModel getBracket() { - return bracket; - } - - public void putAttachment(Direction face, AttachmentTypes rim) { - attachments[face.get3DDataValue()] = rim; - } - - public AttachmentTypes getAttachment(Direction face) { - return attachments[face.get3DDataValue()]; - } - - public void setEncased(boolean encased) { - this.encased = encased; - } - - public boolean isEncased() { - return encased; - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java deleted file mode 100644 index 9fbbfa84ee..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids; - -import java.util.Random; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.block.ProperWaterloggedBlock; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.network.protocol.game.DebugPackets; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SimpleWaterloggedBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraft.world.ticks.TickPriority; - -public class PumpBlock extends DirectionalKineticBlock - implements SimpleWaterloggedBlock, ICogWheel, ITE { - - public PumpBlock(Properties p_i48415_1_) { - super(p_i48415_1_); - registerDefaultState(super.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); - } - - @Override - public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { - return originalState.setValue(FACING, originalState.getValue(FACING) - .getOpposite()); - } - - @Override - public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { - return super.updateAfterWrenched(newState, context); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(FACING) - .getAxis(); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.PUMP.get(state.getValue(FACING)); - } - - @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block otherBlock, BlockPos neighborPos, - boolean isMoving) { - DebugPackets.sendNeighborsUpdatePacket(world, pos); - Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving); - if (d == null) - return; - if (!isOpenAt(state, d)) - return; - world.scheduleTick(pos, this, 1, TickPriority.HIGH); - } - - @Override - public FluidState getFluidState(BlockState state) { - return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) - : Fluids.EMPTY.defaultFluidState(); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(BlockStateProperties.WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, LevelAccessor world, - BlockPos pos, BlockPos neighbourPos) { - if (state.getValue(BlockStateProperties.WATERLOGGED)) - world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); - return state; - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState toPlace = super.getStateForPlacement(context); - Level level = context.getLevel(); - BlockPos pos = context.getClickedPos(); - Player player = context.getPlayer(); - toPlace = ProperWaterloggedBlock.withWater(level, toPlace, pos); - - if (player != null && player.isSteppingCarefully()) - return toPlace; - - for (Direction d : Iterate.directions) { - BlockPos adjPos = pos.relative(d); - BlockState adjState = level.getBlockState(adjPos); - if (!FluidPipeBlock.canConnectTo(level, adjPos, adjState, d)) - continue; - toPlace = toPlace.setValue(FACING, d); - if (context.getClickedFace() == d.getOpposite()) - break; - } - - return toPlace; - } - - public static boolean isPump(BlockState state) { - return state.getBlock() instanceof PumpBlock; - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, world, pos, oldState, isMoving); - if (world.isClientSide) - return; - if (state != oldState) - world.scheduleTick(pos, this, 1, TickPriority.HIGH); - - if (isPump(state) && isPump(oldState) && state.getValue(FACING) == oldState.getValue(FACING) - .getOpposite()) { - BlockEntity tileEntity = world.getBlockEntity(pos); - if (!(tileEntity instanceof PumpTileEntity)) - return; - PumpTileEntity pump = (PumpTileEntity) tileEntity; - pump.pressureUpdate = true; - } - } - - public static boolean isOpenAt(BlockState state, Direction d) { - return d.getAxis() == state.getValue(FACING) - .getAxis(); - } - - @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, Random r) { - FluidPropagator.propagateChangedPipe(world, pos, state); - } - - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - boolean blockTypeChanged = state.getBlock() != newState.getBlock(); - if (blockTypeChanged && !world.isClientSide) - FluidPropagator.propagateChangedPipe(world, pos, state); - if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) - world.removeBlockEntity(pos); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - public Class getTileEntityClass() { - return PumpTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_PUMP.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java deleted file mode 100644 index fcf24d94d8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpCogInstance.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class PumpCogInstance extends SingleRotatingInstance implements DynamicInstance { - - private final PumpTileEntity blockEntity = (PumpTileEntity) super.blockEntity; - private final ModelData[] arrows = new ModelData[2]; - private final Direction direction = blockState.getValue(PumpBlock.FACING); - - public PumpCogInstance(MaterialManager modelManager, PumpTileEntity tile) { - super(modelManager, tile); - } - - @Override - public void init() { - super.init(); - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.MECHANICAL_PUMP_ARROW, blockState) - .createInstances(arrows); - } - - @Override - public void beginFrame() { - float angle = Mth.lerp(blockEntity.arrowDirection.getValue(AnimationTickHolder.getPartialTicks()), 0, 90) - 90; - for (int i = 0, arrowsLength = arrows.length; i < arrowsLength; i++) { - arrows[i].loadIdentity() - .translate(getInstancePosition()) - .centre() - .rotateY(AngleHelper.horizontalAngle(direction) + 180) - .rotateX(-AngleHelper.verticalAngle(direction) - 90) - .unCentre() - .translate(.5, 14 / 16f, .5) - .rotateY(90 * i) - .rotateZ(angle) - .translateBack(.5, 14 / 16f, .5); - } - } - - @Override - public void updateLight() { - super.updateLight(); - relight(pos, arrows); - } - - @Override - protected Instancer getModel() { - BlockState referenceState = blockEntity.getBlockState(); - Direction facing = referenceState.getValue(BlockStateProperties.FACING); - return getRotatingMaterial().getModel(AllBlockPartials.MECHANICAL_PUMP_COG, referenceState, facing); - } - - @Override - public void remove() { - super.remove(); - - for (ModelData arrow : arrows) { - arrow.delete(); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java deleted file mode 100644 index 34336c0bf3..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class PumpRenderer extends KineticTileEntityRenderer { - - public PumpRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - if (Backend.canUseInstancing(te.getLevel())) return; - if (!(te instanceof PumpTileEntity pump)) - return; - Vec3 rotationOffset = new Vec3(.5, 14 / 16f, .5); - BlockState blockState = te.getBlockState(); - float angle = Mth.lerp(pump.arrowDirection.getValue(partialTicks), 0, 90) - 90; - SuperByteBuffer arrow = CachedPartialBuffers.partial(AllBlockPartials.MECHANICAL_PUMP_ARROW, blockState); - for (float yRot : new float[] { 0, 90 }) { - Direction direction = blockState.getValue(PumpBlock.FACING); - arrow.centre() - .rotateY(AngleHelper.horizontalAngle(direction) + 180) - .rotateX(-AngleHelper.verticalAngle(direction) - 90) - .unCentre() - .translate(rotationOffset) - .rotateY(yRot) - .rotateZ(angle) - .translateBack(rotationOffset); - - arrow.light(light).renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacing(AllBlockPartials.MECHANICAL_PUMP_COG, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java deleted file mode 100644 index 319827a5cd..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java +++ /dev/null @@ -1,397 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.mutable.MutableBoolean; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.BlockFace; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; - -public class PumpTileEntity extends KineticTileEntity { - - LerpedFloat arrowDirection; - Couple sidesToUpdate; - boolean pressureUpdate; - boolean reversed; - - public PumpTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - arrowDirection = LerpedFloat.linear() - .startWithValue(1); - sidesToUpdate = Couple.create(MutableBoolean::new); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - behaviours.add(new PumpFluidTransferBehaviour(this)); - registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); - registerAwardables(behaviours, AllAdvancements.PUMP); - } - - @Override - public void initialize() { - super.initialize(); - reversed = getSpeed() < 0; - } - - @Override - public void tick() { - super.tick(); - float speed = getSpeed(); - - if (level.isClientSide) { - if (speed == 0) - return; - arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP); - arrowDirection.tickChaser(); - if (!isVirtual()) - return; - } - -// if (pressureUpdate) -// updatePressureChange(); - - sidesToUpdate.forEachWithContext((update, isFront) -> { - if (update.isFalse()) - return; - update.setFalse(); - distributePressureTo(isFront ? getFront() : getFront().getOpposite()); - }); - - if (speed == 0) - return; - if (speed < 0 != reversed) { - reversed = speed < 0; - updatePressureChange(); - return; - } - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - - if (previousSpeed == getSpeed()) - return; - if (speed != 0) { - reversed = speed < 0; - award(AllAdvancements.PUMP); - } - if (level.isClientSide && !isVirtual()) - return; - - updatePressureChange(); - } - - public void updatePressureChange() { - pressureUpdate = false; - BlockPos frontPos = worldPosition.relative(getFront()); - BlockPos backPos = worldPosition.relative(getFront().getOpposite()); - FluidPropagator.propagateChangedPipe(level, frontPos, level.getBlockState(frontPos)); - FluidPropagator.propagateChangedPipe(level, backPos, level.getBlockState(backPos)); - - FluidTransportBehaviour behaviour = getBehaviour(FluidTransportBehaviour.TYPE); - if (behaviour != null) - behaviour.wipePressure(); - sidesToUpdate.forEach(MutableBoolean::setTrue); - } - - protected void distributePressureTo(Direction side) { - if (getSpeed() == 0) - return; - - BlockFace start = new BlockFace(worldPosition, side); - boolean pull = isPullingOnSide(isFront(side)); - Set targets = new HashSet<>(); - Map>> pipeGraph = new HashMap<>(); - - if (!pull) - FluidPropagator.resetAffectedFluidNetworks(level, worldPosition, side.getOpposite()); - - if (!hasReachedValidEndpoint(level, start, pull)) { - - pipeGraph.computeIfAbsent(worldPosition, $ -> Pair.of(0, new IdentityHashMap<>())) - .getSecond() - .put(side, pull); - pipeGraph.computeIfAbsent(start.getConnectedPos(), $ -> Pair.of(1, new IdentityHashMap<>())) - .getSecond() - .put(side.getOpposite(), !pull); - - List> frontier = new ArrayList<>(); - Set visited = new HashSet<>(); - int maxDistance = FluidPropagator.getPumpRange(); - frontier.add(Pair.of(1, start.getConnectedPos())); - - while (!frontier.isEmpty()) { - Pair entry = frontier.remove(0); - int distance = entry.getFirst(); - BlockPos currentPos = entry.getSecond(); - - if (!level.isLoaded(currentPos)) - continue; - if (visited.contains(currentPos)) - continue; - visited.add(currentPos); - BlockState currentState = level.getBlockState(currentPos); - FluidTransportBehaviour pipe = FluidPropagator.getPipe(level, currentPos); - if (pipe == null) - continue; - - for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) { - BlockFace blockFace = new BlockFace(currentPos, face); - BlockPos connectedPos = blockFace.getConnectedPos(); - - if (!level.isLoaded(connectedPos)) - continue; - if (blockFace.isEquivalent(start)) - continue; - if (hasReachedValidEndpoint(level, blockFace, pull)) { - pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) - .getSecond() - .put(face, pull); - targets.add(blockFace); - continue; - } - - FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(level, connectedPos); - if (pipeBehaviour == null) - continue; - if (pipeBehaviour instanceof PumpFluidTransferBehaviour) - continue; - if (visited.contains(connectedPos)) - continue; - if (distance + 1 >= maxDistance) { - pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) - .getSecond() - .put(face, pull); - targets.add(blockFace); - continue; - } - - pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) - .getSecond() - .put(face, pull); - pipeGraph.computeIfAbsent(connectedPos, $ -> Pair.of(distance + 1, new IdentityHashMap<>())) - .getSecond() - .put(face.getOpposite(), !pull); - frontier.add(Pair.of(distance + 1, connectedPos)); - } - } - } - - // DFS - Map> validFaces = new HashMap<>(); - searchForEndpointRecursively(pipeGraph, targets, validFaces, - new BlockFace(start.getPos(), start.getOppositeFace()), pull); - - float pressure = Math.abs(getSpeed()); - for (Set set : validFaces.values()) { - int parallelBranches = set.size(); - for (BlockFace face : set) { - BlockPos pipePos = face.getPos(); - Direction pipeSide = face.getFace(); - - if (pipePos.equals(worldPosition)) - continue; - - boolean inbound = pipeGraph.get(pipePos) - .getSecond() - .get(pipeSide); - FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(level, pipePos); - if (pipeBehaviour == null) - continue; - - pipeBehaviour.addPressure(pipeSide, inbound, pressure / parallelBranches); - } - } - - } - - protected boolean searchForEndpointRecursively(Map>> pipeGraph, - Set targets, Map> validFaces, BlockFace currentFace, boolean pull) { - BlockPos currentPos = currentFace.getPos(); - if (!pipeGraph.containsKey(currentPos)) - return false; - Pair> pair = pipeGraph.get(currentPos); - int distance = pair.getFirst(); - - boolean atLeastOneBranchSuccessful = false; - for (Direction nextFacing : Iterate.directions) { - if (nextFacing == currentFace.getFace()) - continue; - Map map = pair.getSecond(); - if (!map.containsKey(nextFacing)) - continue; - - BlockFace localTarget = new BlockFace(currentPos, nextFacing); - if (targets.contains(localTarget)) { - validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) - .add(localTarget); - atLeastOneBranchSuccessful = true; - continue; - } - - if (map.get(nextFacing) != pull) - continue; - if (!searchForEndpointRecursively(pipeGraph, targets, validFaces, - new BlockFace(currentPos.relative(nextFacing), nextFacing.getOpposite()), pull)) - continue; - - validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) - .add(localTarget); - atLeastOneBranchSuccessful = true; - } - - if (atLeastOneBranchSuccessful) - validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) - .add(currentFace); - - return atLeastOneBranchSuccessful; - } - - private boolean hasReachedValidEndpoint(LevelAccessor world, BlockFace blockFace, boolean pull) { - BlockPos connectedPos = blockFace.getConnectedPos(); - BlockState connectedState = world.getBlockState(connectedPos); - BlockEntity tileEntity = world.getBlockEntity(connectedPos); - Direction face = blockFace.getFace(); - - // facing a pump - if (PumpBlock.isPump(connectedState) && connectedState.getValue(PumpBlock.FACING) - .getAxis() == face.getAxis() && tileEntity instanceof PumpTileEntity) { - PumpTileEntity pumpTE = (PumpTileEntity) tileEntity; - return pumpTE.isPullingOnSide(pumpTE.isFront(blockFace.getOppositeFace())) != pull; - } - - // other pipe, no endpoint - FluidTransportBehaviour pipe = FluidPropagator.getPipe(world, connectedPos); - if (pipe != null && pipe.canHaveFlowToward(connectedState, blockFace.getOppositeFace())) - return false; - - // fluid handler endpoint - if (tileEntity != null) { - LazyOptional capability = - tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite()); - if (capability.isPresent()) - return true; - } - - // open endpoint - return FluidPropagator.isOpenEnd(world, blockFace.getPos(), face); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Reversed", reversed); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - reversed = compound.getBoolean("Reversed"); - super.read(compound, clientPacket); - } - - public void updatePipesOnSide(Direction side) { - if (!isSideAccessible(side)) - return; - updatePipeNetwork(isFront(side)); - getBehaviour(FluidTransportBehaviour.TYPE).wipePressure(); - } - - protected boolean isFront(Direction side) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof PumpBlock)) - return false; - Direction front = blockState.getValue(PumpBlock.FACING); - boolean isFront = side == front; - return isFront; - } - - @Nullable - protected Direction getFront() { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof PumpBlock)) - return null; - return blockState.getValue(PumpBlock.FACING); - } - - protected void updatePipeNetwork(boolean front) { - sidesToUpdate.get(front) - .setTrue(); - } - - public boolean isSideAccessible(Direction side) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof PumpBlock)) - return false; - return blockState.getValue(PumpBlock.FACING) - .getAxis() == side.getAxis(); - } - - public boolean isPullingOnSide(boolean front) { - return front == reversed; - } - - class PumpFluidTransferBehaviour extends FluidTransportBehaviour { - - public PumpFluidTransferBehaviour(SmartTileEntity te) { - super(te); - } - - @Override - public void tick() { - super.tick(); - for (Entry entry : interfaces.entrySet()) { - boolean pull = isPullingOnSide(isFront(entry.getKey())); - Couple pressure = entry.getValue().pressure; - pressure.set(pull, Math.abs(getSpeed())); - pressure.set(!pull, 0f); - } - } - - @Override - public boolean canHaveFlowToward(BlockState state, Direction direction) { - return isSideAccessible(direction); - } - - @Override - public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, - Direction direction) { - AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); - if (attachment == AttachmentTypes.RIM) - return AttachmentTypes.NONE; - return attachment; - } - - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java deleted file mode 100644 index e49bea738a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingBySpout.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.foundation.fluid.FluidIngredient; - -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.Level; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class FillingBySpout { - - static RecipeWrapper wrapper = new RecipeWrapper(new ItemStackHandler(1)); - - public static boolean canItemBeFilled(Level world, ItemStack stack) { - wrapper.setItem(0, stack); - - Optional assemblyRecipe = - SequencedAssemblyRecipe.getRecipe(world, wrapper, AllRecipeTypes.FILLING.getType(), FillingRecipe.class); - if (assemblyRecipe.isPresent()) - return true; - - if (AllRecipeTypes.FILLING.find(wrapper, world) - .isPresent()) - return true; - return GenericItemFilling.canItemBeFilled(world, stack); - } - - public static int getRequiredAmountForItem(Level world, ItemStack stack, FluidStack availableFluid) { - wrapper.setItem(0, stack); - - Optional assemblyRecipe = - SequencedAssemblyRecipe.getRecipe(world, wrapper, AllRecipeTypes.FILLING.getType(), FillingRecipe.class); - if (assemblyRecipe.isPresent()) { - FluidIngredient requiredFluid = assemblyRecipe.get() - .getRequiredFluid(); - if (requiredFluid.test(availableFluid)) - return requiredFluid.getRequiredAmount(); - } - - for (Recipe recipe : world.getRecipeManager() - .getRecipesFor(AllRecipeTypes.FILLING.getType(), wrapper, world)) { - FillingRecipe fillingRecipe = (FillingRecipe) recipe; - FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid(); - if (requiredFluid.test(availableFluid)) - return requiredFluid.getRequiredAmount(); - } - return GenericItemFilling.getRequiredAmountForItem(world, stack, availableFluid); - } - - public static ItemStack fillItem(Level world, int requiredAmount, ItemStack stack, FluidStack availableFluid) { - FluidStack toFill = availableFluid.copy(); - toFill.setAmount(requiredAmount); - - wrapper.setItem(0, stack); - - FillingRecipe fillingRecipe = - SequencedAssemblyRecipe.getRecipe(world, wrapper, AllRecipeTypes.FILLING.getType(), FillingRecipe.class) - .filter(fr -> fr.getRequiredFluid() - .test(toFill)) - .orElseGet(() -> { - for (Recipe recipe : world.getRecipeManager() - .getRecipesFor(AllRecipeTypes.FILLING.getType(), wrapper, world)) { - FillingRecipe fr = (FillingRecipe) recipe; - FluidIngredient requiredFluid = fr.getRequiredFluid(); - if (requiredFluid.test(toFill)) - return fr; - } - return null; - }); - - if (fillingRecipe != null) { - List results = fillingRecipe.rollResults(); - availableFluid.shrink(requiredAmount); - stack.shrink(1); - return results.isEmpty() ? ItemStack.EMPTY : results.get(0); - } - - return GenericItemFilling.fillItem(world, requiredAmount, stack, availableFluid); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidSplashPacket.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidSplashPacket.java deleted file mode 100644 index f6bd734b0e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidSplashPacket.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.fluids.FluidFX; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class FluidSplashPacket extends SimplePacketBase { - - private BlockPos pos; - private FluidStack fluid; - - public FluidSplashPacket(BlockPos pos, FluidStack fluid) { - this.pos = pos; - this.fluid = fluid; - } - - public FluidSplashPacket(FriendlyByteBuf buffer) { - pos = buffer.readBlockPos(); - fluid = buffer.readFluidStack(); - } - - public void write(FriendlyByteBuf buffer) { - buffer.writeBlockPos(pos); - buffer.writeFluidStack(fluid); - } - - public void handle(Supplier ctx) { - ctx.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - if (Minecraft.getInstance().player.position() - .distanceTo(new Vec3(pos.getX(), pos.getY(), pos.getZ())) > 100) - return; - FluidFX.splash(pos, fluid); - })); - ctx.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyBlock.java deleted file mode 100644 index f5a947704c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyBlock.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class HosePulleyBlock extends HorizontalKineticBlock implements ITE { - - public HosePulleyBlock(Properties properties) { - super(properties); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(HORIZONTAL_FACING) - .getClockWise() - .getAxis(); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - Direction preferredHorizontalFacing = getPreferredHorizontalFacing(context); - return this.defaultBlockState() - .setValue(HORIZONTAL_FACING, - preferredHorizontalFacing != null ? preferredHorizontalFacing.getCounterClockWise() - : context.getHorizontalDirection() - .getOpposite()); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return state.getValue(HORIZONTAL_FACING) - .getClockWise() == face; - } - - public static boolean hasPipeTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return state.getValue(HORIZONTAL_FACING) - .getCounterClockWise() == face; - } - - @Override - public Direction getPreferredHorizontalFacing(BlockPlaceContext context) { - Direction fromParent = super.getPreferredHorizontalFacing(context); - if (fromParent != null) - return fromParent; - - Direction prefferedSide = null; - for (Direction facing : Iterate.horizontalDirections) { - BlockPos pos = context.getClickedPos() - .relative(facing); - BlockState blockState = context.getLevel() - .getBlockState(pos); - if (FluidPipeBlock.canConnectTo(context.getLevel(), pos, blockState, facing)) - if (prefferedSide != null && prefferedSide.getAxis() != facing.getAxis()) { - prefferedSide = null; - break; - } else - prefferedSide = facing; - } - return prefferedSide == null ? null : prefferedSide.getOpposite(); - } - - @Override - public void onRemove(BlockState p_196243_1_, Level world, BlockPos pos, BlockState p_196243_4_, - boolean p_196243_5_) { - if (p_196243_1_.hasBlockEntity() - && (p_196243_1_.getBlock() != p_196243_4_.getBlock() || !p_196243_4_.hasBlockEntity())) { - TileEntityBehaviour.destroy(world, pos, FluidDrainingBehaviour.TYPE); - TileEntityBehaviour.destroy(world, pos, FluidFillingBehaviour.TYPE); - world.removeBlockEntity(pos); - } - } - - @Override - public Class getTileEntityClass() { - return HosePulleyTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.HOSE_PULLEY.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java deleted file mode 100644 index 8541aeb3fa..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyRenderer.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.pulley.AbstractPulleyRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction.Axis; - -public class HosePulleyRenderer extends AbstractPulleyRenderer { - - public HosePulleyRenderer(BlockEntityRendererProvider.Context context) { - super(context, AllBlockPartials.HOSE_HALF, AllBlockPartials.HOSE_HALF_MAGNET); - } - - @Override - protected Axis getShaftAxis(KineticTileEntity te) { - return te.getBlockState() - .getValue(HosePulleyBlock.HORIZONTAL_FACING) - .getClockWise() - .getAxis(); - } - - @Override - protected PartialModel getCoil() { - return AllBlockPartials.HOSE_COIL; - } - - @Override - protected SuperByteBuffer renderRope(KineticTileEntity te) { - return CachedPartialBuffers.partial(AllBlockPartials.HOSE, te.getBlockState()); - } - - @Override - protected SuperByteBuffer renderMagnet(KineticTileEntity te) { - return CachedPartialBuffers.partial(AllBlockPartials.HOSE_MAGNET, te.getBlockState()); - } - - @Override - protected float getOffset(KineticTileEntity te, float partialTicks) { - return ((HosePulleyTileEntity) te).getInterpolatedOffset(partialTicks); - } - - @Override - protected boolean isRunning(KineticTileEntity te) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java deleted file mode 100644 index 4f3e0ec8ae..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyTileEntity.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.fluid.SmartFluidTank; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; - -public class HosePulleyTileEntity extends KineticTileEntity { - - LerpedFloat offset; - boolean isMoving; - - private SmartFluidTank internalTank; - private LazyOptional capability; - private FluidDrainingBehaviour drainer; - private FluidFillingBehaviour filler; - private HosePulleyFluidHandler handler; - private boolean infinite; - - public HosePulleyTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - offset = LerpedFloat.linear() - .startWithValue(0); - isMoving = true; - internalTank = new SmartFluidTank(1500, this::onTankContentsChanged); - handler = new HosePulleyFluidHandler(internalTank, filler, drainer, - () -> worldPosition.below((int) Math.ceil(offset.getValue())), () -> !this.isMoving); - capability = LazyOptional.of(() -> handler); - } - - @Override - public void sendData() { - infinite = filler.infinite || drainer.infinite; - super.sendData(); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - boolean addToGoggleTooltip = super.addToGoggleTooltip(tooltip, isPlayerSneaking); - if (infinite) - TooltipHelper.addHint(tooltip, "hint.hose_pulley"); - return addToGoggleTooltip; - } - - @Override - public void addBehaviours(List behaviours) { - drainer = new FluidDrainingBehaviour(this); - filler = new FluidFillingBehaviour(this); - behaviours.add(drainer); - behaviours.add(filler); - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.HOSE_PULLEY, AllAdvancements.HOSE_PULLEY_LAVA); - } - - protected void onTankContentsChanged(FluidStack contents) {} - - @Override - public void onSpeedChanged(float previousSpeed) { - isMoving = true; - if (getSpeed() == 0) { - offset.forceNextSync(); - offset.setValue(Math.round(offset.getValue())); - isMoving = false; - } - - if (isMoving) { - float newOffset = offset.getValue() + getMovementSpeed(); - if (newOffset < 0) - isMoving = false; - if (!level.getBlockState(worldPosition.below((int) Math.ceil(newOffset))) - .getMaterial() - .isReplaceable()) { - isMoving = false; - } - if (isMoving) { - drainer.reset(); - filler.reset(); - } - } - - super.onSpeedChanged(previousSpeed); - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().expandTowards(0, -offset.getValue(), 0); - } - - @Override - public void tick() { - super.tick(); - float newOffset = offset.getValue() + getMovementSpeed(); - if (newOffset < 0) { - newOffset = 0; - isMoving = false; - } - if (!level.getBlockState(worldPosition.below((int) Math.ceil(newOffset))) - .getMaterial() - .isReplaceable()) { - newOffset = (int) newOffset; - isMoving = false; - } - if (getSpeed() == 0) - isMoving = false; - - offset.setValue(newOffset); - invalidateRenderBoundingBox(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (level.isClientSide) - return; - if (isMoving) - return; - - int ceil = (int) Math.ceil(offset.getValue() + getMovementSpeed()); - if (getMovementSpeed() > 0 && level.getBlockState(worldPosition.below(ceil)) - .getMaterial() - .isReplaceable()) { - isMoving = true; - drainer.reset(); - filler.reset(); - return; - } - - sendData(); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - compound.put("Offset", offset.writeNBT()); - compound.put("Tank", internalTank.writeToNBT(new CompoundTag())); - super.write(compound, clientPacket); - if (clientPacket) - compound.putBoolean("Infinite", infinite); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - offset.readNBT(compound.getCompound("Offset"), clientPacket); - internalTank.readFromNBT(compound.getCompound("Tank")); - super.read(compound, clientPacket); - if (clientPacket) - infinite = compound.getBoolean("Infinite"); - } - - @Override - public void setRemoved() { - super.setRemoved(); - capability.invalidate(); - } - - public float getMovementSpeed() { - float movementSpeed = convertToLinear(getSpeed()); - if (level.isClientSide) - movementSpeed *= ServerSpeedProvider.get(); - return movementSpeed; - } - - public float getInterpolatedOffset(float pt) { - return offset.getValue(pt); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isFluidHandlerCap(cap) - && (side == null || HosePulleyBlock.hasPipeTowards(level, worldPosition, getBlockState(), side))) - return this.capability.cast(); - return super.getCapability(cap, side); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java deleted file mode 100644 index e7a76079ad..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainBlock.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.tileEntity.ComparatorUtil; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.Containers; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; - -public class ItemDrainBlock extends Block implements IWrenchable, ITE { - - public ItemDrainBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - ItemStack heldItem = player.getItemInHand(handIn); - - if (heldItem.getItem() instanceof BlockItem - && !heldItem.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY) - .isPresent()) - return InteractionResult.PASS; - - return onTileEntityUse(worldIn, pos, te -> { - if (!heldItem.isEmpty()) { - te.internalTank.allowInsertion(); - InteractionResult tryExchange = tryExchange(worldIn, player, handIn, heldItem, te); - te.internalTank.forbidInsertion(); - if (tryExchange.consumesAction()) - return tryExchange; - } - - ItemStack heldItemStack = te.getHeldItemStack(); - if (!worldIn.isClientSide && !heldItemStack.isEmpty()) { - player.getInventory().placeItemBackInInventory(heldItemStack); - te.heldItem = null; - te.notifyUpdate(); - } - return InteractionResult.SUCCESS; - }); - } - - protected InteractionResult tryExchange(Level worldIn, Player player, InteractionHand handIn, ItemStack heldItem, - ItemDrainTileEntity te) { - if (FluidHelper.tryEmptyItemIntoTE(worldIn, player, handIn, heldItem, te)) - return InteractionResult.SUCCESS; - if (EmptyingByBasin.canItemBeEmptied(worldIn, heldItem)) - return InteractionResult.SUCCESS; - return InteractionResult.PASS; - } - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.CASING_13PX.get(Direction.UP); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) - return; - withTileEntityDo(worldIn, pos, te -> { - ItemStack heldItemStack = te.getHeldItemStack(); - if (!heldItemStack.isEmpty()) - Containers.dropItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), heldItemStack); - }); - worldIn.removeBlockEntity(pos); - } - - @Override - public Class getTileEntityClass() { - return ItemDrainTileEntity.class; - } - - @Override - public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { - super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); - AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ITEM_DRAIN.get(); - } - - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return ComparatorUtil.levelOfSmartFluidTank(worldIn, pos); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainItemHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainItemHandler.java deleted file mode 100644 index d04a6316a9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainItemHandler.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; - -import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -public class ItemDrainItemHandler implements IItemHandler { - - private ItemDrainTileEntity te; - private Direction side; - - public ItemDrainItemHandler(ItemDrainTileEntity te, Direction side) { - this.te = te; - this.side = side; - } - - @Override - public int getSlots() { - return 1; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return te.getHeldItemStack(); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (!te.getHeldItemStack() - .isEmpty()) - return stack; - - ItemStack returned = ItemStack.EMPTY; - if (stack.getCount() > 1 && EmptyingByBasin.canItemBeEmptied(te.getLevel(), stack)) { - returned = ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1); - stack = ItemHandlerHelper.copyStackWithSize(stack, 1); - } - - if (!simulate) { - TransportedItemStack heldItem = new TransportedItemStack(stack); - heldItem.prevBeltPosition = 0; - te.setHeldItem(heldItem, side.getOpposite()); - te.notifyUpdate(); - } - - return returned; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - TransportedItemStack held = te.heldItem; - if (held == null) - return ItemStack.EMPTY; - - ItemStack stack = held.stack.copy(); - ItemStack extracted = stack.split(amount); - if (!simulate) { - te.heldItem.stack = stack; - if (stack.isEmpty()) - te.heldItem = null; - te.notifyUpdate(); - } - return extracted; - } - - @Override - public int getSlotLimit(int slot) { - return 64; - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainTileEntity.java deleted file mode 100644 index aa62404120..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainTileEntity.java +++ /dev/null @@ -1,302 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.utility.BlockHelper; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.items.ItemHandlerHelper; - -public class ItemDrainTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - public static final int FILLING_TIME = 20; - - SmartFluidTankBehaviour internalTank; - TransportedItemStack heldItem; - protected int processingTicks; - Map> itemHandlers; - - public ItemDrainTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - itemHandlers = new IdentityHashMap<>(); - for (Direction d : Iterate.horizontalDirections) { - ItemDrainItemHandler itemDrainItemHandler = new ItemDrainItemHandler(this, d); - itemHandlers.put(d, LazyOptional.of(() -> itemDrainItemHandler)); - } - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(this).allowingBeltFunnels() - .setInsertionHandler(this::tryInsertingFromSide)); - behaviours.add(internalTank = SmartFluidTankBehaviour.single(this, 1500) - .allowExtraction() - .forbidInsertion()); - registerAwardables(behaviours, AllAdvancements.DRAIN, AllAdvancements.CHAINED_DRAIN); - } - - private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { - ItemStack inserted = transportedStack.stack; - ItemStack returned = ItemStack.EMPTY; - - if (!getHeldItemStack().isEmpty()) - return inserted; - - if (inserted.getCount() > 1 && EmptyingByBasin.canItemBeEmptied(level, inserted)) { - returned = ItemHandlerHelper.copyStackWithSize(inserted, inserted.getCount() - 1); - inserted = ItemHandlerHelper.copyStackWithSize(inserted, 1); - } - - if (simulate) - return returned; - - transportedStack = transportedStack.copy(); - transportedStack.stack = inserted.copy(); - transportedStack.beltPosition = side.getAxis() - .isVertical() ? .5f : 0; - transportedStack.prevSideOffset = transportedStack.sideOffset; - transportedStack.prevBeltPosition = transportedStack.beltPosition; - setHeldItem(transportedStack, side); - setChanged(); - sendData(); - - return returned; - } - - public ItemStack getHeldItemStack() { - return heldItem == null ? ItemStack.EMPTY : heldItem.stack; - } - - @Override - public void tick() { - super.tick(); - - if (heldItem == null) { - processingTicks = 0; - return; - } - - boolean onClient = level.isClientSide && !isVirtual(); - - if (processingTicks > 0) { - heldItem.prevBeltPosition = .5f; - boolean wasAtBeginning = processingTicks == FILLING_TIME; - if (!onClient || processingTicks < FILLING_TIME) - processingTicks--; - if (!continueProcessing()) { - processingTicks = 0; - notifyUpdate(); - return; - } - if (wasAtBeginning != (processingTicks == FILLING_TIME)) - sendData(); - return; - } - - heldItem.prevBeltPosition = heldItem.beltPosition; - heldItem.prevSideOffset = heldItem.sideOffset; - - heldItem.beltPosition += itemMovementPerTick(); - if (heldItem.beltPosition > 1) { - heldItem.beltPosition = 1; - - if (onClient) - return; - - Direction side = heldItem.insertedFrom; - - ItemStack tryExportingToBeltFunnel = getBehaviour(DirectBeltInputBehaviour.TYPE) - .tryExportingToBeltFunnel(heldItem.stack, side.getOpposite(), false); - if (tryExportingToBeltFunnel != null) { - if (tryExportingToBeltFunnel.getCount() != heldItem.stack.getCount()) { - if (tryExportingToBeltFunnel.isEmpty()) - heldItem = null; - else - heldItem.stack = tryExportingToBeltFunnel; - notifyUpdate(); - return; - } - if (!tryExportingToBeltFunnel.isEmpty()) - return; - } - - BlockPos nextPosition = worldPosition.relative(side); - DirectBeltInputBehaviour directBeltInputBehaviour = - TileEntityBehaviour.get(level, nextPosition, DirectBeltInputBehaviour.TYPE); - if (directBeltInputBehaviour == null) { - if (!BlockHelper.hasBlockSolidSide(level.getBlockState(nextPosition), level, nextPosition, - side.getOpposite())) { - ItemStack ejected = heldItem.stack; - Vec3 outPos = VecHelper.getCenterOf(worldPosition) - .add(Vec3.atLowerCornerOf(side.getNormal()) - .scale(.75)); - float movementSpeed = itemMovementPerTick(); - Vec3 outMotion = Vec3.atLowerCornerOf(side.getNormal()) - .scale(movementSpeed) - .add(0, 1 / 8f, 0); - outPos.add(outMotion.normalize()); - ItemEntity entity = new ItemEntity(level, outPos.x, outPos.y + 6 / 16f, outPos.z, ejected); - entity.setDeltaMovement(outMotion); - entity.setDefaultPickUpDelay(); - entity.hurtMarked = true; - level.addFreshEntity(entity); - - heldItem = null; - notifyUpdate(); - } - return; - } - - if (!directBeltInputBehaviour.canInsertFromSide(side)) - return; - - ItemStack returned = directBeltInputBehaviour.handleInsertion(heldItem.copy(), side, false); - - if (returned.isEmpty()) { - if (level.getBlockEntity(nextPosition) instanceof ItemDrainTileEntity) - award(AllAdvancements.CHAINED_DRAIN); - heldItem = null; - notifyUpdate(); - return; - } - - if (returned.getCount() != heldItem.stack.getCount()) { - heldItem.stack = returned; - notifyUpdate(); - return; - } - - return; - } - - if (heldItem.prevBeltPosition < .5f && heldItem.beltPosition >= .5f) { - if (!EmptyingByBasin.canItemBeEmptied(level, heldItem.stack)) - return; - heldItem.beltPosition = .5f; - if (onClient) - return; - processingTicks = FILLING_TIME; - sendData(); - } - - } - - protected boolean continueProcessing() { - if (level.isClientSide && !isVirtual()) - return true; - if (processingTicks < 5) - return true; - if (!EmptyingByBasin.canItemBeEmptied(level, heldItem.stack)) - return false; - - Pair emptyItem = EmptyingByBasin.emptyItem(level, heldItem.stack, true); - FluidStack fluidFromItem = emptyItem.getFirst(); - - if (processingTicks > 5) { - internalTank.allowInsertion(); - if (internalTank.getPrimaryHandler() - .fill(fluidFromItem, FluidAction.SIMULATE) != fluidFromItem.getAmount()) { - internalTank.forbidInsertion(); - processingTicks = FILLING_TIME; - return true; - } - internalTank.forbidInsertion(); - return true; - } - - emptyItem = EmptyingByBasin.emptyItem(level, heldItem.stack.copy(), false); - award(AllAdvancements.DRAIN); - - // Process finished - ItemStack out = emptyItem.getSecond(); - if (!out.isEmpty()) - heldItem.stack = out; - else - heldItem = null; - internalTank.allowInsertion(); - internalTank.getPrimaryHandler() - .fill(fluidFromItem, FluidAction.EXECUTE); - internalTank.forbidInsertion(); - notifyUpdate(); - return true; - } - - private float itemMovementPerTick() { - return 1 / 8f; - } - - @Override - public void setRemoved() { - super.setRemoved(); - for (LazyOptional lazyOptional : itemHandlers.values()) - lazyOptional.invalidate(); - } - - public void setHeldItem(TransportedItemStack heldItem, Direction insertedFrom) { - this.heldItem = heldItem; - this.heldItem.insertedFrom = insertedFrom; - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("ProcessingTicks", processingTicks); - if (heldItem != null) - compound.put("HeldItem", heldItem.serializeNBT()); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - heldItem = null; - processingTicks = compound.getInt("ProcessingTicks"); - if (compound.contains("HeldItem")) - heldItem = TransportedItemStack.read(compound.getCompound("HeldItem")); - super.read(compound, clientPacket); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (side != null && side.getAxis() - .isHorizontal() && isItemHandlerCap(cap)) - return itemHandlers.get(side) - .cast(); - - if (side != Direction.UP && isFluidHandlerCap(cap)) - return internalTank.getCapability() - .cast(); - - return super.getCapability(cap, side); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - return containedFluidTooltip(tooltip, isPlayerSneaking, getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java deleted file mode 100644 index b0264e0c8c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutBlock.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.ComparatorUtil; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -public class SpoutBlock extends Block implements IWrenchable, ITE { - - public SpoutBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - } - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.SPOUT; - } - - @Override - public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { - super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); - AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); - } - - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return ComparatorUtil.levelOfSmartFluidTank(worldIn, pos); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - public Class getTileEntityClass() { - return SpoutTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SPOUT.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java deleted file mode 100644 index 7bd5159dcb..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutRenderer.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.fluid.FluidRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.fluids.FluidStack; - -public class SpoutRenderer extends SafeTileEntityRenderer { - - public SpoutRenderer(BlockEntityRendererProvider.Context context) { - } - - static final PartialModel[] BITS = - { AllBlockPartials.SPOUT_TOP, AllBlockPartials.SPOUT_MIDDLE, AllBlockPartials.SPOUT_BOTTOM }; - - @Override - protected void renderSafe(SpoutTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - SmartFluidTankBehaviour tank = te.tank; - if (tank == null) - return; - - TankSegment primaryTank = tank.getPrimaryTank(); - FluidStack fluidStack = primaryTank.getRenderedFluid(); - float level = primaryTank.getFluidLevel() - .getValue(partialTicks); - - if (!fluidStack.isEmpty() && level != 0) { - level = Math.max(level, 0.175f); - float min = 2.5f / 16f; - float max = min + (11 / 16f); - float yOffset = (11 / 16f) * level; - ms.pushPose(); - ms.translate(0, yOffset, 0); - FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), min, min - yOffset, min, max, min, max, buffer, ms, light, - false); - ms.popPose(); - } - - int processingTicks = te.processingTicks; - float processingPT = processingTicks - partialTicks; - float processingProgress = 1 - (processingPT - 5) / 10; - processingProgress = Mth.clamp(processingProgress, 0, 1); - float radius = 0; - - if (processingTicks != -1) { - radius = (float) (Math.pow(((2 * processingProgress) - 1), 2) - 1); - AABB bb = new AABB(0.5, .5, 0.5, 0.5, -1.2, 0.5).inflate(radius / 32f); - FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), (float) bb.minX, (float) bb.minY, (float) bb.minZ, - (float) bb.maxX, (float) bb.maxY, (float) bb.maxZ, buffer, ms, light, true); - } - - float squeeze = radius; - if (processingPT < 0) - squeeze = 0; - else if (processingPT < 2) - squeeze = Mth.lerp(processingPT / 2f, 0, -1); - else if (processingPT < 10) - squeeze = -1; - - ms.pushPose(); - for (PartialModel bit : BITS) { - CachedPartialBuffers.partial(bit, te.getBlockState()) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - ms.translate(0, -3 * squeeze / 32f, 0); - } - ms.popPose(); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java deleted file mode 100644 index 9a2ef7ed9a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/SpoutTileEntity.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.actors; - -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.HOLD; -import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult.PASS; - -import java.util.ArrayList; -import java.util.List; - -import com.simibubi.create.AllItems; -import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; -import com.simibubi.create.content.contraptions.fluids.FluidFX; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; - -public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - public static final int FILLING_TIME = 20; - protected BeltProcessingBehaviour beltProcessing; - - public int processingTicks; - public boolean sendSplash; - public BlockSpoutingBehaviour customProcess; - - SmartFluidTankBehaviour tank; - - private boolean createdSweetRoll, createdHoneyApple, createdChocolateBerries; - - public SpoutTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - processingTicks = -1; - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().expandTowards(0, -2, 0); - } - - @Override - public void addBehaviours(List behaviours) { - tank = SmartFluidTankBehaviour.single(this, 1000); - behaviours.add(tank); - - beltProcessing = new BeltProcessingBehaviour(this).whenItemEnters(this::onItemReceived) - .whileItemHeld(this::whenItemHeld); - behaviours.add(beltProcessing); - - registerAwardables(behaviours, AllAdvancements.SPOUT, AllAdvancements.FOODS); - } - - protected ProcessingResult onItemReceived(TransportedItemStack transported, - TransportedItemStackHandlerBehaviour handler) { - if (handler.tileEntity.isVirtual()) - return PASS; - if (!FillingBySpout.canItemBeFilled(level, transported.stack)) - return PASS; - if (tank.isEmpty()) - return HOLD; - if (FillingBySpout.getRequiredAmountForItem(level, transported.stack, getCurrentFluidInTank()) == -1) - return PASS; - return HOLD; - } - - protected ProcessingResult whenItemHeld(TransportedItemStack transported, - TransportedItemStackHandlerBehaviour handler) { - if (processingTicks != -1 && processingTicks != 5) - return HOLD; - if (!FillingBySpout.canItemBeFilled(level, transported.stack)) - return PASS; - if (tank.isEmpty()) - return HOLD; - FluidStack fluid = getCurrentFluidInTank(); - int requiredAmountForItem = FillingBySpout.getRequiredAmountForItem(level, transported.stack, fluid.copy()); - if (requiredAmountForItem == -1) - return PASS; - if (requiredAmountForItem > fluid.getAmount()) - return HOLD; - - if (processingTicks == -1) { - processingTicks = FILLING_TIME; - notifyUpdate(); - return HOLD; - } - - // Process finished - ItemStack out = FillingBySpout.fillItem(level, requiredAmountForItem, transported.stack, fluid); - if (!out.isEmpty()) { - List outList = new ArrayList<>(); - TransportedItemStack held = null; - TransportedItemStack result = transported.copy(); - result.stack = out; - if (!transported.stack.isEmpty()) - held = transported.copy(); - outList.add(result); - handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(outList, held)); - } - - award(AllAdvancements.SPOUT); - if (trackFoods()) { - createdChocolateBerries |= AllItems.CHOCOLATE_BERRIES.isIn(out); - createdHoneyApple |= AllItems.HONEYED_APPLE.isIn(out); - createdSweetRoll |= AllItems.SWEET_ROLL.isIn(out); - if (createdChocolateBerries && createdHoneyApple && createdSweetRoll) - award(AllAdvancements.FOODS); - } - - tank.getPrimaryHandler() - .setFluid(fluid); - sendSplash = true; - notifyUpdate(); - return HOLD; - } - - private FluidStack getCurrentFluidInTank() { - return tank.getPrimaryHandler() - .getFluid(); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - - compound.putInt("ProcessingTicks", processingTicks); - if (sendSplash && clientPacket) { - compound.putBoolean("Splash", true); - sendSplash = false; - } - - if (!trackFoods()) - return; - if (createdChocolateBerries) - NBTHelper.putMarker(compound, "ChocolateBerries"); - if (createdHoneyApple) - NBTHelper.putMarker(compound, "HoneyApple"); - if (createdSweetRoll) - NBTHelper.putMarker(compound, "SweetRoll"); - } - - private boolean trackFoods() { - return getBehaviour(AdvancementBehaviour.TYPE).isOwnerPresent(); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - processingTicks = compound.getInt("ProcessingTicks"); - - createdChocolateBerries = compound.contains("ChocolateBerries"); - createdHoneyApple = compound.contains("HoneyApple"); - createdSweetRoll = compound.contains("SweetRoll"); - - if (!clientPacket) - return; - if (compound.contains("Splash")) - spawnSplash(tank.getPrimaryTank() - .getRenderedFluid()); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && side != Direction.DOWN) - return tank.getCapability() - .cast(); - return super.getCapability(cap, side); - } - - public void tick() { - super.tick(); - - FluidStack currentFluidInTank = getCurrentFluidInTank(); - if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) { - BlockSpoutingBehaviour.forEach(behaviour -> { - if (customProcess != null) - return; - if (behaviour.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, true) > 0) { - processingTicks = FILLING_TIME; - customProcess = behaviour; - notifyUpdate(); - } - }); - } - - if (processingTicks >= 0) { - processingTicks--; - if (processingTicks == 5 && customProcess != null) { - int fillBlock = customProcess.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, false); - customProcess = null; - if (fillBlock > 0) { - tank.getPrimaryHandler() - .setFluid(FluidHelper.copyStackWithAmount(currentFluidInTank, - currentFluidInTank.getAmount() - fillBlock)); - sendSplash = true; - notifyUpdate(); - } - } - } - - if (processingTicks >= 8 && level.isClientSide) - spawnProcessingParticles(tank.getPrimaryTank() - .getRenderedFluid()); - } - - protected void spawnProcessingParticles(FluidStack fluid) { - if (isVirtual()) - return; - Vec3 vec = VecHelper.getCenterOf(worldPosition); - vec = vec.subtract(0, 8 / 16f, 0); - ParticleOptions particle = FluidFX.getFluidParticle(fluid); - level.addAlwaysVisibleParticle(particle, vec.x, vec.y, vec.z, 0, -.1f, 0); - } - - protected static int SPLASH_PARTICLE_COUNT = 20; - - protected void spawnSplash(FluidStack fluid) { - if (isVirtual()) - return; - Vec3 vec = VecHelper.getCenterOf(worldPosition); - vec = vec.subtract(0, 2 - 5 / 16f, 0); - ParticleOptions particle = FluidFX.getFluidParticle(fluid); - for (int i = 0; i < SPLASH_PARTICLE_COUNT; i++) { - Vec3 m = VecHelper.offsetRandomly(Vec3.ZERO, level.random, 0.125f); - m = new Vec3(m.x, Math.abs(m.y), m.z); - level.addAlwaysVisibleParticle(particle, vec.x, vec.y, vec.z, m.x, m.y, m.z); - } - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - return containedFluidTooltip(tooltip, isPlayerSneaking, - getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java deleted file mode 100644 index 45e47834b8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/EncasedPipeBlock.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.DOWN; -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.EAST; -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.NORTH; -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.SOUTH; -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.UP; -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WEST; - -import java.util.Map; -import java.util.Random; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.protocol.game.DebugPackets; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.PipeBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.ticks.TickPriority; - -public class EncasedPipeBlock extends Block implements IWrenchable, ISpecialBlockItemRequirement, ITE { - - public static final Map FACING_TO_PROPERTY_MAP = PipeBlock.PROPERTY_BY_DIRECTION; - - public EncasedPipeBlock(Properties p_i48339_1_) { - super(p_i48339_1_); - registerDefaultState(defaultBlockState().setValue(NORTH, false) - .setValue(SOUTH, false) - .setValue(DOWN, false) - .setValue(UP, false) - .setValue(WEST, false) - .setValue(EAST, false)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN); - super.createBlockStateDefinition(builder); - } - - @Override - public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { - super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); - AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); - } - - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - boolean blockTypeChanged = state.getBlock() != newState.getBlock(); - if (blockTypeChanged && !world.isClientSide) - FluidPropagator.propagateChangedPipe(world, pos, state); - if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) - world.removeBlockEntity(pos); - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { - if (!world.isClientSide && state != oldState) - world.scheduleTick(pos, this, 1, TickPriority.HIGH); - } - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { - return AllBlocks.FLUID_PIPE.asStack(); - } - - @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block otherBlock, BlockPos neighborPos, - boolean isMoving) { - DebugPackets.sendNeighborsUpdatePacket(world, pos); - Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving); - if (d == null) - return; - if (!state.getValue(FACING_TO_PROPERTY_MAP.get(d))) - return; - world.scheduleTick(pos, this, 1, TickPriority.HIGH); - } - - @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, Random r) { - FluidPropagator.propagateChangedPipe(world, pos, state); - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - Level world = context.getLevel(); - BlockPos pos = context.getClickedPos(); - - if (world.isClientSide) - return InteractionResult.SUCCESS; - - context.getLevel() - .levelEvent(2001, context.getClickedPos(), Block.getId(state)); - BlockState equivalentPipe = transferSixWayProperties(state, AllBlocks.FLUID_PIPE.getDefaultState()); - - Direction firstFound = Direction.UP; - for (Direction d : Iterate.directions) - if (state.getValue(FACING_TO_PROPERTY_MAP.get(d))) { - firstFound = d; - break; - } - - FluidTransportBehaviour.cacheFlows(world, pos); - world.setBlockAndUpdate(pos, AllBlocks.FLUID_PIPE.get() - .updateBlockState(equivalentPipe, firstFound, null, world, pos)); - FluidTransportBehaviour.loadFlows(world, pos); - return InteractionResult.SUCCESS; - } - - public static BlockState transferSixWayProperties(BlockState from, BlockState to) { - for (Direction d : Iterate.directions) { - BooleanProperty property = FACING_TO_PROPERTY_MAP.get(d); - to = to.setValue(property, from.getValue(property)); - } - return to; - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return ItemRequirement.of(AllBlocks.FLUID_PIPE.getDefaultState(), te); - } - - @Override - public Class getTileEntityClass() { - return FluidPipeTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ENCASED_FLUID_PIPE.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeTileEntity.java deleted file mode 100644 index d3a238a7ac..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeTileEntity.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import java.util.List; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class FluidPipeTileEntity extends SmartTileEntity implements ITransformableTE { - - public FluidPipeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new StandardPipeFluidTransportBehaviour(this)); - behaviours.add(new BracketedTileEntityBehaviour(this, this::canHaveBracket)); - registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); - } - - @Override - public void transform(StructureTransform transform) { - BracketedTileEntityBehaviour bracketBehaviour = getBehaviour(BracketedTileEntityBehaviour.TYPE); - if (bracketBehaviour != null) { - bracketBehaviour.transformBracket(transform); - } - } - - private boolean canHaveBracket(BlockState state) { - return !(state.getBlock() instanceof EncasedPipeBlock); - } - - class StandardPipeFluidTransportBehaviour extends FluidTransportBehaviour { - - public StandardPipeFluidTransportBehaviour(SmartTileEntity te) { - super(te); - } - - @Override - public boolean canHaveFlowToward(BlockState state, Direction direction) { - return (FluidPipeBlock.isPipe(state) || state.getBlock() instanceof EncasedPipeBlock) - && state.getValue(FluidPipeBlock.PROPERTY_BY_DIRECTION.get(direction)); - } - - @Override - public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, - Direction direction) { - AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); - - BlockPos offsetPos = pos.relative(direction); - BlockState otherState = world.getBlockState(offsetPos); - - if (attachment == AttachmentTypes.RIM && !FluidPipeBlock.isPipe(otherState) - && !AllBlocks.MECHANICAL_PUMP.has(otherState) && !AllBlocks.ENCASED_FLUID_PIPE.has(otherState)) { - FluidTransportBehaviour pipeBehaviour = - TileEntityBehaviour.get(world, offsetPos, FluidTransportBehaviour.TYPE); - if (pipeBehaviour != null) - if (pipeBehaviour.canHaveFlowToward(otherState, direction.getOpposite())) - return AttachmentTypes.CONNECTION; - } - - if (attachment == AttachmentTypes.RIM && !FluidPipeBlock.shouldDrawRim(world, pos, state, direction)) - return AttachmentTypes.CONNECTION; - if (attachment == AttachmentTypes.NONE && state.getValue(FluidPipeBlock.PROPERTY_BY_DIRECTION.get(direction))) - return AttachmentTypes.CONNECTION; - return attachment; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java deleted file mode 100644 index e9e7efa513..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveInstance.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; - -public class FluidValveInstance extends ShaftInstance implements DynamicInstance { - - private final FluidValveTileEntity tile; - protected ModelData pointer; - - protected final double xRot; - protected final double yRot; - protected final int pointerRotationOffset; - - public FluidValveInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); - this.tile = (FluidValveTileEntity) tile; - - Direction facing = blockState.getValue(FluidValveBlock.FACING); - - yRot = AngleHelper.horizontalAngle(facing); - xRot = facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90; - - Direction.Axis pipeAxis = FluidValveBlock.getPipeAxis(blockState); - Direction.Axis shaftAxis = KineticTileEntityRenderer.getRotationAxisOf(tile); - - boolean twist = pipeAxis.isHorizontal() && shaftAxis == Direction.Axis.X || pipeAxis.isVertical(); - pointerRotationOffset = twist ? 90 : 0; - - pointer = materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.FLUID_VALVE_POINTER, blockState).createInstance(); - - transformPointer(); - } - - @Override - public void beginFrame() { - if (tile.pointer.settled()) return; - - transformPointer(); - } - - private void transformPointer() { - float pointerRotation = Mth.lerp(tile.pointer.getValue(AnimationTickHolder.getPartialTicks()), 0, -90); - - pointer.loadIdentity() - .translate(getInstancePosition()) - .centre() - .rotateY(yRot) - .rotateX(xRot) - .rotateY(pointerRotationOffset + pointerRotation) - .unCentre(); - } - - @Override - public void updateLight() { - super.updateLight(); - relight(pos, pointer); - } - - @Override - public void remove() { - super.remove(); - pointer.delete(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java deleted file mode 100644 index b62833d2de..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveRenderer.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class FluidValveRenderer extends KineticTileEntityRenderer { - - public FluidValveRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) return; - - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - BlockState blockState = te.getBlockState(); - SuperByteBuffer pointer = CachedPartialBuffers.partial(AllBlockPartials.FLUID_VALVE_POINTER, blockState); - Direction facing = blockState.getValue(FluidValveBlock.FACING); - - if (!(te instanceof FluidValveTileEntity valve)) - return; - - float pointerRotation = Mth.lerp(valve.pointer.getValue(partialTicks), 0, -90); - Axis pipeAxis = FluidValveBlock.getPipeAxis(blockState); - Axis shaftAxis = KineticTileEntityRenderer.getRotationAxisOf(te); - - int pointerRotationOffset; - if (pipeAxis.isHorizontal() && shaftAxis == Axis.X || pipeAxis.isVertical()) - pointerRotationOffset = 90; - else - pointerRotationOffset = 0; - - pointer.centre() - .rotateY(AngleHelper.horizontalAngle(facing)) - .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) - .rotateY(pointerRotationOffset + pointerRotation) - .unCentre(); - - pointer - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java deleted file mode 100644 index 2f932753bc..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveTileEntity.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeFluidTransportBehaviour; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.fluids.FluidStack; - -public class FluidValveTileEntity extends KineticTileEntity { - - LerpedFloat pointer; - - public FluidValveTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - pointer = LerpedFloat.linear() - .startWithValue(0) - .chase(0, 0, Chaser.LINEAR); - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - float speed = getSpeed(); - pointer.chase(speed > 0 ? 1 : 0, getChaseSpeed(), Chaser.LINEAR); - sendData(); - } - - @Override - public void tick() { - super.tick(); - pointer.tickChaser(); - - if (level.isClientSide) - return; - - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof FluidValveBlock)) - return; - boolean stateOpen = blockState.getValue(FluidValveBlock.ENABLED); - - if (stateOpen && pointer.getValue() == 0) { - switchToBlockState(level, worldPosition, blockState.setValue(FluidValveBlock.ENABLED, false)); - return; - } - if (!stateOpen && pointer.getValue() == 1) { - switchToBlockState(level, worldPosition, blockState.setValue(FluidValveBlock.ENABLED, true)); - return; - } - } - - private float getChaseSpeed() { - return Mth.clamp(Math.abs(getSpeed()) / 16 / 20, 0, 1); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.put("Pointer", pointer.writeNBT()); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - pointer.readNBT(compound.getCompound("Pointer"), clientPacket); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new ValvePipeBehaviour(this)); - registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); - } - - class ValvePipeBehaviour extends StraightPipeFluidTransportBehaviour { - - public ValvePipeBehaviour(SmartTileEntity te) { - super(te); - } - - @Override - public boolean canHaveFlowToward(BlockState state, Direction direction) { - return FluidValveBlock.getPipeAxis(state) == direction.getAxis(); - } - - @Override - public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) { - if (state.hasProperty(FluidValveBlock.ENABLED) && state.getValue(FluidValveBlock.ENABLED)) - return super.canPullFluidFrom(fluid, state, direction); - return false; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeTileEntity.java deleted file mode 100644 index ea218cc7da..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeTileEntity.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import java.util.List; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeFluidTransportBehaviour; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.AttachFace; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.fluids.FluidStack; - -public class SmartFluidPipeTileEntity extends SmartTileEntity { - - private FilteringBehaviour filter; - - public SmartFluidPipeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new SmartPipeBehaviour(this)); - behaviours.add(filter = new FilteringBehaviour(this, new SmartPipeFilterSlot()).forFluids() - .withCallback(this::onFilterChanged)); - registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); - } - - private void onFilterChanged(ItemStack newFilter) { - if (level.isClientSide) - return; - FluidPropagator.propagateChangedPipe(level, worldPosition, getBlockState()); - } - - class SmartPipeBehaviour extends StraightPipeFluidTransportBehaviour { - - public SmartPipeBehaviour(SmartTileEntity te) { - super(te); - } - - @Override - public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) { - if (fluid.isEmpty() || filter != null && filter.test(fluid)) - return super.canPullFluidFrom(fluid, state, direction); - return false; - } - - @Override - public boolean canHaveFlowToward(BlockState state, Direction direction) { - return state.getBlock() instanceof SmartFluidPipeBlock - && SmartFluidPipeBlock.getPipeAxis(state) == direction.getAxis(); - } - - } - - class SmartPipeFilterSlot extends ValueBoxTransform { - - @Override - protected Vec3 getLocalOffset(BlockState state) { - AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); - float y = face == AttachFace.CEILING ? 0.3f : face == AttachFace.WALL ? 11.3f : 15.3f; - float z = face == AttachFace.CEILING ? 4.6f : face == AttachFace.WALL ? 0.6f : 4.6f; - return VecHelper.rotateCentered(VecHelper.voxelSpace(8, y, z), angleY(state), Axis.Y); - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); - TransformStack.cast(ms) - .rotateY(angleY(state)) - .rotateX(face == AttachFace.CEILING ? -45 : 45); - } - - protected float angleY(BlockState state) { - AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); - float horizontalAngle = AngleHelper.horizontalAngle(state.getValue(SmartFluidPipeBlock.FACING)); - if (face == AttachFace.WALL) - horizontalAngle += 180; - return horizontalAngle; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/StraightPipeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/StraightPipeTileEntity.java deleted file mode 100644 index ec4101a095..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/StraightPipeTileEntity.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import java.util.List; - -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class StraightPipeTileEntity extends SmartTileEntity { - - public StraightPipeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new StraightPipeFluidTransportBehaviour(this)); - behaviours.add(new BracketedTileEntityBehaviour(this)); - registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); - } - - static class StraightPipeFluidTransportBehaviour extends FluidTransportBehaviour { - - public StraightPipeFluidTransportBehaviour(SmartTileEntity te) { - super(te); - } - - @Override - public boolean canHaveFlowToward(BlockState state, Direction direction) { - return state.hasProperty(AxisPipeBlock.AXIS) && state.getValue(AxisPipeBlock.AXIS) == direction.getAxis(); - } - - @Override - public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, - Direction direction) { - AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); - BlockState otherState = world.getBlockState(pos.relative(direction)); - - Axis axis = IAxisPipe.getAxisOf(state); - Axis otherAxis = IAxisPipe.getAxisOf(otherState); - - if (attachment == AttachmentTypes.RIM && state.getBlock() instanceof FluidValveBlock) - return AttachmentTypes.NONE; - if (attachment == AttachmentTypes.RIM && FluidPipeBlock.isPipe(otherState)) - return AttachmentTypes.PARTIAL_RIM; - if (axis == otherAxis && axis != null) - return AttachmentTypes.NONE; - - if (otherState.getBlock() instanceof FluidValveBlock - && FluidValveBlock.getPipeAxis(otherState) == direction.getAxis()) - return AttachmentTypes.NONE; - - return attachment.withoutConnector(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java deleted file mode 100644 index 307e7cee72..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/TransparentStraightPipeRenderer.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow; -import com.simibubi.create.foundation.fluid.FluidRenderer; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraftforge.fluids.FluidStack; - -public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer { - - public TransparentStraightPipeRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(StraightPipeTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - FluidTransportBehaviour pipe = te.getBehaviour(FluidTransportBehaviour.TYPE); - if (pipe == null) - return; - - for (Direction side : Iterate.directions) { - - Flow flow = pipe.getFlow(side); - if (flow == null) - continue; - FluidStack fluidStack = flow.fluid; - if (fluidStack.isEmpty()) - continue; - LerpedFloat progress = flow.progress; - if (progress == null) - continue; - - float value = progress.getValue(partialTicks); - boolean inbound = flow.inbound; - if (value == 1) { - if (inbound) { - Flow opposite = pipe.getFlow(side.getOpposite()); - if (opposite == null) - value -= 1e-6f; - } else { - FluidTransportBehaviour adjacent = TileEntityBehaviour.get(te.getLevel(), te.getBlockPos() - .relative(side), FluidTransportBehaviour.TYPE); - if (adjacent == null) - value -= 1e-6f; - else { - Flow other = adjacent.getFlow(side.getOpposite()); - if (other == null || !other.inbound && !other.complete) - value -= 1e-6f; - } - } - } - - FluidRenderer.renderFluidStream(fluidStack, side, 3 / 16f, value, inbound, buffer, ms, light); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/CreativeFluidTankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/CreativeFluidTankTileEntity.java deleted file mode 100644 index cae5e65b5d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/CreativeFluidTankTileEntity.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.tank; - -import java.util.List; -import java.util.function.Consumer; - -import com.simibubi.create.foundation.fluid.SmartFluidTank; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.fluids.FluidStack; - -public class CreativeFluidTankTileEntity extends FluidTankTileEntity { - - public CreativeFluidTankTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected SmartFluidTank createInventory() { - return new CreativeSmartFluidTank(getCapacityMultiplier(), this::onFluidStackChanged); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - return false; - } - - public static class CreativeSmartFluidTank extends SmartFluidTank { - - public CreativeSmartFluidTank(int capacity, Consumer updateCallback) { - super(capacity, updateCallback); - } - - @Override - public int getFluidAmount() { - return getFluid().isEmpty() ? 0 : getTankCapacity(0); - } - - public void setContainedFluid(FluidStack fluidStack) { - fluid = fluidStack.copy(); - if (!fluidStack.isEmpty()) - fluid.setAmount(getTankCapacity(0)); - onContentsChanged(); - } - - @Override - public int fill(FluidStack resource, FluidAction action) { - return resource.getAmount(); - } - - @Override - public FluidStack drain(FluidStack resource, FluidAction action) { - return super.drain(resource, FluidAction.SIMULATE); - } - - @Override - public FluidStack drain(int maxDrain, FluidAction action) { - return super.drain(maxDrain, FluidAction.SIMULATE); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankRenderer.java deleted file mode 100644 index a404380b39..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankRenderer.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.tank; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.fluid.FluidRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.templates.FluidTank; - -public class FluidTankRenderer extends SafeTileEntityRenderer { - - public FluidTankRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(FluidTankTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (!te.isController()) - return; - if (!te.window) { - if (te.boiler.isActive()) - renderAsBoiler(te, partialTicks, ms, buffer, light, overlay); - return; - } - - LerpedFloat fluidLevel = te.getFluidLevel(); - if (fluidLevel == null) - return; - - float capHeight = 1 / 4f; - float tankHullWidth = 1 / 16f + 1 / 128f; - float minPuddleHeight = 1 / 16f; - float totalHeight = te.height - 2 * capHeight - minPuddleHeight; - - float level = fluidLevel.getValue(partialTicks); - if (level < 1 / (512f * totalHeight)) - return; - float clampedLevel = Mth.clamp(level * totalHeight, 0, totalHeight); - - FluidTank tank = te.tankInventory; - FluidStack fluidStack = tank.getFluid(); - - if (fluidStack.isEmpty()) - return; - - boolean top = fluidStack.getFluid() - .getAttributes() - .isLighterThanAir(); - - float xMin = tankHullWidth; - float xMax = xMin + te.width - 2 * tankHullWidth; - float yMin = totalHeight + capHeight + minPuddleHeight - clampedLevel; - float yMax = yMin + clampedLevel; - - if (top) { - yMin += totalHeight - clampedLevel; - yMax += totalHeight - clampedLevel; - } - - float zMin = tankHullWidth; - float zMax = zMin + te.width - 2 * tankHullWidth; - - ms.pushPose(); - ms.translate(0, clampedLevel - totalHeight, 0); - FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false); - ms.popPose(); - } - - protected void renderAsBoiler(FluidTankTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - ms.pushPose(); - TransformStack msr = TransformStack.cast(ms); - msr.translate(te.width / 2f, 0.5, te.width / 2f); - - float dialPivot = 5.75f / 16; - float progress = te.boiler.gauge.getValue(partialTicks); - - for (Direction d : Iterate.horizontalDirections) { - ms.pushPose(); - CachedPartialBuffers.partial(AllBlockPartials.BOILER_GAUGE, blockState) - .rotate(Direction.Axis.Y, Mth.DEG_TO_RAD * d.toYRot()) - .translate(-.5, -.5, -.5) - .translate(te.width / 2f - 6 / 16f, 0, 0) - .light(light) - .renderInto(ms, vb); - CachedPartialBuffers.partial(AllBlockPartials.BOILER_GAUGE_DIAL, blockState) - .rotate(Direction.Axis.Y, Mth.DEG_TO_RAD * d.toYRot()) - .translate(-.5, -.5, -.5) - .translate(te.width / 2f - 6 / 16f, 0, 0) - .translate(0, dialPivot, dialPivot) - .rotate(Direction.Axis.X, Mth.DEG_TO_RAD * -90 * progress) - .translate(0, -dialPivot, -dialPivot) - .light(light) - .renderInto(ms, vb); - ms.popPose(); - } - - ms.popPose(); - } - - @Override - public boolean shouldRenderOffScreen(FluidTankTileEntity te) { - return te.isController(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java deleted file mode 100644 index 9bf82f8b5c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankTileEntity.java +++ /dev/null @@ -1,628 +0,0 @@ -package com.simibubi.create.content.contraptions.fluids.tank; - -import static java.lang.Math.abs; - -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import com.simibubi.create.api.connectivity.ConnectivityHandler; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.fluid.SmartFluidTank; -import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidAttributes; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.IFluidTank; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.fluids.capability.templates.FluidTank; - -public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleInformation, IMultiTileContainer.Fluid { - - private static final int MAX_SIZE = 3; - - protected LazyOptional fluidCapability; - protected boolean forceFluidLevelUpdate; - protected FluidTank tankInventory; - protected BlockPos controller; - protected BlockPos lastKnownPos; - protected boolean updateConnectivity; - protected boolean window; - protected int luminosity; - protected int width; - protected int height; - - public BoilerData boiler; - - private static final int SYNC_RATE = 8; - protected int syncCooldown; - protected boolean queuedSync; - - // For rendering purposes only - private LerpedFloat fluidLevel; - - public FluidTankTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - tankInventory = createInventory(); - fluidCapability = LazyOptional.of(() -> tankInventory); - forceFluidLevelUpdate = true; - updateConnectivity = false; - window = true; - height = 1; - width = 1; - boiler = new BoilerData(); - refreshCapability(); - } - - protected SmartFluidTank createInventory() { - return new SmartFluidTank(getCapacityMultiplier(), this::onFluidStackChanged); - } - - protected void updateConnectivity() { - updateConnectivity = false; - if (level.isClientSide) - return; - if (!isController()) - return; - ConnectivityHandler.formMulti(this); - } - - @Override - public void tick() { - super.tick(); - if (syncCooldown > 0) { - syncCooldown--; - if (syncCooldown == 0 && queuedSync) - sendData(); - } - - if (lastKnownPos == null) - lastKnownPos = getBlockPos(); - else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) { - onPositionChanged(); - return; - } - - if (updateConnectivity) - updateConnectivity(); - if (fluidLevel != null) - fluidLevel.tickChaser(); - if (isController()) - boiler.tick(this); - } - - @Override - public BlockPos getLastKnownPos() { - return lastKnownPos; - } - - @Override - public boolean isController() { - return controller == null || worldPosition.getX() == controller.getX() - && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); - } - - @Override - public void initialize() { - super.initialize(); - sendData(); - if (level.isClientSide) - invalidateRenderBoundingBox(); - } - - private void onPositionChanged() { - removeController(true); - lastKnownPos = worldPosition; - } - - protected void onFluidStackChanged(FluidStack newFluidStack) { - if (!hasLevel()) - return; - - FluidAttributes attributes = newFluidStack.getFluid() - .getAttributes(); - int luminosity = (int) (attributes.getLuminosity(newFluidStack) / 1.2f); - boolean reversed = attributes.isLighterThanAir(); - int maxY = (int) ((getFillState() * height) + 1); - - for (int yOffset = 0; yOffset < height; yOffset++) { - boolean isBright = reversed ? (height - yOffset <= maxY) : (yOffset < maxY); - int actualLuminosity = isBright ? luminosity : luminosity > 0 ? 1 : 0; - - for (int xOffset = 0; xOffset < width; xOffset++) { - for (int zOffset = 0; zOffset < width; zOffset++) { - BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset); - FluidTankTileEntity tankAt = ConnectivityHandler.partAt(getType(), level, pos); - if (tankAt == null) - continue; - level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState() - .getBlock()); - if (tankAt.luminosity == actualLuminosity) - continue; - tankAt.setLuminosity(actualLuminosity); - } - } - } - - if (!level.isClientSide) { - setChanged(); - sendData(); - } - - if (isVirtual()) { - if (fluidLevel == null) - fluidLevel = LerpedFloat.linear() - .startWithValue(getFillState()); - fluidLevel.chase(getFillState(), .5f, Chaser.EXP); - } - } - - protected void setLuminosity(int luminosity) { - if (level.isClientSide) - return; - if (this.luminosity == luminosity) - return; - this.luminosity = luminosity; - sendData(); - } - - @SuppressWarnings("unchecked") - @Override - public FluidTankTileEntity getControllerTE() { - if (isController()) - return this; - BlockEntity tileEntity = level.getBlockEntity(controller); - if (tileEntity instanceof FluidTankTileEntity) - return (FluidTankTileEntity) tileEntity; - return null; - } - - public void applyFluidTankSize(int blocks) { - tankInventory.setCapacity(blocks * getCapacityMultiplier()); - int overflow = tankInventory.getFluidAmount() - tankInventory.getCapacity(); - if (overflow > 0) - tankInventory.drain(overflow, FluidAction.EXECUTE); - forceFluidLevelUpdate = true; - } - - public void removeController(boolean keepFluids) { - if (level.isClientSide) - return; - updateConnectivity = true; - if (!keepFluids) - applyFluidTankSize(1); - controller = null; - width = 1; - height = 1; - boiler.clear(); - onFluidStackChanged(tankInventory.getFluid()); - - BlockState state = getBlockState(); - if (FluidTankBlock.isTank(state)) { - state = state.setValue(FluidTankBlock.BOTTOM, true); - state = state.setValue(FluidTankBlock.TOP, true); - state = state.setValue(FluidTankBlock.SHAPE, window ? Shape.WINDOW : Shape.PLAIN); - getLevel().setBlock(worldPosition, state, 22); - } - - refreshCapability(); - setChanged(); - sendData(); - } - - public void toggleWindows() { - FluidTankTileEntity te = getControllerTE(); - if (te == null) - return; - if (te.boiler.isActive()) - return; - te.setWindows(!te.window); - } - - public void updateBoilerTemperature() { - FluidTankTileEntity te = getControllerTE(); - if (te == null) - return; - if (!te.boiler.isActive()) - return; - te.boiler.needsHeatLevelUpdate = true; - } - - public void sendDataImmediately() { - syncCooldown = 0; - queuedSync = false; - sendData(); - } - - @Override - public void sendData() { - if (syncCooldown > 0) { - queuedSync = true; - return; - } - super.sendData(); - queuedSync = false; - syncCooldown = SYNC_RATE; - } - - public void setWindows(boolean window) { - this.window = window; - for (int yOffset = 0; yOffset < height; yOffset++) { - for (int xOffset = 0; xOffset < width; xOffset++) { - for (int zOffset = 0; zOffset < width; zOffset++) { - - BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset); - BlockState blockState = level.getBlockState(pos); - if (!FluidTankBlock.isTank(blockState)) - continue; - - Shape shape = Shape.PLAIN; - if (window) { - // SIZE 1: Every tank has a window - if (width == 1) - shape = Shape.WINDOW; - // SIZE 2: Every tank has a corner window - if (width == 2) - shape = xOffset == 0 ? zOffset == 0 ? Shape.WINDOW_NW : Shape.WINDOW_SW - : zOffset == 0 ? Shape.WINDOW_NE : Shape.WINDOW_SE; - // SIZE 3: Tanks in the center have a window - if (width == 3 && abs(abs(xOffset) - abs(zOffset)) == 1) - shape = Shape.WINDOW; - } - - level.setBlock(pos, blockState.setValue(FluidTankBlock.SHAPE, shape), 22); - level.getChunkSource() - .getLightEngine() - .checkBlock(pos); - } - } - } - } - - public void updateBoilerState() { - if (!isController()) - return; - - boolean wasBoiler = boiler.isActive(); - boolean changed = boiler.evaluate(this); - - if (wasBoiler != boiler.isActive()) { - if (boiler.isActive()) - setWindows(false); - - for (int yOffset = 0; yOffset < height; yOffset++) - for (int xOffset = 0; xOffset < width; xOffset++) - for (int zOffset = 0; zOffset < width; zOffset++) - if (level.getBlockEntity( - worldPosition.offset(xOffset, yOffset, zOffset))instanceof FluidTankTileEntity fte) - fte.refreshCapability(); - } - - if (changed) { - notifyUpdate(); - boiler.checkPipeOrganAdvancement(this); - } - } - - @Override - public void setController(BlockPos controller) { - if (level.isClientSide && !isVirtual()) - return; - if (controller.equals(this.controller)) - return; - this.controller = controller; - refreshCapability(); - setChanged(); - sendData(); - } - - private void refreshCapability() { - LazyOptional oldCap = fluidCapability; - fluidCapability = LazyOptional.of(() -> handlerForCapability()); - oldCap.invalidate(); - } - - private IFluidHandler handlerForCapability() { - return isController() ? boiler.isActive() ? boiler.createHandler() : tankInventory - : getControllerTE() != null ? getControllerTE().handlerForCapability() : new FluidTank(0); - } - - @Override - public BlockPos getController() { - return isController() ? worldPosition : controller; - } - - @Override - protected AABB createRenderBoundingBox() { - if (isController()) - return super.createRenderBoundingBox().expandTowards(width - 1, height - 1, width - 1); - else - return super.createRenderBoundingBox(); - } - - @Nullable - public FluidTankTileEntity getOtherFluidTankTileEntity(Direction direction) { - BlockEntity otherTE = level.getBlockEntity(worldPosition.relative(direction)); - if (otherTE instanceof FluidTankTileEntity) - return (FluidTankTileEntity) otherTE; - return null; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - FluidTankTileEntity controllerTE = getControllerTE(); - if (controllerTE == null) - return false; - if (controllerTE.boiler.addToGoggleTooltip(tooltip, isPlayerSneaking, controllerTE.getTotalTankSize())) - return true; - return containedFluidTooltip(tooltip, isPlayerSneaking, - controllerTE.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - - BlockPos controllerBefore = controller; - int prevSize = width; - int prevHeight = height; - int prevLum = luminosity; - - updateConnectivity = compound.contains("Uninitialized"); - luminosity = compound.getInt("Luminosity"); - controller = null; - lastKnownPos = null; - - if (compound.contains("LastKnownPos")) - lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos")); - if (compound.contains("Controller")) - controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); - - if (isController()) { - window = compound.getBoolean("Window"); - width = compound.getInt("Size"); - height = compound.getInt("Height"); - tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier()); - tankInventory.readFromNBT(compound.getCompound("TankContent")); - if (tankInventory.getSpace() < 0) - tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE); - } - - boiler.read(compound.getCompound("Boiler"), width * width * height); - - if (compound.contains("ForceFluidLevel") || fluidLevel == null) - fluidLevel = LerpedFloat.linear() - .startWithValue(getFillState()); - - if (!clientPacket) - return; - - boolean changeOfController = - controllerBefore == null ? controller != null : !controllerBefore.equals(controller); - if (changeOfController || prevSize != width || prevHeight != height) { - if (hasLevel()) - level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); - if (isController()) - tankInventory.setCapacity(getCapacityMultiplier() * getTotalTankSize()); - invalidateRenderBoundingBox(); - } - if (isController()) { - float fillState = getFillState(); - if (compound.contains("ForceFluidLevel") || fluidLevel == null) - fluidLevel = LerpedFloat.linear() - .startWithValue(fillState); - fluidLevel.chase(fillState, 0.5f, Chaser.EXP); - } - if (luminosity != prevLum && hasLevel()) - level.getChunkSource() - .getLightEngine() - .checkBlock(worldPosition); - - if (compound.contains("LazySync")) - fluidLevel.chase(fluidLevel.getChaseTarget(), 0.125f, Chaser.EXP); - } - - public float getFillState() { - return (float) tankInventory.getFluidAmount() / tankInventory.getCapacity(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (updateConnectivity) - compound.putBoolean("Uninitialized", true); - compound.put("Boiler", boiler.write()); - if (lastKnownPos != null) - compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos)); - if (!isController()) - compound.put("Controller", NbtUtils.writeBlockPos(controller)); - if (isController()) { - compound.putBoolean("Window", window); - compound.put("TankContent", tankInventory.writeToNBT(new CompoundTag())); - compound.putInt("Size", width); - compound.putInt("Height", height); - } - compound.putInt("Luminosity", luminosity); - super.write(compound, clientPacket); - - if (!clientPacket) - return; - if (forceFluidLevelUpdate) - compound.putBoolean("ForceFluidLevel", true); - if (queuedSync) - compound.putBoolean("LazySync", true); - forceFluidLevelUpdate = false; - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (!fluidCapability.isPresent()) - refreshCapability(); - if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) - return fluidCapability.cast(); - return super.getCapability(cap, side); - } - - @Override - public void setRemoved() { - super.setRemoved(); - } - - @Override - public void addBehaviours(List behaviours) { - registerAwardables(behaviours, AllAdvancements.STEAM_ENGINE_MAXED, AllAdvancements.PIPE_ORGAN); - } - - public IFluidTank getTankInventory() { - return tankInventory; - } - - public int getTotalTankSize() { - return width * width * height; - } - - public static int getMaxSize() { - return MAX_SIZE; - } - - public static int getCapacityMultiplier() { - return AllConfigs.SERVER.fluids.fluidTankCapacity.get() * 1000; - } - - public static int getMaxHeight() { - return AllConfigs.SERVER.fluids.fluidTankMaxHeight.get(); - } - - public LerpedFloat getFluidLevel() { - return fluidLevel; - } - - public void setFluidLevel(LerpedFloat fluidLevel) { - this.fluidLevel = fluidLevel; - } - - @Override - public void preventConnectivityUpdate() { - updateConnectivity = false; - } - - @Override - public void notifyMultiUpdated() { - BlockState state = this.getBlockState(); - if (FluidTankBlock.isTank(state)) { // safety - state = state.setValue(FluidTankBlock.BOTTOM, getController().getY() == getBlockPos().getY()); - state = state.setValue(FluidTankBlock.TOP, getController().getY() + height - 1 == getBlockPos().getY()); - level.setBlock(getBlockPos(), state, 6); - } - if (isController()) - setWindows(window); - onFluidStackChanged(tankInventory.getFluid()); - updateBoilerState(); - setChanged(); - } - - @Override - public void setExtraData(@Nullable Object data) { - if (data instanceof Boolean) - window = (boolean) data; - } - - @Override - @Nullable - public Object getExtraData() { - return window; - } - - @Override - public Object modifyExtraData(Object data) { - if (data instanceof Boolean windows) { - windows |= window; - return windows; - } - return data; - } - - @Override - public Direction.Axis getMainConnectionAxis() { - return Direction.Axis.Y; - } - - @Override - public int getMaxLength(Direction.Axis longAxis, int width) { - if (longAxis == Direction.Axis.Y) - return getMaxHeight(); - return getMaxWidth(); - } - - @Override - public int getMaxWidth() { - return MAX_SIZE; - } - - @Override - public int getHeight() { - return height; - } - - @Override - public void setHeight(int height) { - this.height = height; - } - - @Override - public int getWidth() { - return width; - } - - @Override - public void setWidth(int width) { - this.width = width; - } - - @Override - public boolean hasTank() { - return true; - } - - @Override - public int getTankSize(int tank) { - return getCapacityMultiplier(); - } - - @Override - public void setTankSize(int tank, int blocks) { - applyFluidTankSize(blocks); - } - - @Override - public IFluidTank getTank(int tank) { - return tankInventory; - } - - @Override - public FluidStack getFluid(int tank) { - return tankInventory.getFluid() - .copy(); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlock.java index cff65aee1f..9192921226 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryCarriageBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlock.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.gantry; +package com.simibubi.create.content.contraptions.gantry; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlock; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -23,7 +23,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements ITE { +public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements IBE { public GantryCarriageBlock(Properties properties) { super(properties); @@ -40,7 +40,7 @@ public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements @Override public void updateIndirectNeighbourShapes(BlockState stateIn, LevelAccessor worldIn, BlockPos pos, int flags, int count) { super.updateIndirectNeighbourShapes(stateIn, worldIn, pos, flags, count); - withTileEntityDo(worldIn, pos, GantryCarriageTileEntity::checkValidGantryShaft); + withBlockEntityDo(worldIn, pos, GantryCarriageBlockEntity::checkValidGantryShaft); } @Override @@ -59,7 +59,7 @@ public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements return InteractionResult.PASS; if (player.getItemInHand(handIn) .isEmpty()) { - withTileEntityDo(worldIn, pos, te -> te.checkValidGantryShaft()); + withBlockEntityDo(worldIn, pos, be -> be.checkValidGantryShaft()); return InteractionResult.SUCCESS; } return InteractionResult.PASS; @@ -130,13 +130,13 @@ public class GantryCarriageBlock extends DirectionalAxisKineticBlock implements } @Override - public Class getTileEntityClass() { - return GantryCarriageTileEntity.class; + public Class getBlockEntityClass() { + return GantryCarriageBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.GANTRY_PINION.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.GANTRY_PINION.get(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlockEntity.java new file mode 100644 index 0000000000..540ba53abe --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageBlockEntity.java @@ -0,0 +1,192 @@ +package com.simibubi.create.content.contraptions.gantry; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionCollider; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlock; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlockEntity; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencerInstructions; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class GantryCarriageBlockEntity extends KineticBlockEntity implements IDisplayAssemblyExceptions { + + boolean assembleNextTick; + protected AssemblyException lastException; + + public GantryCarriageBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + } + + public void checkValidGantryShaft() { + if (shouldAssemble()) + queueAssembly(); + } + + @Override + public void initialize() { + super.initialize(); + if (!getBlockState().canSurvive(level, worldPosition)) + level.destroyBlock(worldPosition, true); + } + + public void queueAssembly() { + assembleNextTick = true; + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) + return; + + if (assembleNextTick) { + tryAssemble(); + assembleNextTick = false; + } + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + + private void tryAssemble() { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof GantryCarriageBlock)) + return; + + Direction direction = blockState.getValue(GantryCarriageBlock.FACING); + GantryContraption contraption = new GantryContraption(direction); + + BlockEntity blockEntity = level.getBlockEntity(worldPosition.relative(direction.getOpposite())); + if (!(blockEntity instanceof GantryShaftBlockEntity shaftBE)) + return; + BlockState shaftState = shaftBE.getBlockState(); + if (!AllBlocks.GANTRY_SHAFT.has(shaftState)) + return; + + float pinionMovementSpeed = shaftBE.getPinionMovementSpeed(); + Direction shaftOrientation = shaftState.getValue(GantryShaftBlock.FACING); + Direction movementDirection = shaftOrientation; + if (pinionMovementSpeed < 0) + movementDirection = movementDirection.getOpposite(); + + try { + lastException = null; + if (!contraption.assemble(level, worldPosition)) + return; + + sendData(); + } catch (AssemblyException e) { + lastException = e; + sendData(); + return; + } + if (ContraptionCollider.isCollidingWithWorld(level, contraption, worldPosition.relative(movementDirection), + movementDirection)) + return; + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + + contraption.removeBlocksFromWorld(level, BlockPos.ZERO); + GantryContraptionEntity movedContraption = + GantryContraptionEntity.create(level, contraption, shaftOrientation); + BlockPos anchor = worldPosition; + movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); + level.addFreshEntity(movedContraption); + + if (shaftBE.sequenceContext != null + && shaftBE.sequenceContext.instruction() == SequencerInstructions.TURN_DISTANCE) + movedContraption.limitMovement(shaftBE.sequenceContext.getEffectiveValue(shaftBE.getTheoreticalSpeed())); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + } + + @Override + public float propagateRotationTo(KineticBlockEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, + boolean connectedViaAxes, boolean connectedViaCogs) { + float defaultModifier = + super.propagateRotationTo(target, stateFrom, stateTo, diff, connectedViaAxes, connectedViaCogs); + + if (connectedViaAxes) + return defaultModifier; + if (!AllBlocks.GANTRY_SHAFT.has(stateTo)) + return defaultModifier; + if (!stateTo.getValue(GantryShaftBlock.POWERED)) + return defaultModifier; + + Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); + if (stateFrom.getValue(GantryCarriageBlock.FACING) != direction.getOpposite()) + return defaultModifier; + return getGantryPinionModifier(stateTo.getValue(GantryShaftBlock.FACING), stateFrom.getValue(GantryCarriageBlock.FACING)); + } + + public static float getGantryPinionModifier(Direction shaft, Direction pinionDirection) { + Axis shaftAxis = shaft.getAxis(); + float directionModifier = shaft.getAxisDirection() + .getStep(); + if (shaftAxis == Axis.Y) + if (pinionDirection == Direction.NORTH || pinionDirection == Direction.EAST) + return -directionModifier; + if (shaftAxis == Axis.X) + if (pinionDirection == Direction.DOWN || pinionDirection == Direction.SOUTH) + return -directionModifier; + if (shaftAxis == Axis.Z) + if (pinionDirection == Direction.UP || pinionDirection == Direction.WEST) + return -directionModifier; + return directionModifier; + } + + private boolean shouldAssemble() { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof GantryCarriageBlock)) + return false; + Direction facing = blockState.getValue(GantryCarriageBlock.FACING) + .getOpposite(); + BlockState shaftState = level.getBlockState(worldPosition.relative(facing)); + if (!(shaftState.getBlock() instanceof GantryShaftBlock)) + return false; + if (shaftState.getValue(GantryShaftBlock.POWERED)) + return false; + BlockEntity be = level.getBlockEntity(worldPosition.relative(facing)); + return be instanceof GantryShaftBlockEntity && ((GantryShaftBlockEntity) be).canAssembleOn(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageInstance.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageInstance.java new file mode 100644 index 0000000000..27ca09f611 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageInstance.java @@ -0,0 +1,104 @@ +package com.simibubi.create.content.contraptions.gantry; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; + +public class GantryCarriageInstance extends ShaftInstance implements DynamicInstance { + + private final ModelData gantryCogs; + + final Direction facing; + final Boolean alongFirst; + final Direction.Axis rotationAxis; + final float rotationMult; + final BlockPos visualPos; + + private float lastAngle = Float.NaN; + + public GantryCarriageInstance(MaterialManager materialManager, GantryCarriageBlockEntity blockEntity) { + super(materialManager, blockEntity); + + gantryCogs = getTransformMaterial() + .getModel(AllPartialModels.GANTRY_COGS, blockState) + .createInstance(); + + facing = blockState.getValue(GantryCarriageBlock.FACING); + alongFirst = blockState.getValue(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); + rotationAxis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity); + + rotationMult = getRotationMultiplier(getGantryAxis(), facing); + + visualPos = facing.getAxisDirection() == Direction.AxisDirection.POSITIVE ? blockEntity.getBlockPos() + : blockEntity.getBlockPos() + .relative(facing.getOpposite()); + + animateCogs(getCogAngle()); + } + + @Override + public void beginFrame() { + float cogAngle = getCogAngle(); + + if (Mth.equal(cogAngle, lastAngle)) return; + + animateCogs(cogAngle); + } + + private float getCogAngle() { + return GantryCarriageRenderer.getAngleForBE(blockEntity, visualPos, rotationAxis) * rotationMult; + } + + private void animateCogs(float cogAngle) { + gantryCogs.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) + .rotateY(alongFirst ^ facing.getAxis() == Direction.Axis.X ? 0 : 90) + .translate(0, -9 / 16f, 0) + .rotateX(-cogAngle) + .translate(0, 9 / 16f, 0) + .unCentre(); + } + + static float getRotationMultiplier(Direction.Axis gantryAxis, Direction facing) { + float multiplier = 1; + if (gantryAxis == Direction.Axis.X) + if (facing == Direction.UP) + multiplier *= -1; + if (gantryAxis == Direction.Axis.Y) + if (facing == Direction.NORTH || facing == Direction.EAST) + multiplier *= -1; + + return multiplier; + } + + private Direction.Axis getGantryAxis() { + Direction.Axis gantryAxis = Direction.Axis.X; + for (Direction.Axis axis : Iterate.axes) + if (axis != rotationAxis && axis != facing.getAxis()) + gantryAxis = axis; + return gantryAxis; + } + + @Override + public void updateLight() { + relight(pos, gantryCogs, rotatingModel); + } + + @Override + public void remove() { + super.remove(); + gantryCogs.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageRenderer.java new file mode 100644 index 0000000000..2c40a27a86 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryCarriageRenderer.java @@ -0,0 +1,83 @@ +package com.simibubi.create.content.contraptions.gantry; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.block.state.BlockState; + +public class GantryCarriageRenderer extends KineticBlockEntityRenderer { + + public GantryCarriageRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(GantryCarriageBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) return; + + BlockState state = be.getBlockState(); + Direction facing = state.getValue(GantryCarriageBlock.FACING); + Boolean alongFirst = state.getValue(GantryCarriageBlock.AXIS_ALONG_FIRST_COORDINATE); + Axis rotationAxis = getRotationAxisOf(be); + BlockPos visualPos = facing.getAxisDirection() == AxisDirection.POSITIVE ? be.getBlockPos() + : be.getBlockPos() + .relative(facing.getOpposite()); + float angleForBE = getAngleForBE(be, visualPos, rotationAxis); + + Axis gantryAxis = Axis.X; + for (Axis axis : Iterate.axes) + if (axis != rotationAxis && axis != facing.getAxis()) + gantryAxis = axis; + + if (gantryAxis == Axis.X) + if (facing == Direction.UP) + angleForBE *= -1; + if (gantryAxis == Axis.Y) + if (facing == Direction.NORTH || facing == Direction.EAST) + angleForBE *= -1; + + SuperByteBuffer cogs = CachedPartialBuffers.partial(AllPartialModels.GANTRY_COGS, state); + cogs.centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) + .rotateY(alongFirst ^ facing.getAxis() == Axis.X ? 0 : 90) + .translate(0, -9 / 16f, 0) + .rotateX(-angleForBE) + .translate(0, 9 / 16f, 0) + .unCentre(); + + cogs.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + + } + + public static float getAngleForBE(KineticBlockEntity be, final BlockPos pos, Axis axis) { + float time = WorldTickHolder.getRenderTime(be.getLevel()); + float offset = getRotationOffsetForPosition(be, pos, axis); + return (time * be.getSpeed() * 3f / 20 + offset) % 360; + } + + @Override + protected BlockState getRenderedBlockState(GantryCarriageBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraption.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraption.java new file mode 100644 index 0000000000..5b66790d9b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraption.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.contraptions.gantry; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.TranslatingContraption; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.NonStationaryLighter; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class GantryContraption extends TranslatingContraption { + + protected Direction facing; + + public GantryContraption() {} + + public GantryContraption(Direction facing) { + this.facing = facing; + } + + @Override + public boolean assemble(Level world, BlockPos pos) throws AssemblyException { + if (!searchMovedStructure(world, pos, null)) + return false; + startMoving(world); + return true; + } + + @Override + public CompoundTag writeNBT(boolean spawnPacket) { + CompoundTag tag = super.writeNBT(spawnPacket); + tag.putInt("Facing", facing.get3DDataValue()); + return tag; + } + + @Override + public void readNBT(Level world, CompoundTag tag, boolean spawnData) { + facing = Direction.from3DDataValue(tag.getInt("Facing")); + super.readNBT(world, tag, spawnData); + } + + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return super.isAnchoringBlockAt(pos.relative(facing)); + } + + @Override + public ContraptionType getType() { + return ContraptionType.GANTRY; + } + + public Direction getFacing() { + return facing; + } + + @Override + protected boolean shouldUpdateAfterMovement(StructureBlockInfo info) { + return super.shouldUpdateAfterMovement(info) && !AllBlocks.GANTRY_CARRIAGE.has(info.state); + } + + @Override + @OnlyIn(Dist.CLIENT) + public ContraptionLighter makeLighter() { + return new NonStationaryLighter<>(this); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionEntity.java new file mode 100644 index 0000000000..cb12f022c9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionEntity.java @@ -0,0 +1,241 @@ +package com.simibubi.create.content.contraptions.gantry; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionCollider; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlock; +import com.simibubi.create.content.kinetics.gantry.GantryShaftBlockEntity; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.network.PacketDistributor; + +public class GantryContraptionEntity extends AbstractContraptionEntity { + + Direction movementAxis; + double clientOffsetDiff; + double axisMotion; + + public double sequencedOffsetLimit; + + public GantryContraptionEntity(EntityType entityTypeIn, Level worldIn) { + super(entityTypeIn, worldIn); + sequencedOffsetLimit = -1; + } + + public static GantryContraptionEntity create(Level world, Contraption contraption, Direction movementAxis) { + GantryContraptionEntity entity = new GantryContraptionEntity(AllEntityTypes.GANTRY_CONTRAPTION.get(), world); + entity.setContraption(contraption); + entity.movementAxis = movementAxis; + return entity; + } + + public void limitMovement(double maxOffset) { + sequencedOffsetLimit = maxOffset; + } + + @Override + protected void tickContraption() { + if (!(contraption instanceof GantryContraption)) + return; + + double prevAxisMotion = axisMotion; + if (level.isClientSide) { + clientOffsetDiff *= .75f; + updateClientMotion(); + } + + checkPinionShaft(); + tickActors(); + Vec3 movementVec = getDeltaMovement(); + + if (ContraptionCollider.collideBlocks(this)) { + if (!level.isClientSide) + disassemble(); + return; + } + + if (!isStalled() && tickCount > 2) { + if (sequencedOffsetLimit >= 0) + movementVec = VecHelper.clampComponentWise(movementVec, (float) sequencedOffsetLimit); + move(movementVec.x, movementVec.y, movementVec.z); + if (sequencedOffsetLimit > 0) + sequencedOffsetLimit = Math.max(0, sequencedOffsetLimit - movementVec.length()); + } + + if (Math.signum(prevAxisMotion) != Math.signum(axisMotion) && prevAxisMotion != 0) + contraption.stop(level); + if (!level.isClientSide && (prevAxisMotion != axisMotion || tickCount % 3 == 0)) + sendPacket(); + } + + @Override + public void disassemble() { + sequencedOffsetLimit = -1; + super.disassemble(); + } + + protected void checkPinionShaft() { + Vec3 movementVec; + Direction facing = ((GantryContraption) contraption).getFacing(); + Vec3 currentPosition = getAnchorVec().add(.5, .5, .5); + BlockPos gantryShaftPos = new BlockPos(currentPosition).relative(facing.getOpposite()); + + BlockEntity be = level.getBlockEntity(gantryShaftPos); + if (!(be instanceof GantryShaftBlockEntity) || !AllBlocks.GANTRY_SHAFT.has(be.getBlockState())) { + if (!level.isClientSide) { + setContraptionMotion(Vec3.ZERO); + disassemble(); + } + return; + } + + BlockState blockState = be.getBlockState(); + Direction direction = blockState.getValue(GantryShaftBlock.FACING); + GantryShaftBlockEntity gantryShaftBlockEntity = (GantryShaftBlockEntity) be; + + float pinionMovementSpeed = gantryShaftBlockEntity.getPinionMovementSpeed(); + if (blockState.getValue(GantryShaftBlock.POWERED) || pinionMovementSpeed == 0) { + setContraptionMotion(Vec3.ZERO); + if (!level.isClientSide) + disassemble(); + return; + } + + if (sequencedOffsetLimit >= 0) + pinionMovementSpeed = (float) Mth.clamp(pinionMovementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); + movementVec = Vec3.atLowerCornerOf(direction.getNormal()) + .scale(pinionMovementSpeed); + + Vec3 nextPosition = currentPosition.add(movementVec); + double currentCoord = direction.getAxis() + .choose(currentPosition.x, currentPosition.y, currentPosition.z); + double nextCoord = direction.getAxis() + .choose(nextPosition.x, nextPosition.y, nextPosition.z); + + if ((Mth.floor(currentCoord) + .5f < nextCoord != (pinionMovementSpeed * direction.getAxisDirection() + .getStep() < 0))) + if (!gantryShaftBlockEntity.canAssembleOn()) { + setContraptionMotion(Vec3.ZERO); + if (!level.isClientSide) + disassemble(); + return; + } + + if (level.isClientSide) + return; + + axisMotion = pinionMovementSpeed; + setContraptionMotion(movementVec); + } + + @Override + protected void writeAdditional(CompoundTag compound, boolean spawnPacket) { + NBTHelper.writeEnum(compound, "GantryAxis", movementAxis); + if (sequencedOffsetLimit >= 0) + compound.putDouble("SequencedOffsetLimit", sequencedOffsetLimit); + super.writeAdditional(compound, spawnPacket); + } + + protected void readAdditional(CompoundTag compound, boolean spawnData) { + movementAxis = NBTHelper.readEnum(compound, "GantryAxis", Direction.class); + sequencedOffsetLimit = + compound.contains("SequencedOffsetLimit") ? compound.getDouble("SequencedOffsetLimit") : -1; + super.readAdditional(compound, spawnData); + } + + @Override + public Vec3 applyRotation(Vec3 localPos, float partialTicks) { + return localPos; + } + + @Override + public Vec3 reverseRotation(Vec3 localPos, float partialTicks) { + return localPos; + } + + @Override + protected StructureTransform makeStructureTransform() { + return new StructureTransform(new BlockPos(getAnchorVec().add(.5, .5, .5)), 0, 0, 0); + } + + @Override + protected float getStalledAngle() { + return 0; + } + + @Override + public void teleportTo(double p_70634_1_, double p_70634_3_, double p_70634_5_) {} + + @Override + @OnlyIn(Dist.CLIENT) + public void lerpTo(double x, double y, double z, float yw, float pt, int inc, boolean t) {} + + @Override + protected void handleStallInformation(double x, double y, double z, float angle) { + setPosRaw(x, y, z); + clientOffsetDiff = 0; + } + + @Override + public ContraptionRotationState getRotationState() { + return ContraptionRotationState.NONE; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) {} + + public void updateClientMotion() { + float modifier = movementAxis.getAxisDirection() + .getStep(); + Vec3 motion = Vec3.atLowerCornerOf(movementAxis.getNormal()) + .scale((axisMotion + clientOffsetDiff * modifier / 2f) * ServerSpeedProvider.get()); + if (sequencedOffsetLimit >= 0) + motion = VecHelper.clampComponentWise(motion, (float) sequencedOffsetLimit); + setContraptionMotion(motion); + } + + public double getAxisCoord() { + Vec3 anchorVec = getAnchorVec(); + return movementAxis.getAxis() + .choose(anchorVec.x, anchorVec.y, anchorVec.z); + } + + public void sendPacket() { + AllPackets.getChannel() + .send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new GantryContraptionUpdatePacket(getId(), getAxisCoord(), axisMotion, sequencedOffsetLimit)); + } + + @OnlyIn(Dist.CLIENT) + public static void handlePacket(GantryContraptionUpdatePacket packet) { + Entity entity = Minecraft.getInstance().level.getEntity(packet.entityID); + if (!(entity instanceof GantryContraptionEntity)) + return; + GantryContraptionEntity ce = (GantryContraptionEntity) entity; + ce.axisMotion = packet.motion; + ce.clientOffsetDiff = packet.coord - ce.getAxisCoord(); + ce.sequencedOffsetLimit = packet.sequenceLimit; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionUpdatePacket.java new file mode 100644 index 0000000000..0ef5e7850a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/gantry/GantryContraptionUpdatePacket.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.contraptions.gantry; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class GantryContraptionUpdatePacket extends SimplePacketBase { + + int entityID; + double coord; + double motion; + double sequenceLimit; + + public GantryContraptionUpdatePacket(int entityID, double coord, double motion, double sequenceLimit) { + this.entityID = entityID; + this.coord = coord; + this.motion = motion; + this.sequenceLimit = sequenceLimit; + } + + public GantryContraptionUpdatePacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + coord = buffer.readFloat(); + motion = buffer.readFloat(); + sequenceLimit = buffer.readFloat(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + buffer.writeFloat((float) coord); + buffer.writeFloat((float) motion); + buffer.writeFloat((float) sequenceLimit); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork( + () -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> GantryContraptionEntity.handlePacket(this))); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/glue/GlueEffectPacket.java b/src/main/java/com/simibubi/create/content/contraptions/glue/GlueEffectPacket.java new file mode 100644 index 0000000000..817cdf9633 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/GlueEffectPacket.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.contraptions.glue; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class GlueEffectPacket extends SimplePacketBase { + + private BlockPos pos; + private Direction direction; + private boolean fullBlock; + + public GlueEffectPacket(BlockPos pos, Direction direction, boolean fullBlock) { + this.pos = pos; + this.direction = direction; + this.fullBlock = fullBlock; + } + + public GlueEffectPacket(FriendlyByteBuf buffer) { + pos = buffer.readBlockPos(); + direction = Direction.from3DDataValue(buffer.readByte()); + fullBlock = buffer.readBoolean(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBlockPos(pos); + buffer.writeByte(direction.get3DDataValue()); + buffer.writeBoolean(fullBlock); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::handleClient)); + return true; + } + + @OnlyIn(Dist.CLIENT) + public void handleClient() { + Minecraft mc = Minecraft.getInstance(); + if (!mc.player.blockPosition().closerThan(pos, 100)) + return; + SuperGlueItem.spawnParticles(mc.level, pos, direction, fullBlock); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueEntity.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueEntity.java index c6086068c5..1864af6b7b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import java.util.ArrayList; import java.util.List; @@ -8,13 +8,13 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; -import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; +import com.simibubi.create.content.contraptions.BlockMovementChecks; +import com.simibubi.create.content.contraptions.bearing.BearingBlock; +import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialEntityItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueHandler.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueHandler.java index 08c9b8a9c4..692bbc8786 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueHandler.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import java.util.HashSet; import java.util.Set; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.BlockMovementChecks; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.placement.IPlacementHelper; @@ -50,7 +50,7 @@ public class SuperGlueHandler { BlockPos relative = pos.relative(direction); if (SuperGlueEntity.isGlued(world, pos, direction, cached) && BlockMovementChecks.isMovementNecessary(world.getBlockState(relative), entity.level, relative)) - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), new GlueEffectPacket(pos, direction, true)); } @@ -101,7 +101,7 @@ public class SuperGlueHandler { if (SuperGlueEntity.isValidFace(world, gluePos, face)) { if (!world.isClientSide) { world.addFreshEntity(entity); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), new GlueEffectPacket(gluePos, face, true)); } itemstack.hurtAndBreak(1, placer, SuperGlueItem::onBroken); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueItem.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueItem.java index 931bd5ac01..c152e490da 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueItem.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; +import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRemovalPacket.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRemovalPacket.java index cab9c41cd7..2611c5cf04 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRemovalPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRemovalPacket.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; - -import java.util.function.Supplier; +package com.simibubi.create.content.contraptions.glue; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -33,10 +31,9 @@ public class SuperGlueRemovalPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); Entity entity = player.level.getEntity(entityId); if (!(entity instanceof SuperGlueEntity superGlue)) return; @@ -47,7 +44,7 @@ public class SuperGlueRemovalPacket extends SimplePacketBase { superGlue.spawnParticles(); entity.discard(); }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRenderer.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRenderer.java index 8c6beab896..748ec9e0fb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRenderer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHandler.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHandler.java index 2a70835214..1d349dfc6e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHandler.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import java.util.List; import java.util.Optional; import java.util.Set; import com.google.common.base.Objects; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSpecialTextures; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.RaycastHelper; @@ -100,7 +100,7 @@ public class SuperGlueSelectionHandler { CatnipClient.OUTLINER.showAABB(glueEntity, glueEntity.getBoundingBox()) .colored(h ? HIGHLIGHT : PASSIVE) .withFaceTextures(faceTex, faceTex) - .disableNormals() + .disableLineNormals() .lineWidth(h ? 1 / 16f : 1 / 64f); } } @@ -155,12 +155,12 @@ public class SuperGlueSelectionHandler { CatnipClient.OUTLINER.showAABB(bbOutlineSlot, currentSelectionBox) .colored(canReach && canAfford && !cancel ? HIGHLIGHT : FAIL) .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.GLUE) - .disableNormals() + .disableLineNormals() .lineWidth(1 / 16f); CatnipClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) .colored(0x4D9162) - .disableNormals() + .disableLineNormals() .lineWidth(1 / 64f); } @@ -193,7 +193,7 @@ public class SuperGlueSelectionHandler { if (attack) { if (selected == null) return false; - AllPackets.channel.sendToServer(new SuperGlueRemovalPacket(selected.getId(), soundSourceForRemoval)); + AllPackets.getChannel().sendToServer(new SuperGlueRemovalPacket(selected.getId(), soundSourceForRemoval)); selected = null; clusterCooldown = 0; return true; @@ -251,7 +251,7 @@ public class SuperGlueSelectionHandler { public void confirm() { LocalPlayer player = Minecraft.getInstance().player; - AllPackets.channel.sendToServer(new SuperGlueSelectionPacket(firstPos, hoveredPos)); + AllPackets.getChannel().sendToServer(new SuperGlueSelectionPacket(firstPos, hoveredPos)); AllSoundEvents.SLIME_ADDED.playAt(player.level, hoveredPos, 0.5F, 0.95F, false); player.level.playSound(player, hoveredPos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1); @@ -259,7 +259,7 @@ public class SuperGlueSelectionHandler { CatnipClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) .colored(0xB5F2C6) .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.HIGHLIGHT_CHECKERED) - .disableNormals() + .disableLineNormals() .lineWidth(1 / 24f); discard(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHelper.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHelper.java index fc85e12c65..503f8f4107 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionHelper.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionHelper.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; +import com.simibubi.create.content.contraptions.BlockMovementChecks; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionPacket.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java rename to src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionPacket.java index ddc5b49ea7..b1c3713fa2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueSelectionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/glue/SuperGlueSelectionPacket.java @@ -1,7 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.glue; +package com.simibubi.create.content.contraptions.glue; import java.util.Set; -import java.util.function.Supplier; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -36,10 +35,9 @@ public class SuperGlueSelectionPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); double range = player.getAttribute(ForgeMod.REACH_DISTANCE.get()) .getValue() + 2; @@ -64,7 +62,7 @@ public class SuperGlueSelectionPacket extends SimplePacketBase { AllAdvancements.SUPER_GLUE.awardTo(player); }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveHoveringInformation.java b/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveHoveringInformation.java deleted file mode 100644 index 061ab7e6b2..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveHoveringInformation.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.simibubi.create.content.contraptions.goggles; - -import java.util.List; - -import net.minecraft.network.chat.Component; - -/* -* Implement this Interface in the TileEntity class that wants to add info to the screen -* */ -public interface IHaveHoveringInformation { - - default boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingCreationPacket.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingCreationPacket.java new file mode 100644 index 0000000000..4e28892327 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingCreationPacket.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.contraptions.minecart; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraftforge.network.NetworkEvent.Context; + +public class CouplingCreationPacket extends SimplePacketBase { + + int id1, id2; + + public CouplingCreationPacket(AbstractMinecart cart1, AbstractMinecart cart2) { + id1 = cart1.getId(); + id2 = cart2.getId(); + } + + public CouplingCreationPacket(FriendlyByteBuf buffer) { + id1 = buffer.readInt(); + id2 = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(id1); + buffer.writeInt(id2); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + if (sender != null) + CouplingHandler.tryToCoupleCarts(sender, sender.level, id1, id2); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandler.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandler.java index 5dc6aab805..11937b2baf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; import java.util.Set; import java.util.UUID; @@ -8,11 +8,11 @@ import javax.annotation.Nullable; import com.simibubi.create.AllItems; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -90,7 +90,7 @@ public class CouplingHandler { distanceTo = 2; } - if (distanceTo > AllConfigs.SERVER.kinetics.maxCartCouplingLength.get()) { + if (distanceTo > AllConfigs.server().kinetics.maxCartCouplingLength.get()) { status(player, tooFar); return false; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandlerClient.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandlerClient.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandlerClient.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandlerClient.java index ddbe3ad137..859e7bdf36 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandlerClient.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingHandlerClient.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; import java.util.Random; import com.mojang.math.Vector3f; import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; import net.createmod.catnip.utility.VecHelper; import net.minecraft.client.Minecraft; @@ -45,7 +45,7 @@ public class CouplingHandlerClient { return; } spawnSelectionParticles(entity.getBoundingBox(), true); - AllPackets.channel.sendToServer(new CouplingCreationPacket(selectedCart, entity)); + AllPackets.getChannel().sendToServer(new CouplingCreationPacket(selectedCart, entity)); selectedCart = null; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingPhysics.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingPhysics.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingPhysics.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingPhysics.java index d73bb7605f..540d21b0a4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingPhysics.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingPhysics.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; diff --git a/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingRenderer.java new file mode 100644 index 0000000000..af5a9b50cc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/CouplingRenderer.java @@ -0,0 +1,240 @@ +package com.simibubi.create.content.contraptions.minecart; + +import static net.minecraft.util.Mth.lerp; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; +import com.simibubi.create.content.kinetics.KineticDebugger; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class CouplingRenderer { + + public static void renderAll(PoseStack ms, MultiBufferSource buffer, Vec3 camera) { + CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().level, c -> { + if (c.getFirst() + .hasContraptionCoupling(true)) + return; + CouplingRenderer.renderCoupling(ms, buffer, camera, c.map(MinecartController::cart)); + }); + } + + public static void tickDebugModeRenders() { + if (KineticDebugger.isActive()) + CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().level, CouplingRenderer::doDebugRender); + } + + public static void renderCoupling(PoseStack ms, MultiBufferSource buffer, Vec3 camera, Couple carts) { + ClientLevel world = Minecraft.getInstance().level; + + if (carts.getFirst() == null || carts.getSecond() == null) + return; + + Couple lightValues = carts.map(c -> LevelRenderer.getLightColor(world, new BlockPos(c.getBoundingBox() + .getCenter()))); + + Vec3 center = carts.getFirst() + .position() + .add(carts.getSecond() + .position()) + .scale(.5f); + + Couple transforms = carts.map(c -> getSuitableCartEndpoint(c, center)); + + BlockState renderState = Blocks.AIR.defaultBlockState(); + VertexConsumer builder = buffer.getBuffer(RenderType.solid()); + SuperByteBuffer attachment = CachedPartialBuffers.partial(AllPartialModels.COUPLING_ATTACHMENT, renderState); + SuperByteBuffer ring = CachedPartialBuffers.partial(AllPartialModels.COUPLING_RING, renderState); + SuperByteBuffer connector = CachedPartialBuffers.partial(AllPartialModels.COUPLING_CONNECTOR, renderState); + + Vec3 zero = Vec3.ZERO; + Vec3 firstEndpoint = transforms.getFirst() + .apply(zero); + Vec3 secondEndpoint = transforms.getSecond() + .apply(zero); + Vec3 endPointDiff = secondEndpoint.subtract(firstEndpoint); + double connectorYaw = -Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI; + double connectorPitch = Math.atan2(endPointDiff.y, endPointDiff.multiply(1, 0, 1) + .length()) * 180 / Math.PI; + + TransformStack msr = TransformStack.cast(ms); + carts.forEachWithContext((cart, isFirst) -> { + CartEndpoint cartTransform = transforms.get(isFirst); + + ms.pushPose(); + cartTransform.apply(ms, camera); + attachment.light(lightValues.get(isFirst)) + .renderInto(ms, builder); + msr.rotateY(connectorYaw - cartTransform.yaw); + ring.light(lightValues.get(isFirst)) + .renderInto(ms, builder); + ms.popPose(); + }); + + int l1 = lightValues.getFirst(); + int l2 = lightValues.getSecond(); + int meanBlockLight = (((l1 >> 4) & 0xf) + ((l2 >> 4) & 0xf)) / 2; + int meanSkyLight = (((l1 >> 20) & 0xf) + ((l2 >> 20) & 0xf)) / 2; + + ms.pushPose(); + msr.translate(firstEndpoint.subtract(camera)) + .rotateY(connectorYaw) + .rotateZ(connectorPitch); + ms.scale((float) endPointDiff.length(), 1, 1); + + connector.light(meanSkyLight << 20 | meanBlockLight << 4) + .renderInto(ms, builder); + ms.popPose(); + } + + private static CartEndpoint getSuitableCartEndpoint(AbstractMinecart cart, Vec3 centerOfCoupling) { + long i = cart.getId() * 493286711L; + i = i * i * 4392167121L + i * 98761L; + double x = (((float) (i >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; + double y = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F + 0.375F; + double z = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; + + float pt = AnimationTickHolder.getPartialTicks(); + + double xIn = lerp(pt, cart.xOld, cart.getX()); + double yIn = lerp(pt, cart.yOld, cart.getY()); + double zIn = lerp(pt, cart.zOld, cart.getZ()); + + float yaw = lerp(pt, cart.yRotO, cart.getYRot()); + float pitch = lerp(pt, cart.xRotO, cart.getXRot()); + float roll = cart.getHurtTime() - pt; + + float rollAmplifier = cart.getDamage() - pt; + if (rollAmplifier < 0.0F) + rollAmplifier = 0.0F; + roll = roll > 0 ? Mth.sin(roll) * roll * rollAmplifier / 10.0F * cart.getHurtDir() : 0; + + Vec3 positionVec = new Vec3(xIn, yIn, zIn); + Vec3 frontVec = positionVec.add(VecHelper.rotate(new Vec3(.5, 0, 0), 180 - yaw, Axis.Y)); + Vec3 backVec = positionVec.add(VecHelper.rotate(new Vec3(-.5, 0, 0), 180 - yaw, Axis.Y)); + + Vec3 railVecOfPos = cart.getPos(xIn, yIn, zIn); + boolean flip = false; + + if (railVecOfPos != null) { + frontVec = cart.getPosOffs(xIn, yIn, zIn, (double) 0.3F); + backVec = cart.getPosOffs(xIn, yIn, zIn, (double) -0.3F); + if (frontVec == null) + frontVec = railVecOfPos; + if (backVec == null) + backVec = railVecOfPos; + + x += railVecOfPos.x; + y += (frontVec.y + backVec.y) / 2; + z += railVecOfPos.z; + + Vec3 endPointDiff = backVec.add(-frontVec.x, -frontVec.y, -frontVec.z); + if (endPointDiff.length() != 0.0D) { + endPointDiff = endPointDiff.normalize(); + yaw = (float) (Math.atan2(endPointDiff.z, endPointDiff.x) * 180.0D / Math.PI); + pitch = (float) (Math.atan(endPointDiff.y) * 73.0D); + } + } else { + x += xIn; + y += yIn; + z += zIn; + } + + final float offsetMagnitude = 13 / 16f; + boolean isBackFaceCloser = frontVec.distanceToSqr(centerOfCoupling) > backVec.distanceToSqr(centerOfCoupling); + flip = isBackFaceCloser; + float offset = isBackFaceCloser ? -offsetMagnitude : offsetMagnitude; + + return new CartEndpoint(x, y + 2 / 16f, z, 180 - yaw, -pitch, roll, offset, flip); + } + + static class CartEndpoint { + + double x; + double y; + double z; + float yaw; + float pitch; + float roll; + float offset; + boolean flip; + + public CartEndpoint(double x, double y, double z, float yaw, float pitch, float roll, float offset, boolean flip) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + this.roll = roll; + this.offset = offset; + this.flip = flip; + } + + public Vec3 apply(Vec3 vec) { + vec = vec.add(offset, 0, 0); + vec = VecHelper.rotate(vec, roll, Axis.X); + vec = VecHelper.rotate(vec, pitch, Axis.Z); + vec = VecHelper.rotate(vec, yaw, Axis.Y); + return vec.add(x, y, z); + } + + public void apply(PoseStack ms, Vec3 camera) { + TransformStack.cast(ms) + .translate(camera.scale(-1) + .add(x, y, z)) + .rotateY(yaw) + .rotateZ(pitch) + .rotateX(roll) + .translate(offset, 0, 0) + .rotateY(flip ? 180 : 0); + } + + } + + public static void doDebugRender(Couple c) { + int yOffset = 1; + MinecartController first = c.getFirst(); + AbstractMinecart mainCart = first.cart(); + Vec3 mainCenter = mainCart.position() + .add(0, yOffset, 0); + Vec3 connectedCenter = c.getSecond() + .cart() + .position() + .add(0, yOffset, 0); + + int color = Color.mixColors(0xabf0e9, 0xee8572, (float) Mth + .clamp(Math.abs(first.getCouplingLength(true) - connectedCenter.distanceTo(mainCenter)) * 8, 0, 1)); + + CatnipClient.OUTLINER.showLine(mainCart.getId() + "", mainCenter, connectedCenter) + .colored(color) + .lineWidth(1 / 8f); + + Vec3 point = mainCart.position() + .add(0, yOffset, 0); + CatnipClient.OUTLINER.showLine(mainCart.getId() + "_dot", point, point.add(0, 1 / 128f, 0)) + .colored(0xffffff) + .lineWidth(1 / 4f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartCouplingItem.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartCouplingItem.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartCouplingItem.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartCouplingItem.java index 2eb72d2b5b..f3b47ba27d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartCouplingItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartCouplingItem.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; import net.createmod.catnip.utility.Iterate; import net.minecraft.world.InteractionResult; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartSim2020.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartSim2020.java index a885c3d360..e52d2d042d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/MinecartSim2020.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; import java.util.Map; import com.google.common.collect.Maps; import com.mojang.datafixers.util.Pair; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; import net.createmod.catnip.utility.VecHelper; import net.minecraft.Util; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/TrainCargoManager.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/TrainCargoManager.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/TrainCargoManager.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/TrainCargoManager.java index 5d85613699..6b045b69a4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/TrainCargoManager.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/TrainCargoManager.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train; +package com.simibubi.create.content.contraptions.minecart; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption.ContraptionInvWrapper; -import com.simibubi.create.content.contraptions.components.structureMovement.MountedStorageManager; +import com.simibubi.create.content.contraptions.Contraption.ContraptionInvWrapper; +import com.simibubi.create.content.contraptions.MountedStorageManager; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import net.minecraft.core.BlockPos; @@ -51,8 +51,8 @@ public class TrainCargoManager extends MountedStorageManager { } @Override - public void read(CompoundTag nbt, Map presentTileEntities, boolean clientPacket) { - super.read(nbt, presentTileEntities, clientPacket); + public void read(CompoundTag nbt, Map presentBlockEntities, boolean clientPacket) { + super.read(nbt, presentBlockEntities, clientPacket); ticksSinceLastExchange = nbt.getInt("TicksSinceLastExchange"); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/CapabilityMinecartController.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/capability/CapabilityMinecartController.java index c3528dc5ce..ddb27fceae 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/CapabilityMinecartController.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train.capability; +package com.simibubi.create.content.contraptions.minecart.capability; import java.util.ArrayList; import java.util.HashMap; @@ -13,7 +13,7 @@ import javax.annotation.Nullable; import com.simibubi.create.AllItems; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; +import com.simibubi.create.content.contraptions.minecart.CouplingHandler; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectLists; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartController.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartController.java index 21bcad1155..29d1b32963 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartController.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train.capability; +package com.simibubi.create.content.contraptions.minecart.capability; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -10,11 +10,11 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableBoolean; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.minecart.CouplingHandler; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -292,7 +292,7 @@ public class MinecartController implements INBTSerializable { public void sendData() { if (getWorld().isClientSide) return; - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(this::cart), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(this::cart), new MinecartControllerUpdatePacket(this)); } @@ -404,7 +404,7 @@ public class MinecartController implements INBTSerializable { } void tick(AbstractMinecart entity) { - entity.setPos(position.x, position.y, position.z); +// entity.setPos(position.x, position.y, position.z); entity.setDeltaMovement(Vec3.ZERO); entity.setYRot(yaw); entity.setXRot(pitch); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartControllerUpdatePacket.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java rename to src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartControllerUpdatePacket.java index 81e749bc50..009edc376a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/minecart/capability/MinecartControllerUpdatePacket.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.train.capability; - -import java.util.function.Supplier; +package com.simibubi.create.content.contraptions.minecart.capability; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -37,11 +35,9 @@ public class MinecartControllerUpdatePacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::handleCL)); - context.get() - .setPacketHandled(true); + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::handleCL)); + return true; } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssembleRailType.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssembleRailType.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssembleRailType.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssembleRailType.java index f67e1edfe6..291f923bb5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssembleRailType.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssembleRailType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; import java.util.function.Supplier; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlock.java index 4efb61f655..07ff146d18 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; import java.util.ArrayList; import java.util.List; @@ -6,15 +6,15 @@ import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.tracks.ControllerRailBlock; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.redstone.rail.ControllerRailBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -60,7 +60,7 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; public class CartAssemblerBlock extends BaseRailBlock - implements ITE, IWrenchable, ISpecialBlockItemRequirement { + implements IBE, IWrenchable, ISpecialBlockItemRequirement { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public static final BooleanProperty BACKWARDS = BooleanProperty.create("backwards"); @@ -120,7 +120,7 @@ public class CartAssemblerBlock extends BaseRailBlock if (world.isClientSide) return; - withTileEntityDo(world, pos, te -> te.assembleNextTick(cart)); + withBlockEntityDo(world, pos, be -> be.assembleNextTick(cart)); } public enum CartAssemblerAction { @@ -239,13 +239,13 @@ public class CartAssemblerBlock extends BaseRailBlock } @Override - public Class getTileEntityClass() { - return CartAssemblerTileEntity.class; + public Class getBlockEntityClass() { + return CartAssemblerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CART_ASSEMBLER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CART_ASSEMBLER.get(); } @Override @@ -254,7 +254,7 @@ public class CartAssemblerBlock extends BaseRailBlock } @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { ArrayList requiredItems = new ArrayList<>(); requiredItems.add(new ItemStack(getRailItem(state))); requiredItems.add(new ItemStack(asItem())); diff --git a/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockEntity.java new file mode 100644 index 0000000000..ce52a5fcea --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockEntity.java @@ -0,0 +1,325 @@ +package com.simibubi.create.content.contraptions.mounted; + +import java.util.List; +import java.util.UUID; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.minecart.CouplingHandler; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.minecart.capability.MinecartController; +import com.simibubi.create.content.redstone.rail.ControllerRailBlock; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.entity.vehicle.MinecartFurnace; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.RailShape; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class CartAssemblerBlockEntity extends SmartBlockEntity implements IDisplayAssemblyExceptions { + private static final int assemblyCooldown = 8; + + protected ScrollOptionBehaviour movementMode; + private int ticksSinceMinecartUpdate; + protected AssemblyException lastException; + protected AbstractMinecart cartToAssemble; + + public CartAssemblerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + ticksSinceMinecartUpdate = assemblyCooldown; + } + + @Override + public void tick() { + super.tick(); + if (ticksSinceMinecartUpdate < assemblyCooldown) { + ticksSinceMinecartUpdate++; + } + + tryAssemble(cartToAssemble); + cartToAssemble = null; + } + + public void tryAssemble(AbstractMinecart cart) { + if (cart == null) + return; + + if (!isMinecartUpdateValid()) + return; + resetTicksSinceMinecartUpdate(); + + BlockState state = level.getBlockState(worldPosition); + if (!AllBlocks.CART_ASSEMBLER.has(state)) + return; + CartAssemblerBlock block = (CartAssemblerBlock) state.getBlock(); + + CartAssemblerBlock.CartAssemblerAction action = CartAssemblerBlock.getActionForCart(state, cart); + if (action.shouldAssemble()) + assemble(level, worldPosition, cart); + if (action.shouldDisassemble()) + disassemble(level, worldPosition, cart); + if (action == CartAssemblerBlock.CartAssemblerAction.ASSEMBLE_ACCELERATE) { + if (cart.getDeltaMovement() + .length() > 1 / 128f) { + Direction facing = cart.getMotionDirection(); + RailShape railShape = state.getValue(CartAssemblerBlock.RAIL_SHAPE); + for (Direction d : Iterate.directionsInAxis(railShape == RailShape.EAST_WEST ? Axis.X : Axis.Z)) + if (level.getBlockState(worldPosition.relative(d)) + .isRedstoneConductor(level, worldPosition.relative(d))) + facing = d.getOpposite(); + + float speed = block.getRailMaxSpeed(state, level, worldPosition, cart); + cart.setDeltaMovement(facing.getStepX() * speed, facing.getStepY() * speed, facing.getStepZ() * speed); + } + } + if (action == CartAssemblerBlock.CartAssemblerAction.ASSEMBLE_ACCELERATE_DIRECTIONAL) { + Vec3i accelerationVector = + ControllerRailBlock.getAccelerationVector(AllBlocks.CONTROLLER_RAIL.getDefaultState() + .setValue(ControllerRailBlock.SHAPE, state.getValue(CartAssemblerBlock.RAIL_SHAPE)) + .setValue(ControllerRailBlock.BACKWARDS, state.getValue(CartAssemblerBlock.BACKWARDS))); + float speed = block.getRailMaxSpeed(state, level, worldPosition, cart); + cart.setDeltaMovement(Vec3.atLowerCornerOf(accelerationVector) + .scale(speed)); + } + if (action == CartAssemblerBlock.CartAssemblerAction.DISASSEMBLE_BRAKE) { + Vec3 diff = VecHelper.getCenterOf(worldPosition) + .subtract(cart.position()); + cart.setDeltaMovement(diff.x / 16f, 0, diff.z / 16f); + } + } + + protected void assemble(Level world, BlockPos pos, AbstractMinecart cart) { + if (!cart.getPassengers() + .isEmpty()) + return; + + LazyOptional optional = + cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (optional.isPresent() && optional.orElse(null) + .isCoupledThroughContraption()) + return; + + CartMovementMode mode = CartMovementMode.values()[movementMode.value]; + + MountedContraption contraption = new MountedContraption(mode); + try { + if (!contraption.assemble(world, pos)) + return; + + lastException = null; + sendData(); + } catch (AssemblyException e) { + lastException = e; + sendData(); + return; + } + + boolean couplingFound = contraption.connectedCart != null; + Direction initialOrientation = CartAssemblerBlock.getHorizontalDirection(getBlockState()); + + if (couplingFound) { + cart.setPos(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f); + if (!CouplingHandler.tryToCoupleCarts(null, world, cart.getId(), + contraption.connectedCart.getId())) + return; + } + + contraption.removeBlocksFromWorld(world, BlockPos.ZERO); + contraption.startMoving(world); + contraption.expandBoundsAroundAxis(Axis.Y); + + if (couplingFound) { + Vec3 diff = contraption.connectedCart.position() + .subtract(cart.position()); + initialOrientation = Direction.fromYRot(Mth.atan2(diff.z, diff.x) * 180 / Math.PI); + } + + OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation); + if (couplingFound) + entity.setCouplingId(cart.getUUID()); + entity.setPos(pos.getX() + .5, pos.getY(), pos.getZ() + .5); + world.addFreshEntity(entity); + entity.startRiding(cart); + + if (cart instanceof MinecartFurnace) { + CompoundTag nbt = cart.serializeNBT(); + nbt.putDouble("PushZ", 0); + nbt.putDouble("PushX", 0); + cart.deserializeNBT(nbt); + } + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + } + + protected void disassemble(Level world, BlockPos pos, AbstractMinecart cart) { + if (cart.getPassengers() + .isEmpty()) + return; + Entity entity = cart.getPassengers() + .get(0); + if (!(entity instanceof OrientedContraptionEntity)) + return; + OrientedContraptionEntity contraption = (OrientedContraptionEntity) entity; + UUID couplingId = contraption.getCouplingId(); + + if (couplingId == null) { + contraption.yaw = CartAssemblerBlock.getHorizontalDirection(getBlockState()) + .toYRot(); + disassembleCart(cart); + return; + } + + Couple coupledCarts = contraption.getCoupledCartsIfPresent(); + if (coupledCarts == null) + return; + + // Make sure connected cart is present and being disassembled + for (boolean current : Iterate.trueAndFalse) { + MinecartController minecartController = coupledCarts.get(current); + if (minecartController.cart() == cart) + continue; + BlockPos otherPos = minecartController.cart() + .blockPosition(); + BlockState blockState = world.getBlockState(otherPos); + if (!AllBlocks.CART_ASSEMBLER.has(blockState)) + return; + if (!CartAssemblerBlock.getActionForCart(blockState, minecartController.cart()) + .shouldDisassemble()) + return; + } + + for (boolean current : Iterate.trueAndFalse) + coupledCarts.get(current) + .removeConnection(current); + disassembleCart(cart); + } + + protected void disassembleCart(AbstractMinecart cart) { + cart.ejectPassengers(); + if (cart instanceof MinecartFurnace) { + CompoundTag nbt = cart.serializeNBT(); + nbt.putDouble("PushZ", cart.getDeltaMovement().x); + nbt.putDouble("PushX", cart.getDeltaMovement().z); + cart.deserializeNBT(nbt); + } + } + + @Override + public void addBehaviours(List behaviours) { + movementMode = new ScrollOptionBehaviour<>(CartMovementMode.class, + CreateLang.translateDirect("contraptions.cart_movement_mode"), this, getMovementModeSlot()); + behaviours.add(movementMode); + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + + protected ValueBoxTransform getMovementModeSlot() { + return new CartAssemblerValueBoxTransform(); + } + + private class CartAssemblerValueBoxTransform extends CenteredSideValueBoxTransform { + + public CartAssemblerValueBoxTransform() { + super((state, d) -> { + if (d.getAxis() + .isVertical()) + return false; + if (!state.hasProperty(CartAssemblerBlock.RAIL_SHAPE)) + return false; + RailShape railShape = state.getValue(CartAssemblerBlock.RAIL_SHAPE); + return (d.getAxis() == Axis.X) == (railShape == RailShape.NORTH_SOUTH); + }); + } + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 7, 17.5); + } + + } + + public enum CartMovementMode implements INamedIconOptions { + + ROTATE(AllIcons.I_CART_ROTATE), + ROTATE_PAUSED(AllIcons.I_CART_ROTATE_PAUSED), + ROTATION_LOCKED(AllIcons.I_CART_ROTATE_LOCKED), + + ; + + private String translationKey; + private AllIcons icon; + + CartMovementMode(AllIcons icon) { + this.icon = icon; + translationKey = "contraptions.cart_movement_mode." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + } + + public void resetTicksSinceMinecartUpdate() { + ticksSinceMinecartUpdate = 0; + } + + public void assembleNextTick(AbstractMinecart cart) { + if (cartToAssemble == null) + cartToAssemble = cart; + } + + public boolean isMinecartUpdateValid() { + return ticksSinceMinecartUpdate >= assemblyCooldown; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlockItem.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockItem.java index 988509093e..3fa5d1d1ab 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlockItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/CartAssemblerBlockItem.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; import javax.annotation.Nonnull; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.tracks.ControllerRailBlock; +import com.simibubi.create.content.redstone.rail.ControllerRailBlock; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/ItemHandlerModifiableFromIInventory.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/ItemHandlerModifiableFromIInventory.java index f70ee51f99..326e08ee35 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/ItemHandlerModifiableFromIInventory.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/MinecartContraptionItem.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/MinecartContraptionItem.java index d8785317fe..965f54db72 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/MinecartContraptionItem.java @@ -1,25 +1,24 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; -import java.io.IOException; import java.util.List; import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.MutablePair; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; import com.simibubi.create.AllItems; import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement; -import com.simibubi.create.content.contraptions.components.deployer.DeployerFakePlayer; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionData; +import com.simibubi.create.content.contraptions.ContraptionMovementSetting; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.kinetics.deployer.DeployerFakePlayer; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.ContraptionMovementSetting; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.ChatFormatting; @@ -30,7 +29,7 @@ import net.minecraft.core.NonNullList; import net.minecraft.core.dispenser.DefaultDispenseItemBehavior; import net.minecraft.core.dispenser.DispenseItemBehavior; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.tags.BlockTags; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; @@ -69,6 +68,11 @@ public class MinecartContraptionItem extends Item { return new MinecartContraptionItem(Type.CHEST, builder); } + @Override + public boolean canFitInsideContainerItems() { + return AllConfigs.server().kinetics.minecartContraptionInContainers.get(); + } + private MinecartContraptionItem(Type minecartTypeIn, Properties builder) { super(builder); this.minecartType = minecartTypeIn; @@ -205,6 +209,8 @@ public class MinecartContraptionItem extends Item { Player player = event.getPlayer(); if (player == null || entity == null) return; + if (!AllConfigs.server().kinetics.survivalContraptionPickup.get() && !player.isCreative()) + return; ItemStack wrench = player.getItemInHand(event.getHand()); if (!AllItems.WRENCH.isIn(wrench)) @@ -248,18 +254,10 @@ public class MinecartContraptionItem extends Item { ItemStack generatedStack = create(type, oce).setHoverName(entity.getCustomName()); - try { - ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); - NbtIo.write(generatedStack.serializeNBT(), dataOutput); - int estimatedPacketSize = dataOutput.toByteArray().length; - if (estimatedPacketSize > 2_000_000) { - player.displayClientMessage(CreateLang.translateDirect("contraption.minecart_contraption_too_big") - .withStyle(ChatFormatting.RED), true); - return; - } - - } catch (IOException e) { - e.printStackTrace(); + if (ContraptionData.isTooLargeForPickup(generatedStack.serializeNBT())) { + MutableComponent message = CreateLang.translateDirect("contraption.minecart_contraption_too_big") + .withStyle(ChatFormatting.RED); + player.displayClientMessage(message, true); return; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/mounted/MountedContraption.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java rename to src/main/java/com/simibubi/create/content/contraptions/mounted/MountedContraption.java index e98a9a2eb9..7ae84e29d0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/mounted/MountedContraption.java @@ -1,18 +1,18 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.mounted; +package com.simibubi.create.content.contraptions.mounted; -import static com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock.RAIL_SHAPE; +import static com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock.RAIL_SHAPE; import java.util.Queue; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity.CartMovementMode; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.NonStationaryLighter; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.NBTHelper; @@ -50,7 +50,7 @@ public class MountedContraption extends Contraption { } @Override - protected ContraptionType getType() { + public ContraptionType getType() { return ContraptionType.MOUNTED; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java b/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java deleted file mode 100644 index 3d02e32eac..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticle.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.simibubi.create.content.contraptions.particle; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.particle.ParticleProvider; -import net.minecraft.client.particle.ParticleRenderType; -import net.minecraft.client.particle.SimpleAnimatedParticle; -import net.minecraft.client.particle.SpriteSet; -import net.minecraft.util.Mth; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class HeaterParticle extends SimpleAnimatedParticle { - - private final SpriteSet animatedSprite; - - public HeaterParticle(ClientLevel worldIn, float r, float g, float b, double x, double y, double z, double vx, double vy, - double vz, SpriteSet spriteSet) { - super(worldIn, x, y, z, spriteSet, worldIn.random.nextFloat() * .5f); - - this.animatedSprite = spriteSet; - - this.xd = this.xd * (double) 0.01F + vx; - this.yd = this.yd * (double) 0.01F + vy; - this.zd = this.zd * (double) 0.01F + vz; - - this.rCol = r; - this.gCol = g; - this.bCol = b; - - this.x += (this.random.nextFloat() - this.random.nextFloat()) * 0.05F; - this.y += (this.random.nextFloat() - this.random.nextFloat()) * 0.05F; - this.z += (this.random.nextFloat() - this.random.nextFloat()) * 0.05F; - - this.lifetime = (int) (8.0D / (Math.random() * 0.8D + 0.2D)) + 4; - this.quadSize *= 1.875F; - this.setSpriteFromAge(animatedSprite); - - } - - @Override - public ParticleRenderType getRenderType() { - return ParticleRenderType.PARTICLE_SHEET_LIT; - } - - @Override - public float getQuadSize(float p_217561_1_) { - float f = ((float) this.age + p_217561_1_) / (float) this.lifetime; - return this.quadSize * (1.0F - f * f * 0.5F); - } - - @Override - public void move(double x, double y, double z) { - this.setBoundingBox(this.getBoundingBox() - .move(x, y, z)); - this.setLocationFromBoundingbox(); - } - - @Override - public int getLightColor(float p_189214_1_) { - float f = ((float) this.age + p_189214_1_) / (float) this.lifetime; - f = Mth.clamp(f, 0.0F, 1.0F); - int i = super.getLightColor(p_189214_1_); - int j = i & 255; - int k = i >> 16 & 255; - j = j + (int) (f * 15.0F * 16.0F); - if (j > 240) { - j = 240; - } - - return j | k << 16; - } - - @Override - public void tick() { - this.xo = this.x; - this.yo = this.y; - this.zo = this.z; - if (this.age++ >= this.lifetime) { - this.remove(); - } else { - this.setSpriteFromAge(animatedSprite); - this.move(this.xd, this.yd, this.zd); - this.xd *= (double) 0.96F; - this.yd *= (double) 0.96F; - this.zd *= (double) 0.96F; - if (this.onGround) { - this.xd *= (double) 0.7F; - this.zd *= (double) 0.7F; - } - } - } - - public static class Factory implements ParticleProvider { - private final SpriteSet spriteSet; - - public Factory(SpriteSet animatedSprite) { - this.spriteSet = animatedSprite; - } - - @Override - public Particle createParticle(HeaterParticleData data, ClientLevel worldIn, double x, double y, double z, double vx, - double vy, double vz) { - return new HeaterParticle(worldIn, data.r, data.g, data.b, x, y, z, vx, vy, vz, this.spriteSet); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticleData.java b/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticleData.java deleted file mode 100644 index bcaebea9bc..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/HeaterParticleData.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.simibubi.create.content.contraptions.particle; - -import java.util.Locale; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import com.simibubi.create.AllParticleTypes; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.client.particle.ParticleEngine.SpriteParticleRegistration; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.core.particles.ParticleType; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class HeaterParticleData implements ParticleOptions, ICustomParticleDataWithSprite { - - public static final Codec CODEC = RecordCodecBuilder.create(i -> - i.group( - Codec.FLOAT.fieldOf("r").forGetter(p -> p.r), - Codec.FLOAT.fieldOf("g").forGetter(p -> p.g), - Codec.FLOAT.fieldOf("b").forGetter(p -> p.b)) - .apply(i, HeaterParticleData::new)); - - public static final ParticleOptions.Deserializer DESERIALIZER = - new ParticleOptions.Deserializer() { - @Override - public HeaterParticleData fromCommand(ParticleType arg0, StringReader reader) - throws CommandSyntaxException { - reader.expect(' '); - float r = reader.readFloat(); - reader.expect(' '); - float g = reader.readFloat(); - reader.expect(' '); - float b = reader.readFloat(); - return new HeaterParticleData(r, g, b); - } - - @Override - public HeaterParticleData fromNetwork(ParticleType type, FriendlyByteBuf buffer) { - return new HeaterParticleData(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); - } - }; - - final float r; - final float g; - final float b; - - public HeaterParticleData(float r, float g, float b) { - this.r = r; - this.g = g; - this.b = b; - } - - public HeaterParticleData() { - this(0, 0, 0); - } - - @Override - public Deserializer getDeserializer() { - return DESERIALIZER; - } - - @Override - public Codec getCodec(ParticleType type) { - return CODEC; - } - - @Override - @OnlyIn(Dist.CLIENT) - public SpriteParticleRegistration getMetaFactory() { - return HeaterParticle.Factory::new; - } - - @Override - public String writeToString() { - return String.format(Locale.ROOT, "%s %f %f %f", AllParticleTypes.HEATER_PARTICLE.parameter(), r, g, b); - } - - @Override - public ParticleType getType() { - return AllParticleTypes.HEATER_PARTICLE.get(); - } - - @Override - public void writeToNetwork(FriendlyByteBuf buffer) { - buffer.writeFloat(r); - buffer.writeFloat(g); - buffer.writeFloat(b); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/piston/LinearActuatorBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/piston/LinearActuatorBlockEntity.java new file mode 100644 index 0000000000..22dd3b27cf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/LinearActuatorBlockEntity.java @@ -0,0 +1,387 @@ +package com.simibubi.create.content.contraptions.piston; + +import java.util.List; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionCollider; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.IControlContraption; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencerInstructions; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public abstract class LinearActuatorBlockEntity extends KineticBlockEntity + implements IControlContraption, IDisplayAssemblyExceptions { + + public float offset; + public boolean running; + public boolean assembleNextTick; + public boolean needsContraption; + public AbstractContraptionEntity movedContraption; + protected boolean forceMove; + protected ScrollOptionBehaviour movementMode; + protected boolean waitingForSpeedChange; + protected AssemblyException lastException; + protected double sequencedOffsetLimit; + + // Custom position sync + protected float clientOffsetDiff; + + public LinearActuatorBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + setLazyTickRate(3); + forceMove = true; + needsContraption = true; + sequencedOffsetLimit = -1; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + movementMode = new ScrollOptionBehaviour<>(MovementMode.class, CreateLang.translateDirect("contraptions.movement_mode"), + this, getMovementModeSlot()); + movementMode.withCallback(t -> waitingForSpeedChange = false); + behaviours.add(movementMode); + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + protected boolean syncSequenceContext() { + return true; + } + + @Override + public void tick() { + super.tick(); + + if (movedContraption != null) + if (!movedContraption.isAlive()) + movedContraption = null; + + if (isPassive()) + return; + + if (level.isClientSide) + clientOffsetDiff *= .75f; + + if (waitingForSpeedChange) { + if (movedContraption != null) { + if (level.isClientSide) { + float syncSpeed = clientOffsetDiff / 2f; + offset += syncSpeed; + movedContraption.setContraptionMotion(toMotionVector(syncSpeed)); + return; + } + movedContraption.setContraptionMotion(Vec3.ZERO); + } + return; + } + + if (!level.isClientSide && assembleNextTick) { + assembleNextTick = false; + if (running) { + if (getSpeed() == 0) + tryDisassemble(); + else + sendData(); + return; + } else { + if (getSpeed() != 0) + try { + assemble(); + lastException = null; + } catch (AssemblyException e) { + lastException = e; + } + sendData(); + } + return; + } + + if (!running) + return; + + boolean contraptionPresent = movedContraption != null; + if (needsContraption && !contraptionPresent) + return; + + float movementSpeed = getMovementSpeed(); + boolean locked = false; + if (sequencedOffsetLimit > 0) { + sequencedOffsetLimit = Math.max(0, sequencedOffsetLimit - Math.abs(movementSpeed)); + locked = sequencedOffsetLimit == 0; + } + float newOffset = offset + movementSpeed; + if ((int) newOffset != (int) offset) + visitNewPosition(); + + if (locked) { + forceMove = true; + resetContraptionToOffset(); + sendData(); + } + + if (contraptionPresent) { + if (moveAndCollideContraption()) { + movedContraption.setContraptionMotion(Vec3.ZERO); + offset = getGridOffset(offset); + resetContraptionToOffset(); + collided(); + return; + } + } + + if (!contraptionPresent || !movedContraption.isStalled()) + offset = newOffset; + + int extensionRange = getExtensionRange(); + if (offset <= 0 || offset >= extensionRange) { + offset = offset <= 0 ? 0 : extensionRange; + if (!level.isClientSide) { + moveAndCollideContraption(); + resetContraptionToOffset(); + tryDisassemble(); + if (waitingForSpeedChange) { + forceMove = true; + sendData(); + } + } + return; + } + } + + protected boolean isPassive() { + return false; + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (movedContraption != null && !level.isClientSide) + sendData(); + } + + protected int getGridOffset(float offset) { + return Mth.clamp((int) (offset + .5f), 0, getExtensionRange()); + } + + public float getInterpolatedOffset(float partialTicks) { + float interpolatedOffset = + Mth.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, getExtensionRange()); + return interpolatedOffset; + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + sequencedOffsetLimit = -1; + + if (isPassive()) + return; + + assembleNextTick = true; + waitingForSpeedChange = false; + + if (movedContraption != null && Math.signum(prevSpeed) != Math.signum(getSpeed()) && prevSpeed != 0) { + if (!movedContraption.isStalled()) { + offset = Math.round(offset * 16) / 16; + resetContraptionToOffset(); + } + movedContraption.getContraption() + .stop(level); + } + + if (sequenceContext != null && sequenceContext.instruction() == SequencerInstructions.TURN_DISTANCE) + sequencedOffsetLimit = sequenceContext.getEffectiveValue(getTheoreticalSpeed()); + } + + @Override + public void remove() { + this.remove = true; + if (!level.isClientSide) + disassemble(); + super.remove(); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putBoolean("Waiting", waitingForSpeedChange); + compound.putFloat("Offset", offset); + if (sequencedOffsetLimit >= 0) + compound.putDouble("SequencedOffsetLimit", sequencedOffsetLimit); + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + + if (clientPacket && forceMove) { + compound.putBoolean("ForceMovement", forceMove); + forceMove = false; + } + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + boolean forceMovement = compound.contains("ForceMovement"); + float offsetBefore = offset; + + running = compound.getBoolean("Running"); + waitingForSpeedChange = compound.getBoolean("Waiting"); + offset = compound.getFloat("Offset"); + sequencedOffsetLimit = + compound.contains("SequencedOffsetLimit") ? compound.getDouble("SequencedOffsetLimit") : -1; + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (forceMovement) + resetContraptionToOffset(); + else if (running) { + clientOffsetDiff = offset - offsetBefore; + offset = offsetBefore; + } + if (!running) + movedContraption = null; + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + + public abstract void disassemble(); + + protected abstract void assemble() throws AssemblyException; + + protected abstract int getExtensionRange(); + + protected abstract int getInitialOffset(); + + protected abstract ValueBoxTransform getMovementModeSlot(); + + protected abstract Vec3 toMotionVector(float speed); + + protected abstract Vec3 toPosition(float offset); + + protected void visitNewPosition() {} + + protected void tryDisassemble() { + if (remove) { + disassemble(); + return; + } + if (getMovementMode() == MovementMode.MOVE_NEVER_PLACE) { + waitingForSpeedChange = true; + return; + } + int initial = getInitialOffset(); + if ((int) (offset + .5f) != initial && getMovementMode() == MovementMode.MOVE_PLACE_RETURNED) { + waitingForSpeedChange = true; + return; + } + disassemble(); + } + + protected MovementMode getMovementMode() { + return movementMode.get(); + } + + protected boolean moveAndCollideContraption() { + if (movedContraption == null) + return false; + if (movedContraption.isStalled()) { + movedContraption.setContraptionMotion(Vec3.ZERO); + return false; + } + + Vec3 motion = getMotionVector(); + movedContraption.setContraptionMotion(getMotionVector()); + movedContraption.move(motion.x, motion.y, motion.z); + return ContraptionCollider.collideBlocks(movedContraption); + } + + protected void collided() { + if (level.isClientSide) { + waitingForSpeedChange = true; + return; + } + offset = getGridOffset(offset - getMovementSpeed()); + resetContraptionToOffset(); + tryDisassemble(); + } + + protected void resetContraptionToOffset() { + if (movedContraption == null) + return; + if (!movedContraption.isAlive()) + return; + Vec3 vec = toPosition(offset); + movedContraption.setPos(vec.x, vec.y, vec.z); + if (getSpeed() == 0 || waitingForSpeedChange) + movedContraption.setContraptionMotion(Vec3.ZERO); + } + + public float getMovementSpeed() { + float movementSpeed = Mth.clamp(convertToLinear(getSpeed()), -.49f, .49f) + clientOffsetDiff / 2f; + if (level.isClientSide) + movementSpeed *= ServerSpeedProvider.get(); + if (sequencedOffsetLimit >= 0) + movementSpeed = (float) Mth.clamp(movementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); + return movementSpeed; + } + + public Vec3 getMotionVector() { + return toMotionVector(getMovementSpeed()); + } + + @Override + public void onStall() { + if (!level.isClientSide) { + forceMove = true; + sendData(); + } + } + + public void onLengthBroken() { + offset = 0; + sendData(); + } + + @Override + public boolean isValid() { + return !isRemoved(); + } + + @Override + public void attach(ControlledContraptionEntity contraption) { + this.movedContraption = contraption; + if (!level.isClientSide) { + this.running = true; + sendData(); + } + } + + @Override + public boolean isAttachedTo(AbstractContraptionEntity contraption) { + return movedContraption == contraption; + } + + @Override + public BlockPos getBlockPosition() { + return worldPosition; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlock.java b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlock.java index af367514cc..e3a5b8ca42 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlock.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.core.BlockPos; @@ -35,7 +35,7 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.common.Tags; -public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implements ITE { +public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implements IBE { public static final EnumProperty STATE = EnumProperty.create("state", PistonState.class); protected boolean isSticky; @@ -72,7 +72,7 @@ public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implement .is(Tags.Items.SLIMEBALLS)) { if (player.getItemInHand(handIn) .isEmpty()) { - withTileEntityDo(worldIn, pos, te -> te.assembleNextTick = true); + withBlockEntityDo(worldIn, pos, be -> be.assembleNextTick = true); return InteractionResult.SUCCESS; } return InteractionResult.PASS; @@ -119,11 +119,11 @@ public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implement if (pole.getValue(PistonExtensionPoleBlock.FACING) .getAxis() != direction.getAxis()) return; - withTileEntityDo(worldIn, pos, te -> { - if (te.lastException == null) + withBlockEntityDo(worldIn, pos, be -> { + if (be.lastException == null) return; - te.lastException = null; - te.sendData(); + be.lastException = null; + be.sendData(); }); } @@ -189,7 +189,7 @@ public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implement } public static int maxAllowedPistonPoles() { - return AllConfigs.SERVER.kinetics.maxPistonPoles.get(); + return AllConfigs.server().kinetics.maxPistonPoles.get(); } @Override @@ -205,13 +205,13 @@ public class MechanicalPistonBlock extends DirectionalAxisKineticBlock implement } @Override - public Class getTileEntityClass() { - return MechanicalPistonTileEntity.class; + public Class getBlockEntityClass() { + return MechanicalPistonBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_PISTON.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_PISTON.get(); } public static boolean isPiston(BlockState state) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlockEntity.java new file mode 100644 index 0000000000..454be0101b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonBlockEntity.java @@ -0,0 +1,180 @@ +package com.simibubi.create.content.contraptions.piston; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionCollider; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.DirectionalExtenderScrollOptionSlot; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.Vec3; + +public class MechanicalPistonBlockEntity extends LinearActuatorBlockEntity { + + protected boolean hadCollisionWithOtherPiston; + protected int extensionLength; + + public MechanicalPistonBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + extensionLength = compound.getInt("ExtensionLength"); + super.read(compound, clientPacket); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + tag.putInt("ExtensionLength", extensionLength); + super.write(tag, clientPacket); + } + + @Override + public void assemble() throws AssemblyException { + if (!(level.getBlockState(worldPosition) + .getBlock() instanceof MechanicalPistonBlock)) + return; + + Direction direction = getBlockState().getValue(BlockStateProperties.FACING); + + // Collect Construct + PistonContraption contraption = new PistonContraption(direction, getMovementSpeed() < 0); + if (!contraption.assemble(level, worldPosition)) + return; + + Direction positive = Direction.get(AxisDirection.POSITIVE, direction.getAxis()); + Direction movementDirection = + getSpeed() > 0 ^ direction.getAxis() != Axis.Z ? positive : positive.getOpposite(); + + BlockPos anchor = contraption.anchor.relative(direction, contraption.initialExtensionProgress); + if (ContraptionCollider.isCollidingWithWorld(level, contraption, anchor.relative(movementDirection), + movementDirection)) + return; + + // Check if not at limit already + extensionLength = contraption.extensionLength; + float resultingOffset = contraption.initialExtensionProgress + Math.signum(getMovementSpeed()) * .5f; + if (resultingOffset <= 0 || resultingOffset >= extensionLength) { + return; + } + + // Run + running = true; + offset = contraption.initialExtensionProgress; + sendData(); + clientOffsetDiff = 0; + + BlockPos startPos = BlockPos.ZERO.relative(direction, contraption.initialExtensionProgress); + contraption.removeBlocksFromWorld(level, startPos); + movedContraption = ControlledContraptionEntity.create(getLevel(), this, contraption); + resetContraptionToOffset(); + forceMove = true; + level.addFreshEntity(movedContraption); + + AllSoundEvents.CONTRAPTION_ASSEMBLE.playOnServer(level, worldPosition); + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + } + + @Override + public void disassemble() { + if (!running && movedContraption == null) + return; + if (!remove) + getLevel().setBlock(worldPosition, getBlockState().setValue(MechanicalPistonBlock.STATE, PistonState.EXTENDED), + 3 | 16); + if (movedContraption != null) { + resetContraptionToOffset(); + movedContraption.disassemble(); + AllSoundEvents.CONTRAPTION_DISASSEMBLE.playOnServer(level, worldPosition); + } + running = false; + movedContraption = null; + sendData(); + + if (remove) + AllBlocks.MECHANICAL_PISTON.get() + .playerWillDestroy(level, worldPosition, getBlockState(), null); + } + + @Override + protected void collided() { + super.collided(); + if (!running && getMovementSpeed() > 0) + assembleNextTick = true; + } + + @Override + public float getMovementSpeed() { + float movementSpeed = Mth.clamp(convertToLinear(getSpeed()), -.49f, .49f); + if (level.isClientSide) + movementSpeed *= ServerSpeedProvider.get(); + Direction pistonDirection = getBlockState().getValue(BlockStateProperties.FACING); + int movementModifier = pistonDirection.getAxisDirection() + .getStep() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1); + movementSpeed = movementSpeed * -movementModifier + clientOffsetDiff / 2f; + + int extensionRange = getExtensionRange(); + movementSpeed = Mth.clamp(movementSpeed, 0 - offset, extensionRange - offset); + if (sequencedOffsetLimit >= 0) + movementSpeed = (float) Mth.clamp(movementSpeed, -sequencedOffsetLimit, sequencedOffsetLimit); + return movementSpeed; + } + + @Override + protected int getExtensionRange() { + return extensionLength; + } + + @Override + protected void visitNewPosition() {} + + @Override + protected Vec3 toMotionVector(float speed) { + Direction pistonDirection = getBlockState().getValue(BlockStateProperties.FACING); + return Vec3.atLowerCornerOf(pistonDirection.getNormal()) + .scale(speed); + } + + @Override + protected Vec3 toPosition(float offset) { + Vec3 position = Vec3.atLowerCornerOf(getBlockState().getValue(BlockStateProperties.FACING) + .getNormal()) + .scale(offset); + return position.add(Vec3.atLowerCornerOf(movedContraption.getContraption().anchor)); + } + + @Override + protected ValueBoxTransform getMovementModeSlot() { + return new DirectionalExtenderScrollOptionSlot((state, d) -> { + Axis axis = d.getAxis(); + Axis extensionAxis = state.getValue(MechanicalPistonBlock.FACING) + .getAxis(); + Axis shaftAxis = ((IRotate) state.getBlock()).getRotationAxis(state); + return extensionAxis != axis && shaftAxis != axis; + }); + } + + @Override + protected int getInitialOffset() { + return movedContraption == null ? 0 + : ((PistonContraption) movedContraption.getContraption()).initialExtensionProgress; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonGenerator.java b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonGenerator.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonGenerator.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonGenerator.java index 2483e8ac1d..f28a426d00 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonGenerator.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonGenerator.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonHeadBlock.java b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonHeadBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonHeadBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonHeadBlock.java index 202a8ffa9c..cecd5a2ab6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonHeadBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonHeadBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isExtensionPole; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonRenderer.java new file mode 100644 index 0000000000..e1ec5901d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/MechanicalPistonRenderer.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.contraptions.piston; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; + +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class MechanicalPistonRenderer extends KineticBlockEntityRenderer { + + public MechanicalPistonRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected BlockState getRenderedBlockState(MechanicalPistonBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonContraption.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/PistonContraption.java index a35c278e45..f55de5bb9d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonContraption.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; import static com.simibubi.create.AllBlocks.MECHANICAL_PISTON_HEAD; import static com.simibubi.create.AllBlocks.PISTON_EXTENSION_POLE; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPiston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isStickyPiston; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isPiston; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isPistonHead; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isStickyPiston; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; import java.util.ArrayList; @@ -14,13 +14,13 @@ import java.util.Queue; import org.apache.commons.lang3.tuple.Pair; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.BlockMovementChecks; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.TranslatingContraption; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -49,7 +49,7 @@ public class PistonContraption extends TranslatingContraption { private boolean retract; @Override - protected ContraptionType getType() { + public ContraptionType getType() { return ContraptionType.PISTON; } @@ -160,7 +160,7 @@ public class PistonContraption extends TranslatingContraption { boolean retracting = direction != orientation; if (retracting && !sticky) return true; - for (int offset = 0; offset <= AllConfigs.SERVER.kinetics.maxChassisRange.get(); offset++) { + for (int offset = 0; offset <= AllConfigs.server().kinetics.maxChassisRange.get(); offset++) { if (offset == 1 && retracting) return true; BlockPos currentPos = pos.relative(orientation, offset + initialExtensionProgress); @@ -204,9 +204,9 @@ public class PistonContraption extends TranslatingContraption { protected boolean customBlockPlacement(LevelAccessor world, BlockPos pos, BlockState state) { BlockPos pistonPos = anchor.relative(orientation, -1); BlockState pistonState = world.getBlockState(pistonPos); - BlockEntity te = world.getBlockEntity(pistonPos); + BlockEntity be = world.getBlockEntity(pistonPos); if (pos.equals(pistonPos)) { - if (te == null || te.isRemoved()) + if (be == null || be.isRemoved()) return true; if (!isExtensionPole(state) && isPiston(pistonState)) world.setBlock(pistonPos, pistonState.setValue(MechanicalPistonBlock.STATE, PistonState.RETRACTED), diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonExtensionPoleBlock.java similarity index 87% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/PistonExtensionPoleBlock.java index f153df8fde..ec8affdd86 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonExtensionPoleBlock.java @@ -1,17 +1,17 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPiston; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isPiston; +import static com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.isPistonHead; import java.util.function.Predicate; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; -import com.simibubi.create.foundation.utility.placement.PoleHelper; +import com.simibubi.create.foundation.placement.PoleHelper; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementHelpers; @@ -98,11 +98,11 @@ public class PistonExtensionPoleBlock extends WrenchableDirectionalBlock impleme worldIn.setBlockAndUpdate(basePos, worldIn.getBlockState(basePos) .setValue(MechanicalPistonBlock.STATE, PistonState.RETRACTED)); - BlockEntity te = worldIn.getBlockEntity(basePos); - if (te instanceof MechanicalPistonTileEntity) { - MechanicalPistonTileEntity baseTE = (MechanicalPistonTileEntity) te; - baseTE.offset = 0; - baseTE.onLengthBroken(); + BlockEntity be = worldIn.getBlockEntity(basePos); + if (be instanceof MechanicalPistonBlockEntity) { + MechanicalPistonBlockEntity baseBE = (MechanicalPistonBlockEntity) be; + baseBE.offset = 0; + baseBE.onLengthBroken(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonLighter.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java rename to src/main/java/com/simibubi/create/content/contraptions/piston/PistonLighter.java index cf1b2f9619..b21c795059 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonLighter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/piston/PistonLighter.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.piston; +package com.simibubi.create.content.contraptions.piston; import com.jozufozu.flywheel.util.box.GridAlignedBB; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; import net.minecraft.core.Vec3i; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java deleted file mode 100644 index c23c6c19c7..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.EntityCollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; - -public class BasinBlock extends Block implements ITE, IWrenchable { - - public static final DirectionProperty FACING = BlockStateProperties.FACING_HOPPER; - - public BasinBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - registerDefaultState(defaultBlockState().setValue(FACING, Direction.DOWN)); - } - - @Override - protected void createBlockStateDefinition(Builder p_206840_1_) { - super.createBlockStateDefinition(p_206840_1_.add(FACING)); - } - - @Override - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { - BlockEntity tileEntity = world.getBlockEntity(pos.above()); - if (tileEntity instanceof BasinOperatingTileEntity) - return false; - return true; - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - if (!context.getLevel().isClientSide) - withTileEntityDo(context.getLevel(), context.getClickedPos(), - bte -> bte.onWrenched(context.getClickedFace())); - return InteractionResult.SUCCESS; - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - ItemStack heldItem = player.getItemInHand(handIn); - - return onTileEntityUse(worldIn, pos, te -> { - if (!heldItem.isEmpty()) { - if (FluidHelper.tryEmptyItemIntoTE(worldIn, player, handIn, heldItem, te)) - return InteractionResult.SUCCESS; - if (FluidHelper.tryFillItemFromTE(worldIn, player, handIn, heldItem, te)) - return InteractionResult.SUCCESS; - - if (EmptyingByBasin.canItemBeEmptied(worldIn, heldItem) - || GenericItemFilling.canItemBeFilled(worldIn, heldItem)) - return InteractionResult.SUCCESS; - if (heldItem.getItem() - .equals(Items.SPONGE) - && !te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) - .map(iFluidHandler -> iFluidHandler.drain(Integer.MAX_VALUE, IFluidHandler.FluidAction.EXECUTE)) - .orElse(FluidStack.EMPTY) - .isEmpty()) { - return InteractionResult.SUCCESS; - } - return InteractionResult.PASS; - } - - IItemHandlerModifiable inv = te.itemCapability.orElse(new ItemStackHandler(1)); - boolean success = false; - for (int slot = 0; slot < inv.getSlots(); slot++) { - ItemStack stackInSlot = inv.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; - player.getInventory() - .placeItemBackInInventory(stackInSlot); - inv.setStackInSlot(slot, ItemStack.EMPTY); - success = true; - } - if (success) - worldIn.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, - 1f + Create.RANDOM.nextFloat()); - te.onEmptied(); - return InteractionResult.SUCCESS; - }); - } - - @Override - public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { - super.updateEntityAfterFallOn(worldIn, entityIn); - if (!AllBlocks.BASIN.has(worldIn.getBlockState(entityIn.blockPosition()))) - return; - if (!(entityIn instanceof ItemEntity)) - return; - if (!entityIn.isAlive()) - return; - ItemEntity itemEntity = (ItemEntity) entityIn; - withTileEntityDo(worldIn, entityIn.blockPosition(), te -> { - - // Tossed items bypass the quarter-stack limit - te.inputInventory.withMaxStackSize(64); - ItemStack insertItem = ItemHandlerHelper.insertItem(te.inputInventory, itemEntity.getItem() - .copy(), false); - te.inputInventory.withMaxStackSize(16); - - if (insertItem.isEmpty()) { - itemEntity.discard(); - return; - } - - itemEntity.setItem(insertItem); - }); - } - - @Override - public VoxelShape getInteractionShape(BlockState p_199600_1_, BlockGetter p_199600_2_, BlockPos p_199600_3_) { - return AllShapes.BASIN_RAYTRACE_SHAPE; - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return AllShapes.BASIN_BLOCK_SHAPE; - } - - @Override - public VoxelShape getCollisionShape(BlockState state, BlockGetter reader, BlockPos pos, CollisionContext ctx) { - if (ctx instanceof EntityCollisionContext && ((EntityCollisionContext) ctx).getEntity() instanceof ItemEntity) - return AllShapes.BASIN_COLLISION_SHAPE; - return getShape(state, reader, pos, ctx); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) - return; - TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE); - withTileEntityDo(worldIn, pos, te -> { - ItemHelper.dropContents(worldIn, pos, te.inputInventory); - ItemHelper.dropContents(worldIn, pos, te.outputInventory); - te.spoutputBuffer.forEach(is -> Block.popResource(worldIn, pos, is)); - }); - worldIn.removeBlockEntity(pos); - } - - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return getTileEntityOptional(worldIn, pos).map(BasinTileEntity::getInputInventory) - .map(ItemHelper::calcRedstoneFromInventory) - .orElse(0); - } - - @Override - public Class getTileEntityClass() { - return BasinTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.BASIN.get(); - } - - public static boolean canOutputTo(BlockGetter world, BlockPos basinPos, Direction direction) { - BlockPos neighbour = basinPos.relative(direction); - BlockPos output = neighbour.below(); - BlockState blockState = world.getBlockState(neighbour); - - if (FunnelBlock.isFunnel(blockState)) { - if (FunnelBlock.getFunnelFacing(blockState) == direction) - return false; - } else if (!blockState.getCollisionShape(world, neighbour) - .isEmpty()) { - return false; - } else { - BlockEntity tileEntity = world.getBlockEntity(output); - if (tileEntity instanceof BeltTileEntity) { - BeltTileEntity belt = (BeltTileEntity) tileEntity; - return belt.getSpeed() == 0 || belt.getMovementFacing() != direction.getOpposite(); - } - } - - DirectBeltInputBehaviour directBeltInputBehaviour = - TileEntityBehaviour.get(world, output, DirectBeltInputBehaviour.TYPE); - if (directBeltInputBehaviour != null) - return directBeltInputBehaviour.canInsertFromSide(direction); - return false; - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java deleted file mode 100644 index 3d590017a5..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import java.util.HashMap; -import java.util.Map; - -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; - -import net.minecraft.core.Direction; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.items.ItemStackHandler; - -public class BasinMovementBehaviour implements MovementBehaviour { - public Map getOrReadInventory(MovementContext context) { - Map map = new HashMap<>(); - map.put("InputItems", new ItemStackHandler(9)); - map.put("OutputItems", new ItemStackHandler(8)); - map.forEach((s, h) -> h.deserializeNBT(context.tileData.getCompound(s))); - return map; - } - - @Override - public boolean renderAsNormalTileEntity() { - return true; - } - - @Override - public void tick(MovementContext context) { - MovementBehaviour.super.tick(context); - if (context.temporaryData == null || (boolean) context.temporaryData) { - Vec3 facingVec = context.rotation.apply(Vec3.atLowerCornerOf(Direction.UP.getNormal())); - facingVec.normalize(); - if (Direction.getNearest(facingVec.x, facingVec.y, facingVec.z) == Direction.DOWN) - dump(context, facingVec); - } - } - - private void dump(MovementContext context, Vec3 facingVec) { - getOrReadInventory(context).forEach((key, itemStackHandler) -> { - for (int i = 0; i < itemStackHandler.getSlots(); i++) { - if (itemStackHandler.getStackInSlot(i) - .isEmpty()) - continue; - ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y, - context.position.z, itemStackHandler.getStackInSlot(i)); - itemEntity.setDeltaMovement(facingVec.scale(.05)); - context.world.addFreshEntity(itemEntity); - itemStackHandler.setStackInSlot(i, ItemStack.EMPTY); - } - context.tileData.put(key, itemStackHandler.serializeNBT()); - }); - BlockEntity tileEntity = context.contraption.presentTileEntities.get(context.localPos); - if (tileEntity instanceof BasinTileEntity) - ((BasinTileEntity) tileEntity).readOnlyItems(context.tileData); - context.temporaryData = false; // did already dump, so can't any more - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java deleted file mode 100644 index 925853aa2e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.advancement.CreateAdvancement; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.simple.DeferralBehaviour; -import com.simibubi.create.foundation.utility.recipe.RecipeFinder; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.Container; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class BasinOperatingTileEntity extends KineticTileEntity { - - public DeferralBehaviour basinChecker; - public boolean basinRemoved; - protected Recipe currentRecipe; - - public BasinOperatingTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - basinChecker = new DeferralBehaviour(this, this::updateBasin); - behaviours.add(basinChecker); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - if (getSpeed() == 0) - basinRemoved = true; - basinRemoved = false; - basinChecker.scheduleUpdate(); - } - - @Override - public void tick() { - if (basinRemoved) { - basinRemoved = false; - onBasinRemoved(); - sendData(); - return; - } - - super.tick(); - } - - protected boolean updateBasin() { - if (!isSpeedRequirementFulfilled()) - return true; - if (getSpeed() == 0) - return true; - if (isRunning()) - return true; - if (level == null || level.isClientSide) - return true; - Optional basin = getBasin(); - if (!basin.filter(BasinTileEntity::canContinueProcessing) - .isPresent()) - return true; - - List> recipes = getMatchingRecipes(); - if (recipes.isEmpty()) - return true; - currentRecipe = recipes.get(0); - startProcessingBasin(); - sendData(); - return true; - } - - protected abstract boolean isRunning(); - - public void startProcessingBasin() {} - - public boolean continueWithPreviousRecipe() { - return true; - } - - protected boolean matchBasinRecipe(Recipe recipe) { - if (recipe == null) - return false; - Optional basin = getBasin(); - if (!basin.isPresent()) - return false; - return BasinRecipe.match(basin.get(), recipe); - } - - protected void applyBasinRecipe() { - if (currentRecipe == null) - return; - - Optional optionalBasin = getBasin(); - if (!optionalBasin.isPresent()) - return; - BasinTileEntity basin = optionalBasin.get(); - boolean wasEmpty = basin.canContinueProcessing(); - if (!BasinRecipe.apply(basin, currentRecipe)) - return; - getProcessedRecipeTrigger().ifPresent(this::award); - basin.inputTank.sendDataImmediately(); - - // Continue mixing - if (wasEmpty && matchBasinRecipe(currentRecipe)) { - continueWithPreviousRecipe(); - sendData(); - } - - basin.notifyChangeOfContents(); - } - - protected List> getMatchingRecipes() { - if (getBasin().map(BasinTileEntity::isEmpty) - .orElse(true)) - return new ArrayList<>(); - - List> list = RecipeFinder.get(getRecipeCacheKey(), level, this::matchStaticFilters); - return list.stream() - .filter(this::matchBasinRecipe) - .sorted((r1, r2) -> r2.getIngredients() - .size() - - r1.getIngredients() - .size()) - .collect(Collectors.toList()); - } - - protected abstract void onBasinRemoved(); - - protected Optional getBasin() { - if (level == null) - return Optional.empty(); - BlockEntity basinTE = level.getBlockEntity(worldPosition.below(2)); - if (!(basinTE instanceof BasinTileEntity)) - return Optional.empty(); - return Optional.of((BasinTileEntity) basinTE); - } - - protected Optional getProcessedRecipeTrigger() { - return Optional.empty(); - } - - protected abstract boolean matchStaticFilters(Recipe recipe); - - protected abstract Object getRecipeCacheKey(); -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java deleted file mode 100644 index feb613367e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ /dev/null @@ -1,744 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -import javax.annotation.Nonnull; - -import com.google.common.collect.ImmutableList; -import com.simibubi.create.AllParticleTypes; -import com.simibubi.create.AllTags; -import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; -import com.simibubi.create.content.contraptions.fluids.FluidFX; -import com.simibubi.create.content.contraptions.fluids.particle.FluidParticleData; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.foundation.fluid.CombinedTankWrapper; -import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.IntAttached; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.StringTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.wrapper.CombinedInvWrapper; - -public class BasinTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - private boolean areFluidsMoving; - LerpedFloat ingredientRotationSpeed; - LerpedFloat ingredientRotation; - - public BasinInventory inputInventory; - public SmartFluidTankBehaviour inputTank; - protected SmartInventory outputInventory; - protected SmartFluidTankBehaviour outputTank; - private FilteringBehaviour filtering; - private boolean contentsChanged; - - private Couple invs; - private Couple tanks; - - protected LazyOptional itemCapability; - protected LazyOptional fluidCapability; - - List disabledSpoutputs; - Direction preferredSpoutput; - protected List spoutputBuffer; - protected List spoutputFluidBuffer; - int recipeBackupCheck; - - public static final int OUTPUT_ANIMATION_TIME = 10; - List> visualizedOutputItems; - List> visualizedOutputFluids; - - public BasinTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inputInventory = new BasinInventory(9, this); - inputInventory.whenContentsChanged($ -> contentsChanged = true); - outputInventory = new BasinInventory(9, this).forbidInsertion() - .withMaxStackSize(64); - areFluidsMoving = false; - itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory)); - contentsChanged = true; - ingredientRotation = LerpedFloat.angular() - .startWithValue(0); - ingredientRotationSpeed = LerpedFloat.linear() - .startWithValue(0); - - invs = Couple.create(inputInventory, outputInventory); - tanks = Couple.create(inputTank, outputTank); - visualizedOutputItems = Collections.synchronizedList(new ArrayList<>()); - visualizedOutputFluids = Collections.synchronizedList(new ArrayList<>()); - disabledSpoutputs = new ArrayList<>(); - preferredSpoutput = null; - spoutputBuffer = new ArrayList<>(); - spoutputFluidBuffer = new ArrayList<>(); - recipeBackupCheck = 20; - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(this)); - filtering = new FilteringBehaviour(this, new BasinValueBox()).moveText(new Vec3(2, -8, 0)) - .withCallback(newFilter -> contentsChanged = true) - .forRecipes(); - behaviours.add(filtering); - - inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true) - .whenFluidUpdates(() -> contentsChanged = true); - outputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.OUTPUT, this, 2, 1000, true) - .whenFluidUpdates(() -> contentsChanged = true) - .forbidInsertion(); - behaviours.add(inputTank); - behaviours.add(outputTank); - - fluidCapability = LazyOptional.of(() -> { - LazyOptional inputCap = inputTank.getCapability(); - LazyOptional outputCap = outputTank.getCapability(); - return new CombinedTankWrapper(outputCap.orElse(null), inputCap.orElse(null)); - }); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - inputInventory.deserializeNBT(compound.getCompound("InputItems")); - outputInventory.deserializeNBT(compound.getCompound("OutputItems")); - - preferredSpoutput = null; - if (compound.contains("PreferredSpoutput")) - preferredSpoutput = NBTHelper.readEnum(compound, "PreferredSpoutput", Direction.class); - disabledSpoutputs.clear(); - ListTag disabledList = compound.getList("DisabledSpoutput", Tag.TAG_STRING); - disabledList.forEach(d -> disabledSpoutputs.add(Direction.valueOf(((StringTag) d).getAsString()))); - spoutputBuffer = NBTHelper.readItemList(compound.getList("Overflow", Tag.TAG_COMPOUND)); - spoutputFluidBuffer = NBTHelper.readCompoundList(compound.getList("FluidOverflow", Tag.TAG_COMPOUND), - FluidStack::loadFluidStackFromNBT); - - if (!clientPacket) - return; - - NBTHelper.iterateCompoundList(compound.getList("VisualizedItems", Tag.TAG_COMPOUND), - c -> visualizedOutputItems.add(IntAttached.with(OUTPUT_ANIMATION_TIME, ItemStack.of(c)))); - NBTHelper.iterateCompoundList(compound.getList("VisualizedFluids", Tag.TAG_COMPOUND), - c -> visualizedOutputFluids - .add(IntAttached.with(OUTPUT_ANIMATION_TIME, FluidStack.loadFluidStackFromNBT(c)))); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.put("InputItems", inputInventory.serializeNBT()); - compound.put("OutputItems", outputInventory.serializeNBT()); - - if (preferredSpoutput != null) - NBTHelper.writeEnum(compound, "PreferredSpoutput", preferredSpoutput); - ListTag disabledList = new ListTag(); - disabledSpoutputs.forEach(d -> disabledList.add(StringTag.valueOf(d.name()))); - compound.put("DisabledSpoutput", disabledList); - compound.put("Overflow", NBTHelper.writeItemList(spoutputBuffer)); - compound.put("FluidOverflow", - NBTHelper.writeCompoundList(spoutputFluidBuffer, fs -> fs.writeToNBT(new CompoundTag()))); - - if (!clientPacket) - return; - - compound.put("VisualizedItems", NBTHelper.writeCompoundList(visualizedOutputItems, ia -> ia.getValue() - .serializeNBT())); - compound.put("VisualizedFluids", NBTHelper.writeCompoundList(visualizedOutputFluids, ia -> ia.getValue() - .writeToNBT(new CompoundTag()))); - visualizedOutputItems.clear(); - visualizedOutputFluids.clear(); - } - - public void onEmptied() { - getOperator().ifPresent(te -> te.basinRemoved = true); - } - - @Override - public void setRemoved() { - itemCapability.invalidate(); - fluidCapability.invalidate(); - super.setRemoved(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - onEmptied(); - super.setRemovedNotDueToChunkUnload(); - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return itemCapability.cast(); - if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) - return fluidCapability.cast(); - return super.getCapability(cap, side); - } - - @Override - public void notifyUpdate() { - super.notifyUpdate(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - - if (!level.isClientSide) { - updateSpoutput(); - if (recipeBackupCheck-- > 0) - return; - recipeBackupCheck = 20; - if (isEmpty()) - return; - notifyChangeOfContents(); - return; - } - - BlockEntity tileEntity = level.getBlockEntity(worldPosition.above(2)); - if (!(tileEntity instanceof MechanicalMixerTileEntity)) { - setAreFluidsMoving(false); - return; - } - - MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) tileEntity; - setAreFluidsMoving(mixer.running && mixer.runningTicks <= 20); - } - - public boolean isEmpty() { - return inputInventory.isEmpty() && outputInventory.isEmpty() && inputTank.isEmpty() && outputTank.isEmpty(); - } - - public void onWrenched(Direction face) { - BlockState blockState = getBlockState(); - Direction currentFacing = blockState.getValue(BasinBlock.FACING); - - disabledSpoutputs.remove(face); - if (currentFacing == face) { - if (preferredSpoutput == face) - preferredSpoutput = null; - disabledSpoutputs.add(face); - } else - preferredSpoutput = face; - - updateSpoutput(); - } - - private void updateSpoutput() { - BlockState blockState = getBlockState(); - Direction currentFacing = blockState.getValue(BasinBlock.FACING); - Direction newFacing = Direction.DOWN; - for (Direction test : Iterate.horizontalDirections) { - boolean canOutputTo = BasinBlock.canOutputTo(level, worldPosition, test); - if (canOutputTo && !disabledSpoutputs.contains(test)) - newFacing = test; - } - - if (preferredSpoutput != null && BasinBlock.canOutputTo(level, worldPosition, preferredSpoutput) - && preferredSpoutput != Direction.UP) - newFacing = preferredSpoutput; - - if (newFacing == currentFacing) - return; - - level.setBlockAndUpdate(worldPosition, blockState.setValue(BasinBlock.FACING, newFacing)); - - if (newFacing.getAxis() - .isVertical()) - return; - - for (int slot = 0; slot < outputInventory.getSlots(); slot++) { - ItemStack extractItem = outputInventory.extractItem(slot, 64, true); - if (extractItem.isEmpty()) - continue; - if (acceptOutputs(ImmutableList.of(extractItem), Collections.emptyList(), true)) - acceptOutputs(ImmutableList.of(outputInventory.extractItem(slot, 64, false)), Collections.emptyList(), - false); - } - - IFluidHandler handler = outputTank.getCapability() - .orElse(null); - for (int slot = 0; slot < handler.getTanks(); slot++) { - FluidStack fs = handler.getFluidInTank(slot) - .copy(); - if (fs.isEmpty()) - continue; - if (acceptOutputs(Collections.emptyList(), ImmutableList.of(fs), true)) { - handler.drain(fs, FluidAction.EXECUTE); - acceptOutputs(Collections.emptyList(), ImmutableList.of(fs), false); - } - } - - notifyChangeOfContents(); - notifyUpdate(); - } - - @Override - public void tick() { - super.tick(); - if (level.isClientSide) { - createFluidParticles(); - tickVisualizedOutputs(); - ingredientRotationSpeed.tickChaser(); - ingredientRotation.setValue(ingredientRotation.getValue() + ingredientRotationSpeed.getValue()); - } - - if ((!spoutputBuffer.isEmpty() || !spoutputFluidBuffer.isEmpty()) && !level.isClientSide) - tryClearingSpoutputOverflow(); - if (!contentsChanged) - return; - - contentsChanged = false; - getOperator().ifPresent(te -> te.basinChecker.scheduleUpdate()); - - for (Direction offset : Iterate.horizontalDirections) { - BlockPos toUpdate = worldPosition.above() - .relative(offset); - BlockState stateToUpdate = level.getBlockState(toUpdate); - if (stateToUpdate.getBlock() instanceof BasinBlock - && stateToUpdate.getValue(BasinBlock.FACING) == offset.getOpposite()) { - BlockEntity te = level.getBlockEntity(toUpdate); - if (te instanceof BasinTileEntity) - ((BasinTileEntity) te).contentsChanged = true; - } - } - } - - private void tryClearingSpoutputOverflow() { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof BasinBlock)) - return; - Direction direction = blockState.getValue(BasinBlock.FACING); - BlockEntity te = level.getBlockEntity(worldPosition.below() - .relative(direction)); - - FilteringBehaviour filter = null; - InvManipulationBehaviour inserter = null; - if (te != null) { - filter = TileEntityBehaviour.get(level, te.getBlockPos(), FilteringBehaviour.TYPE); - inserter = TileEntityBehaviour.get(level, te.getBlockPos(), InvManipulationBehaviour.TYPE); - } - - IItemHandler targetInv = te == null ? null - : te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, direction.getOpposite()) - .orElse(inserter == null ? null : inserter.getInventory()); - - IFluidHandler targetTank = te == null ? null - : te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite()) - .orElse(null); - - boolean update = false; - - for (Iterator iterator = spoutputBuffer.iterator(); iterator.hasNext();) { - ItemStack itemStack = iterator.next(); - - if (direction == Direction.DOWN) { - Block.popResource(level, worldPosition, itemStack); - iterator.remove(); - update = true; - continue; - } - - if (targetInv == null) - break; - if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack, true) - .isEmpty()) - continue; - if (filter != null && !filter.test(itemStack)) - continue; - - update = true; - ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), false); - iterator.remove(); - visualizedOutputItems.add(IntAttached.withZero(itemStack)); - } - - for (Iterator iterator = spoutputFluidBuffer.iterator(); iterator.hasNext();) { - FluidStack fluidStack = iterator.next(); - - if (direction == Direction.DOWN) { - iterator.remove(); - update = true; - continue; - } - - if (targetTank == null) - break; - - for (boolean simulate : Iterate.trueAndFalse) { - FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; - int fill = targetTank instanceof SmartFluidTankBehaviour.InternalFluidHandler - ? ((SmartFluidTankBehaviour.InternalFluidHandler) targetTank).forceFill(fluidStack.copy(), action) - : targetTank.fill(fluidStack.copy(), action); - if (fill != fluidStack.getAmount()) - break; - if (simulate) - continue; - - update = true; - iterator.remove(); - visualizedOutputFluids.add(IntAttached.withZero(fluidStack)); - } - } - - if (update) { - notifyChangeOfContents(); - sendData(); - } - } - - public float getTotalFluidUnits(float partialTicks) { - int renderedFluids = 0; - float totalUnits = 0; - - for (SmartFluidTankBehaviour behaviour : getTanks()) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) { - if (tankSegment.getRenderedFluid() - .isEmpty()) - continue; - float units = tankSegment.getTotalUnits(partialTicks); - if (units < 1) - continue; - totalUnits += units; - renderedFluids++; - } - } - - if (renderedFluids == 0) - return 0; - if (totalUnits < 1) - return 0; - return totalUnits; - } - - private Optional getOperator() { - if (level == null) - return Optional.empty(); - BlockEntity te = level.getBlockEntity(worldPosition.above(2)); - if (te instanceof BasinOperatingTileEntity) - return Optional.of((BasinOperatingTileEntity) te); - return Optional.empty(); - } - - public FilteringBehaviour getFilter() { - return filtering; - } - - public void notifyChangeOfContents() { - contentsChanged = true; - } - - public SmartInventory getInputInventory() { - return inputInventory; - } - - public SmartInventory getOutputInventory() { - return outputInventory; - } - - public boolean canContinueProcessing() { - return spoutputBuffer.isEmpty() && spoutputFluidBuffer.isEmpty(); - } - - public boolean acceptOutputs(List outputItems, List outputFluids, boolean simulate) { - outputInventory.allowInsertion(); - outputTank.allowInsertion(); - boolean acceptOutputsInner = acceptOutputsInner(outputItems, outputFluids, simulate); - outputInventory.forbidInsertion(); - outputTank.forbidInsertion(); - return acceptOutputsInner; - } - - private boolean acceptOutputsInner(List outputItems, List outputFluids, boolean simulate) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof BasinBlock)) - return false; - - Direction direction = blockState.getValue(BasinBlock.FACING); - if (direction != Direction.DOWN) { - - BlockEntity te = level.getBlockEntity(worldPosition.below() - .relative(direction)); - - InvManipulationBehaviour inserter = - te == null ? null : TileEntityBehaviour.get(level, te.getBlockPos(), InvManipulationBehaviour.TYPE); - IItemHandler targetInv = te == null ? null - : te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, direction.getOpposite()) - .orElse(inserter == null ? null : inserter.getInventory()); - IFluidHandler targetTank = te == null ? null - : te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite()) - .orElse(null); - boolean externalTankNotPresent = targetTank == null; - - if (!outputItems.isEmpty() && targetInv == null) - return false; - if (!outputFluids.isEmpty() && externalTankNotPresent) { - // Special case - fluid outputs but output only accepts items - targetTank = outputTank.getCapability() - .orElse(null); - if (targetTank == null) - return false; - if (!acceptFluidOutputsIntoBasin(outputFluids, simulate, targetTank)) - return false; - } - - if (simulate) - return true; - for (ItemStack itemStack : outputItems) { - if (itemStack.hasContainerItem() && itemStack.getContainerItem() - .sameItem(itemStack)) - continue; - spoutputBuffer.add(itemStack.copy()); - } - if (!externalTankNotPresent) - for (FluidStack fluidStack : outputFluids) - spoutputFluidBuffer.add(fluidStack.copy()); - return true; - } - - IItemHandler targetInv = outputInventory; - IFluidHandler targetTank = outputTank.getCapability() - .orElse(null); - - if (targetInv == null && !outputItems.isEmpty()) - return false; - if (!acceptItemOutputsIntoBasin(outputItems, simulate, targetInv)) - return false; - if (outputFluids.isEmpty()) - return true; - if (targetTank == null) - return false; - if (!acceptFluidOutputsIntoBasin(outputFluids, simulate, targetTank)) - return false; - - return true; - } - - private boolean acceptFluidOutputsIntoBasin(List outputFluids, boolean simulate, - IFluidHandler targetTank) { - for (FluidStack fluidStack : outputFluids) { - FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; - int fill = targetTank instanceof SmartFluidTankBehaviour.InternalFluidHandler - ? ((SmartFluidTankBehaviour.InternalFluidHandler) targetTank).forceFill(fluidStack.copy(), action) - : targetTank.fill(fluidStack.copy(), action); - if (fill != fluidStack.getAmount()) - return false; - } - return true; - } - - private boolean acceptItemOutputsIntoBasin(List outputItems, boolean simulate, IItemHandler targetInv) { - for (ItemStack itemStack : outputItems) { - // Catalyst items are never consumed - if (itemStack.hasContainerItem() && itemStack.getContainerItem() - .sameItem(itemStack)) - continue; - if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate) - .isEmpty()) - return false; - } - return true; - } - - public void readOnlyItems(CompoundTag compound) { - inputInventory.deserializeNBT(compound.getCompound("InputItems")); - outputInventory.deserializeNBT(compound.getCompound("OutputItems")); - } - - public static HeatLevel getHeatLevelOf(BlockState state) { - if (state.hasProperty(BlazeBurnerBlock.HEAT_LEVEL)) - return state.getValue(BlazeBurnerBlock.HEAT_LEVEL); - return AllTags.AllBlockTags.PASSIVE_BOILER_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; - } - - public Couple getTanks() { - return tanks; - } - - public Couple getInvs() { - return invs; - } - - // client things - - private void tickVisualizedOutputs() { - visualizedOutputFluids.forEach(IntAttached::decrement); - visualizedOutputItems.forEach(IntAttached::decrement); - visualizedOutputFluids.removeIf(IntAttached::isOrBelowZero); - visualizedOutputItems.removeIf(IntAttached::isOrBelowZero); - } - - private void createFluidParticles() { - Random r = level.random; - - if (!visualizedOutputFluids.isEmpty()) - createOutputFluidParticles(r); - - if (!areFluidsMoving && r.nextFloat() > 1 / 8f) - return; - - int segments = 0; - for (SmartFluidTankBehaviour behaviour : getTanks()) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) - if (!tankSegment.isEmpty(0)) - segments++; - } - if (segments < 2) - return; - - float totalUnits = getTotalFluidUnits(0); - if (totalUnits == 0) - return; - float fluidLevel = Mth.clamp(totalUnits / 2000, 0, 1); - float rim = 2 / 16f; - float space = 12 / 16f; - float surface = worldPosition.getY() + rim + space * fluidLevel + 1 / 32f; - - if (areFluidsMoving) { - createMovingFluidParticles(surface, segments); - return; - } - - for (SmartFluidTankBehaviour behaviour : getTanks()) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) { - if (tankSegment.isEmpty(0)) - continue; - float x = worldPosition.getX() + rim + space * r.nextFloat(); - float z = worldPosition.getZ() + rim + space * r.nextFloat(); - level.addAlwaysVisibleParticle( - new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), x, - surface, z, 0, 0, 0); - } - } - } - - private void createOutputFluidParticles(Random r) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof BasinBlock)) - return; - Direction direction = blockState.getValue(BasinBlock.FACING); - if (direction == Direction.DOWN) - return; - Vec3 directionVec = Vec3.atLowerCornerOf(direction.getNormal()); - Vec3 outVec = VecHelper.getCenterOf(worldPosition) - .add(directionVec.scale(.65) - .subtract(0, 1 / 4f, 0)); - Vec3 outMotion = directionVec.scale(1 / 16f) - .add(0, -1 / 16f, 0); - - for (int i = 0; i < 2; i++) { - visualizedOutputFluids.forEach(ia -> { - FluidStack fluidStack = ia.getValue(); - ParticleOptions fluidParticle = FluidFX.getFluidParticle(fluidStack); - Vec3 m = VecHelper.offsetRandomly(outMotion, r, 1 / 16f); - level.addAlwaysVisibleParticle(fluidParticle, outVec.x, outVec.y, outVec.z, m.x, m.y, m.z); - }); - } - } - - private void createMovingFluidParticles(float surface, int segments) { - Vec3 pointer = new Vec3(1, 0, 0).scale(1 / 16f); - float interval = 360f / segments; - Vec3 centerOf = VecHelper.getCenterOf(worldPosition); - float intervalOffset = (AnimationTickHolder.getTicks() * 18) % 360; - - int currentSegment = 0; - for (SmartFluidTankBehaviour behaviour : getTanks()) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) { - if (tankSegment.isEmpty(0)) - continue; - float angle = interval * (1 + currentSegment) + intervalOffset; - Vec3 vec = centerOf.add(VecHelper.rotate(pointer, angle, Axis.Y)); - level.addAlwaysVisibleParticle( - new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), vec.x(), - surface, vec.z(), 1, 0, 0); - currentSegment++; - } - } - } - - public boolean areFluidsMoving() { - return areFluidsMoving; - } - - public boolean setAreFluidsMoving(boolean areFluidsMoving) { - this.areFluidsMoving = areFluidsMoving; - ingredientRotationSpeed.chase(areFluidsMoving ? 20 : 0, .1f, Chaser.EXP); - return areFluidsMoving; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - return containedFluidTooltip(tooltip, isPlayerSneaking, - getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); - } - - class BasinValueBox extends ValueBoxTransform.Sided { - - @Override - protected Vec3 getSouthLocation() { - return VecHelper.voxelSpace(8, 12, 15.75); - } - - @Override - protected boolean isSideActive(BlockState state, Direction direction) { - return direction.getAxis() - .isHorizontal(); - } - - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java b/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java deleted file mode 100644 index 95f75c9621..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingByBasin.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; - -import net.createmod.catnip.utility.Pair; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.PotionItem; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.Level; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; -import net.minecraftforge.fluids.capability.IFluidHandlerItem; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class EmptyingByBasin { - - static RecipeWrapper wrapper = new RecipeWrapper(new ItemStackHandler(1)); - - public static boolean canItemBeEmptied(Level world, ItemStack stack) { - if (stack.getItem() instanceof PotionItem) - return true; - - wrapper.setItem(0, stack); - if (AllRecipeTypes.EMPTYING.find(wrapper, world) - .isPresent()) - return true; - - LazyOptional capability = - stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); - IFluidHandlerItem tank = capability.orElse(null); - if (tank == null) - return false; - for (int i = 0; i < tank.getTanks(); i++) { - if (tank.getFluidInTank(i) - .getAmount() > 0) - return true; - } - return false; - } - - public static Pair emptyItem(Level world, ItemStack stack, boolean simulate) { - FluidStack resultingFluid = FluidStack.EMPTY; - ItemStack resultingItem = ItemStack.EMPTY; - - if (stack.getItem() instanceof PotionItem) - return PotionFluidHandler.emptyPotion(stack, simulate); - - wrapper.setItem(0, stack); - Optional> recipe = AllRecipeTypes.EMPTYING.find(wrapper, world); - if (recipe.isPresent()) { - EmptyingRecipe emptyingRecipe = (EmptyingRecipe) recipe.get(); - List results = emptyingRecipe.rollResults(); - if (!simulate) - stack.shrink(1); - resultingItem = results.isEmpty() ? ItemStack.EMPTY : results.get(0); - resultingFluid = emptyingRecipe.getResultingFluid(); - return Pair.of(resultingFluid, resultingItem); - } - - ItemStack split = stack.copy(); - split.setCount(1); - LazyOptional capability = - split.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); - IFluidHandlerItem tank = capability.orElse(null); - if (tank == null) - return Pair.of(resultingFluid, resultingItem); - resultingFluid = tank.drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE); - resultingItem = tank.getContainer() - .copy(); - if (!simulate) - stack.shrink(1); - - return Pair.of(resultingFluid, resultingItem); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/InWorldProcessing.java b/src/main/java/com/simibubi/create/content/contraptions/processing/InWorldProcessing.java deleted file mode 100644 index e309645429..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/InWorldProcessing.java +++ /dev/null @@ -1,505 +0,0 @@ -package com.simibubi.create.content.contraptions.processing; - -import static com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.getHeatLevelOf; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.components.deployer.ManualApplicationRecipe; -import com.simibubi.create.content.contraptions.components.fan.HauntingRecipe; -import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.LitBlazeBurnerBlock; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.core.BlockPos; -import net.minecraft.core.particles.DustParticleOptions; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.animal.horse.Horse; -import net.minecraft.world.entity.animal.horse.SkeletonHorse; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.monster.EnderMan; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.BlastingRecipe; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraft.world.item.crafting.SmeltingRecipe; -import net.minecraft.world.item.crafting.SmokingRecipe; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.CampfireBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.RecipeWrapper; - -public class InWorldProcessing { - - private static final DamageSource FIRE_DAMAGE_SOURCE = new DamageSource("create.fan_fire").setScalesWithDifficulty() - .setIsFire(); - private static final DamageSource LAVA_DAMAGE_SOURCE = new DamageSource("create.fan_lava").setScalesWithDifficulty() - .setIsFire(); - - private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1)); - private static final SplashingWrapper SPLASHING_WRAPPER = new SplashingWrapper(); - private static final HauntingWrapper HAUNTING_WRAPPER = new HauntingWrapper(); - - public static boolean canProcess(ItemEntity entity, Type type) { - if (entity.getPersistentData() - .contains("CreateData")) { - CompoundTag compound = entity.getPersistentData() - .getCompound("CreateData"); - if (compound.contains("Processing")) { - CompoundTag processing = compound.getCompound("Processing"); - - if (Type.valueOf(processing.getString("Type")) != type) - return type.canProcess(entity.getItem(), entity.level); - else if (processing.getInt("Time") >= 0) - return true; - else if (processing.getInt("Time") == -1) - return false; - } - } - return type.canProcess(entity.getItem(), entity.level); - } - - public static boolean isWashable(ItemStack stack, Level world) { - SPLASHING_WRAPPER.setItem(0, stack); - Optional recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world); - return recipe.isPresent(); - } - - public static boolean isHauntable(ItemStack stack, Level world) { - HAUNTING_WRAPPER.setItem(0, stack); - Optional recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world); - return recipe.isPresent(); - } - - public static boolean applyProcessing(ItemEntity entity, Type type) { - if (decrementProcessingTime(entity, type) != 0) - return false; - List stacks = process(entity.getItem(), type, entity.level); - if (stacks == null) - return false; - if (stacks.isEmpty()) { - entity.discard(); - return false; - } - entity.setItem(stacks.remove(0)); - for (ItemStack additional : stacks) { - ItemEntity entityIn = new ItemEntity(entity.level, entity.getX(), entity.getY(), entity.getZ(), additional); - entityIn.setDeltaMovement(entity.getDeltaMovement()); - entity.level.addFreshEntity(entityIn); - } - return true; - } - - public static TransportedResult applyProcessing(TransportedItemStack transported, Level world, Type type) { - TransportedResult ignore = TransportedResult.doNothing(); - if (transported.processedBy != type) { - transported.processedBy = type; - int timeModifierForStackSize = ((transported.stack.getCount() - 1) / 16) + 1; - int processingTime = - (int) (AllConfigs.SERVER.kinetics.inWorldProcessingTime.get() * timeModifierForStackSize) + 1; - transported.processingTime = processingTime; - if (!type.canProcess(transported.stack, world)) - transported.processingTime = -1; - return ignore; - } - if (transported.processingTime == -1) - return ignore; - if (transported.processingTime-- > 0) - return ignore; - - List stacks = process(transported.stack, type, world); - if (stacks == null) - return ignore; - - List transportedStacks = new ArrayList<>(); - for (ItemStack additional : stacks) { - TransportedItemStack newTransported = transported.getSimilar(); - newTransported.stack = additional.copy(); - transportedStacks.add(newTransported); - } - return TransportedResult.convertTo(transportedStacks); - } - - private static List process(ItemStack stack, Type type, Level world) { - if (type == Type.SPLASHING) { - SPLASHING_WRAPPER.setItem(0, stack); - Optional recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world); - if (recipe.isPresent()) - return applyRecipeOn(stack, recipe.get()); - return null; - } - if (type == Type.HAUNTING) { - HAUNTING_WRAPPER.setItem(0, stack); - Optional recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world); - if (recipe.isPresent()) - return applyRecipeOn(stack, recipe.get()); - return null; - } - - RECIPE_WRAPPER.setItem(0, stack); - Optional smokingRecipe = world.getRecipeManager() - .getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, world); - - if (type == Type.BLASTING) { - if (!smokingRecipe.isPresent()) { - RECIPE_WRAPPER.setItem(0, stack); - Optional smeltingRecipe = world.getRecipeManager() - .getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, world); - - if (smeltingRecipe.isPresent()) - return applyRecipeOn(stack, smeltingRecipe.get()); - - RECIPE_WRAPPER.setItem(0, stack); - Optional blastingRecipe = world.getRecipeManager() - .getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, world); - - if (blastingRecipe.isPresent()) - return applyRecipeOn(stack, blastingRecipe.get()); - } - - return Collections.emptyList(); - } - - if (type == Type.SMOKING && smokingRecipe.isPresent()) - return applyRecipeOn(stack, smokingRecipe.get()); - - return null; - } - - private static int decrementProcessingTime(ItemEntity entity, Type type) { - CompoundTag nbt = entity.getPersistentData(); - - if (!nbt.contains("CreateData")) - nbt.put("CreateData", new CompoundTag()); - CompoundTag createData = nbt.getCompound("CreateData"); - - if (!createData.contains("Processing")) - createData.put("Processing", new CompoundTag()); - CompoundTag processing = createData.getCompound("Processing"); - - if (!processing.contains("Type") || Type.valueOf(processing.getString("Type")) != type) { - processing.putString("Type", type.name()); - int timeModifierForStackSize = ((entity.getItem() - .getCount() - 1) / 16) + 1; - int processingTime = - (int) (AllConfigs.SERVER.kinetics.inWorldProcessingTime.get() * timeModifierForStackSize) + 1; - processing.putInt("Time", processingTime); - } - - int value = processing.getInt("Time") - 1; - processing.putInt("Time", value); - return value; - } - - public static void applyRecipeOn(ItemEntity entity, Recipe recipe) { - List stacks = applyRecipeOn(entity.getItem(), recipe); - if (stacks == null) - return; - if (stacks.isEmpty()) { - entity.discard(); - return; - } - entity.setItem(stacks.remove(0)); - for (ItemStack additional : stacks) { - ItemEntity entityIn = new ItemEntity(entity.level, entity.getX(), entity.getY(), entity.getZ(), additional); - entityIn.setDeltaMovement(entity.getDeltaMovement()); - entity.level.addFreshEntity(entityIn); - } - } - - public static List applyRecipeOn(ItemStack stackIn, Recipe recipe) { - List stacks; - - if (recipe instanceof ProcessingRecipe pr) { - stacks = new ArrayList<>(); - for (int i = 0; i < stackIn.getCount(); i++) { - List outputs = - pr instanceof ManualApplicationRecipe mar ? mar.getRollableResults() : pr.getRollableResults(); - for (ItemStack stack : pr.rollResults(outputs)) { - for (ItemStack previouslyRolled : stacks) { - if (stack.isEmpty()) - continue; - if (!ItemHandlerHelper.canItemStacksStack(stack, previouslyRolled)) - continue; - int amount = Math.min(previouslyRolled.getMaxStackSize() - previouslyRolled.getCount(), - stack.getCount()); - previouslyRolled.grow(amount); - stack.shrink(amount); - } - - if (stack.isEmpty()) - continue; - - stacks.add(stack); - } - } - } else { - ItemStack out = recipe.getResultItem() - .copy(); - stacks = ItemHelper.multipliedOutput(stackIn, out); - } - - return stacks; - } - - public enum Type { - SPLASHING { - @Override - public void spawnParticlesForProcessing(Level level, Vec3 pos) { - if (level.random.nextInt(8) != 0) - return; - Vector3f color = new Color(0x0055FF).asVectorF(); - level.addParticle(new DustParticleOptions(color, 1), pos.x + (level.random.nextFloat() - .5f) * .5f, - pos.y + .5f, pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); - level.addParticle(ParticleTypes.SPIT, pos.x + (level.random.nextFloat() - .5f) * .5f, pos.y + .5f, - pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); - } - - @Override - public void affectEntity(Entity entity, Level level) { - if (level.isClientSide) - return; - - if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM - || entity.getType() == EntityType.BLAZE) { - entity.hurt(DamageSource.DROWN, 2); - } - if (entity.isOnFire()) { - entity.clearFire(); - level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, - SoundSource.NEUTRAL, 0.7F, 1.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F); - } - } - - @Override - public boolean canProcess(ItemStack stack, Level level) { - return isWashable(stack, level); - } - }, - SMOKING { - @Override - public void spawnParticlesForProcessing(Level level, Vec3 pos) { - if (level.random.nextInt(8) != 0) - return; - level.addParticle(ParticleTypes.POOF, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0); - } - - @Override - public void affectEntity(Entity entity, Level level) { - if (level.isClientSide) - return; - - if (!entity.fireImmune()) { - entity.setSecondsOnFire(2); - entity.hurt(FIRE_DAMAGE_SOURCE, 2); - } - } - - @Override - public boolean canProcess(ItemStack stack, Level level) { - RECIPE_WRAPPER.setItem(0, stack); - Optional recipe = level.getRecipeManager() - .getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level); - return recipe.isPresent(); - } - }, - HAUNTING { - @Override - public void spawnParticlesForProcessing(Level level, Vec3 pos) { - if (level.random.nextInt(8) != 0) - return; - pos = pos.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) - .multiply(1, 0.05f, 1) - .normalize() - .scale(0.15f)); - level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, pos.x, pos.y + .45f, pos.z, 0, 0, 0); - if (level.random.nextInt(2) == 0) - level.addParticle(ParticleTypes.SMOKE, pos.x, pos.y + .25f, pos.z, 0, 0, 0); - } - - @Override - public void affectEntity(Entity entity, Level level) { - if (level.isClientSide) { - if (entity instanceof Horse) { - Vec3 p = entity.getPosition(0); - Vec3 v = p.add(0, 0.5f, 0) - .add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) - .multiply(1, 0.2f, 1) - .normalize() - .scale(1f)); - level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0); - if (level.random.nextInt(3) == 0) - level.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z, - (level.random.nextFloat() - .5f) * .5f, 0.1f, (level.random.nextFloat() - .5f) * .5f); - } - return; - } - - if (entity instanceof LivingEntity livingEntity) { - livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false)); - livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false)); - } - if (entity instanceof Horse horse) { - int progress = horse.getPersistentData() - .getInt("CreateHaunting"); - if (progress < 100) { - if (progress % 10 == 0) { - level.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL, - 1f, 1.5f * progress / 100f); - } - horse.getPersistentData() - .putInt("CreateHaunting", progress + 1); - return; - } - - level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, - SoundSource.NEUTRAL, 1.25f, 0.65f); - - SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(level); - CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag()); - serializeNBT.remove("UUID"); - if (!horse.getArmor() - .isEmpty()) - horse.spawnAtLocation(horse.getArmor()); - - skeletonHorse.deserializeNBT(serializeNBT); - skeletonHorse.setPos(horse.getPosition(0)); - level.addFreshEntity(skeletonHorse); - horse.discard(); - } - } - - @Override - public boolean canProcess(ItemStack stack, Level level) { - return isHauntable(stack, level); - } - }, - BLASTING { - @Override - public void spawnParticlesForProcessing(Level level, Vec3 pos) { - if (level.random.nextInt(8) != 0) - return; - level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0); - } - - @Override - public void affectEntity(Entity entity, Level level) { - if (level.isClientSide) - return; - - if (!entity.fireImmune()) { - entity.setSecondsOnFire(10); - entity.hurt(LAVA_DAMAGE_SOURCE, 4); - } - } - - @Override - public boolean canProcess(ItemStack stack, Level level) { - RECIPE_WRAPPER.setItem(0, stack); - Optional smeltingRecipe = level.getRecipeManager() - .getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level); - - if (smeltingRecipe.isPresent()) - return true; - - RECIPE_WRAPPER.setItem(0, stack); - Optional blastingRecipe = level.getRecipeManager() - .getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level); - - if (blastingRecipe.isPresent()) - return true; - - return !stack.getItem() - .isFireResistant(); - } - }, - NONE { - @Override - public void spawnParticlesForProcessing(Level level, Vec3 pos) {} - - @Override - public void affectEntity(Entity entity, Level level) {} - - @Override - public boolean canProcess(ItemStack stack, Level level) { - return false; - } - }; - - public abstract boolean canProcess(ItemStack stack, Level level); - - public abstract void spawnParticlesForProcessing(Level level, Vec3 pos); - - public abstract void affectEntity(Entity entity, Level level); - - public static Type byBlock(BlockGetter reader, BlockPos pos) { - FluidState fluidState = reader.getFluidState(pos); - if (fluidState.getType() == Fluids.WATER || fluidState.getType() == Fluids.FLOWING_WATER) - return Type.SPLASHING; - BlockState blockState = reader.getBlockState(pos); - Block block = blockState.getBlock(); - if (block == Blocks.SOUL_FIRE - || block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT) - .orElse(false) - || AllBlocks.LIT_BLAZE_BURNER.has(blockState) - && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE) - .map(flame -> flame == LitBlazeBurnerBlock.FlameType.SOUL) - .orElse(false)) - return Type.HAUNTING; - if (block == Blocks.FIRE - || blockState.is(BlockTags.CAMPFIRES) && blockState.getOptionalValue(CampfireBlock.LIT) - .orElse(false) - || AllBlocks.LIT_BLAZE_BURNER.has(blockState) - && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE) - .map(flame -> flame == LitBlazeBurnerBlock.FlameType.REGULAR) - .orElse(false) - || getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING) - return Type.SMOKING; - if (block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) - return Type.BLASTING; - return Type.NONE; - } - } - - public static class SplashingWrapper extends RecipeWrapper { - public SplashingWrapper() { - super(new ItemStackHandler(1)); - } - } - - public static class HauntingWrapper extends RecipeWrapper { - public HauntingWrapper() { - super(new ItemStackHandler(1)); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java deleted file mode 100644 index 29fde8d2df..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java +++ /dev/null @@ -1,344 +0,0 @@ -package com.simibubi.create.content.contraptions.processing.burner; - -import java.util.List; -import java.util.Random; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllTags.AllItemTags; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeHooks; - -public class BlazeBurnerTileEntity extends SmartTileEntity { - - public static final int MAX_HEAT_CAPACITY = 10000; - - protected FuelType activeFuel; - protected int remainingBurnTime; - protected LerpedFloat headAnimation; - protected LerpedFloat headAngle; - protected boolean isCreative; - protected boolean goggles; - protected boolean hat; - - public BlazeBurnerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - activeFuel = FuelType.NONE; - remainingBurnTime = 0; - headAnimation = LerpedFloat.linear(); - headAngle = LerpedFloat.angular(); - isCreative = false; - goggles = false; - - headAngle.startWithValue((AngleHelper.horizontalAngle(state.getOptionalValue(BlazeBurnerBlock.FACING) - .orElse(Direction.SOUTH)) + 180) % 360); - } - - public FuelType getActiveFuel() { - return activeFuel; - } - - public int getRemainingBurnTime() { - return remainingBurnTime; - } - - public boolean isCreative() { - return isCreative; - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) { - tickAnimation(); - if (!isVirtual()) - spawnParticles(getHeatLevelFromBlock(), 1); - return; - } - - if (isCreative) - return; - - if (remainingBurnTime > 0) - remainingBurnTime--; - - if (activeFuel == FuelType.NORMAL) - updateBlockState(); - if (remainingBurnTime > 0) - return; - - if (activeFuel == FuelType.SPECIAL) { - activeFuel = FuelType.NORMAL; - remainingBurnTime = MAX_HEAT_CAPACITY / 2; - } else - activeFuel = FuelType.NONE; - - updateBlockState(); - } - - @OnlyIn(Dist.CLIENT) - private void tickAnimation() { - boolean active = getHeatLevelFromBlock().isAtLeast(HeatLevel.FADING) && isValidBlockAbove(); - - if (!active) { - float target = 0; - LocalPlayer player = Minecraft.getInstance().player; - if (player != null && !player.isInvisible()) { - double x; - double z; - if (isVirtual()) { - x = -4; - z = -10; - } else { - x = player.getX(); - z = player.getZ(); - } - double dx = x - (getBlockPos().getX() + 0.5); - double dz = z - (getBlockPos().getZ() + 0.5); - target = AngleHelper.deg(-Mth.atan2(dz, dx)) - 90; - } - target = headAngle.getValue() + AngleHelper.getShortestAngleDiff(headAngle.getValue(), target); - headAngle.chase(target, .25f, Chaser.exp(5)); - headAngle.tickChaser(); - } else { - headAngle.chase((AngleHelper.horizontalAngle(getBlockState().getOptionalValue(BlazeBurnerBlock.FACING) - .orElse(Direction.SOUTH)) + 180) % 360, .125f, Chaser.EXP); - headAngle.tickChaser(); - } - - headAnimation.chase(active ? 1 : 0, .25f, Chaser.exp(.25f)); - headAnimation.tickChaser(); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (!isCreative) { - compound.putInt("fuelLevel", activeFuel.ordinal()); - compound.putInt("burnTimeRemaining", remainingBurnTime); - } else - compound.putBoolean("isCreative", true); - if (goggles) - compound.putBoolean("Goggles", true); - if (hat) - compound.putBoolean("TrainHat", true); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - activeFuel = FuelType.values()[compound.getInt("fuelLevel")]; - remainingBurnTime = compound.getInt("burnTimeRemaining"); - isCreative = compound.getBoolean("isCreative"); - goggles = compound.contains("Goggles"); - hat = compound.contains("TrainHat"); - super.read(compound, clientPacket); - } - - public BlazeBurnerBlock.HeatLevel getHeatLevelFromBlock() { - return BlazeBurnerBlock.getHeatLevelOf(getBlockState()); - } - - public void updateBlockState() { - setBlockHeat(getHeatLevelFromFuelType(activeFuel)); - } - - protected void setBlockHeat(HeatLevel heat) { - HeatLevel inBlockState = getHeatLevelFromBlock(); - if (inBlockState == heat) - return; - level.setBlockAndUpdate(worldPosition, getBlockState().setValue(BlazeBurnerBlock.HEAT_LEVEL, heat)); - notifyUpdate(); - } - - /** - * @return true if the heater updated its burn time and an item should be - * consumed - */ - protected boolean tryUpdateFuel(ItemStack itemStack, boolean forceOverflow, boolean simulate) { - if (isCreative) - return false; - - FuelType newFuel = FuelType.NONE; - int newBurnTime; - - if (AllItemTags.BLAZE_BURNER_FUEL_SPECIAL.matches(itemStack)) { - newBurnTime = 1000; - newFuel = FuelType.SPECIAL; - } else { - newBurnTime = ForgeHooks.getBurnTime(itemStack, null); - if (newBurnTime > 0) - newFuel = FuelType.NORMAL; - else if (AllItemTags.BLAZE_BURNER_FUEL_REGULAR.matches(itemStack)) { - newBurnTime = 1600; // Same as coal - newFuel = FuelType.NORMAL; - } - } - - if (newFuel == FuelType.NONE) - return false; - if (newFuel.ordinal() < activeFuel.ordinal()) - return false; - if (activeFuel == FuelType.SPECIAL && remainingBurnTime > 20) - return false; - - if (newFuel == activeFuel) { - if (remainingBurnTime + newBurnTime > MAX_HEAT_CAPACITY && !forceOverflow) - return false; - newBurnTime = Mth.clamp(remainingBurnTime + newBurnTime, 0, MAX_HEAT_CAPACITY); - } - - if (simulate) - return true; - - activeFuel = newFuel; - remainingBurnTime = newBurnTime; - - if (level.isClientSide) { - spawnParticleBurst(activeFuel == FuelType.SPECIAL); - return true; - } - - HeatLevel prev = getHeatLevelFromBlock(); - playSound(); - updateBlockState(); - - if (prev != getHeatLevelFromBlock()) - level.playSound(null, worldPosition, SoundEvents.BLAZE_AMBIENT, SoundSource.BLOCKS, - .125f + level.random.nextFloat() * .125f, 1.15f - level.random.nextFloat() * .25f); - - return true; - } - - protected void applyCreativeFuel() { - activeFuel = FuelType.NONE; - remainingBurnTime = 0; - isCreative = true; - - HeatLevel next = getHeatLevelFromBlock().nextActiveLevel(); - - if (level.isClientSide) { - spawnParticleBurst(next.isAtLeast(HeatLevel.SEETHING)); - return; - } - - playSound(); - if (next == HeatLevel.FADING) - next = next.nextActiveLevel(); - setBlockHeat(next); - } - - public boolean isCreativeFuel(ItemStack stack) { - return AllItems.CREATIVE_BLAZE_CAKE.isIn(stack); - } - - public boolean isValidBlockAbove() { - BlockState blockState = level.getBlockState(worldPosition.above()); - return AllBlocks.BASIN.has(blockState) || blockState.getBlock() instanceof FluidTankBlock; - } - - protected void playSound() { - level.playSound(null, worldPosition, SoundEvents.BLAZE_SHOOT, SoundSource.BLOCKS, - .125f + level.random.nextFloat() * .125f, .75f - level.random.nextFloat() * .25f); - } - - protected HeatLevel getHeatLevelFromFuelType(FuelType fuel) { - HeatLevel level = HeatLevel.SMOULDERING; - switch (activeFuel) { - case SPECIAL: - level = HeatLevel.SEETHING; - break; - case NORMAL: - boolean lowPercent = (double) remainingBurnTime / MAX_HEAT_CAPACITY < 0.0125; - level = lowPercent ? HeatLevel.FADING : HeatLevel.KINDLED; - break; - default: - case NONE: - break; - } - return level; - } - - protected void spawnParticles(HeatLevel heatLevel, double burstMult) { - if (level == null) - return; - if (heatLevel == BlazeBurnerBlock.HeatLevel.NONE) - return; - - Random r = level.getRandom(); - - Vec3 c = VecHelper.getCenterOf(worldPosition); - Vec3 v = c.add(VecHelper.offsetRandomly(Vec3.ZERO, r, .125f) - .multiply(1, 0, 1)); - - if (r.nextInt(3) == 0) - level.addParticle(ParticleTypes.LARGE_SMOKE, v.x, v.y, v.z, 0, 0, 0); - if (r.nextInt(2) != 0) - return; - - boolean empty = level.getBlockState(worldPosition.above()) - .getCollisionShape(level, worldPosition.above()) - .isEmpty(); - - double yMotion = empty ? .0625f : r.nextDouble() * .0125f; - Vec3 v2 = c.add(VecHelper.offsetRandomly(Vec3.ZERO, r, .5f) - .multiply(1, .25f, 1) - .normalize() - .scale((empty ? .25f : .5) + r.nextDouble() * .125f)) - .add(0, .5, 0); - - if (heatLevel.isAtLeast(HeatLevel.SEETHING)) { - level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v2.x, v2.y, v2.z, 0, yMotion, 0); - } else if (heatLevel.isAtLeast(HeatLevel.FADING)) { - level.addParticle(ParticleTypes.FLAME, v2.x, v2.y, v2.z, 0, yMotion, 0); - } - return; - } - - public void spawnParticleBurst(boolean soulFlame) { - Vec3 c = VecHelper.getCenterOf(worldPosition); - Random r = level.random; - for (int i = 0; i < 20; i++) { - Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, r, .5f) - .multiply(1, .25f, 1) - .normalize(); - Vec3 v = c.add(offset.scale(.5 + r.nextDouble() * .125f)) - .add(0, .125, 0); - Vec3 m = offset.scale(1 / 32f); - - level.addParticle(soulFlame ? ParticleTypes.SOUL_FIRE_FLAME : ParticleTypes.FLAME, v.x, v.y, v.z, m.x, m.y, - m.z); - } - } - - public enum FuelType { - NONE, NORMAL, SPECIAL - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyInstance.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyInstance.java index 75ff9156ae..5f0ec44612 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/AbstractPulleyInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; +package com.simibubi.create.content.contraptions.pulley; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.MaterialManager; @@ -13,14 +13,14 @@ import com.jozufozu.flywheel.light.TickingLightListener; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; import com.mojang.math.Vector3f; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.ShaftInstance; import net.minecraft.core.Direction; import net.minecraft.util.Mth; import net.minecraft.world.level.LightLayer; -public abstract class AbstractPulleyInstance extends ShaftInstance implements DynamicInstance, TickingLightListener { +public abstract class AbstractPulleyInstance extends ShaftInstance implements DynamicInstance, TickingLightListener { final OrientedData coil; final SelectInstance magnet; @@ -34,8 +34,8 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements Dy private final GridAlignedBB volume = new GridAlignedBB(); private final LightVolume light; - public AbstractPulleyInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); + public AbstractPulleyInstance(MaterialManager dispatcher, T blockEntity) { + super(dispatcher, blockEntity); rotatingAbout = Direction.get(Direction.AxisDirection.POSITIVE, axis); rotationAxis = rotatingAbout.step(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyRenderer.java new file mode 100644 index 0000000000..798c4f8212 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/AbstractPulleyRenderer.java @@ -0,0 +1,120 @@ +package com.simibubi.create.content.contraptions.pulley; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class AbstractPulleyRenderer extends KineticBlockEntityRenderer { + + private PartialModel halfRope; + private PartialModel halfMagnet; + + public AbstractPulleyRenderer(BlockEntityRendererProvider.Context context, PartialModel halfRope, + PartialModel halfMagnet) { + super(context); + this.halfRope = halfRope; + this.halfMagnet = halfMagnet; + } + + @Override + public boolean shouldRenderOffScreen(T p_188185_1_) { + return true; + } + + @Override + protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) + return; + + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + float offset = getOffset(be, partialTicks); + boolean running = isRunning(be); + + Axis rotationAxis = ((IRotate) be.getBlockState() + .getBlock()).getRotationAxis(be.getBlockState()); + kineticRotationTransform(getRotatedCoil(be), be, rotationAxis, AngleHelper.rad(offset * 180), light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + + Level world = be.getLevel(); + BlockState blockState = be.getBlockState(); + BlockPos pos = be.getBlockPos(); + + SuperByteBuffer halfMagnet = CachedPartialBuffers.partial(this.halfMagnet, blockState); + SuperByteBuffer halfRope = CachedPartialBuffers.partial(this.halfRope, blockState); + SuperByteBuffer magnet = renderMagnet(be); + SuperByteBuffer rope = renderRope(be); + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + if (running || offset == 0) + renderAt(world, offset > .25f ? magnet : halfMagnet, offset, pos, ms, vb); + + float f = offset % 1; + if (offset > .75f && (f < .25f || f > .75f)) + renderAt(world, halfRope, f > .75f ? f - 1 : f, pos, ms, vb); + + if (!running) + return; + + for (int i = 0; i < offset - 1.25f; i++) + renderAt(world, rope, offset - i - 1, pos, ms, vb); + } + + public static void renderAt(LevelAccessor world, SuperByteBuffer partial, float offset, BlockPos pulleyPos, + PoseStack ms, VertexConsumer buffer) { + BlockPos actualPos = pulleyPos.below((int) offset); + int light = LevelRenderer.getLightColor(world, world.getBlockState(actualPos), actualPos); + partial.translate(0, -offset, 0) + .light(light) + .renderInto(ms, buffer); + } + + protected abstract Axis getShaftAxis(T be); + + protected abstract PartialModel getCoil(); + + protected abstract SuperByteBuffer renderRope(T be); + + protected abstract SuperByteBuffer renderMagnet(T be); + + protected abstract float getOffset(T be, float partialTicks); + + protected abstract boolean isRunning(T be); + + @Override + protected BlockState getRenderedBlockState(T be) { + return shaft(getShaftAxis(be)); + } + + protected SuperByteBuffer getRotatedCoil(T be) { + BlockState blockState = be.getBlockState(); + return CachedPartialBuffers.partialFacing(getCoil(), blockState, + Direction.get(AxisDirection.POSITIVE, getShaftAxis(be))); + } + + @Override + public int getViewDistance() { + return 256; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/HosePulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/HosePulleyInstance.java new file mode 100644 index 0000000000..a2c54de80b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/HosePulleyInstance.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.pulley; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.fluids.hosePulley.HosePulleyBlockEntity; + +import net.createmod.catnip.utility.AnimationTickHolder; + +public class HosePulleyInstance extends AbstractPulleyInstance { + + public HosePulleyInstance(MaterialManager dispatcher, HosePulleyBlockEntity blockEntity) { + super(dispatcher, blockEntity); + } + + protected Instancer getRopeModel() { + return getOrientedMaterial().getModel(AllPartialModels.HOSE, blockState); + } + + protected Instancer getMagnetModel() { + return materialManager.defaultCutout() + .material(Materials.ORIENTED) + .getModel(AllPartialModels.HOSE_MAGNET, blockState); + } + + protected Instancer getHalfMagnetModel() { + return materialManager.defaultCutout() + .material(Materials.ORIENTED) + .getModel(AllPartialModels.HOSE_HALF_MAGNET, blockState); + } + + protected Instancer getCoilModel() { + return getOrientedMaterial().getModel(AllPartialModels.HOSE_COIL, blockState, rotatingAbout); + } + + protected Instancer getHalfRopeModel() { + return getOrientedMaterial().getModel(AllPartialModels.HOSE_HALF, blockState); + } + + protected float getOffset() { + return blockEntity.getInterpolatedOffset(AnimationTickHolder.getPartialTicks()); + } + + protected boolean isRunning() { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyBlock.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlock.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyBlock.java rename to src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlock.java index 0031780ac8..79e3277941 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; +package com.simibubi.create.content.contraptions.pulley; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -32,33 +32,32 @@ import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class PulleyBlock extends HorizontalAxisKineticBlock implements ITE { +public class PulleyBlock extends HorizontalAxisKineticBlock implements IBE { public PulleyBlock(Properties properties) { super(properties); } private static void onRopeBroken(Level world, BlockPos pulleyPos) { - BlockEntity te = world.getBlockEntity(pulleyPos); - if (te instanceof PulleyTileEntity) { - PulleyTileEntity pulley = (PulleyTileEntity) te; + BlockEntity be = world.getBlockEntity(pulleyPos); + if (be instanceof PulleyBlockEntity) { + PulleyBlockEntity pulley = (PulleyBlockEntity) be; pulley.initialOffset = 0; pulley.onLengthBroken(); } } - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.getBlock() != newState.getBlock()) { - if (!worldIn.isClientSide) { - BlockState below = worldIn.getBlockState(pos.below()); - if (below.getBlock() instanceof RopeBlockBase) - worldIn.destroyBlock(pos.below(), true); - } - if (state.hasBlockEntity()) - worldIn.removeBlockEntity(pos); - } - } + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + super.onRemove(state, worldIn, pos, newState, isMoving); + if (state.is(newState.getBlock())) + return; + if (worldIn.isClientSide) + return; + BlockState below = worldIn.getBlockState(pos.below()); + if (below.getBlock() instanceof RopeBlockBase) + worldIn.destroyBlock(pos.below(), true); + } public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, BlockHitResult hit) { @@ -68,7 +67,7 @@ public class PulleyBlock extends HorizontalAxisKineticBlock implements ITE te.assembleNextTick = true); + withBlockEntityDo(worldIn, pos, be -> be.assembleNextTick = true); return InteractionResult.SUCCESS; } return InteractionResult.PASS; @@ -80,13 +79,13 @@ public class PulleyBlock extends HorizontalAxisKineticBlock implements ITE getTileEntityClass() { - return PulleyTileEntity.class; + public Class getBlockEntityClass() { + return PulleyBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ROPE_PULLEY.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ROPE_PULLEY.get(); } private static class RopeBlockBase extends Block implements SimpleWaterloggedBlock { diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlockEntity.java new file mode 100644 index 0000000000..43501c4043 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyBlockEntity.java @@ -0,0 +1,386 @@ +package com.simibubi.create.content.contraptions.pulley; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.BlockMovementChecks; +import com.simibubi.create.content.contraptions.ContraptionCollider; +import com.simibubi.create.content.contraptions.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.piston.LinearActuatorBlockEntity; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchObservable; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class PulleyBlockEntity extends LinearActuatorBlockEntity implements ThresholdSwitchObservable { + + protected int initialOffset; + private float prevAnimatedOffset; + + protected BlockPos mirrorParent; + protected List mirrorChildren; + public WeakReference sharedMirrorContraption; + + public PulleyBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected AABB createRenderBoundingBox() { + double expandY = -offset; + if (sharedMirrorContraption != null) { + AbstractContraptionEntity ace = sharedMirrorContraption.get(); + if (ace != null) + expandY = ace.getY() - worldPosition.getY(); + } + return super.createRenderBoundingBox().expandTowards(0, expandY, 0); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.PULLEY_MAXED); + } + + @Override + public void tick() { + float prevOffset = offset; + super.tick(); + + if (level.isClientSide() && mirrorParent != null) + if (sharedMirrorContraption == null || sharedMirrorContraption.get() == null + || !sharedMirrorContraption.get() + .isAlive()) { + sharedMirrorContraption = null; + if (level.getBlockEntity(mirrorParent)instanceof PulleyBlockEntity pte && pte.movedContraption != null) + sharedMirrorContraption = new WeakReference<>(pte.movedContraption); + } + + if (isVirtual()) + prevAnimatedOffset = offset; + invalidateRenderBoundingBox(); + + if (prevOffset < 200 && offset >= 200) + award(AllAdvancements.PULLEY_MAXED); + } + + @Override + protected boolean isPassive() { + return mirrorParent != null; + } + + @Nullable + public AbstractContraptionEntity getAttachedContraption() { + return mirrorParent != null && sharedMirrorContraption != null ? sharedMirrorContraption.get() + : movedContraption; + } + + @Override + protected void assemble() throws AssemblyException { + if (!(level.getBlockState(worldPosition) + .getBlock() instanceof PulleyBlock)) + return; + if (speed == 0 && mirrorParent == null) + return; + int maxLength = AllConfigs.server().kinetics.maxRopeLength.get(); + int i = 1; + while (i <= maxLength) { + BlockPos ropePos = worldPosition.below(i); + BlockState ropeState = level.getBlockState(ropePos); + if (!AllBlocks.ROPE.has(ropeState) && !AllBlocks.PULLEY_MAGNET.has(ropeState)) { + break; + } + ++i; + } + offset = i - 1; + if (offset >= getExtensionRange() && getSpeed() > 0) + return; + if (offset <= 0 && getSpeed() < 0) + return; + + // Collect Construct + if (!level.isClientSide && mirrorParent == null) { + needsContraption = false; + BlockPos anchor = worldPosition.below(Mth.floor(offset + 1)); + initialOffset = Mth.floor(offset); + PulleyContraption contraption = new PulleyContraption(initialOffset); + boolean canAssembleStructure = contraption.assemble(level, anchor); + + if (canAssembleStructure) { + Direction movementDirection = getSpeed() > 0 ? Direction.DOWN : Direction.UP; + if (ContraptionCollider.isCollidingWithWorld(level, contraption, anchor.relative(movementDirection), + movementDirection)) + canAssembleStructure = false; + } + + if (!canAssembleStructure && getSpeed() > 0) + return; + + removeRopes(); + + if (!contraption.getBlocks() + .isEmpty()) { + contraption.removeBlocksFromWorld(level, BlockPos.ZERO); + movedContraption = ControlledContraptionEntity.create(level, this, contraption); + movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ()); + level.addFreshEntity(movedContraption); + forceMove = true; + needsContraption = true; + + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + + for (BlockPos pos : contraption.createColliders(level, Direction.UP)) { + if (pos.getY() != 0) + continue; + pos = pos.offset(anchor); + if (level.getBlockEntity( + new BlockPos(pos.getX(), worldPosition.getY(), pos.getZ())) instanceof PulleyBlockEntity pbe) + pbe.startMirroringOther(worldPosition); + } + } + } + + if (mirrorParent != null) + removeRopes(); + + clientOffsetDiff = 0; + running = true; + sendData(); + } + + private void removeRopes() { + for (int i = ((int) offset); i > 0; i--) { + BlockPos offset = worldPosition.below(i); + BlockState oldState = level.getBlockState(offset); + level.setBlock(offset, oldState.getFluidState() + .createLegacyBlock(), 66); + } + } + + @Override + public void disassemble() { + if (!running && movedContraption == null && mirrorParent == null) + return; + offset = getGridOffset(offset); + if (movedContraption != null) + resetContraptionToOffset(); + + if (!level.isClientSide) { + if (shouldCreateRopes()) { + if (offset > 0) { + BlockPos magnetPos = worldPosition.below((int) offset); + FluidState ifluidstate = level.getFluidState(magnetPos); + level.destroyBlock(magnetPos, level.getBlockState(magnetPos) + .getCollisionShape(level, magnetPos) + .isEmpty()); + level.setBlock(magnetPos, AllBlocks.PULLEY_MAGNET.getDefaultState() + .setValue(BlockStateProperties.WATERLOGGED, + Boolean.valueOf(ifluidstate.getType() == Fluids.WATER)), + 66); + } + + boolean[] waterlog = new boolean[(int) offset]; + + for (int i = 1; i <= ((int) offset) - 1; i++) { + BlockPos ropePos = worldPosition.below(i); + FluidState ifluidstate = level.getFluidState(ropePos); + waterlog[i] = ifluidstate.getType() == Fluids.WATER; + level.destroyBlock(ropePos, level.getBlockState(ropePos) + .getCollisionShape(level, ropePos) + .isEmpty()); + } + for (int i = 1; i <= ((int) offset) - 1; i++) + level.setBlock(worldPosition.below(i), AllBlocks.ROPE.getDefaultState() + .setValue(BlockStateProperties.WATERLOGGED, waterlog[i]), 66); + } + + if (movedContraption != null && mirrorParent == null) + movedContraption.disassemble(); + notifyMirrorsOfDisassembly(); + } + + if (movedContraption != null) + movedContraption.discard(); + + movedContraption = null; + initialOffset = 0; + running = false; + sendData(); + } + + protected boolean shouldCreateRopes() { + return !remove; + } + + @Override + protected Vec3 toPosition(float offset) { + if (movedContraption.getContraption() instanceof PulleyContraption) { + PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption(); + return Vec3.atLowerCornerOf(contraption.anchor) + .add(0, contraption.getInitialOffset() - offset, 0); + + } + return Vec3.ZERO; + } + + @Override + protected void visitNewPosition() { + super.visitNewPosition(); + if (level.isClientSide) + return; + if (movedContraption != null) + return; + if (getSpeed() <= 0) + return; + + BlockPos posBelow = worldPosition.below((int) (offset + getMovementSpeed()) + 1); + BlockState state = level.getBlockState(posBelow); + if (!BlockMovementChecks.isMovementNecessary(state, level, posBelow)) + return; + if (BlockMovementChecks.isBrittle(state)) + return; + + disassemble(); + assembleNextTick = true; + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + initialOffset = compound.getInt("InitialOffset"); + needsContraption = compound.getBoolean("NeedsContraption"); + super.read(compound, clientPacket); + + BlockPos prevMirrorParent = mirrorParent; + mirrorParent = null; + mirrorChildren = null; + + if (compound.contains("MirrorParent")) { + mirrorParent = NbtUtils.readBlockPos(compound.getCompound("MirrorParent")); + offset = 0; + if (prevMirrorParent == null || !prevMirrorParent.equals(mirrorParent)) + sharedMirrorContraption = null; + } + + if (compound.contains("MirrorChildren")) + mirrorChildren = NBTHelper.readCompoundList(compound.getList("MirrorChildren", Tag.TAG_COMPOUND), + NbtUtils::readBlockPos); + + if (mirrorParent == null) + sharedMirrorContraption = null; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("InitialOffset", initialOffset); + super.write(compound, clientPacket); + + if (mirrorParent != null) + compound.put("MirrorParent", NbtUtils.writeBlockPos(mirrorParent)); + if (mirrorChildren != null) + compound.put("MirrorChildren", NBTHelper.writeCompoundList(mirrorChildren, NbtUtils::writeBlockPos)); + } + + public void startMirroringOther(BlockPos parent) { + if (parent.equals(worldPosition)) + return; + if (!(level.getBlockEntity(parent) instanceof PulleyBlockEntity pbe)) + return; + if (pbe.getType() != getType()) + return; + if (pbe.mirrorChildren == null) + pbe.mirrorChildren = new ArrayList<>(); + pbe.mirrorChildren.add(worldPosition); + pbe.notifyUpdate(); + + mirrorParent = parent; + try { + assemble(); + } catch (AssemblyException e) { + } + notifyUpdate(); + } + + public void notifyMirrorsOfDisassembly() { + if (mirrorChildren == null) + return; + for (BlockPos blockPos : mirrorChildren) { + if (!(level.getBlockEntity(blockPos) instanceof PulleyBlockEntity pbe)) + continue; + pbe.offset = offset; + pbe.disassemble(); + pbe.mirrorParent = null; + pbe.notifyUpdate(); + } + mirrorChildren.clear(); + notifyUpdate(); + } + + @Override + protected int getExtensionRange() { + return Math.max(0, Math.min(AllConfigs.server().kinetics.maxRopeLength.get(), + (worldPosition.getY() - 1) - level.getMinBuildHeight())); + } + + @Override + protected int getInitialOffset() { + return initialOffset; + } + + @Override + protected Vec3 toMotionVector(float speed) { + return new Vec3(0, -speed, 0); + } + + @Override + protected ValueBoxTransform getMovementModeSlot() { + return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); + } + + @Override + public float getInterpolatedOffset(float partialTicks) { + if (isVirtual()) + return Mth.lerp(partialTicks, prevAnimatedOffset, offset); + boolean moving = running && (movedContraption == null || !movedContraption.isStalled()); + return super.getInterpolatedOffset(moving ? partialTicks : 0.5f); + } + + public void animateOffset(float forcedOffset) { + offset = forcedOffset; + } + + @Override + public float getPercent() { + int distance = worldPosition.getY() - level.getMinBuildHeight(); + if (distance <= 0) + return 100; + return 100 * getInterpolatedOffset(.5f) / distance; + } + + public BlockPos getMirrorParent() { + return mirrorParent; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyContraption.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyContraption.java new file mode 100644 index 0000000000..cc4eb19a45 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyContraption.java @@ -0,0 +1,69 @@ +package com.simibubi.create.content.contraptions.pulley; + +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.TranslatingContraption; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class PulleyContraption extends TranslatingContraption { + + int initialOffset; + + @Override + public ContraptionType getType() { + return ContraptionType.PULLEY; + } + + public PulleyContraption() {} + + public PulleyContraption(int initialOffset) { + this.initialOffset = initialOffset; + } + + @Override + public boolean assemble(Level world, BlockPos pos) throws AssemblyException { + if (!searchMovedStructure(world, pos, null)) + return false; + startMoving(world); + return true; + } + + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + if (pos.getX() != anchor.getX() || pos.getZ() != anchor.getZ()) + return false; + int y = pos.getY(); + if (y <= anchor.getY() || y > anchor.getY() + initialOffset + 1) + return false; + return true; + } + + @Override + public CompoundTag writeNBT(boolean spawnPacket) { + CompoundTag tag = super.writeNBT(spawnPacket); + tag.putInt("InitialOffset", initialOffset); + return tag; + } + + @Override + public void readNBT(Level world, CompoundTag nbt, boolean spawnData) { + initialOffset = nbt.getInt("InitialOffset"); + super.readNBT(world, nbt, spawnData); + } + + @Override + @OnlyIn(Dist.CLIENT) + public ContraptionLighter makeLighter() { + return new PulleyLighter(this); + } + + public int getInitialOffset() { + return initialOffset; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyLighter.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java rename to src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyLighter.java index 01c9d289d8..0b723c4537 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyLighter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyLighter.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.pulley; +package com.simibubi.create.content.contraptions.pulley; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyRenderer.java new file mode 100644 index 0000000000..a8c5fca98a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/PulleyRenderer.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.contraptions.pulley; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; + +public class PulleyRenderer extends AbstractPulleyRenderer { + + public PulleyRenderer(BlockEntityRendererProvider.Context context) { + super(context, AllPartialModels.ROPE_HALF, AllPartialModels.ROPE_HALF_MAGNET); + } + + @Override + protected Axis getShaftAxis(PulleyBlockEntity be) { + return be.getBlockState() + .getValue(PulleyBlock.HORIZONTAL_AXIS); + } + + @Override + protected PartialModel getCoil() { + return AllPartialModels.ROPE_COIL; + } + + @Override + protected SuperByteBuffer renderRope(PulleyBlockEntity be) { + return CachedBlockBuffers.block(AllBlocks.ROPE.getDefaultState()); + } + + @Override + protected SuperByteBuffer renderMagnet(PulleyBlockEntity be) { + return CachedBlockBuffers.block(AllBlocks.PULLEY_MAGNET.getDefaultState()); + } + + @Override + protected float getOffset(PulleyBlockEntity be, float partialTicks) { + return getBlockEntityOffset(partialTicks, be); + } + + @Override + protected boolean isRunning(PulleyBlockEntity be) { + return isPulleyRunning(be); + } + + public static boolean isPulleyRunning(PulleyBlockEntity be) { + return be.running || be.mirrorParent != null || be.isVirtual(); + } + + public static float getBlockEntityOffset(float partialTicks, PulleyBlockEntity blockEntity) { + float offset = blockEntity.getInterpolatedOffset(partialTicks); + + AbstractContraptionEntity attachedContraption = blockEntity.getAttachedContraption(); + if (attachedContraption != null) { + PulleyContraption c = (PulleyContraption) attachedContraption.getContraption(); + double entityPos = Mth.lerp(partialTicks, attachedContraption.yOld, attachedContraption.getY()); + offset = (float) -(entityPos - c.anchor.getY() - c.getInitialOffset()); + } + + return offset; + } + + @Override + public int getViewDistance() { + return 128; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/pulley/RopePulleyInstance.java b/src/main/java/com/simibubi/create/content/contraptions/pulley/RopePulleyInstance.java new file mode 100644 index 0000000000..172b34aa9a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/pulley/RopePulleyInstance.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.contraptions.pulley; + + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; + +import net.createmod.catnip.utility.AnimationTickHolder; + +public class RopePulleyInstance extends AbstractPulleyInstance { + public RopePulleyInstance(MaterialManager materialManager, PulleyBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + protected Instancer getRopeModel() { + return getOrientedMaterial().getModel(AllBlocks.ROPE.getDefaultState()); + } + + protected Instancer getMagnetModel() { + return getOrientedMaterial().getModel(AllBlocks.PULLEY_MAGNET.getDefaultState()); + } + + protected Instancer getHalfMagnetModel() { + return getOrientedMaterial().getModel(AllPartialModels.ROPE_HALF_MAGNET, blockState); + } + + protected Instancer getCoilModel() { + return getOrientedMaterial().getModel(AllPartialModels.ROPE_COIL, blockState, rotatingAbout); + } + + protected Instancer getHalfRopeModel() { + return getOrientedMaterial().getModel(AllPartialModels.ROPE_HALF, blockState); + } + + protected float getOffset() { + float partialTicks = AnimationTickHolder.getPartialTicks(); + return PulleyRenderer.getBlockEntityOffset(partialTicks, blockEntity); + } + + protected boolean isRunning() { + return PulleyRenderer.isPulleyRunning(blockEntity); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java deleted file mode 100644 index 2b46a3d279..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftTileEntity.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageTileEntity; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class GantryShaftTileEntity extends KineticTileEntity { - - public GantryShaftTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - public void checkAttachedCarriageBlocks() { - if (!canAssembleOn()) - return; - for (Direction d : Iterate.directions) { - if (d.getAxis() == getBlockState().getValue(GantryShaftBlock.FACING) - .getAxis()) - continue; - BlockPos offset = worldPosition.relative(d); - BlockState pinionState = level.getBlockState(offset); - if (!AllBlocks.GANTRY_CARRIAGE.has(pinionState)) - continue; - if (pinionState.getValue(GantryCarriageBlock.FACING) != d) - continue; - BlockEntity tileEntity = level.getBlockEntity(offset); - if (tileEntity instanceof GantryCarriageTileEntity) - ((GantryCarriageTileEntity) tileEntity).queueAssembly(); - } - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - checkAttachedCarriageBlocks(); - } - - @Override - public float propagateRotationTo(KineticTileEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, - boolean connectedViaAxes, boolean connectedViaCogs) { - float defaultModifier = - super.propagateRotationTo(target, stateFrom, stateTo, diff, connectedViaAxes, connectedViaCogs); - - if (connectedViaAxes) - return defaultModifier; - if (!stateFrom.getValue(GantryShaftBlock.POWERED)) - return defaultModifier; - if (!AllBlocks.GANTRY_CARRIAGE.has(stateTo)) - return defaultModifier; - - Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); - if (stateTo.getValue(GantryCarriageBlock.FACING) != direction) - return defaultModifier; - return GantryCarriageTileEntity.getGantryPinionModifier(stateFrom.getValue(GantryShaftBlock.FACING), - stateTo.getValue(GantryCarriageBlock.FACING)); - } - - @Override - public boolean isCustomConnection(KineticTileEntity other, BlockState state, BlockState otherState) { - if (!AllBlocks.GANTRY_CARRIAGE.has(otherState)) - return false; - final BlockPos diff = other.getBlockPos() - .subtract(worldPosition); - Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); - return otherState.getValue(GantryCarriageBlock.FACING) == direction; - } - - public boolean canAssembleOn() { - BlockState blockState = getBlockState(); - if (!AllBlocks.GANTRY_SHAFT.has(blockState)) - return false; - if (blockState.getValue(GantryShaftBlock.POWERED)) - return false; - float speed = getPinionMovementSpeed(); - - switch (blockState.getValue(GantryShaftBlock.PART)) { - case END: - return speed < 0; - case MIDDLE: - return speed != 0; - case START: - return speed > 0; - case SINGLE: - default: - return false; - } - } - - public float getPinionMovementSpeed() { - BlockState blockState = getBlockState(); - if (!AllBlocks.GANTRY_SHAFT.has(blockState)) - return 0; - return Mth.clamp(convertToLinear(-getSpeed()), -.49f, .49f); - } - - @Override - protected boolean isNoisy() { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java deleted file mode 100644 index c762ffc753..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerRenderer.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; - -public class SpeedControllerRenderer extends SmartTileEntityRenderer { - - public SpeedControllerRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(SpeedControllerTileEntity tileEntityIn, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay); - - VertexConsumer builder = buffer.getBuffer(RenderType.solid()); - if (!Backend.canUseInstancing(tileEntityIn.getLevel())) { - KineticTileEntityRenderer.renderRotatingBuffer(tileEntityIn, getRotatedModel(tileEntityIn), ms, builder, light); - } - - if (!tileEntityIn.hasBracket) - return; - - BlockPos pos = tileEntityIn.getBlockPos(); - Level world = tileEntityIn.getLevel(); - BlockState blockState = tileEntityIn.getBlockState(); - boolean alongX = blockState.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == Axis.X; - - SuperByteBuffer bracket = CachedPartialBuffers.partial(AllBlockPartials.SPEED_CONTROLLER_BRACKET, blockState); - bracket.translate(0, 1, 0); - bracket.rotateCentered(Direction.UP, - (float) (alongX ? Math.PI : Math.PI / 2)); - bracket.light(LevelRenderer.getLightColor(world, pos.above())); - bracket.renderInto(ms, builder); - } - - private SuperByteBuffer getRotatedModel(SpeedControllerTileEntity te) { - return CachedBlockBuffers.block(KineticTileEntityRenderer.KINETIC_TILE, - KineticTileEntityRenderer.shaft(KineticTileEntityRenderer.getRotationAxisOf(te))); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java deleted file mode 100644 index 2e6a609ec9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerTileEntity.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced; - -import java.util.List; - -import com.simibubi.create.content.contraptions.RotationPropagator; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class SpeedControllerTileEntity extends KineticTileEntity { - - public static final int DEFAULT_SPEED = 16; - protected ScrollValueBehaviour targetSpeed; - - boolean hasBracket; - - public SpeedControllerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - hasBracket = false; - } - - @Override - public void lazyTick() { - super.lazyTick(); - updateBracket(); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - Integer max = AllConfigs.SERVER.kinetics.maxRotationSpeed.get(); - - targetSpeed = - new ScrollValueBehaviour(CreateLang.translateDirect("generic.speed"), this, new ControllerValueBoxTransform()); - targetSpeed.between(-max, max); - targetSpeed.value = DEFAULT_SPEED; - targetSpeed.moveText(new Vec3(9, 0, 10)); - targetSpeed.withUnit(i -> CreateLang.translateDirect("generic.unit.rpm")); - targetSpeed.withCallback(i -> this.updateTargetRotation()); - targetSpeed.withStepFunction(CreativeMotorTileEntity::step); - behaviours.add(targetSpeed); - - registerAwardables(behaviours, AllAdvancements.SPEED_CONTROLLER); - } - - private void updateTargetRotation() { - if (hasNetwork()) - getOrCreateNetwork().remove(this); - RotationPropagator.handleRemoved(level, worldPosition, this); - removeSource(); - attachKinetics(); - - if (isCogwheelPresent() && getSpeed() != 0) - award(AllAdvancements.SPEED_CONTROLLER); - } - - public static float getConveyedSpeed(KineticTileEntity cogWheel, KineticTileEntity speedControllerIn, - boolean targetingController) { - if (!(speedControllerIn instanceof SpeedControllerTileEntity)) - return 0; - - float speed = speedControllerIn.getTheoreticalSpeed(); - float wheelSpeed = cogWheel.getTheoreticalSpeed(); - float desiredOutputSpeed = getDesiredOutputSpeed(cogWheel, speedControllerIn, targetingController); - - float compareSpeed = targetingController ? speed : wheelSpeed; - if (desiredOutputSpeed >= 0 && compareSpeed >= 0) - return Math.max(desiredOutputSpeed, compareSpeed); - if (desiredOutputSpeed < 0 && compareSpeed < 0) - return Math.min(desiredOutputSpeed, compareSpeed); - - return desiredOutputSpeed; - } - - public static float getDesiredOutputSpeed(KineticTileEntity cogWheel, KineticTileEntity speedControllerIn, - boolean targetingController) { - SpeedControllerTileEntity speedController = (SpeedControllerTileEntity) speedControllerIn; - float targetSpeed = speedController.targetSpeed.getValue(); - float speed = speedControllerIn.getTheoreticalSpeed(); - float wheelSpeed = cogWheel.getTheoreticalSpeed(); - - if (targetSpeed == 0) - return 0; - if (targetingController && wheelSpeed == 0) - return 0; - if (!speedController.hasSource()) { - if (targetingController) - return targetSpeed; - return 0; - } - - boolean wheelPowersController = speedController.source.equals(cogWheel.getBlockPos()); - - if (wheelPowersController) { - if (targetingController) - return targetSpeed; - return wheelSpeed; - } - - if (targetingController) - return speed; - return targetSpeed; - } - - public void updateBracket() { - if (level != null && level.isClientSide) - hasBracket = isCogwheelPresent(); - } - - private boolean isCogwheelPresent() { - BlockState stateAbove = level.getBlockState(worldPosition.above()); - return ICogWheel.isDedicatedCogWheel(stateAbove.getBlock()) && ICogWheel.isLargeCog(stateAbove) - && stateAbove.getValue(CogWheelBlock.AXIS).isHorizontal(); - } - - private class ControllerValueBoxTransform extends ValueBoxTransform.Sided { - - @Override - protected Vec3 getSouthLocation() { - return VecHelper.voxelSpace(8, 11f, 16); - } - - @Override - protected boolean isSideActive(BlockState state, Direction direction) { - if (direction.getAxis() - .isVertical()) - return false; - return state.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) != direction.getAxis(); - } - - @Override - protected float getScale() { - return 0.275f; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java deleted file mode 100644 index 75fb4ca84e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/ConfigureSequencedGearshiftPacket.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; - -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.FriendlyByteBuf; - -public class ConfigureSequencedGearshiftPacket extends TileEntityConfigurationPacket { - - private ListTag instructions; - - public ConfigureSequencedGearshiftPacket(BlockPos pos, ListTag instructions) { - super(pos); - this.instructions = instructions; - } - - public ConfigureSequencedGearshiftPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void readSettings(FriendlyByteBuf buffer) { - instructions = buffer.readNbt().getList("data", Tag.TAG_COMPOUND); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) { - CompoundTag tag = new CompoundTag(); - tag.put("data", instructions); - buffer.writeNbt(tag); - } - - @Override - protected void applySettings(SequencedGearshiftTileEntity te) { - te.run(-1); - te.instructions = Instruction.deserializeAll(instructions); - te.sendData(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java deleted file mode 100644 index 017fe02714..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/InstructionSpeedModifiers.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; - -import java.util.ArrayList; -import java.util.List; - -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.network.chat.Component; - -public enum InstructionSpeedModifiers { - - FORWARD_FAST(2, ">>"), FORWARD(1, "->"), BACK(-1, "<-"), BACK_FAST(-2, "<<"), - - ; - - String translationKey; - int value; - Component label; - - private InstructionSpeedModifiers(int modifier, Component label) { - this.label = label; - translationKey = "gui.sequenced_gearshift.speed." + Lang.asId(name()); - value = modifier; - } - private InstructionSpeedModifiers(int modifier, String label) { - this.label = Components.literal(label); - translationKey = "gui.sequenced_gearshift.speed." + Lang.asId(name()); - value = modifier; - } - - static List getOptions() { - List options = new ArrayList<>(); - for (InstructionSpeedModifiers entry : values()) - options.add(CreateLang.translateDirect(entry.translationKey)); - return options; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/OnIsPoweredResult.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/OnIsPoweredResult.java deleted file mode 100644 index e942da652d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/OnIsPoweredResult.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; - -public enum OnIsPoweredResult { - NOTHING, - CONTINUE -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java deleted file mode 100644 index 4f2f50326b..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java +++ /dev/null @@ -1,203 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; - -import java.util.Vector; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.gui.widget.ScrollInput; -import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.gui.AbstractSimiScreen; -import net.createmod.catnip.gui.element.GuiGameElement; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.ItemStack; - -public class SequencedGearshiftScreen extends AbstractSimiScreen { - - private final ItemStack renderedItem = AllBlocks.SEQUENCED_GEARSHIFT.asStack(); - private final AllGuiTextures background = AllGuiTextures.SEQUENCER; - private IconButton confirmButton; - - private ListTag compareTag; - private Vector instructions; - private BlockPos pos; - - private Vector> inputs; - - public SequencedGearshiftScreen(SequencedGearshiftTileEntity te) { - super(CreateLang.translateDirect("gui.sequenced_gearshift.title")); - this.instructions = te.instructions; - this.pos = te.getBlockPos(); - compareTag = Instruction.serializeAll(instructions); - } - - @Override - protected void init() { - setWindowSize(background.getWidth(), background.getHeight()); - setWindowOffset(-20, 0); - super.init(); - - int x = guiLeft; - int y = guiTop; - - inputs = new Vector<>(5); - for (int row = 0; row < inputs.capacity(); row++) - inputs.add(new Vector<>(3)); - - for (int row = 0; row < instructions.size(); row++) - initInputsOfRow(row, x, y); - - confirmButton = - new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); - confirmButton.withCallback(() -> { - onClose(); - }); - addRenderableWidget(confirmButton); - } - - public void initInputsOfRow(int row, int backgroundX, int backgroundY) { - int x = backgroundX + 30; - int y = backgroundY + 18; - int rowHeight = 22; - - Vector rowInputs = inputs.get(row); - removeWidgets(rowInputs); - rowInputs.clear(); - int index = row; - Instruction instruction = instructions.get(row); - - ScrollInput type = - new SelectionScrollInput(x, y + rowHeight * row, 50, 18).forOptions(SequencerInstructions.getOptions()) - .calling(state -> instructionUpdated(index, state)) - .setState(instruction.instruction.ordinal()) - .titled(CreateLang.translateDirect("gui.sequenced_gearshift.instruction")); - ScrollInput value = - new ScrollInput(x + 58, y + rowHeight * row, 28, 18).calling(state -> instruction.value = state); - ScrollInput direction = new SelectionScrollInput(x + 88, y + rowHeight * row, 28, 18) - .forOptions(InstructionSpeedModifiers.getOptions()) - .calling(state -> instruction.speedModifier = InstructionSpeedModifiers.values()[state]) - .titled(CreateLang.translateDirect("gui.sequenced_gearshift.speed")); - - rowInputs.add(type); - rowInputs.add(value); - rowInputs.add(direction); - - addRenderableWidgets(rowInputs); - updateParamsOfRow(row); - } - - public void updateParamsOfRow(int row) { - Instruction instruction = instructions.get(row); - Vector rowInputs = inputs.get(row); - SequencerInstructions def = instruction.instruction; - boolean hasValue = def.hasValueParameter; - boolean hasModifier = def.hasSpeedParameter; - - ScrollInput value = rowInputs.get(1); - value.active = value.visible = hasValue; - if (hasValue) - value.withRange(1, def.maxValue + 1) - .titled(CreateLang.translateDirect(def.parameterKey)) - .withShiftStep(def.shiftStep) - .setState(instruction.value) - .onChanged(); - if (def == SequencerInstructions.DELAY) { - value.withStepFunction(context -> { - int v = context.currentValue; - if (!context.forward) - v--; - if (v < 20) - return context.shift ? 20 : 1; - return context.shift ? 100 : 20; - }); - } else - value.withStepFunction(value.standardStep()); - - ScrollInput modifier = rowInputs.get(2); - modifier.active = modifier.visible = hasModifier; - if (hasModifier) - modifier.setState(instruction.speedModifier.ordinal()); - } - - @Override - protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { - int x = guiLeft; - int y = guiTop; - - background.render(ms, x, y, this); - - for (int row = 0; row < instructions.capacity(); row++) { - AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; - int yOffset = toDraw.getHeight() * row; - if (row >= instructions.size()) { - toDraw.render(ms, x, y + 14 + yOffset, this); - continue; - } - - Instruction instruction = instructions.get(row); - SequencerInstructions def = instruction.instruction; - def.background.render(ms, x, y + 14 + yOffset, this); - - label(ms, 36, yOffset - 3, CreateLang.translateDirect(def.translationKey)); - if (def.hasValueParameter) { - String text = def.formatValue(instruction.value); - int stringWidth = font.width(text); - label(ms, 90 + (12 - stringWidth / 2), yOffset - 3, Components.literal(text)); - } - if (def.hasSpeedParameter) - label(ms, 127, yOffset - 3, instruction.speedModifier.label); - } - - drawCenteredString(ms, font, title, x + (background.getWidth() - 8) / 2, y + 3, 0xFFFFFF); - - GuiGameElement.of(renderedItem) - .at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200) - .scale(5) - .render(ms); - } - - private void label(PoseStack ms, int x, int y, Component text) { - font.drawShadow(ms, text, guiLeft + x, guiTop + 26 + y, 0xFFFFEE); - } - - public void sendPacket() { - ListTag serialized = Instruction.serializeAll(instructions); - if (serialized.equals(compareTag)) - return; - AllPackets.channel.sendToServer(new ConfigureSequencedGearshiftPacket(pos, serialized)); - } - - @Override - public void removed() { - sendPacket(); - } - - private void instructionUpdated(int index, int state) { - SequencerInstructions newValue = SequencerInstructions.values()[state]; - instructions.get(index).instruction = newValue; - instructions.get(index).value = newValue.defaultValue; - updateParamsOfRow(index); - if (newValue == SequencerInstructions.END) { - for (int i = instructions.size() - 1; i > index; i--) { - instructions.remove(i); - Vector rowInputs = inputs.get(i); - removeWidgets(rowInputs); - rowInputs.clear(); - } - } else { - if (index + 1 < instructions.capacity() && index + 1 == instructions.size()) { - instructions.add(new Instruction(SequencerInstructions.END)); - initInputsOfRow(index + 1, guiLeft, guiTop); - } - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java deleted file mode 100644 index 9c595af723..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; - -import java.util.Vector; - -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { - - Vector instructions; - int currentInstruction; - int currentInstructionDuration; - float currentInstructionProgress; - int timer; - boolean poweredPreviously; - - public SequencedGearshiftTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - instructions = Instruction.createDefault(); - currentInstruction = -1; - currentInstructionDuration = -1; - currentInstructionProgress = 0; - timer = 0; - poweredPreviously = false; - } - - @Override - public void tick() { - super.tick(); - - if (isIdle()) - return; - if (level.isClientSide) - return; - if (currentInstructionDuration < 0) - return; - if (timer < currentInstructionDuration) { - timer++; - currentInstructionProgress += getInstruction(currentInstruction).getTickProgress(speed); - return; - } - run(currentInstruction + 1); - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - if (isIdle()) - return; - float currentSpeed = Math.abs(speed); - if (Math.abs(previousSpeed) == currentSpeed) - return; - Instruction instruction = getInstruction(currentInstruction); - if (instruction == null) - return; - if (getSpeed() == 0) - run(-1); - - // Update instruction time with regards to new speed - currentInstructionDuration = instruction.getDuration(currentInstructionProgress, getTheoreticalSpeed()); - timer = 0; - } - - public boolean isIdle() { - return currentInstruction == -1; - } - - public void onRedstoneUpdate(boolean isPowered, boolean isRunning) { - if (!poweredPreviously && isPowered) - risingFlank(); - poweredPreviously = isPowered; - if (!isIdle()) - return; - if (isPowered == isRunning) - return; - if (!level.hasNeighborSignal(worldPosition)) { - level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, 0), 3); - return; - } - if (getSpeed() == 0) - return; - run(0); - } - - public void risingFlank() { - Instruction instruction = getInstruction(currentInstruction); - if (instruction == null) - return; - if (poweredPreviously) - return; - poweredPreviously = true; - - switch (instruction.onRedstonePulse()) { - case CONTINUE: - run(currentInstruction + 1); - break; - default: - break; - } - } - - protected void run(int instructionIndex) { - Instruction instruction = getInstruction(instructionIndex); - if (instruction == null || instruction.instruction == SequencerInstructions.END) { - if (getModifier() != 0) - detachKinetics(); - currentInstruction = -1; - currentInstructionDuration = -1; - currentInstructionProgress = 0; - timer = 0; - if (!level.hasNeighborSignal(worldPosition)) - level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, 0), 3); - else - sendData(); - return; - } - - detachKinetics(); - currentInstructionDuration = instruction.getDuration(0, getTheoreticalSpeed()); - currentInstruction = instructionIndex; - currentInstructionProgress = 0; - timer = 0; - level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, instructionIndex + 1), 3); - } - - public Instruction getInstruction(int instructionIndex) { - return instructionIndex >= 0 && instructionIndex < instructions.size() ? instructions.get(instructionIndex) - : null; - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("InstructionIndex", currentInstruction); - compound.putInt("InstructionDuration", currentInstructionDuration); - compound.putFloat("InstructionProgress", currentInstructionProgress); - compound.putInt("Timer", timer); - compound.putBoolean("PrevPowered", poweredPreviously); - compound.put("Instructions", Instruction.serializeAll(instructions)); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - currentInstruction = compound.getInt("InstructionIndex"); - currentInstructionDuration = compound.getInt("InstructionDuration"); - currentInstructionProgress = compound.getFloat("InstructionProgress"); - poweredPreviously = compound.getBoolean("PrevPowered"); - timer = compound.getInt("Timer"); - instructions = Instruction.deserializeAll(compound.getList("Instructions", Tag.TAG_COMPOUND)); - super.read(compound, clientPacket); - } - - @Override - public float getRotationSpeedModifier(Direction face) { - if (isVirtual()) - return 1; - return (!hasSource() || face == getSourceFacing()) ? 1 : getModifier(); - } - - public int getModifier() { - if (currentInstruction >= instructions.size()) - return 0; - return isIdle() ? 0 - : instructions.get(currentInstruction) - .getSpeedModifier(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java deleted file mode 100644 index a636499f9a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltHelper.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.belt; - -import com.simibubi.create.AllTags.AllItemTags; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; - -public class BeltHelper { - - public static boolean isItemUpright(ItemStack stack) { - return stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY) - .isPresent() || AllItemTags.UPRIGHT_ON_BELT.matches(stack); - } - - public static BeltTileEntity getSegmentTE(LevelAccessor world, BlockPos pos) { - if (world instanceof Level l && !l.isLoaded(pos)) - return null; - BlockEntity tileEntity = world.getBlockEntity(pos); - if (!(tileEntity instanceof BeltTileEntity)) - return null; - return (BeltTileEntity) tileEntity; - } - - public static BeltTileEntity getControllerTE(LevelAccessor world, BlockPos pos) { - BeltTileEntity segment = getSegmentTE(world, pos); - if (segment == null) - return null; - BlockPos controllerPos = segment.controller; - if (controllerPos == null) - return null; - return getSegmentTE(world, controllerPos); - } - - public static BeltTileEntity getBeltForOffset(BeltTileEntity controller, float offset) { - return getBeltAtSegment(controller, (int) Math.floor(offset)); - } - - public static BeltTileEntity getBeltAtSegment(BeltTileEntity controller, int segment) { - BlockPos pos = getPositionForOffset(controller, segment); - BlockEntity te = controller.getLevel() - .getBlockEntity(pos); - if (te == null || !(te instanceof BeltTileEntity)) - return null; - return (BeltTileEntity) te; - } - - public static BlockPos getPositionForOffset(BeltTileEntity controller, int offset) { - BlockPos pos = controller.getBlockPos(); - Vec3i vec = controller.getBeltFacing() - .getNormal(); - BeltSlope slope = controller.getBlockState() - .getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - - return pos.offset(offset * vec.getX(), Mth.clamp(offset, 0, controller.beltLength - 1) * verticality, - offset * vec.getZ()); - } - - public static Vec3 getVectorForOffset(BeltTileEntity controller, float offset) { - BeltSlope slope = controller.getBlockState() - .getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - float verticalMovement = verticality; - if (offset < .5) - verticalMovement = 0; - verticalMovement = verticalMovement * (Math.min(offset, controller.beltLength - .5f) - .5f); - Vec3 vec = VecHelper.getCenterOf(controller.getBlockPos()); - Vec3 horizontalMovement = Vec3.atLowerCornerOf(controller.getBeltFacing() - .getNormal()) - .scale(offset - .5f); - - if (slope == BeltSlope.VERTICAL) - horizontalMovement = Vec3.ZERO; - - vec = vec.add(horizontalMovement) - .add(0, verticalMovement, 0); - return vec; - } - - public static Vec3 getBeltVector(BlockState state) { - BeltSlope slope = state.getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - Vec3 horizontalMovement = Vec3.atLowerCornerOf(state.getValue(BeltBlock.HORIZONTAL_FACING) - .getNormal()); - if (slope == BeltSlope.VERTICAL) - return new Vec3(0, state.getValue(BeltBlock.HORIZONTAL_FACING) - .getAxisDirection() - .getStep(), 0); - return new Vec3(0, verticality, 0).add(horizontalMovement); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java deleted file mode 100644 index b4545f7c82..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltModel.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.belt; - -import static com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CASING_PROPERTY; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; -import com.simibubi.create.foundation.block.render.QuadHelper; - -import net.createmod.catnip.render.SpriteShiftEntry; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.BakedModelWrapper; -import net.minecraftforge.client.model.data.IModelData; - -public class BeltModel extends BakedModelWrapper { - - private static final SpriteShiftEntry SPRITE_SHIFT = AllSpriteShifts.ANDESIDE_BELT_CASING; - - public BeltModel(BakedModel template) { - super(template); - } - - @Override - public List getQuads(BlockState state, Direction side, Random rand, IModelData extraData) { - List quads = super.getQuads(state, side, rand, extraData); - if (!extraData.hasProperty(CASING_PROPERTY)) - return quads; - CasingType type = extraData.getData(CASING_PROPERTY); - if (type == CasingType.NONE || type == CasingType.BRASS) - return quads; - - quads = new ArrayList<>(quads); - - for (int i = 0; i < quads.size(); i++) { - BakedQuad quad = quads.get(i); - TextureAtlasSprite original = quad.getSprite(); - if (original != SPRITE_SHIFT.getOriginal()) - continue; - - BakedQuad newQuad = QuadHelper.clone(quad); - int[] vertexData = newQuad.getVertices(); - - for (int vertex = 0; vertex < 4; vertex++) { - float u = QuadHelper.getU(vertexData, vertex); - float v = QuadHelper.getV(vertexData, vertex); - QuadHelper.setU(vertexData, vertex, SPRITE_SHIFT.getTargetU(u)); - QuadHelper.setV(vertexData, vertex, SPRITE_SHIFT.getTargetV(v)); - } - - quads.set(i, newQuad); - } - - return quads; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java deleted file mode 100644 index e48eb6b2ee..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ /dev/null @@ -1,646 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.belt; - -import static com.simibubi.create.content.contraptions.relays.belt.BeltPart.MIDDLE; -import static com.simibubi.create.content.contraptions.relays.belt.BeltSlope.HORIZONTAL; -import static net.minecraft.core.Direction.AxisDirection.NEGATIVE; -import static net.minecraft.core.Direction.AxisDirection.POSITIVE; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.light.LightListener; -import com.jozufozu.flywheel.light.LightUpdater; -import com.jozufozu.flywheel.util.box.GridAlignedBB; -import com.jozufozu.flywheel.util.box.ImmutableBox; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; -import com.simibubi.create.content.contraptions.relays.belt.transport.ItemHandlerBeltSegment; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.data.ModelDataMap; -import net.minecraftforge.client.model.data.ModelProperty; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class BeltTileEntity extends KineticTileEntity { - - public Map passengers; - public Optional color; - public int beltLength; - public int index; - public Direction lastInsert; - public CasingType casing; - - protected BlockPos controller; - protected BeltInventory inventory; - protected LazyOptional itemHandler; - - public CompoundTag trackerUpdateTag; - - @OnlyIn(Dist.CLIENT) - public BeltLighter lighter; - - public static enum CasingType { - NONE, ANDESITE, BRASS; - } - - public BeltTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - controller = BlockPos.ZERO; - itemHandler = LazyOptional.empty(); - casing = CasingType.NONE; - color = Optional.empty(); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::canInsertFrom) - .setInsertionHandler(this::tryInsertingFromSide)); - behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) - .withStackPlacement(this::getWorldPositionOf)); - } - - @Override - public void tick() { - // Init belt - if (beltLength == 0) - BeltBlock.initBelt(level, worldPosition); - - super.tick(); - - if (!AllBlocks.BELT.has(level.getBlockState(worldPosition))) - return; - - initializeItemHandler(); - - // Move Items - if (!isController()) - return; - - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - if (beltLength > 0 && lighter == null) { - lighter = new BeltLighter(); - } - }); - invalidateRenderBoundingBox(); - - getInventory().tick(); - - if (getSpeed() == 0) - return; - - // Move Entities - if (passengers == null) - passengers = new HashMap<>(); - - List toRemove = new ArrayList<>(); - passengers.forEach((entity, info) -> { - boolean canBeTransported = BeltMovementHandler.canBeTransported(entity); - boolean leftTheBelt = - info.getTicksSinceLastCollision() > ((getBlockState().getValue(BeltBlock.SLOPE) != HORIZONTAL) ? 3 : 1); - if (!canBeTransported || leftTheBelt) { - toRemove.add(entity); - return; - } - - info.tick(); - BeltMovementHandler.transportEntity(this, entity, info); - }); - toRemove.forEach(passengers::remove); - } - - @Override - public float calculateStressApplied() { - if (!isController()) - return 0; - return super.calculateStressApplied(); - } - - @Override - public AABB createRenderBoundingBox() { - if (!isController()) - return super.createRenderBoundingBox(); - else - return super.createRenderBoundingBox().inflate(beltLength + 1); - } - - protected void initializeItemHandler() { - if (level.isClientSide || itemHandler.isPresent()) - return; - if (!level.isLoaded(controller)) - return; - BlockEntity te = level.getBlockEntity(controller); - if (te == null || !(te instanceof BeltTileEntity)) - return; - BeltInventory inventory = ((BeltTileEntity) te).getInventory(); - if (inventory == null) - return; - IItemHandler handler = new ItemHandlerBeltSegment(inventory, index); - itemHandler = LazyOptional.of(() -> handler); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { - if (side == Direction.UP || BeltBlock.canAccessFromSide(side, getBlockState())) { - return itemHandler.cast(); - } - } - return super.getCapability(cap, side); - } - - @Override - public void setRemoved() { - super.setRemoved(); - itemHandler.invalidate(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (controller != null) - compound.put("Controller", NbtUtils.writeBlockPos(controller)); - compound.putBoolean("IsController", isController()); - compound.putInt("Length", beltLength); - compound.putInt("Index", index); - NBTHelper.writeEnum(compound, "Casing", casing); - - if (color.isPresent()) - NBTHelper.writeEnum(compound, "Dye", color.get()); - - if (isController()) - compound.put("Inventory", getInventory().write()); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - int prevBeltLength = beltLength; - super.read(compound, clientPacket); - - if (compound.getBoolean("IsController")) - controller = worldPosition; - - color = compound.contains("Dye") ? Optional.of(NBTHelper.readEnum(compound, "Dye", DyeColor.class)) - : Optional.empty(); - - if (!wasMoved) { - if (!isController()) - controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); - trackerUpdateTag = compound; - index = compound.getInt("Index"); - beltLength = compound.getInt("Length"); - if (prevBeltLength != beltLength) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - if (lighter != null) { - lighter.initializeLight(); - } - }); - } - } - - if (isController()) - getInventory().read(compound.getCompound("Inventory")); - - CasingType casingBefore = casing; - casing = NBTHelper.readEnum(compound, "Casing", CasingType.class); - - if (!clientPacket) - return; - - if (casingBefore == casing) - return; - if (!isVirtual()) - requestModelDataUpdate(); - if (hasLevel()) - level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); - } - - @Override - public void clearKineticInformation() { - super.clearKineticInformation(); - beltLength = 0; - index = 0; - controller = null; - trackerUpdateTag = new CompoundTag(); - } - - public void applyColor(DyeColor colorIn) { - if (colorIn == null) { - if (!color.isPresent()) - return; - } else if (color.isPresent() && color.get() == colorIn) - return; - - for (BlockPos blockPos : BeltBlock.getBeltChain(level, getController())) { - BeltTileEntity belt = BeltHelper.getSegmentTE(level, blockPos); - if (belt == null) - continue; - belt.color = Optional.ofNullable(colorIn); - belt.setChanged(); - belt.sendData(); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(belt)); - } - } - - public BeltTileEntity getControllerTE() { - if (controller == null) - return null; - if (!level.isLoaded(controller)) - return null; - BlockEntity te = level.getBlockEntity(controller); - if (te == null || !(te instanceof BeltTileEntity)) - return null; - return (BeltTileEntity) te; - } - - public void setController(BlockPos controller) { - this.controller = controller; - } - - public BlockPos getController() { - return controller == null ? worldPosition : controller; - } - - public boolean isController() { - return controller != null && worldPosition.getX() == controller.getX() - && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); - } - - public float getBeltMovementSpeed() { - return getSpeed() / 480f; - } - - public float getDirectionAwareBeltMovementSpeed() { - int offset = getBeltFacing().getAxisDirection() - .getStep(); - if (getBeltFacing().getAxis() == Axis.X) - offset *= -1; - return getBeltMovementSpeed() * offset; - } - - public boolean hasPulley() { - if (!AllBlocks.BELT.has(getBlockState())) - return false; - return getBlockState().getValue(BeltBlock.PART) != MIDDLE; - } - - protected boolean isLastBelt() { - if (getSpeed() == 0) - return false; - - Direction direction = getBeltFacing(); - if (getBlockState().getValue(BeltBlock.SLOPE) == BeltSlope.VERTICAL) - return false; - - BeltPart part = getBlockState().getValue(BeltBlock.PART); - if (part == MIDDLE) - return false; - - boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection() - .getStep() == 1)) ^ direction.getAxis() == Axis.X; - return part == BeltPart.START ^ movingPositively; - } - - public Vec3i getMovementDirection(boolean firstHalf) { - return this.getMovementDirection(firstHalf, false); - } - - public Vec3i getBeltChainDirection() { - return this.getMovementDirection(true, true); - } - - protected Vec3i getMovementDirection(boolean firstHalf, boolean ignoreHalves) { - if (getSpeed() == 0) - return BlockPos.ZERO; - - final BlockState blockState = getBlockState(); - final Direction beltFacing = blockState.getValue(BlockStateProperties.HORIZONTAL_FACING); - final BeltSlope slope = blockState.getValue(BeltBlock.SLOPE); - final BeltPart part = blockState.getValue(BeltBlock.PART); - final Axis axis = beltFacing.getAxis(); - - Direction movementFacing = Direction.get(axis == Axis.X ? NEGATIVE : POSITIVE, axis); - boolean notHorizontal = blockState.getValue(BeltBlock.SLOPE) != HORIZONTAL; - if (getSpeed() < 0) - movementFacing = movementFacing.getOpposite(); - Vec3i movement = movementFacing.getNormal(); - - boolean slopeBeforeHalf = (part == BeltPart.END) == (beltFacing.getAxisDirection() == POSITIVE); - boolean onSlope = notHorizontal && (part == MIDDLE || slopeBeforeHalf == firstHalf || ignoreHalves); - boolean movingUp = onSlope && slope == (movementFacing == beltFacing ? BeltSlope.UPWARD : BeltSlope.DOWNWARD); - - if (!onSlope) - return movement; - - return new Vec3i(movement.getX(), movingUp ? 1 : -1, movement.getZ()); - } - - public Direction getMovementFacing() { - Axis axis = getBeltFacing().getAxis(); - return Direction.fromAxisAndDirection(axis, getBeltMovementSpeed() < 0 ^ axis == Axis.X ? NEGATIVE : POSITIVE); - } - - protected Direction getBeltFacing() { - return getBlockState().getValue(BlockStateProperties.HORIZONTAL_FACING); - } - - public BeltInventory getInventory() { - if (!isController()) { - BeltTileEntity controllerTE = getControllerTE(); - if (controllerTE != null) - return controllerTE.getInventory(); - return null; - } - if (inventory == null) { - inventory = new BeltInventory(this); - } - return inventory; - } - - private void applyToAllItems(float maxDistanceFromCenter, - Function processFunction) { - BeltTileEntity controller = getControllerTE(); - if (controller == null) - return; - BeltInventory inventory = controller.getInventory(); - if (inventory != null) - inventory.applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction); - } - - private Vec3 getWorldPositionOf(TransportedItemStack transported) { - BeltTileEntity controllerTE = getControllerTE(); - if (controllerTE == null) - return Vec3.ZERO; - return BeltHelper.getVectorForOffset(controllerTE, transported.beltPosition); - } - - public void setCasingType(CasingType type) { - if (casing == type) - return; - if (casing != CasingType.NONE) - level.levelEvent(2001, worldPosition, - Block.getId(casing == CasingType.ANDESITE ? AllBlocks.ANDESITE_CASING.getDefaultState() - : AllBlocks.BRASS_CASING.getDefaultState())); - casing = type; - boolean shouldBlockHaveCasing = type != CasingType.NONE; - BlockState blockState = getBlockState(); - if (blockState.getValue(BeltBlock.CASING) != shouldBlockHaveCasing) - KineticTileEntity.switchToBlockState(level, worldPosition, - blockState.setValue(BeltBlock.CASING, shouldBlockHaveCasing)); - setChanged(); - sendData(); - } - - private boolean canInsertFrom(Direction side) { - if (getSpeed() == 0) - return false; - BlockState state = getBlockState(); - if (state.hasProperty(BeltBlock.SLOPE) && (state.getValue(BeltBlock.SLOPE) == BeltSlope.SIDEWAYS - || state.getValue(BeltBlock.SLOPE) == BeltSlope.VERTICAL)) - return false; - return getMovementFacing() != side.getOpposite(); - } - - private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { - BeltTileEntity nextBeltController = getControllerTE(); - ItemStack inserted = transportedStack.stack; - ItemStack empty = ItemStack.EMPTY; - - if (nextBeltController == null) - return inserted; - BeltInventory nextInventory = nextBeltController.getInventory(); - if (nextInventory == null) - return inserted; - - BlockEntity teAbove = level.getBlockEntity(worldPosition.above()); - if (teAbove instanceof BrassTunnelTileEntity) { - BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) teAbove; - if (tunnelTE.hasDistributionBehaviour()) { - if (!tunnelTE.getStackToDistribute() - .isEmpty()) - return inserted; - if (!tunnelTE.testFlapFilter(side.getOpposite(), inserted)) - return inserted; - if (!simulate) { - BeltTunnelInteractionHandler.flapTunnel(nextInventory, index, side.getOpposite(), true); - tunnelTE.setStackToDistribute(inserted, side.getOpposite()); - } - return empty; - } - } - - if (getSpeed() == 0) - return inserted; - if (getMovementFacing() == side.getOpposite()) - return inserted; - if (!nextInventory.canInsertAtFromSide(index, side)) - return inserted; - if (simulate) - return empty; - - transportedStack = transportedStack.copy(); - transportedStack.beltPosition = index + .5f - Math.signum(getDirectionAwareBeltMovementSpeed()) / 16f; - - Direction movementFacing = getMovementFacing(); - if (!side.getAxis() - .isVertical()) { - if (movementFacing != side) { - transportedStack.sideOffset = side.getAxisDirection() - .getStep() * .35f; - if (side.getAxis() == Axis.X) - transportedStack.sideOffset *= -1; - } else - transportedStack.beltPosition = getDirectionAwareBeltMovementSpeed() > 0 ? index : index + 1; - } - - transportedStack.prevSideOffset = transportedStack.sideOffset; - transportedStack.insertedAt = index; - transportedStack.insertedFrom = side; - transportedStack.prevBeltPosition = transportedStack.beltPosition; - - BeltTunnelInteractionHandler.flapTunnel(nextInventory, index, side.getOpposite(), true); - - nextInventory.addItem(transportedStack); - nextBeltController.setChanged(); - nextBeltController.sendData(); - return empty; - } - - public static final ModelProperty CASING_PROPERTY = new ModelProperty<>(); - - @Override - public IModelData getModelData() { - return new ModelDataMap.Builder().withInitial(CASING_PROPERTY, casing) - .build(); - } - - @Override - protected boolean canPropagateDiagonally(IRotate block, BlockState state) { - return state.hasProperty(BeltBlock.SLOPE) && (state.getValue(BeltBlock.SLOPE) == BeltSlope.UPWARD - || state.getValue(BeltBlock.SLOPE) == BeltSlope.DOWNWARD); - } - - @Override - public float propagateRotationTo(KineticTileEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, - boolean connectedViaAxes, boolean connectedViaCogs) { - if (target instanceof BeltTileEntity && !connectedViaAxes) - return getController().equals(((BeltTileEntity) target).getController()) ? 1 : 0; - return 0; - } - - public void invalidateItemHandler() { - itemHandler.invalidate(); - } - - public boolean shouldRenderNormally() { - if (level == null) - return isController(); - BlockState state = getBlockState(); - return state != null && state.hasProperty(BeltBlock.PART) && state.getValue(BeltBlock.PART) == BeltPart.START; - } - - /** - * Hide this behavior in an inner class to avoid loading LightListener on servers. - */ - @OnlyIn(Dist.CLIENT) - class BeltLighter implements LightListener { - private byte[] light; - - public BeltLighter() { - initializeLight(); - LightUpdater.get(level) - .addListener(this); - } - - /** - * Get the number of belt segments represented by the lighter. - * @return The number of segments. - */ - public int lightSegments() { - return light == null ? 0 : light.length / 2; - } - - /** - * Get the light value for a given segment. - * @param segment The segment to get the light value for. - * @return The light value. - */ - public int getPackedLight(int segment) { - return light == null ? 0 : LightTexture.pack(light[segment * 2], light[segment * 2 + 1]); - } - - @Override - public GridAlignedBB getVolume() { - BlockPos endPos = BeltHelper.getPositionForOffset(BeltTileEntity.this, beltLength - 1); - GridAlignedBB bb = GridAlignedBB.from(worldPosition, endPos); - bb.fixMinMax(); - return bb; - } - - @Override - public boolean isListenerInvalid() { - return remove; - } - - @Override - public void onLightUpdate(LightLayer type, ImmutableBox changed) { - if (remove) - return; - if (level == null) - return; - - GridAlignedBB beltVolume = getVolume(); - - if (beltVolume.intersects(changed)) { - if (type == LightLayer.BLOCK) - updateBlockLight(); - - if (type == LightLayer.SKY) - updateSkyLight(); - } - } - - private void initializeLight() { - light = new byte[beltLength * 2]; - - Vec3i vec = getBeltFacing().getNormal(); - BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - - MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); - for (int i = 0; i < beltLength * 2; i += 2) { - light[i] = (byte) level.getBrightness(LightLayer.BLOCK, pos); - light[i + 1] = (byte) level.getBrightness(LightLayer.SKY, pos); - pos.move(vec.getX(), verticality, vec.getZ()); - } - } - - private void updateBlockLight() { - Vec3i vec = getBeltFacing().getNormal(); - BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - - MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); - for (int i = 0; i < beltLength * 2; i += 2) { - light[i] = (byte) level.getBrightness(LightLayer.BLOCK, pos); - - pos.move(vec.getX(), verticality, vec.getZ()); - } - } - - private void updateSkyLight() { - Vec3i vec = getBeltFacing().getNormal(); - BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); - int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; - - MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); - for (int i = 1; i < beltLength * 2; i += 2) { - light[i] = (byte) level.getBrightness(LightLayer.SKY, pos); - - pos.move(vec.getX(), verticality, vec.getZ()); - } - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java deleted file mode 100644 index 52f0cbe7a9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltFunnelInteractionHandler.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; - -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; -import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.items.ItemHandlerHelper; - -public class BeltFunnelInteractionHandler { - - public static boolean checkForFunnels(BeltInventory beltInventory, TransportedItemStack currentItem, - float nextOffset) { - boolean beltMovementPositive = beltInventory.beltMovementPositive; - int firstUpcomingSegment = (int) Math.floor(currentItem.beltPosition); - int step = beltMovementPositive ? 1 : -1; - firstUpcomingSegment = Mth.clamp(firstUpcomingSegment, 0, beltInventory.belt.beltLength - 1); - - for (int segment = firstUpcomingSegment; beltMovementPositive ? segment <= nextOffset - : segment + 1 >= nextOffset; segment += step) { - BlockPos funnelPos = BeltHelper.getPositionForOffset(beltInventory.belt, segment) - .above(); - Level world = beltInventory.belt.getLevel(); - BlockState funnelState = world.getBlockState(funnelPos); - if (!(funnelState.getBlock() instanceof BeltFunnelBlock)) - continue; - Direction funnelFacing = funnelState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); - Direction movementFacing = beltInventory.belt.getMovementFacing(); - boolean blocking = funnelFacing == movementFacing.getOpposite(); - if (funnelFacing == movementFacing) - continue; - if (funnelState.getValue(BeltFunnelBlock.SHAPE) == Shape.PUSHING) - continue; - - float funnelEntry = segment + .5f; - if (funnelState.getValue(BeltFunnelBlock.SHAPE) == Shape.EXTENDED) - funnelEntry += .499f * (beltMovementPositive ? -1 : 1); - - boolean hasCrossed = nextOffset > funnelEntry && beltMovementPositive - || nextOffset < funnelEntry && !beltMovementPositive; - if (!hasCrossed) - return false; - if (blocking) - currentItem.beltPosition = funnelEntry; - - if (world.isClientSide || funnelState.getOptionalValue(BeltFunnelBlock.POWERED).orElse(false)) - if (blocking) - return true; - else - continue; - - BlockEntity te = world.getBlockEntity(funnelPos); - if (!(te instanceof FunnelTileEntity)) - return true; - - FunnelTileEntity funnelTE = (FunnelTileEntity) te; - InvManipulationBehaviour inserting = funnelTE.getBehaviour(InvManipulationBehaviour.TYPE); - FilteringBehaviour filtering = funnelTE.getBehaviour(FilteringBehaviour.TYPE); - - if (inserting == null || filtering != null && !filtering.test(currentItem.stack)) - if (blocking) - return true; - else - continue; - - int amountToExtract = funnelTE.getAmountToExtract(); - ItemStack toInsert = currentItem.stack.copy(); - if (amountToExtract > toInsert.getCount()) - if (blocking) - return true; - else - continue; - - if (amountToExtract != -1) { - toInsert.setCount(amountToExtract); - ItemStack remainder = inserting.simulate().insert(toInsert); - if (!remainder.isEmpty()) - if (blocking) - return true; - else - continue; - } - - ItemStack remainder = inserting.insert(toInsert); - if (toInsert.equals(remainder, false)) - if (blocking) - return true; - else - continue; - - int notFilled = currentItem.stack.getCount() - toInsert.getCount(); - if (!remainder.isEmpty()) { - remainder.grow(notFilled); - } else if (notFilled > 0) - remainder = ItemHandlerHelper.copyStackWithSize(currentItem.stack, notFilled); - - funnelTE.flap(true); - funnelTE.onTransfer(toInsert); - currentItem.stack = remainder; - beltInventory.belt.sendData(); - if (blocking) - return true; - } - - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java deleted file mode 100644 index 6d70e746af..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltTunnelInteractionHandler.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BrassTunnelTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.block.display.source.AccumulatedItemCountDisplaySource; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.items.ItemHandlerHelper; - -public class BeltTunnelInteractionHandler { - - public static boolean flapTunnelsAndCheckIfStuck(BeltInventory beltInventory, TransportedItemStack current, - float nextOffset) { - - int currentSegment = (int) current.beltPosition; - int upcomingSegment = (int) nextOffset; - - Direction movementFacing = beltInventory.belt.getMovementFacing(); - if (!beltInventory.beltMovementPositive && nextOffset == 0) - upcomingSegment = -1; - if (currentSegment == upcomingSegment) - return false; - - if (stuckAtTunnel(beltInventory, upcomingSegment, current.stack, movementFacing)) { - current.beltPosition = currentSegment + (beltInventory.beltMovementPositive ? .99f : .01f); - return true; - } - - Level world = beltInventory.belt.getLevel(); - boolean onServer = !world.isClientSide || beltInventory.belt.isVirtual(); - boolean removed = false; - BeltTunnelTileEntity nextTunnel = getTunnelOnSegment(beltInventory, upcomingSegment); - int transferred = current.stack.getCount(); - - if (nextTunnel instanceof BrassTunnelTileEntity) { - BrassTunnelTileEntity brassTunnel = (BrassTunnelTileEntity) nextTunnel; - if (brassTunnel.hasDistributionBehaviour()) { - if (!brassTunnel.canTakeItems()) - return true; - if (onServer) { - brassTunnel.setStackToDistribute(current.stack, movementFacing.getOpposite()); - current.stack = ItemStack.EMPTY; - beltInventory.belt.sendData(); - beltInventory.belt.setChanged(); - } - removed = true; - } - } else if (nextTunnel != null) { - BlockState blockState = nextTunnel.getBlockState(); - if (current.stack.getCount() > 1 && AllBlocks.ANDESITE_TUNNEL.has(blockState) - && BeltTunnelBlock.isJunction(blockState) - && movementFacing.getAxis() == blockState.getValue(BeltTunnelBlock.HORIZONTAL_AXIS)) { - - for (Direction d : Iterate.horizontalDirections) { - if (d.getAxis() == blockState.getValue(BeltTunnelBlock.HORIZONTAL_AXIS)) - continue; - if (!nextTunnel.flaps.containsKey(d)) - continue; - BlockPos outpos = nextTunnel.getBlockPos() - .below() - .relative(d); - if (!world.isLoaded(outpos)) - return true; - DirectBeltInputBehaviour behaviour = - TileEntityBehaviour.get(world, outpos, DirectBeltInputBehaviour.TYPE); - if (behaviour == null) - continue; - if (!behaviour.canInsertFromSide(d)) - continue; - - ItemStack toinsert = ItemHandlerHelper.copyStackWithSize(current.stack, 1); - if (!behaviour.handleInsertion(toinsert, d, false) - .isEmpty()) - return true; - if (onServer) - flapTunnel(beltInventory, upcomingSegment, d, false); - - current.stack.shrink(1); - beltInventory.belt.sendData(); - if (current.stack.getCount() <= 1) - break; - } - } - } - - if (onServer) { - flapTunnel(beltInventory, currentSegment, movementFacing, false); - flapTunnel(beltInventory, upcomingSegment, movementFacing.getOpposite(), true); - - if (nextTunnel != null) - DisplayLinkBlock.sendToGatherers(world, nextTunnel.getBlockPos(), - (dgte, b) -> b.itemReceived(dgte, transferred), AccumulatedItemCountDisplaySource.class); - } - - if (removed) - return true; - - return false; - } - - public static boolean stuckAtTunnel(BeltInventory beltInventory, int offset, ItemStack stack, - Direction movementDirection) { - BeltTileEntity belt = beltInventory.belt; - BlockPos pos = BeltHelper.getPositionForOffset(belt, offset) - .above(); - if (!(belt.getLevel() - .getBlockState(pos) - .getBlock() instanceof BrassTunnelBlock)) - return false; - BlockEntity te = belt.getLevel() - .getBlockEntity(pos); - if (te == null || !(te instanceof BrassTunnelTileEntity)) - return false; - BrassTunnelTileEntity tunnel = (BrassTunnelTileEntity) te; - return !tunnel.canInsert(movementDirection.getOpposite(), stack); - } - - public static void flapTunnel(BeltInventory beltInventory, int offset, Direction side, boolean inward) { - BeltTunnelTileEntity te = getTunnelOnSegment(beltInventory, offset); - if (te == null) - return; - te.flap(side, inward); - } - - protected static BeltTunnelTileEntity getTunnelOnSegment(BeltInventory beltInventory, int offset) { - BeltTileEntity belt = beltInventory.belt; - if (belt.getBlockState() - .getValue(BeltBlock.SLOPE) != BeltSlope.HORIZONTAL) - return null; - return getTunnelOnPosition(belt.getLevel(), BeltHelper.getPositionForOffset(belt, offset)); - } - - public static BeltTunnelTileEntity getTunnelOnPosition(Level world, BlockPos pos) { - pos = pos.above(); - if (!(world.getBlockState(pos) - .getBlock() instanceof BeltTunnelBlock)) - return null; - BlockEntity te = world.getBlockEntity(pos); - if (te == null || !(te instanceof BeltTunnelTileEntity)) - return null; - return ((BeltTunnelTileEntity) te); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractSimpleShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractSimpleShaftBlock.java deleted file mode 100644 index 1921837091..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractSimpleShaftBlock.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import java.util.Optional; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.PushReaction; - -public abstract class AbstractSimpleShaftBlock extends AbstractShaftBlock implements IWrenchableWithBracket { - - public AbstractSimpleShaftBlock(Properties properties) { - super(properties); - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - return IWrenchableWithBracket.super.onWrenched(state, context); - } - - @Override - public PushReaction getPistonPushReaction(BlockState state) { - return PushReaction.NORMAL; - } - - @Override - @SuppressWarnings("deprecation") - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - if (state != newState && !isMoving) - removeBracket(world, pos, true).ifPresent(stack -> Block.popResource(world, pos, stack)); - super.onRemove(state, world, pos, newState, isMoving); - } - - @Override - public Optional removeBracket(BlockGetter world, BlockPos pos, boolean inOnReplacedContext) { - BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); - if (behaviour == null) - return Optional.empty(); - BlockState bracket = behaviour.removeBracket(inOnReplacedContext); - if (bracket == null) - return Optional.empty(); - return Optional.of(new ItemStack(bracket.getBlock())); - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.BRACKETED_KINETIC.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticBlockModel.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticBlockModel.java deleted file mode 100644 index 4679668467..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticBlockModel.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.ForgeCatnipClient; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.BakedModelWrapper; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.data.ModelDataMap; -import net.minecraftforge.client.model.data.ModelProperty; - -public class BracketedKineticBlockModel extends BakedModelWrapper { - - private static final ModelProperty BRACKET_PROPERTY = new ModelProperty<>(); - - public BracketedKineticBlockModel(BakedModel template) { - super(template); - } - - @Override - public IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state, IModelData tileData) { - if (VirtualEmptyModelData.is(tileData)) - return tileData; - - BracketedModelData data = new BracketedModelData(); - BracketedTileEntityBehaviour attachmentBehaviour = - TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); - if (attachmentBehaviour != null) - data.putBracket(attachmentBehaviour.getBracket()); - return new ModelDataMap.Builder().withInitial(BRACKET_PROPERTY, data) - .build(); - } - - @Override - public List getQuads(BlockState state, Direction side, Random rand, IModelData data) { - if (VirtualEmptyModelData.is(data) || data.equals(ForgeCatnipClient.NoModelData)) { - return super.getQuads(state, side, rand, data); - } - - if (data.hasProperty(BRACKET_PROPERTY)) { - BracketedModelData pipeData = data.getData(BRACKET_PROPERTY); - BakedModel bracket = pipeData.getBracket(); - if (bracket != null) - return bracket.getQuads(state, side, rand, data); - } - - return Collections.emptyList(); - } - - private static class BracketedModelData { - private BakedModel bracket; - - public void putBracket(BlockState state) { - if (state != null) { - this.bracket = Minecraft.getInstance() - .getBlockRenderer() - .getBlockModel(state); - } - } - - public BakedModel getBracket() { - return bracket; - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileEntity.java deleted file mode 100644 index 14db8435b8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileEntity.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import java.util.List; - -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class BracketedKineticTileEntity extends SimpleKineticTileEntity implements ITransformableTE { - - public BracketedKineticTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours - .add(new BracketedTileEntityBehaviour(this, state -> state.getBlock() instanceof AbstractSimpleShaftBlock)); - super.addBehaviours(behaviours); - } - - @Override - public void transform(StructureTransform transform) { - BracketedTileEntityBehaviour bracketBehaviour = getBehaviour(BracketedTileEntityBehaviour.TYPE); - if (bracketBehaviour != null) { - bracketBehaviour.transformBracket(transform); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileInstance.java deleted file mode 100644 index e6ab3d5ef9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileInstance.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; - -public class BracketedKineticTileInstance extends SingleRotatingInstance { - - protected RotatingData additionalShaft; - - public BracketedKineticTileInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - public void init() { - super.init(); - if (!ICogWheel.isLargeCog(blockEntity.getBlockState())) - return; - - // Large cogs sometimes have to offset their teeth by 11.25 degrees in order to - // mesh properly - - float speed = blockEntity.getSpeed(); - Axis axis = KineticTileEntityRenderer.getRotationAxisOf(blockEntity); - BlockPos pos = blockEntity.getBlockPos(); - float offset = BracketedKineticTileRenderer.getShaftAngleOffset(axis, pos); - Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); - Instancer half = getRotatingMaterial().getModel(AllBlockPartials.COGWHEEL_SHAFT, blockState, - facing, () -> this.rotateToAxis(axis)); - - additionalShaft = setup(half.createInstance(), speed); - additionalShaft.setRotationOffset(offset); - } - - @Override - protected Instancer getModel() { - if (!ICogWheel.isLargeCog(blockEntity.getBlockState())) - return super.getModel(); - - Axis axis = KineticTileEntityRenderer.getRotationAxisOf(blockEntity); - Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); - return getRotatingMaterial().getModel(AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL, blockState, facing, - () -> this.rotateToAxis(axis)); - } - - private PoseStack rotateToAxis(Axis axis) { - Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); - PoseStack poseStack = new PoseStack(); - TransformStack.cast(poseStack) - .centre() - .rotateToFace(facing) - .multiply(Vector3f.XN.rotationDegrees(-90)) - .unCentre(); - return poseStack; - } - - @Override - public void update() { - super.update(); - if (additionalShaft != null) { - updateRotation(additionalShaft); - additionalShaft.setRotationOffset(BracketedKineticTileRenderer.getShaftAngleOffset(axis, pos)); - } - } - - @Override - public void updateLight() { - super.updateLight(); - if (additionalShaft != null) - relight(pos, additionalShaft); - } - - @Override - public void remove() { - super.remove(); - if (additionalShaft != null) - additionalShaft.delete(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileRenderer.java deleted file mode 100644 index d3b65a5d6e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedKineticTileRenderer.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; - -public class BracketedKineticTileRenderer extends KineticTileEntityRenderer { - - public BracketedKineticTileRenderer(Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) - return; - - if (!AllBlocks.LARGE_COGWHEEL.has(te.getBlockState())) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - return; - } - - // Large cogs sometimes have to offset their teeth by 11.25 degrees in order to - // mesh properly - - Axis axis = getRotationAxisOf(te); - BlockPos pos = te.getBlockPos(); - - Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); - renderRotatingBuffer(te, - CachedPartialBuffers.partialFacingVertical(AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL, te.getBlockState(), facing), - ms, buffer.getBuffer(RenderType.solid()), light); - - float offset = getShaftAngleOffset(axis, pos); - float time = WorldTickHolder.getRenderTime(te.getLevel()); - float angle = ((time * te.getSpeed() * 3f / 10 + offset) % 360) / 180 * (float) Math.PI; - - SuperByteBuffer shaft = - CachedPartialBuffers.partialFacingVertical(AllBlockPartials.COGWHEEL_SHAFT, te.getBlockState(), facing); - kineticRotationTransform(shaft, te, axis, angle, light); - shaft.renderInto(ms, buffer.getBuffer(RenderType.solid())); - - } - - public static float getShaftAngleOffset(Axis axis, BlockPos pos) { - float offset = 0; - double d = (((axis == Axis.X) ? 0 : pos.getX()) + ((axis == Axis.Y) ? 0 : pos.getY()) - + ((axis == Axis.Z) ? 0 : pos.getZ())) % 2; - if (d == 0) - offset = 22.5f; - return offset; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java deleted file mode 100644 index 733362df59..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import java.util.function.Predicate; - -import org.jetbrains.annotations.Nullable; - -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class BracketedTileEntityBehaviour extends TileEntityBehaviour { - - public static final BehaviourType TYPE = new BehaviourType<>(); - - private BlockState bracket; - private boolean reRender; - - private Predicate pred; - - public BracketedTileEntityBehaviour(SmartTileEntity te) { - this(te, state -> true); - } - - public BracketedTileEntityBehaviour(SmartTileEntity te, Predicate pred) { - super(te); - this.pred = pred; - } - - @Override - public BehaviourType getType() { - return TYPE; - } - - public void applyBracket(BlockState state) { - this.bracket = state; - reRender = true; - tileEntity.notifyUpdate(); - Level world = getWorld(); - if (world.isClientSide) - return; - tileEntity.getBlockState() - .updateNeighbourShapes(world, getPos(), 3); - } - - public void transformBracket(StructureTransform transform) { - if (isBracketPresent()) { - BlockState transformedBracket = transform.apply(bracket); - applyBracket(transformedBracket); - } - } - - @Nullable - public BlockState removeBracket(boolean inOnReplacedContext) { - if (bracket == null) { - return null; - } - - BlockState removed = this.bracket; - Level world = getWorld(); - if (!world.isClientSide) - world.levelEvent(2001, getPos(), Block.getId(bracket)); - this.bracket = null; - reRender = true; - if (inOnReplacedContext) { - tileEntity.sendData(); - return removed; - } - tileEntity.notifyUpdate(); - if (world.isClientSide) - return removed; - tileEntity.getBlockState() - .updateNeighbourShapes(world, getPos(), 3); - return removed; - } - - public boolean isBracketPresent() { - return bracket != null; - } - - @Nullable - public BlockState getBracket() { - return bracket; - } - - public boolean canHaveBracket() { - return pred.test(tileEntity.getBlockState()); - } - - @Override - public ItemRequirement getRequiredItems() { - if (!isBracketPresent()) { - return ItemRequirement.NONE; - } - return ItemRequirement.of(bracket, null); - } - - @Override - public boolean isSafeNBT() { - return true; - } - - @Override - public void write(CompoundTag nbt, boolean clientPacket) { - if (isBracketPresent()) { - nbt.put("Bracket", NbtUtils.writeBlockState(bracket)); - } - if (clientPacket && reRender) { - NBTHelper.putMarker(nbt, "Redraw"); - reRender = false; - } - super.write(nbt, clientPacket); - } - - @Override - public void read(CompoundTag nbt, boolean clientPacket) { - if (nbt.contains("Bracket")) - bracket = NbtUtils.readBlockState(nbt.getCompound("Bracket")); - if (clientPacket && nbt.contains("Redraw")) - getWorld().sendBlockUpdated(getPos(), tileEntity.getBlockState(), tileEntity.getBlockState(), 16); - super.read(nbt, clientPacket); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java deleted file mode 100644 index 87c9243d27..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/SimpleKineticTileEntity.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.elementary; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class SimpleKineticTileEntity extends KineticTileEntity { - - public SimpleKineticTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).inflate(1); - } - - @Override - public List addPropagationLocations(IRotate block, BlockState state, List neighbours) { - if (!ICogWheel.isLargeCog(state)) - return super.addPropagationLocations(block, state, neighbours); - - BlockPos.betweenClosedStream(new BlockPos(-1, -1, -1), new BlockPos(1, 1, 1)) - .forEach(offset -> { - if (offset.distSqr(BlockPos.ZERO) == 2) - neighbours.add(worldPosition.offset(offset)); - }); - return neighbours; - } - - @Override - protected boolean isNoisy() { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyBlock.java deleted file mode 100644 index 9c02eb5638..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyBlock.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; - -public class AdjustablePulleyBlock extends EncasedBeltBlock { - - public static BooleanProperty POWERED = BlockStateProperties.POWERED; - - public AdjustablePulleyBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(POWERED, false)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - super.createBlockStateDefinition(builder.add(POWERED)); - } - - @Override - public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, worldIn, pos, oldState, isMoving); - if (oldState.getBlock() == state.getBlock()) - return; - withTileEntityDo(worldIn, pos, kte -> ((AdjustablePulleyTileEntity) kte).neighbourChanged()); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - return super.getStateForPlacement(context).setValue(POWERED, context.getLevel() - .hasNeighborSignal(context.getClickedPos())); - } - - @Override - protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { - return super.areStatesKineticallyEquivalent(oldState, newState) - && oldState.getValue(POWERED) == newState.getValue(POWERED); - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - if (worldIn.isClientSide) - return; - - withTileEntityDo(worldIn, pos, kte -> ((AdjustablePulleyTileEntity) kte).neighbourChanged()); - - boolean previouslyPowered = state.getValue(POWERED); - if (previouslyPowered != worldIn.hasNeighborSignal(pos)) - worldIn.setBlock(pos, state.cycle(POWERED), 18); - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ADJUSTABLE_PULLEY.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java deleted file mode 100644 index 886456a317..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class AdjustablePulleyTileEntity extends KineticTileEntity { - - int signal; - boolean signalChanged; - - public AdjustablePulleyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - signal = 0; - setLazyTickRate(40); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("Signal", signal); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - signal = compound.getInt("Signal"); - super.read(compound, clientPacket); - } - - public float getModifier() { - return getModifierForSignal(signal); - } - - public void neighbourChanged() { - if (!hasLevel()) - return; - int power = level.getBestNeighborSignal(worldPosition); - if (power != signal) - signalChanged = true; - } - - @Override - public void lazyTick() { - super.lazyTick(); - neighbourChanged(); - } - - @Override - public void tick() { - super.tick(); - if (level.isClientSide) - return; - if (signalChanged) { - signalChanged = false; - analogSignalChanged(level.getBestNeighborSignal(worldPosition)); - } - } - - protected void analogSignalChanged(int newSignal) { - detachKinetics(); - removeSource(); - signal = newSignal; - attachKinetics(); - } - - protected float getModifierForSignal(int newPower) { - if (newPower == 0) - return 1; - return 1 + ((newPower + 1) / 16f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchTileEntity.java deleted file mode 100644 index 23fade805e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchTileEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class ClutchTileEntity extends SplitShaftTileEntity { - - public ClutchTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public float getRotationSpeedModifier(Direction face) { - if (hasSource()) { - if (face != getSourceFacing() && getBlockState().getValue(BlockStateProperties.POWERED)) - return 0; - } - return 1; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/DirectionalShaftHalvesTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/DirectionalShaftHalvesTileEntity.java deleted file mode 100644 index 04f9f6b350..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/DirectionalShaftHalvesTileEntity.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class DirectionalShaftHalvesTileEntity extends KineticTileEntity { - - public DirectionalShaftHalvesTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - public Direction getSourceFacing() { - BlockPos localSource = source.subtract(getBlockPos()); - return Direction.getNearest(localSource.getX(), localSource.getY(), localSource.getZ()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltBlock.java deleted file mode 100644 index 0712f27fc8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltBlock.java +++ /dev/null @@ -1,221 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.block.ITE; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.material.PushReaction; - -public class EncasedBeltBlock extends RotatedPillarKineticBlock implements ITE { - - public static final Property PART = EnumProperty.create("part", Part.class); - public static final BooleanProperty CONNECTED_ALONG_FIRST_COORDINATE = - DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; - - public EncasedBeltBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(PART, Part.NONE)); - } - - @Override - public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) { - return false; - } - - @Override - public PushReaction getPistonPushReaction(BlockState state) { - return PushReaction.NORMAL; - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - super.createBlockStateDefinition(builder.add(PART, CONNECTED_ALONG_FIRST_COORDINATE)); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - Axis placedAxis = context.getNearestLookingDirection() - .getAxis(); - Axis axis = context.getPlayer() != null && context.getPlayer() - .isShiftKeyDown() ? placedAxis : getPreferredAxis(context); - if (axis == null) - axis = placedAxis; - - BlockState state = defaultBlockState().setValue(AXIS, axis); - for (Direction facing : Iterate.directions) { - if (facing.getAxis() == axis) - continue; - BlockPos pos = context.getClickedPos(); - BlockPos offset = pos.relative(facing); - state = updateShape(state, facing, context.getLevel() - .getBlockState(offset), context.getLevel(), pos, offset); - } - return state; - } - - @Override - public BlockState updateShape(BlockState stateIn, Direction face, BlockState neighbour, LevelAccessor worldIn, - BlockPos currentPos, BlockPos facingPos) { - Part part = stateIn.getValue(PART); - Axis axis = stateIn.getValue(AXIS); - boolean connectionAlongFirst = stateIn.getValue(CONNECTED_ALONG_FIRST_COORDINATE); - Axis connectionAxis = - connectionAlongFirst ? (axis == Axis.X ? Axis.Y : Axis.X) : (axis == Axis.Z ? Axis.Y : Axis.Z); - - Axis faceAxis = face.getAxis(); - boolean facingAlongFirst = axis == Axis.X ? faceAxis.isVertical() : faceAxis == Axis.X; - boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE; - - if (axis == faceAxis) - return stateIn; - - if (!(neighbour.getBlock() instanceof EncasedBeltBlock)) { - if (facingAlongFirst != connectionAlongFirst || part == Part.NONE) - return stateIn; - if (part == Part.MIDDLE) - return stateIn.setValue(PART, positive ? Part.END : Part.START); - if ((part == Part.START) == positive) - return stateIn.setValue(PART, Part.NONE); - return stateIn; - } - - Part otherPart = neighbour.getValue(PART); - Axis otherAxis = neighbour.getValue(AXIS); - boolean otherConnection = neighbour.getValue(CONNECTED_ALONG_FIRST_COORDINATE); - Axis otherConnectionAxis = - otherConnection ? (otherAxis == Axis.X ? Axis.Y : Axis.X) : (otherAxis == Axis.Z ? Axis.Y : Axis.Z); - - if (neighbour.getValue(AXIS) == faceAxis) - return stateIn; - if (otherPart != Part.NONE && otherConnectionAxis != faceAxis) - return stateIn; - - if (part == Part.NONE) { - part = positive ? Part.START : Part.END; - connectionAlongFirst = axis == Axis.X ? faceAxis.isVertical() : faceAxis == Axis.X; - } else if (connectionAxis != faceAxis) { - return stateIn; - } - - if ((part == Part.START) != positive) - part = Part.MIDDLE; - - return stateIn.setValue(PART, part) - .setValue(CONNECTED_ALONG_FIRST_COORDINATE, connectionAlongFirst); - } - - @Override - public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { - if (originalState.getValue(PART) == Part.NONE) - return super.getRotatedBlockState(originalState, targetedFace); - return super.getRotatedBlockState(originalState, - Direction.get(AxisDirection.POSITIVE, getConnectionAxis(originalState))); - } - - @Override - public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { -// Blocks.AIR.getDefaultState() -// .updateNeighbors(context.getWorld(), context.getPos(), 1); - Axis axis = newState.getValue(AXIS); - newState = defaultBlockState().setValue(AXIS, axis); - if (newState.hasProperty(BlockStateProperties.POWERED)) - newState = newState.setValue(BlockStateProperties.POWERED, context.getLevel() - .hasNeighborSignal(context.getClickedPos())); - for (Direction facing : Iterate.directions) { - if (facing.getAxis() == axis) - continue; - BlockPos pos = context.getClickedPos(); - BlockPos offset = pos.relative(facing); - newState = updateShape(newState, facing, context.getLevel() - .getBlockState(offset), context.getLevel(), pos, offset); - } -// newState.updateNeighbors(context.getWorld(), context.getPos(), 1 | 2); - return newState; - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face.getAxis() == state.getValue(AXIS); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(AXIS); - } - - public static boolean areBlocksConnected(BlockState state, BlockState other, Direction facing) { - Part part = state.getValue(PART); - Axis connectionAxis = getConnectionAxis(state); - Axis otherConnectionAxis = getConnectionAxis(other); - - if (otherConnectionAxis != connectionAxis) - return false; - if (facing.getAxis() != connectionAxis) - return false; - if (facing.getAxisDirection() == AxisDirection.POSITIVE && (part == Part.MIDDLE || part == Part.START)) - return true; - if (facing.getAxisDirection() == AxisDirection.NEGATIVE && (part == Part.MIDDLE || part == Part.END)) - return true; - - return false; - } - - protected static Axis getConnectionAxis(BlockState state) { - Axis axis = state.getValue(AXIS); - boolean connectionAlongFirst = state.getValue(CONNECTED_ALONG_FIRST_COORDINATE); - Axis connectionAxis = - connectionAlongFirst ? (axis == Axis.X ? Axis.Y : Axis.X) : (axis == Axis.Z ? Axis.Y : Axis.Z); - return connectionAxis; - } - - public static float getRotationSpeedModifier(KineticTileEntity from, KineticTileEntity to) { - float fromMod = 1; - float toMod = 1; - if (from instanceof AdjustablePulleyTileEntity) - fromMod = ((AdjustablePulleyTileEntity) from).getModifier(); - if (to instanceof AdjustablePulleyTileEntity) - toMod = ((AdjustablePulleyTileEntity) to).getModifier(); - return fromMod / toMod; - } - - public enum Part implements StringRepresentable { - START, MIDDLE, END, NONE; - - @Override - public String getSerializedName() { - return Lang.asId(name()); - } - } - - @Override - public Class getTileEntityClass() { - return KineticTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ENCASED_SHAFT.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltGenerator.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltGenerator.java deleted file mode 100644 index 933f2dd9d3..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedBeltGenerator.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import java.util.function.BiFunction; - -import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock.Part; -import com.simibubi.create.foundation.data.SpecialBlockStateGen; -import com.tterrag.registrate.providers.DataGenContext; -import com.tterrag.registrate.providers.RegistrateBlockstateProvider; - -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.generators.ModelFile; - -public class EncasedBeltGenerator extends SpecialBlockStateGen { - - private BiFunction modelFunc; - - public EncasedBeltGenerator(BiFunction modelFunc) { - this.modelFunc = modelFunc; - } - - @Override - protected int getXRotation(BlockState state) { - EncasedBeltBlock.Part part = state.getValue(EncasedBeltBlock.PART); - boolean connectedAlongFirst = state.getValue(EncasedBeltBlock.CONNECTED_ALONG_FIRST_COORDINATE); - Axis axis = state.getValue(EncasedBeltBlock.AXIS); - - if (part == Part.NONE) - return axis == Axis.Y ? 90 : 0; - if (axis == Axis.X) - return (connectedAlongFirst ? 90 : 0) + (part == Part.START ? 180 : 0); - if (axis == Axis.Z) - return (connectedAlongFirst ? 0 : (part == Part.START ? 270 : 90)); - return 0; - } - - @Override - protected int getYRotation(BlockState state) { - EncasedBeltBlock.Part part = state.getValue(EncasedBeltBlock.PART); - boolean connectedAlongFirst = state.getValue(EncasedBeltBlock.CONNECTED_ALONG_FIRST_COORDINATE); - Axis axis = state.getValue(EncasedBeltBlock.AXIS); - - if (part == Part.NONE) - return axis == Axis.X ? 90 : 0; - if (axis == Axis.Z) - return (connectedAlongFirst && part == Part.END ? 270 : 90); - boolean flip = part == Part.END && !connectedAlongFirst || part == Part.START && connectedAlongFirst; - if (axis == Axis.Y) - return (connectedAlongFirst ? 90 : 0) + (flip ? 180 : 0); - return 0; - } - - @Override - public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, - BlockState state) { - return modelFunc.apply(state, getModelSuffix(state)); - } - - protected String getModelSuffix(BlockState state) { - EncasedBeltBlock.Part part = state.getValue(EncasedBeltBlock.PART); - Axis axis = state.getValue(EncasedBeltBlock.AXIS); - - if (part == Part.NONE) - return "single"; - - String orientation = axis == Axis.Y ? "vertical" : "horizontal"; - String section = part == Part.MIDDLE ? "middle" : "end"; - return section + "_" + orientation; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogInstance.java deleted file mode 100644 index 3baebd86a9..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogInstance.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import java.util.Optional; - -import com.jozufozu.flywheel.api.InstanceData; -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class EncasedCogInstance extends KineticTileInstance { - - private boolean large; - - protected RotatingData rotatingModel; - protected Optional rotatingTopShaft; - protected Optional rotatingBottomShaft; - - public static EncasedCogInstance small(MaterialManager modelManager, KineticTileEntity tile) { - return new EncasedCogInstance(modelManager, tile, false); - } - - public static EncasedCogInstance large(MaterialManager modelManager, KineticTileEntity tile) { - return new EncasedCogInstance(modelManager, tile, true); - } - - public EncasedCogInstance(MaterialManager modelManager, KineticTileEntity tile, boolean large) { - super(modelManager, tile); - this.large = large; - } - - @Override - public void init() { - rotatingModel = setup(getCogModel().createInstance()); - - Block block = blockState.getBlock(); - if (!(block instanceof IRotate)) - return; - - IRotate def = (IRotate) block; - rotatingTopShaft = Optional.empty(); - rotatingBottomShaft = Optional.empty(); - - for (Direction d : Iterate.directionsInAxis(axis)) { - if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d)) - continue; - RotatingData data = setup(getRotatingMaterial().getModel(AllBlockPartials.SHAFT_HALF, blockState, d) - .createInstance()); - if (d.getAxisDirection() == AxisDirection.POSITIVE) - rotatingTopShaft = Optional.of(data); - else - rotatingBottomShaft = Optional.of(data); - } - } - - @Override - public void update() { - updateRotation(rotatingModel); - rotatingTopShaft.ifPresent(this::updateRotation); - rotatingBottomShaft.ifPresent(this::updateRotation); - } - - @Override - public void updateLight() { - relight(pos, rotatingModel); - rotatingTopShaft.ifPresent(d -> relight(pos, d)); - rotatingBottomShaft.ifPresent(d -> relight(pos, d)); - } - - @Override - public void remove() { - rotatingModel.delete(); - rotatingTopShaft.ifPresent(InstanceData::delete); - rotatingBottomShaft.ifPresent(InstanceData::delete); - } - - protected Instancer getCogModel() { - BlockState referenceState = blockEntity.getBlockState(); - Direction facing = - Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), AxisDirection.POSITIVE); - PartialModel partial = large ? AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL : AllBlockPartials.SHAFTLESS_COGWHEEL; - - return getRotatingMaterial().getModel(partial, referenceState, facing, () -> { - PoseStack poseStack = new PoseStack(); - TransformStack.cast(poseStack) - .centre() - .rotateToFace(facing) - .multiply(Vector3f.XN.rotationDegrees(90)) - .unCentre(); - return poseStack; - }); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogRenderer.java deleted file mode 100644 index 809cb1f00c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogRenderer.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class EncasedCogRenderer extends KineticTileEntityRenderer { - - private boolean large; - - public static EncasedCogRenderer small(BlockEntityRendererProvider.Context context) { - return new EncasedCogRenderer(context, false); - } - - public static EncasedCogRenderer large(BlockEntityRendererProvider.Context context) { - return new EncasedCogRenderer(context, true); - } - - public EncasedCogRenderer(BlockEntityRendererProvider.Context context, boolean large) { - super(context); - this.large = large; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - if (Backend.canUseInstancing(te.getLevel())) - return; - - BlockState blockState = te.getBlockState(); - Block block = blockState.getBlock(); - if (!(block instanceof IRotate)) - return; - IRotate def = (IRotate) block; - - for (Direction d : Iterate.directionsInAxis(getRotationAxisOf(te))) { - if (!def.hasShaftTowards(te.getLevel(), te.getBlockPos(), blockState, d)) - continue; - renderRotatingBuffer(te, CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, te.getBlockState(), d), - ms, buffer.getBuffer(RenderType.solid()), light); - } - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacingVertical( - large ? AllBlockPartials.SHAFTLESS_LARGE_COGWHEEL : AllBlockPartials.SHAFTLESS_COGWHEEL, state, - Direction.fromAxisAndDirection(state.getValue(EncasedCogwheelBlock.AXIS), AxisDirection.POSITIVE)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogwheelBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogwheelBlock.java deleted file mode 100644 index 2178372927..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogwheelBlock.java +++ /dev/null @@ -1,279 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.CasingBlock; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.block.ITE; -import com.tterrag.registrate.util.entry.BlockEntry; - -import net.createmod.catnip.utility.VoxelShaper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.core.NonNullList; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Mirror; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; - -public class EncasedCogwheelBlock extends RotatedPillarKineticBlock - implements ICogWheel, ITE, ISpecialBlockItemRequirement, ITransformableBlock { - - public static final BooleanProperty TOP_SHAFT = BooleanProperty.create("top_shaft"); - public static final BooleanProperty BOTTOM_SHAFT = BooleanProperty.create("bottom_shaft"); - - boolean isLarge; - private BlockEntry casing; - - public static EncasedCogwheelBlock andesite(boolean large, Properties properties) { - return new EncasedCogwheelBlock(large, properties, AllBlocks.ANDESITE_CASING); - } - - public static EncasedCogwheelBlock brass(boolean large, Properties properties) { - return new EncasedCogwheelBlock(large, properties, AllBlocks.BRASS_CASING); - } - - public EncasedCogwheelBlock(boolean large, Properties properties, BlockEntry casing) { - super(properties); - isLarge = large; - this.casing = casing; - registerDefaultState(defaultBlockState().setValue(TOP_SHAFT, false) - .setValue(BOTTOM_SHAFT, false)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - super.createBlockStateDefinition(builder.add(TOP_SHAFT, BOTTOM_SHAFT)); - } - - @Override - public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { - if (target instanceof BlockHitResult) - return ((BlockHitResult) target).getDirection() - .getAxis() != getRotationAxis(state) - ? isLarge ? AllBlocks.LARGE_COGWHEEL.asStack() : AllBlocks.COGWHEEL.asStack() - : getCasing().asStack(); - return super.getCloneItemStack(state, target, world, pos, player); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState placedOn = context.getLevel() - .getBlockState(context.getClickedPos() - .relative(context.getClickedFace() - .getOpposite())); - BlockState stateForPlacement = super.getStateForPlacement(context); - if (ICogWheel.isSmallCog(placedOn)) - stateForPlacement = - stateForPlacement.setValue(AXIS, ((IRotate) placedOn.getBlock()).getRotationAxis(placedOn)); - return stateForPlacement; - } - - public BlockEntry getCasing() { - return casing; - } - - @Override - public boolean skipRendering(BlockState pState, BlockState pAdjacentBlockState, Direction pDirection) { - return pState.getBlock() == pAdjacentBlockState.getBlock() - && pState.getValue(AXIS) == pAdjacentBlockState.getValue(AXIS); - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - if (context.getClickedFace() - .getAxis() != state.getValue(AXIS)) - return super.onWrenched(state, context); - - Level level = context.getLevel(); - if (level.isClientSide) - return InteractionResult.SUCCESS; - - BlockPos pos = context.getClickedPos(); - KineticTileEntity.switchToBlockState(level, pos, state.cycle(context.getClickedFace() - .getAxisDirection() == AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT)); - playRotateSound(level, pos); - return InteractionResult.SUCCESS; - } - - @Override - public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { - originalState = swapShaftsForRotation(originalState, Rotation.CLOCKWISE_90, targetedFace.getAxis()); - return originalState.setValue(RotatedPillarKineticBlock.AXIS, - VoxelShaper - .axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS)) - .getClockWise(targetedFace.getAxis()) - .getAxis()); - } - - @Override - public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { - if (context.getLevel().isClientSide) - return InteractionResult.SUCCESS; - context.getLevel() - .levelEvent(2001, context.getClickedPos(), Block.getId(state)); - KineticTileEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), - (isLarge ? AllBlocks.LARGE_COGWHEEL : AllBlocks.COGWHEEL).getDefaultState() - .setValue(AXIS, state.getValue(AXIS))); - return InteractionResult.SUCCESS; - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face.getAxis() == state.getValue(AXIS) - && state.getValue(face.getAxisDirection() == AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT); - } - - @Override - protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { - if (newState.getBlock() instanceof EncasedCogwheelBlock - && oldState.getBlock() instanceof EncasedCogwheelBlock) { - if (newState.getValue(TOP_SHAFT) != oldState.getValue(TOP_SHAFT)) - return false; - if (newState.getValue(BOTTOM_SHAFT) != oldState.getValue(BOTTOM_SHAFT)) - return false; - } - return super.areStatesKineticallyEquivalent(oldState, newState); - } - - @Override - public boolean isSmallCog() { - return !isLarge; - } - - @Override - public boolean isLargeCog() { - return isLarge; - } - - @Override - public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { - return CogWheelBlock.isValidCogwheelPosition(ICogWheel.isLargeCog(state), worldIn, pos, state.getValue(AXIS)); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(AXIS); - } - - public BlockState swapShafts(BlockState state) { - boolean bottom = state.getValue(BOTTOM_SHAFT); - boolean top = state.getValue(TOP_SHAFT); - state = state.setValue(BOTTOM_SHAFT, top); - state = state.setValue(TOP_SHAFT, bottom); - return state; - } - - public BlockState swapShaftsForRotation(BlockState state, Rotation rotation, Direction.Axis rotationAxis) { - if (rotation == Rotation.NONE) { - return state; - } - - Direction.Axis axis = state.getValue(AXIS); - if (axis == rotationAxis) { - return state; - } - - if (rotation == Rotation.CLOCKWISE_180) { - return swapShafts(state); - } - - boolean clockwise = rotation == Rotation.CLOCKWISE_90; - - if (rotationAxis == Direction.Axis.X) { - if ( axis == Direction.Axis.Z && !clockwise - || axis == Direction.Axis.Y && clockwise) { - return swapShafts(state); - } - } else if (rotationAxis == Direction.Axis.Y) { - if ( axis == Direction.Axis.X && !clockwise - || axis == Direction.Axis.Z && clockwise) { - return swapShafts(state); - } - } else if (rotationAxis == Direction.Axis.Z) { - if ( axis == Direction.Axis.Y && !clockwise - || axis == Direction.Axis.X && clockwise) { - return swapShafts(state); - } - } - - return state; - } - - @Override - public BlockState mirror(BlockState state, Mirror mirror) { - Direction.Axis axis = state.getValue(AXIS); - if (axis == Direction.Axis.X && mirror == Mirror.FRONT_BACK - || axis == Direction.Axis.Z && mirror == Mirror.LEFT_RIGHT) { - return swapShafts(state); - } - return state; - } - - @Override - public BlockState rotate(BlockState state, Rotation rotation) { - state = swapShaftsForRotation(state, rotation, Direction.Axis.Y); - return super.rotate(state, rotation); - } - - @Override - public BlockState transform(BlockState state, StructureTransform transform) { - if (transform.mirror != null) { - state = mirror(state, transform.mirror); - } - - if (transform.rotationAxis == Direction.Axis.Y) { - return rotate(state, transform.rotation); - } - - state = swapShaftsForRotation(state, transform.rotation, transform.rotationAxis); - state = state.setValue(AXIS, transform.rotateAxis(state.getValue(AXIS))); - return state; - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return ItemRequirement - .of(isLarge ? AllBlocks.LARGE_COGWHEEL.getDefaultState() : AllBlocks.COGWHEEL.getDefaultState(), te); - } - - @Override - public Class getTileEntityClass() { - return SimpleKineticTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return isLarge ? AllTileEntities.ENCASED_LARGE_COGWHEEL.get() : AllTileEntities.ENCASED_COGWHEEL.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedShaftBlock.java deleted file mode 100644 index 8552663dc2..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedShaftBlock.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.CasingBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.block.ITE; -import com.tterrag.registrate.util.entry.BlockEntry; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.NonNullList; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; - -public class EncasedShaftBlock extends AbstractEncasedShaftBlock - implements ITE, ISpecialBlockItemRequirement { - - private BlockEntry casing; - - public static EncasedShaftBlock andesite(Properties properties) { - return new EncasedShaftBlock(properties, AllBlocks.ANDESITE_CASING); - } - - public static EncasedShaftBlock brass(Properties properties) { - return new EncasedShaftBlock(properties, AllBlocks.BRASS_CASING); - } - - protected EncasedShaftBlock(Properties properties, BlockEntry casing) { - super(properties); - this.casing = casing; - } - - public BlockEntry getCasing() { - return casing; - } - - @Override - public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} - - @Override - public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { - if (context.getLevel().isClientSide) - return InteractionResult.SUCCESS; - context.getLevel() - .levelEvent(2001, context.getClickedPos(), Block.getId(state)); - KineticTileEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), - AllBlocks.SHAFT.getDefaultState() - .setValue(AXIS, state.getValue(AXIS))); - return InteractionResult.SUCCESS; - } - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { - if (target instanceof BlockHitResult) - return ((BlockHitResult) target).getDirection() - .getAxis() == getRotationAxis(state) ? AllBlocks.SHAFT.asStack() : getCasing().asStack(); - return super.getCloneItemStack(state, target, world, pos, player); - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return ItemRequirement.of(AllBlocks.SHAFT.getDefaultState(), te); - } - - @Override - public Class getTileEntityClass() { - return KineticTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ENCASED_SHAFT.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java deleted file mode 100644 index 099d2c3f8c..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import java.util.Random; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.RotationPropagator; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.ticks.TickPriority; - -public class GearshiftBlock extends AbstractEncasedShaftBlock implements ITE { - - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - - public GearshiftBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(POWERED, false)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(POWERED); - super.createBlockStateDefinition(builder); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - return super.getStateForPlacement(context).setValue(POWERED, - context.getLevel().hasNeighborSignal(context.getClickedPos())); - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - if (worldIn.isClientSide) - return; - - boolean previouslyPowered = state.getValue(POWERED); - if (previouslyPowered != worldIn.hasNeighborSignal(pos)) { - detachKinetics(worldIn, pos, true); - worldIn.setBlock(pos, state.cycle(POWERED), 2); - } - } - - @Override - public Class getTileEntityClass() { - return SplitShaftTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.GEARSHIFT.get(); - } - - public void detachKinetics(Level worldIn, BlockPos pos, boolean reAttachNextTick) { - BlockEntity te = worldIn.getBlockEntity(pos); - if (te == null || !(te instanceof KineticTileEntity)) - return; - RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) te); - - // Re-attach next tick - if (reAttachNextTick) - worldIn.scheduleTick(pos, this, 0, TickPriority.EXTREMELY_HIGH); - } - - @Override - public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { - BlockEntity te = worldIn.getBlockEntity(pos); - if (te == null || !(te instanceof KineticTileEntity)) - return; - KineticTileEntity kte = (KineticTileEntity) te; - RotationPropagator.handleAdded(worldIn, pos, kte); - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java deleted file mode 100644 index dee669b335..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftInstance.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; - -import net.minecraft.world.level.block.state.BlockState; - -public class ShaftInstance extends SingleRotatingInstance { - - public ShaftInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); - } - - @Override - protected BlockState getRenderedBlockState() { - return shaft(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftRenderer.java deleted file mode 100644 index b70afbf45e..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ShaftRenderer.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; - -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.state.BlockState; - -public class ShaftRenderer extends KineticTileEntityRenderer { - - public ShaftRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java deleted file mode 100644 index 9b1576a0be..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftInstance.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import java.util.ArrayList; - -import com.jozufozu.flywheel.api.InstanceData; -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.Block; - -public class SplitShaftInstance extends KineticTileInstance { - - protected final ArrayList keys; - - public SplitShaftInstance(MaterialManager modelManager, SplitShaftTileEntity tile) { - super(modelManager, tile); - - keys = new ArrayList<>(2); - - float speed = tile.getSpeed(); - - Material rotatingMaterial = getRotatingMaterial(); - - for (Direction dir : Iterate.directionsInAxis(getRotationAxis())) { - - Instancer half = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, blockState, dir); - - float splitSpeed = speed * tile.getRotationSpeedModifier(dir); - - keys.add(setup(half.createInstance(), splitSpeed)); - } - } - - @Override - public void update() { - Block block = blockState.getBlock(); - final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(blockState); - - Direction[] directions = Iterate.directionsInAxis(boxAxis); - - for (int i : Iterate.zeroAndOne) { - updateRotation(keys.get(i), blockEntity.getSpeed() * blockEntity.getRotationSpeedModifier(directions[i])); - } - } - - @Override - public void updateLight() { - relight(pos, keys.stream()); - } - - @Override - public void remove() { - keys.forEach(InstanceData::delete); - keys.clear(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java deleted file mode 100644 index a2b4518e6d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftRenderer.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.Block; - -public class SplitShaftRenderer extends KineticTileEntityRenderer { - - public SplitShaftRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) return; - - Block block = te.getBlockState().getBlock(); - final Axis boxAxis = ((IRotate) block).getRotationAxis(te.getBlockState()); - final BlockPos pos = te.getBlockPos(); - float time = WorldTickHolder.getRenderTime(te.getLevel()); - - for (Direction direction : Iterate.directions) { - Axis axis = direction.getAxis(); - if (boxAxis != axis) - continue; - - float offset = getRotationOffsetForPosition(te, pos, axis); - float angle = (time * te.getSpeed() * 3f / 10) % 360; - float modifier = 1; - - if (te instanceof SplitShaftTileEntity) - modifier = ((SplitShaftTileEntity) te).getRotationSpeedModifier(direction); - - angle *= modifier; - angle += offset; - angle = angle / 180f * (float) Math.PI; - - SuperByteBuffer superByteBuffer = - CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, te.getBlockState(), direction); - kineticRotationTransform(superByteBuffer, te, axis, angle, light); - superByteBuffer.renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftTileEntity.java deleted file mode 100644 index 82ba0dfc9a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/SplitShaftTileEntity.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.encased; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class SplitShaftTileEntity extends DirectionalShaftHalvesTileEntity { - - public SplitShaftTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - public abstract float getRotationSpeedModifier(Direction face); - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeObservedPacket.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeObservedPacket.java deleted file mode 100644 index 8a9a85245f..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeObservedPacket.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gauge; - -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; - -public class GaugeObservedPacket extends TileEntityConfigurationPacket { - - public GaugeObservedPacket(BlockPos pos) { - super(pos); - } - - public GaugeObservedPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) {} - - @Override - protected void readSettings(FriendlyByteBuf buffer) {} - - @Override - protected void applySettings(StressGaugeTileEntity te) { - te.onObserved(); - } - - @Override - protected boolean causeUpdate() { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java deleted file mode 100644 index 41ac6e65f8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeRenderer.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gauge; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock.Type; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class GaugeRenderer extends KineticTileEntityRenderer { - - protected GaugeBlock.Type type; - - public static GaugeRenderer speed(BlockEntityRendererProvider.Context context) { - return new GaugeRenderer(context, Type.SPEED); - } - - public static GaugeRenderer stress(BlockEntityRendererProvider.Context context) { - return new GaugeRenderer(context, Type.STRESS); - } - - protected GaugeRenderer(BlockEntityRendererProvider.Context context, GaugeBlock.Type type) { - super(context); - this.type = type; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) return; - - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - BlockState gaugeState = te.getBlockState(); - GaugeTileEntity gaugeTE = (GaugeTileEntity) te; - - PartialModel partialModel = (type == Type.SPEED ? AllBlockPartials.GAUGE_HEAD_SPEED : AllBlockPartials.GAUGE_HEAD_STRESS); - SuperByteBuffer headBuffer = - CachedPartialBuffers.partial(partialModel, gaugeState); - SuperByteBuffer dialBuffer = CachedPartialBuffers.partial(AllBlockPartials.GAUGE_DIAL, gaugeState); - - float dialPivot = 5.75f / 16; - float progress = Mth.lerp(partialTicks, gaugeTE.prevDialState, gaugeTE.dialState); - - for (Direction facing : Iterate.directions) { - if (!((GaugeBlock) gaugeState.getBlock()).shouldRenderHeadOnFace(te.getLevel(), te.getBlockPos(), gaugeState, - facing)) - continue; - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - rotateBufferTowards(dialBuffer, facing).translate(0, dialPivot, dialPivot) - .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) - .translate(0, -dialPivot, -dialPivot) - .light(light) - .renderInto(ms, vb); - rotateBufferTowards(headBuffer, facing).light(light) - .renderInto(ms, vb); - } - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - - protected SuperByteBuffer rotateBufferTowards(SuperByteBuffer buffer, Direction target) { - return buffer.rotateCentered(Direction.UP, (float) ((-target.toYRot() - 90) / 180 * Math.PI)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java deleted file mode 100644 index dc7e10a1e8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gauge; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInformation { - - public float dialTarget; - public float dialState; - public float prevDialState; - public int color; - - public GaugeTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putFloat("Value", dialTarget); - compound.putInt("Color", color); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - dialTarget = compound.getFloat("Value"); - color = compound.getInt("Color"); - super.read(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - prevDialState = dialState; - dialState += (dialTarget - dialState) * .125f; - if (dialState > 1 && level.random.nextFloat() < 1 / 2f) - dialState -= (dialState - 1) * level.random.nextFloat(); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - tooltip.add(componentSpacing.plainCopy().append(CreateLang.translateDirect("gui.gauge.info_header"))); - - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java deleted file mode 100644 index 18aed589f4..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/SpeedGaugeTileEntity.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gauge; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class SpeedGaugeTileEntity extends GaugeTileEntity { - - public SpeedGaugeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - float speed = Math.abs(getSpeed()); - - dialTarget = getDialTarget(speed); - color = Color.mixColors(SpeedLevel.of(speed) - .getColor(), 0xffffff, .25f); - - setChanged(); - } - - public static float getDialTarget(float speed) { - speed = Math.abs(speed); - float medium = AllConfigs.SERVER.kinetics.mediumSpeed.get() - .floatValue(); - float fast = AllConfigs.SERVER.kinetics.fastSpeed.get() - .floatValue(); - float max = AllConfigs.SERVER.kinetics.maxRotationSpeed.get() - .floatValue(); - float target = 0; - if (speed == 0) - target = 0; - else if (speed < medium) - target = Mth.lerp(speed / medium, 0, .45f); - else if (speed < fast) - target = Mth.lerp((speed - medium) / (fast - medium), .45f, .75f); - else - target = Mth.lerp((speed - fast) / (max - fast), .75f, 1.125f); - return target; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - super.addToGoggleTooltip(tooltip, isPlayerSneaking); - CreateLang.translate("gui.speedometer.title") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - SpeedLevel.getFormattedSpeedText(speed, isOverStressed()) - .forGoggles(tooltip); - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java deleted file mode 100644 index 85301cf74d..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/StressGaugeTileEntity.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gauge; - -import java.util.List; - -import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.item.ItemDescription; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.LangBuilder; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class StressGaugeTileEntity extends GaugeTileEntity { - - static BlockPos lastSent; - - public StressGaugeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.STRESSOMETER, AllAdvancements.STRESSOMETER_MAXED); - } - - @Override - public void updateFromNetwork(float maxStress, float currentStress, int networkSize) { - super.updateFromNetwork(maxStress, currentStress, networkSize); - - if (!StressImpact.isEnabled()) - dialTarget = 0; - else if (isOverStressed()) - dialTarget = 1.125f; - else if (maxStress == 0) - dialTarget = 0; - else - dialTarget = currentStress / maxStress; - - if (dialTarget > 0) { - if (dialTarget < .5f) - color = Color.mixColors(0x00FF00, 0xFFFF00, dialTarget * 2); - else if (dialTarget < 1) - color = Color.mixColors(0xFFFF00, 0xFF0000, (dialTarget) * 2 - 1); - else - color = 0xFF0000; - } - - sendData(); - setChanged(); - } - - @Override - public void onSpeedChanged(float prevSpeed) { - super.onSpeedChanged(prevSpeed); - if (getSpeed() == 0) { - dialTarget = 0; - setChanged(); - return; - } - - updateFromNetwork(capacity, stress, getOrCreateNetwork().getSize()); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - if (!StressImpact.isEnabled()) - return false; - - super.addToGoggleTooltip(tooltip, isPlayerSneaking); - - double capacity = getNetworkCapacity(); - double stressFraction = getNetworkStress() / (capacity == 0 ? 1 : capacity); - - CreateLang.translate("gui.stressometer.title") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - - if (getTheoreticalSpeed() == 0) - CreateLang.text(ItemDescription.makeProgressBar(3, 0)) - .translate("gui.stressometer.no_rotation") - .style(ChatFormatting.DARK_GRAY) - .forGoggles(tooltip); - else { - StressImpact.getFormattedStressText(stressFraction) - .forGoggles(tooltip); - CreateLang.translate("gui.stressometer.capacity") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - - double remainingCapacity = capacity - getNetworkStress(); - - LangBuilder su = CreateLang.translate("generic.unit.stress"); - LangBuilder stressTip = CreateLang.number(remainingCapacity) - .add(su) - .style(StressImpact.of(stressFraction) - .getRelativeColor()); - - if (remainingCapacity != capacity) - stressTip.text(ChatFormatting.GRAY, " / ") - .add(CreateLang.number(capacity) - .add(su) - .style(ChatFormatting.DARK_GRAY)); - - stressTip.forGoggles(tooltip, 1); - } - - if (!worldPosition.equals(lastSent)) - AllPackets.channel.sendToServer(new GaugeObservedPacket(lastSent = worldPosition)); - - return true; - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - if (clientPacket && worldPosition != null && worldPosition.equals(lastSent)) - lastSent = null; - } - - public float getNetworkStress() { - return stress; - } - - public float getNetworkCapacity() { - return capacity; - } - - public void onObserved() { - award(AllAdvancements.STRESSOMETER); - if (Mth.equal(dialTarget, 1)) - award(AllAdvancements.STRESSOMETER_MAXED); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java deleted file mode 100644 index 0ef72e4d49..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxRenderer.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class GearboxRenderer extends KineticTileEntityRenderer { - - public GearboxRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - if (Backend.canUseInstancing(te.getLevel())) return; - - final Axis boxAxis = te.getBlockState().getValue(BlockStateProperties.AXIS); - final BlockPos pos = te.getBlockPos(); - float time = WorldTickHolder.getRenderTime(te.getLevel()); - - for (Direction direction : Iterate.directions) { - final Axis axis = direction.getAxis(); - if (boxAxis == axis) - continue; - - SuperByteBuffer shaft = CachedPartialBuffers.partialFacing(AllBlockPartials.SHAFT_HALF, te.getBlockState(), direction); - float offset = getRotationOffsetForPosition(te, pos, axis); - float angle = (time * te.getSpeed() * 3f / 10) % 360; - - if (te.getSpeed() != 0 && te.hasSource()) { - BlockPos source = te.source.subtract(te.getBlockPos()); - Direction sourceFacing = Direction.getNearest(source.getX(), source.getY(), source.getZ()); - if (sourceFacing.getAxis() == direction.getAxis()) - angle *= sourceFacing == direction ? 1 : -1; - else if (sourceFacing.getAxisDirection() == direction.getAxisDirection()) - angle *= -1; - } - - angle += offset; - angle = angle / 180f * (float) Math.PI; - - kineticRotationTransform(shaft, te, axis, angle, light); - shaft.renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxTileEntity.java deleted file mode 100644 index d7b1a3ca2a..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxTileEntity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; - -import com.simibubi.create.content.contraptions.relays.encased.DirectionalShaftHalvesTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class GearboxTileEntity extends DirectionalShaftHalvesTileEntity { - - public GearboxTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected boolean isNoisy() { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearshiftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearshiftTileEntity.java deleted file mode 100644 index cb96e271d1..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearshiftTileEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; - -import com.simibubi.create.content.contraptions.relays.encased.SplitShaftTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public class GearshiftTileEntity extends SplitShaftTileEntity { - - public GearshiftTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public float getRotationSpeedModifier(Direction face) { - if (hasSource()) { - if (face != getSourceFacing() && getBlockState().getValue(BlockStateProperties.POWERED)) - return -1; - } - return 1; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java b/src/main/java/com/simibubi/create/content/contraptions/render/ActorInstance.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ActorInstance.java index 0097df6e50..ff37307d89 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ActorInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ActorInstance.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.minecraft.world.level.LightLayer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionEntityRenderer.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionEntityRenderer.java index 9a9a965c59..9005060ae6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionEntityRenderer.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.culling.Frustum; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionGroup.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionGroup.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionGroup.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionGroup.java index a51193ecda..17a92c8800 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionGroup.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionGroup.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterialGroup; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionInstanceManager.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionInstanceManager.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionInstanceManager.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionInstanceManager.java index e235053032..adec03d1e2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionInstanceManager.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionInstanceManager.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import java.util.ArrayList; @@ -12,9 +12,9 @@ import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; import net.minecraft.client.Camera; import net.minecraft.world.level.block.entity.BlockEntity; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionLighter.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionLighter.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionLighter.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionLighter.java index 4ecd4c3cdd..d1abc17196 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionLighter.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionLighter.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.jozufozu.flywheel.light.GPULightVolume; import com.jozufozu.flywheel.light.LightListener; import com.jozufozu.flywheel.light.LightUpdater; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.Contraption; import net.minecraft.world.level.LightLayer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionMatrices.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionMatrices.java index dba46b984c..be0115244f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMatrices.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionMatrices.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.util.Mth; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionProgram.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionProgram.java index c1c6e7f91e..b00e1ccee0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionProgram.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionProgram.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import org.lwjgl.opengl.GL20; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderDispatcher.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderDispatcher.java index e34a04dd5a..c335bcdd05 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderDispatcher.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import java.util.Collection; @@ -7,6 +7,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.error.GlError; import com.jozufozu.flywheel.config.BackendType; +import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferedData; import com.jozufozu.flywheel.core.model.WorldModelBuilder; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.event.BeginFrameEvent; @@ -15,16 +16,15 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.util.WorldAttached; import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllMovementBehaviours; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionWorld; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.foundation.render.BlockEntityRenderHelper; import com.simibubi.create.foundation.render.FlwSuperByteBuffer; -import com.simibubi.create.foundation.render.TileEntityRenderHelper; import net.createmod.catnip.render.SuperByteBuffer; import net.minecraft.client.Minecraft; @@ -107,7 +107,7 @@ public class ContraptionRenderDispatcher { VirtualRenderWorld renderWorld = renderInfo.renderWorld; - renderTileEntities(world, renderWorld, contraption, matrices, buffers); + renderBlockEntities(world, renderWorld, contraption, matrices, buffers); if (buffers instanceof MultiBufferSource.BufferSource) ((MultiBufferSource.BufferSource) buffers).endBatch(); @@ -128,7 +128,7 @@ public class ContraptionRenderDispatcher { } }; - renderWorld.setBlockEntities(c.presentTileEntities.values()); + renderWorld.setBlockEntities(c.presentBlockEntities.values()); for (StructureTemplate.StructureBlockInfo info : c.getBlocks() .values()) // Skip individual lighting updates to prevent lag with large contraptions @@ -138,9 +138,9 @@ public class ContraptionRenderDispatcher { return renderWorld; } - public static void renderTileEntities(Level world, VirtualRenderWorld renderWorld, Contraption c, + public static void renderBlockEntities(Level world, VirtualRenderWorld renderWorld, Contraption c, ContraptionMatrices matrices, MultiBufferSource buffer) { - TileEntityRenderHelper.renderTileEntities(world, renderWorld, c.getSpecialRenderedTEs(), + BlockEntityRenderHelper.renderBlockEntities(world, renderWorld, c.getSpecialRenderedTEs(), matrices.getModelViewProjection(), matrices.getLight(), buffer); } @@ -172,11 +172,13 @@ public class ContraptionRenderDispatcher { public static SuperByteBuffer buildStructureBuffer(VirtualRenderWorld renderWorld, Contraption c, RenderType layer) { Collection values = c.getRenderedBlocks(); - BufferBuilder builder = new WorldModelBuilder(layer).withRenderWorld(renderWorld) + ShadeSeparatedBufferedData data = new WorldModelBuilder(layer).withRenderWorld(renderWorld) .withBlocks(values) .withModelData(c.modelData) .build(); - return new FlwSuperByteBuffer(builder); + SuperByteBuffer sbb = new FlwSuperByteBuffer(data); + data.release(); + return sbb; } public static int getLight(Level world, float lx, float ly, float lz) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderInfo.java similarity index 87% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderInfo.java index 87b25cff7e..9a0aac523c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderInfo.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderInfo.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.util.Mth; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderingWorld.java b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderingWorld.java similarity index 87% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderingWorld.java rename to src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderingWorld.java index 072b8842d8..de71b0d941 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionRenderingWorld.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/ContraptionRenderingWorld.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import java.lang.ref.Reference; import java.util.List; @@ -7,9 +7,9 @@ import java.util.Objects; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionHandler; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -64,6 +64,7 @@ public abstract class ContraptionRenderingWorld .map(Reference::get) .filter(Objects::nonNull) .map(AbstractContraptionEntity::getContraption) + .filter(Objects::nonNull) // contraptions that are too large will not be synced, and un-synced contraptions will be null .forEach(this::getRenderInfo); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/render/EmptyLighter.java b/src/main/java/com/simibubi/create/content/contraptions/render/EmptyLighter.java new file mode 100644 index 0000000000..6ff1e1bd8e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/render/EmptyLighter.java @@ -0,0 +1,16 @@ +package com.simibubi.create.content.contraptions.render; + +import com.jozufozu.flywheel.util.box.GridAlignedBB; +import com.simibubi.create.content.contraptions.Contraption; + +// so other contraptions don't crash before they have a lighter +public class EmptyLighter extends ContraptionLighter { + public EmptyLighter(Contraption contraption) { + super(contraption); + } + + @Override + public GridAlignedBB getContraptionBounds() { + return new GridAlignedBB(0, 0, 0, 1, 1, 1); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraption.java b/src/main/java/com/simibubi/create/content/contraptions/render/FlwContraption.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraption.java rename to src/main/java/com/simibubi/create/content/contraptions/render/FlwContraption.java index bc07e08e06..91a4c52973 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/FlwContraption.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import java.util.Collection; import java.util.HashMap; @@ -20,8 +20,8 @@ import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.foundation.render.CreateContexts; import net.createmod.catnip.utility.AnimationTickHolder; @@ -54,7 +54,7 @@ public class FlwContraption extends ContraptionRenderInfo { var restoreState = GlStateTracker.getRestoreState(); buildLayers(); if (ContraptionRenderDispatcher.canInstance()) { - buildInstancedTiles(); + buildInstancedBlockEntities(); buildActors(); } restoreState.restore(); @@ -95,7 +95,7 @@ public class FlwContraption extends ContraptionRenderInfo { if (!isVisible()) return; - instanceWorld.tileInstanceManager.beginFrame(SerialTaskEngine.INSTANCE, event.getCamera()); + instanceWorld.blockEntityInstanceManager.beginFrame(SerialTaskEngine.INSTANCE, event.getCamera()); Vec3 cameraPos = event.getCameraPos(); @@ -120,8 +120,9 @@ public class FlwContraption extends ContraptionRenderInfo { } public void invalidate() { - for (ArrayModelRenderer buffer : renderLayers.values()) { - buffer.delete(); + for (ArrayModelRenderer renderer : renderLayers.values()) { + renderer.delete(); + renderer.getModel().delete(); } renderLayers.clear(); @@ -131,8 +132,9 @@ public class FlwContraption extends ContraptionRenderInfo { } private void buildLayers() { - for (ArrayModelRenderer buffer : renderLayers.values()) { - buffer.delete(); + for (ArrayModelRenderer renderer : renderLayers.values()) { + renderer.delete(); + renderer.getModel().delete(); } renderLayers.clear(); @@ -144,26 +146,26 @@ public class FlwContraption extends ContraptionRenderInfo { Model layerModel = new WorldModelBuilder(layer).withRenderWorld(renderWorld) .withModelData(contraption.modelData) .withBlocks(renderedBlocks) - .intoMesh(layer + "_" + contraption.entity.getId()); + .toModel(layer + "_" + contraption.entity.getId()); renderLayers.put(layer, new ArrayModelRenderer(layerModel)); } } - private void buildInstancedTiles() { - for (BlockEntity te : contraption.maybeInstancedTileEntities) { - if (!InstancedRenderRegistry.canInstance(te.getType())) { + private void buildInstancedBlockEntities() { + for (BlockEntity be : contraption.maybeInstancedBlockEntities) { + if (!InstancedRenderRegistry.canInstance(be.getType())) { continue; } - Level world = te.getLevel(); - te.setLevel(renderWorld); - instanceWorld.tileInstanceManager.add(te); - te.setLevel(world); + Level world = be.getLevel(); + be.setLevel(renderWorld); + instanceWorld.blockEntityInstanceManager.add(be); + be.setLevel(world); } } private void buildActors() { - contraption.getActors().forEach(instanceWorld.tileInstanceManager::createActor); + contraption.getActors().forEach(instanceWorld.blockEntityInstanceManager::createActor); } public static void setupModelViewPartial(Matrix4f matrix, Matrix4f modelMatrix, AbstractContraptionEntity entity, double camX, double camY, double camZ, float pt) { @@ -175,13 +177,13 @@ public class FlwContraption extends ContraptionRenderInfo { } public void tick() { - instanceWorld.tileInstanceManager.tick(); + instanceWorld.blockEntityInstanceManager.tick(); } public static class ContraptionInstanceWorld { private final Engine engine; - private final ContraptionInstanceManager tileInstanceManager; + private final ContraptionInstanceManager blockEntityInstanceManager; public ContraptionInstanceWorld(FlwContraption parent) { switch (Backend.getBackendType()) { @@ -190,14 +192,14 @@ public class FlwContraption extends ContraptionRenderInfo { .setGroupFactory(ContraptionGroup.forContraption(parent)) .setIgnoreOriginCoordinate(true) .build(); - tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption); - engine.addListener(tileInstanceManager); + blockEntityInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption); + engine.addListener(blockEntityInstanceManager); this.engine = engine; } case BATCHING -> { engine = new BatchingEngine(); - tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption); + blockEntityInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption); } default -> throw new IllegalArgumentException("Unknown engine type"); } @@ -205,7 +207,7 @@ public class FlwContraption extends ContraptionRenderInfo { public void delete() { engine.delete(); - tileInstanceManager.invalidate(); + blockEntityInstanceManager.invalidate(); } } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java b/src/main/java/com/simibubi/create/content/contraptions/render/FlwContraptionManager.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java rename to src/main/java/com/simibubi/create/content/contraptions/render/FlwContraptionManager.java index 3c44caea78..47a58f3802 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/FlwContraptionManager.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/FlwContraptionManager.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.render; +package com.simibubi.create.content.contraptions.render; import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D; @@ -14,7 +14,7 @@ import com.jozufozu.flywheel.core.compile.ProgramContext; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.util.Textures; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.foundation.render.CreateContexts; import net.minecraft.world.level.LevelAccessor; diff --git a/src/main/java/com/simibubi/create/content/contraptions/render/NonStationaryLighter.java b/src/main/java/com/simibubi/create/content/contraptions/render/NonStationaryLighter.java new file mode 100644 index 0000000000..d339258fdc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/render/NonStationaryLighter.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.contraptions.render; + +import com.jozufozu.flywheel.light.TickingLightListener; +import com.jozufozu.flywheel.util.box.GridAlignedBB; +import com.jozufozu.flywheel.util.box.ImmutableBox; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.infrastructure.config.AllConfigs; + +public class NonStationaryLighter extends ContraptionLighter implements TickingLightListener { + public NonStationaryLighter(C contraption) { + super(contraption); + } + + @Override + public boolean tickLightListener() { + if (getVolume().volume() > AllConfigs.client().maxContraptionLightVolume.get()) + return false; + + ImmutableBox contraptionBounds = getContraptionBounds(); + + if (bounds.sameAs(contraptionBounds, 2)) { + return false; + } + bounds.assign(contraptionBounds); + growBoundsForEdgeData(bounds); + + lightVolume.move(bounds); + + return true; + } + + @Override + public GridAlignedBB getContraptionBounds() { + GridAlignedBB bb = GridAlignedBB.from(contraption.bounds); + + bb.translate(contraption.entity.blockPosition()); + + return bb; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/render/OrientedContraptionEntityRenderer.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java rename to src/main/java/com/simibubi/create/content/contraptions/render/OrientedContraptionEntityRenderer.java index 0789157fa4..53b8e89af2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/render/OrientedContraptionEntityRenderer.java @@ -1,6 +1,7 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; +package com.simibubi.create.content.contraptions.render; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.entity.EntityRendererProvider; diff --git a/src/main/java/com/simibubi/create/content/contraptions/render/SBBContraptionManager.java b/src/main/java/com/simibubi/create/content/contraptions/render/SBBContraptionManager.java new file mode 100644 index 0000000000..515523363a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/render/SBBContraptionManager.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.contraptions.render; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.contraptions.Contraption; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.render.SuperByteBufferCache; +import net.createmod.catnip.render.SuperByteBufferCache.Compartment; +import net.createmod.catnip.utility.Pair; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.world.level.LevelAccessor; + +public class SBBContraptionManager extends ContraptionRenderingWorld { + public static final Compartment> CONTRAPTION = new Compartment<>(); + + public SBBContraptionManager(LevelAccessor world) { + super(world); + } + + @Override + public void renderLayer(RenderLayerEvent event) { + super.renderLayer(event); + RenderType type = event.getType(); + VertexConsumer consumer = event.buffers.bufferSource() + .getBuffer(type); + visible.forEach(info -> renderContraptionLayerSBB(info, type, consumer)); + + event.buffers.bufferSource().endBatch(type); + } + + @Override + public boolean invalidate(Contraption contraption) { + for (RenderType chunkBufferLayer : RenderType.chunkBufferLayers()) { + SuperByteBufferCache.getInstance().invalidate(CONTRAPTION, Pair.of(contraption, chunkBufferLayer)); + } + return super.invalidate(contraption); + } + + @Override + protected ContraptionRenderInfo create(Contraption c) { + VirtualRenderWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); + return new ContraptionRenderInfo(c, renderWorld); + } + + private void renderContraptionLayerSBB(ContraptionRenderInfo renderInfo, RenderType layer, VertexConsumer consumer) { + if (!renderInfo.isVisible()) return; + + SuperByteBuffer contraptionBuffer = SuperByteBufferCache.getInstance().get(CONTRAPTION, Pair.of(renderInfo.contraption, layer), () -> ContraptionRenderDispatcher.buildStructureBuffer(renderInfo.renderWorld, renderInfo.contraption, layer)); + + if (!contraptionBuffer.isEmpty()) { + ContraptionMatrices matrices = renderInfo.getMatrices(); + + contraptionBuffer.transform(matrices.getModel()) + .light(matrices.getWorld()) + .hybridLight() + .renderInto(matrices.getViewProjection(), consumer); + } + + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/render/package-info.java b/src/main/java/com/simibubi/create/content/contraptions/render/package-info.java new file mode 100644 index 0000000000..7c51e431d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/render/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.simibubi.create.content.contraptions.render; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/sync/ClientMotionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/ClientMotionPacket.java new file mode 100644 index 0000000000..8b98a2a166 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/ClientMotionPacket.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.contraptions.sync; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +public class ClientMotionPacket extends SimplePacketBase { + + private Vec3 motion; + private boolean onGround; + private float limbSwing; + + public ClientMotionPacket(Vec3 motion, boolean onGround, float limbSwing) { + this.motion = motion; + this.onGround = onGround; + this.limbSwing = limbSwing; + } + + public ClientMotionPacket(FriendlyByteBuf buffer) { + motion = new Vec3(buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); + onGround = buffer.readBoolean(); + limbSwing = buffer.readFloat(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeFloat((float) motion.x); + buffer.writeFloat((float) motion.y); + buffer.writeFloat((float) motion.z); + buffer.writeBoolean(onGround); + buffer.writeFloat(limbSwing); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + if (sender == null) + return; + sender.setDeltaMovement(motion); + sender.setOnGround(onGround); + if (onGround) { + sender.causeFallDamage(sender.fallDistance, 1, DamageSource.FALL); + sender.fallDistance = 0; + sender.connection.aboveGroundTickCount = 0; + sender.connection.aboveGroundVehicleTickCount = 0; + } + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> sender), + new LimbSwingUpdatePacket(sender.getId(), sender.position(), limbSwing)); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionFluidPacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionFluidPacket.java new file mode 100644 index 0000000000..2c94225b87 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionFluidPacket.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.sync; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionFluidPacket extends SimplePacketBase { + + private int entityId; + private BlockPos localPos; + private FluidStack containedFluid; + + public ContraptionFluidPacket(int entityId, BlockPos localPos, FluidStack containedFluid) { + this.entityId = entityId; + this.localPos = localPos; + this.containedFluid = containedFluid; + } + + public ContraptionFluidPacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + localPos = buffer.readBlockPos(); + containedFluid = FluidStack.readFromPacket(buffer); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeBlockPos(localPos); + containedFluid.writeToPacket(buffer); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityId); + if (!(entityByID instanceof AbstractContraptionEntity)) + return; + AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; + contraptionEntity.getContraption().handleContraptionFluidPacket(localPos, containedFluid); + }); + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionInteractionPacket.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java rename to src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionInteractionPacket.java index 4d4492ca18..51dab433ee 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionInteractionPacket.java @@ -1,8 +1,6 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.sync; +package com.simibubi.create.content.contraptions.sync; -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.core.BlockPos; @@ -46,9 +44,9 @@ public class ContraptionInteractionPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer sender = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); if (sender == null) return; Entity entityByID = sender.getLevel().getEntity(target); @@ -66,7 +64,7 @@ public class ContraptionInteractionPacket extends SimplePacketBase { if (contraptionEntity.handlePlayerInteraction(sender, localPos, face, interactionHand)) sender.swing(interactionHand, true); }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionSeatMappingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionSeatMappingPacket.java new file mode 100644 index 0000000000..eaa136d035 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/ContraptionSeatMappingPacket.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.contraptions.sync; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionSeatMappingPacket extends SimplePacketBase { + + private Map mapping; + private int entityID; + private int dismountedID; + + public ContraptionSeatMappingPacket(int entityID, Map mapping) { + this(entityID, mapping, -1); + } + + public ContraptionSeatMappingPacket(int entityID, Map mapping, int dismountedID) { + this.entityID = entityID; + this.mapping = mapping; + this.dismountedID = dismountedID; + } + + public ContraptionSeatMappingPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + dismountedID = buffer.readInt(); + mapping = new HashMap<>(); + short size = buffer.readShort(); + for (int i = 0; i < size; i++) + mapping.put(buffer.readUUID(), (int) buffer.readShort()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + buffer.writeInt(dismountedID); + buffer.writeShort(mapping.size()); + mapping.forEach((k, v) -> { + buffer.writeUUID(k); + buffer.writeShort(v); + }); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().level.getEntity(entityID); + if (!(entityByID instanceof AbstractContraptionEntity)) + return; + AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; + + if (dismountedID != -1) { + Entity dismountedByID = Minecraft.getInstance().level.getEntity(dismountedID); + if (Minecraft.getInstance().player != dismountedByID) + return; + Vec3 transformedVector = contraptionEntity.getPassengerPosition(dismountedByID, 1); + if (transformedVector != null) + dismountedByID.getPersistentData() + .put("ContraptionDismountLocation", VecHelper.writeNBT(transformedVector)); + } + + contraptionEntity.getContraption() + .setSeatMapping(mapping); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/sync/LimbSwingUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/sync/LimbSwingUpdatePacket.java new file mode 100644 index 0000000000..cfde843d67 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/sync/LimbSwingUpdatePacket.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.contraptions.sync; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.network.NetworkEvent.Context; + +public class LimbSwingUpdatePacket extends SimplePacketBase { + + private int entityId; + private Vec3 position; + private float limbSwing; + + public LimbSwingUpdatePacket(int entityId, Vec3 position, float limbSwing) { + this.entityId = entityId; + this.position = position; + this.limbSwing = limbSwing; + } + + public LimbSwingUpdatePacket(FriendlyByteBuf buffer) { + entityId = buffer.readInt(); + position = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + limbSwing = buffer.readFloat(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityId); + buffer.writeDouble(position.x); + buffer.writeDouble(position.y); + buffer.writeDouble(position.z); + buffer.writeFloat(limbSwing); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ClientLevel world = Minecraft.getInstance().level; + if (world == null) + return; + Entity entity = world.getEntity(entityId); + if (entity == null) + return; + CompoundTag data = entity.getPersistentData(); + data.putInt("LastOverrideLimbSwingUpdate", 0); + data.putFloat("OverrideLimbSwing", limbSwing); + entity.lerpTo(position.x, position.y, position.z, entity.getYRot(), + entity.getXRot(), 2, false); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchHandler.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchHandler.java index 5212dd9793..f9102531a3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchHandler.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.wrench; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.createmod.catnip.gui.ScreenOpener; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchMenu.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchMenu.java index 702d4d20e3..ff51db14f2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchMenu.java +++ b/src/main/java/com/simibubi/create/content/contraptions/wrench/RadialWrenchMenu.java @@ -8,10 +8,11 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; import com.simibubi.create.AllKeys; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; import net.createmod.catnip.gui.AbstractSimiScreen; import net.createmod.catnip.gui.RadialMenu; diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java deleted file mode 100644 index ef305f1177..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItemRenderer.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.simibubi.create.content.contraptions.wrench; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; -import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.world.item.ItemStack; - -public class WrenchItemRenderer extends CustomRenderedItemModelRenderer { - - @Override - protected void render(ItemStack stack, WrenchModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, - PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - renderer.render(model.getOriginalModel(), light); - - float xOffset = -1/16f; - ms.translate(-xOffset, 0, 0); - ms.mulPose(Vector3f.YP.rotationDegrees(ScrollValueHandler.getScroll(AnimationTickHolder.getPartialTicks()))); - ms.translate(xOffset, 0, 0); - - renderer.render(model.getPartial("gear"), light); - } - - @Override - public WrenchModel createModel(BakedModel originalModel) { - return new WrenchModel(originalModel); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchModel.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchModel.java deleted file mode 100644 index c1901c3ef8..0000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.contraptions.wrench; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class WrenchModel extends CreateCustomRenderedItemModel { - - public WrenchModel(BakedModel template) { - super(template, "wrench"); - addPartials("gear"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/BackTankUtil.java b/src/main/java/com/simibubi/create/content/curiosities/armor/BackTankUtil.java deleted file mode 100644 index fb1e1a7ee1..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/BackTankUtil.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.simibubi.create.AllEnchantments; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTags; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; -import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; -import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - -public class BackTankUtil { - - public static ItemStack get(LivingEntity entity) { - for (ItemStack itemStack : entity.getArmorSlots()) - if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack)) - return itemStack; - return ItemStack.EMPTY; - } - - public static boolean hasAirRemaining(ItemStack backtank) { - return getAir(backtank) > 0; - } - - public static float getAir(ItemStack backtank) { - CompoundTag tag = backtank.getOrCreateTag(); - return Math.min(tag.getFloat("Air"), maxAir(backtank)); - } - - public static void consumeAir(LivingEntity entity, ItemStack backtank, float i) { - CompoundTag tag = backtank.getOrCreateTag(); - int maxAir = maxAir(backtank); - float air = getAir(backtank); - float newAir = air - i; - tag.putFloat("Air", Math.min(newAir, maxAir)); - backtank.setTag(tag); - - if (!(entity instanceof ServerPlayer player)) - return; - sendWarning(player, air, newAir, maxAir / 10f); - sendWarning(player, air, newAir, 1); - } - - private static void sendWarning(ServerPlayer player, float air, float newAir, float threshold) { - if (newAir > threshold) - return; - if (air <= threshold) - return; - - boolean depleted = threshold == 1; - MutableComponent component = CreateLang.translateDirect(depleted ? "backtank.depleted" : "backtank.low"); - - AllSoundEvents.DENY.play(player.level, null, player.blockPosition(), 1, 1.25f); - AllSoundEvents.STEAM.play(player.level, null, player.blockPosition(), .5f, .5f); - - player.connection.send(new ClientboundSetTitlesAnimationPacket(10, 40, 10)); - player.connection.send(new ClientboundSetSubtitleTextPacket( - Components.literal("\u26A0 ").withStyle(depleted ? ChatFormatting.RED : ChatFormatting.GOLD) - .append(component.withStyle(ChatFormatting.GRAY)))); - player.connection.send(new ClientboundSetTitleTextPacket(Components.immutableEmpty())); - } - - public static int maxAir(ItemStack backtank) { - return maxAir(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), backtank)); - } - - public static int maxAir(int enchantLevel) { - return AllConfigs.SERVER.curiosities.airInBacktank.get() - + AllConfigs.SERVER.curiosities.enchantedBacktankCapacity.get() * enchantLevel; - } - - public static int maxAirWithoutEnchants() { - return AllConfigs.SERVER.curiosities.airInBacktank.get(); - } - - public static boolean canAbsorbDamage(LivingEntity entity, int usesPerTank) { - if (usesPerTank == 0) - return true; - if (entity instanceof Player && ((Player) entity).isCreative()) - return true; - ItemStack backtank = get(entity); - if (backtank.isEmpty()) - return false; - if (!hasAirRemaining(backtank)) - return false; - float cost = ((float) maxAirWithoutEnchants()) / usesPerTank; - consumeAir(entity, backtank, cost); - return true; - } - - // For Air-using tools - - public static boolean isBarVisible(ItemStack stack, int usesPerTank) { - if (usesPerTank == 0) - return false; - Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); - if (player == null) - return false; - ItemStack backtank = get(player); - if (backtank.isEmpty() || !hasAirRemaining(backtank)) - return stack.isDamaged(); - return true; - } - - public static int getBarWidth(ItemStack stack, int usesPerTank) { - if (usesPerTank == 0) - return 13; - Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); - if (player == null) - return 13; - ItemStack backtank = get(player); - if (backtank.isEmpty() || !hasAirRemaining(backtank)) - return Math.round(13.0F - (float) stack.getDamageValue() / stack.getMaxDamage() * 13.0F); - return backtank.getItem() - .getBarWidth(backtank); - } - - public static int getBarColor(ItemStack stack, int usesPerTank) { - if (usesPerTank == 0) - return 0; - Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); - if (player == null) - return 0; - ItemStack backtank = get(player); - if (backtank.isEmpty() || !hasAirRemaining(backtank)) - return Mth.hsvToRgb(Math.max(0.0F, 1.0F - (float) stack.getDamageValue() / stack.getMaxDamage()) / 3.0F, - 1.0F, 1.0F); - return backtank.getItem() - .getBarColor(backtank); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CapacityEnchantment.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CapacityEnchantment.java deleted file mode 100644 index 531e1bf4e3..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CapacityEnchantment.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentCategory; - -public class CapacityEnchantment extends Enchantment { - - public CapacityEnchantment(Rarity p_i46731_1_, EnchantmentCategory p_i46731_2_, EquipmentSlot[] p_i46731_3_) { - super(p_i46731_1_, p_i46731_2_, p_i46731_3_); - } - - @Override - public int getMaxLevel() { - return 3; - } - - @Override - public boolean canApplyAtEnchantingTable(ItemStack stack) { - return stack.getItem() instanceof ICapacityEnchantable; - } - - public interface ICapacityEnchantable { - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperArmorItem.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperArmorItem.java deleted file mode 100644 index 8b3220ad11..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperArmorItem.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.simibubi.create.Create; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.ItemStack; - -public class CopperArmorItem extends ArmorItem { - - public static final ResourceLocation TEXTURE = Create.asResource("textures/models/armor/copper.png"); - private static final String TEXTURE_STRING = TEXTURE.toString(); - - public CopperArmorItem(EquipmentSlot p_i48534_2_, Properties p_i48534_3_) { - super(AllArmorMaterials.COPPER, p_i48534_2_, p_i48534_3_.stacksTo(1)); - } - - public boolean isWornBy(Entity entity) { - if (!(entity instanceof LivingEntity)) - return false; - LivingEntity livingEntity = (LivingEntity) entity; - return livingEntity.getItemBySlot(slot).getItem() == this; - } - - @Override - public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String type) { - return TEXTURE_STRING; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankArmorLayer.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankArmorLayer.java deleted file mode 100644 index 346a3aa8e4..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankArmorLayer.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.gui.element.GuiGameElement; -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.catnip.utility.theme.Color; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.model.EntityModel; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Sheets; -import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.client.renderer.entity.LivingEntityRenderer; -import net.minecraft.client.renderer.entity.RenderLayerParent; -import net.minecraft.client.renderer.entity.layers.RenderLayer; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.tags.FluidTags; -import net.minecraft.util.StringUtil; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Pose; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.GameType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.gui.ForgeIngameGui; -import net.minecraftforge.client.gui.IIngameOverlay; - -public class CopperBacktankArmorLayer> extends RenderLayer { - - public static final IIngameOverlay REMAINING_AIR_OVERLAY = CopperBacktankArmorLayer::renderRemainingAirOverlay; - - public CopperBacktankArmorLayer(RenderLayerParent renderer) { - super(renderer); - } - - @Override - public void render(PoseStack ms, MultiBufferSource buffer, int light, LivingEntity entity, float yaw, float pitch, - float pt, float p_225628_8_, float p_225628_9_, float p_225628_10_) { - if (entity.getPose() == Pose.SLEEPING) - return; - if (!AllItems.COPPER_BACKTANK.get() - .isWornBy(entity)) - return; - - M entityModel = getParentModel(); - if (!(entityModel instanceof HumanoidModel)) - return; - - HumanoidModel model = (HumanoidModel) entityModel; - RenderType renderType = Sheets.cutoutBlockSheet(); - BlockState renderedState = AllBlocks.COPPER_BACKTANK.getDefaultState() - .setValue(CopperBacktankBlock.HORIZONTAL_FACING, Direction.SOUTH); - SuperByteBuffer backtank = CachedBlockBuffers.block(renderedState); - SuperByteBuffer cogs = CachedPartialBuffers.partial(AllBlockPartials.COPPER_BACKTANK_COGS, renderedState); - - ms.pushPose(); - - model.body.translateAndRotate(ms); - ms.translate(-1 / 2f, 10 / 16f, 1f); - ms.scale(1, -1, -1); - - backtank - .forEntityRender() - .light(light) - .renderInto(ms, buffer.getBuffer(renderType)); - - cogs - .forEntityRender() - .centre() - .rotateY(180) - .unCentre() - .translate(0, 6.5f / 16, 11f / 16) - .rotate(Direction.EAST, AngleHelper.rad(2 * WorldTickHolder.getRenderTime(entity.level) % 360)) - .translate(0, -6.5f / 16, -11f / 16); - - cogs.light(light).renderInto(ms, buffer.getBuffer(renderType)); - - ms.popPose(); - } - - public static void registerOnAll(EntityRenderDispatcher renderManager) { - for (EntityRenderer renderer : renderManager.getSkinMap().values()) - registerOn(renderer); - for (EntityRenderer renderer : renderManager.renderers.values()) - registerOn(renderer); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static void registerOn(EntityRenderer entityRenderer) { - if (!(entityRenderer instanceof LivingEntityRenderer)) - return; - LivingEntityRenderer livingRenderer = (LivingEntityRenderer) entityRenderer; - if (!(livingRenderer.getModel() instanceof HumanoidModel)) - return; - CopperBacktankArmorLayer layer = new CopperBacktankArmorLayer<>(livingRenderer); - livingRenderer.addLayer((CopperBacktankArmorLayer) layer); - } - - public static void renderRemainingAirOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, int height) { - Minecraft mc = Minecraft.getInstance(); - if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) - return; - - LocalPlayer player = mc.player; - if (player == null) - return; - if (player.isCreative()) - return; - if (!player.getPersistentData() - .contains("VisualBacktankAir")) - return; - if (!player.isEyeInFluid(FluidTags.WATER)) - return; - - int timeLeft = player.getPersistentData() - .getInt("VisualBacktankAir"); - - poseStack.pushPose(); - - poseStack.translate(width / 2 + 90, height - 53, 0); - - Component text = Components.literal(StringUtil.formatTickDuration(timeLeft * 20)); - GuiGameElement.of(AllItems.COPPER_BACKTANK.asStack()) - .at(0, 0) - .render(poseStack); - int color = 0xFF_FFFFFF; - if (timeLeft < 60 && timeLeft % 2 == 0) { - color = Color.mixColors(0xFF_FF0000, color, Math.max(timeLeft / 60f, .25f)); - } - Minecraft.getInstance().font.drawShadow(poseStack, text, 16, 5, color); - - poseStack.popPose(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankBlock.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankBlock.java deleted file mode 100644 index a83030faa7..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankBlock.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import java.util.Optional; - -import com.simibubi.create.AllEnchantments; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SimpleWaterloggedBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.common.util.FakePlayer; - -public class CopperBacktankBlock extends HorizontalKineticBlock - implements ITE, SimpleWaterloggedBlock { - - public CopperBacktankBlock(Properties properties) { - super(properties); - registerDefaultState(super.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); - } - - @Override - public FluidState getFluidState(BlockState state) { - return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) - : Fluids.EMPTY.defaultFluidState(); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(BlockStateProperties.WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - @Override - public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} - - @Override - public boolean hasAnalogOutputSignal(BlockState p_149740_1_) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState p_180641_1_, Level world, BlockPos pos) { - return getTileEntityOptional(world, pos).map(CopperBacktankTileEntity::getComparatorOutput) - .orElse(0); - } - - @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, - LevelAccessor world, BlockPos pos, BlockPos neighbourPos) { - if (state.getValue(BlockStateProperties.WATERLOGGED)) - world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); - return state; - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - FluidState ifluidstate = context.getLevel() - .getFluidState(context.getClickedPos()); - return super.getStateForPlacement(context).setValue(BlockStateProperties.WATERLOGGED, - Boolean.valueOf(ifluidstate.getType() == Fluids.WATER)); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return face == Direction.UP; - } - - @Override - public Axis getRotationAxis(BlockState state) { - return Axis.Y; - } - - @Override - public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { - super.setPlacedBy(worldIn, pos, state, placer, stack); - if (worldIn.isClientSide) - return; - if (stack == null) - return; - withTileEntityDo(worldIn, pos, te -> { - te.setCapacityEnchantLevel(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), stack)); - te.setAirLevel(stack.getOrCreateTag() - .getInt("Air")); - if (stack.isEnchanted()) - te.setEnchantmentTag(stack.getEnchantmentTags()); - if (stack.hasCustomHoverName()) - te.setCustomName(stack.getHoverName()); - }); - } - - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand p_225533_5_, - BlockHitResult p_225533_6_) { - if (player == null) - return InteractionResult.PASS; - if (player instanceof FakePlayer) - return InteractionResult.PASS; - if (player.isShiftKeyDown()) - return InteractionResult.PASS; - if (player.getMainHandItem() - .getItem() instanceof BlockItem) - return InteractionResult.PASS; - if (!player.getItemBySlot(EquipmentSlot.CHEST) - .isEmpty()) - return InteractionResult.PASS; - if (!world.isClientSide) { - world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .75f, 1); - player.setItemSlot(EquipmentSlot.CHEST, getCloneItemStack(world, pos, state)); - world.destroyBlock(pos, false); - } - return InteractionResult.SUCCESS; - } - - @Override - public ItemStack getCloneItemStack(BlockGetter p_185473_1_, BlockPos p_185473_2_, BlockState p_185473_3_) { - ItemStack item = AllItems.COPPER_BACKTANK.asStack(); - Optional tileEntityOptional = getTileEntityOptional(p_185473_1_, p_185473_2_); - - int air = tileEntityOptional.map(CopperBacktankTileEntity::getAirLevel) - .orElse(0); - CompoundTag tag = item.getOrCreateTag(); - tag.putInt("Air", air); - - ListTag enchants = tileEntityOptional.map(CopperBacktankTileEntity::getEnchantmentTag) - .orElse(new ListTag()); - if (!enchants.isEmpty()) { - ListTag enchantmentTagList = item.getEnchantmentTags(); - enchantmentTagList.addAll(enchants); - tag.put("Enchantments", enchantmentTagList); - } - - Component customName = tileEntityOptional.map(CopperBacktankTileEntity::getCustomName) - .orElse(null); - if (customName != null) - item.setHoverName(customName); - return item; - } - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.BACKTANK; - } - - @Override - public Class getTileEntityClass() { - return CopperBacktankTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.COPPER_BACKTANK.get(); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankInstance.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankInstance.java deleted file mode 100644 index 26d1b91393..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankInstance.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -public class CopperBacktankInstance extends SingleRotatingInstance { - - public CopperBacktankInstance(MaterialManager modelManager, KineticTileEntity tile) { - super(modelManager, tile); - } - - @Override - protected Instancer getModel() { - return getRotatingMaterial().getModel(AllBlockPartials.COPPER_BACKTANK_SHAFT, blockState); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankItem.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankItem.java deleted file mode 100644 index eef4852c6a..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankItem.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.simibubi.create.content.curiosities.armor.CapacityEnchantment.ICapacityEnchantable; -import com.tterrag.registrate.util.entry.ItemEntry; - -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.block.Block; - -public class CopperBacktankItem extends CopperArmorItem implements ICapacityEnchantable { - - public static final int DURABILITY_BAR = 0xEFEFEF; - private ItemEntry blockItem; - - public CopperBacktankItem(Properties p_i48534_3_, ItemEntry copperBacktankPlaceable) { - super(EquipmentSlot.CHEST, p_i48534_3_); - this.blockItem = copperBacktankPlaceable; - } - - @Override - public InteractionResult useOn(UseOnContext p_195939_1_) { - return blockItem.get() - .useOn(p_195939_1_); - } - - @Override - public boolean canBeDepleted() { - return false; - } - - @Override - public boolean isEnchantable(ItemStack p_77616_1_) { - return true; - } - - @Override - public void fillItemCategory(CreativeModeTab p_150895_1_, NonNullList p_150895_2_) { - if (!allowdedIn(p_150895_1_)) - return; - - ItemStack stack = new ItemStack(this); - CompoundTag nbt = new CompoundTag(); - nbt.putInt("Air", BackTankUtil.maxAirWithoutEnchants()); - stack.setTag(nbt); - p_150895_2_.add(stack); - } - - @Override - public boolean isBarVisible(ItemStack stack) { - return true; - } - - @Override - public int getBarWidth(ItemStack stack) { - return Math.round(13.0F * Mth.clamp(getRemainingAir(stack) / ((float) BackTankUtil.maxAir(stack)), 0, 1)); - } - - @Override - public int getBarColor(ItemStack stack) { - return DURABILITY_BAR; - } - - public static int getRemainingAir(ItemStack stack) { - CompoundTag orCreateTag = stack.getOrCreateTag(); - return orCreateTag.getInt("Air"); - } - - public static class CopperBacktankBlockItem extends BlockItem { - - public CopperBacktankBlockItem(Block pBlock, Properties pProperties) { - super(pBlock, pProperties); - } - - @Override - public void fillItemCategory(CreativeModeTab pGroup, NonNullList pItems) {} - - @Override - public String getDescriptionId() { - return this.getOrCreateDescriptionId(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankRenderer.java deleted file mode 100644 index c4df6f90ca..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankRenderer.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class CopperBacktankRenderer extends KineticTileEntityRenderer { - - public CopperBacktankRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - BlockState blockState = te.getBlockState(); - SuperByteBuffer cogs = CachedPartialBuffers.partial(AllBlockPartials.COPPER_BACKTANK_COGS, blockState); - cogs.rotateCentered(Direction.Axis.Y, Mth.DEG_TO_RAD * (180 + AngleHelper.horizontalAngle(blockState.getValue(CopperBacktankBlock.HORIZONTAL_FACING)))) - .translate(0, 6.5f / 16, 11f / 16) - .rotate(Direction.EAST, - AngleHelper.rad(te.getSpeed() / 4f * WorldTickHolder.getRenderTime(te.getLevel()) % 360)) - .translate(0, -6.5f / 16, -11f / 16); - cogs.light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partial(AllBlockPartials.COPPER_BACKTANK_SHAFT, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankTileEntity.java deleted file mode 100644 index f24043699e..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/CopperBacktankTileEntity.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import java.util.List; - -import com.simibubi.create.AllItems; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.particle.AirParticleData; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.ComparatorUtil; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.Nameable; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.Vec3; - -public class CopperBacktankTileEntity extends KineticTileEntity implements Nameable { - - public int airLevel; - public int airLevelTimer; - private Component customName; - - private int capacityEnchantLevel; - private ListTag enchantmentTag; - - public CopperBacktankTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - enchantmentTag = new ListTag(); - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.BACKTANK); - } - - @Override - public void onSpeedChanged(float previousSpeed) { - super.onSpeedChanged(previousSpeed); - if (getSpeed() != 0) - award(AllAdvancements.BACKTANK); - } - - @Override - public void tick() { - super.tick(); - if (getSpeed() == 0) - return; - - BlockState state = getBlockState(); - BooleanProperty waterProperty = BlockStateProperties.WATERLOGGED; - if (state.hasProperty(waterProperty) && state.getValue(waterProperty)) - return; - - if (airLevelTimer > 0) { - airLevelTimer--; - return; - } - - int max = BackTankUtil.maxAir(capacityEnchantLevel); - if (level.isClientSide) { - Vec3 centerOf = VecHelper.getCenterOf(worldPosition); - Vec3 v = VecHelper.offsetRandomly(centerOf, Create.RANDOM, .65f); - Vec3 m = centerOf.subtract(v); - if (airLevel != max) - level.addParticle(new AirParticleData(1, .05f), v.x, v.y, v.z, m.x, m.y, m.z); - return; - } - - if (airLevel == max) - return; - - int prevComparatorLevel = getComparatorOutput(); - float abs = Math.abs(getSpeed()); - int increment = Mth.clamp(((int) abs - 100) / 20, 1, 5); - airLevel = Math.min(max, airLevel + increment); - if (getComparatorOutput() != prevComparatorLevel && !level.isClientSide) - level.updateNeighbourForOutputSignal(worldPosition, state.getBlock()); - if (airLevel == max) - sendData(); - airLevelTimer = Mth.clamp((int) (128f - abs / 5f) - 108, 0, 20); - } - - public int getComparatorOutput() { - int max = BackTankUtil.maxAir(capacityEnchantLevel); - return ComparatorUtil.fractionToRedstoneLevel(airLevel / (float) max); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.putInt("Air", airLevel); - compound.putInt("Timer", airLevelTimer); - compound.putInt("CapacityEnchantment", capacityEnchantLevel); - if (this.customName != null) - compound.putString("CustomName", Component.Serializer.toJson(this.customName)); - compound.put("Enchantments", enchantmentTag); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - int prev = airLevel; - capacityEnchantLevel = compound.getInt("CapacityEnchantment"); - airLevel = compound.getInt("Air"); - airLevelTimer = compound.getInt("Timer"); - enchantmentTag = compound.getList("Enchantments", Tag.TAG_COMPOUND); - if (compound.contains("CustomName", 8)) - this.customName = Component.Serializer.fromJson(compound.getString("CustomName")); - if (prev != 0 && prev != airLevel && airLevel == BackTankUtil.maxAir(capacityEnchantLevel) && clientPacket) - playFilledEffect(); - } - - protected void playFilledEffect() { - AllSoundEvents.CONFIRM.playAt(level, worldPosition, 0.4f, 1, true); - Vec3 baseMotion = new Vec3(.25, 0.1, 0); - Vec3 baseVec = VecHelper.getCenterOf(worldPosition); - for (int i = 0; i < 360; i += 10) { - Vec3 m = VecHelper.rotate(baseMotion, i, Axis.Y); - Vec3 v = baseVec.add(m.normalize() - .scale(.25f)); - - level.addParticle(ParticleTypes.SPIT, v.x, v.y, v.z, m.x, m.y, m.z); - } - } - - @Override - public Component getName() { - return this.customName != null ? this.customName - : AllItems.COPPER_BACKTANK.get() - .getDescription(); - } - - public int getAirLevel() { - return airLevel; - } - - public void setAirLevel(int airLevel) { - this.airLevel = airLevel; - sendData(); - } - - public void setCustomName(Component customName) { - this.customName = customName; - } - - public Component getCustomName() { - return customName; - } - - public ListTag getEnchantmentTag() { - return enchantmentTag; - } - - public void setEnchantmentTag(ListTag enchantmentTag) { - this.enchantmentTag = enchantmentTag; - } - - public void setCapacityEnchantLevel(int capacityEnchantLevel) { - this.capacityEnchantLevel = capacityEnchantLevel; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/DivingBootsItem.java b/src/main/java/com/simibubi/create/content/curiosities/armor/DivingBootsItem.java deleted file mode 100644 index d0d914d703..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/DivingBootsItem.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.simibubi.create.AllItems; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Pose; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber -public class DivingBootsItem extends CopperArmorItem { - - public DivingBootsItem(Properties p_i48534_3_) { - super(EquipmentSlot.FEET, p_i48534_3_); - } - - @SubscribeEvent - public static void accellerateDescentUnderwater(LivingUpdateEvent event) { - LivingEntity entity = event.getEntityLiving(); - if (!affects(entity)) - return; - - Vec3 motion = entity.getDeltaMovement(); - boolean isJumping = entity.jumping; - entity.setOnGround(entity.isOnGround() || entity.verticalCollision); - - if (isJumping && entity.isOnGround()) { - motion = motion.add(0, .5f, 0); - entity.setOnGround(false); - } else { - motion = motion.add(0, -0.05f, 0); - } - - float multiplier = 1.3f; - if (motion.multiply(1, 0, 1) - .length() < 0.145f && (entity.zza > 0 || entity.xxa != 0) && !entity.isShiftKeyDown()) - motion = motion.multiply(multiplier, 1, multiplier); - entity.setDeltaMovement(motion); - } - - protected static boolean affects(LivingEntity entity) { - if (!AllItems.DIVING_BOOTS.get() - .isWornBy(entity)) { - entity.getPersistentData() - .remove("HeavyBoots"); - return false; - } - - NBTHelper.putMarker(entity.getPersistentData(), "HeavyBoots"); - if (!entity.isInWater()) - return false; - if (entity.getPose() == Pose.SWIMMING) - return false; - if (entity instanceof Player) { - Player playerEntity = (Player) entity; - if (playerEntity.getAbilities().flying) - return false; - } - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/DivingHelmetItem.java b/src/main/java/com/simibubi/create/content/curiosities/armor/DivingHelmetItem.java deleted file mode 100644 index bde2a4e659..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/DivingHelmetItem.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.simibubi.create.content.curiosities.armor; - -import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.advancement.AllAdvancements; - -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber -public class DivingHelmetItem extends CopperArmorItem { - - public DivingHelmetItem(Properties p_i48534_3_) { - super(EquipmentSlot.HEAD, p_i48534_3_); - } - - @SubscribeEvent - public static void breatheUnderwater(LivingUpdateEvent event) { - LivingEntity entity = event.getEntityLiving(); - Level world = entity.level; - boolean second = world.getGameTime() % 20 == 0; - boolean drowning = entity.getAirSupply() == 0; - - if (world.isClientSide) - entity.getPersistentData() - .remove("VisualBacktankAir"); - - if (!AllItems.DIVING_HELMET.get() - .isWornBy(entity)) - return; - - boolean lavaDiving = entity.isEyeInFluid(FluidTags.LAVA); - if (!entity.isEyeInFluid(FluidTags.WATER) && !lavaDiving) - return; - if (entity instanceof Player && ((Player) entity).isCreative()) - return; - - ItemStack backtank = BackTankUtil.get(entity); - if (backtank.isEmpty()) - return; - if (!BackTankUtil.hasAirRemaining(backtank)) - return; - - if (lavaDiving) { - if (entity instanceof ServerPlayer sp) - AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp); - return; - } - - if (drowning) - entity.setAirSupply(10); - - if (world.isClientSide) - entity.getPersistentData() - .putInt("VisualBacktankAir", (int) BackTankUtil.getAir(backtank)); - - if (!second) - return; - - if (entity instanceof ServerPlayer sp) - AllAdvancements.DIVING_SUIT.awardTo(sp); - - entity.setAirSupply(Math.min(entity.getMaxAirSupply(), entity.getAirSupply() + 10)); - entity.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 30, 0, true, false, true)); - BackTankUtil.consumeAir(entity, backtank, 1); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellTileEntity.java deleted file mode 100644 index 079889058a..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellTileEntity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import java.util.List; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public abstract class AbstractBellTileEntity extends SmartTileEntity { - - public static final int RING_DURATION = 74; - - public boolean isRinging; - public int ringingTicks; - public Direction ringDirection; - - public AbstractBellTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { } - - public boolean ring(Level world, BlockPos pos, Direction direction) { - isRinging = true; - ringingTicks = 0; - ringDirection = direction; - sendData(); - return true; - }; - - @Override - public void tick() { - super.tick(); - - if (isRinging) { - ++ringingTicks; - } - - if (ringingTicks >= RING_DURATION) { - isRinging = false; - ringingTicks = 0; - } - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - if (!clientPacket || ringingTicks != 0 || !isRinging) - return; - NBTHelper.writeEnum(tag, "Ringing", ringDirection); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - super.read(tag, clientPacket); - if (!clientPacket || !tag.contains("Ringing")) - return; - ringDirection = NBTHelper.readEnum(tag, "Ringing", Direction.class); - ringingTicks = 0; - isRinging = true; - } - - @OnlyIn(Dist.CLIENT) - public abstract PartialModel getBellModel(); - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/BellRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/bell/BellRenderer.java deleted file mode 100644 index 0b13b7b9f0..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/BellRenderer.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.BellBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BellAttachType; - -public class BellRenderer extends SafeTileEntityRenderer { - - public BellRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(TE te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - BlockState state = te.getBlockState(); - Direction facing = state.getValue(BellBlock.FACING); - BellAttachType attachment = state.getValue(BellBlock.ATTACHMENT); - - SuperByteBuffer bell = CachedPartialBuffers.partial(te.getBellModel(), state); - - if (te.isRinging) - bell.rotateCentered(te.ringDirection.getCounterClockWise(), getSwingAngle(te.ringingTicks + partialTicks)); - - float rY = AngleHelper.horizontalAngle(facing); - if (attachment == BellAttachType.SINGLE_WALL || attachment == BellAttachType.DOUBLE_WALL) - rY += 90; - bell.rotateCentered(Direction.UP, AngleHelper.rad(rY)); - - bell.light(light) - .renderInto(ms, buffer.getBuffer(RenderType.cutout())); - } - - public static float getSwingAngle(float time) { - float t = time / 1.5f; - return 1.2f * Mth.sin(t / (float) Math.PI) / (2.5f + t / 3.0f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellBlock.java b/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellBlock.java deleted file mode 100644 index 4813daa134..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellBlock.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.advancement.AllAdvancements; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class HauntedBellBlock extends AbstractBellBlock { - - public HauntedBellBlock(Properties properties) { - super(properties); - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.HAUNTED_BELL.get(); - } - - @Override - protected boolean ring(Level world, BlockPos pos, Direction direction, Player player) { - boolean ring = super.ring(world, pos, direction, player); - if (ring) - AllAdvancements.HAUNTED_BELL.awardTo(player); - return ring; - } - - @Override - public Class getTileEntityClass() { - return HauntedBellTileEntity.class; - } - - @Override - public void playSound(Level world, BlockPos pos) { - AllSoundEvents.HAUNTED_BELL_USE.playOnServer(world, pos, 4f, 1f); - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { - if (oldState.getBlock() != this && !world.isClientSide) - withTileEntityDo(world, pos, hbte -> { - hbte.effectTicks = HauntedBellTileEntity.EFFECT_TICKS; - hbte.sendData(); - }); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellMovementBehaviour.java deleted file mode 100644 index 4eeec2f612..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellMovementBehaviour.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import com.simibubi.create.content.contraptions.components.actors.BellMovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; - -import net.minecraft.core.BlockPos; - -public class HauntedBellMovementBehaviour extends BellMovementBehaviour { - - public static final int DISTANCE = 3; - - @Override - public void tick(MovementContext context) { - int recharge = getRecharge(context); - if (recharge > 0) - setRecharge(context, recharge - 1); - } - - @Override - public void visitNewPosition(MovementContext context, BlockPos pos) { - if (!context.world.isClientSide && getRecharge(context) == 0) { - HauntedBellPulser.sendPulse(context.world, pos, DISTANCE, false); - setRecharge(context, HauntedBellTileEntity.RECHARGE_TICKS); - playSound(context); - } - } - - @Override - public void writeExtraData(MovementContext context) { - context.tileData.putInt("Recharge", getRecharge(context)); - } - - private int getRecharge(MovementContext context) { - if (!(context.temporaryData instanceof Integer) && context.world != null) { - context.temporaryData = context.tileData.getInt("Recharge"); - } - return (Integer) context.temporaryData; - } - - private void setRecharge(MovementContext context, int value) { - context.temporaryData = value; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellTileEntity.java deleted file mode 100644 index 619e6e3f07..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellTileEntity.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import java.util.Random; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class HauntedBellTileEntity extends AbstractBellTileEntity { - - public static final int DISTANCE = 10; - public static final int RECHARGE_TICKS = 65; - public static final int EFFECT_TICKS = 20; - - public int effectTicks = 0; - - public HauntedBellTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - @OnlyIn(Dist.CLIENT) - public PartialModel getBellModel() { - return AllBlockPartials.HAUNTED_BELL; - } - - @Override - public boolean ring(Level world, BlockPos pos, Direction direction) { - if (isRinging && ringingTicks < RECHARGE_TICKS) - return false; - HauntedBellPulser.sendPulse(world, pos, DISTANCE, false); - effectTicks = EFFECT_TICKS; - return super.ring(world, pos, direction); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.putInt("EffectTicks", effectTicks); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - effectTicks = compound.getInt("EffectTicks"); - } - - @Override - public void tick() { - super.tick(); - - if (effectTicks <= 0) - return; - effectTicks--; - - if (!level.isClientSide) - return; - - Random rand = level.getRandom(); - if (rand.nextFloat() > 0.25f) - return; - - spawnParticle(rand); - playSound(rand); - } - - protected void spawnParticle(Random rand) { - double x = worldPosition.getX() + rand.nextDouble(); - double y = worldPosition.getY() + 0.5; - double z = worldPosition.getZ() + rand.nextDouble(); - double vx = rand.nextDouble() * 0.04 - 0.02; - double vy = 0.1; - double vz = rand.nextDouble() * 0.04 - 0.02; - level.addParticle(ParticleTypes.SOUL, x, y, z, vx, vy, vz); - } - - protected void playSound(Random rand) { - float vol = rand.nextFloat() * 0.4F + rand.nextFloat() > 0.9F ? 0.6F : 0.0F; - float pitch = 0.6F + rand.nextFloat() * 0.4F; - level.playSound(null, worldPosition, SoundEvents.SOUL_ESCAPE, SoundSource.BLOCKS, vol, pitch); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellTileEntity.java deleted file mode 100644 index 07c521de91..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellTileEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.simibubi.create.content.curiosities.bell; - -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class PeculiarBellTileEntity extends AbstractBellTileEntity { - - public PeculiarBellTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - @OnlyIn(Dist.CLIENT) - public PartialModel getBellModel() { - return AllBlockPartials.PECULIAR_BELL; - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardTileEntity.java deleted file mode 100644 index 26edb157af..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardTileEntity.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.simibubi.create.content.curiosities.deco; - -import java.util.List; - -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.particles.DustParticleOptions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class PlacardTileEntity extends SmartTileEntity { - - ItemStack heldItem; - int poweredTicks; - - public PlacardTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - heldItem = ItemStack.EMPTY; - poweredTicks = 0; - } - - @Override - public void tick() { - super.tick(); - if (level.isClientSide) - return; - if (poweredTicks == 0) - return; - - poweredTicks--; - if (poweredTicks > 0) - return; - - BlockState blockState = getBlockState(); - level.setBlock(worldPosition, blockState.setValue(PlacardBlock.POWERED, false), 3); - PlacardBlock.updateNeighbours(blockState, level, worldPosition); - } - - public ItemStack getHeldItem() { - return heldItem; - } - - public void setHeldItem(ItemStack heldItem) { - this.heldItem = heldItem; - notifyUpdate(); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - tag.putInt("PoweredTicks", poweredTicks); - tag.put("Item", heldItem.serializeNBT()); - super.write(tag, clientPacket); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - int prevTicks = poweredTicks; - poweredTicks = tag.getInt("PoweredTicks"); - heldItem = ItemStack.of(tag.getCompound("Item")); - super.read(tag, clientPacket); - - if (clientPacket && prevTicks < poweredTicks) - spawnParticles(); - } - - private void spawnParticles() { - BlockState blockState = getBlockState(); - if (!AllBlocks.PLACARD.has(blockState)) - return; - - DustParticleOptions pParticleData = new DustParticleOptions(new Vector3f(1, .2f, 0), 1); - Vec3 centerOf = VecHelper.getCenterOf(worldPosition); - Vec3 normal = Vec3.atLowerCornerOf(PlacardBlock.connectedDirection(blockState) - .getNormal()); - Vec3 offset = VecHelper.axisAlingedPlaneOf(normal); - - for (int i = 0; i < 10; i++) { - Vec3 v = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .5f) - .multiply(offset) - .normalize() - .scale(.45f) - .add(normal.scale(-.45f)) - .add(centerOf); - level.addParticle(pParticleData, v.x, v.y, v.z, 0, 0, 0); - } - } - - @Override - public void addBehaviours(List behaviours) {} - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java deleted file mode 100644 index ecea33eafd..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.simibubi.create.content.curiosities.deco; - -import java.util.Map; - -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.CarriageSyncData; - -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.block.DoorBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; - -public class SlidingDoorMovementBehaviour implements MovementBehaviour { - - @Override - public boolean renderAsNormalTileEntity() { - return true; - } - - @Override - public void tick(MovementContext context) { - StructureBlockInfo structureBlockInfo = context.contraption.getBlocks() - .get(context.localPos); - if (structureBlockInfo == null) - return; - boolean open = SlidingDoorTileEntity.isOpen(structureBlockInfo.state); - - if (!context.world.isClientSide()) - tickOpen(context, open); - - Map tes = context.contraption.presentTileEntities; - if (!(tes.get(context.localPos) instanceof SlidingDoorTileEntity doorTE)) - return; - boolean wasSettled = doorTE.animation.settled(); - doorTE.animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); - doorTE.animation.tickChaser(); - - if (!wasSettled && doorTE.animation.settled() && !open) - context.world.playLocalSound(context.position.x, context.position.y, context.position.z, - SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .125f, 1, false); - } - - protected void tickOpen(MovementContext context, boolean currentlyOpen) { - boolean shouldOpen = shouldOpen(context); - if (!shouldUpdate(context, shouldOpen)) - return; - if (currentlyOpen == shouldOpen) - return; - - BlockPos pos = context.localPos; - Contraption contraption = context.contraption; - - StructureBlockInfo info = contraption.getBlocks() - .get(pos); - if (info == null || !info.state.hasProperty(DoorBlock.OPEN)) - return; - - toggleDoor(pos, contraption, info); - - if (shouldOpen) - context.world.playSound(null, new BlockPos(context.position), SoundEvents.IRON_DOOR_OPEN, - SoundSource.BLOCKS, .125f, 1); - } - - private void toggleDoor(BlockPos pos, Contraption contraption, StructureBlockInfo info) { - BlockState newState = info.state.cycle(DoorBlock.OPEN); - contraption.entity.setBlock(pos, new StructureBlockInfo(info.pos, newState, info.nbt)); - - BlockPos otherPos = newState.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? pos.above() : pos.below(); - info = contraption.getBlocks() - .get(otherPos); - if (info != null && info.state.hasProperty(DoorBlock.OPEN)) { - newState = info.state.cycle(DoorBlock.OPEN); - contraption.entity.setBlock(otherPos, new StructureBlockInfo(info.pos, newState, info.nbt)); - contraption.invalidateColliders(); - } - } - - protected boolean shouldUpdate(MovementContext context, boolean shouldOpen) { - if (context.firstMovement && shouldOpen) - return false; - if (!context.data.contains("Open")) { - context.data.putBoolean("Open", shouldOpen); - return true; - } - boolean wasOpen = context.data.getBoolean("Open"); - context.data.putBoolean("Open", shouldOpen); - return wasOpen != shouldOpen; - } - - protected boolean shouldOpen(MovementContext context) { - if (context.contraption.entity instanceof CarriageContraptionEntity cce) { - CarriageSyncData carriageData = cce.getCarriageData(); - if (Math.abs(carriageData.distanceToDestination) > 1) - return false; - } - return context.motion.length() < 1 / 128f && !context.contraption.entity.isStalled(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java deleted file mode 100644 index 8afa39a3b4..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.simibubi.create.content.curiosities.deco; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.DoorBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.DoorHingeSide; -import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; -import net.minecraft.world.phys.Vec3; - -public class SlidingDoorRenderer extends SafeTileEntityRenderer { - - public SlidingDoorRenderer(Context context) {} - - @Override - protected void renderSafe(SlidingDoorTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - if (!te.shouldRenderSpecial(blockState)) - return; - - Direction facing = blockState.getValue(DoorBlock.FACING); - Direction movementDirection = facing.getClockWise(); - - if (blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.LEFT) - movementDirection = movementDirection.getOpposite(); - - float value = te.animation.getValue(partialTicks); - float value2 = Mth.clamp(value * 10, 0, 1); - - Vec3 offset = Vec3.atLowerCornerOf(movementDirection.getNormal()) - .scale(value * value * 13 / 16f) - .add(Vec3.atLowerCornerOf(facing.getNormal()) - .scale(value2 * 1 / 32f)); - - VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - for (DoubleBlockHalf half : DoubleBlockHalf.values()) { - CachedBlockBuffers.block(blockState.setValue(DoorBlock.OPEN, false) - .setValue(DoorBlock.HALF, half)) - .translate(0, half == DoubleBlockHalf.UPPER ? 1 - 1 / 512f : 0, 0) - .translate(offset.x, offset.y, offset.z) - .light(light) - .renderInto(ms, vb); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorTileEntity.java deleted file mode 100644 index bfac67e9f8..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorTileEntity.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.simibubi.create.content.curiosities.deco; - -import java.util.List; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.DoorBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class SlidingDoorTileEntity extends SmartTileEntity { - - LerpedFloat animation; - int bridgeTicks; - boolean deferUpdate; - - public SlidingDoorTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - animation = LerpedFloat.linear() - .startWithValue(isOpen(state) ? 1 : 0); - } - - @Override - public void tick() { - if (deferUpdate && !level.isClientSide()) { - deferUpdate = false; - BlockState blockState = getBlockState(); - blockState.neighborChanged(level, worldPosition, Blocks.AIR, worldPosition, false); - } - - super.tick(); - boolean open = isOpen(getBlockState()); - boolean wasSettled = animation.settled(); - animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); - animation.tickChaser(); - - if (level.isClientSide()) { - if (bridgeTicks < 2 && open) - bridgeTicks++; - else if (bridgeTicks > 0 && !open && isVisible(getBlockState())) - bridgeTicks--; - return; - } - - if (!open && !wasSettled && animation.settled() && !isVisible(getBlockState())) - showBlockModel(); - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(1); - } - - protected boolean isVisible(BlockState state) { - return state.getOptionalValue(SlidingDoorBlock.VISIBLE) - .orElse(true); - } - - protected boolean shouldRenderSpecial(BlockState state) { - return !isVisible(state) || bridgeTicks != 0; - } - - protected void showBlockModel() { - level.setBlock(worldPosition, getBlockState().setValue(SlidingDoorBlock.VISIBLE, true), 3); - level.playSound(null, worldPosition, SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .5f, 1); - } - - @Override - public void addBehaviours(List behaviours) {} - - public static boolean isOpen(BlockState state) { - return state.getOptionalValue(DoorBlock.OPEN) - .orElse(false); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandItemRenderer.java deleted file mode 100644 index 0710777052..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandItemRenderer.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.simibubi.create.content.curiosities.symmetry.client; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; -import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; - -public class SymmetryWandItemRenderer extends CustomRenderedItemModelRenderer { - - @Override - protected void render(ItemStack stack, SymmetryWandModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, - PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - float worldTime = AnimationTickHolder.getRenderTime() / 20; - int maxLight = LightTexture.FULL_BRIGHT; - - renderer.render(model.getOriginalModel(), light); - renderer.renderSolidGlowing(model.getPartial("core"), maxLight); - renderer.renderGlowing(model.getPartial("core_glow"), maxLight); - - float floating = Mth.sin(worldTime) * .05f; - float angle = worldTime * -10 % 360; - - ms.translate(0, floating, 0); - ms.mulPose(Vector3f.YP.rotationDegrees(angle)); - - renderer.renderGlowing(model.getPartial("bits"), maxLight); - } - - @Override - public SymmetryWandModel createModel(BakedModel originalModel) { - return new SymmetryWandModel(originalModel); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandModel.java b/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandModel.java deleted file mode 100644 index 233914a750..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/client/SymmetryWandModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.curiosities.symmetry.client; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class SymmetryWandModel extends CreateCustomRenderedItemModel { - - public SymmetryWandModel(BakedModel template) { - super(template, "wand_of_symmetry"); - addPartials("bits", "core", "core_glow"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxContainer.java b/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxContainer.java deleted file mode 100644 index c7b5ddfe6c..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxContainer.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import static com.simibubi.create.content.curiosities.toolbox.ToolboxInventory.STACKS_PER_COMPARTMENT; - -import com.simibubi.create.AllContainerTypes; -import com.simibubi.create.foundation.gui.container.ContainerBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.items.SlotItemHandler; - -public class ToolboxContainer extends ContainerBase { - - public ToolboxContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public ToolboxContainer(MenuType type, int id, Inventory inv, ToolboxTileEntity te) { - super(type, id, inv, te); - te.startOpen(player); - } - - public static ToolboxContainer create(int id, Inventory inv, ToolboxTileEntity te) { - return new ToolboxContainer(AllContainerTypes.TOOLBOX.get(), id, inv, te); - } - - @Override - protected ToolboxTileEntity createOnClient(FriendlyByteBuf extraData) { - BlockPos readBlockPos = extraData.readBlockPos(); - CompoundTag readNbt = extraData.readNbt(); - - ClientLevel world = Minecraft.getInstance().level; - BlockEntity tileEntity = world.getBlockEntity(readBlockPos); - if (tileEntity instanceof ToolboxTileEntity) { - ToolboxTileEntity toolbox = (ToolboxTileEntity) tileEntity; - toolbox.readClient(readNbt); - return toolbox; - } - - return null; - } - - @Override - public ItemStack quickMoveStack(Player player, int index) { - Slot clickedSlot = getSlot(index); - if (!clickedSlot.hasItem()) - return ItemStack.EMPTY; - - ItemStack stack = clickedSlot.getItem(); - int size = contentHolder.inventory.getSlots(); - boolean success = false; - if (index < size) { - success = !moveItemStackTo(stack, size, slots.size(), false); - contentHolder.inventory.onContentsChanged(index); - } else - success = !moveItemStackTo(stack, 0, size - 1, false); - - return success ? ItemStack.EMPTY : stack; - } - - @Override - protected void initAndReadInventory(ToolboxTileEntity contentHolder) { - - } - - @Override - public void clicked(int index, int flags, ClickType type, Player player) { - int size = contentHolder.inventory.getSlots(); - - if (index >= 0 && index < size) { - ItemStack itemInClickedSlot = getSlot(index).getItem(); - ItemStack carried = getCarried(); - - if (type == ClickType.PICKUP && !carried.isEmpty() && !itemInClickedSlot.isEmpty() - && ToolboxInventory.canItemsShareCompartment(itemInClickedSlot, carried)) { - int subIndex = index % STACKS_PER_COMPARTMENT; - if (subIndex != STACKS_PER_COMPARTMENT - 1) { - clicked(index - subIndex + STACKS_PER_COMPARTMENT - 1, flags, type, player); - return; - } - } - - if (type == ClickType.PICKUP && carried.isEmpty() && itemInClickedSlot.isEmpty()) - if (!player.level.isClientSide) { - contentHolder.inventory.filters.set(index / STACKS_PER_COMPARTMENT, ItemStack.EMPTY); - contentHolder.sendData(); - } - - } - super.clicked(index, flags, type, player); - } - - @Override - public boolean canDragTo(Slot slot) { - return slot.index > contentHolder.inventory.getSlots() && super.canDragTo(slot); - } - - public ItemStack getFilter(int compartment) { - return contentHolder.inventory.filters.get(compartment); - } - - public int totalCountInCompartment(int compartment) { - int count = 0; - int baseSlot = compartment * STACKS_PER_COMPARTMENT; - for (int i = 0; i < STACKS_PER_COMPARTMENT; i++) - count += getSlot(baseSlot + i).getItem() - .getCount(); - return count; - } - - public boolean renderPass; - - @Override - protected void addSlots() { - ToolboxInventory inventory = contentHolder.inventory; - - int x = 79; - int y = 37; - - int[] xOffsets = { x, x + 33, x + 66, x + 66 + 6, x + 66, x + 33, x, x - 6 }; - int[] yOffsets = { y, y - 6, y, y + 33, y + 66, y + 66 + 6, y + 66, y + 33 }; - - for (int compartment = 0; compartment < 8; compartment++) { - int baseIndex = compartment * STACKS_PER_COMPARTMENT; - - // Representative Slots - addSlot(new ToolboxSlot(this, inventory, baseIndex, xOffsets[compartment], yOffsets[compartment])); - - // Hidden Slots - for (int i = 1; i < STACKS_PER_COMPARTMENT; i++) - addSlot(new SlotItemHandler(inventory, baseIndex + i, -10000, -10000)); - } - - addPlayerSlots(8, 165); - } - - @Override - protected void saveData(ToolboxTileEntity contentHolder) { - - } - - @Override - public void removed(Player playerIn) { - super.removed(playerIn); - if (!playerIn.level.isClientSide) - contentHolder.stopOpen(playerIn); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxRenderer.java deleted file mode 100644 index a59afc6986..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxRenderer.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class ToolboxRenderer extends SmartTileEntityRenderer { - - public ToolboxRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(ToolboxTileEntity tileEntityIn, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - - BlockState blockState = tileEntityIn.getBlockState(); - Direction facing = blockState.getValue(ToolboxBlock.FACING) - .getOpposite(); - SuperByteBuffer lid = - CachedPartialBuffers.partial(AllBlockPartials.TOOLBOX_LIDS.get(tileEntityIn.getColor()), blockState); - SuperByteBuffer drawer = CachedPartialBuffers.partial(AllBlockPartials.TOOLBOX_DRAWER, blockState); - - float lidAngle = tileEntityIn.lid.getValue(partialTicks); - float drawerOffset = tileEntityIn.drawers.getValue(partialTicks); - - VertexConsumer builder = buffer.getBuffer(RenderType.cutoutMipped()); - lid - .rotateCentered(Direction.Axis.Y, Mth.DEG_TO_RAD * -facing.toYRot()) - .translate(0, 6 / 16f, 12 / 16f) - .rotate(Direction.Axis.X, Mth.DEG_TO_RAD * (135 * lidAngle)) - .translate(0, -6 / 16f, -12 / 16f) - .light(light) - .renderInto(ms, builder); - - for (int offset : Iterate.zeroAndOne) { - drawer - .rotateCentered(Direction.Axis.Y, Mth.DEG_TO_RAD * -facing.toYRot()) - .translate(0, offset * 1 / 8f, -drawerOffset * .175f * (2 - offset)) - .light(light) - .renderInto(ms, builder); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxSlot.java b/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxSlot.java deleted file mode 100644 index b14d0573fd..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxSlot.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class ToolboxSlot extends SlotItemHandler { - - private ToolboxContainer toolboxMenu; - - public ToolboxSlot(ToolboxContainer container, IItemHandler itemHandler, int index, int xPosition, int yPosition) { - super(itemHandler, index, xPosition, yPosition); - this.toolboxMenu = container; - } - - @Override - public boolean isActive() { - return !toolboxMenu.renderPass && super.isActive(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxTileEntity.java deleted file mode 100644 index 5a1fa9f2b1..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxTileEntity.java +++ /dev/null @@ -1,421 +0,0 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; -import java.util.WeakHashMap; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.ResetableLazy; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.Nameable; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -public class ToolboxTileEntity extends SmartTileEntity implements MenuProvider, Nameable { - - public LerpedFloat lid = LerpedFloat.linear() - .startWithValue(0); - - public LerpedFloat drawers = LerpedFloat.linear() - .startWithValue(0); - - UUID uniqueId; - ToolboxInventory inventory; - LazyOptional inventoryProvider; - ResetableLazy colorProvider; - protected int openCount; - - Map> connectedPlayers; - - private Component customName; - - public ToolboxTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - connectedPlayers = new HashMap<>(); - inventory = new ToolboxInventory(this); - inventoryProvider = LazyOptional.of(() -> inventory); - colorProvider = ResetableLazy.of(() -> { - BlockState blockState = getBlockState(); - if (blockState != null && blockState.getBlock() instanceof ToolboxBlock) - return ((ToolboxBlock) blockState.getBlock()).getColor(); - return DyeColor.BROWN; - }); - setLazyTickRate(10); - } - - public DyeColor getColor() { - return colorProvider.get(); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void initialize() { - super.initialize(); - ToolboxHandler.onLoad(this); - } - - @Override - public void setRemoved() { - super.setRemoved(); - ToolboxHandler.onUnload(this); - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) - tickAudio(); - if (!level.isClientSide) - tickPlayers(); - - lid.chase(openCount > 0 ? 1 : 0, 0.2f, Chaser.LINEAR); - drawers.chase(openCount > 0 ? 1 : 0, 0.2f, Chaser.EXP); - lid.tickChaser(); - drawers.tickChaser(); - } - - private void tickPlayers() { - boolean update = false; - - for (Iterator>> toolboxSlots = connectedPlayers.entrySet() - .iterator(); toolboxSlots.hasNext();) { - - Entry> toolboxSlotEntry = toolboxSlots.next(); - WeakHashMap set = toolboxSlotEntry.getValue(); - int slot = toolboxSlotEntry.getKey(); - - ItemStack referenceItem = inventory.filters.get(slot); - boolean clear = referenceItem.isEmpty(); - - for (Iterator> playerEntries = set.entrySet() - .iterator(); playerEntries.hasNext();) { - Entry playerEntry = playerEntries.next(); - - Player player = playerEntry.getKey(); - int hotbarSlot = playerEntry.getValue(); - - if (!clear && !ToolboxHandler.withinRange(player, this)) - continue; - - Inventory playerInv = player.getInventory(); - ItemStack playerStack = playerInv.getItem(hotbarSlot); - - if (clear || !playerStack.isEmpty() - && !ToolboxInventory.canItemsShareCompartment(playerStack, referenceItem)) { - player.getPersistentData() - .getCompound("CreateToolboxData") - .remove(String.valueOf(hotbarSlot)); - playerEntries.remove(); - if (player instanceof ServerPlayer) - ToolboxHandler.syncData(player); - continue; - } - - int count = playerStack.getCount(); - int targetAmount = (referenceItem.getMaxStackSize() + 1) / 2; - - if (count < targetAmount) { - int amountToReplenish = targetAmount - count; - - if (isOpenInContainer(player)) { - ItemStack extracted = inventory.takeFromCompartment(amountToReplenish, slot, true); - if (!extracted.isEmpty()) { - ToolboxHandler.unequip(player, hotbarSlot, false); - ToolboxHandler.syncData(player); - continue; - } - } - - ItemStack extracted = inventory.takeFromCompartment(amountToReplenish, slot, false); - if (!extracted.isEmpty()) { - update = true; - ItemStack template = playerStack.isEmpty() ? extracted : playerStack; - playerInv.setItem(hotbarSlot, - ItemHandlerHelper.copyStackWithSize(template, count + extracted.getCount())); - } - } - - if (count > targetAmount) { - int amountToDeposit = count - targetAmount; - ItemStack toDistribute = ItemHandlerHelper.copyStackWithSize(playerStack, amountToDeposit); - - if (isOpenInContainer(player)) { - int deposited = amountToDeposit - inventory.distributeToCompartment(toDistribute, slot, true) - .getCount(); - if (deposited > 0) { - ToolboxHandler.unequip(player, hotbarSlot, true); - ToolboxHandler.syncData(player); - continue; - } - } - - int deposited = amountToDeposit - inventory.distributeToCompartment(toDistribute, slot, false) - .getCount(); - if (deposited > 0) { - update = true; - playerInv.setItem(hotbarSlot, - ItemHandlerHelper.copyStackWithSize(playerStack, count - deposited)); - } - } - } - - if (clear) - toolboxSlots.remove(); - } - - if (update) - - sendData(); - - } - - private boolean isOpenInContainer(Player player) { - return player.containerMenu instanceof ToolboxContainer - && ((ToolboxContainer) player.containerMenu).contentHolder == this; - } - - public void unequipTracked() { - if (level.isClientSide) - return; - - Set affected = new HashSet<>(); - - for (Iterator>> toolboxSlots = connectedPlayers.entrySet() - .iterator(); toolboxSlots.hasNext();) { - - Entry> toolboxSlotEntry = toolboxSlots.next(); - WeakHashMap set = toolboxSlotEntry.getValue(); - - for (Iterator> playerEntries = set.entrySet() - .iterator(); playerEntries.hasNext();) { - Entry playerEntry = playerEntries.next(); - - Player player = playerEntry.getKey(); - int hotbarSlot = playerEntry.getValue(); - - ToolboxHandler.unequip(player, hotbarSlot, false); - if (player instanceof ServerPlayer) - affected.add((ServerPlayer) player); - } - } - - for (ServerPlayer player : affected) - ToolboxHandler.syncData(player); - connectedPlayers.clear(); - } - - public void unequip(int slot, Player player, int hotbarSlot, boolean keepItems) { - if (!connectedPlayers.containsKey(slot)) - return; - connectedPlayers.get(slot) - .remove(player); - if (keepItems) - return; - - Inventory playerInv = player.getInventory(); - ItemStack playerStack = playerInv.getItem(hotbarSlot); - ItemStack toInsert = ToolboxInventory.cleanItemNBT(playerStack.copy()); - ItemStack remainder = inventory.distributeToCompartment(toInsert, slot, false); - - if (remainder.getCount() != toInsert.getCount()) - playerInv.setItem(hotbarSlot, remainder); - } - - private void tickAudio() { - Vec3 vec = VecHelper.getCenterOf(worldPosition); - if (lid.settled()) { - if (openCount > 0 && lid.getChaseTarget() == 0) { - level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 0.25F, - level.random.nextFloat() * 0.1F + 1.2F, true); - level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, 0.1F, - level.random.nextFloat() * 0.1F + 1.1F, true); - } - if (openCount == 0 && lid.getChaseTarget() == 1) - level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.1F, - level.random.nextFloat() * 0.1F + 1.1F, true); - - } else if (openCount == 0 && lid.getChaseTarget() == 0 && lid.getValue(0) > 1 / 16f - && lid.getValue(1) < 1 / 16f) - level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.25F, - level.random.nextFloat() * 0.1F + 1.2F, true); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return inventoryProvider.cast(); - return super.getCapability(cap, side); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - inventory.deserializeNBT(compound.getCompound("Inventory")); - super.read(compound, clientPacket); - if (compound.contains("UniqueId", 11)) - this.uniqueId = compound.getUUID("UniqueId"); - if (compound.contains("CustomName", 8)) - this.customName = Component.Serializer.fromJson(compound.getString("CustomName")); - if (clientPacket) - openCount = compound.getInt("OpenCount"); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - if (uniqueId == null) - uniqueId = UUID.randomUUID(); - - compound.put("Inventory", inventory.serializeNBT()); - compound.putUUID("UniqueId", uniqueId); - - if (customName != null) - compound.putString("CustomName", Component.Serializer.toJson(customName)); - super.write(compound, clientPacket); - if (clientPacket) - compound.putInt("OpenCount", openCount); - } - - @Override - public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { - return ToolboxContainer.create(id, inv, this); - } - - @Override - public void lazyTick() { - updateOpenCount(); - // keep re-advertising active TEs - ToolboxHandler.onLoad(this); - super.lazyTick(); - } - - void updateOpenCount() { - if (level.isClientSide) - return; - if (openCount == 0) - return; - - int prevOpenCount = openCount; - openCount = 0; - - for (Player playerentity : level.getEntitiesOfClass(Player.class, new AABB(worldPosition).inflate(8))) - if (playerentity.containerMenu instanceof ToolboxContainer - && ((ToolboxContainer) playerentity.containerMenu).contentHolder == this) - openCount++; - - if (prevOpenCount != openCount) - sendData(); - } - - public void startOpen(Player player) { - if (player.isSpectator()) - return; - if (openCount < 0) - openCount = 0; - openCount++; - sendData(); - } - - public void stopOpen(Player player) { - if (player.isSpectator()) - return; - openCount--; - sendData(); - } - - public void connectPlayer(int slot, Player player, int hotbarSlot) { - if (level.isClientSide) - return; - WeakHashMap map = connectedPlayers.computeIfAbsent(slot, WeakHashMap::new); - Integer previous = map.get(player); - if (previous != null) { - if (previous == hotbarSlot) - return; - ToolboxHandler.unequip(player, previous, false); - } - map.put(player, hotbarSlot); - } - - public void readInventory(CompoundTag compound) { - inventory.deserializeNBT(compound); - } - - public void setUniqueId(UUID uniqueId) { - this.uniqueId = uniqueId; - } - - public UUID getUniqueId() { - return uniqueId; - } - - public boolean isFullyInitialized() { - // returns true when uniqueId has been initialized - return uniqueId != null; - } - - public void setCustomName(Component customName) { - this.customName = customName; - } - - @Override - public Component getDisplayName() { - return customName != null ? customName - : AllBlocks.TOOLBOXES.get(getColor()) - .get() - .getName(); - } - - @Override - public Component getCustomName() { - return customName; - } - - @Override - public boolean hasCustomName() { - return customName != null; - } - - @Override - public Component getName() { - return customName; - } - - @SuppressWarnings("deprecation") - @Override - public void setBlockState(BlockState state) { - super.setBlockState(state); - colorProvider.reset(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java deleted file mode 100644 index ec87a05c66..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintAssignCompleteRecipePacket.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.simibubi.create.content.curiosities.tools; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent.Context; - -public class BlueprintAssignCompleteRecipePacket extends SimplePacketBase { - - private ResourceLocation recipeID; - - public BlueprintAssignCompleteRecipePacket(ResourceLocation recipeID) { - this.recipeID = recipeID; - } - - public BlueprintAssignCompleteRecipePacket(FriendlyByteBuf buffer) { - recipeID = buffer.readResourceLocation(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeResourceLocation(recipeID); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - if (player.containerMenu instanceof BlueprintContainer) { - BlueprintContainer c = (BlueprintContainer) player.containerMenu; - player.getLevel() - .getRecipeManager() - .byKey(recipeID) - .ifPresent(r -> BlueprintItem.assignCompleteRecipe(c.ghostInventory, r)); - } - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java deleted file mode 100644 index 78c43e52c2..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintContainer.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.simibubi.create.content.curiosities.tools; - -import java.util.Optional; - -import com.simibubi.create.AllContainerTypes; -import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; -import com.simibubi.create.foundation.gui.container.GhostItemContainer; - -import net.minecraft.client.Minecraft; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingRecipe; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class BlueprintContainer extends GhostItemContainer { - - public BlueprintContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public BlueprintContainer(MenuType type, int id, Inventory inv, BlueprintSection section) { - super(type, id, inv, section); - } - - public static BlueprintContainer create(int id, Inventory inv, BlueprintSection section) { - return new BlueprintContainer(AllContainerTypes.CRAFTING_BLUEPRINT.get(), id, inv, section); - } - - @Override - protected boolean allowRepeats() { - return true; - } - - @Override - protected void addSlots() { - addPlayerSlots(8, 131); - - int x = 29; - int y = 21; - int index = 0; - for (int row = 0; row < 3; ++row) - for (int col = 0; col < 3; ++col) - this.addSlot(new BlueprintCraftSlot(ghostInventory, index++, x + col * 18, y + row * 18)); - - addSlot(new BlueprintCraftSlot(ghostInventory, index++, 123, 40)); - addSlot(new SlotItemHandler(ghostInventory, index++, 135, 57)); - } - - public void onCraftMatrixChanged() { - if (contentHolder.getBlueprintWorld().isClientSide) - return; - - ServerPlayer serverplayerentity = (ServerPlayer) player; - CraftingContainer craftingInventory = new BlueprintCraftingInventory(this, ghostInventory); - Optional optional = player.getServer() - .getRecipeManager() - .getRecipeFor(RecipeType.CRAFTING, craftingInventory, player.getCommandSenderWorld()); - - if (!optional.isPresent()) { - if (ghostInventory.getStackInSlot(9) - .isEmpty()) - return; - if (!contentHolder.inferredIcon) - return; - - ghostInventory.setStackInSlot(9, ItemStack.EMPTY); - serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, ItemStack.EMPTY)); - contentHolder.inferredIcon = false; - return; - } - - CraftingRecipe icraftingrecipe = optional.get(); - ItemStack itemstack = icraftingrecipe.assemble(craftingInventory); - ghostInventory.setStackInSlot(9, itemstack); - contentHolder.inferredIcon = true; - ItemStack toSend = itemstack.copy(); - toSend.getOrCreateTag() - .putBoolean("InferredFromRecipe", true); - serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, toSend)); - } - - @Override - public void setItem(int slotId, int stateId, ItemStack stack) { - if (slotId == 36 + 9) { - if (stack.hasTag()) { - contentHolder.inferredIcon = stack.getTag() - .getBoolean("InferredFromRecipe"); - stack.getTag() - .remove("InferredFromRecipe"); - } else - contentHolder.inferredIcon = false; - } - super.setItem(slotId, stateId, stack); - } - - @Override - protected ItemStackHandler createGhostInventory() { - return contentHolder.getItems(); - } - - @Override - protected void initAndReadInventory(BlueprintSection contentHolder) { - super.initAndReadInventory(contentHolder); - } - - @Override - protected void saveData(BlueprintSection contentHolder) { - contentHolder.save(ghostInventory); - } - - @Override - @OnlyIn(Dist.CLIENT) - protected BlueprintSection createOnClient(FriendlyByteBuf extraData) { - int entityID = extraData.readVarInt(); - int section = extraData.readVarInt(); - Entity entityByID = Minecraft.getInstance().level.getEntity(entityID); - if (!(entityByID instanceof BlueprintEntity)) - return null; - BlueprintEntity blueprintEntity = (BlueprintEntity) entityByID; - BlueprintSection blueprintSection = blueprintEntity.getSection(section); - return blueprintSection; - } - - @Override - public boolean stillValid(Player player) { - return contentHolder != null && contentHolder.canPlayerUse(player); - } - - static class BlueprintCraftingInventory extends CraftingContainer { - - public BlueprintCraftingInventory(AbstractContainerMenu container, ItemStackHandler items) { - super(container, 3, 3); - for (int y = 0; y < 3; y++) { - for (int x = 0; x < 3; x++) { - ItemStack stack = items.getStackInSlot(y * 3 + x); - setItem(y * 3 + x, stack == null ? ItemStack.EMPTY : stack.copy()); - } - } - } - - } - - class BlueprintCraftSlot extends SlotItemHandler { - - private int index; - - public BlueprintCraftSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition) { - super(itemHandler, index, xPosition, yPosition); - this.index = index; - } - - @Override - public void setChanged() { - super.setChanged(); - if (index == 9 && hasItem() && !contentHolder.getBlueprintWorld().isClientSide) { - contentHolder.inferredIcon = false; - ServerPlayer serverplayerentity = (ServerPlayer) player; - serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, getItem())); - } - if (index < 9) - onCraftMatrixChanged(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java deleted file mode 100644 index cf57bd455a..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripInteractionPacket.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.simibubi.create.content.curiosities.tools; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ExtendoGripInteractionPacket extends SimplePacketBase { - - private InteractionHand interactionHand; - private int target; - private Vec3 specificPoint; - - public ExtendoGripInteractionPacket(Entity target) { - this(target, null); - } - - public ExtendoGripInteractionPacket(Entity target, InteractionHand hand) { - this(target, hand, null); - } - - public ExtendoGripInteractionPacket(Entity target, InteractionHand hand, Vec3 specificPoint) { - interactionHand = hand; - this.specificPoint = specificPoint; - this.target = target.getId(); - } - - public ExtendoGripInteractionPacket(FriendlyByteBuf buffer) { - target = buffer.readInt(); - int handId = buffer.readInt(); - interactionHand = handId == -1 ? null : InteractionHand.values()[handId]; - if (buffer.readBoolean()) - specificPoint = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(target); - buffer.writeInt(interactionHand == null ? -1 : interactionHand.ordinal()); - buffer.writeBoolean(specificPoint != null); - if (specificPoint != null) { - buffer.writeDouble(specificPoint.x); - buffer.writeDouble(specificPoint.y); - buffer.writeDouble(specificPoint.z); - } - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer sender = context.get() - .getSender(); - if (sender == null) - return; - Entity entityByID = sender.getLevel() - .getEntity(target); - if (entityByID != null && ExtendoGripItem.isHoldingExtendoGrip(sender)) { - double d = sender.getAttribute(ForgeMod.REACH_DISTANCE.get()) - .getValue(); - if (!sender.hasLineOfSight(entityByID)) - d -= 3; - d *= d; - if (sender.distanceToSqr(entityByID) > d) - return; - if (interactionHand == null) - sender.attack(entityByID); - else if (specificPoint == null) - sender.interactOn(entityByID, interactionHand); - else - entityByID.interactAt(sender, specificPoint, interactionHand); - } - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java deleted file mode 100644 index 4e1f6f1ab4..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItemRenderer.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.simibubi.create.content.curiosities.tools; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; -import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.Vec3; - -public class ExtendoGripItemRenderer extends CustomRenderedItemModelRenderer { - - private static final Vec3 rotationOffset = new Vec3(0, 1 / 2f, 1 / 2f); - private static final Vec3 cogRotationOffset = new Vec3(0, 1 / 16f, 0); - - @Override - protected void render(ItemStack stack, ExtendoGripModel model, PartialItemModelRenderer renderer, TransformType transformType, - PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - TransformStack stacker = TransformStack.cast(ms); - float animation = 0.25f; - boolean leftHand = transformType == TransformType.FIRST_PERSON_LEFT_HAND; - boolean rightHand = transformType == TransformType.FIRST_PERSON_RIGHT_HAND; - if (leftHand || rightHand) - animation = Mth.lerp(AnimationTickHolder.getPartialTicks(), - ExtendoGripRenderHandler.lastMainHandAnimation, - ExtendoGripRenderHandler.mainHandAnimation); - - animation = animation * animation * animation; - float extensionAngle = Mth.lerp(animation, 24f, 156f); - float halfAngle = extensionAngle / 2; - float oppositeAngle = 180 - extensionAngle; - - // grip - renderer.renderSolid(model.getOriginalModel(), light); - - // bits - ms.pushPose(); - ms.translate(0, 1 / 16f, -7 / 16f); - ms.scale(1, 1, 1 + animation); - ms.pushPose(); - stacker.rotateX(-halfAngle) - .translate(rotationOffset); - renderer.renderSolid(model.getPartial("thin_short"), light); - stacker.translateBack(rotationOffset); - - ms.translate(0, 5.5f / 16f, 0); - stacker.rotateX(-oppositeAngle) - .translate(rotationOffset); - renderer.renderSolid(model.getPartial("wide_long"), light); - stacker.translateBack(rotationOffset); - - ms.translate(0, 11 / 16f, 0); - stacker.rotateX(oppositeAngle) - .translate(rotationOffset); - ms.translate(0, 0.5f / 16f, 0); - renderer.renderSolid(model.getPartial("thin_short"), light); - stacker.translateBack(rotationOffset); - - ms.popPose(); - ms.pushPose(); - - stacker.rotateX(-180 + halfAngle) - .translate(rotationOffset); - renderer.renderSolid(model.getPartial("wide_short"), light); - stacker.translateBack(rotationOffset); - - ms.translate(0, 5.5f / 16f, 0); - stacker.rotateX(oppositeAngle) - .translate(rotationOffset); - renderer.renderSolid(model.getPartial("thin_long"), light); - stacker.translateBack(rotationOffset); - - ms.translate(0, 11 / 16f, 0); - stacker.rotateX(-oppositeAngle) - .translate(rotationOffset); - ms.translate(0, 0.5f / 16f, 0); - renderer.renderSolid(model.getPartial("wide_short"), light); - stacker.translateBack(rotationOffset); - - // hand - ms.translate(0, 5.5f / 16f, 0); - stacker.rotateX(180 - halfAngle) - .rotateY(180); - ms.translate(0, 0, -4 / 16f); - ms.scale(1, 1, 1 / (1 + animation)); - renderer.renderSolid((leftHand || rightHand) ? ExtendoGripRenderHandler.pose.get() - : AllBlockPartials.DEPLOYER_HAND_POINTING.get(), light); - ms.popPose(); - - ms.popPose(); - - // cog - ms.pushPose(); - float angle = AnimationTickHolder.getRenderTime() * -2; - if (leftHand || rightHand) - angle += 360 * animation; - angle %= 360; - stacker.translate(cogRotationOffset) - .rotateZ(angle) - .translateBack(cogRotationOffset); - renderer.renderSolid(model.getPartial("cog"), light); - ms.popPose(); - } - - @Override - public ExtendoGripModel createModel(BakedModel originalModel) { - return new ExtendoGripModel(originalModel); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripModel.java b/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripModel.java deleted file mode 100644 index d098158741..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.curiosities.tools; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class ExtendoGripModel extends CreateCustomRenderedItemModel { - - public ExtendoGripModel(BakedModel template) { - super(template, "extendo_grip"); - addPartials("cog", "thin_short", "wide_short", "thin_long", "wide_long"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonModel.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonModel.java deleted file mode 100644 index 12ed5200c0..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.curiosities.weapons; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class PotatoCannonModel extends CreateCustomRenderedItemModel { - - public PotatoCannonModel(BakedModel template) { - super(template, "potato_cannon"); - addPartials("cog"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java deleted file mode 100644 index e5a7384efe..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.simibubi.create.content.curiosities.zapper; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.network.NetworkEvent.Context; - -public abstract class ShootGadgetPacket extends SimplePacketBase { - - public Vec3 location; - public InteractionHand hand; - public boolean self; - - public ShootGadgetPacket(Vec3 location, InteractionHand hand, boolean self) { - this.location = location; - this.hand = hand; - this.self = self; - } - - public ShootGadgetPacket(FriendlyByteBuf buffer) { - hand = buffer.readBoolean() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - self = buffer.readBoolean(); - location = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); - readAdditional(buffer); - } - - public final void write(FriendlyByteBuf buffer) { - buffer.writeBoolean(hand == InteractionHand.MAIN_HAND); - buffer.writeBoolean(self); - buffer.writeDouble(location.x); - buffer.writeDouble(location.y); - buffer.writeDouble(location.z); - writeAdditional(buffer); - } - - protected abstract void readAdditional(FriendlyByteBuf buffer); - - protected abstract void writeAdditional(FriendlyByteBuf buffer); - - @OnlyIn(Dist.CLIENT) - protected abstract void handleAdditional(); - - @OnlyIn(Dist.CLIENT) - protected abstract ShootableGadgetRenderHandler getHandler(); - - @Override - @OnlyIn(Dist.CLIENT) - public final void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - Entity renderViewEntity = Minecraft.getInstance() - .getCameraEntity(); - if (renderViewEntity == null) - return; - if (renderViewEntity.position() - .distanceTo(location) > 100) - return; - - ShootableGadgetRenderHandler handler = getHandler(); - handleAdditional(); - if (self) - handler.shoot(hand, location); - else - handler.playSound(hand, location); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItemRenderer.java deleted file mode 100644 index 9986edd82d..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItemRenderer.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; - -import static java.lang.Math.max; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; -import com.simibubi.create.content.curiosities.zapper.ZapperItemRenderer; -import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.HumanoidArm; -import net.minecraft.world.item.ItemStack; - -public class WorldshaperItemRenderer extends ZapperItemRenderer { - - @Override - protected void render(ItemStack stack, WorldshaperModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, - PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - super.render(stack, model, renderer, transformType, ms, buffer, light, overlay); - - float pt = AnimationTickHolder.getPartialTicks(); - float worldTime = AnimationTickHolder.getRenderTime() / 20; - - renderer.renderSolid(model.getOriginalModel(), light); - - LocalPlayer player = Minecraft.getInstance().player; - boolean leftHanded = player.getMainArm() == HumanoidArm.LEFT; - boolean mainHand = player.getMainHandItem() == stack; - boolean offHand = player.getOffhandItem() == stack; - float animation = getAnimationProgress(pt, leftHanded, mainHand); - - // Core glows - float multiplier; - if (mainHand || offHand) - multiplier = animation; - else - multiplier = Mth.sin(worldTime * 5); - - int lightItensity = (int) (15 * Mth.clamp(multiplier, 0, 1)); - int glowLight = LightTexture.pack(lightItensity, max(lightItensity, 4)); - renderer.renderSolidGlowing(model.getPartial("core"), glowLight); - renderer.renderGlowing(model.getPartial("core_glow"), glowLight); - - // Accelerator spins - float angle = worldTime * -25; - if (mainHand || offHand) - angle += 360 * animation; - - angle %= 360; - float offset = -.155f; - ms.translate(0, offset, 0); - ms.mulPose(Vector3f.ZP.rotationDegrees(angle)); - ms.translate(0, -offset, 0); - renderer.render(model.getPartial("accelerator"), light); - } - - @Override - public WorldshaperModel createModel(BakedModel originalModel) { - return new WorldshaperModel(originalModel); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperModel.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperModel.java deleted file mode 100644 index 3253e3990b..0000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class WorldshaperModel extends CreateCustomRenderedItemModel { - - public WorldshaperModel(BakedModel template) { - super(template, "handheld_worldshaper"); - addPartials("core", "core_glow", "accelerator"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/MetalLadderBlock.java b/src/main/java/com/simibubi/create/content/decoration/MetalLadderBlock.java similarity index 92% rename from src/main/java/com/simibubi/create/content/curiosities/deco/MetalLadderBlock.java rename to src/main/java/com/simibubi/create/content/decoration/MetalLadderBlock.java index 82c150814a..13ba601da0 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/MetalLadderBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/MetalLadderBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration; import java.util.function.Predicate; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripItem; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementHelpers; @@ -90,7 +90,7 @@ public class MetalLadderBlock extends LadderBlock implements IWrenchable { BlockHitResult ray) { Direction dir = player.getXRot() < 0 ? Direction.UP : Direction.DOWN; - int range = AllConfigs.SERVER.curiosities.placementAssistRange.get(); + int range = AllConfigs.server().equipment.placementAssistRange.get(); if (player != null) { AttributeInstance reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get()); if (reach != null && reach.hasModifier(ExtendoGripItem.singleRangeAttributeModifier)) diff --git a/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlock.java b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlock.java new file mode 100644 index 0000000000..1b4549a554 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlock.java @@ -0,0 +1,88 @@ +package com.simibubi.create.content.decoration; + +import java.util.Random; + +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.ScaffoldingBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class MetalScaffoldingBlock extends ScaffoldingBlock implements IWrenchable { + + public MetalScaffoldingBlock(Properties pProperties) { + super(pProperties); + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRand) {} + + @Override + public boolean canSurvive(BlockState pState, LevelReader pLevel, BlockPos pPos) { + return true; + } + + @Override + public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, + CollisionContext pContext) { + if (pState.getValue(BOTTOM)) + return AllShapes.SCAFFOLD_HALF; + return super.getCollisionShape(pState, pLevel, pPos, pContext); + } + + @Override + public boolean isScaffolding(BlockState state, LevelReader level, BlockPos pos, LivingEntity entity) { + return true; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + if (pState.getValue(BOTTOM)) + return AllShapes.SCAFFOLD_HALF; + if (!pContext.isHoldingItem(pState.getBlock() + .asItem())) + return AllShapes.SCAFFOLD_FULL; + return Shapes.block(); + } + + @Override + public VoxelShape getInteractionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) { + return Shapes.block(); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel, + BlockPos pCurrentPos, BlockPos pFacingPos) { + super.updateShape(pState, pFacing, pFacingState, pLevel, pCurrentPos, pFacingPos); + BlockState stateBelow = pLevel.getBlockState(pCurrentPos.below()); + return pFacing == Direction.DOWN ? pState.setValue(BOTTOM, + !stateBelow.is(this) && !stateBelow.isFaceSturdy(pLevel, pCurrentPos.below(), Direction.UP)) : pState; + } + + @Override + public boolean supportsExternalFaceHiding(BlockState state) { + return true; + } + + @Override + public boolean hidesNeighborFace(BlockGetter level, BlockPos pos, BlockState state, BlockState neighborState, + Direction dir) { + if (!(neighborState.getBlock() instanceof MetalScaffoldingBlock)) + return false; + if (!neighborState.getValue(BOTTOM) && state.getValue(BOTTOM)) + return false; + return dir.getAxis() != Axis.Y; + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlockItem.java b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlockItem.java new file mode 100644 index 0000000000..481e001032 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingBlockItem.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.decoration; + +import javax.annotation.Nullable; + +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ScaffoldingBlockItem; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class MetalScaffoldingBlockItem extends ScaffoldingBlockItem { + + public MetalScaffoldingBlockItem(Block pBlock, Properties pProperties) { + super(pBlock, pProperties); + } + + @Nullable + public BlockPlaceContext updatePlacementContext(BlockPlaceContext pContext) { // TODO replace with placement helper + BlockPos blockpos = pContext.getClickedPos(); + Level level = pContext.getLevel(); + BlockState blockstate = level.getBlockState(blockpos); + Block block = this.getBlock(); + if (!blockstate.is(block)) + return pContext; + + Direction direction; + if (pContext.isSecondaryUseActive()) { + direction = pContext.isInside() ? pContext.getClickedFace() + .getOpposite() : pContext.getClickedFace(); + } else { + direction = pContext.getClickedFace() == Direction.UP ? pContext.getHorizontalDirection() : Direction.UP; + } + + int i = 0; + BlockPos.MutableBlockPos blockpos$mutableblockpos = blockpos.mutable() + .move(direction); + + while (i < 7) { + if (!level.isClientSide && !level.isInWorldBounds(blockpos$mutableblockpos)) { + Player player = pContext.getPlayer(); + int j = level.getMaxBuildHeight(); + if (player instanceof ServerPlayer && blockpos$mutableblockpos.getY() >= j) { + ((ServerPlayer) player).sendMessage( + (new TranslatableComponent("build.tooHigh", j - 1)).withStyle(ChatFormatting.RED), + ChatType.GAME_INFO, Util.NIL_UUID); + } + break; + } + + blockstate = level.getBlockState(blockpos$mutableblockpos); + if (!blockstate.is(this.getBlock())) { + if (blockstate.canBeReplaced(pContext)) { + return BlockPlaceContext.at(pContext, blockpos$mutableblockpos, direction); + } + break; + } + + blockpos$mutableblockpos.move(direction); + if (direction.getAxis() + .isHorizontal()) { + ++i; + } + } + + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingCTBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingCTBehaviour.java new file mode 100644 index 0000000000..a85e7d2e17 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/MetalScaffoldingCTBehaviour.java @@ -0,0 +1,50 @@ +package com.simibubi.create.content.decoration; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class MetalScaffoldingCTBehaviour extends HorizontalCTBehaviour { + + protected CTSpriteShiftEntry insideShift; + + public MetalScaffoldingCTBehaviour(CTSpriteShiftEntry outsideShift, CTSpriteShiftEntry insideShift, + CTSpriteShiftEntry topShift) { + super(outsideShift, topShift); + this.insideShift = insideShift; + } + + @Override + public boolean buildContextForOccludedDirections() { + return true; + } + + @Override + protected boolean isBeingBlocked(BlockState state, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, + Direction face) { + return face.getAxis() == Axis.Y && super.isBeingBlocked(state, reader, pos, otherPos, face); + } + + @Override + public CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite) { + if (direction.getAxis() != Axis.Y && sprite == insideShift.getOriginal()) + return insideShift; + return super.getShift(state, direction, sprite); + } + + @Override + public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, + BlockPos otherPos, Direction face) { + return super.connectsTo(state, other, reader, pos, otherPos, face) + && state.getValue(MetalScaffoldingBlock.BOTTOM) && other.getValue(MetalScaffoldingBlock.BOTTOM); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java b/src/main/java/com/simibubi/create/content/decoration/TrainTrapdoorBlock.java similarity index 88% rename from src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java rename to src/main/java/com/simibubi/create/content/decoration/TrainTrapdoorBlock.java index 7fbd3233b3..701866bb6f 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/TrainTrapdoorBlock.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -37,8 +37,10 @@ public class TrainTrapdoorBlock extends TrapDoorBlock implements IWrenchable { } public static boolean isConnected(BlockState state, BlockState other, Direction pDirection) { - state = state.setValue(WATERLOGGED, false); - other = other.setValue(WATERLOGGED, false); + state = state.setValue(WATERLOGGED, false) + .setValue(POWERED, false); + other = other.setValue(WATERLOGGED, false) + .setValue(POWERED, false); boolean open = state.getValue(OPEN); Half half = state.getValue(HALF); diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/TrapdoorCTBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/TrapdoorCTBehaviour.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/deco/TrapdoorCTBehaviour.java rename to src/main/java/com/simibubi/create/content/decoration/TrapdoorCTBehaviour.java index 8856fa52ec..1b1ea63cfb 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/TrapdoorCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/decoration/TrapdoorCTBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlock.java b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlock.java rename to src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlock.java index bf93122107..2eaafc0eda 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.decoration.bracket; import java.util.Optional; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.relays.elementary.AbstractSimpleShaftBlock; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.createmod.catnip.utility.lang.Lang; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlockItem.java b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlockItem.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlockItem.java rename to src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlockItem.java index 71cfe27551..18ecd15223 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketBlockItem.java +++ b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketBlockItem.java @@ -1,9 +1,8 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.decoration.bracket; import java.util.Optional; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -31,7 +30,7 @@ public class BracketBlockItem extends BlockItem { BracketBlock bracketBlock = getBracketBlock(); Player player = context.getPlayer(); - BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); + BracketedBlockEntityBehaviour behaviour = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); if (behaviour == null) return InteractionResult.FAIL; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketGenerator.java b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketGenerator.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketGenerator.java rename to src/main/java/com/simibubi/create/content/decoration/bracket/BracketGenerator.java index 4b11ad2c01..30a2b01426 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/BracketGenerator.java +++ b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.decoration.bracket; import com.simibubi.create.foundation.data.DirectionalAxisBlockStateGen; import com.tterrag.registrate.builders.ItemBuilder; diff --git a/src/main/java/com/simibubi/create/content/decoration/bracket/BracketedBlockEntityBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketedBlockEntityBehaviour.java new file mode 100644 index 0000000000..76f0db4cb5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/bracket/BracketedBlockEntityBehaviour.java @@ -0,0 +1,132 @@ +package com.simibubi.create.content.decoration.bracket; + +import java.util.function.Predicate; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class BracketedBlockEntityBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + private BlockState bracket; + private boolean reRender; + + private Predicate pred; + + public BracketedBlockEntityBehaviour(SmartBlockEntity be) { + this(be, state -> true); + } + + public BracketedBlockEntityBehaviour(SmartBlockEntity be, Predicate pred) { + super(be); + this.pred = pred; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + public void applyBracket(BlockState state) { + this.bracket = state; + reRender = true; + blockEntity.notifyUpdate(); + Level world = getWorld(); + if (world.isClientSide) + return; + blockEntity.getBlockState() + .updateNeighbourShapes(world, getPos(), 3); + } + + public void transformBracket(StructureTransform transform) { + if (isBracketPresent()) { + BlockState transformedBracket = transform.apply(bracket); + applyBracket(transformedBracket); + } + } + + @Nullable + public BlockState removeBracket(boolean inOnReplacedContext) { + if (bracket == null) { + return null; + } + + BlockState removed = this.bracket; + Level world = getWorld(); + if (!world.isClientSide) + world.levelEvent(2001, getPos(), Block.getId(bracket)); + this.bracket = null; + reRender = true; + if (inOnReplacedContext) { + blockEntity.sendData(); + return removed; + } + blockEntity.notifyUpdate(); + if (world.isClientSide) + return removed; + blockEntity.getBlockState() + .updateNeighbourShapes(world, getPos(), 3); + return removed; + } + + public boolean isBracketPresent() { + return bracket != null; + } + + @Nullable + public BlockState getBracket() { + return bracket; + } + + public boolean canHaveBracket() { + return pred.test(blockEntity.getBlockState()); + } + + @Override + public ItemRequirement getRequiredItems() { + if (!isBracketPresent()) { + return ItemRequirement.NONE; + } + return ItemRequirement.of(bracket, null); + } + + @Override + public boolean isSafeNBT() { + return true; + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + if (isBracketPresent()) { + nbt.put("Bracket", NbtUtils.writeBlockState(bracket)); + } + if (clientPacket && reRender) { + NBTHelper.putMarker(nbt, "Redraw"); + reRender = false; + } + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + if (nbt.contains("Bracket")) + bracket = NbtUtils.readBlockState(nbt.getCompound("Bracket")); + if (clientPacket && nbt.contains("Redraw")) + getWorld().sendBlockUpdated(getPos(), blockEntity.getBlockState(), blockEntity.getBlockState(), 16); + super.read(nbt, clientPacket); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBarsModel.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBarsModel.java new file mode 100644 index 0000000000..4469fe74a2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBarsModel.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.simibubi.create.foundation.model.BakedQuadHelper; + +import net.createmod.catnip.render.SpriteShiftEntry; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.IModelData; + +public class CopycatBarsModel extends CopycatModel { + + public CopycatBarsModel(BakedModel originalModel) { + super(originalModel); + } + + @Override + public boolean useAmbientOcclusion() { + return false; + } + + @Override + protected List getCroppedQuads(BlockState state, Direction side, Random rand, BlockState material, + IModelData wrappedData) { + BakedModel model = getModelOf(material); + List templateQuads = model.getQuads(material, null, rand, wrappedData); + List superQuads = originalModel.getQuads(state, side, rand, wrappedData); + List quads = new ArrayList<>(); + TextureAtlasSprite targetSprite = model.getParticleIcon(wrappedData); + + boolean vertical = state.getValue(CopycatPanelBlock.FACING) + .getAxis() == Axis.Y; + + if (side != null && (vertical || side.getAxis() == Axis.Y)) + for (int i = 0; i < templateQuads.size(); i++) { + BakedQuad quad = templateQuads.get(i); + if (quad.getDirection() != Direction.UP) + continue; + targetSprite = quad.getSprite(); + break; + } + + if (targetSprite == null) + return superQuads; + + for (int i = 0; i < superQuads.size(); i++) { + BakedQuad quad = superQuads.get(i); + TextureAtlasSprite original = quad.getSprite(); + BakedQuad newQuad = BakedQuadHelper.clone(quad); + int[] vertexData = newQuad.getVertices(); + for (int vertex = 0; vertex < 4; vertex++) { + BakedQuadHelper.setU(vertexData, vertex, targetSprite + .getU(SpriteShiftEntry.getUnInterpolatedU(original, BakedQuadHelper.getU(vertexData, vertex)))); + BakedQuadHelper.setV(vertexData, vertex, targetSprite + .getV(SpriteShiftEntry.getUnInterpolatedV(original, BakedQuadHelper.getV(vertexData, vertex)))); + } + quads.add(newQuad); + } + + return quads; + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlock.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlock.java new file mode 100644 index 0000000000..e464390495 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlock.java @@ -0,0 +1,385 @@ +package com.simibubi.create.content.decoration.copycat; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.color.block.BlockColor; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.SpawnPlacements.Type; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.GrassColor; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.StairBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class CopycatBlock extends Block implements IBE, IWrenchable { + + public CopycatBlock(Properties pProperties) { + super(pProperties); + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, + BlockEntityType p_153214_) { + return null; + } + + @Override + public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { + onWrenched(state, context); + return IWrenchable.super.onSneakWrenched(state, context); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return onBlockEntityUse(context.getLevel(), context.getClickedPos(), ufte -> { + ItemStack consumedItem = ufte.getConsumedItem(); + if (!ufte.hasCustomMaterial()) + return InteractionResult.PASS; + Player player = context.getPlayer(); + if (!player.isCreative()) + player.getInventory() + .placeItemBackInInventory(consumedItem); + context.getLevel() + .levelEvent(2001, context.getClickedPos(), Block.getId(ufte.getBlockState())); + ufte.setMaterial(AllBlocks.COPYCAT_BASE.getDefaultState()); + ufte.setConsumedItem(ItemStack.EMPTY); + return InteractionResult.SUCCESS; + }); + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + + if (pPlayer == null) + return InteractionResult.PASS; + + Direction face = pHit.getDirection(); + ItemStack itemInHand = pPlayer.getItemInHand(pHand); + BlockState materialIn = getAcceptedBlockState(pLevel, pPos, itemInHand, face); + + if (materialIn != null) + materialIn = prepareMaterial(pLevel, pPos, pState, pPlayer, pHand, pHit, materialIn); + if (materialIn == null) + return InteractionResult.PASS; + + BlockState material = materialIn; + return onBlockEntityUse(pLevel, pPos, ufte -> { + if (ufte.getMaterial() + .is(material.getBlock())) { + if (!ufte.cycleMaterial()) + return InteractionResult.PASS; + ufte.getLevel() + .playSound(null, ufte.getBlockPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .75f, + .95f); + return InteractionResult.SUCCESS; + } + if (ufte.hasCustomMaterial()) + return InteractionResult.PASS; + if (pLevel.isClientSide()) + return InteractionResult.SUCCESS; + + ufte.setMaterial(material); + ufte.setConsumedItem(itemInHand); + ufte.getLevel() + .playSound(null, ufte.getBlockPos(), material.getSoundType() + .getPlaceSound(), SoundSource.BLOCKS, 1, .75f); + + if (pPlayer.isCreative()) + return InteractionResult.SUCCESS; + + itemInHand.shrink(1); + if (itemInHand.isEmpty()) + pPlayer.setItemInHand(pHand, ItemStack.EMPTY); + return InteractionResult.SUCCESS; + }); + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + if (pPlacer == null) + return; + ItemStack offhandItem = pPlacer.getItemInHand(InteractionHand.OFF_HAND); + BlockState appliedState = + getAcceptedBlockState(pLevel, pPos, offhandItem, Direction.orderedByNearest(pPlacer)[0]); + + if (appliedState == null) + return; + withBlockEntityDo(pLevel, pPos, ufte -> { + if (ufte.hasCustomMaterial()) + return; + + ufte.setMaterial(appliedState); + ufte.setConsumedItem(offhandItem); + + if (pPlacer instanceof Player player && player.isCreative()) + return; + offhandItem.shrink(1); + if (offhandItem.isEmpty()) + pPlacer.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + }); + } + + @Nullable + public BlockState getAcceptedBlockState(Level pLevel, BlockPos pPos, ItemStack item, Direction face) { + if (!(item.getItem()instanceof BlockItem bi)) + return null; + + Block block = bi.getBlock(); + if (block instanceof CopycatBlock) + return null; + + BlockState appliedState = block.defaultBlockState(); + boolean hardCodedAllow = isAcceptedRegardless(appliedState); + + if (!AllBlockTags.COPYCAT_ALLOW.matches(block) && !hardCodedAllow) { + + if (AllBlockTags.COPYCAT_DENY.matches(block)) + return null; + if (block instanceof EntityBlock) + return null; + if (block instanceof StairBlock) + return null; + + if (pLevel != null) { + VoxelShape shape = appliedState.getShape(pLevel, pPos); + if (shape.isEmpty() || !shape.bounds() + .equals(Shapes.block() + .bounds())) + return null; + + VoxelShape collisionShape = appliedState.getCollisionShape(pLevel, pPos); + if (collisionShape.isEmpty()) + return null; + } + } + + if (face != null) { + Axis axis = face.getAxis(); + + if (appliedState.hasProperty(BlockStateProperties.FACING)) + appliedState = appliedState.setValue(BlockStateProperties.FACING, face); + if (appliedState.hasProperty(BlockStateProperties.HORIZONTAL_FACING) && axis != Axis.Y) + appliedState = appliedState.setValue(BlockStateProperties.HORIZONTAL_FACING, face); + if (appliedState.hasProperty(BlockStateProperties.AXIS)) + appliedState = appliedState.setValue(BlockStateProperties.AXIS, axis); + if (appliedState.hasProperty(BlockStateProperties.HORIZONTAL_AXIS) && axis != Axis.Y) + appliedState = appliedState.setValue(BlockStateProperties.HORIZONTAL_AXIS, axis); + } + + return appliedState; + } + + public boolean isAcceptedRegardless(BlockState material) { + return false; + } + + public BlockState prepareMaterial(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer, + InteractionHand pHand, BlockHitResult pHit, BlockState material) { + return material; + } + + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + if (!pState.hasBlockEntity() || pState.getBlock() == pNewState.getBlock()) + return; + if (!pIsMoving) + withBlockEntityDo(pLevel, pPos, ufte -> Block.popResource(pLevel, pPos, ufte.getConsumedItem())); + pLevel.removeBlockEntity(pPos); + } + + @Override + public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { + super.playerWillDestroy(pLevel, pPos, pState, pPlayer); + if (pPlayer.isCreative()) + withBlockEntityDo(pLevel, pPos, ufte -> ufte.setConsumedItem(ItemStack.EMPTY)); + } + + @Override + public Class getBlockEntityClass() { + return CopycatBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.COPYCAT.get(); + } + + // Connected Textures + + @Nullable + /** + * The wrapped blockstate at toPos. Wrapper guaranteed to be a block of this + * type
+ * Return null if the 'from' state shouldn't connect to this block/face + * + * @param from + * @param reader + * @param targetPos + * @param face + * @return + */ + public abstract BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face, + BlockPos fromPos, BlockPos toPos); + + public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + return false; + } + + public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + return false; + } + + public static BlockState getMaterial(BlockGetter reader, BlockPos targetPos) { + if (reader.getBlockEntity(targetPos) instanceof CopycatBlockEntity cbe) + return cbe.getMaterial(); + return Blocks.AIR.defaultBlockState(); + } + + public boolean canFaceBeOccluded(BlockState state, Direction face) { + return false; + } + + public boolean shouldFaceAlwaysRender(BlockState state, Direction face) { + return false; + } + + // Wrapped properties + + @Override + public SoundType getSoundType(BlockState state, LevelReader level, BlockPos pos, Entity entity) { + return getMaterial(level, pos).getSoundType(); + } + + @Override + public float getFriction(BlockState state, LevelReader level, BlockPos pos, Entity entity) { + return getMaterial(level, pos).getFriction(level, pos, entity); + } + + @Override + public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) { + return getMaterial(level, pos).getLightEmission(level, pos); + } + + @Override + public boolean canHarvestBlock(BlockState state, BlockGetter level, BlockPos pos, Player player) { + return getMaterial(level, pos).canHarvestBlock(level, pos, player); + } + + @Override + public float getExplosionResistance(BlockState state, BlockGetter level, BlockPos pos, Explosion explosion) { + return getMaterial(level, pos).getExplosionResistance(level, pos, explosion); + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, + Player player) { + BlockState material = getMaterial(level, pos); + if (AllBlocks.COPYCAT_BASE.has(material) || player != null && player.isSteppingCarefully()) + return new ItemStack(this); + return material.getCloneItemStack(target, level, pos, player); + } + + @Override + public boolean addLandingEffects(BlockState state1, ServerLevel level, BlockPos pos, BlockState state2, + LivingEntity entity, int numberOfParticles) { + return getMaterial(level, pos).addLandingEffects(level, pos, state2, entity, numberOfParticles); + } + + @Override + public boolean addRunningEffects(BlockState state, Level level, BlockPos pos, Entity entity) { + return getMaterial(level, pos).addRunningEffects(level, pos, entity); + } + + @Override + public float getEnchantPowerBonus(BlockState state, LevelReader level, BlockPos pos) { + return getMaterial(level, pos).getEnchantPowerBonus(level, pos); + } + + @Override + public boolean canEntityDestroy(BlockState state, BlockGetter level, BlockPos pos, Entity entity) { + return getMaterial(level, pos).canEntityDestroy(level, pos, entity); + } + + @Override + public boolean isValidSpawn(BlockState state, BlockGetter level, BlockPos pos, Type type, + EntityType entityType) { + return false; + } + + @Override + public void fallOn(Level pLevel, BlockState pState, BlockPos pPos, Entity pEntity, float p_152430_) { + BlockState material = getMaterial(pLevel, pPos); + material.getBlock() + .fallOn(pLevel, material, pPos, pEntity, p_152430_); + } + + @Override + public float getDestroyProgress(BlockState pState, Player pPlayer, BlockGetter pLevel, BlockPos pPos) { + return getMaterial(pLevel, pPos).getDestroyProgress(pPlayer, pLevel, pPos); + } + + // + + @OnlyIn(Dist.CLIENT) + public static BlockColor wrappedColor() { + return new WrappedBlockColor(); + } + + @OnlyIn(Dist.CLIENT) + public static class WrappedBlockColor implements BlockColor { + + @Override + public int getColor(BlockState pState, @Nullable BlockAndTintGetter pLevel, @Nullable BlockPos pPos, + int pTintIndex) { + if (pLevel == null || pPos == null) + return GrassColor.get(0.5D, 1.0D); + return Minecraft.getInstance() + .getBlockColors() + .getColor(getMaterial(pLevel, pPos), pLevel, pPos, pTintIndex); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlockEntity.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlockEntity.java new file mode 100644 index 0000000000..b766050e00 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatBlockEntity.java @@ -0,0 +1,195 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.redstone.RoseQuartzLampBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockEntityItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.IPartialSafeNBT; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap; +import net.minecraftforge.items.ItemHandlerHelper; + +public class CopycatBlockEntity extends SmartBlockEntity + implements ISpecialBlockEntityItemRequirement, ITransformableBlockEntity, IPartialSafeNBT { + + private BlockState material; + private ItemStack consumedItem; + + public CopycatBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + material = AllBlocks.COPYCAT_BASE.getDefaultState(); + consumedItem = ItemStack.EMPTY; + } + + public BlockState getMaterial() { + return material; + } + + public boolean hasCustomMaterial() { + return !AllBlocks.COPYCAT_BASE.has(getMaterial()); + } + + public void setMaterial(BlockState blockState) { + BlockState wrapperState = getBlockState(); + + if (!material.is(blockState.getBlock())) + for (Direction side : Iterate.directions) { + BlockPos neighbour = worldPosition.relative(side); + BlockState neighbourState = level.getBlockState(neighbour); + if (neighbourState != wrapperState) + continue; + if (!(level.getBlockEntity(neighbour)instanceof CopycatBlockEntity cbe)) + continue; + BlockState otherMaterial = cbe.getMaterial(); + if (!otherMaterial.is(blockState.getBlock())) + continue; + blockState = otherMaterial; + break; + } + + material = blockState; + if (!level.isClientSide()) { + notifyUpdate(); + return; + } + redraw(); + } + + public boolean cycleMaterial() { + if (material.hasProperty(TrapDoorBlock.HALF) && material.getOptionalValue(TrapDoorBlock.OPEN) + .orElse(false)) + setMaterial(material.cycle(TrapDoorBlock.HALF)); + else if (material.hasProperty(BlockStateProperties.FACING)) + setMaterial(material.cycle(BlockStateProperties.FACING)); + else if (material.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) + setMaterial(material.setValue(BlockStateProperties.HORIZONTAL_FACING, + material.getValue(BlockStateProperties.HORIZONTAL_FACING) + .getClockWise())); + else if (material.hasProperty(BlockStateProperties.AXIS)) + setMaterial(material.cycle(BlockStateProperties.AXIS)); + else if (material.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) + setMaterial(material.cycle(BlockStateProperties.HORIZONTAL_AXIS)); + else if (material.hasProperty(BlockStateProperties.LIT)) + setMaterial(material.cycle(BlockStateProperties.LIT)); + else if (material.hasProperty(RoseQuartzLampBlock.POWERING)) + setMaterial(material.cycle(RoseQuartzLampBlock.POWERING)); + else + return false; + + return true; + } + + public ItemStack getConsumedItem() { + return consumedItem; + } + + public void setConsumedItem(ItemStack stack) { + consumedItem = ItemHandlerHelper.copyStackWithSize(stack, 1); + setChanged(); + } + + private void redraw() { + if (!isVirtual()) + requestModelDataUpdate(); + if (hasLevel()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + level.getChunkSource() + .getLightEngine() + .checkBlock(worldPosition); + } + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public ItemRequirement getRequiredItems(BlockState state) { + if (consumedItem.isEmpty()) + return ItemRequirement.NONE; + return new ItemRequirement(ItemUseType.CONSUME, consumedItem); + } + + @Override + public void transform(StructureTransform transform) { + material = transform.apply(material); + notifyUpdate(); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + + consumedItem = ItemStack.of(tag.getCompound("Item")); + + BlockState prevMaterial = material; + if (!tag.contains("Material")) { + consumedItem = ItemStack.EMPTY; + return; + } + + material = NbtUtils.readBlockState(tag.getCompound("Material")); + + // Validate Material + if (material != null && !clientPacket) { + BlockState blockState = getBlockState(); + if (blockState == null) + return; + if (!(blockState.getBlock() instanceof CopycatBlock cb)) + return; + BlockState acceptedBlockState = cb.getAcceptedBlockState(level, worldPosition, consumedItem, null); + if (acceptedBlockState != null && material.is(acceptedBlockState.getBlock())) + return; + consumedItem = ItemStack.EMPTY; + material = AllBlocks.COPYCAT_BASE.getDefaultState(); + } + + if (clientPacket && prevMaterial != material) + redraw(); + } + + @Override + public void writeSafe(CompoundTag tag) { + super.writeSafe(tag); + + ItemStack stackWithoutNBT = consumedItem.copy(); + stackWithoutNBT.setTag(null); + + write(tag, stackWithoutNBT, material); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + write(tag, consumedItem, material); + } + + protected void write(CompoundTag tag, ItemStack stack, BlockState material) { + tag.put("Item", stack.serializeNBT()); + tag.put("Material", NbtUtils.writeBlockState(material)); + } + + @Override + public IModelData getModelData() { + return new ModelDataMap.Builder().withInitial(CopycatModel.MATERIAL_PROPERTY, material) + .build(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatModel.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatModel.java new file mode 100644 index 0000000000..f9ec91e6a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatModel.java @@ -0,0 +1,163 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.model.BakedModelWrapperWithData; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap.Builder; +import net.minecraftforge.client.model.data.ModelProperty; + +public abstract class CopycatModel extends BakedModelWrapperWithData { + + public static final ModelProperty MATERIAL_PROPERTY = new ModelProperty<>(); + private static final ModelProperty OCCLUSION_PROPERTY = new ModelProperty<>(); + private static final ModelProperty WRAPPED_DATA_PROPERTY = new ModelProperty<>(); + + public CopycatModel(BakedModel originalModel) { + super(originalModel); + } + + @Override + protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, + IModelData blockEntityData) { + BlockState material = getMaterial(blockEntityData); + if (material == null) + return; + + builder.withInitial(MATERIAL_PROPERTY, material); + + OcclusionData occlusionData = new OcclusionData(); + if (state.getBlock() instanceof CopycatBlock copycatBlock) { + gatherOcclusionData(world, pos, state, material, occlusionData, copycatBlock); + builder.withInitial(OCCLUSION_PROPERTY, occlusionData); + } + + IModelData wrappedData = getModelOf(material).getModelData(world, pos, material, EmptyModelData.INSTANCE); + builder.withInitial(WRAPPED_DATA_PROPERTY, wrappedData); + } + + private void gatherOcclusionData(BlockAndTintGetter world, BlockPos pos, BlockState state, BlockState material, + OcclusionData occlusionData, CopycatBlock copycatBlock) { + MutableBlockPos mutablePos = new MutableBlockPos(); + for (Direction face : Iterate.directions) { + + // Rubidium: Run an additional IForgeBlock.hidesNeighborFace check because it + // seems to be missing in Block.shouldRenderFace + MutableBlockPos neighbourPos = mutablePos.setWithOffset(pos, face); + BlockState neighbourState = world.getBlockState(neighbourPos); + if (state.supportsExternalFaceHiding() + && neighbourState.hidesNeighborFace(world, neighbourPos, state, face.getOpposite())) { + occlusionData.occlude(face); + continue; + } + + if (!copycatBlock.canFaceBeOccluded(state, face)) + continue; + if (!Block.shouldRenderFace(material, world, pos, face, neighbourPos)) + occlusionData.occlude(face); + } + } + + @Override + public List getQuads(BlockState state, Direction side, Random rand, IModelData data) { + + // Rubidium: see below + if (side != null && state.getBlock() instanceof CopycatBlock ccb && ccb.shouldFaceAlwaysRender(state, side)) + return Collections.emptyList(); + + BlockState material = getMaterial(data); + + if (material == null) + return super.getQuads(state, side, rand, data); + + OcclusionData occlusionData = data.getData(OCCLUSION_PROPERTY); + if (occlusionData != null && occlusionData.isOccluded(side)) + return super.getQuads(state, side, rand, data); + + RenderType renderType = MinecraftForgeClient.getRenderType(); + if (renderType != null && !ItemBlockRenderTypes.canRenderInLayer(material, renderType)) + return super.getQuads(state, side, rand, data); + + IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY); + if (wrappedData == null) + wrappedData = EmptyModelData.INSTANCE; + + List croppedQuads = getCroppedQuads(state, side, rand, material, wrappedData); + + // Rubidium: render side!=null versions of the base material during side==null, + // to avoid getting culled away + if (side == null && state.getBlock() instanceof CopycatBlock ccb) + for (Direction nonOcclusionSide : Iterate.directions) + if (ccb.shouldFaceAlwaysRender(state, nonOcclusionSide)) + croppedQuads.addAll(getCroppedQuads(state, nonOcclusionSide, rand, material, wrappedData)); + + return croppedQuads; + } + + protected abstract List getCroppedQuads(BlockState state, Direction side, Random rand, + BlockState material, IModelData wrappedData); + + @Override + public TextureAtlasSprite getParticleIcon(IModelData data) { + BlockState material = getMaterial(data); + + if (material == null) + return super.getParticleIcon(data); + + IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY); + if (wrappedData == null) + wrappedData = EmptyModelData.INSTANCE; + + return getModelOf(material).getParticleIcon(wrappedData); + } + + @Nullable + public static BlockState getMaterial(IModelData data) { + BlockState material = data.getData(MATERIAL_PROPERTY); + return material == null ? AllBlocks.COPYCAT_BASE.getDefaultState() : material; + } + + public static BakedModel getModelOf(BlockState state) { + return Minecraft.getInstance() + .getBlockRenderer() + .getBlockModel(state); + } + + private static class OcclusionData { + private final boolean[] occluded; + + public OcclusionData() { + occluded = new boolean[6]; + } + + public void occlude(Direction face) { + occluded[face.get3DDataValue()] = true; + } + + public boolean isOccluded(Direction face) { + return face == null ? false : occluded[face.get3DDataValue()]; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelBlock.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelBlock.java new file mode 100644 index 0000000000..99f35ee451 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelBlock.java @@ -0,0 +1,243 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.List; +import java.util.function.Predicate; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllShapes; + +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.createmod.catnip.utility.placement.PlacementOffset; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class CopycatPanelBlock extends WaterloggedCopycatBlock { + + public static final DirectionProperty FACING = BlockStateProperties.FACING; + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public CopycatPanelBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(FACING, Direction.UP)); + } + + @Override + public boolean isAcceptedRegardless(BlockState material) { + return CopycatSpecialCases.isBarsMaterial(material) || CopycatSpecialCases.isTrapdoorMaterial(material); + } + + @Override + public BlockState prepareMaterial(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer, + InteractionHand pHand, BlockHitResult pHit, BlockState material) { + if (!CopycatSpecialCases.isTrapdoorMaterial(material)) + return super.prepareMaterial(pLevel, pPos, pState, pPlayer, pHand, pHit, material); + + Direction panelFacing = pState.getValue(FACING); + if (panelFacing == Direction.DOWN) + material = material.setValue(TrapDoorBlock.HALF, Half.TOP); + if (panelFacing.getAxis() == Axis.Y) + return material.setValue(TrapDoorBlock.FACING, pPlayer.getDirection()) + .setValue(TrapDoorBlock.OPEN, false); + + boolean clickedNearTop = pHit.getLocation().y - .5 > pPos.getY(); + return material.setValue(TrapDoorBlock.OPEN, true) + .setValue(TrapDoorBlock.HALF, clickedNearTop ? Half.TOP : Half.BOTTOM) + .setValue(TrapDoorBlock.FACING, panelFacing); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + + if (!player.isShiftKeyDown() && player.mayBuild()) { + ItemStack heldItem = player.getItemInHand(hand); + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (placementHelper.matchesItem(heldItem)) { + placementHelper.getOffset(player, world, state, pos, ray) + .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return InteractionResult.SUCCESS; + } + } + + return super.use(state, world, pos, player, hand, ray); + } + + @Override + public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + return true; + } + + @Override + public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + Direction facing = state.getValue(FACING); + BlockState toState = reader.getBlockState(toPos); + + if (!toState.is(this)) + return facing != face.getOpposite(); + + BlockPos diff = fromPos.subtract(toPos); + int coord = facing.getAxis() + .choose(diff.getX(), diff.getY(), diff.getZ()); + return facing == toState.getValue(FACING) + .getOpposite() + && !(coord != 0 && coord == facing.getAxisDirection() + .getStep()); + } + + @Override + public boolean canFaceBeOccluded(BlockState state, Direction face) { + return state.getValue(FACING) + .getOpposite() == face; + } + + @Override + public boolean shouldFaceAlwaysRender(BlockState state, Direction face) { + return canFaceBeOccluded(state, face.getOpposite()); + } + + @Override + public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face, + BlockPos fromPos, BlockPos toPos) { + BlockState panelState = reader.getBlockState(toPos); + Direction facing = panelState.getValue(FACING); + + if (!otherState.is(this)) + return facing == face.getOpposite() ? getMaterial(reader, toPos) : null; + + if (isOccluded(panelState, otherState, facing)) + return getMaterial(reader, toPos); + + BlockPos diff = fromPos.subtract(toPos); + int coord = facing.getAxis() + .choose(diff.getX(), diff.getY(), diff.getZ()); + + if (otherState.setValue(WATERLOGGED, false) == panelState.setValue(WATERLOGGED, false) && coord == 0) + return getMaterial(reader, toPos); + + return null; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + BlockState stateForPlacement = super.getStateForPlacement(pContext); + return stateForPlacement.setValue(FACING, pContext.getNearestLookingDirection() + .getOpposite()); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(FACING)); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return AllShapes.CASING_3PX.get(pState.getValue(FACING)); + } + + @Override + public boolean isPathfindable(BlockState pState, BlockGetter pLevel, BlockPos pPos, PathComputationType pType) { + return false; + } + + @Override + public boolean supportsExternalFaceHiding(BlockState state) { + return true; + } + + @Override + public boolean hidesNeighborFace(BlockGetter level, BlockPos pos, BlockState state, BlockState neighborState, + Direction dir) { + if (state.is(this) == neighborState.is(this)) { + if (CopycatSpecialCases.isBarsMaterial(getMaterial(level, pos)) + && CopycatSpecialCases.isBarsMaterial(getMaterial(level, pos.relative(dir)))) + return state.getValue(FACING) == neighborState.getValue(FACING); + if (getMaterial(level, pos).skipRendering(getMaterial(level, pos.relative(dir)), dir.getOpposite())) + return isOccluded(state, neighborState, dir.getOpposite()); + } + + return state.getValue(FACING) == dir.getOpposite() + && getMaterial(level, pos).skipRendering(neighborState, dir.getOpposite()); + } + + public static boolean isOccluded(BlockState state, BlockState other, Direction pDirection) { + state = state.setValue(WATERLOGGED, false); + other = other.setValue(WATERLOGGED, false); + Direction facing = state.getValue(FACING); + if (facing.getOpposite() == other.getValue(FACING) && pDirection == facing) + return true; + if (other.getValue(FACING) != facing) + return false; + return pDirection.getAxis() != facing.getAxis(); + } + + @Override + public BlockState rotate(BlockState state, Rotation rot) { + return state.setValue(FACING, rot.rotate(state.getValue(FACING))); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState mirror(BlockState state, Mirror mirrorIn) { + return state.rotate(mirrorIn.getRotation(state.getValue(FACING))); + } + + @MethodsReturnNonnullByDefault + private static class PlacementHelper implements IPlacementHelper { + @Override + public Predicate getItemPredicate() { + return AllBlocks.COPYCAT_PANEL::isIn; + } + + @Override + public Predicate getStatePredicate() { + return AllBlocks.COPYCAT_PANEL::has; + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, + BlockHitResult ray) { + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), + state.getValue(FACING) + .getAxis(), + dir -> world.getBlockState(pos.relative(dir)) + .getMaterial() + .isReplaceable()); + + if (directions.isEmpty()) + return PlacementOffset.fail(); + else { + return PlacementOffset.success(pos.relative(directions.get(0)), + s -> s.setValue(FACING, state.getValue(FACING))); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelModel.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelModel.java new file mode 100644 index 0000000000..ac6a698917 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatPanelModel.java @@ -0,0 +1,89 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.model.BakedModelHelper; +import com.simibubi.create.foundation.model.BakedQuadHelper; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.DirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.data.IModelData; + +public class CopycatPanelModel extends CopycatModel { + + protected static final AABB CUBE_AABB = new AABB(BlockPos.ZERO); + + public CopycatPanelModel(BakedModel originalModel) { + super(originalModel); + } + + @Override + protected List getCroppedQuads(BlockState state, Direction side, Random rand, BlockState material, + IModelData wrappedData) { + Direction facing = state.getOptionalValue(CopycatPanelBlock.FACING) + .orElse(Direction.UP); + BlockRenderDispatcher blockRenderer = Minecraft.getInstance() + .getBlockRenderer(); + + BlockState specialCopycatModelState = null; + if (CopycatSpecialCases.isBarsMaterial(material)) + specialCopycatModelState = AllBlocks.COPYCAT_BARS.getDefaultState(); + if (CopycatSpecialCases.isTrapdoorMaterial(material)) + return blockRenderer.getBlockModel(material) + .getQuads(material, side, rand, wrappedData); + + if (specialCopycatModelState != null) { + BakedModel blockModel = blockRenderer + .getBlockModel(specialCopycatModelState.setValue(DirectionalBlock.FACING, facing)); + if (blockModel instanceof CopycatModel cm) + return cm.getCroppedQuads(state, side, rand, material, wrappedData); + } + + BakedModel model = getModelOf(material); + List templateQuads = model.getQuads(material, side, rand, wrappedData); + int size = templateQuads.size(); + + List quads = new ArrayList<>(); + + Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal()); + Vec3 normalScaled14 = normal.scale(14 / 16f); + + // 2 Pieces + for (boolean front : Iterate.trueAndFalse) { + Vec3 normalScaledN13 = normal.scale(front ? 0 : -13 / 16f); + float contract = 16 - (front ? 1 : 2); + AABB bb = CUBE_AABB.contract(normal.x * contract / 16, normal.y * contract / 16, normal.z * contract / 16); + if (!front) + bb = bb.move(normalScaled14); + + for (int i = 0; i < size; i++) { + BakedQuad quad = templateQuads.get(i); + Direction direction = quad.getDirection(); + + if (front && direction == facing) + continue; + if (!front && direction == facing.getOpposite()) + continue; + + quads.add(BakedQuadHelper.cloneWithCustomGeometry(quad, + BakedModelHelper.cropAndMove(quad.getVertices(), quad.getSprite(), bb, normalScaledN13))); + } + + } + + return quads; + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatSpecialCases.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatSpecialCases.java new file mode 100644 index 0000000000..a7ba28e3d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatSpecialCases.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.decoration.copycat; + +import com.simibubi.create.content.decoration.palettes.GlassPaneBlock; + +import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.StainedGlassPaneBlock; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.state.BlockState; + +public class CopycatSpecialCases { + + public static boolean isBarsMaterial(BlockState material) { + return material.getBlock() instanceof IronBarsBlock && !(material.getBlock() instanceof GlassPaneBlock) + && !(material.getBlock() instanceof StainedGlassPaneBlock); + } + + public static boolean isTrapdoorMaterial(BlockState material) { + return material.getBlock() instanceof TrapDoorBlock && material.hasProperty(TrapDoorBlock.HALF) + && material.hasProperty(TrapDoorBlock.OPEN) && material.hasProperty(TrapDoorBlock.FACING); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepBlock.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepBlock.java new file mode 100644 index 0000000000..7fb4353a25 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepBlock.java @@ -0,0 +1,231 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.function.Predicate; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllShapes; +import com.simibubi.create.foundation.placement.PoleHelper; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VoxelShaper; +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class CopycatStepBlock extends WaterloggedCopycatBlock { + + public static final EnumProperty HALF = BlockStateProperties.HALF; + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public CopycatStepBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(HALF, Half.BOTTOM) + .setValue(FACING, Direction.SOUTH)); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + + if (!player.isShiftKeyDown() && player.mayBuild()) { + ItemStack heldItem = player.getItemInHand(hand); + IPlacementHelper helper = PlacementHelpers.get(placementHelperId); + if (helper.matchesItem(heldItem)) + return helper.getOffset(player, world, state, pos, ray) + .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + } + + return super.use(state, world, pos, player, hand, ray); + } + + @Override + public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face, + BlockPos fromPos, BlockPos toPos) { + if (!otherState.is(this)) + return null; + + BlockState stepState = reader.getBlockState(toPos); + Direction facing = stepState.getValue(FACING); + BlockPos diff = fromPos.subtract(toPos); + + if (diff.getY() != 0) { + if (isOccluded(stepState, otherState, diff.getY() > 0 ? Direction.UP : Direction.DOWN)) + return getMaterial(reader, toPos); + return null; + } + + if (isOccluded(stepState, otherState, facing)) + return getMaterial(reader, toPos); + + int coord = facing.getAxis() + .choose(diff.getX(), diff.getY(), diff.getZ()); + + if (otherState.setValue(WATERLOGGED, false) == stepState.setValue(WATERLOGGED, false) && coord == 0) + return getMaterial(reader, toPos); + + return null; + } + + @Override + public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + return true; + } + + @Override + public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face, + BlockPos fromPos, BlockPos toPos) { + BlockState toState = reader.getBlockState(toPos); + + if (!toState.is(this)) { + if (!canFaceBeOccluded(state, face.getOpposite())) + return true; + for (Direction d : Iterate.directions) + if (fromPos.relative(d) + .equals(toPos) && !canFaceBeOccluded(state, d)) + return true; + return false; + } + + Direction facing = state.getValue(FACING); + BlockPos diff = fromPos.subtract(toPos); + int coord = facing.getAxis() + .choose(diff.getX(), diff.getY(), diff.getZ()); + + Half half = state.getValue(HALF); + if (half != toState.getValue(HALF)) + return diff.getY() == 0; + + return facing == toState.getValue(FACING) + .getOpposite() + && !(coord != 0 && coord != facing.getAxisDirection() + .getStep()); + } + + @Override + public boolean canFaceBeOccluded(BlockState state, Direction face) { + if (face.getAxis() == Axis.Y) + return (state.getValue(HALF) == Half.TOP) == (face == Direction.UP); + return state.getValue(FACING) == face; + } + + @Override + public boolean shouldFaceAlwaysRender(BlockState state, Direction face) { + return canFaceBeOccluded(state, face.getOpposite()); + } + + @Override + public boolean isPathfindable(BlockState pState, BlockGetter pLevel, BlockPos pPos, PathComputationType pType) { + return false; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + BlockState stateForPlacement = + super.getStateForPlacement(pContext).setValue(FACING, pContext.getHorizontalDirection()); + Direction direction = pContext.getClickedFace(); + if (direction == Direction.UP) + return stateForPlacement; + if (direction == Direction.DOWN || (pContext.getClickLocation().y - pContext.getClickedPos() + .getY() > 0.5D)) + return stateForPlacement.setValue(HALF, Half.TOP); + return stateForPlacement; + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(HALF, FACING)); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + VoxelShaper voxelShaper = pState.getValue(HALF) == Half.BOTTOM ? AllShapes.STEP_BOTTOM : AllShapes.STEP_TOP; + return voxelShaper.get(pState.getValue(FACING)); + } + + @Override + public boolean supportsExternalFaceHiding(BlockState state) { + return true; + } + + @Override + public boolean hidesNeighborFace(BlockGetter level, BlockPos pos, BlockState state, BlockState neighborState, + Direction dir) { + if (state.is(this) == neighborState.is(this) + && getMaterial(level, pos).skipRendering(getMaterial(level, pos.relative(dir)), dir.getOpposite())) + return isOccluded(state, neighborState, dir); + return false; + } + + public static boolean isOccluded(BlockState state, BlockState other, Direction pDirection) { + state = state.setValue(WATERLOGGED, false); + other = other.setValue(WATERLOGGED, false); + + Half half = state.getValue(HALF); + boolean vertical = pDirection.getAxis() == Axis.Y; + if (half != other.getValue(HALF)) + return vertical && (pDirection == Direction.UP) == (half == Half.TOP); + if (vertical) + return false; + + Direction facing = state.getValue(FACING); + if (facing.getOpposite() == other.getValue(FACING) && pDirection == facing) + return true; + if (other.getValue(FACING) != facing) + return false; + return pDirection.getAxis() != facing.getAxis(); + } + + @Override + public BlockState rotate(BlockState pState, Rotation pRot) { + return pState.setValue(FACING, pRot.rotate(pState.getValue(FACING))); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState mirror(BlockState pState, Mirror pMirror) { + return pState.rotate(pMirror.getRotation(pState.getValue(FACING))); + } + + private static class PlacementHelper extends PoleHelper { + + public PlacementHelper() { + super(AllBlocks.COPYCAT_STEP::has, state -> state.getValue(FACING) + .getClockWise() + .getAxis(), FACING); + } + + @Override + public Predicate getItemPredicate() { + return AllBlocks.COPYCAT_STEP::isIn; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepModel.java b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepModel.java new file mode 100644 index 0000000000..3e815c955f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/CopycatStepModel.java @@ -0,0 +1,90 @@ +package com.simibubi.create.content.decoration.copycat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.simibubi.create.foundation.model.BakedModelHelper; +import com.simibubi.create.foundation.model.BakedQuadHelper; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.data.IModelData; + +public class CopycatStepModel extends CopycatModel { + + protected static final Vec3 VEC_Y_3 = new Vec3(0, .75, 0); + protected static final Vec3 VEC_Y_2 = new Vec3(0, .5, 0); + protected static final Vec3 VEC_Y_N2 = new Vec3(0, -.5, 0); + protected static final AABB CUBE_AABB = new AABB(BlockPos.ZERO); + + public CopycatStepModel(BakedModel originalModel) { + super(originalModel); + } + + @Override + protected List getCroppedQuads(BlockState state, Direction side, Random rand, BlockState material, + IModelData wrappedData) { + Direction facing = state.getOptionalValue(CopycatStepBlock.FACING) + .orElse(Direction.SOUTH); + boolean upperHalf = state.getOptionalValue(CopycatStepBlock.HALF) + .orElse(Half.BOTTOM) == Half.TOP; + + BakedModel model = getModelOf(material); + List templateQuads = model.getQuads(material, side, rand, wrappedData); + int size = templateQuads.size(); + + List quads = new ArrayList<>(); + + Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal()); + Vec3 normalScaled2 = normal.scale(.5); + Vec3 normalScaledN3 = normal.scale(-.75); + AABB bb = CUBE_AABB.contract(-normal.x * .75, .75, -normal.z * .75); + + // 4 Pieces + for (boolean top : Iterate.trueAndFalse) { + for (boolean front : Iterate.trueAndFalse) { + + AABB bb1 = bb; + if (front) + bb1 = bb1.move(normalScaledN3); + if (top) + bb1 = bb1.move(VEC_Y_3); + + Vec3 offset = Vec3.ZERO; + if (front) + offset = offset.add(normalScaled2); + if (top != upperHalf) + offset = offset.add(upperHalf ? VEC_Y_2 : VEC_Y_N2); + + for (int i = 0; i < size; i++) { + BakedQuad quad = templateQuads.get(i); + Direction direction = quad.getDirection(); + + if (front && direction == facing) + continue; + if (!front && direction == facing.getOpposite()) + continue; + if (!top && direction == Direction.UP) + continue; + if (top && direction == Direction.DOWN) + continue; + + quads.add(BakedQuadHelper.cloneWithCustomGeometry(quad, + BakedModelHelper.cropAndMove(quad.getVertices(), quad.getSprite(), bb1, offset))); + } + + } + } + + return quads; + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/SpecialCopycatPanelBlockState.java b/src/main/java/com/simibubi/create/content/decoration/copycat/SpecialCopycatPanelBlockState.java new file mode 100644 index 0000000000..3cf375ace1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/SpecialCopycatPanelBlockState.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.decoration.copycat; + +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.DirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.generators.BlockModelProvider; +import net.minecraftforge.client.model.generators.ModelFile; + +public class SpecialCopycatPanelBlockState extends SpecialBlockStateGen { + + private String name; + + public SpecialCopycatPanelBlockState(String name) { + this.name = name; + } + + @Override + protected int getXRotation(BlockState state) { + return facing(state) == Direction.UP ? 0 : facing(state) == Direction.DOWN ? 180 : 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(facing(state)); + } + + private Direction facing(BlockState state) { + return state.getValue(DirectionalBlock.FACING); + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + BlockModelProvider models = prov.models(); + return facing(state).getAxis() == Axis.Y + ? models.getExistingFile(prov.modLoc("block/copycat_panel/" + name + "_vertical")) + : models.getExistingFile(prov.modLoc("block/copycat_panel/" + name)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/decoration/copycat/WaterloggedCopycatBlock.java b/src/main/java/com/simibubi/create/content/decoration/copycat/WaterloggedCopycatBlock.java new file mode 100644 index 0000000000..a82f162abf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/copycat/WaterloggedCopycatBlock.java @@ -0,0 +1,43 @@ +package com.simibubi.create.content.decoration.copycat; + +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.material.FluidState; + +public abstract class WaterloggedCopycatBlock extends CopycatBlock implements ProperWaterloggedBlock { + + public WaterloggedCopycatBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(WATERLOGGED)); + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + return withWater(super.getStateForPlacement(pContext), pContext); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/CasingBlock.java b/src/main/java/com/simibubi/create/content/decoration/encasing/CasingBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/base/CasingBlock.java rename to src/main/java/com/simibubi/create/content/decoration/encasing/CasingBlock.java index b774a12cb6..547fb4df62 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/CasingBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/CasingBlock.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.decoration.encasing; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.minecraft.core.NonNullList; import net.minecraft.world.InteractionResult; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/CasingConnectivity.java b/src/main/java/com/simibubi/create/content/decoration/encasing/CasingConnectivity.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/relays/encased/CasingConnectivity.java rename to src/main/java/com/simibubi/create/content/decoration/encasing/CasingConnectivity.java index d352617138..04405ac914 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/CasingConnectivity.java +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/CasingConnectivity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.encased; +package com.simibubi.create.content.decoration.encasing; import java.util.IdentityHashMap; import java.util.Map; diff --git a/src/main/java/com/simibubi/create/content/decoration/encasing/EncasableBlock.java b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasableBlock.java new file mode 100644 index 0000000000..6c31ae78c1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasableBlock.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.decoration.encasing; + +import java.util.List; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +/** + * Implement this interface to indicate that this block is encasable. + */ +public interface EncasableBlock { + /** + * This method should be called in the {@link Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)} method. + */ + default InteractionResult tryEncase(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand, + BlockHitResult ray) { + List encasedVariants = EncasingRegistry.getVariants(state.getBlock()); + for (Block block : encasedVariants) { + if (block instanceof EncasedBlock encased) { + if (encased.getCasing().asItem() != heldItem.getItem()) + continue; + + if (level.isClientSide) + return InteractionResult.SUCCESS; + + encased.handleEncasing(state, level, pos, heldItem, player, hand, ray); + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; + } +} diff --git a/src/main/java/com/simibubi/create/content/decoration/encasing/EncasedBlock.java b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasedBlock.java new file mode 100644 index 0000000000..acaca578d3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasedBlock.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.decoration.encasing; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +/** + * Implement this interface to indicate that this block is encased. + */ +public interface EncasedBlock { + Block getCasing(); + + /** + * Handles how encasing should be done if {@link EncasableBlock#tryEncase(BlockState, Level, BlockPos, ItemStack, Player, InteractionHand, BlockHitResult)} is successful. + */ + default void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand, BlockHitResult ray) { + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCTBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasedCTBehaviour.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCTBehaviour.java rename to src/main/java/com/simibubi/create/content/decoration/encasing/EncasedCTBehaviour.java index 9afdaacb95..7c3d046bda 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasedCTBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.encased; +package com.simibubi.create.content.decoration.encasing; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/decoration/encasing/EncasingRegistry.java b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasingRegistry.java new file mode 100644 index 0000000000..c33ae383d3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/encasing/EncasingRegistry.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.decoration.encasing; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import com.tterrag.registrate.builders.BlockBuilder; +import com.tterrag.registrate.util.nullness.NonNullUnaryOperator; + +import net.minecraft.core.Registry; +import net.minecraft.world.level.block.Block; + +public class EncasingRegistry { + private static final Map> ENCASED_VARIANTS = new HashMap<>(); + + /** + * This method must not be called before block registration is finished. + */ + public static void addVariant(B encasable, E encased) { + ENCASED_VARIANTS.computeIfAbsent(encasable, b -> new ArrayList<>()).add(encased); + } + + public static List getVariants(Block block) { + return ENCASED_VARIANTS.getOrDefault(block, Collections.emptyList()); + } + + public static NonNullUnaryOperator> addVariantTo(Supplier encasable) { + return builder -> { + builder.onRegisterAfter(Registry.BLOCK_REGISTRY, b -> addVariant(encasable.get(), b)); + return builder; + }; + } +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java b/src/main/java/com/simibubi/create/content/decoration/girder/ConnectedGirderModel.java similarity index 77% rename from src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java rename to src/main/java/com/simibubi/create/content/decoration/girder/ConnectedGirderModel.java index 5fe648575a..7c1eb1f1b6 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/ConnectedGirderModel.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.block.connected.CTModel; import net.createmod.catnip.utility.Iterate; @@ -21,18 +21,20 @@ import net.minecraftforge.client.model.data.ModelProperty; public class ConnectedGirderModel extends CTModel { - protected static ModelProperty CONNECTION_PROPERTY = new ModelProperty<>(); + protected static final ModelProperty CONNECTION_PROPERTY = new ModelProperty<>(); public ConnectedGirderModel(BakedModel originalModel) { super(originalModel, new GirderCTBehaviour()); } @Override - protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) { + protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, + IModelData blockEntityData) { + super.gatherModelData(builder, world, pos, state, blockEntityData); ConnectionData connectionData = new ConnectionData(); for (Direction d : Iterate.horizontalDirections) connectionData.setConnected(d, GirderBlock.isConnected(world, pos, state, d)); - return super.gatherModelData(builder, world, pos, state).withInitial(CONNECTION_PROPERTY, connectionData); + builder.withInitial(CONNECTION_PROPERTY, connectionData); } @Override @@ -44,13 +46,13 @@ public class ConnectedGirderModel extends CTModel { ConnectionData data = extraData.getData(CONNECTION_PROPERTY); for (Direction d : Iterate.horizontalDirections) if (data.isConnected(d)) - quads.addAll(AllBlockPartials.METAL_GIRDER_BRACKETS.get(d) + quads.addAll(AllPartialModels.METAL_GIRDER_BRACKETS.get(d) .get() .getQuads(state, side, rand, extraData)); return quads; } - private class ConnectionData { + private static class ConnectionData { boolean[] connectedFaces; public ConnectionData() { diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderBlock.java similarity index 92% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderBlock.java index eb9fe907eb..72ccf18943 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import static net.minecraft.world.level.block.FaceAttachedHorizontalDirectionalBlock.FACE; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; @@ -8,17 +8,18 @@ import java.util.Random; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.curiosities.deco.PlacardBlock; -import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlock; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackShape; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.decoration.bracket.BracketBlock; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.decoration.placard.PlacardBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.logistics.chute.AbstractChuteBlock; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlock; +import com.simibubi.create.content.trains.display.FlapDisplayBlock; +import com.simibubi.create.content.trains.track.TrackBlock; +import com.simibubi.create.content.trains.track.TrackShape; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.placement.IPlacementHelper; @@ -103,7 +104,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc ItemStack itemInHand = pPlayer.getItemInHand(pHand); if (AllBlocks.SHAFT.isIn(itemInHand)) { - KineticTileEntity.switchToBlockState(pLevel, pPos, AllBlocks.METAL_GIRDER_ENCASED_SHAFT.getDefaultState() + KineticBlockEntity.switchToBlockState(pLevel, pPos, AllBlocks.METAL_GIRDER_ENCASED_SHAFT.getDefaultState() .setValue(WATERLOGGED, pState.getValue(WATERLOGGED)) .setValue(TOP, pState.getValue(TOP)) .setValue(BOTTOM, pState.getValue(BOTTOM)) @@ -224,7 +225,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc for (Direction d2 : Iterate.directionsInAxis(axis == Axis.X ? Axis.Z : Axis.X)) { BlockState above = level.getBlockState(pos.above() .relative(d2)); - if (AllBlocks.TRACK.has(above)) { + if (AllTags.AllBlockTags.GIRDABLE_TRACKS.matches(above)) { TrackShape shape = above.getValue(TrackBlock.SHAPE); if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO)) state = state.setValue(updateProperty, true); @@ -236,9 +237,9 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc public static boolean isFacingBracket(BlockAndTintGetter level, BlockPos pos, Direction d) { BlockEntity blockEntity = level.getBlockEntity(pos.relative(d)); - if (!(blockEntity instanceof SmartTileEntity ste)) + if (!(blockEntity instanceof SmartBlockEntity sbe)) return false; - BracketedTileEntityBehaviour behaviour = ste.getBehaviour(BracketedTileEntityBehaviour.TYPE); + BracketedBlockEntityBehaviour behaviour = sbe.getBehaviour(BracketedBlockEntityBehaviour.TYPE); if (behaviour == null) return false; BlockState bracket = behaviour.getBracket(); diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlockStateGenerator.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderBlockStateGenerator.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlockStateGenerator.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderBlockStateGenerator.java index affde64b4f..ea857c9388 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlockStateGenerator.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderBlockStateGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import com.simibubi.create.foundation.data.AssetLookup; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderCTBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderCTBehaviour.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderCTBehaviour.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderCTBehaviour.java index 31eb029c18..55d09ea61d 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderCTBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderEncasedShaftBlock.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderEncasedShaftBlock.java similarity index 77% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderEncasedShaftBlock.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderEncasedShaftBlock.java index ae514be8f9..4a46cae8f7 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderEncasedShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderEncasedShaftBlock.java @@ -1,14 +1,16 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -22,6 +24,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition.Builder; @@ -34,13 +37,17 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; public class GirderEncasedShaftBlock extends HorizontalAxisKineticBlock - implements ITE, SimpleWaterloggedBlock, IWrenchable { + implements IBE, SimpleWaterloggedBlock, IWrenchable, ISpecialBlockItemRequirement { public static final BooleanProperty TOP = GirderBlock.TOP; public static final BooleanProperty BOTTOM = GirderBlock.BOTTOM; public GirderEncasedShaftBlock(Properties properties) { super(properties); + registerDefaultState(super.defaultBlockState() + .setValue(WATERLOGGED, false) + .setValue(TOP, false) + .setValue(BOTTOM, false)); } @Override @@ -81,13 +88,13 @@ public class GirderEncasedShaftBlock extends HorizontalAxisKineticBlock } @Override - public Class getTileEntityClass() { - return KineticTileEntity.class; + public Class getBlockEntityClass() { + return KineticBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ENCASED_SHAFT.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ENCASED_SHAFT.get(); } @Override @@ -123,4 +130,10 @@ public class GirderEncasedShaftBlock extends HorizontalAxisKineticBlock return state.setValue(WATERLOGGED, Boolean.valueOf(ifluidstate.getType() == Fluids.WATER)); } + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement.of(AllBlocks.SHAFT.getDefaultState(), be) + .union(ItemRequirement.of(AllBlocks.METAL_GIRDER.getDefaultState(), be)); + } + } diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderPlacementHelper.java similarity index 93% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderPlacementHelper.java index 0f2e26c364..7a06fa8c19 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderPlacementHelper.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import java.util.List; import java.util.function.Predicate; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripItem; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementOffset; @@ -79,7 +79,7 @@ public class GirderPlacementHelper implements IPlacementHelper { List directions = IPlacementHelper.orderedByDistance(pos, ray.getLocation(), dir -> canExtendToward(state, dir)); for (Direction dir : directions) { - int range = AllConfigs.SERVER.curiosities.placementAssistRange.get(); + int range = AllConfigs.server().equipment.placementAssistRange.get(); if (player != null) { AttributeInstance reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get()); if (reach != null && reach.hasModifier(ExtendoGripItem.singleRangeAttributeModifier)) diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderWrenchBehavior.java b/src/main/java/com/simibubi/create/content/decoration/girder/GirderWrenchBehavior.java similarity index 99% rename from src/main/java/com/simibubi/create/content/curiosities/girder/GirderWrenchBehavior.java rename to src/main/java/com/simibubi/create/content/decoration/girder/GirderWrenchBehavior.java index 9b35c0a954..bdddcb54c8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderWrenchBehavior.java +++ b/src/main/java/com/simibubi/create/content/decoration/girder/GirderWrenchBehavior.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.girder; +package com.simibubi.create.content.decoration.girder; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/com/simibubi/create/content/palettes/AllPaletteBlocks.java b/src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteBlocks.java similarity index 93% rename from src/main/java/com/simibubi/create/content/palettes/AllPaletteBlocks.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteBlocks.java index 228a820b42..6c5f948195 100644 --- a/src/main/java/com/simibubi/create/content/palettes/AllPaletteBlocks.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteBlocks.java @@ -1,5 +1,6 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; +import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.foundation.data.WindowGen.customWindowBlock; import static com.simibubi.create.foundation.data.WindowGen.customWindowPane; import static com.simibubi.create.foundation.data.WindowGen.framedGlass; @@ -7,13 +8,12 @@ import static com.simibubi.create.foundation.data.WindowGen.framedGlassPane; import static com.simibubi.create.foundation.data.WindowGen.woodenWindowBlock; import static com.simibubi.create.foundation.data.WindowGen.woodenWindowPane; +import com.simibubi.create.AllCreativeModeTabs; import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.Create; -import com.simibubi.create.content.AllSections; import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour; import com.simibubi.create.foundation.block.connected.SimpleCTBehaviour; import com.simibubi.create.foundation.data.BlockStateGen; -import com.simibubi.create.foundation.data.CreateRegistrate; import com.simibubi.create.foundation.data.WindowGen; import com.tterrag.registrate.util.DataIngredient; import com.tterrag.registrate.util.entry.BlockEntry; @@ -30,9 +30,9 @@ import net.minecraftforge.common.Tags; public class AllPaletteBlocks { - private static final CreateRegistrate REGISTRATE = Create.registrate() - .creativeModeTab(() -> Create.PALETTES_CREATIVE_TAB) - .startSection(AllSections.PALETTES); + static { + REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.PALETTES_CREATIVE_TAB); + } // Windows and Glass diff --git a/src/main/java/com/simibubi/create/content/palettes/AllPaletteStoneTypes.java b/src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteStoneTypes.java similarity index 86% rename from src/main/java/com/simibubi/create/content/palettes/AllPaletteStoneTypes.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteStoneTypes.java index aeebf7d03e..95ccaba2cd 100644 --- a/src/main/java/com/simibubi/create/content/palettes/AllPaletteStoneTypes.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/AllPaletteStoneTypes.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; -import static com.simibubi.create.content.palettes.PaletteBlockPattern.STANDARD_RANGE; -import static com.simibubi.create.content.palettes.PaletteBlockPattern.VANILLA_RANGE; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPattern.STANDARD_RANGE; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPattern.VANILLA_RANGE; import java.util.function.Function; @@ -28,35 +28,35 @@ public enum AllPaletteStoneTypes { DEEPSLATE(VANILLA_RANGE, r -> () -> Blocks.DEEPSLATE), TUFF(VANILLA_RANGE, r -> () -> Blocks.TUFF), - ASURINE(STANDARD_RANGE, r -> r.paletteStoneBlock("asurine", () -> Blocks.DEEPSLATE, true) + ASURINE(STANDARD_RANGE, r -> r.paletteStoneBlock("asurine", () -> Blocks.DEEPSLATE, true, true) .properties(p -> p.destroyTime(1.25f) .color(MaterialColor.COLOR_BLUE)) .register()), - CRIMSITE(STANDARD_RANGE, r -> r.paletteStoneBlock("crimsite", () -> Blocks.DEEPSLATE, true) + CRIMSITE(STANDARD_RANGE, r -> r.paletteStoneBlock("crimsite", () -> Blocks.DEEPSLATE, true, true) .properties(p -> p.destroyTime(1.25f) .color(MaterialColor.COLOR_RED)) .register()), - LIMESTONE(STANDARD_RANGE, r -> r.paletteStoneBlock("limestone", () -> Blocks.SANDSTONE, true) + LIMESTONE(STANDARD_RANGE, r -> r.paletteStoneBlock("limestone", () -> Blocks.SANDSTONE, true, false) .properties(p -> p.destroyTime(1.25f) .color(MaterialColor.SAND)) .register()), - OCHRUM(STANDARD_RANGE, r -> r.paletteStoneBlock("ochrum", () -> Blocks.CALCITE, true) + OCHRUM(STANDARD_RANGE, r -> r.paletteStoneBlock("ochrum", () -> Blocks.CALCITE, true, true) .properties(p -> p.destroyTime(1.25f) .color(MaterialColor.TERRACOTTA_YELLOW)) .register()), - SCORIA(STANDARD_RANGE, r -> r.paletteStoneBlock("scoria", () -> Blocks.BLACKSTONE, true) + SCORIA(STANDARD_RANGE, r -> r.paletteStoneBlock("scoria", () -> Blocks.BLACKSTONE, true, false) .properties(p -> p.color(MaterialColor.COLOR_BROWN)) .register()), - SCORCHIA(STANDARD_RANGE, r -> r.paletteStoneBlock("scorchia", () -> Blocks.BLACKSTONE, true) + SCORCHIA(STANDARD_RANGE, r -> r.paletteStoneBlock("scorchia", () -> Blocks.BLACKSTONE, true, false) .properties(p -> p.color(MaterialColor.TERRACOTTA_GRAY)) .register()), - VERIDIUM(STANDARD_RANGE, r -> r.paletteStoneBlock("veridium", () -> Blocks.TUFF, true) + VERIDIUM(STANDARD_RANGE, r -> r.paletteStoneBlock("veridium", () -> Blocks.TUFF, true, true) .properties(p -> p.destroyTime(1.25f) .color(MaterialColor.WARPED_NYLIUM)) .register()) diff --git a/src/main/java/com/simibubi/create/content/palettes/ConnectedGlassBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassBlock.java similarity index 94% rename from src/main/java/com/simibubi/create/content/palettes/ConnectedGlassBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassBlock.java index d961a0aff9..3781375458 100644 --- a/src/main/java/com/simibubi/create/content/palettes/ConnectedGlassBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/palettes/ConnectedGlassPaneBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassPaneBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/palettes/ConnectedGlassPaneBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassPaneBlock.java index e789ac5151..8a67e55f6b 100644 --- a/src/main/java/com/simibubi/create/content/palettes/ConnectedGlassPaneBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedGlassPaneBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; diff --git a/src/main/java/com/simibubi/create/content/palettes/ConnectedPillarBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedPillarBlock.java similarity index 99% rename from src/main/java/com/simibubi/create/content/palettes/ConnectedPillarBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedPillarBlock.java index 1f5be362a7..2a48196f5a 100644 --- a/src/main/java/com/simibubi/create/content/palettes/ConnectedPillarBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/ConnectedPillarBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import java.util.Random; diff --git a/src/main/java/com/simibubi/create/content/palettes/GlassPaneBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/GlassPaneBlock.java similarity index 75% rename from src/main/java/com/simibubi/create/content/palettes/GlassPaneBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/GlassPaneBlock.java index ce07f4aeec..b9e1f6bc57 100644 --- a/src/main/java/com/simibubi/create/content/palettes/GlassPaneBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/GlassPaneBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import net.minecraft.world.level.block.IronBarsBlock; diff --git a/src/main/java/com/simibubi/create/content/palettes/LayeredBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/LayeredBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/palettes/LayeredBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/LayeredBlock.java index e2f84ef33e..8bc7f63e90 100644 --- a/src/main/java/com/simibubi/create/content/palettes/LayeredBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/LayeredBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.block.RotatedPillarBlock; diff --git a/src/main/java/com/simibubi/create/content/palettes/PaletteBlockPartial.java b/src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPartial.java similarity index 96% rename from src/main/java/com/simibubi/create/content/palettes/PaletteBlockPartial.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPartial.java index 2190e039cb..dda14e6f92 100644 --- a/src/main/java/com/simibubi/create/content/palettes/PaletteBlockPartial.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPartial.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; -import static com.simibubi.create.AllTags.pickaxeOnly; +import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly; import java.util.Arrays; import java.util.function.Supplier; @@ -54,7 +54,7 @@ public abstract class PaletteBlockPartial { String patternName = Lang.nonPluralId(pattern.createName(variantName)); String blockName = patternName + "_" + this.name; - BlockBuilder blockBuilder = Create.registrate() + BlockBuilder blockBuilder = Create.REGISTRATE .block(blockName, p -> createBlock(block)) .blockstate((c, p) -> generateBlockState(c, p, variantName, pattern, block)) .recipe((c, p) -> createRecipes(variant, block, c, p)) @@ -135,7 +135,6 @@ public abstract class PaletteBlockPartial { DataGenContext c, RegistrateRecipeProvider p) { p.stairs(DataIngredient.items(patternBlock), c::get, c.getName(), false); p.stonecutting(DataIngredient.tag(type.materialTag), c::get, 1); - p.stonecutting(DataIngredient.items(type.getBaseBlock()), c::get, 1); } } @@ -198,7 +197,6 @@ public abstract class PaletteBlockPartial { DataGenContext c, RegistrateRecipeProvider p) { p.slab(DataIngredient.items(patternBlock), c::get, c.getName(), false); p.stonecutting(DataIngredient.tag(type.materialTag), c::get, 2); - p.stonecutting(DataIngredient.items(type.getBaseBlock()), c::get, 2); DataIngredient ingredient = DataIngredient.items(c.get()); ShapelessRecipeBuilder.shapeless(patternBlock.get()) .requires(ingredient) @@ -255,7 +253,6 @@ public abstract class PaletteBlockPartial { protected void createRecipes(AllPaletteStoneTypes type, BlockEntry patternBlock, DataGenContext c, RegistrateRecipeProvider p) { p.stonecutting(DataIngredient.tag(type.materialTag), c::get, 1); - p.stonecutting(DataIngredient.items(type.getBaseBlock()), c::get, 1); DataIngredient ingredient = DataIngredient.items(patternBlock); ShapedRecipeBuilder.shaped(c.get(), 6) .pattern("XXX") diff --git a/src/main/java/com/simibubi/create/content/palettes/PaletteBlockPattern.java b/src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPattern.java similarity index 93% rename from src/main/java/com/simibubi/create/content/palettes/PaletteBlockPattern.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPattern.java index 00e02d1722..7010c2fc77 100644 --- a/src/main/java/com/simibubi/create/content/palettes/PaletteBlockPattern.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/PaletteBlockPattern.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; -import static com.simibubi.create.content.palettes.PaletteBlockPartial.ALL_PARTIALS; -import static com.simibubi.create.content.palettes.PaletteBlockPartial.FOR_POLISHED; -import static com.simibubi.create.content.palettes.PaletteBlockPattern.PatternNameType.PREFIX; -import static com.simibubi.create.content.palettes.PaletteBlockPattern.PatternNameType.SUFFIX; -import static com.simibubi.create.content.palettes.PaletteBlockPattern.PatternNameType.WRAP; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPartial.ALL_PARTIALS; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPartial.FOR_POLISHED; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPattern.PatternNameType.PREFIX; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPattern.PatternNameType.SUFFIX; +import static com.simibubi.create.content.decoration.palettes.PaletteBlockPattern.PatternNameType.WRAP; import java.util.Optional; import java.util.function.Function; @@ -21,7 +21,6 @@ import com.simibubi.create.foundation.block.connected.RotatedPillarCTBehaviour; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; import com.tterrag.registrate.providers.RegistrateRecipeProvider; -import com.tterrag.registrate.util.DataIngredient; import com.tterrag.registrate.util.nullness.NonNullBiConsumer; import com.tterrag.registrate.util.nullness.NonNullFunction; import com.tterrag.registrate.util.nullness.NonNullSupplier; @@ -129,7 +128,6 @@ public class PaletteBlockPattern { public void addRecipes(NonNullSupplier baseBlock, DataGenContext c, RegistrateRecipeProvider p) { - p.stonecutting(DataIngredient.items(baseBlock), c::get); additionalRecipes.apply(baseBlock) .accept(c, p); } diff --git a/src/main/java/com/simibubi/create/content/decoration/palettes/PalettesCreativeModeTab.java b/src/main/java/com/simibubi/create/content/decoration/palettes/PalettesCreativeModeTab.java new file mode 100644 index 0000000000..d267cacfb8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/PalettesCreativeModeTab.java @@ -0,0 +1,21 @@ +package com.simibubi.create.content.decoration.palettes; + +import com.simibubi.create.infrastructure.item.CreateCreativeModeTab; + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; + +public class PalettesCreativeModeTab extends CreateCreativeModeTab { + public PalettesCreativeModeTab() { + super("palettes"); + } + + @Override + public void addItems(NonNullList items, boolean specialItems) { + } + + @Override + public ItemStack makeIcon() { + return AllPaletteBlocks.ORNATE_IRON_WINDOW.asStack(); + } +} diff --git a/src/main/java/com/simibubi/create/content/palettes/PalettesVariantEntry.java b/src/main/java/com/simibubi/create/content/decoration/palettes/PalettesVariantEntry.java similarity index 82% rename from src/main/java/com/simibubi/create/content/palettes/PalettesVariantEntry.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/PalettesVariantEntry.java index 7718428e54..e4758718ee 100644 --- a/src/main/java/com/simibubi/create/content/palettes/PalettesVariantEntry.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/PalettesVariantEntry.java @@ -1,13 +1,15 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; -import static com.simibubi.create.AllTags.pickaxeOnly; +import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; +import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly; import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; import com.simibubi.create.foundation.data.CreateRegistrate; import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.builders.ItemBuilder; +import com.tterrag.registrate.providers.ProviderType; import com.tterrag.registrate.util.DataIngredient; import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.nullness.NonNullSupplier; @@ -26,12 +28,11 @@ public class PalettesVariantEntry { public PalettesVariantEntry(String name, AllPaletteStoneTypes paletteStoneVariants) { ImmutableList.Builder> registeredBlocks = ImmutableList.builder(); ImmutableList.Builder> registeredPartials = ImmutableList.builder(); - CreateRegistrate registrate = Create.registrate(); NonNullSupplier baseBlock = paletteStoneVariants.baseBlock; for (PaletteBlockPattern pattern : paletteStoneVariants.variantTypes) { BlockBuilder builder = - registrate.block(pattern.createName(name), pattern.getBlockFactory()) + REGISTRATE.block(pattern.createName(name), pattern.getBlockFactory()) .initialProperties(baseBlock) .transform(pickaxeOnly()) .blockstate(pattern.getBlockStateGenerator() @@ -69,6 +70,12 @@ public class PalettesVariantEntry { .register()); } + Create.REGISTRATE.addDataGenerator(ProviderType.RECIPE, + p -> p.stonecutting(DataIngredient.tag(paletteStoneVariants.materialTag), baseBlock)); + Create.REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, p -> p.tag(paletteStoneVariants.materialTag) + .add(baseBlock.get() + .asItem())); + this.registeredBlocks = registeredBlocks.build(); this.registeredPartials = registeredPartials.build(); } diff --git a/src/main/java/com/simibubi/create/content/palettes/WindowBlock.java b/src/main/java/com/simibubi/create/content/decoration/palettes/WindowBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/palettes/WindowBlock.java rename to src/main/java/com/simibubi/create/content/decoration/palettes/WindowBlock.java index 54018f9a5a..0b02bbf561 100644 --- a/src/main/java/com/simibubi/create/content/palettes/WindowBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/palettes/WindowBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.palettes; +package com.simibubi.create.content.decoration.palettes; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardBlock.java b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java similarity index 86% rename from src/main/java/com/simibubi/create/content/curiosities/deco/PlacardBlock.java rename to src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java index 18b47c8483..4b7012c4de 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlock.java @@ -1,17 +1,17 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration.placard; import java.util.List; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.minecraft.core.BlockPos; @@ -43,7 +43,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.items.ItemHandlerHelper; public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock - implements ProperWaterloggedBlock, ITE, ISpecialBlockItemRequirement, IWrenchable { + implements ProperWaterloggedBlock, IBE, ISpecialBlockItemRequirement, IWrenchable { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -122,7 +122,7 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock return InteractionResult.SUCCESS; ItemStack inHand = player.getItemInHand(pHand); - return onTileEntityUse(pLevel, pPos, pte -> { + return onBlockEntityUse(pLevel, pPos, pte -> { ItemStack inBlock = pte.getHeldItem(); if (!player.mayBuild() || inHand.isEmpty() || !inBlock.isEmpty()) { @@ -174,7 +174,7 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock if (pState.hasBlockEntity() && (blockChanged || !pNewState.hasBlockEntity())) { if (!pIsMoving) - withTileEntityDo(pLevel, pPos, te -> Block.popResource(pLevel, pPos, te.getHeldItem())); + withBlockEntityDo(pLevel, pPos, be -> Block.popResource(pLevel, pPos, be.getHeldItem())); pLevel.removeBlockEntity(pPos); } } @@ -188,7 +188,7 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock public void attack(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) { if (pLevel.isClientSide) return; - withTileEntityDo(pLevel, pPos, pte -> { + withBlockEntityDo(pLevel, pPos, pte -> { ItemStack heldItem = pte.getHeldItem(); if (heldItem.isEmpty()) return; @@ -200,10 +200,10 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock } @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { ItemStack placardStack = AllBlocks.PLACARD.asStack(); - if (te instanceof PlacardTileEntity pte) { - ItemStack heldItem = pte.getHeldItem(); + if (be instanceof PlacardBlockEntity pbe) { + ItemStack heldItem = pbe.getHeldItem(); if (!heldItem.isEmpty()) { return new ItemRequirement(List.of( new ItemRequirement.StackRequirement(placardStack, ItemUseType.CONSUME), @@ -215,13 +215,13 @@ public class PlacardBlock extends FaceAttachedHorizontalDirectionalBlock } @Override - public Class getTileEntityClass() { - return PlacardTileEntity.class; + public Class getBlockEntityClass() { + return PlacardBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.PLACARD.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.PLACARD.get(); } } diff --git a/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlockEntity.java b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlockEntity.java new file mode 100644 index 0000000000..7df38597b4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardBlockEntity.java @@ -0,0 +1,99 @@ +package com.simibubi.create.content.decoration.placard; + +import java.util.List; + +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class PlacardBlockEntity extends SmartBlockEntity { + + ItemStack heldItem; + int poweredTicks; + + public PlacardBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + heldItem = ItemStack.EMPTY; + poweredTicks = 0; + } + + @Override + public void tick() { + super.tick(); + if (level.isClientSide) + return; + if (poweredTicks == 0) + return; + + poweredTicks--; + if (poweredTicks > 0) + return; + + BlockState blockState = getBlockState(); + level.setBlock(worldPosition, blockState.setValue(PlacardBlock.POWERED, false), 3); + PlacardBlock.updateNeighbours(blockState, level, worldPosition); + } + + public ItemStack getHeldItem() { + return heldItem; + } + + public void setHeldItem(ItemStack heldItem) { + this.heldItem = heldItem; + notifyUpdate(); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + tag.putInt("PoweredTicks", poweredTicks); + tag.put("Item", heldItem.serializeNBT()); + super.write(tag, clientPacket); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + int prevTicks = poweredTicks; + poweredTicks = tag.getInt("PoweredTicks"); + heldItem = ItemStack.of(tag.getCompound("Item")); + super.read(tag, clientPacket); + + if (clientPacket && prevTicks < poweredTicks) + spawnParticles(); + } + + private void spawnParticles() { + BlockState blockState = getBlockState(); + if (!AllBlocks.PLACARD.has(blockState)) + return; + + DustParticleOptions pParticleData = new DustParticleOptions(new Vector3f(1, .2f, 0), 1); + Vec3 centerOf = VecHelper.getCenterOf(worldPosition); + Vec3 normal = Vec3.atLowerCornerOf(PlacardBlock.connectedDirection(blockState) + .getNormal()); + Vec3 offset = VecHelper.axisAlingedPlaneOf(normal); + + for (int i = 0; i < 10; i++) { + Vec3 v = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .5f) + .multiply(offset) + .normalize() + .scale(.45f) + .add(normal.scale(-.45f)) + .add(centerOf); + level.addParticle(pParticleData, v.x, v.y, v.z, 0, 0, 0); + } + } + + @Override + public void addBehaviours(List behaviours) {} + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardRenderer.java b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardRenderer.java similarity index 79% rename from src/main/java/com/simibubi/create/content/curiosities/deco/PlacardRenderer.java rename to src/main/java/com/simibubi/create/content/decoration/placard/PlacardRenderer.java index 3a6eab42cd..cb5c695417 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/PlacardRenderer.java +++ b/src/main/java/com/simibubi/create/content/decoration/placard/PlacardRenderer.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration.placard; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; import net.createmod.catnip.utility.math.AngleHelper; import net.minecraft.client.Minecraft; @@ -16,18 +16,18 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.AttachFace; -public class PlacardRenderer extends SafeTileEntityRenderer { +public class PlacardRenderer extends SafeBlockEntityRenderer { public PlacardRenderer(BlockEntityRendererProvider.Context context) {} @Override - protected void renderSafe(PlacardTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(PlacardBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - ItemStack heldItem = te.getHeldItem(); + ItemStack heldItem = be.getHeldItem(); if (heldItem.isEmpty()) return; - BlockState blockState = te.getBlockState(); + BlockState blockState = be.getBlockState(); Direction facing = blockState.getValue(PlacardBlock.FACING); AttachFace face = blockState.getValue(PlacardBlock.FACE); diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControl.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControl.java new file mode 100644 index 0000000000..7c2a800a6a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControl.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import java.util.Arrays; +import java.util.function.Consumer; + +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public enum DoorControl { + + ALL, NORTH, EAST, SOUTH, WEST, NONE; + + private static String[] valuesAsString() { + DoorControl[] values = values(); + return Arrays.stream(values) + .map(dc -> Lang.asId(dc.name())) + .toList() + .toArray(new String[values.length]); + } + + public boolean matches(Direction doorDirection) { + return switch (this) { + case ALL -> true; + case NORTH -> doorDirection == Direction.NORTH; + case EAST -> doorDirection == Direction.EAST; + case SOUTH -> doorDirection == Direction.SOUTH; + case WEST -> doorDirection == Direction.WEST; + default -> false; + }; + } + + @OnlyIn(Dist.CLIENT) + public static Pair createWidget(int x, int y, Consumer callback, + DoorControl initial) { + + DoorControl playerFacing = NONE; + Entity cameraEntity = Minecraft.getInstance().cameraEntity; + if (cameraEntity != null) { + Direction direction = cameraEntity.getDirection(); + if (direction == Direction.EAST) + playerFacing = EAST; + if (direction == Direction.WEST) + playerFacing = WEST; + if (direction == Direction.NORTH) + playerFacing = NORTH; + if (direction == Direction.SOUTH) + playerFacing = SOUTH; + } + + Label label = new Label(x + 4, y + 6, Components.empty()).withShadow(); + ScrollInput input = new SelectionScrollInput(x, y, 53, 16) + .forOptions(CreateLang.translatedOptions("contraption.door_control", valuesAsString())) + .titled(CreateLang.translateDirect("contraption.door_control")) + .calling(s -> { + DoorControl mode = values()[s]; + label.text = CreateLang.translateDirect("contraption.door_control." + Lang.asId(mode.name()) + ".short"); + callback.accept(mode); + }) + .addHint(CreateLang.translateDirect("contraption.door_control.player_facing", + CreateLang.translateDirect("contraption.door_control." + Lang.asId(playerFacing.name()) + ".short"))) + .setState(initial.ordinal()); + input.onChanged(); + return Pair.of(input, label); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControlBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControlBehaviour.java new file mode 100644 index 0000000000..5b139e5619 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/DoorControlBehaviour.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.nbt.CompoundTag; + +public class DoorControlBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + public DoorControl mode; + + public DoorControlBehaviour(SmartBlockEntity be) { + super(be); + mode = DoorControl.ALL; + } + + public void set(DoorControl mode) { + if (this.mode == mode) + return; + this.mode = mode; + blockEntity.notifyUpdate(); + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + NBTHelper.writeEnum(nbt, "DoorControl", mode); + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + mode = NBTHelper.readEnum(nbt, "DoorControl", DoorControl.class); + super.read(nbt, clientPacket); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorBlock.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlock.java similarity index 83% rename from src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorBlock.java rename to src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlock.java index 2f1dbd3404..ca1720fe11 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlock.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.deco; +package com.simibubi.create.content.decoration.slidingDoor; import javax.annotation.Nullable; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionWorld; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.contraptions.ContraptionWorld; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -36,21 +36,10 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.eventbus.api.Event.Result; -public class SlidingDoorBlock extends DoorBlock implements IWrenchable, ITE { - - protected static final VoxelShape SE_AABB = Block.box(0.0D, 0.0D, -13.0D, 3.0D, 16.0D, 3.0D); - protected static final VoxelShape ES_AABB = Block.box(-13.0D, 0.0D, 0.0D, 3.0D, 16.0D, 3.0D); - - protected static final VoxelShape NW_AABB = Block.box(13.0D, 0.0D, 13.0D, 16.0D, 16.0D, 29.0D); - protected static final VoxelShape WN_AABB = Block.box(13.0D, 0.0D, 13.0D, 29.0D, 16.0D, 16.0D); - - protected static final VoxelShape SW_AABB = Block.box(13.0D, 0.0D, -13.0D, 16.0D, 16.0D, 3.0D); - protected static final VoxelShape WS_AABB = Block.box(13.0D, 0.0D, 0.0D, 29.0D, 16.0D, 3.0D); - - protected static final VoxelShape NE_AABB = Block.box(0.0D, 0.0D, 13.0D, 3.0D, 16.0D, 29.0D); - protected static final VoxelShape EN_AABB = Block.box(-13.0D, 0.0D, 13.0D, 3.0D, 16.0D, 16.0D); +public class SlidingDoorBlock extends DoorBlock implements IWrenchable, IBE { public static final BooleanProperty VISIBLE = BooleanProperty.create("visible"); + private boolean folds; @Deprecated // Remove in 1.19 - Fixes incompatibility with Quarks double door module public static void stopItQuark(PlayerInteractEvent.RightClickBlock event) { @@ -64,14 +53,19 @@ public class SlidingDoorBlock extends DoorBlock implements IWrenchable, ITE (hinge ? ES_AABB : WS_AABB); - case WEST -> (hinge ? SW_AABB : NW_AABB); - case NORTH -> (hinge ? WN_AABB : EN_AABB); - default -> (hinge ? NE_AABB : SE_AABB); - }; + return SlidingDoorShapes.get(direction, hinge, isFoldingDoor()); } @Override @@ -170,8 +158,8 @@ public class SlidingDoorBlock extends DoorBlock implements IWrenchable, ITE sdte.deferUpdate = true); + withBlockEntityDo(level, pos, sdte -> sdte.deferUpdate = true); } public static boolean isDoubleDoor(BlockState pState, DoorHingeSide hinge, Direction facing, BlockState otherDoor) { @@ -269,17 +257,17 @@ public class SlidingDoorBlock extends DoorBlock implements IWrenchable, ITE getTileEntityClass() { - return SlidingDoorTileEntity.class; + public Class getBlockEntityClass() { + return SlidingDoorBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SLIDING_DOOR.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SLIDING_DOOR.get(); } } diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlockEntity.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlockEntity.java new file mode 100644 index 0000000000..9a26047023 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorBlockEntity.java @@ -0,0 +1,84 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class SlidingDoorBlockEntity extends SmartBlockEntity { + + LerpedFloat animation; + int bridgeTicks; + boolean deferUpdate; + + public SlidingDoorBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + animation = LerpedFloat.linear() + .startWithValue(isOpen(state) ? 1 : 0); + } + + @Override + public void tick() { + if (deferUpdate && !level.isClientSide()) { + deferUpdate = false; + BlockState blockState = getBlockState(); + blockState.neighborChanged(level, worldPosition, Blocks.AIR, worldPosition, false); + } + + super.tick(); + boolean open = isOpen(getBlockState()); + boolean wasSettled = animation.settled(); + animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); + animation.tickChaser(); + + if (level.isClientSide()) { + if (bridgeTicks < 2 && open) + bridgeTicks++; + else if (bridgeTicks > 0 && !open && isVisible(getBlockState())) + bridgeTicks--; + return; + } + + if (!open && !wasSettled && animation.settled() && !isVisible(getBlockState())) + showBlockModel(); + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(1); + } + + protected boolean isVisible(BlockState state) { + return state.getOptionalValue(SlidingDoorBlock.VISIBLE) + .orElse(true); + } + + protected boolean shouldRenderSpecial(BlockState state) { + return !isVisible(state) || bridgeTicks != 0; + } + + protected void showBlockModel() { + level.setBlock(worldPosition, getBlockState().setValue(SlidingDoorBlock.VISIBLE, true), 3); + level.playSound(null, worldPosition, SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .5f, 1); + } + + @Override + public void addBehaviours(List behaviours) {} + + public static boolean isOpen(BlockState state) { + return state.getOptionalValue(DoorBlock.OPEN) + .orElse(false); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorMovementBehaviour.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorMovementBehaviour.java new file mode 100644 index 0000000000..cb037a1986 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorMovementBehaviour.java @@ -0,0 +1,206 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import java.lang.ref.WeakReference; +import java.util.Map; + +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.Vec3; + +public class SlidingDoorMovementBehaviour implements MovementBehaviour { + + @Override + public boolean renderAsNormalBlockEntity() { + return true; + } + + @Override + public boolean mustTickWhileDisabled() { + return true; + } + + @Override + public void tick(MovementContext context) { + StructureBlockInfo structureBlockInfo = context.contraption.getBlocks() + .get(context.localPos); + if (structureBlockInfo == null) + return; + boolean open = SlidingDoorBlockEntity.isOpen(structureBlockInfo.state); + + if (!context.world.isClientSide()) + tickOpen(context, open); + + Map tes = context.contraption.presentBlockEntities; + if (!(tes.get(context.localPos) instanceof SlidingDoorBlockEntity sdbe)) + return; + boolean wasSettled = sdbe.animation.settled(); + sdbe.animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); + sdbe.animation.tickChaser(); + + if (!wasSettled && sdbe.animation.settled() && !open) + context.world.playLocalSound(context.position.x, context.position.y, context.position.z, + SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .125f, 1, false); + } + + protected void tickOpen(MovementContext context, boolean currentlyOpen) { + boolean shouldOpen = shouldOpen(context); + if (!shouldUpdate(context, shouldOpen)) + return; + if (currentlyOpen == shouldOpen) + return; + + BlockPos pos = context.localPos; + Contraption contraption = context.contraption; + + StructureBlockInfo info = contraption.getBlocks() + .get(pos); + if (info == null || !info.state.hasProperty(DoorBlock.OPEN)) + return; + + toggleDoor(pos, contraption, info); + + if (shouldOpen) + context.world.playSound(null, new BlockPos(context.position), SoundEvents.IRON_DOOR_OPEN, + SoundSource.BLOCKS, .125f, 1); + } + + private void toggleDoor(BlockPos pos, Contraption contraption, StructureBlockInfo info) { + BlockState newState = info.state.cycle(DoorBlock.OPEN); + contraption.entity.setBlock(pos, new StructureBlockInfo(info.pos, newState, info.nbt)); + + BlockPos otherPos = newState.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? pos.above() : pos.below(); + info = contraption.getBlocks() + .get(otherPos); + if (info != null && info.state.hasProperty(DoorBlock.OPEN)) { + newState = info.state.cycle(DoorBlock.OPEN); + contraption.entity.setBlock(otherPos, new StructureBlockInfo(info.pos, newState, info.nbt)); + contraption.invalidateColliders(); + } + } + + protected boolean shouldUpdate(MovementContext context, boolean shouldOpen) { + if (context.firstMovement && shouldOpen) + return false; + if (!context.data.contains("Open")) { + context.data.putBoolean("Open", shouldOpen); + return true; + } + boolean wasOpen = context.data.getBoolean("Open"); + context.data.putBoolean("Open", shouldOpen); + return wasOpen != shouldOpen; + } + + protected boolean shouldOpen(MovementContext context) { + if (context.disabled) + return false; + Contraption contraption = context.contraption; + boolean canOpen = context.motion.length() < 1 / 128f && !contraption.entity.isStalled() + || contraption instanceof ElevatorContraption ec && ec.arrived; + + if (!canOpen) { + context.temporaryData = null; + return false; + } + + if (context.temporaryData instanceof WeakReference wr && wr.get()instanceof DoorControlBehaviour dcb) + if (dcb.blockEntity != null && !dcb.blockEntity.isRemoved()) + return shouldOpenAt(dcb, context); + + context.temporaryData = null; + DoorControlBehaviour doorControls = null; + + if (contraption instanceof ElevatorContraption ec) + doorControls = getElevatorDoorControl(ec, context); + if (context.contraption.entity instanceof CarriageContraptionEntity cce) + doorControls = getTrainStationDoorControl(cce, context); + + if (doorControls == null) + return false; + + context.temporaryData = new WeakReference<>(doorControls); + return shouldOpenAt(doorControls, context); + } + + protected boolean shouldOpenAt(DoorControlBehaviour controller, MovementContext context) { + if (controller.mode == DoorControl.ALL) + return true; + if (controller.mode == DoorControl.NONE) + return false; + return controller.mode.matches(getDoorFacing(context)); + } + + protected DoorControlBehaviour getElevatorDoorControl(ElevatorContraption ec, MovementContext context) { + Integer currentTargetY = ec.getCurrentTargetY(context.world); + if (currentTargetY == null) + return null; + ColumnCoords columnCoords = ec.getGlobalColumn(); + if (columnCoords == null) + return null; + ElevatorColumn elevatorColumn = ElevatorColumn.get(context.world, columnCoords); + if (elevatorColumn == null) + return null; + return BlockEntityBehaviour.get(context.world, elevatorColumn.contactAt(currentTargetY), + DoorControlBehaviour.TYPE); + } + + protected DoorControlBehaviour getTrainStationDoorControl(CarriageContraptionEntity cce, MovementContext context) { + Carriage carriage = cce.getCarriage(); + if (carriage == null || carriage.train == null) + return null; + GlobalStation currentStation = carriage.train.getCurrentStation(); + if (currentStation == null) + return null; + + BlockPos stationPos = currentStation.getBlockEntityPos(); + ResourceKey stationDim = currentStation.getBlockEntityDimension(); + MinecraftServer server = context.world.getServer(); + if (server == null) + return null; + ServerLevel stationLevel = server.getLevel(stationDim); + if (stationLevel == null || !stationLevel.isLoaded(stationPos)) + return null; + return BlockEntityBehaviour.get(stationLevel, stationPos, DoorControlBehaviour.TYPE); + } + + protected Direction getDoorFacing(MovementContext context) { + Direction stateFacing = context.state.getValue(DoorBlock.FACING); + Direction originalFacing = Direction.get(AxisDirection.POSITIVE, stateFacing.getAxis()); + Vec3 centerOfContraption = context.contraption.bounds.getCenter(); + Vec3 diff = Vec3.atCenterOf(context.localPos) + .add(Vec3.atLowerCornerOf(stateFacing.getNormal()) + .scale(-.45f)) + .subtract(centerOfContraption); + if (originalFacing.getAxis() + .choose(diff.x, diff.y, diff.z) < 0) + originalFacing = originalFacing.getOpposite(); + + Vec3 directionVec = Vec3.atLowerCornerOf(originalFacing.getNormal()); + directionVec = context.rotation.apply(directionVec); + return Direction.getNearest(directionVec.x, directionVec.y, directionVec.z); + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorRenderer.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorRenderer.java new file mode 100644 index 0000000000..ddaea86b43 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorRenderer.java @@ -0,0 +1,96 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoorHingeSide; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.phys.Vec3; + +public class SlidingDoorRenderer extends SafeBlockEntityRenderer { + + public SlidingDoorRenderer(Context context) {} + + @Override + protected void renderSafe(SlidingDoorBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + if (!be.shouldRenderSpecial(blockState)) + return; + + Direction facing = blockState.getValue(DoorBlock.FACING); + Direction movementDirection = facing.getClockWise(); + + if (blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.LEFT) + movementDirection = movementDirection.getOpposite(); + + float value = be.animation.getValue(partialTicks); + float value2 = Mth.clamp(value * 10, 0, 1); + + VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); + Vec3 offset = Vec3.atLowerCornerOf(movementDirection.getNormal()) + .scale(value * value * 13 / 16f) + .add(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(value2 * 1 / 32f)); + + if (((SlidingDoorBlock) blockState.getBlock()).isFoldingDoor()) { + Couple partials = AllPartialModels.FOLDING_DOORS.get(blockState.getBlock() + .getRegistryName()); + + boolean flip = blockState.getValue(DoorBlock.HINGE) == DoorHingeSide.RIGHT; + for (boolean left : Iterate.trueAndFalse) { + SuperByteBuffer partial = CachedPartialBuffers.partial(partials.get(left ^ flip), blockState); + float f = flip ? -1 : 1; + + partial.translate(0, -1 / 512f, 0) + .translate(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(value2 * 1 / 32f)); + partial.rotateCentered(Direction.UP, + Mth.DEG_TO_RAD * AngleHelper.horizontalAngle(facing.getClockWise())); + + if (flip) + partial.translate(0, 0, 1); + partial.rotateY(91 * f * value * value); + + if (!left) + partial.translate(0, 0, f / 2f) + .rotateY(-181 * f * value * value); + + if (flip) + partial.translate(0, 0, -1 / 2f); + + partial.light(light) + .renderInto(ms, vb); + } + + return; + } + + for (DoubleBlockHalf half : DoubleBlockHalf.values()) { + CachedBlockBuffers.block(blockState.setValue(DoorBlock.OPEN, false) + .setValue(DoorBlock.HALF, half)) + .translate(0, half == DoubleBlockHalf.UPPER ? 1 - 1 / 512f : 0, 0) + .translate(offset) + .light(light) + .renderInto(ms, vb); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorShapes.java b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorShapes.java new file mode 100644 index 0000000000..54697ac86e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/slidingDoor/SlidingDoorShapes.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.decoration.slidingDoor; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class SlidingDoorShapes { + + protected static final VoxelShape SE_AABB = Block.box(0.0D, 0.0D, -13.0D, 3.0D, 16.0D, 3.0D); + protected static final VoxelShape ES_AABB = Block.box(-13.0D, 0.0D, 0.0D, 3.0D, 16.0D, 3.0D); + protected static final VoxelShape NW_AABB = Block.box(13.0D, 0.0D, 13.0D, 16.0D, 16.0D, 29.0D); + protected static final VoxelShape WN_AABB = Block.box(13.0D, 0.0D, 13.0D, 29.0D, 16.0D, 16.0D); + protected static final VoxelShape SW_AABB = Block.box(13.0D, 0.0D, -13.0D, 16.0D, 16.0D, 3.0D); + protected static final VoxelShape WS_AABB = Block.box(13.0D, 0.0D, 0.0D, 29.0D, 16.0D, 3.0D); + protected static final VoxelShape NE_AABB = Block.box(0.0D, 0.0D, 13.0D, 3.0D, 16.0D, 29.0D); + protected static final VoxelShape EN_AABB = Block.box(-13.0D, 0.0D, 13.0D, 3.0D, 16.0D, 16.0D); + + protected static final VoxelShape SE_AABB_FOLD = Block.box(0.0D, 0.0D, -3.0D, 9.0D, 16.0D, 3.0D); + protected static final VoxelShape ES_AABB_FOLD = Block.box(-3.0D, 0.0D, 0.0D, 3.0D, 16.0D, 9.0D); + protected static final VoxelShape NW_AABB_FOLD = Block.box(7.0D, 0.0D, 13.0D, 16.0D, 16.0D, 19.0D); + protected static final VoxelShape WN_AABB_FOLD = Block.box(13.0D, 0.0D, 7.0D, 19.0D, 16.0D, 16.0D); + protected static final VoxelShape SW_AABB_FOLD = Block.box(7.0D, 0.0D, -3.0D, 16.0D, 16.0D, 3.0D); + protected static final VoxelShape WS_AABB_FOLD = Block.box(13.0D, 0.0D, 0.0D, 19.0D, 16.0D, 9.0D); + protected static final VoxelShape NE_AABB_FOLD = Block.box(0.0D, 0.0D, 13.0D, 9.0D, 16.0D, 19.0D); + protected static final VoxelShape EN_AABB_FOLD = Block.box(-3.0D, 0.0D, 7.0D, 3.0D, 16.0D, 16.0D); + + public static VoxelShape get(Direction facing, boolean hinge, boolean fold) { + if (fold) + return switch (facing) { + case SOUTH -> (hinge ? ES_AABB_FOLD : WS_AABB_FOLD); + case WEST -> (hinge ? SW_AABB_FOLD : NW_AABB_FOLD); + case NORTH -> (hinge ? WN_AABB_FOLD : EN_AABB_FOLD); + default -> (hinge ? NE_AABB_FOLD : SE_AABB_FOLD); + }; + + return switch (facing) { + case SOUTH -> (hinge ? ES_AABB : WS_AABB); + case WEST -> (hinge ? SW_AABB : NW_AABB); + case NORTH -> (hinge ? WN_AABB : EN_AABB); + default -> (hinge ? NE_AABB : SE_AABB); + }; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleBlock.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlock.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleBlock.java rename to src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlock.java index 8f52b20766..2917f6f861 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlock.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; +package com.simibubi.create.content.decoration.steamWhistle; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock.WhistleExtenderShape; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock.WhistleExtenderShape; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.tank.FluidTankBlock; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.core.BlockPos; @@ -47,7 +47,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class WhistleBlock extends Block implements ITE, IWrenchable { +public class WhistleBlock extends Block implements IBE, IWrenchable { public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final BooleanProperty WALL = BooleanProperty.create("wall"); @@ -181,7 +181,7 @@ public class WhistleBlock extends Block implements ITE, IWren @Override public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRandom) { - withTileEntityDo(pLevel, pPos, WhistleTileEntity::updatePitch); + withBlockEntityDo(pLevel, pPos, WhistleBlockEntity::updatePitch); } @Override @@ -193,8 +193,7 @@ public class WhistleBlock extends Block implements ITE, IWren @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { - if (pState.hasBlockEntity() && (!pState.is(pNewState.getBlock()) || !pNewState.hasBlockEntity())) - pLevel.removeBlockEntity(pPos); + IBE.onRemove(pState, pLevel, pPos, pNewState); FluidTankBlock.updateBoilerState(pState, pLevel, pPos.relative(getAttachedDirection(pState))); } @@ -236,13 +235,13 @@ public class WhistleBlock extends Block implements ITE, IWren } @Override - public Class getTileEntityClass() { - return WhistleTileEntity.class; + public Class getBlockEntityClass() { + return WhistleBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.STEAM_WHISTLE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.STEAM_WHISTLE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlockEntity.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlockEntity.java new file mode 100644 index 0000000000..16b323a8a0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleBlockEntity.java @@ -0,0 +1,197 @@ +package com.simibubi.create.content.decoration.steamWhistle; + +import java.lang.ref.WeakReference; +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock.WhistleExtenderShape; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.kinetics.steamEngine.SteamJetParticleData; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class WhistleBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + public WeakReference source; + public LerpedFloat animation; + protected int pitch; + + public WhistleBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + source = new WeakReference<>(null); + animation = LerpedFloat.linear(); + } + + @Override + public void addBehaviours(List behaviours) { + registerAwardables(behaviours, AllAdvancements.STEAM_WHISTLE); + } + + public void updatePitch() { + BlockPos currentPos = worldPosition.above(); + int newPitch; + for (newPitch = 0; newPitch <= 24; newPitch += 2) { + BlockState blockState = level.getBlockState(currentPos); + if (!AllBlocks.STEAM_WHISTLE_EXTENSION.has(blockState)) + break; + if (blockState.getValue(WhistleExtenderBlock.SHAPE) == WhistleExtenderShape.SINGLE) { + newPitch++; + break; + } + currentPos = currentPos.above(); + } + if (pitch == newPitch) + return; + pitch = newPitch; + + notifyUpdate(); + + FluidTankBlockEntity tank = getTank(); + if (tank != null && tank.boiler != null) + tank.boiler.checkPipeOrganAdvancement(tank); + } + + @Override + public void tick() { + super.tick(); + if (!level.isClientSide()) { + if (isPowered()) + award(AllAdvancements.STEAM_WHISTLE); + return; + } + + FluidTankBlockEntity tank = getTank(); + boolean powered = isPowered() + && (tank != null && tank.boiler.isActive() && (tank.boiler.passiveHeat || tank.boiler.activeHeat > 0) + || isVirtual()); + animation.chase(powered ? 1 : 0, powered ? .5f : .4f, powered ? Chaser.EXP : Chaser.LINEAR); + animation.tickChaser(); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio(getOctave(), powered)); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + tag.putInt("Pitch", pitch); + super.write(tag, clientPacket); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + pitch = tag.getInt("Pitch"); + super.read(tag, clientPacket); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + String[] pitches = CreateLang.translateDirect("generic.notes") + .getString() + .split(";"); + MutableComponent textComponent = Components.literal(spacing); + tooltip.add(textComponent.append(CreateLang.translateDirect("generic.pitch", pitches[pitch % pitches.length]))); + return true; + } + + protected boolean isPowered() { + return getBlockState().getOptionalValue(WhistleBlock.POWERED) + .orElse(false); + } + + protected WhistleSize getOctave() { + return getBlockState().getOptionalValue(WhistleBlock.SIZE) + .orElse(WhistleSize.MEDIUM); + } + + @OnlyIn(Dist.CLIENT) + protected WhistleSoundInstance soundInstance; + + @OnlyIn(Dist.CLIENT) + protected void tickAudio(WhistleSize size, boolean powered) { + if (!powered) { + if (soundInstance != null) { + soundInstance.fadeOut(); + soundInstance = null; + } + return; + } + + float f = (float) Math.pow(2, -pitch / 12.0); + boolean particle = level.getGameTime() % 8 == 0; + Vec3 eyePosition = Minecraft.getInstance().cameraEntity.getEyePosition(); + float maxVolume = (float) Mth.clamp((64 - eyePosition.distanceTo(Vec3.atCenterOf(worldPosition))) / 64, 0, 1); + + if (soundInstance == null || soundInstance.isStopped() || soundInstance.getOctave() != size) { + Minecraft.getInstance() + .getSoundManager() + .play(soundInstance = new WhistleSoundInstance(size, worldPosition)); + AllSoundEvents.WHISTLE_CHIFF.playAt(level, worldPosition, maxVolume * .175f, + size == WhistleSize.SMALL ? f + .75f : f, false); + particle = true; + } + + soundInstance.keepAlive(); + soundInstance.setPitch(f); + + if (!particle) + return; + + Direction facing = getBlockState().getOptionalValue(WhistleBlock.FACING) + .orElse(Direction.SOUTH); + float angle = 180 + AngleHelper.horizontalAngle(facing); + Vec3 sizeOffset = VecHelper.rotate(new Vec3(0, -0.4f, 1 / 16f * size.ordinal()), angle, Axis.Y); + Vec3 offset = VecHelper.rotate(new Vec3(0, 1, 0.75f), angle, Axis.Y); + Vec3 v = offset.scale(.45f) + .add(sizeOffset) + .add(Vec3.atCenterOf(worldPosition)); + Vec3 m = offset.subtract(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(.75f)); + level.addParticle(new SteamJetParticleData(1), v.x, v.y, v.z, m.x, m.y, m.z); + } + + public int getPitchId() { + return pitch + 100 * getBlockState().getOptionalValue(WhistleBlock.SIZE) + .orElse(WhistleSize.MEDIUM) + .ordinal(); + } + + public FluidTankBlockEntity getTank() { + FluidTankBlockEntity tank = source.get(); + if (tank == null || tank.isRemoved()) { + if (tank != null) + source = new WeakReference<>(null); + Direction facing = WhistleBlock.getAttachedDirection(getBlockState()); + BlockEntity be = level.getBlockEntity(worldPosition.relative(facing)); + if (be instanceof FluidTankBlockEntity tankBe) + source = new WeakReference<>(tank = tankBe); + } + if (tank == null) + return null; + return tank.getControllerBE(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleExtenderBlock.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleExtenderBlock.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleExtenderBlock.java rename to src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleExtenderBlock.java index cc4cb63cab..c194c4bfd9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleExtenderBlock.java +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleExtenderBlock.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; +package com.simibubi.create.content.decoration.steamWhistle; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleGenerator.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleGenerator.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleGenerator.java rename to src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleGenerator.java index 15317a1ca8..2923980a79 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleGenerator.java +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; +package com.simibubi.create.content.decoration.steamWhistle; import com.simibubi.create.Create; import com.simibubi.create.foundation.data.AssetLookup; diff --git a/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleRenderer.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleRenderer.java new file mode 100644 index 0000000000..e5d1b6ed08 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleRenderer.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.decoration.steamWhistle; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class WhistleRenderer extends SafeBlockEntityRenderer { + + public WhistleRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(WhistleBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + if (!(blockState.getBlock() instanceof WhistleBlock)) + return; + + Direction direction = blockState.getValue(WhistleBlock.FACING); + WhistleSize size = blockState.getValue(WhistleBlock.SIZE); + + PartialModel mouth = size == WhistleSize.LARGE ? AllPartialModels.WHISTLE_MOUTH_LARGE + : size == WhistleSize.MEDIUM ? AllPartialModels.WHISTLE_MOUTH_MEDIUM : AllPartialModels.WHISTLE_MOUTH_SMALL; + + float offset = be.animation.getValue(partialTicks); + if (be.animation.getChaseTarget() > 0 && be.animation.getValue() > 0.5f) { + float wiggleProgress = (WorldTickHolder.getTicks(be.getLevel()) + partialTicks) / 8f; + offset -= Math.sin(wiggleProgress * (2 * Mth.PI) * (4 - size.ordinal())) / 16f; + } + + CachedPartialBuffers.partial(mouth, blockState) + .centre() + .rotateY(AngleHelper.horizontalAngle(direction)) + .unCentre() + .translate(0, offset * 4 / 16f, 0) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleSoundInstance.java b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleSoundInstance.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleSoundInstance.java rename to src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleSoundInstance.java index 4919b895b7..276459bb44 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/whistle/WhistleSoundInstance.java +++ b/src/main/java/com/simibubi/create/content/decoration/steamWhistle/WhistleSoundInstance.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.steam.whistle; +package com.simibubi.create.content.decoration.steamWhistle; import static com.simibubi.create.AllSoundEvents.WHISTLE_HIGH; import static com.simibubi.create.AllSoundEvents.WHISTLE_LOW; import static com.simibubi.create.AllSoundEvents.WHISTLE_MEDIUM; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/curiosities/BuildersTeaItem.java b/src/main/java/com/simibubi/create/content/equipment/BuildersTeaItem.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/BuildersTeaItem.java rename to src/main/java/com/simibubi/create/content/equipment/BuildersTeaItem.java index 15b25d3b60..caea8034c0 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/BuildersTeaItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/BuildersTeaItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.equipment; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.server.level.ServerPlayer; diff --git a/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java b/src/main/java/com/simibubi/create/content/equipment/TreeFertilizerItem.java similarity index 92% rename from src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java rename to src/main/java/com/simibubi/create/content/equipment/TreeFertilizerItem.java index 5d80b7e416..b01354312a 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/TreeFertilizerItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/TreeFertilizerItem.java @@ -1,8 +1,5 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.equipment; -import javax.annotation.Nonnull; - -import org.jetbrains.annotations.NotNull; import net.createmod.catnip.utility.worldWrappers.PlacementSimulationServerWorld; import net.minecraft.core.BlockPos; @@ -96,14 +93,14 @@ public class TreeFertilizerItem extends Item { } @Override - public @NotNull BlockState getBlockState(@Nonnull BlockPos pos) { + public BlockState getBlockState(BlockPos pos) { if (pos.getY() <= 9) return soil; return super.getBlockState(pos); } @Override - public boolean setBlock(@Nonnull BlockPos pos, @Nonnull BlockState newState, int flags) { + public boolean setBlock(BlockPos pos, BlockState newState, int flags) { if (newState.getBlock() == Blocks.PODZOL) return true; return super.setBlock(pos, newState, flags); diff --git a/src/main/java/com/simibubi/create/content/curiosities/armor/AllArmorMaterials.java b/src/main/java/com/simibubi/create/content/equipment/armor/AllArmorMaterials.java similarity index 90% rename from src/main/java/com/simibubi/create/content/curiosities/armor/AllArmorMaterials.java rename to src/main/java/com/simibubi/create/content/equipment/armor/AllArmorMaterials.java index 0937f2b7de..3064b5bcf8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/armor/AllArmorMaterials.java +++ b/src/main/java/com/simibubi/create/content/equipment/armor/AllArmorMaterials.java @@ -1,9 +1,10 @@ -package com.simibubi.create.content.curiosities.armor; +package com.simibubi.create.content.equipment.armor; import java.util.function.Supplier; import com.google.common.base.Suppliers; import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.Create; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.entity.EquipmentSlot; @@ -13,7 +14,7 @@ import net.minecraft.world.item.crafting.Ingredient; public enum AllArmorMaterials implements ArmorMaterial { - COPPER("copper", 7, new int[] { 1, 3, 4, 2 }, 25, () -> AllSoundEvents.COPPER_ARMOR_EQUIP.getMainEvent(), 0.0F, 0.0F, + COPPER(Create.asResource("copper").toString(), 7, new int[] { 1, 3, 4, 2 }, 25, () -> AllSoundEvents.COPPER_ARMOR_EQUIP.getMainEvent(), 0.0F, 0.0F, () -> Ingredient.of(Items.COPPER_INGOT)) ; diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankArmorLayer.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankArmorLayer.java new file mode 100644 index 0000000000..bb1c0d0565 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankArmorLayer.java @@ -0,0 +1,93 @@ +package com.simibubi.create.content.equipment.armor; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.state.BlockState; + +public class BacktankArmorLayer> extends RenderLayer { + public BacktankArmorLayer(RenderLayerParent renderer) { + super(renderer); + } + + @Override + public void render(PoseStack ms, MultiBufferSource buffer, int light, LivingEntity entity, float yaw, float pitch, + float pt, float p_225628_8_, float p_225628_9_, float p_225628_10_) { + if (entity.getPose() == Pose.SLEEPING) + return; + + BacktankItem item = BacktankItem.getWornBy(entity); + if (item == null) + return; + + M entityModel = getParentModel(); + if (!(entityModel instanceof HumanoidModel)) + return; + + HumanoidModel model = (HumanoidModel) entityModel; + RenderType renderType = Sheets.cutoutBlockSheet(); + BlockState renderedState = item.getBlock().defaultBlockState() + .setValue(BacktankBlock.HORIZONTAL_FACING, Direction.SOUTH); + SuperByteBuffer backtank = CachedBlockBuffers.block(renderedState); + SuperByteBuffer cogs = CachedPartialBuffers.partial(BacktankRenderer.getCogsModel(renderedState), renderedState); + + ms.pushPose(); + + model.body.translateAndRotate(ms); + ms.translate(-1 / 2f, 10 / 16f, 1f); + ms.scale(1, -1, -1); + + backtank.forEntityRender() + .light(light) + .renderInto(ms, buffer.getBuffer(renderType)); + + cogs.centre() + .rotateY(180) + .unCentre() + .translate(0, 6.5f / 16, 11f / 16) + .rotate(Direction.EAST, AngleHelper.rad(2 * WorldTickHolder.getRenderTime(entity.level) % 360)) + .translate(0, -6.5f / 16, -11f / 16); + + cogs.forEntityRender() + .light(light) + .renderInto(ms, buffer.getBuffer(renderType)); + + ms.popPose(); + } + + public static void registerOnAll(EntityRenderDispatcher renderManager) { + for (EntityRenderer renderer : renderManager.getSkinMap().values()) + registerOn(renderer); + for (EntityRenderer renderer : renderManager.renderers.values()) + registerOn(renderer); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static void registerOn(EntityRenderer entityRenderer) { + if (!(entityRenderer instanceof LivingEntityRenderer)) + return; + LivingEntityRenderer livingRenderer = (LivingEntityRenderer) entityRenderer; + if (!(livingRenderer.getModel() instanceof HumanoidModel)) + return; + BacktankArmorLayer layer = new BacktankArmorLayer<>(livingRenderer); + livingRenderer.addLayer((BacktankArmorLayer) layer); + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlock.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlock.java new file mode 100644 index 0000000000..8848aa3927 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlock.java @@ -0,0 +1,201 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.Optional; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllEnchantments; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.common.util.FakePlayer; + +public class BacktankBlock extends HorizontalKineticBlock + implements IBE, SimpleWaterloggedBlock { + + public BacktankBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); + } + + @Override + public FluidState getFluidState(BlockState state) { + return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) + : Fluids.EMPTY.defaultFluidState(); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(BlockStateProperties.WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} + + @Override + public boolean hasAnalogOutputSignal(BlockState p_149740_1_) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { + return getBlockEntityOptional(world, pos).map(BacktankBlockEntity::getComparatorOutput) + .orElse(0); + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, + LevelAccessor world, BlockPos pos, BlockPos neighbourPos) { + if (state.getValue(BlockStateProperties.WATERLOGGED)) + world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + return state; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + FluidState fluidState = context.getLevel() + .getFluidState(context.getClickedPos()); + return super.getStateForPlacement(context).setValue(BlockStateProperties.WATERLOGGED, + fluidState.getType() == Fluids.WATER); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face == Direction.UP; + } + + @Override + public Axis getRotationAxis(BlockState state) { + return Axis.Y; + } + + @Override + public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + super.setPlacedBy(worldIn, pos, state, placer, stack); + if (worldIn.isClientSide) + return; + if (stack == null) + return; + withBlockEntityDo(worldIn, pos, be -> { + be.setCapacityEnchantLevel(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), stack)); + be.setAirLevel(stack.getOrCreateTag() + .getInt("Air")); + if (stack.isEnchanted()) + be.setEnchantmentTag(stack.getEnchantmentTags()); + if (stack.hasCustomHoverName()) + be.setCustomName(stack.getHoverName()); + }); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + if (player == null) + return InteractionResult.PASS; + if (player instanceof FakePlayer) + return InteractionResult.PASS; + if (player.isShiftKeyDown()) + return InteractionResult.PASS; + if (player.getMainHandItem() + .getItem() instanceof BlockItem) + return InteractionResult.PASS; + if (!player.getItemBySlot(EquipmentSlot.CHEST) + .isEmpty()) + return InteractionResult.PASS; + if (!world.isClientSide) { + world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .75f, 1); + player.setItemSlot(EquipmentSlot.CHEST, getCloneItemStack(world, pos, state)); + world.destroyBlock(pos, false); + } + return InteractionResult.SUCCESS; + } + + @Override + public ItemStack getCloneItemStack(BlockGetter blockGetter, BlockPos pos, BlockState state) { + Item item = asItem(); + if (item instanceof BacktankItem.BacktankBlockItem placeable) { + item = placeable.getActualItem(); + } + + ItemStack stack = new ItemStack(item); + Optional blockEntityOptional = getBlockEntityOptional(blockGetter, pos); + + int air = blockEntityOptional.map(BacktankBlockEntity::getAirLevel) + .orElse(0); + CompoundTag tag = stack.getOrCreateTag(); + tag.putInt("Air", air); + + ListTag enchants = blockEntityOptional.map(BacktankBlockEntity::getEnchantmentTag) + .orElse(new ListTag()); + if (!enchants.isEmpty()) { + ListTag enchantmentTagList = stack.getEnchantmentTags(); + enchantmentTagList.addAll(enchants); + tag.put("Enchantments", enchantmentTagList); + } + + Component customName = blockEntityOptional.map(BacktankBlockEntity::getCustomName) + .orElse(null); + if (customName != null) + stack.setHoverName(customName); + return stack; + } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.BACKTANK; + } + + @Override + public Class getBlockEntityClass() { + return BacktankBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BACKTANK.get(); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlockEntity.java new file mode 100644 index 0000000000..4225637164 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankBlockEntity.java @@ -0,0 +1,185 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.ComparatorUtil; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.particle.AirParticleData; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.Nameable; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.Vec3; + +public class BacktankBlockEntity extends KineticBlockEntity implements Nameable { + + public int airLevel; + public int airLevelTimer; + private Component defaultName; + private Component customName; + + private int capacityEnchantLevel; + private ListTag enchantmentTag; + + public BacktankBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + defaultName = getDefaultName(state); + enchantmentTag = new ListTag(); + } + + public static Component getDefaultName(BlockState state) { + if (AllBlocks.NETHERITE_BACKTANK.has(state)) { + AllItems.NETHERITE_BACKTANK.get().getDescription(); + } + + return AllItems.COPPER_BACKTANK.get().getDescription(); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.BACKTANK); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + if (getSpeed() != 0) + award(AllAdvancements.BACKTANK); + } + + @Override + public void tick() { + super.tick(); + if (getSpeed() == 0) + return; + + BlockState state = getBlockState(); + BooleanProperty waterProperty = BlockStateProperties.WATERLOGGED; + if (state.hasProperty(waterProperty) && state.getValue(waterProperty)) + return; + + if (airLevelTimer > 0) { + airLevelTimer--; + return; + } + + int max = BacktankUtil.maxAir(capacityEnchantLevel); + if (level.isClientSide) { + Vec3 centerOf = VecHelper.getCenterOf(worldPosition); + Vec3 v = VecHelper.offsetRandomly(centerOf, level.random, .65f); + Vec3 m = centerOf.subtract(v); + if (airLevel != max) + level.addParticle(new AirParticleData(1, .05f), v.x, v.y, v.z, m.x, m.y, m.z); + return; + } + + if (airLevel == max) + return; + + int prevComparatorLevel = getComparatorOutput(); + float abs = Math.abs(getSpeed()); + int increment = Mth.clamp(((int) abs - 100) / 20, 1, 5); + airLevel = Math.min(max, airLevel + increment); + if (getComparatorOutput() != prevComparatorLevel && !level.isClientSide) + level.updateNeighbourForOutputSignal(worldPosition, state.getBlock()); + if (airLevel == max) + sendData(); + airLevelTimer = Mth.clamp((int) (128f - abs / 5f) - 108, 0, 20); + } + + public int getComparatorOutput() { + int max = BacktankUtil.maxAir(capacityEnchantLevel); + return ComparatorUtil.fractionToRedstoneLevel(airLevel / (float) max); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("Air", airLevel); + compound.putInt("Timer", airLevelTimer); + compound.putInt("CapacityEnchantment", capacityEnchantLevel); + if (this.customName != null) + compound.putString("CustomName", Component.Serializer.toJson(this.customName)); + compound.put("Enchantments", enchantmentTag); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + int prev = airLevel; + capacityEnchantLevel = compound.getInt("CapacityEnchantment"); + airLevel = compound.getInt("Air"); + airLevelTimer = compound.getInt("Timer"); + enchantmentTag = compound.getList("Enchantments", Tag.TAG_COMPOUND); + if (compound.contains("CustomName", 8)) + this.customName = Component.Serializer.fromJson(compound.getString("CustomName")); + if (prev != 0 && prev != airLevel && airLevel == BacktankUtil.maxAir(capacityEnchantLevel) && clientPacket) + playFilledEffect(); + } + + protected void playFilledEffect() { + AllSoundEvents.CONFIRM.playAt(level, worldPosition, 0.4f, 1, true); + Vec3 baseMotion = new Vec3(.25, 0.1, 0); + Vec3 baseVec = VecHelper.getCenterOf(worldPosition); + for (int i = 0; i < 360; i += 10) { + Vec3 m = VecHelper.rotate(baseMotion, i, Axis.Y); + Vec3 v = baseVec.add(m.normalize() + .scale(.25f)); + + level.addParticle(ParticleTypes.SPIT, v.x, v.y, v.z, m.x, m.y, m.z); + } + } + + @Override + public Component getName() { + return this.customName != null ? this.customName + : defaultName; + } + + public int getAirLevel() { + return airLevel; + } + + public void setAirLevel(int airLevel) { + this.airLevel = airLevel; + sendData(); + } + + public void setCustomName(Component customName) { + this.customName = customName; + } + + public Component getCustomName() { + return customName; + } + + public ListTag getEnchantmentTag() { + return enchantmentTag; + } + + public void setEnchantmentTag(ListTag enchantmentTag) { + this.enchantmentTag = enchantmentTag; + } + + public void setCapacityEnchantLevel(int capacityEnchantLevel) { + this.capacityEnchantLevel = capacityEnchantLevel; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankInstance.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankInstance.java new file mode 100644 index 0000000000..c382e3ff5c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankInstance.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.equipment.armor; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +public class BacktankInstance extends SingleRotatingInstance { + + public BacktankInstance(MaterialManager materialManager, BacktankBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + return getRotatingMaterial().getModel(BacktankRenderer.getShaftModel(blockState), blockState); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankItem.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankItem.java new file mode 100644 index 0000000000..e7a8ec90f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankItem.java @@ -0,0 +1,132 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.Locale; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.content.equipment.armor.CapacityEnchantment.ICapacityEnchantable; +import com.simibubi.create.foundation.item.LayeredArmorItem; + +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.Block; + +public class BacktankItem extends BaseArmorItem implements ICapacityEnchantable { + public static final EquipmentSlot SLOT = EquipmentSlot.CHEST; + public static final int BAR_COLOR = 0xEFEFEF; + + private final Supplier blockItem; + + public BacktankItem(ArmorMaterial material, Properties properties, ResourceLocation textureLoc, Supplier placeable) { + super(material, SLOT, properties, textureLoc); + this.blockItem = placeable; + } + + @Nullable + public static BacktankItem getWornBy(Entity entity) { + if (!(entity instanceof LivingEntity livingEntity)) { + return null; + } + if (!(livingEntity.getItemBySlot(SLOT).getItem() instanceof BacktankItem item)) { + return null; + } + return item; + } + + @Override + public InteractionResult useOn(UseOnContext ctx) { + return blockItem.get() + .useOn(ctx); + } + + @Override + public boolean canBeDepleted() { + return false; + } + + @Override + public boolean isEnchantable(ItemStack p_77616_1_) { + return true; + } + + @Override + public void fillItemCategory(CreativeModeTab tab, NonNullList items) { + if (!allowdedIn(tab)) + return; + + ItemStack stack = new ItemStack(this); + CompoundTag nbt = new CompoundTag(); + nbt.putInt("Air", BacktankUtil.maxAirWithoutEnchants()); + stack.setTag(nbt); + items.add(stack); + } + + @Override + public boolean isBarVisible(ItemStack stack) { + return true; + } + + @Override + public int getBarWidth(ItemStack stack) { + return Math.round(13.0F * Mth.clamp(getRemainingAir(stack) / ((float) BacktankUtil.maxAir(stack)), 0, 1)); + } + + @Override + public int getBarColor(ItemStack stack) { + return BAR_COLOR; + } + + public Block getBlock() { + return blockItem.get().getBlock(); + } + + public static int getRemainingAir(ItemStack stack) { + CompoundTag orCreateTag = stack.getOrCreateTag(); + return orCreateTag.getInt("Air"); + } + + public static class BacktankBlockItem extends BlockItem { + private final Supplier actualItem; + + public BacktankBlockItem(Block block, Supplier actualItem, Properties properties) { + super(block, properties); + this.actualItem = actualItem; + } + + @Override + public void fillItemCategory(CreativeModeTab group, NonNullList items) {} + + @Override + public String getDescriptionId() { + return this.getOrCreateDescriptionId(); + } + + public Item getActualItem() { + return actualItem.get(); + } + } + + public static class Layered extends BacktankItem implements LayeredArmorItem { + public Layered(ArmorMaterial material, Properties properties, ResourceLocation textureLoc, Supplier placeable) { + super(material, properties, textureLoc, placeable); + } + + @Override + public String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer) { + return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%d.png", textureLoc.getNamespace(), textureLoc.getPath(), layer); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankRenderer.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankRenderer.java new file mode 100644 index 0000000000..4470db564d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankRenderer.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.equipment.armor; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class BacktankRenderer extends KineticBlockEntityRenderer { + public BacktankRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(BacktankBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + BlockState blockState = be.getBlockState(); + SuperByteBuffer cogs = CachedPartialBuffers.partial(getCogsModel(blockState), blockState); + cogs.centre() + .rotateY(180 + AngleHelper.horizontalAngle(blockState.getValue(BacktankBlock.HORIZONTAL_FACING))) + .unCentre() + .translate(0, 6.5f / 16, 11f / 16) + .rotate(Direction.EAST, + AngleHelper.rad(be.getSpeed() / 4f * WorldTickHolder.getRenderTime(be.getLevel()) % 360)) + .translate(0, -6.5f / 16, -11f / 16); + cogs.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + + @Override + protected SuperByteBuffer getRotatedModel(BacktankBlockEntity be, BlockState state) { + return CachedPartialBuffers.partial(getShaftModel(state), state); + } + + public static PartialModel getCogsModel(BlockState state) { + if (AllBlocks.NETHERITE_BACKTANK.has(state)) { + return AllPartialModels.NETHERITE_BACKTANK_COGS; + } + return AllPartialModels.COPPER_BACKTANK_COGS; + } + + public static PartialModel getShaftModel(BlockState state) { + if (AllBlocks.NETHERITE_BACKTANK.has(state)) { + return AllPartialModels.NETHERITE_BACKTANK_SHAFT; + } + return AllPartialModels.COPPER_BACKTANK_SHAFT; + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BacktankUtil.java b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankUtil.java new file mode 100644 index 0000000000..cee6bc48d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BacktankUtil.java @@ -0,0 +1,197 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import com.simibubi.create.AllEnchantments; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.AllTags; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class BacktankUtil { + + private static final List>> BACKTANK_SUPPLIERS = new ArrayList<>(); + + static { + addBacktankSupplier(entity -> { + List stacks = new ArrayList<>(); + for (ItemStack itemStack : entity.getArmorSlots()) + if (AllTags.AllItemTags.PRESSURIZED_AIR_SOURCES.matches(itemStack)) + stacks.add(itemStack); + + return stacks; + }); + } + + public static List getAllWithAir(LivingEntity entity) { + List all = new ArrayList<>(); + + for (Function> supplier : BACKTANK_SUPPLIERS) { + List result = supplier.apply(entity); + + for (ItemStack stack : result) + if (hasAirRemaining(stack)) + all.add(stack); + } + + // Sort with ascending order (we want to prioritize the most empty so things actually run out) + all.sort((a, b) -> Float.compare(getAir(a), getAir(b))); + + return all; + } + + public static boolean hasAirRemaining(ItemStack backtank) { + return getAir(backtank) > 0; + } + + public static float getAir(ItemStack backtank) { + CompoundTag tag = backtank.getOrCreateTag(); + return Math.min(tag.getFloat("Air"), maxAir(backtank)); + } + + public static void consumeAir(LivingEntity entity, ItemStack backtank, float i) { + CompoundTag tag = backtank.getOrCreateTag(); + int maxAir = maxAir(backtank); + float air = getAir(backtank); + float newAir = Math.max(air - i, 0); + tag.putFloat("Air", Math.min(newAir, maxAir)); + backtank.setTag(tag); + + if (!(entity instanceof ServerPlayer player)) + return; + + sendWarning(player, air, newAir, maxAir / 10f); + sendWarning(player, air, newAir, 1); + } + + private static void sendWarning(ServerPlayer player, float air, float newAir, float threshold) { + if (newAir > threshold) + return; + if (air <= threshold) + return; + + boolean depleted = threshold == 1; + MutableComponent component = CreateLang.translateDirect(depleted ? "backtank.depleted" : "backtank.low"); + + AllSoundEvents.DENY.play(player.level, null, player.blockPosition(), 1, 1.25f); + AllSoundEvents.STEAM.play(player.level, null, player.blockPosition(), .5f, .5f); + + player.connection.send(new ClientboundSetTitlesAnimationPacket(10, 40, 10)); + player.connection.send(new ClientboundSetSubtitleTextPacket( + Components.literal("\u26A0 ").withStyle(depleted ? ChatFormatting.RED : ChatFormatting.GOLD) + .append(component.withStyle(ChatFormatting.GRAY)))); + player.connection.send(new ClientboundSetTitleTextPacket(Components.immutableEmpty())); + } + + public static int maxAir(ItemStack backtank) { + return maxAir(EnchantmentHelper.getItemEnchantmentLevel(AllEnchantments.CAPACITY.get(), backtank)); + } + + public static int maxAir(int enchantLevel) { + return AllConfigs.server().equipment.airInBacktank.get() + + AllConfigs.server().equipment.enchantedBacktankCapacity.get() * enchantLevel; + } + + public static int maxAirWithoutEnchants() { + return AllConfigs.server().equipment.airInBacktank.get(); + } + + public static boolean canAbsorbDamage(LivingEntity entity, int usesPerTank) { + if (usesPerTank == 0) + return true; + if (entity instanceof Player && ((Player) entity).isCreative()) + return true; + List backtanks = getAllWithAir(entity); + if (backtanks.isEmpty()) + return false; + float cost = ((float) maxAirWithoutEnchants()) / usesPerTank; + consumeAir(entity, backtanks.get(0), cost); + return true; + } + + // For Air-using tools + + public static boolean isBarVisible(ItemStack stack, int usesPerTank) { + if (usesPerTank == 0) + return false; + Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); + if (player == null) + return false; + List backtanks = getAllWithAir(player); + if (backtanks.isEmpty()) + return stack.isDamaged(); + return true; + } + + public static int getBarWidth(ItemStack stack, int usesPerTank) { + if (usesPerTank == 0) + return 13; + Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); + if (player == null) + return 13; + + List backtanks = getAllWithAir(player); + + if (backtanks.isEmpty()) + return Math.round(13.0F - (float) stack.getDamageValue() / stack.getMaxDamage() * 13.0F); + + if (backtanks.size() == 1) + return backtanks.get(0) + .getItem() + .getBarWidth(backtanks.get(0)); + + // If there is more than one backtank, average the bar widths. + int sumBarWidth = backtanks.stream() + .map(backtank -> backtank.getItem() + .getBarWidth(backtank)) + .reduce(0, Integer::sum); + + return Math.round((float) sumBarWidth / backtanks.size()); + } + + public static int getBarColor(ItemStack stack, int usesPerTank) { + if (usesPerTank == 0) + return 0; + Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> () -> Minecraft.getInstance().player); + if (player == null) + return 0; + List backtanks = getAllWithAir(player); + + // Fallback colour + if (backtanks.isEmpty()) + return Mth.hsvToRgb(Math.max(0.0F, 1.0F - (float) stack.getDamageValue() / stack.getMaxDamage()) / 3.0F, + 1.0F, 1.0F); + + // Just return the "first" backtank for the bar color since that's the one we are consuming from + return backtanks.get(0) + .getItem() + .getBarColor(backtanks.get(0)); + } + + /** + * Use this method to add custom entry points to the backtank item stack supplier, e.g. getting them from custom + * slots or items. + */ + public static void addBacktankSupplier(Function> supplier) { + BACKTANK_SUPPLIERS.add(supplier); + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/BaseArmorItem.java b/src/main/java/com/simibubi/create/content/equipment/armor/BaseArmorItem.java new file mode 100644 index 0000000000..5c1fbeb144 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/BaseArmorItem.java @@ -0,0 +1,24 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.Locale; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ItemStack; + +public class BaseArmorItem extends ArmorItem { + protected final ResourceLocation textureLoc; + + public BaseArmorItem(ArmorMaterial armorMaterial, EquipmentSlot slot, Properties properties, ResourceLocation textureLoc) { + super(armorMaterial, slot, properties.stacksTo(1)); + this.textureLoc = textureLoc; + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String type) { + return String.format(Locale.ROOT, "%s:textures/models/armor/%s_layer_%d%s.png", textureLoc.getNamespace(), textureLoc.getPath(), slot == EquipmentSlot.LEGS ? 2 : 1, type == null ? "" : String.format(Locale.ROOT, "_%s", type)); + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/CapacityEnchantment.java b/src/main/java/com/simibubi/create/content/equipment/armor/CapacityEnchantment.java new file mode 100644 index 0000000000..d1109caa28 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/CapacityEnchantment.java @@ -0,0 +1,27 @@ +package com.simibubi.create.content.equipment.armor; + +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentCategory; + +public class CapacityEnchantment extends Enchantment { + + public CapacityEnchantment(Rarity rarity, EnchantmentCategory category, EquipmentSlot[] slots) { + super(rarity, category, slots); + } + + @Override + public int getMaxLevel() { + return 3; + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack) { + return stack.getItem() instanceof ICapacityEnchantable; + } + + public interface ICapacityEnchantable { + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/DivingBootsItem.java b/src/main/java/com/simibubi/create/content/equipment/armor/DivingBootsItem.java new file mode 100644 index 0000000000..f6ad7f445b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/DivingBootsItem.java @@ -0,0 +1,108 @@ +package com.simibubi.create.content.equipment.armor; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.FluidTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class DivingBootsItem extends BaseArmorItem { + public static final EquipmentSlot SLOT = EquipmentSlot.FEET; + + public DivingBootsItem(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) { + super(material, SLOT, properties, textureLoc); + } + + public static boolean isWornBy(Entity entity) { + return !getWornItem(entity).isEmpty(); + } + + public static ItemStack getWornItem(Entity entity) { + if (!(entity instanceof LivingEntity livingEntity)) { + return ItemStack.EMPTY; + } + ItemStack stack = livingEntity.getItemBySlot(SLOT); + if (!(stack.getItem() instanceof DivingBootsItem)) { + return ItemStack.EMPTY; + } + return stack; + } + + @SubscribeEvent + public static void accellerateDescentUnderwater(LivingUpdateEvent event) { + LivingEntity entity = event.getEntityLiving(); + if (!affects(entity)) + return; + + Vec3 motion = entity.getDeltaMovement(); + boolean isJumping = entity.jumping; + entity.setOnGround(entity.isOnGround() || entity.verticalCollision); + + if (isJumping && entity.isOnGround()) { + motion = motion.add(0, .5f, 0); + entity.setOnGround(false); + } else { + motion = motion.add(0, -0.05f, 0); + } + + float multiplier = 1.3f; + if (motion.multiply(1, 0, 1) + .length() < 0.145f && (entity.zza > 0 || entity.xxa != 0) && !entity.isShiftKeyDown()) + motion = motion.multiply(multiplier, 1, multiplier); + entity.setDeltaMovement(motion); + } + + protected static boolean affects(LivingEntity entity) { + if (!isWornBy(entity)) { + entity.getPersistentData() + .remove("HeavyBoots"); + return false; + } + + NBTHelper.putMarker(entity.getPersistentData(), "HeavyBoots"); + if (!entity.isInWater()) + return false; + if (entity.getPose() == Pose.SWIMMING) + return false; + if (entity instanceof Player) { + Player playerEntity = (Player) entity; + if (playerEntity.getAbilities().flying) + return false; + } + return true; + } + + public static Vec3 getMovementMultiplier(LivingEntity entity) { + double yMotion = entity.getDeltaMovement().y; + double vMultiplier = yMotion < 0 ? Math.max(0, 2.5 - Math.abs(yMotion) * 2) : 1; + + if (!entity.isOnGround()) { + if (entity.jumping && entity.getPersistentData() + .contains("LavaGrounded")) { + boolean eyeInFluid = entity.isEyeInFluid(FluidTags.LAVA); + vMultiplier = yMotion == 0 ? 0 : (eyeInFluid ? 1 : 0.5) / yMotion; + } else if (yMotion > 0) + vMultiplier = 1.3; + + entity.getPersistentData() + .remove("LavaGrounded"); + return new Vec3(1.75, vMultiplier, 1.75); + } + + entity.getPersistentData() + .putBoolean("LavaGrounded", true); + double hMultiplier = entity.isSprinting() ? 1.85 : 1.75; + return new Vec3(hMultiplier, vMultiplier, hMultiplier); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/DivingHelmetItem.java b/src/main/java/com/simibubi/create/content/equipment/armor/DivingHelmetItem.java new file mode 100644 index 0000000000..4640f4671f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/DivingHelmetItem.java @@ -0,0 +1,116 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.List; + +import com.simibubi.create.foundation.advancement.AllAdvancements; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.FluidTags; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.Level; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class DivingHelmetItem extends BaseArmorItem { + public static final EquipmentSlot SLOT = EquipmentSlot.HEAD; + + public DivingHelmetItem(ArmorMaterial material, Properties properties, ResourceLocation textureLoc) { + super(material, SLOT, properties, textureLoc); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + if (enchantment == Enchantments.AQUA_AFFINITY) { + return false; + } + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + public static boolean isWornBy(Entity entity) { + return !getWornItem(entity).isEmpty(); + } + + public static ItemStack getWornItem(Entity entity) { + if (!(entity instanceof LivingEntity livingEntity)) { + return ItemStack.EMPTY; + } + ItemStack stack = livingEntity.getItemBySlot(SLOT); + if (!(stack.getItem() instanceof DivingHelmetItem)) { + return ItemStack.EMPTY; + } + return stack; + } + + @SubscribeEvent + public static void breatheUnderwater(LivingUpdateEvent event) { + LivingEntity entity = event.getEntityLiving(); + Level world = entity.level; + boolean second = world.getGameTime() % 20 == 0; + boolean drowning = entity.getAirSupply() == 0; + + if (world.isClientSide) + entity.getPersistentData() + .remove("VisualBacktankAir"); + + ItemStack helmet = getWornItem(entity); + if (helmet.isEmpty()) + return; + + boolean lavaDiving = entity.isInLava(); + if (!helmet.getItem() + .isFireResistant() && lavaDiving) + return; + if (!entity.isEyeInFluid(FluidTags.WATER) && !lavaDiving) + return; + if (entity instanceof Player && ((Player) entity).isCreative()) + return; + + List backtanks = BacktankUtil.getAllWithAir(entity); + if (backtanks.isEmpty()) + return; + + if (lavaDiving) { + if (entity instanceof ServerPlayer sp) + AllAdvancements.DIVING_SUIT_LAVA.awardTo(sp); + if (backtanks.stream() + .noneMatch(backtank -> backtank.getItem() + .isFireResistant())) + return; + } + + if (drowning) + entity.setAirSupply(10); + + if (world.isClientSide) + entity.getPersistentData() + .putInt("VisualBacktankAir", Math.round(backtanks.stream() + .map(BacktankUtil::getAir) + .reduce(0f, Float::sum))); + + if (!second) + return; + + BacktankUtil.consumeAir(entity, backtanks.get(0), 1); + + if (lavaDiving) + return; + + if (entity instanceof ServerPlayer sp) + AllAdvancements.DIVING_SUIT.awardTo(sp); + + entity.setAirSupply(Math.min(entity.getMaxAirSupply(), entity.getAirSupply() + 10)); + entity.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 30, 0, true, false, true)); + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteBacktankFirstPersonRenderer.java b/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteBacktankFirstPersonRenderer.java new file mode 100644 index 0000000000..9d995838a2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteBacktankFirstPersonRenderer.java @@ -0,0 +1,63 @@ +package com.simibubi.create.content.equipment.armor; + +import com.simibubi.create.AllItems; +import com.simibubi.create.Create; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.player.PlayerRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderArmEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber(value = Dist.CLIENT) +public class NetheriteBacktankFirstPersonRenderer { + + private static final ResourceLocation BACKTANK_ARMOR_LOCATION = + Create.asResource("textures/models/armor/netherite_diving_arm.png"); + + private static boolean rendererActive = false; + + public static void clientTick() { + Minecraft mc = Minecraft.getInstance(); + rendererActive = + mc.player != null && AllItems.NETHERITE_BACKTANK.isIn(mc.player.getItemBySlot(EquipmentSlot.CHEST)); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onRenderPlayerHand(RenderArmEvent event) { + if (!rendererActive) + return; + + Minecraft mc = Minecraft.getInstance(); + LocalPlayer player = mc.player; + MultiBufferSource buffer = event.getMultiBufferSource(); + if (!(mc.getEntityRenderDispatcher() + .getRenderer(player) instanceof PlayerRenderer pr)) + return; + + PlayerModel model = pr.getModel(); + model.attackTime = 0.0F; + model.crouching = false; + model.swimAmount = 0.0F; + model.setupAnim(player, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F); + ModelPart armPart = event.getArm() == HumanoidArm.LEFT ? model.leftSleeve : model.rightSleeve; + armPart.xRot = 0.0F; + armPart.render(event.getPoseStack(), buffer.getBuffer(RenderType.entitySolid(BACKTANK_ARMOR_LOCATION)), + LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); + event.setCanceled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteDivingHandler.java b/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteDivingHandler.java new file mode 100644 index 0000000000..1ab209728c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/NetheriteDivingHandler.java @@ -0,0 +1,92 @@ +package com.simibubi.create.content.equipment.armor; + +import com.simibubi.create.AllItems; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public final class NetheriteDivingHandler { + public static final String NETHERITE_DIVING_BITS_KEY = "CreateNetheriteDivingBits"; + public static final String FIRE_IMMUNE_KEY = "CreateFireImmune"; + + @SubscribeEvent + public static void onLivingEquipmentChange(LivingEquipmentChangeEvent event) { + EquipmentSlot slot = event.getSlot(); + if (slot.getType() != EquipmentSlot.Type.ARMOR) { + return; + } + + LivingEntity entity = event.getEntityLiving(); + ItemStack to = event.getTo(); + + if (slot == EquipmentSlot.HEAD) { + if (AllItems.NETHERITE_DIVING_HELMET.isIn(to)) { + setBit(entity, slot); + } else { + clearBit(entity, slot); + } + } else if (slot == EquipmentSlot.CHEST) { + if (AllItems.NETHERITE_BACKTANK.isIn(to) && BacktankUtil.hasAirRemaining(to)) { + setBit(entity, slot); + } else { + clearBit(entity, slot); + } + } else if (slot == EquipmentSlot.LEGS || slot == EquipmentSlot.FEET) { + if (isNetheriteArmor(to)) { + setBit(entity, slot); + } else { + clearBit(entity, slot); + } + } + } + + public static boolean isNetheriteArmor(ItemStack stack) { + return stack.getItem() instanceof ArmorItem armorItem && armorItem.getMaterial() == ArmorMaterials.NETHERITE; + } + + public static void setBit(LivingEntity entity, EquipmentSlot slot) { + CompoundTag nbt = entity.getPersistentData(); + byte bits = nbt.getByte(NETHERITE_DIVING_BITS_KEY); + if ((bits & 0b1111) == 0b1111) { + return; + } + + bits |= 1 << slot.getIndex(); + nbt.putByte(NETHERITE_DIVING_BITS_KEY, bits); + + if ((bits & 0b1111) == 0b1111) { + setFireImmune(entity, true); + } + } + + public static void clearBit(LivingEntity entity, EquipmentSlot slot) { + CompoundTag nbt = entity.getPersistentData(); + if (!nbt.contains(NETHERITE_DIVING_BITS_KEY)) { + return; + } + + byte bits = nbt.getByte(NETHERITE_DIVING_BITS_KEY); + boolean prevFullSet = (bits & 0b1111) == 0b1111; + bits &= ~(1 << slot.getIndex()); + nbt.putByte(NETHERITE_DIVING_BITS_KEY, bits); + + if (prevFullSet) { + setFireImmune(entity, false); + } + } + + // TODO: sync to the client + // The feature works without syncing because health and burning are calculated server-side and synced through vanilla code. + // This method will not be called when the entity is wearing a full diving set on creation because the NBT values are persistent. + public static void setFireImmune(LivingEntity entity, boolean fireImmune) { + entity.getPersistentData().putBoolean(FIRE_IMMUNE_KEY, fireImmune); + } +} diff --git a/src/main/java/com/simibubi/create/content/equipment/armor/RemainingAirOverlay.java b/src/main/java/com/simibubi/create/content/equipment/armor/RemainingAirOverlay.java new file mode 100644 index 0000000000..19c1c69672 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/armor/RemainingAirOverlay.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.equipment.armor; + +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllItems; + +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.tags.FluidTags; +import net.minecraft.util.StringUtil; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameType; +import net.minecraftforge.client.gui.ForgeIngameGui; +import net.minecraftforge.client.gui.IIngameOverlay; + +public class RemainingAirOverlay implements IIngameOverlay { + public static final RemainingAirOverlay INSTANCE = new RemainingAirOverlay(); + + @Override + public void render(ForgeIngameGui gui, PoseStack poseStack, float partialTick, int width, int height) { + Minecraft mc = Minecraft.getInstance(); + if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) + return; + + LocalPlayer player = mc.player; + if (player == null) + return; + if (player.isCreative()) + return; + if (!player.getPersistentData() + .contains("VisualBacktankAir")) + return; + if (!player.isEyeInFluid(FluidTags.WATER) && !player.isInLava()) + return; + + int timeLeft = player.getPersistentData() + .getInt("VisualBacktankAir"); + + poseStack.pushPose(); + + ItemStack backtank = getDisplayedBacktank(player); + poseStack.translate(width / 2 + 90, height - 53 + (backtank.getItem() + .isFireResistant() ? 9 : 0), 0); + + Component text = Components.literal(StringUtil.formatTickDuration(Math.max(0, timeLeft - 1) * 20)); + GuiGameElement.of(backtank) + .at(0, 0) + .render(poseStack); + int color = 0xFF_FFFFFF; + if (timeLeft < 60 && timeLeft % 2 == 0) { + color = Color.mixColors(0xFF_FF0000, color, Math.max(timeLeft / 60f, .25f)); + } + mc.font.drawShadow(poseStack, text, 16, 5, color); + + poseStack.popPose(); + } + + public static ItemStack getDisplayedBacktank(LocalPlayer player) { + List backtanks = BacktankUtil.getAllWithAir(player); + if (!backtanks.isEmpty()) { + return backtanks.get(0); + } + return AllItems.COPPER_BACKTANK.asStack(); + } +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellBlock.java b/src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellBlock.java rename to src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlock.java index 0e0c9cdad2..5467bc4032 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/AbstractBellBlock.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlock.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import javax.annotation.Nullable; import com.simibubi.create.AllShapes; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -23,7 +23,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -public abstract class AbstractBellBlock extends BellBlock implements ITE { +public abstract class AbstractBellBlock extends BellBlock implements IBE { public AbstractBellBlock(Properties properties) { super(properties); @@ -76,10 +76,10 @@ public abstract class AbstractBellBlock exten } protected boolean ring(Level world, BlockPos pos, Direction direction, Player player) { - TE te = getTileEntity(world, pos); + BE be = getBlockEntity(world, pos); if (world.isClientSide) return true; - if (te == null || !te.ring(world, pos, direction)) + if (be == null || !be.ring(world, pos, direction)) return false; playSound(world, pos); if (player != null) @@ -109,13 +109,13 @@ public abstract class AbstractBellBlock exten @Nullable public BlockEntity newBlockEntity(BlockPos p_152198_, BlockState p_152199_) { - return ITE.super.newBlockEntity(p_152198_, p_152199_); + return IBE.super.newBlockEntity(p_152198_, p_152199_); } @Nullable public BlockEntityTicker getTicker(Level p_152194_, BlockState p_152195_, BlockEntityType p_152196_) { - return ITE.super.getTicker(p_152194_, p_152195_, p_152196_); + return IBE.super.getTicker(p_152194_, p_152195_, p_152196_); } public abstract void playSound(Level world, BlockPos pos); diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlockEntity.java new file mode 100644 index 0000000000..5e9100beb4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/AbstractBellBlockEntity.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.equipment.bell; + +import java.util.List; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class AbstractBellBlockEntity extends SmartBlockEntity { + + public static final int RING_DURATION = 74; + + public boolean isRinging; + public int ringingTicks; + public Direction ringDirection; + + public AbstractBellBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { } + + public boolean ring(Level world, BlockPos pos, Direction direction) { + isRinging = true; + ringingTicks = 0; + ringDirection = direction; + sendData(); + return true; + }; + + @Override + public void tick() { + super.tick(); + + if (isRinging) { + ++ringingTicks; + } + + if (ringingTicks >= RING_DURATION) { + isRinging = false; + ringingTicks = 0; + } + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + if (!clientPacket || ringingTicks != 0 || !isRinging) + return; + NBTHelper.writeEnum(tag, "Ringing", ringDirection); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + if (!clientPacket || !tag.contains("Ringing")) + return; + ringDirection = NBTHelper.readEnum(tag, "Ringing", Direction.class); + ringingTicks = 0; + isRinging = true; + } + + @OnlyIn(Dist.CLIENT) + public abstract PartialModel getBellModel(); + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/BasicParticleData.java b/src/main/java/com/simibubi/create/content/equipment/bell/BasicParticleData.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/bell/BasicParticleData.java rename to src/main/java/com/simibubi/create/content/equipment/bell/BasicParticleData.java index baef1531a1..7fa1115e72 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/BasicParticleData.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/BasicParticleData.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import javax.annotation.ParametersAreNonnullByDefault; import com.mojang.brigadier.StringReader; import com.mojang.serialization.Codec; -import com.simibubi.create.content.contraptions.particle.ICustomParticleDataWithSprite; +import com.simibubi.create.foundation.particle.ICustomParticleDataWithSprite; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/BellRenderer.java b/src/main/java/com/simibubi/create/content/equipment/bell/BellRenderer.java new file mode 100644 index 0000000000..14c40fd822 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/BellRenderer.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.equipment.bell; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BellAttachType; + +public class BellRenderer extends SafeBlockEntityRenderer { + + public BellRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(BE be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + BlockState state = be.getBlockState(); + Direction facing = state.getValue(BellBlock.FACING); + BellAttachType attachment = state.getValue(BellBlock.ATTACHMENT); + + SuperByteBuffer bell = CachedPartialBuffers.partial(be.getBellModel(), state); + + if (be.isRinging) + bell.rotateCentered(be.ringDirection.getCounterClockWise(), getSwingAngle(be.ringingTicks + partialTicks)); + + float rY = AngleHelper.horizontalAngle(facing); + if (attachment == BellAttachType.SINGLE_WALL || attachment == BellAttachType.DOUBLE_WALL) + rY += 90; + bell.rotateCentered(Direction.UP, AngleHelper.rad(rY)); + + bell.light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutout())); + } + + public static float getSwingAngle(float time) { + float t = time / 1.5f; + return 1.2f * Mth.sin(t / (float) Math.PI) / (2.5f + t / 3.0f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/CustomRotationParticle.java b/src/main/java/com/simibubi/create/content/equipment/bell/CustomRotationParticle.java similarity index 98% rename from src/main/java/com/simibubi/create/content/curiosities/bell/CustomRotationParticle.java rename to src/main/java/com/simibubi/create/content/equipment/bell/CustomRotationParticle.java index 3f6d0ef2c6..9b80868bf8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/CustomRotationParticle.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/CustomRotationParticle.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.mojang.blaze3d.vertex.VertexConsumer; diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlock.java b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlock.java new file mode 100644 index 0000000000..e7886ca61b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlock.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.equipment.bell; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.foundation.advancement.AllAdvancements; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class HauntedBellBlock extends AbstractBellBlock { + + public HauntedBellBlock(Properties properties) { + super(properties); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.HAUNTED_BELL.get(); + } + + @Override + protected boolean ring(Level world, BlockPos pos, Direction direction, Player player) { + boolean ring = super.ring(world, pos, direction, player); + if (ring) + AllAdvancements.HAUNTED_BELL.awardTo(player); + return ring; + } + + @Override + public Class getBlockEntityClass() { + return HauntedBellBlockEntity.class; + } + + @Override + public void playSound(Level world, BlockPos pos) { + AllSoundEvents.HAUNTED_BELL_USE.playOnServer(world, pos, 4f, 1f); + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { + if (oldState.getBlock() != this && !world.isClientSide) + withBlockEntityDo(world, pos, hbte -> { + hbte.effectTicks = HauntedBellBlockEntity.EFFECT_TICKS; + hbte.sendData(); + }); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlockEntity.java new file mode 100644 index 0000000000..2cce88e489 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellBlockEntity.java @@ -0,0 +1,94 @@ +package com.simibubi.create.content.equipment.bell; + +import java.util.Random; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllPartialModels; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class HauntedBellBlockEntity extends AbstractBellBlockEntity { + + public static final int DISTANCE = 10; + public static final int RECHARGE_TICKS = 65; + public static final int EFFECT_TICKS = 20; + + public int effectTicks = 0; + + public HauntedBellBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + @OnlyIn(Dist.CLIENT) + public PartialModel getBellModel() { + return AllPartialModels.HAUNTED_BELL; + } + + @Override + public boolean ring(Level world, BlockPos pos, Direction direction) { + if (isRinging && ringingTicks < RECHARGE_TICKS) + return false; + HauntedBellPulser.sendPulse(world, pos, DISTANCE, false); + effectTicks = EFFECT_TICKS; + return super.ring(world, pos, direction); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("EffectTicks", effectTicks); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + effectTicks = compound.getInt("EffectTicks"); + } + + @Override + public void tick() { + super.tick(); + + if (effectTicks <= 0) + return; + effectTicks--; + + if (!level.isClientSide) + return; + + Random rand = level.getRandom(); + if (rand.nextFloat() > 0.25f) + return; + + spawnParticle(rand); + playSound(rand); + } + + protected void spawnParticle(Random rand) { + double x = worldPosition.getX() + rand.nextDouble(); + double y = worldPosition.getY() + 0.5; + double z = worldPosition.getZ() + rand.nextDouble(); + double vx = rand.nextDouble() * 0.04 - 0.02; + double vy = 0.1; + double vz = rand.nextDouble() * 0.04 - 0.02; + level.addParticle(ParticleTypes.SOUL, x, y, z, vx, vy, vz); + } + + protected void playSound(Random rand) { + float vol = rand.nextFloat() * 0.4F + rand.nextFloat() > 0.9F ? 0.6F : 0.0F; + float pitch = 0.6F + rand.nextFloat() * 0.4F; + level.playSound(null, worldPosition, SoundEvents.SOUL_ESCAPE, SoundSource.BLOCKS, vol, pitch); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellMovementBehaviour.java new file mode 100644 index 0000000000..239f8b9246 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellMovementBehaviour.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.equipment.bell; + +import com.simibubi.create.content.contraptions.behaviour.BellMovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; + +import net.minecraft.core.BlockPos; + +public class HauntedBellMovementBehaviour extends BellMovementBehaviour { + + public static final int DISTANCE = 3; + + @Override + public void tick(MovementContext context) { + int recharge = getRecharge(context); + if (recharge > 0) + setRecharge(context, recharge - 1); + } + + @Override + public void visitNewPosition(MovementContext context, BlockPos pos) { + if (!context.world.isClientSide && getRecharge(context) == 0) { + HauntedBellPulser.sendPulse(context.world, pos, DISTANCE, false); + setRecharge(context, HauntedBellBlockEntity.RECHARGE_TICKS); + playSound(context); + } + } + + @Override + public void writeExtraData(MovementContext context) { + context.blockEntityData.putInt("Recharge", getRecharge(context)); + } + + private int getRecharge(MovementContext context) { + if (!(context.temporaryData instanceof Integer) && context.world != null) { + context.temporaryData = context.blockEntityData.getInt("Recharge"); + } + return (Integer) context.temporaryData; + } + + private void setRecharge(MovementContext context, int value) { + context.temporaryData = value; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellPulser.java b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellPulser.java similarity index 91% rename from src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellPulser.java rename to src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellPulser.java index 57488fa7da..1d7e1e11b2 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/HauntedBellPulser.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/HauntedBellPulser.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -7,7 +7,7 @@ import java.util.concurrent.TimeUnit; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; import net.createmod.catnip.utility.IntAttached; import net.minecraft.core.BlockPos; @@ -62,7 +62,7 @@ public class HauntedBellPulser { public static void sendPulse(Level world, BlockPos pos, int distance, boolean canOverlap) { LevelChunk chunk = world.getChunkAt(pos); - AllPackets.channel.send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), + AllPackets.getChannel().send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), new SoulPulseEffectPacket(pos, distance, canOverlap)); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellBlock.java b/src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellBlock.java rename to src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlock.java index 4eea011d7e..157fbce242 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/PeculiarBellBlock.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -18,20 +18,20 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -public class PeculiarBellBlock extends AbstractBellBlock { +public class PeculiarBellBlock extends AbstractBellBlock { public PeculiarBellBlock(Properties properties) { super(properties); } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.PECULIAR_BELL.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.PECULIAR_BELL.get(); } @Override - public Class getTileEntityClass() { - return PeculiarBellTileEntity.class; + public Class getBlockEntityClass() { + return PeculiarBellBlockEntity.class; } @Override diff --git a/src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlockEntity.java new file mode 100644 index 0000000000..6cb81e2572 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/bell/PeculiarBellBlockEntity.java @@ -0,0 +1,24 @@ +package com.simibubi.create.content.equipment.bell; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllPartialModels; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class PeculiarBellBlockEntity extends AbstractBellBlockEntity { + + public PeculiarBellBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + @OnlyIn(Dist.CLIENT) + public PartialModel getBellModel() { + return AllPartialModels.PECULIAR_BELL; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulBaseParticle.java b/src/main/java/com/simibubi/create/content/equipment/bell/SoulBaseParticle.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/bell/SoulBaseParticle.java rename to src/main/java/com/simibubi/create/content/equipment/bell/SoulBaseParticle.java index 5c979d5c73..24bd614cca 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulBaseParticle.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/SoulBaseParticle.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulParticle.java b/src/main/java/com/simibubi/create/content/equipment/bell/SoulParticle.java similarity index 99% rename from src/main/java/com/simibubi/create/content/curiosities/bell/SoulParticle.java rename to src/main/java/com/simibubi/create/content/equipment/bell/SoulParticle.java index b878d51424..8f0db29f4c 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulParticle.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/SoulParticle.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Quaternion; diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffect.java b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffect.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffect.java rename to src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffect.java index bba8951f0b..28ddae56ec 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffect.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffect.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import java.util.ArrayList; import java.util.List; @@ -6,7 +6,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.collect.Streams; -import com.simibubi.create.content.curiosities.bell.SoulParticle.ExpandingPerimeterData; +import com.simibubi.create.content.equipment.bell.SoulParticle.ExpandingPerimeterData; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectHandler.java b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectHandler.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectHandler.java rename to src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectHandler.java index 99217687e1..93224e6aa0 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.bell; +package com.simibubi.create.content.equipment.bell; import java.util.ArrayList; import java.util.HashSet; diff --git a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectPacket.java b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectPacket.java similarity index 76% rename from src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectPacket.java rename to src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectPacket.java index 57d8bbccec..74652139aa 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/bell/SoulPulseEffectPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/bell/SoulPulseEffectPacket.java @@ -1,13 +1,11 @@ -package com.simibubi.create.content.curiosities.bell; - -import java.util.function.Supplier; +package com.simibubi.create.content.equipment.bell; import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.network.NetworkEvent.Context; public class SoulPulseEffectPacket extends SimplePacketBase { @@ -35,11 +33,11 @@ public class SoulPulseEffectPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { + public boolean handle(Context context) { + context.enqueueWork(() -> { CreateClient.SOUL_PULSE_EFFECT_HANDLER.addPulse(new SoulPulseEffect(pos, distance, canOverlap)); }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintAssignCompleteRecipePacket.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintAssignCompleteRecipePacket.java new file mode 100644 index 0000000000..707fb974f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintAssignCompleteRecipePacket.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.equipment.blueprint; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent.Context; + +public class BlueprintAssignCompleteRecipePacket extends SimplePacketBase { + + private ResourceLocation recipeID; + + public BlueprintAssignCompleteRecipePacket(ResourceLocation recipeID) { + this.recipeID = recipeID; + } + + public BlueprintAssignCompleteRecipePacket(FriendlyByteBuf buffer) { + recipeID = buffer.readResourceLocation(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeResourceLocation(recipeID); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + if (player.containerMenu instanceof BlueprintMenu) { + BlueprintMenu c = (BlueprintMenu) player.containerMenu; + player.getLevel() + .getRecipeManager() + .byKey(recipeID) + .ifPresent(r -> BlueprintItem.assignCompleteRecipe(c.ghostInventory, r)); + } + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java rename to src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java index 506a89d92a..b3c9ea70d4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintEntity.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.blueprint; import java.util.HashMap; import java.util.Map; @@ -12,10 +12,10 @@ import org.apache.commons.lang3.Validate; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.schematics.requirement.ISpecialEntityItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.networking.ISyncPersistentData; import com.simibubi.create.foundation.utility.IInteractionChecker; @@ -538,7 +538,7 @@ public class BlueprintEntity extends HangingEntity @Override public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { - return BlueprintContainer.create(id, inv, this); + return BlueprintMenu.create(id, inv, this); } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java rename to src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintItem.java index 0b278081cf..fb9791da33 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintItem.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.blueprint; import java.util.Collection; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintMenu.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintMenu.java new file mode 100644 index 0000000000..4aaf0bb39c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintMenu.java @@ -0,0 +1,179 @@ +package com.simibubi.create.content.equipment.blueprint; + +import java.util.Optional; + +import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.BlueprintSection; +import com.simibubi.create.foundation.gui.menu.GhostItemMenu; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class BlueprintMenu extends GhostItemMenu { + + public BlueprintMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public BlueprintMenu(MenuType type, int id, Inventory inv, BlueprintSection section) { + super(type, id, inv, section); + } + + public static BlueprintMenu create(int id, Inventory inv, BlueprintSection section) { + return new BlueprintMenu(AllMenuTypes.CRAFTING_BLUEPRINT.get(), id, inv, section); + } + + @Override + protected boolean allowRepeats() { + return true; + } + + @Override + protected void addSlots() { + addPlayerSlots(8, 131); + + int x = 29; + int y = 21; + int index = 0; + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 3; ++col) + this.addSlot(new BlueprintCraftSlot(ghostInventory, index++, x + col * 18, y + row * 18)); + + addSlot(new BlueprintCraftSlot(ghostInventory, index++, 123, 40)); + addSlot(new SlotItemHandler(ghostInventory, index++, 135, 57)); + } + + public void onCraftMatrixChanged() { + if (contentHolder.getBlueprintWorld().isClientSide) + return; + + ServerPlayer serverplayerentity = (ServerPlayer) player; + CraftingContainer craftingInventory = new BlueprintCraftingInventory(this, ghostInventory); + Optional optional = player.getServer() + .getRecipeManager() + .getRecipeFor(RecipeType.CRAFTING, craftingInventory, player.getCommandSenderWorld()); + + if (!optional.isPresent()) { + if (ghostInventory.getStackInSlot(9) + .isEmpty()) + return; + if (!contentHolder.inferredIcon) + return; + + ghostInventory.setStackInSlot(9, ItemStack.EMPTY); + serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, ItemStack.EMPTY)); + contentHolder.inferredIcon = false; + return; + } + + CraftingRecipe icraftingrecipe = optional.get(); + ItemStack itemstack = icraftingrecipe.assemble(craftingInventory); + ghostInventory.setStackInSlot(9, itemstack); + contentHolder.inferredIcon = true; + ItemStack toSend = itemstack.copy(); + toSend.getOrCreateTag() + .putBoolean("InferredFromRecipe", true); + serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, toSend)); + } + + @Override + public void setItem(int slotId, int stateId, ItemStack stack) { + if (slotId == 36 + 9) { + if (stack.hasTag()) { + contentHolder.inferredIcon = stack.getTag() + .getBoolean("InferredFromRecipe"); + stack.getTag() + .remove("InferredFromRecipe"); + } else + contentHolder.inferredIcon = false; + } + super.setItem(slotId, stateId, stack); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return contentHolder.getItems(); + } + + @Override + protected void initAndReadInventory(BlueprintSection contentHolder) { + super.initAndReadInventory(contentHolder); + } + + @Override + protected void saveData(BlueprintSection contentHolder) { + contentHolder.save(ghostInventory); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected BlueprintSection createOnClient(FriendlyByteBuf extraData) { + int entityID = extraData.readVarInt(); + int section = extraData.readVarInt(); + Entity entityByID = Minecraft.getInstance().level.getEntity(entityID); + if (!(entityByID instanceof BlueprintEntity)) + return null; + BlueprintEntity blueprintEntity = (BlueprintEntity) entityByID; + BlueprintSection blueprintSection = blueprintEntity.getSection(section); + return blueprintSection; + } + + @Override + public boolean stillValid(Player player) { + return contentHolder != null && contentHolder.canPlayerUse(player); + } + + static class BlueprintCraftingInventory extends CraftingContainer { + + public BlueprintCraftingInventory(AbstractContainerMenu menu, ItemStackHandler items) { + super(menu, 3, 3); + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 3; x++) { + ItemStack stack = items.getStackInSlot(y * 3 + x); + setItem(y * 3 + x, stack == null ? ItemStack.EMPTY : stack.copy()); + } + } + } + + } + + class BlueprintCraftSlot extends SlotItemHandler { + + private int index; + + public BlueprintCraftSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition) { + super(itemHandler, index, xPosition, yPosition); + this.index = index; + } + + @Override + public void setChanged() { + super.setChanged(); + if (index == 9 && hasItem() && !contentHolder.getBlueprintWorld().isClientSide) { + contentHolder.inferredIcon = false; + ServerPlayer serverplayerentity = (ServerPlayer) player; + serverplayerentity.connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 36 + 9, getItem())); + } + if (index < 9) + onCraftMatrixChanged(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java similarity index 93% rename from src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java index e8d2386926..a955a2dafe 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintOverlayRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.blueprint; import java.util.ArrayList; import java.util.HashMap; @@ -9,14 +9,13 @@ import java.util.Optional; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; -import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; -import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; +import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.BlueprintCraftingInventory; +import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.BlueprintSection; +import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.logistics.filter.ItemAttribute; +import com.simibubi.create.content.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.gui.AllGuiTextures; import net.createmod.catnip.gui.element.GuiGameElement; @@ -107,7 +106,7 @@ public class BlueprintOverlayRenderer { int tracks = info.requiredTracks; while (tracks > 0) { - ingredients.add(Pair.of(AllBlocks.TRACK.asStack(Math.min(64, tracks)), info.hasRequiredTracks)); + ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getBlock(), Math.min(64, tracks)), info.hasRequiredTracks)); tracks -= 64; } diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintRenderer.java similarity index 85% rename from src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintRenderer.java index c6529c49a4..3fdc962dd3 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintRenderer.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.blueprint; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.equipment.blueprint.BlueprintEntity.BlueprintSection; import com.simibubi.create.foundation.render.CachedPartialBuffers; import net.createmod.catnip.render.SuperByteBuffer; @@ -31,23 +31,18 @@ public class BlueprintRenderer extends EntityRenderer { @Override public void render(BlueprintEntity entity, float yaw, float pt, PoseStack ms, MultiBufferSource buffer, int light) { - PartialModel partialModel = entity.size == 3 ? AllBlockPartials.CRAFTING_BLUEPRINT_3x3 - : entity.size == 2 ? AllBlockPartials.CRAFTING_BLUEPRINT_2x2 : AllBlockPartials.CRAFTING_BLUEPRINT_1x1; + PartialModel partialModel = entity.size == 3 ? AllPartialModels.CRAFTING_BLUEPRINT_3x3 + : entity.size == 2 ? AllPartialModels.CRAFTING_BLUEPRINT_2x2 : AllPartialModels.CRAFTING_BLUEPRINT_1x1; SuperByteBuffer sbb = CachedPartialBuffers.partial(partialModel, Blocks.AIR.defaultBlockState()); - - sbb - .rotateY(-yaw) - .rotateX(90.0F + entity.getXRot()) - .translate(-.5, -1 / 32f, -.5); - + sbb.rotateY(-yaw) + .rotateX(90.0F + entity.getXRot()) + .translate(-.5, -1 / 32f, -.5); if (entity.size == 2) sbb.translate(.5, 0, -.5); - sbb - .forEntityRender() - .light(light) - .renderInto(ms, buffer.getBuffer(Sheets.solidBlockSheet())); - + sbb.forEntityRender() + .light(light) + .renderInto(ms, buffer.getBuffer(Sheets.solidBlockSheet())); super.render(entity, yaw, pt, ms, buffer, light); ms.pushPose(); diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintScreen.java similarity index 88% rename from src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java rename to src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintScreen.java index 09fedc9ff8..e67678bc5e 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/blueprint/BlueprintScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.blueprint; import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; @@ -8,15 +8,15 @@ import java.util.List; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.logistics.filter.FilterScreenPacket; +import com.simibubi.create.content.logistics.filter.FilterScreenPacket.Option; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.element.GuiGameElement; @@ -26,7 +26,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class BlueprintScreen extends AbstractSimiContainerScreen { +public class BlueprintScreen extends AbstractSimiContainerScreen { protected AllGuiTextures background; private List extraAreas = Collections.emptyList(); @@ -34,8 +34,8 @@ public class BlueprintScreen extends AbstractSimiContainerScreenat(x + background.getWidth() + 20, y + background.getHeight() - 32, 0) .rotate(45, -45, 22.5f) .scale(40) @@ -167,7 +167,7 @@ public class BlueprintScreen extends AbstractSimiContainerScreen, IWrenchable, ProperWaterloggedBlock { + + public static final BooleanProperty WRITTEN = BooleanProperty.create("written"); + + public ClipboardBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false) + .setValue(WRITTEN, false)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(WRITTEN, FACE, FACING, WATERLOGGED)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + BlockState stateForPlacement = super.getStateForPlacement(pContext); + if (stateForPlacement == null) + return null; + if (stateForPlacement.getValue(FACE) != AttachFace.WALL) + stateForPlacement = stateForPlacement.setValue(FACING, stateForPlacement.getValue(FACING) + .getOpposite()); + return withWater(stateForPlacement, pContext).setValue(WRITTEN, pContext.getItemInHand() + .hasTag()); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return (switch (pState.getValue(FACE)) { + case FLOOR -> AllShapes.CLIPBOARD_FLOOR; + case CEILING -> AllShapes.CLIPBOARD_CEILING; + default -> AllShapes.CLIPBOARD_WALL; + }).get(pState.getValue(FACING)); + } + + public boolean canSurvive(BlockState pState, LevelReader pLevel, BlockPos pPos) { + return !pLevel.getBlockState(pPos.relative(getConnectedDirection(pState).getOpposite())) + .getMaterial() + .isReplaceable(); + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + if (pPlayer.isSteppingCarefully()) { + breakAndCollect(pState, pLevel, pPos, pPlayer); + return InteractionResult.SUCCESS; + } + + return onBlockEntityUse(pLevel, pPos, cbe -> { + if (pLevel.isClientSide()) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(pPlayer, cbe.dataContainer, pPos)); + return InteractionResult.SUCCESS; + }); + } + + @OnlyIn(Dist.CLIENT) + private void openScreen(Player player, ItemStack stack, BlockPos pos) { + if (Minecraft.getInstance().player == player) + ScreenOpener.open(new ClipboardScreen(player.getInventory().selected, stack, pos)); + } + + @Override + public void attack(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) { + breakAndCollect(pState, pLevel, pPos, pPlayer); + } + + private void breakAndCollect(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) { + if (pPlayer instanceof FakePlayer) + return; + if (pLevel.isClientSide) + return; + ItemStack cloneItemStack = getCloneItemStack(pLevel, pPos, pState); + pLevel.destroyBlock(pPos, false); + if (pLevel.getBlockState(pPos) != pState) + pPlayer.getInventory() + .placeItemBackInInventory(cloneItemStack); + } + + @Override + public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) { + if (world.getBlockEntity(pos) instanceof ClipboardBlockEntity cbe) + return cbe.dataContainer; + return new ItemStack(this); + } + + @Override + public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { + if (!(pLevel.getBlockEntity(pPos) instanceof ClipboardBlockEntity cbe)) + return; + if (pLevel.isClientSide || pPlayer.isCreative()) + return; + Block.popResource(pLevel, pPos, cbe.dataContainer.copy()); + } + + @Override + @SuppressWarnings("deprecation") + public List getDrops(BlockState pState, LootContext.Builder pBuilder) { + if (!(pBuilder.getOptionalParameter(LootContextParams.BLOCK_ENTITY) instanceof ClipboardBlockEntity cbe)) + return super.getDrops(pState, pBuilder); + pBuilder.withDynamicDrop(ShulkerBoxBlock.CONTENTS, + (p_56218_, p_56219_) -> p_56219_.accept(cbe.dataContainer.copy())); + return ImmutableList.of(cbe.dataContainer.copy()); + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel, + BlockPos pCurrentPos, BlockPos pFacingPos) { + updateWater(pLevel, pState, pCurrentPos); + return super.updateShape(pState, pFacing, pFacingState, pLevel, pCurrentPos, pFacingPos); + } + + @Override + public Class getBlockEntityClass() { + return ClipboardBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CLIPBOARD.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockEntity.java new file mode 100644 index 0000000000..7d1afe661b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockEntity.java @@ -0,0 +1,89 @@ +package com.simibubi.create.content.equipment.clipboard; + +import java.util.List; +import java.util.UUID; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class ClipboardBlockEntity extends SmartBlockEntity { + + public ItemStack dataContainer; + private UUID lastEdit; + + public ClipboardBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + dataContainer = AllBlocks.CLIPBOARD.asStack(); + } + + @Override + public void initialize() { + super.initialize(); + updateWrittenState(); + } + + public void onEditedBy(Player player) { + lastEdit = player.getUUID(); + notifyUpdate(); + updateWrittenState(); + } + + public void updateWrittenState() { + BlockState blockState = getBlockState(); + if (!AllBlocks.CLIPBOARD.has(blockState)) + return; + if (level.isClientSide()) + return; + boolean isWritten = blockState.getValue(ClipboardBlock.WRITTEN); + boolean shouldBeWritten = dataContainer.getTag() != null; + if (isWritten == shouldBeWritten) + return; + level.setBlockAndUpdate(worldPosition, blockState.setValue(ClipboardBlock.WRITTEN, shouldBeWritten)); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + tag.put("Item", dataContainer.serializeNBT()); + if (clientPacket && lastEdit != null) + tag.putUUID("LastEdit", lastEdit); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + dataContainer = ItemStack.of(tag.getCompound("Item")); + + if (clientPacket) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> readClientSide(tag)); + } + + @OnlyIn(Dist.CLIENT) + private void readClientSide(CompoundTag tag) { + Minecraft mc = Minecraft.getInstance(); + if (!(mc.screen instanceof ClipboardScreen cs)) + return; + if (tag.contains("LastEdit") && tag.getUUID("LastEdit") + .equals(mc.player.getUUID())) + return; + if (!worldPosition.equals(cs.targetedBlock)) + return; + cs.reopenWith(dataContainer); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockItem.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockItem.java new file mode 100644 index 0000000000..306b61cacf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardBlockItem.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.equipment.clipboard; + +import javax.annotation.Nonnull; + +import net.createmod.catnip.gui.ScreenOpener; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.items.ItemHandlerHelper; + +public class ClipboardBlockItem extends BlockItem { + + public ClipboardBlockItem(Block pBlock, Properties pProperties) { + super(pBlock, pProperties); + } + + @Nonnull + @Override + public InteractionResult useOn(UseOnContext context) { + Player player = context.getPlayer(); + if (player == null) + return InteractionResult.PASS; + if (player.isSteppingCarefully()) + return super.useOn(context); + return use(context.getLevel(), player, context.getHand()).getResult(); + } + + @Override + protected boolean updateCustomBlockEntityTag(BlockPos pPos, Level pLevel, Player pPlayer, ItemStack pStack, + BlockState pState) { + if (pLevel.isClientSide()) + return false; + if (!(pLevel.getBlockEntity(pPos) instanceof ClipboardBlockEntity cbe)) + return false; + cbe.dataContainer = ItemHandlerHelper.copyStackWithSize(pStack, 1); + cbe.notifyUpdate(); + return true; + } + + @Override + public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { + ItemStack heldItem = player.getItemInHand(hand); + if (hand == InteractionHand.OFF_HAND) + return InteractionResultHolder.pass(heldItem); + + player.getCooldowns() + .addCooldown(heldItem.getItem(), 10); + if (world.isClientSide) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(player, heldItem)); + CompoundTag tag = heldItem.getOrCreateTag(); + tag.putInt("Type", ClipboardOverrides.ClipboardType.EDITING.ordinal()); + heldItem.setTag(tag); + + return InteractionResultHolder.success(heldItem); + } + + @OnlyIn(Dist.CLIENT) + private void openScreen(Player player, ItemStack stack) { + if (Minecraft.getInstance().player == player) + ScreenOpener.open(new ClipboardScreen(player.getInventory().selected, stack, null)); + } + + public void registerModelOverrides() { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClipboardOverrides.registerModelOverridesClient(this)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardCloneable.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardCloneable.java new file mode 100644 index 0000000000..fcd783b900 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardCloneable.java @@ -0,0 +1,15 @@ +package com.simibubi.create.content.equipment.clipboard; + +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; + +public interface ClipboardCloneable { + + public String getClipboardKey(); + + public boolean writeToClipboard(CompoundTag tag, Direction side); + + public boolean readFromClipboard(CompoundTag tag, Player player, Direction side, boolean simulate); + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEditPacket.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEditPacket.java new file mode 100644 index 0000000000..85a92e8ce4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEditPacket.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.equipment.clipboard; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ClipboardEditPacket extends SimplePacketBase { + + private int hotbarSlot; + private CompoundTag data; + private BlockPos targetedBlock; + + public ClipboardEditPacket(int hotbarSlot, CompoundTag data, @Nullable BlockPos targetedBlock) { + this.hotbarSlot = hotbarSlot; + this.data = data; + this.targetedBlock = targetedBlock; + } + + public ClipboardEditPacket(FriendlyByteBuf buffer) { + hotbarSlot = buffer.readVarInt(); + data = buffer.readNbt(); + if (buffer.readBoolean()) + targetedBlock = buffer.readBlockPos(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeVarInt(hotbarSlot); + buffer.writeNbt(data); + buffer.writeBoolean(targetedBlock != null); + if (targetedBlock != null) + buffer.writeBlockPos(targetedBlock); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + + if (targetedBlock != null) { + Level world = sender.level; + if (world == null || !world.isLoaded(targetedBlock)) + return; + if (!targetedBlock.closerThan(sender.blockPosition(), 20)) + return; + if (world.getBlockEntity(targetedBlock) instanceof ClipboardBlockEntity cbe) { + cbe.dataContainer.setTag(data.isEmpty() ? null : data); + cbe.onEditedBy(sender); + } + return; + } + + ItemStack itemStack = sender.getInventory() + .getItem(hotbarSlot); + if (!AllBlocks.CLIPBOARD.isIn(itemStack)) + return; + itemStack.setTag(data.isEmpty() ? null : data); + }); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEntry.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEntry.java new file mode 100644 index 0000000000..57e9cacf04 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardEntry.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.equipment.clipboard; + +import java.util.ArrayList; +import java.util.List; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; + +public class ClipboardEntry { + + public boolean checked; + public MutableComponent text; + public ItemStack icon; + + public ClipboardEntry(boolean checked, MutableComponent text) { + this.checked = checked; + this.text = text; + this.icon = ItemStack.EMPTY; + } + + public ClipboardEntry displayItem(ItemStack icon) { + this.icon = icon; + return this; + } + + public static List> readAll(ItemStack clipboardItem) { + CompoundTag tag = clipboardItem.getTag(); + if (tag == null) + return new ArrayList<>(); + return NBTHelper.readCompoundList(tag.getList("Pages", Tag.TAG_COMPOUND), pageTag -> NBTHelper + .readCompoundList(pageTag.getList("Entries", Tag.TAG_COMPOUND), ClipboardEntry::readNBT)); + } + + public static List getLastViewedEntries(ItemStack heldItem) { + List> pages = ClipboardEntry.readAll(heldItem); + if (pages.isEmpty()) + return new ArrayList<>(); + int page = heldItem.getTag() == null ? 0 + : Math.min(heldItem.getTag() + .getInt("PreviouslyOpenedPage"), pages.size() - 1); + List entries = pages.get(page); + return entries; + } + + public static void saveAll(List> entries, ItemStack clipboardItem) { + CompoundTag tag = clipboardItem.getOrCreateTag(); + tag.put("Pages", NBTHelper.writeCompoundList(entries, list -> { + CompoundTag pageTag = new CompoundTag(); + pageTag.put("Entries", NBTHelper.writeCompoundList(list, ClipboardEntry::writeNBT)); + return pageTag; + })); + } + + public CompoundTag writeNBT() { + CompoundTag nbt = new CompoundTag(); + nbt.putBoolean("Checked", checked); + nbt.putString("Text", Component.Serializer.toJson(text)); + if (icon.isEmpty()) + return nbt; + nbt.put("Icon", icon.serializeNBT()); + return nbt; + } + + public static ClipboardEntry readNBT(CompoundTag tag) { + ClipboardEntry clipboardEntry = + new ClipboardEntry(tag.getBoolean("Checked"), Component.Serializer.fromJson(tag.getString("Text"))); + if (tag.contains("Icon")) + clipboardEntry.displayItem(ItemStack.of(tag.getCompound("Icon"))); + return clipboardEntry; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardOverrides.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardOverrides.java new file mode 100644 index 0000000000..5d8cf71fe4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardOverrides.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.equipment.clipboard; + +import com.simibubi.create.Create; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateItemModelProvider; + +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.model.generators.ItemModelBuilder; +import net.minecraftforge.client.model.generators.ModelFile.UncheckedModelFile; + +public class ClipboardOverrides { + + public enum ClipboardType { + EMPTY("empty_clipboard"), WRITTEN("clipboard"), EDITING("clipboard_and_quill"); + + public String file; + public static ResourceLocation ID = Create.asResource("clipboard_type"); + + private ClipboardType(String file) { + this.file = file; + } + } + + public static void switchTo(ClipboardType type, ItemStack clipboardItem) { + CompoundTag tag = clipboardItem.getOrCreateTag(); + tag.putInt("Type", type.ordinal()); + } + + @OnlyIn(Dist.CLIENT) + public static void registerModelOverridesClient(ClipboardBlockItem item) { + ItemProperties.register(item, ClipboardType.ID, (pStack, pLevel, pEntity, pSeed) -> { + CompoundTag tag = pStack.getTag(); + return tag == null ? 0 : tag.getInt("Type"); + }); + } + + public static ItemModelBuilder addOverrideModels(DataGenContext c, + RegistrateItemModelProvider p) { + ItemModelBuilder builder = p.generated(() -> c.get()); + for (int i = 0; i < ClipboardType.values().length; i++) { + builder.override() + .predicate(ClipboardType.ID, i) + .model(p.getBuilder(c.getName() + "_" + i) + .parent(new UncheckedModelFile("item/generated")) + .texture("layer0", Create.asResource("item/" + ClipboardType.values()[i].file))) + .end(); + } + return builder; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardScreen.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardScreen.java new file mode 100644 index 0000000000..9e5892e564 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardScreen.java @@ -0,0 +1,840 @@ +package com.simibubi.create.content.equipment.clipboard; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.apache.commons.lang3.mutable.MutableInt; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.equipment.clipboard.ClipboardOverrides.ClipboardType; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.utility.CreateLang; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.SharedConstants; +import net.minecraft.Util; +import net.minecraft.client.StringSplitter; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.font.TextFieldHelper; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.PageButton; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class ClipboardScreen extends AbstractSimiScreen { + + public ItemStack item; + public BlockPos targetedBlock; + + List> pages; + List currentEntries; + int editingIndex; + int frameTick; + PageButton forward; + PageButton backward; + int currentPage; + long lastClickTime; + int lastIndex = -1; + + int hoveredEntry; + boolean hoveredCheck; + boolean readonly; + + DisplayCache displayCache = DisplayCache.EMPTY; + TextFieldHelper editContext; + + IconButton closeBtn; + IconButton clearBtn; + + private int targetSlot; + + public ClipboardScreen(int targetSlot, ItemStack item, @Nullable BlockPos pos) { + this.targetSlot = targetSlot; + this.targetedBlock = pos; + reopenWith(item); + } + + public void reopenWith(ItemStack clipboard) { + item = clipboard; + pages = ClipboardEntry.readAll(item); + if (pages.isEmpty()) + pages.add(new ArrayList<>()); + if (clearBtn == null) { + currentPage = item.getTag() == null ? 0 + : item.getTag() + .getInt("PreviouslyOpenedPage"); + currentPage = Mth.clamp(currentPage, 0, pages.size() - 1); + } + currentEntries = pages.get(currentPage); + boolean startEmpty = currentEntries.isEmpty(); + if (startEmpty) + currentEntries.add(new ClipboardEntry(false, Components.empty())); + editingIndex = 0; + editContext = new TextFieldHelper(this::getCurrentEntryText, this::setCurrentEntryText, this::getClipboard, + this::setClipboard, this::validateTextForEntry); + editingIndex = startEmpty ? 0 : -1; + readonly = item.getTag() != null && item.getTag() + .getBoolean("Readonly"); + if (readonly) + editingIndex = -1; + if (clearBtn != null) + init(); + } + + @Override + protected void init() { + setWindowSize(256, 256); + super.init(); + minecraft.keyboardHandler.setSendRepeatsToGui(true); + clearDisplayCache(); + + int x = guiLeft; + int y = guiTop - 8; + + clearWidgets(); + clearBtn = new IconButton(x + 234, y + 153, AllIcons.I_CLEAR_CHECKED).withCallback(() -> { + editingIndex = -1; + currentEntries.removeIf(ce -> ce.checked); + if (currentEntries.isEmpty()) + currentEntries.add(new ClipboardEntry(false, Components.empty())); + sendIfEditingBlock(); + }); + clearBtn.setToolTip(CreateLang.translateDirect("gui.clipboard.erase_checked")); + closeBtn = new IconButton(x + 234, y + 175, AllIcons.I_PRIORITY_VERY_LOW) + .withCallback(() -> minecraft.setScreen(null)); + closeBtn.setToolTip(CreateLang.translateDirect("station.close")); + addRenderableWidget(closeBtn); + addRenderableWidget(clearBtn); + + forward = new PageButton(x + 176, y + 229, true, $ -> changePage(true), true); + backward = new PageButton(x + 53, y + 229, false, $ -> changePage(false), true); + addRenderableWidget(forward); + addRenderableWidget(backward); + + forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size()); + backward.visible = currentPage > 0; + } + + private int getNumPages() { + return pages.size(); + } + + public void tick() { + super.tick(); + frameTick++; + + if (targetedBlock != null) { + if (!minecraft.player.blockPosition() + .closerThan(targetedBlock, 10)) { + removed(); + return; + } + if (!AllBlocks.CLIPBOARD.has(minecraft.level.getBlockState(targetedBlock))) { + removed(); + return; + } + } + + int mx = (int) (this.minecraft.mouseHandler.xpos() * (double) this.minecraft.getWindow() + .getGuiScaledWidth() / (double) this.minecraft.getWindow() + .getScreenWidth()); + int my = (int) (this.minecraft.mouseHandler.ypos() * (double) this.minecraft.getWindow() + .getGuiScaledHeight() / (double) this.minecraft.getWindow() + .getScreenHeight()); + + mx -= guiLeft + 35; + my -= guiTop + 41; + + hoveredCheck = false; + hoveredEntry = -1; + + if (mx > 0 && mx < 183 && my > 0 && my < 190) { + hoveredCheck = mx < 20; + int totalHeight = 0; + for (int i = 0; i < currentEntries.size(); i++) { + ClipboardEntry clipboardEntry = currentEntries.get(i); + String text = clipboardEntry.text.getString(); + totalHeight += + Math.max(12, font.split(Components.literal(text), clipboardEntry.icon.isEmpty() ? 150 : 130) + .size() * 9 + 3); + + if (totalHeight > my) { + hoveredEntry = i; + return; + } + } + hoveredEntry = currentEntries.size(); + } + } + + private String getCurrentEntryText() { + return currentEntries.get(editingIndex).text.getString(); + } + + private void setCurrentEntryText(String text) { + currentEntries.get(editingIndex).text = Components.literal(text); + sendIfEditingBlock(); + } + + private void setClipboard(String p_98148_) { + if (minecraft != null) + TextFieldHelper.setClipboardContents(minecraft, p_98148_); + } + + private String getClipboard() { + return minecraft != null ? TextFieldHelper.getClipboardContents(minecraft) : ""; + } + + private boolean validateTextForEntry(String newText) { + int totalHeight = 0; + for (int i = 0; i < currentEntries.size(); i++) { + ClipboardEntry clipboardEntry = currentEntries.get(i); + String text = i == editingIndex ? newText : clipboardEntry.text.getString(); + totalHeight += Math.max(12, font.split(Components.literal(text), 150) + .size() * 9 + 3); + } + return totalHeight < 185; + } + + private int yOffsetOfEditingEntry() { + int totalHeight = 0; + for (int i = 0; i < currentEntries.size(); i++) { + if (i == editingIndex) + break; + ClipboardEntry clipboardEntry = currentEntries.get(i); + totalHeight += Math.max(12, font.split(clipboardEntry.text, 150) + .size() * 9 + 3); + } + return totalHeight; + } + + private void changePage(boolean next) { + int previously = currentPage; + currentPage = Mth.clamp(currentPage + (next ? 1 : -1), 0, 50); + if (currentPage == previously) + return; + editingIndex = -1; + if (pages.size() <= currentPage) { + if (readonly) { + currentPage = previously; + return; + } + pages.add(new ArrayList<>()); + } + currentEntries = pages.get(currentPage); + if (currentEntries.isEmpty()) { + currentEntries.add(new ClipboardEntry(false, Components.empty())); + if (!readonly) { + editingIndex = 0; + editContext.setCursorToEnd(); + clearDisplayCacheAfterChange(); + } + } + + forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size()); + backward.visible = currentPage > 0; + + if (next) + return; + if (pages.get(currentPage + 1) + .stream() + .allMatch(ce -> ce.text.getString() + .isBlank())) + pages.remove(currentPage + 1); + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop - 8; + + AllGuiTextures.CLIPBOARD.render(ms, x, y); + font.draw(ms, new TranslatableComponent("book.pageIndicator", currentPage + 1, getNumPages()), x + 150, y + 9, + 0x43ffffff); + + for (int i = 0; i < currentEntries.size(); i++) { + ClipboardEntry clipboardEntry = currentEntries.get(i); + boolean checked = clipboardEntry.checked; + int iconOffset = clipboardEntry.icon.isEmpty() ? 0 : 16; + + font.draw(ms, "\u25A1", x + 45, y + 51, checked ? 0x668D7F6B : 0xff8D7F6B); + if (checked) + font.draw(ms, "\u2714", x + 45, y + 50, 0x31B25D); + + List split = font.split(clipboardEntry.text, 150 - iconOffset); + if (split.isEmpty()) { + y += 12; + continue; + } + + if (!clipboardEntry.icon.isEmpty()) + itemRenderer.renderGuiItem(clipboardEntry.icon, x + 54, y + 50); + + for (FormattedCharSequence sequence : split) { + if (i != editingIndex) + font.draw(ms, sequence, x + 58 + iconOffset, y + 50, checked ? 0x31B25D : 0x311A00); + y += 9; + } + y += 3; + } + + if (editingIndex == -1) + return; + + boolean checked = currentEntries.get(editingIndex).checked; + + setFocused(null); + DisplayCache cache = getDisplayCache(); + + for (LineInfo line : cache.lines) + font.draw(ms, line.asComponent, line.x, line.y, checked ? 0x31B25D : 0x311A00); + + renderHighlight(cache.selection); + renderCursor(ms, cache.cursor, cache.cursorAtEnd); + } + + @Override + public void removed() { + minecraft.keyboardHandler.setSendRepeatsToGui(false); + pages.forEach(list -> list.removeIf(ce -> ce.text.getString() + .isBlank())); + pages.removeIf(List::isEmpty); + + for (int i = 0; i < pages.size(); i++) + if (pages.get(i) == currentEntries) + item.getOrCreateTag() + .putInt("PreviouslyOpenedPage", i); + + send(); + + super.removed(); + } + + private void sendIfEditingBlock() { + ClientPacketListener handler = minecraft.player.connection; + if (handler.getOnlinePlayers() + .size() > 1 && targetedBlock != null) + send(); + } + + private void send() { + ClipboardEntry.saveAll(pages, item); + ClipboardOverrides.switchTo(ClipboardType.WRITTEN, item); + if (pages.isEmpty()) + item.setTag(new CompoundTag()); + AllPackets.getChannel() + .sendToServer(new ClipboardEditPacket(targetSlot, item.getOrCreateTag(), targetedBlock)); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) { + changePage(pDelta < 0); + return true; + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + if (pKeyCode == 266) { + backward.onPress(); + return true; + } + if (pKeyCode == 267) { + forward.onPress(); + return true; + } + if (editingIndex != -1 && pKeyCode != 256) { + keyPressedWhileEditing(pKeyCode, pScanCode, pModifiers); + clearDisplayCache(); + return true; + } + if (super.keyPressed(pKeyCode, pScanCode, pModifiers)) + return true; + return true; + } + + @Override + public boolean charTyped(char pCodePoint, int pModifiers) { + if (super.charTyped(pCodePoint, pModifiers)) + return true; + if (!SharedConstants.isAllowedChatCharacter(pCodePoint)) + return false; + if (editingIndex == -1) + return false; + editContext.insertText(Character.toString(pCodePoint)); + clearDisplayCache(); + return true; + } + + private boolean keyPressedWhileEditing(int pKeyCode, int pScanCode, int pModifiers) { + if (Screen.isSelectAll(pKeyCode)) { + editContext.selectAll(); + return true; + } else if (Screen.isCopy(pKeyCode)) { + editContext.copy(); + return true; + } else if (Screen.isPaste(pKeyCode)) { + editContext.paste(); + return true; + } else if (Screen.isCut(pKeyCode)) { + editContext.cut(); + return true; + } else { + switch (pKeyCode) { + case 257: + case 335: + if (hasShiftDown()) { + editContext.insertText("\n"); + return true; + } else if (!hasControlDown()) { + if (currentEntries.size() <= editingIndex + 1 + || !currentEntries.get(editingIndex + 1).text.getString() + .isEmpty()) + currentEntries.add(editingIndex + 1, new ClipboardEntry(false, Components.empty())); + editingIndex += 1; + editContext.setCursorToEnd(); + if (validateTextForEntry(" ")) + return true; + currentEntries.remove(editingIndex); + editingIndex -= 1; + editContext.setCursorToEnd(); + return true; + } + editingIndex = -1; + return true; + case 259: + if (currentEntries.get(editingIndex).text.getString() + .isEmpty() && currentEntries.size() > 1) { + currentEntries.remove(editingIndex); + editingIndex = Math.max(0, editingIndex - 1); + editContext.setCursorToEnd(); + return true; + } else if (hasControlDown()) { + int prevPos = editContext.getCursorPos(); + editContext.moveByWords(-1); + if (prevPos != editContext.getCursorPos()) + editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos()); + return true; + } + editContext.removeCharsFromCursor(-1); + return true; + case 261: + if (hasControlDown()) { + int prevPos = editContext.getCursorPos(); + editContext.moveByWords(1); + if (prevPos != editContext.getCursorPos()) + editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos()); + return true; + } + editContext.removeCharsFromCursor(1); + return true; + case 262: + if (hasControlDown()) { + editContext.moveByWords(1, Screen.hasShiftDown()); + return true; + } + editContext.moveByChars(1, Screen.hasShiftDown()); + return true; + case 263: + if (hasControlDown()) { + editContext.moveByWords(-1, Screen.hasShiftDown()); + return true; + } + editContext.moveByChars(-1, Screen.hasShiftDown()); + return true; + case 264: + keyDown(); + return true; + case 265: + keyUp(); + return true; + case 268: + keyHome(); + return true; + case 269: + keyEnd(); + return true; + default: + return false; + } + } + } + + private void keyUp() { + changeLine(-1); + } + + private void keyDown() { + changeLine(1); + } + + private void changeLine(int pYChange) { + int i = editContext.getCursorPos(); + int j = getDisplayCache().changeLine(i, pYChange); + editContext.setCursorPos(j, Screen.hasShiftDown()); + } + + private void keyHome() { + int i = editContext.getCursorPos(); + int j = getDisplayCache().findLineStart(i); + editContext.setCursorPos(j, Screen.hasShiftDown()); + } + + private void keyEnd() { + DisplayCache cache = getDisplayCache(); + int i = editContext.getCursorPos(); + int j = cache.findLineEnd(i); + editContext.setCursorPos(j, Screen.hasShiftDown()); + } + + private void renderCursor(PoseStack pPoseStack, Pos2i pCursorPos, boolean pIsEndOfText) { + if (frameTick / 6 % 2 != 0) + return; + pCursorPos = convertLocalToScreen(pCursorPos); + if (!pIsEndOfText) { + GuiComponent.fill(pPoseStack, pCursorPos.x, pCursorPos.y - 1, pCursorPos.x + 1, pCursorPos.y + 9, + -16777216); + } else { + font.draw(pPoseStack, "_", (float) pCursorPos.x, (float) pCursorPos.y, 0); + } + } + + private void renderHighlight(Rect2i[] pSelected) { + Tesselator tesselator = Tesselator.getInstance(); + BufferBuilder bufferbuilder = tesselator.getBuilder(); + RenderSystem.setShader(GameRenderer::getPositionShader); + RenderSystem.setShaderColor(0.0F, 0.0F, 255.0F, 255.0F); + RenderSystem.disableTexture(); + RenderSystem.enableColorLogicOp(); + RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION); + + for (Rect2i rect2i : pSelected) { + int i = rect2i.getX(); + int j = rect2i.getY(); + int k = i + rect2i.getWidth(); + int l = j + rect2i.getHeight(); + bufferbuilder.vertex((double) i, (double) l, 0.0D) + .endVertex(); + bufferbuilder.vertex((double) k, (double) l, 0.0D) + .endVertex(); + bufferbuilder.vertex((double) k, (double) j, 0.0D) + .endVertex(); + bufferbuilder.vertex((double) i, (double) j, 0.0D) + .endVertex(); + } + + tesselator.end(); + RenderSystem.disableColorLogicOp(); + RenderSystem.enableTexture(); + } + + private Pos2i convertScreenToLocal(Pos2i pScreenPos) { + return new Pos2i(pScreenPos.x - (width - 192) / 2 - 36 + 10, + pScreenPos.y - 32 - 24 - yOffsetOfEditingEntry() - guiTop + 14); + } + + private Pos2i convertLocalToScreen(Pos2i pLocalScreenPos) { + return new Pos2i(pLocalScreenPos.x + (width - 192) / 2 + 36 - 10, + pLocalScreenPos.y + 32 + 24 + yOffsetOfEditingEntry() + guiTop - 14); + } + + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { + if (super.mouseClicked(pMouseX, pMouseY, pButton)) + return true; + if (pButton != 0) + return true; + + if (hoveredEntry != -1) { + if (hoveredCheck) { + editingIndex = -1; + if (hoveredEntry < currentEntries.size()) + currentEntries.get(hoveredEntry).checked ^= true; + sendIfEditingBlock(); + return true; + } + + if (hoveredEntry != editingIndex && !readonly) { + editingIndex = hoveredEntry; + if (hoveredEntry >= currentEntries.size()) { + currentEntries.add(new ClipboardEntry(false, Components.empty())); + if (!validateTextForEntry(" ")) { + currentEntries.remove(hoveredEntry); + editingIndex = -1; + return true; + } + } + clearDisplayCacheAfterChange(); + } + } + + if (editingIndex == -1) + return false; + + long i = Util.getMillis(); + DisplayCache cache = getDisplayCache(); + int j = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY))); + if (j >= 0) { + if (j == lastIndex && i - lastClickTime < 250L) { + if (!editContext.isSelecting()) { + selectWord(j); + } else { + editContext.selectAll(); + } + } else { + editContext.setCursorPos(j, Screen.hasShiftDown()); + } + + clearDisplayCache(); + } + + lastIndex = j; + lastClickTime = i; + return true; + } + + private void selectWord(int pIndex) { + String s = getCurrentEntryText(); + editContext.setSelectionRange(StringSplitter.getWordPosition(s, -1, pIndex, false), + StringSplitter.getWordPosition(s, 1, pIndex, false)); + } + + public boolean mouseDragged(double pMouseX, double pMouseY, int pButton, double pDragX, double pDragY) { + if (super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY)) + return true; + if (pButton != 0) + return true; + if (editingIndex == -1) + return false; + + DisplayCache cache = getDisplayCache(); + int i = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY))); + editContext.setCursorPos(i, true); + clearDisplayCache(); + return true; + } + + private DisplayCache getDisplayCache() { + if (displayCache == null) + displayCache = rebuildDisplayCache(); + return displayCache; + } + + private void clearDisplayCache() { + displayCache = null; + } + + private void clearDisplayCacheAfterChange() { + editContext.setCursorToEnd(); + clearDisplayCache(); + } + + private DisplayCache rebuildDisplayCache() { + String s = getCurrentEntryText(); + if (s.isEmpty()) + return DisplayCache.EMPTY; + + int i = editContext.getCursorPos(); + int j = editContext.getSelectionPos(); + IntList intlist = new IntArrayList(); + List list = Lists.newArrayList(); + MutableInt mutableint = new MutableInt(); + MutableBoolean mutableboolean = new MutableBoolean(); + StringSplitter stringsplitter = font.getSplitter(); + stringsplitter.splitLines(s, 150, Style.EMPTY, true, (p_98132_, p_98133_, p_98134_) -> { + int k3 = mutableint.getAndIncrement(); + String s2 = s.substring(p_98133_, p_98134_); + mutableboolean.setValue(s2.endsWith("\n")); + String s3 = StringUtils.stripEnd(s2, " \n"); + int l3 = k3 * 9; + Pos2i pos1 = convertLocalToScreen(new Pos2i(0, l3)); + intlist.add(p_98133_); + list.add(new LineInfo(p_98132_, s3, pos1.x, pos1.y)); + }); + + int[] aint = intlist.toIntArray(); + boolean flag = i == s.length(); + Pos2i pos; + if (flag && mutableboolean.isTrue()) { + pos = new Pos2i(0, list.size() * 9); + } else { + int k = findLineFromPos(aint, i); + int l = font.width(s.substring(aint[k], i)); + pos = new Pos2i(l, k * 9); + } + + List list1 = Lists.newArrayList(); + if (i != j) { + int l2 = Math.min(i, j); + int i1 = Math.max(i, j); + int j1 = findLineFromPos(aint, l2); + int k1 = findLineFromPos(aint, i1); + if (j1 == k1) { + int l1 = j1 * 9; + int i2 = aint[j1]; + list1.add(createPartialLineSelection(s, stringsplitter, l2, i1, l1, i2)); + } else { + int i3 = j1 + 1 > aint.length ? s.length() : aint[j1 + 1]; + list1.add(createPartialLineSelection(s, stringsplitter, l2, i3, j1 * 9, aint[j1])); + + for (int j3 = j1 + 1; j3 < k1; ++j3) { + int j2 = j3 * 9; + String s1 = s.substring(aint[j3], aint[j3 + 1]); + int k2 = (int) stringsplitter.stringWidth(s1); + list1.add(createSelection(new Pos2i(0, j2), new Pos2i(k2, j2 + 9))); + } + + list1.add(createPartialLineSelection(s, stringsplitter, aint[k1], i1, k1 * 9, aint[k1])); + } + } + + return new DisplayCache(s, pos, flag, aint, list.toArray(new LineInfo[0]), list1.toArray(new Rect2i[0])); + } + + static int findLineFromPos(int[] pLineStarts, int pFind) { + int i = Arrays.binarySearch(pLineStarts, pFind); + return i < 0 ? -(i + 2) : i; + } + + private Rect2i createPartialLineSelection(String pInput, StringSplitter pSplitter, int p_98122_, int p_98123_, + int p_98124_, int p_98125_) { + String s = pInput.substring(p_98125_, p_98122_); + String s1 = pInput.substring(p_98125_, p_98123_); + Pos2i firstPos = new Pos2i((int) pSplitter.stringWidth(s), p_98124_); + Pos2i secondPos = new Pos2i((int) pSplitter.stringWidth(s1), p_98124_ + 9); + return createSelection(firstPos, secondPos); + } + + private Rect2i createSelection(Pos2i pCorner1, Pos2i pCorner2) { + Pos2i firstPos = convertLocalToScreen(pCorner1); + Pos2i secondPos = convertLocalToScreen(pCorner2); + int i = Math.min(firstPos.x, secondPos.x); + int j = Math.max(firstPos.x, secondPos.x); + int k = Math.min(firstPos.y, secondPos.y); + int l = Math.max(firstPos.y, secondPos.y); + return new Rect2i(i, k, j - i, l - k); + } + + @OnlyIn(Dist.CLIENT) + static class DisplayCache { + static final DisplayCache EMPTY = new DisplayCache("", new Pos2i(0, 0), true, new int[] { 0 }, + new LineInfo[] { new LineInfo(Style.EMPTY, "", 0, 0) }, new Rect2i[0]); + private final String fullText; + final Pos2i cursor; + final boolean cursorAtEnd; + private final int[] lineStarts; + final LineInfo[] lines; + final Rect2i[] selection; + + public DisplayCache(String pFullText, Pos2i pCursor, boolean pCursorAtEnd, int[] pLineStarts, LineInfo[] pLines, + Rect2i[] pSelection) { + fullText = pFullText; + cursor = pCursor; + cursorAtEnd = pCursorAtEnd; + lineStarts = pLineStarts; + lines = pLines; + selection = pSelection; + } + + public int getIndexAtPosition(Font pFont, Pos2i pCursorPosition) { + int i = pCursorPosition.y / 9; + if (i < 0) + return 0; + if (i >= lines.length) + return fullText.length(); + LineInfo line = lines[i]; + return lineStarts[i] + pFont.getSplitter() + .plainIndexAtWidth(line.contents, pCursorPosition.x, line.style); + } + + public int changeLine(int pXChange, int pYChange) { + int i = findLineFromPos(lineStarts, pXChange); + int j = i + pYChange; + int k; + if (0 <= j && j < lineStarts.length) { + int l = pXChange - lineStarts[i]; + int i1 = lines[j].contents.length(); + k = lineStarts[j] + Math.min(l, i1); + } else { + k = pXChange; + } + + return k; + } + + public int findLineStart(int pLine) { + int i = findLineFromPos(lineStarts, pLine); + return lineStarts[i]; + } + + public int findLineEnd(int pLine) { + int i = findLineFromPos(lineStarts, pLine); + return lineStarts[i] + lines[i].contents.length(); + } + } + + @OnlyIn(Dist.CLIENT) + static class LineInfo { + final Style style; + final String contents; + final Component asComponent; + final int x; + final int y; + + public LineInfo(Style pStyle, String pContents, int pX, int pY) { + style = pStyle; + contents = pContents; + x = pX; + y = pY; + asComponent = (new TextComponent(pContents)).setStyle(pStyle); + } + } + + @OnlyIn(Dist.CLIENT) + static class Pos2i { + public final int x; + public final int y; + + Pos2i(int pX, int pY) { + x = pX; + y = pY; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardValueSettingsHandler.java b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardValueSettingsHandler.java new file mode 100644 index 0000000000..cf752b2d6f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/clipboard/ClipboardValueSettingsHandler.java @@ -0,0 +1,214 @@ +package com.simibubi.create.content.equipment.clipboard; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.equipment.clipboard.ClipboardOverrides.ClipboardType; +import com.simibubi.create.content.trains.track.TrackBlockOutline; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.DrawSelectionEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class ClipboardValueSettingsHandler { + + @SubscribeEvent + @OnlyIn(Dist.CLIENT) + public static void drawCustomBlockSelection(DrawSelectionEvent.HighlightBlock event) { + Minecraft mc = Minecraft.getInstance(); + BlockHitResult target = event.getTarget(); + BlockPos pos = target.getBlockPos(); + BlockState blockstate = mc.level.getBlockState(pos); + + if (mc.player == null || mc.player.isSpectator()) + return; + if (!mc.level.getWorldBorder() + .isWithinBounds(pos)) + return; + if (!AllBlocks.CLIPBOARD.isIn(mc.player.getMainHandItem())) + return; + if (!(mc.level.getBlockEntity(pos) instanceof SmartBlockEntity smartBE)) + return; + if (!smartBE.getAllBehaviours() + .stream() + .anyMatch(b -> b instanceof ClipboardCloneable cc + && cc.writeToClipboard(new CompoundTag(), target.getDirection()))) + return; + + VoxelShape shape = blockstate.getShape(mc.level, pos); + if (shape.isEmpty()) + return; + + VertexConsumer vb = event.getMultiBufferSource() + .getBuffer(RenderType.lines()); + Vec3 camPos = event.getCamera() + .getPosition(); + + PoseStack ms = event.getPoseStack(); + + ms.pushPose(); + ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z); + TrackBlockOutline.renderShape(shape, ms, vb, true); + event.setCanceled(true); + + ms.popPose(); + } + + @OnlyIn(Dist.CLIENT) + public static void clientTick() { + Minecraft mc = Minecraft.getInstance(); + if (!(mc.hitResult instanceof BlockHitResult target)) + return; + if (!AllBlocks.CLIPBOARD.isIn(mc.player.getMainHandItem())) + return; + BlockPos pos = target.getBlockPos(); + if (!(mc.level.getBlockEntity(pos) instanceof SmartBlockEntity smartBE)) + return; + + CompoundTag tagElement = mc.player.getMainHandItem() + .getTagElement("CopiedValues"); + + boolean canCopy = smartBE.getAllBehaviours() + .stream() + .anyMatch(b -> b instanceof ClipboardCloneable cc + && cc.writeToClipboard(new CompoundTag(), target.getDirection())) + || smartBE instanceof ClipboardCloneable ccbe + && ccbe.writeToClipboard(new CompoundTag(), target.getDirection()); + + boolean canPaste = tagElement != null && (smartBE.getAllBehaviours() + .stream() + .anyMatch(b -> b instanceof ClipboardCloneable cc && cc.readFromClipboard( + tagElement.getCompound(cc.getClipboardKey()), mc.player, target.getDirection(), true)) + || smartBE instanceof ClipboardCloneable ccbe && ccbe.readFromClipboard( + tagElement.getCompound(ccbe.getClipboardKey()), mc.player, target.getDirection(), true)); + + if (!canCopy && !canPaste) + return; + + List tip = new ArrayList<>(); + tip.add(CreateLang.translateDirect("clipboard.actions")); + if (canCopy) + tip.add(CreateLang.translateDirect("clipboard.to_copy", Components.keybind("key.use"))); + if (canPaste) + tip.add(CreateLang.translateDirect("clipboard.to_paste", Components.keybind("key.attack"))); + + CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip); + } + + @SubscribeEvent + public static void rightClickToCopy(PlayerInteractEvent.RightClickBlock event) { + interact(event, false); + } + + @SubscribeEvent + public static void leftClickToPaste(PlayerInteractEvent.LeftClickBlock event) { + interact(event, true); + } + + private static void interact(PlayerInteractEvent event, boolean paste) { + ItemStack itemStack = event.getItemStack(); + if (!AllBlocks.CLIPBOARD.isIn(itemStack)) + return; + + BlockPos pos = event.getPos(); + Level world = event.getWorld(); + Player player = event.getPlayer(); + if (player != null && player.isSpectator()) + return; + if (player.isSteppingCarefully()) + return; + if (!(world.getBlockEntity(pos) instanceof SmartBlockEntity smartBE)) + return; + CompoundTag tag = itemStack.getTagElement("CopiedValues"); + if (paste && tag == null) + return; + if (!paste) + tag = new CompoundTag(); + + boolean anySuccess = false; + boolean anyValid = false; + for (BlockEntityBehaviour behaviour : smartBE.getAllBehaviours()) { + if (!(behaviour instanceof ClipboardCloneable cc)) + continue; + anyValid = true; + String clipboardKey = cc.getClipboardKey(); + if (paste) { + anySuccess |= + cc.readFromClipboard(tag.getCompound(clipboardKey), player, event.getFace(), world.isClientSide()); + continue; + } + CompoundTag compoundTag = new CompoundTag(); + boolean success = cc.writeToClipboard(compoundTag, event.getFace()); + anySuccess |= success; + if (success) + tag.put(clipboardKey, compoundTag); + } + + if (smartBE instanceof ClipboardCloneable ccbe) { + anyValid = true; + String clipboardKey = ccbe.getClipboardKey(); + if (paste) { + anySuccess |= ccbe.readFromClipboard(tag.getCompound(clipboardKey), player, event.getFace(), + world.isClientSide()); + } else { + CompoundTag compoundTag = new CompoundTag(); + boolean success = ccbe.writeToClipboard(compoundTag, event.getFace()); + anySuccess |= success; + if (success) + tag.put(clipboardKey, compoundTag); + } + } + + if (!anyValid) + return; + + event.setCanceled(true); + event.setCancellationResult(InteractionResult.SUCCESS); + + if (world.isClientSide()) + return; + if (!anySuccess) + return; + + player.displayClientMessage(CreateLang + .translate(paste ? "clipboard.pasted_to" : "clipboard.copied_from", world.getBlockState(pos) + .getBlock() + .getName() + .withStyle(ChatFormatting.WHITE)) + .style(ChatFormatting.GREEN) + .component(), true); + + if (!paste) { + ClipboardOverrides.switchTo(ClipboardType.WRITTEN, itemStack); + itemStack.getOrCreateTag() + .put("CopiedValues", tag); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripInteractionPacket.java b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripInteractionPacket.java new file mode 100644 index 0000000000..9df32850af --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripInteractionPacket.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.equipment.extendoGrip; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ExtendoGripInteractionPacket extends SimplePacketBase { + + private InteractionHand interactionHand; + private int target; + private Vec3 specificPoint; + + public ExtendoGripInteractionPacket(Entity target) { + this(target, null); + } + + public ExtendoGripInteractionPacket(Entity target, InteractionHand hand) { + this(target, hand, null); + } + + public ExtendoGripInteractionPacket(Entity target, InteractionHand hand, Vec3 specificPoint) { + interactionHand = hand; + this.specificPoint = specificPoint; + this.target = target.getId(); + } + + public ExtendoGripInteractionPacket(FriendlyByteBuf buffer) { + target = buffer.readInt(); + int handId = buffer.readInt(); + interactionHand = handId == -1 ? null : InteractionHand.values()[handId]; + if (buffer.readBoolean()) + specificPoint = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(target); + buffer.writeInt(interactionHand == null ? -1 : interactionHand.ordinal()); + buffer.writeBoolean(specificPoint != null); + if (specificPoint != null) { + buffer.writeDouble(specificPoint.x); + buffer.writeDouble(specificPoint.y); + buffer.writeDouble(specificPoint.z); + } + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + if (sender == null) + return; + Entity entityByID = sender.getLevel() + .getEntity(target); + if (entityByID != null && ExtendoGripItem.isHoldingExtendoGrip(sender)) { + double d = sender.getAttribute(ForgeMod.REACH_DISTANCE.get()) + .getValue(); + if (!sender.hasLineOfSight(entityByID)) + d -= 3; + d *= d; + if (sender.distanceToSqr(entityByID) > d) + return; + if (interactionHand == null) + sender.attack(entityByID); + else if (specificPoint == null) + sender.interactOn(entityByID, interactionHand); + else + entityByID.interactAt(sender, specificPoint, interactionHand); + } + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java rename to src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItem.java index 126a79bc94..3ff6492e4e 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.extendoGrip; import java.util.UUID; import java.util.function.Consumer; @@ -8,11 +8,11 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.simibubi.create.AllItems; -import com.simibubi.create.content.curiosities.armor.BackTankUtil; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.equipment.armor.BacktankUtil; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; @@ -205,27 +205,27 @@ public class ExtendoGripItem extends Item { if (!AllItems.EXTENDO_GRIP.isIn(extendo)) return; final InteractionHand h = hand; - if (!BackTankUtil.canAbsorbDamage(player, maxUses())) + if (!BacktankUtil.canAbsorbDamage(player, maxUses())) extendo.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(h)); } @Override public boolean isBarVisible(ItemStack stack) { - return BackTankUtil.isBarVisible(stack, maxUses()); + return BacktankUtil.isBarVisible(stack, maxUses()); } @Override public int getBarWidth(ItemStack stack) { - return BackTankUtil.getBarWidth(stack, maxUses()); + return BacktankUtil.getBarWidth(stack, maxUses()); } @Override public int getBarColor(ItemStack stack) { - return BackTankUtil.getBarColor(stack, maxUses()); + return BacktankUtil.getBarColor(stack, maxUses()); } private static int maxUses() { - return AllConfigs.SERVER.curiosities.maxExtendoGripActions.get(); + return AllConfigs.server().equipment.maxExtendoGripActions.get(); } @SubscribeEvent @@ -274,7 +274,7 @@ public class ExtendoGripItem extends Item { return; Player player = (Player) entity; if (isHoldingExtendoGrip(player)) - AllPackets.channel.sendToServer(new ExtendoGripInteractionPacket(target)); + AllPackets.getChannel().sendToServer(new ExtendoGripInteractionPacket(target)); } @SubscribeEvent @@ -286,7 +286,7 @@ public class ExtendoGripItem extends Item { return; Player player = (Player) entity; if (isHoldingExtendoGrip(player)) - AllPackets.channel.sendToServer(new ExtendoGripInteractionPacket(target, event.getHand())); + AllPackets.getChannel().sendToServer(new ExtendoGripInteractionPacket(target, event.getHand())); } @SubscribeEvent @@ -298,7 +298,7 @@ public class ExtendoGripItem extends Item { return; Player player = (Player) entity; if (isHoldingExtendoGrip(player)) - AllPackets.channel + AllPackets.getChannel() .sendToServer(new ExtendoGripInteractionPacket(target, event.getHand(), event.getLocalPos())); } diff --git a/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItemRenderer.java new file mode 100644 index 0000000000..9c4d364e7e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripItemRenderer.java @@ -0,0 +1,119 @@ +package com.simibubi.create.content.equipment.extendoGrip; + +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; +import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public class ExtendoGripItemRenderer extends CustomRenderedItemModelRenderer { + + protected static final PartialModel COG = new PartialModel(Create.asResource("item/extendo_grip/cog")); + protected static final PartialModel THIN_SHORT = new PartialModel(Create.asResource("item/extendo_grip/thin_short")); + protected static final PartialModel WIDE_SHORT = new PartialModel(Create.asResource("item/extendo_grip/wide_short")); + protected static final PartialModel THIN_LONG = new PartialModel(Create.asResource("item/extendo_grip/thin_long")); + protected static final PartialModel WIDE_LONG = new PartialModel(Create.asResource("item/extendo_grip/wide_long")); + + private static final Vec3 ROTATION_OFFSET = new Vec3(0, 1 / 2f, 1 / 2f); + private static final Vec3 COG_ROTATION_OFFSET = new Vec3(0, 1 / 16f, 0); + + @Override + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, TransformType transformType, + PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + TransformStack stacker = TransformStack.cast(ms); + float animation = 0.25f; + boolean leftHand = transformType == TransformType.FIRST_PERSON_LEFT_HAND; + boolean rightHand = transformType == TransformType.FIRST_PERSON_RIGHT_HAND; + if (leftHand || rightHand) + animation = Mth.lerp(AnimationTickHolder.getPartialTicks(), + ExtendoGripRenderHandler.lastMainHandAnimation, + ExtendoGripRenderHandler.mainHandAnimation); + + animation = animation * animation * animation; + float extensionAngle = Mth.lerp(animation, 24f, 156f); + float halfAngle = extensionAngle / 2; + float oppositeAngle = 180 - extensionAngle; + + // grip + renderer.renderSolid(model.getOriginalModel(), light); + + // bits + ms.pushPose(); + ms.translate(0, 1 / 16f, -7 / 16f); + ms.scale(1, 1, 1 + animation); + ms.pushPose(); + stacker.rotateX(-halfAngle) + .translate(ROTATION_OFFSET); + renderer.renderSolid(THIN_SHORT.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + ms.translate(0, 5.5f / 16f, 0); + stacker.rotateX(-oppositeAngle) + .translate(ROTATION_OFFSET); + renderer.renderSolid(WIDE_LONG.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + ms.translate(0, 11 / 16f, 0); + stacker.rotateX(oppositeAngle) + .translate(ROTATION_OFFSET); + ms.translate(0, 0.5f / 16f, 0); + renderer.renderSolid(THIN_SHORT.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + ms.popPose(); + ms.pushPose(); + + stacker.rotateX(-180 + halfAngle) + .translate(ROTATION_OFFSET); + renderer.renderSolid(WIDE_SHORT.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + ms.translate(0, 5.5f / 16f, 0); + stacker.rotateX(oppositeAngle) + .translate(ROTATION_OFFSET); + renderer.renderSolid(THIN_LONG.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + ms.translate(0, 11 / 16f, 0); + stacker.rotateX(-oppositeAngle) + .translate(ROTATION_OFFSET); + ms.translate(0, 0.5f / 16f, 0); + renderer.renderSolid(WIDE_SHORT.get(), light); + stacker.translateBack(ROTATION_OFFSET); + + // hand + ms.translate(0, 5.5f / 16f, 0); + stacker.rotateX(180 - halfAngle) + .rotateY(180); + ms.translate(0, 0, -4 / 16f); + ms.scale(1, 1, 1 / (1 + animation)); + renderer.renderSolid((leftHand || rightHand) ? ExtendoGripRenderHandler.pose.get() + : AllPartialModels.DEPLOYER_HAND_POINTING.get(), light); + ms.popPose(); + + ms.popPose(); + + // cog + ms.pushPose(); + float angle = AnimationTickHolder.getRenderTime() * -2; + if (leftHand || rightHand) + angle += 360 * animation; + angle %= 360; + stacker.translate(COG_ROTATION_OFFSET) + .rotateZ(angle) + .translateBack(COG_ROTATION_OFFSET); + renderer.renderSolid(COG.get(), light); + ms.popPose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripRenderHandler.java b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripRenderHandler.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripRenderHandler.java rename to src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripRenderHandler.java index 3a05d49e32..516d9fea54 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/ExtendoGripRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/extendoGrip/ExtendoGripRenderHandler.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.extendoGrip; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllItems; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; @@ -30,13 +30,13 @@ public class ExtendoGripRenderHandler { public static float mainHandAnimation; public static float lastMainHandAnimation; - public static PartialModel pose = AllBlockPartials.DEPLOYER_HAND_PUNCHING; + public static PartialModel pose = AllPartialModels.DEPLOYER_HAND_PUNCHING; public static void tick() { lastMainHandAnimation = mainHandAnimation; mainHandAnimation *= Mth.clamp(mainHandAnimation, 0.8f, 0.99f); - pose = AllBlockPartials.DEPLOYER_HAND_PUNCHING; + pose = AllPartialModels.DEPLOYER_HAND_PUNCHING; if (!AllItems.EXTENDO_GRIP.isIn(getRenderedOffHandStack())) return; ItemStack main = getRenderedMainHandStack(); @@ -49,7 +49,7 @@ public class ExtendoGripRenderHandler { .getModel(main, null, null, 0) .isGui3d()) return; - pose = AllBlockPartials.DEPLOYER_HAND_HOLDING; + pose = AllPartialModels.DEPLOYER_HAND_HOLDING; } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleConfigScreen.java b/src/main/java/com/simibubi/create/content/equipment/goggles/GoggleConfigScreen.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleConfigScreen.java rename to src/main/java/com/simibubi/create/content/equipment/goggles/GoggleConfigScreen.java index b14c0dafdd..dcb74271aa 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleConfigScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/GoggleConfigScreen.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.goggles; +package com.simibubi.create.content.equipment.goggles; import java.util.ArrayList; import java.util.List; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.gui.AbstractSimiScreen; import net.createmod.catnip.gui.element.GuiGameElement; @@ -57,14 +57,14 @@ public class GoggleConfigScreen extends AbstractSimiScreen { this.height = minecraft.getWindow() .getGuiScaledHeight(); - offsetX = AllConfigs.CLIENT.overlayOffsetX.get(); - offsetY = AllConfigs.CLIENT.overlayOffsetY.get(); + offsetX = AllConfigs.client().overlayOffsetX.get(); + offsetY = AllConfigs.client().overlayOffsetY.get(); } @Override public void removed() { - AllConfigs.CLIENT.overlayOffsetX.set(offsetX); - AllConfigs.CLIENT.overlayOffsetY.set(offsetY); + AllConfigs.client().overlayOffsetX.set(offsetX); + AllConfigs.client().overlayOffsetY.set(offsetY); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java b/src/main/java/com/simibubi/create/content/equipment/goggles/GoggleOverlayRenderer.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/goggles/GoggleOverlayRenderer.java index fa87971143..d7289b5511 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/GoggleOverlayRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.goggles; +package com.simibubi.create.content.equipment.goggles; import java.util.ArrayList; import java.util.List; @@ -7,15 +7,15 @@ import java.util.Map; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonExtensionPoleBlock; -import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CClient; +import com.simibubi.create.content.contraptions.IDisplayAssemblyExceptions; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock; +import com.simibubi.create.content.contraptions.piston.PistonExtensionPoleBlock; +import com.simibubi.create.content.trains.entity.TrainRelocator; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox; import com.simibubi.create.foundation.gui.RemovedGuiUtils; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CClient; import net.createmod.catnip.CatnipClient; import net.createmod.catnip.gui.element.GuiGameElement; @@ -34,6 +34,7 @@ import net.minecraft.network.chat.FormattedText; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -74,19 +75,18 @@ public class GoggleOverlayRenderer { BlockHitResult result = (BlockHitResult) objectMouseOver; ClientLevel world = mc.level; BlockPos pos = result.getBlockPos(); - BlockEntity te = world.getBlockEntity(pos); int prevHoverTicks = hoverTicks; - if (lastHovered == null || lastHovered.equals(pos)) - hoverTicks++; - else - hoverTicks = 0; + hoverTicks++; lastHovered = pos; + pos = proxiedOverlayPosition(world, pos); + + BlockEntity be = world.getBlockEntity(pos); boolean wearingGoggles = GogglesItem.isWearingGoggles(mc.player); - boolean hasGoggleInformation = te instanceof IHaveGoggleInformation; - boolean hasHoveringInformation = te instanceof IHaveHoveringInformation; + boolean hasGoggleInformation = be instanceof IHaveGoggleInformation; + boolean hasHoveringInformation = be instanceof IHaveHoveringInformation; boolean goggleAddedInformation = false; boolean hoverAddedInformation = false; @@ -94,22 +94,22 @@ public class GoggleOverlayRenderer { List tooltip = new ArrayList<>(); if (hasGoggleInformation && wearingGoggles) { - IHaveGoggleInformation gte = (IHaveGoggleInformation) te; + IHaveGoggleInformation gte = (IHaveGoggleInformation) be; goggleAddedInformation = gte.addToGoggleTooltip(tooltip, mc.player.isShiftKeyDown()); } if (hasHoveringInformation) { if (!tooltip.isEmpty()) tooltip.add(Components.immutableEmpty()); - IHaveHoveringInformation hte = (IHaveHoveringInformation) te; + IHaveHoveringInformation hte = (IHaveHoveringInformation) be; hoverAddedInformation = hte.addToTooltip(tooltip, mc.player.isShiftKeyDown()); if (goggleAddedInformation && !hoverAddedInformation) tooltip.remove(tooltip.size() - 1); } - if (te instanceof IDisplayAssemblyExceptions) { - boolean exceptionAdded = ((IDisplayAssemblyExceptions) te).addExceptionToTooltip(tooltip); + if (be instanceof IDisplayAssemblyExceptions) { + boolean exceptionAdded = ((IDisplayAssemblyExceptions) be).addExceptionToTooltip(tooltip); if (exceptionAdded) { hasHoveringInformation = true; hoverAddedInformation = true; @@ -122,8 +122,10 @@ public class GoggleOverlayRenderer { hoverTicks = prevHoverTicks + 1; // break early if goggle or hover returned false when present - if ((hasGoggleInformation && !goggleAddedInformation) && (hasHoveringInformation && !hoverAddedInformation)) + if ((hasGoggleInformation && !goggleAddedInformation) && (hasHoveringInformation && !hoverAddedInformation)) { + hoverTicks = 0; return; + } // check for piston poles if goggles are worn BlockState state = world.getBlockState(pos); @@ -140,8 +142,10 @@ public class GoggleOverlayRenderer { .getBlock() instanceof MechanicalPistonBlock; } - if (!pistonFound) + if (!pistonFound) { + hoverTicks = 0; return; + } if (!tooltip.isEmpty()) tooltip.add(Components.immutableEmpty()); @@ -150,8 +154,10 @@ public class GoggleOverlayRenderer { .append(Components.literal(" " + poles))); } - if (tooltip.isEmpty()) + if (tooltip.isEmpty()) { + hoverTicks = 0; return; + } poseStack.pushPose(); @@ -168,27 +174,24 @@ public class GoggleOverlayRenderer { tooltipHeight += (tooltip.size() - 1) * 10; } - CClient cfg = AllConfigs.CLIENT; + CClient cfg = AllConfigs.client(); int posX = width / 2 + cfg.overlayOffsetX.get(); int posY = height / 2 + cfg.overlayOffsetY.get(); posX = Math.min(posX, width - tooltipTextWidth - 20); posY = Math.min(posY, height - tooltipHeight - 20); - float fade = Mth.clamp((hoverTicks + partialTicks) / 12f, 0, 1); + float fade = Mth.clamp((hoverTicks + partialTicks) / 24f, 0, 1); Boolean useCustom = cfg.overlayCustomColor.get(); Color colorBackground = useCustom ? new Color(cfg.overlayBackgroundColor.get()) - : Theme.Key.VANILLA_TOOLTIP_BACKGROUND.c() - .scaleAlpha(.75f); + : Theme.Key.VANILLA_TOOLTIP_BACKGROUND.c().scaleAlpha(.75f); Color colorBorderTop = useCustom ? new Color(cfg.overlayBorderColorTop.get()) - : Theme.Key.VANILLA_TOOLTIP_BORDER.c(true) - .copy(); + : Theme.Key.VANILLA_TOOLTIP_BORDER.c(true).copy(); Color colorBorderBot = useCustom ? new Color(cfg.overlayBorderColorBot.get()) - : Theme.Key.VANILLA_TOOLTIP_BORDER.c(false) - .copy(); + : Theme.Key.VANILLA_TOOLTIP_BORDER.c(false).copy(); if (fade < 1) { - poseStack.translate((1 - fade) * Math.signum(cfg.overlayOffsetX.get() + .5f) * 4, 0, 0); + poseStack.translate(Math.pow(1 - fade, 3) * Math.signum(cfg.overlayOffsetX.get() + .5f) * 8, 0, 0); colorBackground.scaleAlpha(fade); colorBorderTop.scaleAlpha(fade); colorBorderBot.scaleAlpha(fade); @@ -204,4 +207,11 @@ public class GoggleOverlayRenderer { poseStack.popPose(); } + public static BlockPos proxiedOverlayPosition(Level level, BlockPos pos) { + BlockState targetedState = level.getBlockState(pos); + if (targetedState.getBlock() instanceof IProxyHoveringInformation proxy) + return proxy.getInformationSource(level, pos, targetedState); + return pos; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesItem.java b/src/main/java/com/simibubi/create/content/equipment/goggles/GogglesItem.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesItem.java rename to src/main/java/com/simibubi/create/content/equipment/goggles/GogglesItem.java index 19063c4d68..22d59c6bd4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/GogglesItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.goggles; +package com.simibubi.create.content.equipment.goggles; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java b/src/main/java/com/simibubi/create/content/equipment/goggles/GogglesModel.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java rename to src/main/java/com/simibubi/create/content/equipment/goggles/GogglesModel.java index 84c2aae735..f205562993 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/GogglesModel.java +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/GogglesModel.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.goggles; +package com.simibubi.create.content.equipment.goggles; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; import net.minecraft.client.resources.model.BakedModel; @@ -16,7 +16,7 @@ public class GogglesModel extends BakedModelWrapper { @Override public BakedModel handlePerspective(TransformType cameraTransformType, PoseStack mat) { if (cameraTransformType == TransformType.HEAD) - return AllBlockPartials.GOGGLES.get() + return AllPartialModels.GOGGLES.get() .handlePerspective(cameraTransformType, mat); return super.handlePerspective(cameraTransformType, mat); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java b/src/main/java/com/simibubi/create/content/equipment/goggles/IHaveGoggleInformation.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java rename to src/main/java/com/simibubi/create/content/equipment/goggles/IHaveGoggleInformation.java index 3ac53636a3..520bfd9c44 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/IHaveGoggleInformation.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.goggles; +package com.simibubi.create.content.equipment.goggles; import java.util.List; import java.util.Optional; @@ -14,7 +14,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; /* -* Implement this Interface in the TileEntity class that wants to add info to the screen +* Implement this Interface in the BlockEntity class that wants to add info to the screen * */ public interface IHaveGoggleInformation { @@ -30,7 +30,7 @@ public interface IHaveGoggleInformation { Component componentSpacing = Components.literal(spacing); /** - * this method will be called when looking at a TileEntity that implemented this + * this method will be called when looking at a BlockEntity that implemented this * interface * * @return {@code true} if the tooltip creation was successful and should be diff --git a/src/main/java/com/simibubi/create/content/equipment/goggles/IHaveHoveringInformation.java b/src/main/java/com/simibubi/create/content/equipment/goggles/IHaveHoveringInformation.java new file mode 100644 index 0000000000..ea97e262a5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/IHaveHoveringInformation.java @@ -0,0 +1,16 @@ +package com.simibubi.create.content.equipment.goggles; + +import java.util.List; + +import net.minecraft.network.chat.Component; + +/* +* Implement this Interface in the BlockEntity class that wants to add info to the screen +* */ +public interface IHaveHoveringInformation { + + default boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/goggles/IProxyHoveringInformation.java b/src/main/java/com/simibubi/create/content/equipment/goggles/IProxyHoveringInformation.java new file mode 100644 index 0000000000..dad2d3051c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/goggles/IProxyHoveringInformation.java @@ -0,0 +1,11 @@ +package com.simibubi.create.content.equipment.goggles; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public interface IProxyHoveringInformation { + + public BlockPos getInformationSource(Level level, BlockPos pos, BlockState state); + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/BuiltinPotatoProjectileTypes.java b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/BuiltinPotatoProjectileTypes.java similarity index 99% rename from src/main/java/com/simibubi/create/content/curiosities/weapons/BuiltinPotatoProjectileTypes.java rename to src/main/java/com/simibubi/create/content/equipment/potatoCannon/BuiltinPotatoProjectileTypes.java index e0bd81b05f..449d32f7f8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/BuiltinPotatoProjectileTypes.java +++ b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/BuiltinPotatoProjectileTypes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.weapons; +package com.simibubi.create.content.equipment.potatoCannon; import java.util.UUID; import java.util.function.BiPredicate; @@ -312,6 +312,8 @@ public class BuiltinPotatoProjectileTypes { if (world instanceof Level l && !l.isLoaded(hitPos)) return true; Direction face = ray.getDirection(); + if (face != Direction.UP) + return false; BlockPos placePos = hitPos.relative(face); if (!world.getBlockState(placePos) .getMaterial() diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItem.java similarity index 90% rename from src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java rename to src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItem.java index fd320cf228..9b97102d92 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItem.java @@ -1,25 +1,30 @@ -package com.simibubi.create.content.curiosities.weapons; +package com.simibubi.create.content.equipment.potatoCannon; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; +import org.jetbrains.annotations.Nullable; + import com.simibubi.create.AllEnchantments; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.curiosities.armor.BackTankUtil; -import com.simibubi.create.content.curiosities.zapper.ShootableGadgetItemMethods; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.equipment.armor.BacktankUtil; +import com.simibubi.create.content.equipment.zapper.ShootableGadgetItemMethods; +import com.simibubi.create.foundation.item.CustomArmPoseItem; import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.lang.Components; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel.ArmPose; +import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction.Axis; @@ -46,7 +51,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.IItemRenderProperties; -public class PotatoCannonItem extends ProjectileWeaponItem { +public class PotatoCannonItem extends ProjectileWeaponItem implements CustomArmPoseItem { public static ItemStack CLIENT_CURRENT_AMMO = ItemStack.EMPTY; public static final int MAX_DAMAGE = 100; @@ -82,21 +87,21 @@ public class PotatoCannonItem extends ProjectileWeaponItem { @Override public boolean isBarVisible(ItemStack stack) { - return BackTankUtil.isBarVisible(stack, maxUses()); + return BacktankUtil.isBarVisible(stack, maxUses()); } @Override public int getBarWidth(ItemStack stack) { - return BackTankUtil.getBarWidth(stack, maxUses()); + return BacktankUtil.getBarWidth(stack, maxUses()); } @Override public int getBarColor(ItemStack stack) { - return BackTankUtil.getBarColor(stack, maxUses()); + return BacktankUtil.getBarColor(stack, maxUses()); } private int maxUses() { - return AllConfigs.SERVER.curiosities.maxPotatoCannonShots.get(); + return AllConfigs.server().equipment.maxPotatoCannonShots.get(); } public boolean isCannon(ItemStack stack) { @@ -164,7 +169,7 @@ public class PotatoCannonItem extends ProjectileWeaponItem { player.getInventory().removeItem(itemStack); } - if (!BackTankUtil.canAbsorbDamage(player, maxUses())) + if (!BacktankUtil.canAbsorbDamage(player, maxUses())) stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand)); Integer cooldown = @@ -270,6 +275,15 @@ public class PotatoCannonItem extends ProjectileWeaponItem { return UseAnim.NONE; } + @Override + @Nullable + public ArmPose getArmPose(ItemStack stack, AbstractClientPlayer player, InteractionHand hand) { + if (!player.swinging) { + return ArmPose.CROSSBOW_HOLD; + } + return null; + } + @Override public int getDefaultProjectileRange() { return 15; diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItemRenderer.java similarity index 82% rename from src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItemRenderer.java index b7e604858f..277dfea6b4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoCannonItemRenderer.java @@ -1,9 +1,12 @@ -package com.simibubi.create.content.curiosities.weapons; +package com.simibubi.create.content.equipment.potatoCannon; +import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; +import com.simibubi.create.Create; import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; @@ -14,15 +17,16 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.util.Mth; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.item.ItemStack; -public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer { +public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer { + + protected static final PartialModel COG = new PartialModel(Create.asResource("item/potato_cannon/cog")); @Override - protected void render(ItemStack stack, PotatoCannonModel model, PartialItemModelRenderer renderer, + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, TransformType transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { ItemRenderer itemRenderer = Minecraft.getInstance() .getItemRenderer(); @@ -46,7 +50,7 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer player), new SyncPacket()); + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> player), new SyncPacket()); } public static void syncToAll() { - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SyncPacket()); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new SyncPacket()); } public static class ReloadListener extends SimpleJsonResourceReloadListener { @@ -148,11 +148,11 @@ public class PotatoProjectileTypeManager { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { + public boolean handle(Context context) { + context.enqueueWork(() -> { fromBuffer(buffer); }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoRecoveryEnchantment.java b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoRecoveryEnchantment.java similarity index 91% rename from src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoRecoveryEnchantment.java rename to src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoRecoveryEnchantment.java index 2f8a2f0632..47e767ffff 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoRecoveryEnchantment.java +++ b/src/main/java/com/simibubi/create/content/equipment/potatoCannon/PotatoRecoveryEnchantment.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.weapons; +package com.simibubi.create.content.equipment.potatoCannon; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItem.java b/src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItem.java similarity index 99% rename from src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItem.java rename to src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItem.java index dda35d2aa3..bc28eeaa55 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.sandPaper; import java.util.Random; import java.util.function.Consumer; diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItemRenderer.java similarity index 81% rename from src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItemRenderer.java index cbe3f61a78..4c4649a854 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/SandPaperItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/sandPaper/SandPaperItemRenderer.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.curiosities.tools; +package com.simibubi.create.content.equipment.sandPaper; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; @@ -12,15 +12,14 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; -public class SandPaperItemRenderer extends CustomRenderedItemModelRenderer { +public class SandPaperItemRenderer extends CustomRenderedItemModelRenderer { @Override - protected void render(ItemStack stack, SandPaperModel model, PartialItemModelRenderer renderer, + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, TransformType transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); LocalPlayer player = Minecraft.getInstance().player; @@ -79,17 +78,4 @@ public class SandPaperItemRenderer extends CustomRenderedItemModelRenderer context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) { return; } @@ -44,7 +42,7 @@ public class ConfigureSymmetryWandPacket extends SimplePacketBase { SymmetryWandItem.configureSettings(stack, mirror); } }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryEffectPacket.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryEffectPacket.java similarity index 83% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryEffectPacket.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryEffectPacket.java index 9ddd7f21ca..c7572c4cbb 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryEffectPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryEffectPacket.java @@ -1,8 +1,7 @@ -package com.simibubi.create.content.curiosities.symmetry; +package com.simibubi.create.content.equipment.symmetryWand; import java.util.ArrayList; import java.util.List; -import java.util.function.Supplier; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -43,14 +42,14 @@ public class SymmetryEffectPacket extends SimplePacketBase { } @Override - public void handle(Supplier ctx) { - ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { if (Minecraft.getInstance().player.position().distanceTo(Vec3.atLowerCornerOf(mirror)) > 100) return; for (BlockPos to : positions) SymmetryHandler.drawEffect(mirror, to); })); - ctx.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryHandler.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryHandler.java index 9cef1e6855..dea2e43437 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry; +package com.simibubi.create.content.equipment.symmetryWand; import java.util.Random; @@ -6,8 +6,8 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Vector3f; import com.simibubi.create.AllItems; -import com.simibubi.create.content.curiosities.symmetry.mirror.EmptyMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.SymmetryMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.EmptyMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.SymmetryMirror; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.client.Camera; @@ -111,8 +111,7 @@ public class SymmetryHandler { PoseStack ms = event.getPoseStack(); ms.pushPose(); - ms.translate(-view.x(), -view.y(), -view.z()); - ms.translate(pos.getX(), pos.getY(), pos.getZ()); + ms.translate(pos.getX() - view.x(), pos.getY() - view.y(), pos.getZ() - view.z()); ms.translate(0, yShift + .2f, 0); mirror.applyModelTransform(ms); BakedModel model = mirror.getModel() diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandItem.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItem.java similarity index 89% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandItem.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItem.java index a935b7591b..bc1aba341f 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry; +package com.simibubi.create.content.equipment.symmetryWand; import java.util.ArrayList; import java.util.HashMap; @@ -9,16 +9,15 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; -import com.simibubi.create.content.curiosities.symmetry.client.SymmetryWandItemRenderer; -import com.simibubi.create.content.curiosities.symmetry.mirror.CrossPlaneMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.EmptyMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.PlaneMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.SymmetryMirror; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock; +import com.simibubi.create.content.equipment.symmetryWand.mirror.CrossPlaneMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.EmptyMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.PlaneMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.SymmetryMirror; import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.gui.ScreenOpener; import net.createmod.catnip.utility.Iterate; @@ -204,7 +203,7 @@ public class SymmetryWandItem extends Item { .getCompound(SYMMETRY)); Vec3 mirrorPos = symmetry.getPosition(); - if (mirrorPos.distanceTo(Vec3.atLowerCornerOf(pos)) > AllConfigs.SERVER.curiosities.maxSymmetryWandRange.get()) + if (mirrorPos.distanceTo(Vec3.atLowerCornerOf(pos)) > AllConfigs.server().equipment.maxSymmetryWandRange.get()) return; if (!player.isCreative() && isHoldingBlock(player, block) && BlockHelper.findAndRemoveInInventory(block, player, 1) == 0) @@ -267,7 +266,7 @@ public class SymmetryWandItem extends Item { } } - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new SymmetryEffectPacket(to, targets)); } @@ -292,7 +291,7 @@ public class SymmetryWandItem extends Item { .getCompound(SYMMETRY)); Vec3 mirrorPos = symmetry.getPosition(); - if (mirrorPos.distanceTo(Vec3.atLowerCornerOf(pos)) > AllConfigs.SERVER.curiosities.maxSymmetryWandRange.get()) + if (mirrorPos.distanceTo(Vec3.atLowerCornerOf(pos)) > AllConfigs.server().equipment.maxSymmetryWandRange.get()) return; symmetry.process(blockSet); @@ -319,13 +318,13 @@ public class SymmetryWandItem extends Item { .isEmpty()) player.getMainHandItem() .mineBlock(world, blockstate, position, player); - BlockEntity tileentity = blockstate.hasBlockEntity() ? world.getBlockEntity(position) : null; - Block.dropResources(blockstate, world, pos, tileentity, player, player.getMainHandItem()); // Add fortune, silk touch and other loot modifiers + BlockEntity blockEntity = blockstate.hasBlockEntity() ? world.getBlockEntity(position) : null; + Block.dropResources(blockstate, world, pos, blockEntity, player, player.getMainHandItem()); // Add fortune, silk touch and other loot modifiers } } } - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new SymmetryEffectPacket(to, targets)); } diff --git a/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItemRenderer.java new file mode 100644 index 0000000000..5d37ab2502 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandItemRenderer.java @@ -0,0 +1,43 @@ +package com.simibubi.create.content.equipment.symmetryWand; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; +import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; + +public class SymmetryWandItemRenderer extends CustomRenderedItemModelRenderer { + + protected static final PartialModel BITS = new PartialModel(Create.asResource("item/wand_of_symmetry/bits")); + protected static final PartialModel CORE = new PartialModel(Create.asResource("item/wand_of_symmetry/core")); + protected static final PartialModel CORE_GLOW = new PartialModel(Create.asResource("item/wand_of_symmetry/core_glow")); + + @Override + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, + PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + float worldTime = AnimationTickHolder.getRenderTime() / 20; + int maxLight = LightTexture.FULL_BRIGHT; + + renderer.render(model.getOriginalModel(), light); + renderer.renderSolidGlowing(CORE.get(), maxLight); + renderer.renderGlowing(CORE_GLOW.get(), maxLight); + + float floating = Mth.sin(worldTime) * .05f; + float angle = worldTime * -10 % 360; + + ms.translate(0, floating, 0); + ms.mulPose(Vector3f.YP.rotationDegrees(angle)); + + renderer.renderGlowing(BITS.get(), maxLight); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandScreen.java similarity index 86% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandScreen.java index a1f518c32c..f9a2e12c56 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/SymmetryWandScreen.java @@ -1,12 +1,13 @@ -package com.simibubi.create.content.curiosities.symmetry; +package com.simibubi.create.content.equipment.symmetryWand; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.content.curiosities.symmetry.mirror.CrossPlaneMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.EmptyMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.PlaneMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.SymmetryMirror; -import com.simibubi.create.content.curiosities.symmetry.mirror.TriplePlaneMirror; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.equipment.symmetryWand.mirror.CrossPlaneMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.EmptyMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.PlaneMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.SymmetryMirror; +import com.simibubi.create.content.equipment.symmetryWand.mirror.TriplePlaneMirror; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; @@ -14,7 +15,6 @@ import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.ScrollInput; import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.AbstractSimiScreen; @@ -123,7 +123,7 @@ public class SymmetryWandScreen extends AbstractSimiScreen { int y = guiTop; background.render(ms, x, y, this); - font.draw(ms, wand.getHoverName(), x + 11, y + 4, 0x6B3802); + font.draw(ms, wand.getHoverName(), x + 11, y + 4, 0x592424); renderBlock(ms, x, y); GuiGameElement.of(wand) @@ -139,6 +139,7 @@ public class SymmetryWandScreen extends AbstractSimiScreen { ms.scale(16, 16, 16); ms.mulPose(new Vector3f(.3f, 1f, 0f).rotationDegrees(-22.5f)); currentElement.applyModelTransform(ms); + // RenderSystem.multMatrix(ms.peek().getModel()); PartialModelGuiElement.of(currentElement.getModel()) .render(ms); @@ -148,7 +149,7 @@ public class SymmetryWandScreen extends AbstractSimiScreen { @Override public void removed() { SymmetryWandItem.configureSettings(wand, currentElement); - AllPackets.channel.sendToServer(new ConfigureSymmetryWandPacket(hand, currentElement)); + AllPackets.getChannel().sendToServer(new ConfigureSymmetryWandPacket(hand, currentElement)); } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/CrossPlaneMirror.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/CrossPlaneMirror.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/CrossPlaneMirror.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/CrossPlaneMirror.java index 12764744ac..6114aa8160 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/CrossPlaneMirror.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/CrossPlaneMirror.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry.mirror; +package com.simibubi.create.content.equipment.symmetryWand.mirror; import java.util.HashMap; import java.util.List; @@ -8,7 +8,7 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.core.BlockPos; @@ -91,7 +91,7 @@ public class CrossPlaneMirror extends SymmetryMirror { @Override @OnlyIn(Dist.CLIENT) public PartialModel getModel() { - return AllBlockPartials.SYMMETRY_CROSSPLANE; + return AllPartialModels.SYMMETRY_CROSSPLANE; } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/EmptyMirror.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/EmptyMirror.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/EmptyMirror.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/EmptyMirror.java index 56103a1ee2..cf30a04fdb 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/EmptyMirror.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/EmptyMirror.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry.mirror; +package com.simibubi.create.content.equipment.symmetryWand.mirror; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/PlaneMirror.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/PlaneMirror.java similarity index 93% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/PlaneMirror.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/PlaneMirror.java index d3fd47378e..197f7103f6 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/PlaneMirror.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/PlaneMirror.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry.mirror; +package com.simibubi.create.content.equipment.symmetryWand.mirror; import java.util.HashMap; import java.util.List; @@ -8,7 +8,7 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.core.BlockPos; @@ -87,7 +87,7 @@ public class PlaneMirror extends SymmetryMirror { @Override @OnlyIn(Dist.CLIENT) public PartialModel getModel() { - return AllBlockPartials.SYMMETRY_PLANE; + return AllPartialModels.SYMMETRY_PLANE; } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/SymmetryMirror.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/SymmetryMirror.java similarity index 98% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/SymmetryMirror.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/SymmetryMirror.java index afd3f9faf3..0f484bfb92 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/SymmetryMirror.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/SymmetryMirror.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry.mirror; +package com.simibubi.create.content.equipment.symmetryWand.mirror; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/TriplePlaneMirror.java b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/TriplePlaneMirror.java similarity index 91% rename from src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/TriplePlaneMirror.java rename to src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/TriplePlaneMirror.java index 163863af08..80dc64bfdf 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/mirror/TriplePlaneMirror.java +++ b/src/main/java/com/simibubi/create/content/equipment/symmetryWand/mirror/TriplePlaneMirror.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.symmetry.mirror; +package com.simibubi.create.content.equipment.symmetryWand.mirror; import java.util.HashMap; import java.util.List; @@ -6,7 +6,7 @@ import java.util.Map; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.core.BlockPos; @@ -48,7 +48,7 @@ public class TriplePlaneMirror extends SymmetryMirror { @Override @OnlyIn(Dist.CLIENT) public PartialModel getModel() { - return AllBlockPartials.SYMMETRY_TRIPLEPLANE; + return AllPartialModels.SYMMETRY_TRIPLEPLANE; } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ItemReturnInvWrapper.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ItemReturnInvWrapper.java similarity index 90% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ItemReturnInvWrapper.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ItemReturnInvWrapper.java index 24346ff201..24bcc11fda 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ItemReturnInvWrapper.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ItemReturnInvWrapper.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/RadialToolboxMenu.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/RadialToolboxMenu.java similarity index 90% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/RadialToolboxMenu.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/RadialToolboxMenu.java index 9ff5270cec..a804488d98 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/RadialToolboxMenu.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/RadialToolboxMenu.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; -import static com.simibubi.create.content.curiosities.toolbox.ToolboxInventory.STACKS_PER_COMPARTMENT; +import static com.simibubi.create.content.equipment.toolbox.ToolboxInventory.STACKS_PER_COMPARTMENT; import java.util.List; @@ -13,9 +13,9 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.AbstractSimiScreen; @@ -36,13 +36,13 @@ public class RadialToolboxMenu extends AbstractSimiScreen { private int hoveredSlot; private boolean scrollMode; private int scrollSlot = 0; - private List toolboxes; - private ToolboxTileEntity selectedBox; + private List toolboxes; + private ToolboxBlockEntity selectedBox; private static final int DEPOSIT = -7; private static final int UNEQUIP = -5; - public RadialToolboxMenu(List toolboxes, State state, @Nullable ToolboxTileEntity selectedBox) { + public RadialToolboxMenu(List toolboxes, State state, @Nullable ToolboxBlockEntity selectedBox) { this.toolboxes = toolboxes; this.state = state; hoveredSlot = -1; @@ -155,15 +155,15 @@ public class RadialToolboxMenu extends AbstractSimiScreen { if (slot < toolboxes.size()) { AllGuiTextures.TOOLBELT_SLOT.render(ms, 0, 0, this); - ToolboxTileEntity toolboxTileEntity = toolboxes.get(slot); - GuiGameElement.of(AllBlocks.TOOLBOXES.get(toolboxTileEntity.getColor()) + ToolboxBlockEntity toolboxBlockEntity = toolboxes.get(slot); + GuiGameElement.of(AllBlocks.TOOLBOXES.get(toolboxBlockEntity.getColor()) .asStack()) .at(3, 3) .render(ms); if (slot == (scrollMode ? scrollSlot : hoveredSlot)) { AllGuiTextures.TOOLBELT_SLOT_HIGHLIGHT.render(ms, -1, -1, this); - tip = toolboxTileEntity.getDisplayName(); + tip = toolboxBlockEntity.getDisplayName(); } } else AllGuiTextures.TOOLBELT_EMPTY_SLOT.render(ms, 0, 0, this); @@ -231,9 +231,9 @@ public class RadialToolboxMenu extends AbstractSimiScreen { if (state == State.DETACH) return; else if (state == State.SELECT_BOX) - toolboxes.forEach(te -> AllPackets.channel.sendToServer(new ToolboxDisposeAllPacket(te.getBlockPos()))); + toolboxes.forEach(be -> AllPackets.getChannel().sendToServer(new ToolboxDisposeAllPacket(be.getBlockPos()))); else - AllPackets.channel.sendToServer(new ToolboxDisposeAllPacket(selectedBox.getBlockPos())); + AllPackets.getChannel().sendToServer(new ToolboxDisposeAllPacket(selectedBox.getBlockPos())); return; } @@ -242,13 +242,13 @@ public class RadialToolboxMenu extends AbstractSimiScreen { if (state == State.DETACH) { if (selected == UNEQUIP) - AllPackets.channel.sendToServer( + AllPackets.getChannel().sendToServer( new ToolboxEquipPacket(null, selected, minecraft.player.getInventory().selected)); return; } if (selected == UNEQUIP) - AllPackets.channel.sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, + AllPackets.getChannel().sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, minecraft.player.getInventory().selected)); if (selected < 0) @@ -261,7 +261,7 @@ public class RadialToolboxMenu extends AbstractSimiScreen { .isEmpty()) return; - AllPackets.channel.sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, + AllPackets.getChannel().sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, minecraft.player.getInventory().selected)); } @@ -334,7 +334,7 @@ public class RadialToolboxMenu extends AbstractSimiScreen { if (state == State.SELECT_ITEM_UNEQUIP && selected == UNEQUIP) { if (toolboxes.size() > 1) { - AllPackets.channel.sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, + AllPackets.getChannel().sendToServer(new ToolboxEquipPacket(selectedBox.getBlockPos(), selected, minecraft.player.getInventory().selected)); state = State.SELECT_BOX; return true; diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolBoxInstance.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolBoxInstance.java similarity index 86% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolBoxInstance.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolBoxInstance.java index d7bdcea9cd..2c61039aa7 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolBoxInstance.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolBoxInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.MaterialManager; @@ -6,21 +6,21 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; -public class ToolBoxInstance extends BlockEntityInstance implements DynamicInstance { +public class ToolBoxInstance extends BlockEntityInstance implements DynamicInstance { private final Direction facing; private ModelData lid; private ModelData[] drawers; - public ToolBoxInstance(MaterialManager materialManager, ToolboxTileEntity tile) { - super(materialManager, tile); + public ToolBoxInstance(MaterialManager materialManager, ToolboxBlockEntity blockEntity) { + super(materialManager, blockEntity); facing = blockState.getValue(ToolboxBlock.FACING) .getOpposite(); @@ -32,12 +32,12 @@ public class ToolBoxInstance extends BlockEntityInstance impl Instancer drawerModel = materialManager.defaultSolid() .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.TOOLBOX_DRAWER, blockState); + .getModel(AllPartialModels.TOOLBOX_DRAWER, blockState); drawers = new ModelData[]{drawerModel.createInstance(), drawerModel.createInstance()}; lid = materialManager.defaultCutout() .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.TOOLBOX_LIDS.get(blockEntity.getColor()), blockState) + .getModel(AllPartialModels.TOOLBOX_LIDS.get(blockEntity.getColor()), blockState) .createInstance(); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxBlock.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlock.java similarity index 85% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxBlock.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlock.java index 6257a88df7..92c6344462 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxBlock.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlock.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; import java.util.Optional; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.utility.BlockHelper; import net.minecraft.core.BlockPos; @@ -43,7 +43,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.network.NetworkHooks; -public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWaterloggedBlock, ITE { +public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWaterloggedBlock, IBE { protected final DyeColor color; @@ -78,13 +78,13 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa return; if (stack == null) return; - withTileEntityDo(worldIn, pos, te -> { + withBlockEntityDo(worldIn, pos, be -> { CompoundTag orCreateTag = stack.getOrCreateTag(); - te.readInventory(orCreateTag.getCompound("Inventory")); + be.readInventory(orCreateTag.getCompound("Inventory")); if (orCreateTag.contains("UniqueId")) - te.setUniqueId(orCreateTag.getUUID("UniqueId")); + be.setUniqueId(orCreateTag.getUUID("UniqueId")); if (stack.hasCustomHoverName()) - te.setCustomName(stack.getHoverName()); + be.setCustomName(stack.getHoverName()); }); } @@ -100,7 +100,7 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa return; if (world.isClientSide) return; - withTileEntityDo(world, pos, ToolboxTileEntity::unequipTracked); + withBlockEntityDo(world, pos, ToolboxBlockEntity::unequipTracked); if (world instanceof ServerLevel) { ItemStack cloneItemStack = getCloneItemStack(world, pos, state); world.destroyBlock(pos, false); @@ -112,16 +112,16 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa @Override public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) { ItemStack item = new ItemStack(this); - Optional tileEntityOptional = getTileEntityOptional(world, pos); + Optional blockEntityOptional = getBlockEntityOptional(world, pos); CompoundTag tag = item.getOrCreateTag(); - CompoundTag inv = tileEntityOptional.map(tb -> tb.inventory.serializeNBT()) + CompoundTag inv = blockEntityOptional.map(tb -> tb.inventory.serializeNBT()) .orElse(new CompoundTag()); tag.put("Inventory", inv); - tileEntityOptional.map(tb -> tb.getUniqueId()) + blockEntityOptional.map(tb -> tb.getUniqueId()) .ifPresent(uid -> tag.putUUID("UniqueId", uid)); - tileEntityOptional.map(ToolboxTileEntity::getCustomName) + blockEntityOptional.map(ToolboxBlockEntity::getCustomName) .ifPresent(item::setHoverName); return item; } @@ -162,8 +162,8 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa if (world.isClientSide) return InteractionResult.SUCCESS; - withTileEntityDo(world, pos, - toolbox -> NetworkHooks.openGui((ServerPlayer) player, toolbox, toolbox::sendToContainer)); + withBlockEntityDo(world, pos, + toolbox -> NetworkHooks.openGui((ServerPlayer) player, toolbox, toolbox::sendToMenu)); return InteractionResult.SUCCESS; } @@ -177,13 +177,13 @@ public class ToolboxBlock extends HorizontalDirectionalBlock implements SimpleWa } @Override - public Class getTileEntityClass() { - return ToolboxTileEntity.class; + public Class getBlockEntityClass() { + return ToolboxBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TOOLBOX.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TOOLBOX.get(); } public DyeColor getColor() { diff --git a/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlockEntity.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlockEntity.java new file mode 100644 index 0000000000..98d18b0e6e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxBlockEntity.java @@ -0,0 +1,421 @@ +package com.simibubi.create.content.equipment.toolbox; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.WeakHashMap; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.ResetableLazy; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +public class ToolboxBlockEntity extends SmartBlockEntity implements MenuProvider, Nameable { + + public LerpedFloat lid = LerpedFloat.linear() + .startWithValue(0); + + public LerpedFloat drawers = LerpedFloat.linear() + .startWithValue(0); + + UUID uniqueId; + ToolboxInventory inventory; + LazyOptional inventoryProvider; + ResetableLazy colorProvider; + protected int openCount; + + Map> connectedPlayers; + + private Component customName; + + public ToolboxBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + connectedPlayers = new HashMap<>(); + inventory = new ToolboxInventory(this); + inventoryProvider = LazyOptional.of(() -> inventory); + colorProvider = ResetableLazy.of(() -> { + BlockState blockState = getBlockState(); + if (blockState != null && blockState.getBlock() instanceof ToolboxBlock) + return ((ToolboxBlock) blockState.getBlock()).getColor(); + return DyeColor.BROWN; + }); + setLazyTickRate(10); + } + + public DyeColor getColor() { + return colorProvider.get(); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void initialize() { + super.initialize(); + ToolboxHandler.onLoad(this); + } + + @Override + public void invalidate() { + super.invalidate(); + ToolboxHandler.onUnload(this); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) + tickAudio(); + if (!level.isClientSide) + tickPlayers(); + + lid.chase(openCount > 0 ? 1 : 0, 0.2f, Chaser.LINEAR); + drawers.chase(openCount > 0 ? 1 : 0, 0.2f, Chaser.EXP); + lid.tickChaser(); + drawers.tickChaser(); + } + + private void tickPlayers() { + boolean update = false; + + for (Iterator>> toolboxSlots = connectedPlayers.entrySet() + .iterator(); toolboxSlots.hasNext();) { + + Entry> toolboxSlotEntry = toolboxSlots.next(); + WeakHashMap set = toolboxSlotEntry.getValue(); + int slot = toolboxSlotEntry.getKey(); + + ItemStack referenceItem = inventory.filters.get(slot); + boolean clear = referenceItem.isEmpty(); + + for (Iterator> playerEntries = set.entrySet() + .iterator(); playerEntries.hasNext();) { + Entry playerEntry = playerEntries.next(); + + Player player = playerEntry.getKey(); + int hotbarSlot = playerEntry.getValue(); + + if (!clear && !ToolboxHandler.withinRange(player, this)) + continue; + + Inventory playerInv = player.getInventory(); + ItemStack playerStack = playerInv.getItem(hotbarSlot); + + if (clear || !playerStack.isEmpty() + && !ToolboxInventory.canItemsShareCompartment(playerStack, referenceItem)) { + player.getPersistentData() + .getCompound("CreateToolboxData") + .remove(String.valueOf(hotbarSlot)); + playerEntries.remove(); + if (player instanceof ServerPlayer) + ToolboxHandler.syncData(player); + continue; + } + + int count = playerStack.getCount(); + int targetAmount = (referenceItem.getMaxStackSize() + 1) / 2; + + if (count < targetAmount) { + int amountToReplenish = targetAmount - count; + + if (isOpenInContainer(player)) { + ItemStack extracted = inventory.takeFromCompartment(amountToReplenish, slot, true); + if (!extracted.isEmpty()) { + ToolboxHandler.unequip(player, hotbarSlot, false); + ToolboxHandler.syncData(player); + continue; + } + } + + ItemStack extracted = inventory.takeFromCompartment(amountToReplenish, slot, false); + if (!extracted.isEmpty()) { + update = true; + ItemStack template = playerStack.isEmpty() ? extracted : playerStack; + playerInv.setItem(hotbarSlot, + ItemHandlerHelper.copyStackWithSize(template, count + extracted.getCount())); + } + } + + if (count > targetAmount) { + int amountToDeposit = count - targetAmount; + ItemStack toDistribute = ItemHandlerHelper.copyStackWithSize(playerStack, amountToDeposit); + + if (isOpenInContainer(player)) { + int deposited = amountToDeposit - inventory.distributeToCompartment(toDistribute, slot, true) + .getCount(); + if (deposited > 0) { + ToolboxHandler.unequip(player, hotbarSlot, true); + ToolboxHandler.syncData(player); + continue; + } + } + + int deposited = amountToDeposit - inventory.distributeToCompartment(toDistribute, slot, false) + .getCount(); + if (deposited > 0) { + update = true; + playerInv.setItem(hotbarSlot, + ItemHandlerHelper.copyStackWithSize(playerStack, count - deposited)); + } + } + } + + if (clear) + toolboxSlots.remove(); + } + + if (update) + + sendData(); + + } + + private boolean isOpenInContainer(Player player) { + return player.containerMenu instanceof ToolboxMenu + && ((ToolboxMenu) player.containerMenu).contentHolder == this; + } + + public void unequipTracked() { + if (level.isClientSide) + return; + + Set affected = new HashSet<>(); + + for (Iterator>> toolboxSlots = connectedPlayers.entrySet() + .iterator(); toolboxSlots.hasNext();) { + + Entry> toolboxSlotEntry = toolboxSlots.next(); + WeakHashMap set = toolboxSlotEntry.getValue(); + + for (Iterator> playerEntries = set.entrySet() + .iterator(); playerEntries.hasNext();) { + Entry playerEntry = playerEntries.next(); + + Player player = playerEntry.getKey(); + int hotbarSlot = playerEntry.getValue(); + + ToolboxHandler.unequip(player, hotbarSlot, false); + if (player instanceof ServerPlayer) + affected.add((ServerPlayer) player); + } + } + + for (ServerPlayer player : affected) + ToolboxHandler.syncData(player); + connectedPlayers.clear(); + } + + public void unequip(int slot, Player player, int hotbarSlot, boolean keepItems) { + if (!connectedPlayers.containsKey(slot)) + return; + connectedPlayers.get(slot) + .remove(player); + if (keepItems) + return; + + Inventory playerInv = player.getInventory(); + ItemStack playerStack = playerInv.getItem(hotbarSlot); + ItemStack toInsert = ToolboxInventory.cleanItemNBT(playerStack.copy()); + ItemStack remainder = inventory.distributeToCompartment(toInsert, slot, false); + + if (remainder.getCount() != toInsert.getCount()) + playerInv.setItem(hotbarSlot, remainder); + } + + private void tickAudio() { + Vec3 vec = VecHelper.getCenterOf(worldPosition); + if (lid.settled()) { + if (openCount > 0 && lid.getChaseTarget() == 0) { + level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 0.25F, + level.random.nextFloat() * 0.1F + 1.2F, true); + level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, 0.1F, + level.random.nextFloat() * 0.1F + 1.1F, true); + } + if (openCount == 0 && lid.getChaseTarget() == 1) + level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.1F, + level.random.nextFloat() * 0.1F + 1.1F, true); + + } else if (openCount == 0 && lid.getChaseTarget() == 0 && lid.getValue(0) > 1 / 16f + && lid.getValue(1) < 1 / 16f) + level.playLocalSound(vec.x, vec.y, vec.z, SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.25F, + level.random.nextFloat() * 0.1F + 1.2F, true); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return inventoryProvider.cast(); + return super.getCapability(cap, side); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + inventory.deserializeNBT(compound.getCompound("Inventory")); + super.read(compound, clientPacket); + if (compound.contains("UniqueId", 11)) + this.uniqueId = compound.getUUID("UniqueId"); + if (compound.contains("CustomName", 8)) + this.customName = Component.Serializer.fromJson(compound.getString("CustomName")); + if (clientPacket) + openCount = compound.getInt("OpenCount"); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + if (uniqueId == null) + uniqueId = UUID.randomUUID(); + + compound.put("Inventory", inventory.serializeNBT()); + compound.putUUID("UniqueId", uniqueId); + + if (customName != null) + compound.putString("CustomName", Component.Serializer.toJson(customName)); + super.write(compound, clientPacket); + if (clientPacket) + compound.putInt("OpenCount", openCount); + } + + @Override + public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { + return ToolboxMenu.create(id, inv, this); + } + + @Override + public void lazyTick() { + updateOpenCount(); + // keep re-advertising active TEs + ToolboxHandler.onLoad(this); + super.lazyTick(); + } + + void updateOpenCount() { + if (level.isClientSide) + return; + if (openCount == 0) + return; + + int prevOpenCount = openCount; + openCount = 0; + + for (Player playerentity : level.getEntitiesOfClass(Player.class, new AABB(worldPosition).inflate(8))) + if (playerentity.containerMenu instanceof ToolboxMenu + && ((ToolboxMenu) playerentity.containerMenu).contentHolder == this) + openCount++; + + if (prevOpenCount != openCount) + sendData(); + } + + public void startOpen(Player player) { + if (player.isSpectator()) + return; + if (openCount < 0) + openCount = 0; + openCount++; + sendData(); + } + + public void stopOpen(Player player) { + if (player.isSpectator()) + return; + openCount--; + sendData(); + } + + public void connectPlayer(int slot, Player player, int hotbarSlot) { + if (level.isClientSide) + return; + WeakHashMap map = connectedPlayers.computeIfAbsent(slot, WeakHashMap::new); + Integer previous = map.get(player); + if (previous != null) { + if (previous == hotbarSlot) + return; + ToolboxHandler.unequip(player, previous, false); + } + map.put(player, hotbarSlot); + } + + public void readInventory(CompoundTag compound) { + inventory.deserializeNBT(compound); + } + + public void setUniqueId(UUID uniqueId) { + this.uniqueId = uniqueId; + } + + public UUID getUniqueId() { + return uniqueId; + } + + public boolean isFullyInitialized() { + // returns true when uniqueId has been initialized + return uniqueId != null; + } + + public void setCustomName(Component customName) { + this.customName = customName; + } + + @Override + public Component getDisplayName() { + return customName != null ? customName + : AllBlocks.TOOLBOXES.get(getColor()) + .get() + .getName(); + } + + @Override + public Component getCustomName() { + return customName; + } + + @Override + public boolean hasCustomName() { + return customName != null; + } + + @Override + public Component getName() { + return customName; + } + + @SuppressWarnings("deprecation") + @Override + public void setBlockState(BlockState state) { + super.setBlockState(state); + colorProvider.reset(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDisposeAllPacket.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDisposeAllPacket.java similarity index 84% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDisposeAllPacket.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDisposeAllPacket.java index 920ab41dbd..e9a6fb2ffd 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDisposeAllPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDisposeAllPacket.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import java.util.function.Supplier; +package com.simibubi.create.content.equipment.toolbox; import org.apache.commons.lang3.mutable.MutableBoolean; @@ -35,10 +33,9 @@ public class ToolboxDisposeAllPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); Level world = player.level; BlockEntity blockEntity = world.getBlockEntity(toolboxPos); @@ -46,9 +43,9 @@ public class ToolboxDisposeAllPacket extends SimplePacketBase { if (player.distanceToSqr(toolboxPos.getX() + 0.5, toolboxPos.getY(), toolboxPos.getZ() + 0.5) > maxRange * maxRange) return; - if (!(blockEntity instanceof ToolboxTileEntity)) + if (!(blockEntity instanceof ToolboxBlockEntity)) return; - ToolboxTileEntity toolbox = (ToolboxTileEntity) blockEntity; + ToolboxBlockEntity toolbox = (ToolboxBlockEntity) blockEntity; CompoundTag compound = player.getPersistentData() .getCompound("CreateToolboxData"); @@ -73,9 +70,8 @@ public class ToolboxDisposeAllPacket extends SimplePacketBase { if (sendData.booleanValue()) ToolboxHandler.syncData(player); - }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDyeingRecipe.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDyeingRecipe.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDyeingRecipe.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDyeingRecipe.java index df2498433c..50b5171e70 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxDyeingRecipe.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxDyeingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxEquipPacket.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxEquipPacket.java similarity index 82% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxEquipPacket.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxEquipPacket.java index 55538921ed..13c8c32843 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxEquipPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxEquipPacket.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; - -import java.util.function.Supplier; +package com.simibubi.create.content.equipment.toolbox; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -44,10 +42,9 @@ public class ToolboxEquipPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer player = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); Level world = player.level; if (toolboxPos == null) { @@ -62,7 +59,7 @@ public class ToolboxEquipPacket extends SimplePacketBase { if (player.distanceToSqr(toolboxPos.getX() + 0.5, toolboxPos.getY(), toolboxPos.getZ() + 0.5) > maxRange * maxRange) return; - if (!(blockEntity instanceof ToolboxTileEntity)) + if (!(blockEntity instanceof ToolboxBlockEntity)) return; ToolboxHandler.unequip(player, hotbarSlot, false); @@ -72,12 +69,12 @@ public class ToolboxEquipPacket extends SimplePacketBase { return; } - ToolboxTileEntity toolboxTileEntity = (ToolboxTileEntity) blockEntity; + ToolboxBlockEntity toolboxBlockEntity = (ToolboxBlockEntity) blockEntity; ItemStack playerStack = player.getInventory().getItem(hotbarSlot); if (!playerStack.isEmpty() && !ToolboxInventory.canItemsShareCompartment(playerStack, - toolboxTileEntity.inventory.filters.get(slot))) { - toolboxTileEntity.inventory.inLimitedMode(inventory -> { + toolboxBlockEntity.inventory.filters.get(slot))) { + toolboxBlockEntity.inventory.inLimitedMode(inventory -> { ItemStack remainder = ItemHandlerHelper.insertItemStacked(inventory, playerStack, false); if (!remainder.isEmpty()) remainder = ItemHandlerHelper.insertItemStacked(new ItemReturnInvWrapper(player.getInventory()), @@ -99,10 +96,10 @@ public class ToolboxEquipPacket extends SimplePacketBase { player.getPersistentData() .put("CreateToolboxData", compound); - toolboxTileEntity.connectPlayer(slot, player, hotbarSlot); + toolboxBlockEntity.connectPlayer(slot, player, hotbarSlot); ToolboxHandler.syncData(player); }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandler.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandler.java similarity index 78% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandler.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandler.java index 5dc5d971e4..e88c8edf3f 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandler.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import java.util.List; import java.util.WeakHashMap; import java.util.stream.Collectors; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.networking.ISyncPersistentData.PersistentDataPacket; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.WorldAttached; import net.minecraft.core.BlockPos; @@ -24,17 +24,17 @@ import net.minecraftforge.network.PacketDistributor; public class ToolboxHandler { - public static final WorldAttached> toolboxes = + public static final WorldAttached> toolboxes = new WorldAttached<>(w -> new WeakHashMap<>()); - public static void onLoad(ToolboxTileEntity te) { - toolboxes.get(te.getLevel()) - .put(te.getBlockPos(), te); + public static void onLoad(ToolboxBlockEntity be) { + toolboxes.get(be.getLevel()) + .put(be.getBlockPos(), be); } - public static void onUnload(ToolboxTileEntity te) { - toolboxes.get(te.getLevel()) - .remove(te.getBlockPos()); + public static void onUnload(ToolboxBlockEntity be) { + toolboxes.get(be.getLevel()) + .remove(be.getBlockPos()); } static int validationTimer = 20; @@ -76,8 +76,8 @@ public class ToolboxHandler { } BlockEntity prevBlockEntity = world.getBlockEntity(pos); - if (prevBlockEntity instanceof ToolboxTileEntity) - ((ToolboxTileEntity) prevBlockEntity).connectPlayer(slot, player, i); + if (prevBlockEntity instanceof ToolboxBlockEntity) + ((ToolboxBlockEntity) prevBlockEntity).connectPlayer(slot, player, i); } if (sendData) @@ -97,11 +97,11 @@ public class ToolboxHandler { } public static void syncData(Player player) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new PersistentDataPacket(player)); } - public static List getNearest(LevelAccessor world, Player player, int maxAmount) { + public static List getNearest(LevelAccessor world, Player player, int maxAmount) { Vec3 location = player.position(); double maxRange = getMaxRange(player); return toolboxes.get(world) @@ -111,7 +111,7 @@ public class ToolboxHandler { .sorted((p1, p2) -> Double.compare(distance(location, p1), distance(location, p2))) .limit(maxAmount) .map(toolboxes.get(world)::get) - .filter(ToolboxTileEntity::isFullyInitialized) + .filter(ToolboxBlockEntity::isFullyInitialized) .collect(Collectors.toList()); } @@ -128,14 +128,14 @@ public class ToolboxHandler { int prevSlot = prevData.getInt("Slot"); BlockEntity prevBlockEntity = world.getBlockEntity(prevPos); - if (prevBlockEntity instanceof ToolboxTileEntity) { - ToolboxTileEntity toolbox = (ToolboxTileEntity) prevBlockEntity; + if (prevBlockEntity instanceof ToolboxBlockEntity) { + ToolboxBlockEntity toolbox = (ToolboxBlockEntity) prevBlockEntity; toolbox.unequip(prevSlot, player, hotbarSlot, keepItems || !ToolboxHandler.withinRange(player, toolbox)); } compound.remove(key); } - public static boolean withinRange(Player player, ToolboxTileEntity box) { + public static boolean withinRange(Player player, ToolboxBlockEntity box) { if (player.level != box.getLevel()) return false; double maxRange = getMaxRange(player); @@ -147,7 +147,7 @@ public class ToolboxHandler { } public static double getMaxRange(Player player) { - return AllConfigs.SERVER.curiosities.toolboxRange.get() + return AllConfigs.server().equipment.toolboxRange.get() .doubleValue(); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandlerClient.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandlerClient.java similarity index 88% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandlerClient.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandlerClient.java index 42db1d8081..5b8e2fb01a 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxHandlerClient.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxHandlerClient.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import static com.simibubi.create.foundation.gui.AllGuiTextures.TOOLBELT_HOTBAR_OFF; import static com.simibubi.create.foundation.gui.AllGuiTextures.TOOLBELT_HOTBAR_ON; @@ -12,8 +12,8 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.networking.AllPackets; import net.createmod.catnip.gui.ScreenOpener; import net.minecraft.client.Minecraft; @@ -60,7 +60,7 @@ public class ToolboxHandlerClient { return false; ItemStack result = ItemStack.EMPTY; - List toolboxes = ToolboxHandler.getNearest(player.level, player, 8); + List toolboxes = ToolboxHandler.getNearest(player.level, player, 8); if (toolboxes.isEmpty()) return false; @@ -80,8 +80,8 @@ public class ToolboxHandlerClient { if (result.isEmpty()) return false; - for (ToolboxTileEntity toolboxTileEntity : toolboxes) { - ToolboxInventory inventory = toolboxTileEntity.inventory; + for (ToolboxBlockEntity toolboxBlockEntity : toolboxes) { + ToolboxInventory inventory = toolboxBlockEntity.inventory; for (int comp = 0; comp < 8; comp++) { ItemStack inSlot = inventory.takeFromCompartment(1, comp, true); if (inSlot.isEmpty()) @@ -91,8 +91,8 @@ public class ToolboxHandlerClient { if (!ItemStack.tagMatches(inSlot, result)) continue; - AllPackets.channel.sendToServer( - new ToolboxEquipPacket(toolboxTileEntity.getBlockPos(), comp, player.getInventory().selected)); + AllPackets.getChannel().sendToServer( + new ToolboxEquipPacket(toolboxBlockEntity.getBlockPos(), comp, player.getInventory().selected)); return true; } @@ -115,8 +115,8 @@ public class ToolboxHandlerClient { return; Level level = player.level; - List toolboxes = ToolboxHandler.getNearest(player.level, player, 8); - toolboxes.sort(Comparator.comparing(ToolboxTileEntity::getUniqueId)); + List toolboxes = ToolboxHandler.getNearest(player.level, player, 8); + toolboxes.sort(Comparator.comparing(ToolboxBlockEntity::getUniqueId)); CompoundTag compound = player.getPersistentData() .getCompound("CreateToolboxData"); @@ -132,9 +132,9 @@ public class ToolboxHandlerClient { if (canReachToolbox) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof ToolboxTileEntity) { + if (blockEntity instanceof ToolboxBlockEntity) { RadialToolboxMenu screen = new RadialToolboxMenu(toolboxes, - RadialToolboxMenu.State.SELECT_ITEM_UNEQUIP, (ToolboxTileEntity) blockEntity); + RadialToolboxMenu.State.SELECT_ITEM_UNEQUIP, (ToolboxBlockEntity) blockEntity); screen.prevSlot(compound.getCompound(slotKey) .getInt("Slot")); ScreenOpener.open(screen); diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxInventory.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxInventory.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxInventory.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxInventory.java index e6b6a94e05..c4f51c4f31 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxInventory.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxInventory.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import java.util.ArrayList; import java.util.List; @@ -20,13 +20,13 @@ public class ToolboxInventory extends ItemStackHandler { public static final int STACKS_PER_COMPARTMENT = 4; List filters; boolean settling; - private ToolboxTileEntity te; + private ToolboxBlockEntity blockEntity; private boolean limitedMode; - public ToolboxInventory(ToolboxTileEntity te) { + public ToolboxInventory(ToolboxBlockEntity be) { super(8 * STACKS_PER_COMPARTMENT); - this.te = te; + this.blockEntity = be; limitedMode = false; filters = new ArrayList<>(); settling = false; @@ -83,7 +83,7 @@ public class ToolboxInventory extends ItemStackHandler { } } settling = false; - te.sendData(); + blockEntity.sendData(); } @Override @@ -109,7 +109,7 @@ public class ToolboxInventory extends ItemStackHandler { if (!stack.isEmpty() && filters.get(compartment) .isEmpty()) { filters.set(compartment, ItemHandlerHelper.copyStackWithSize(stack, 1)); - te.sendData(); + blockEntity.sendData(); } } @@ -121,7 +121,7 @@ public class ToolboxInventory extends ItemStackHandler { if (!stack.isEmpty() && filters.get(compartment) .isEmpty()) { filters.set(compartment, ItemHandlerHelper.copyStackWithSize(stack, 1)); - te.sendData(); + blockEntity.sendData(); } } return insertItem; @@ -136,10 +136,10 @@ public class ToolboxInventory extends ItemStackHandler { @Override protected void onContentsChanged(int slot) { - if (!settling && !te.getLevel().isClientSide) + if (!settling && !blockEntity.getLevel().isClientSide) settle(slot / STACKS_PER_COMPARTMENT); - te.sendData(); - te.setChanged(); + blockEntity.sendData(); + blockEntity.setChanged(); super.onContentsChanged(slot); } diff --git a/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxMenu.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxMenu.java new file mode 100644 index 0000000000..8dacb716f8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxMenu.java @@ -0,0 +1,159 @@ +package com.simibubi.create.content.equipment.toolbox; + +import static com.simibubi.create.content.equipment.toolbox.ToolboxInventory.STACKS_PER_COMPARTMENT; + +import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.foundation.gui.menu.MenuBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.SlotItemHandler; + +public class ToolboxMenu extends MenuBase { + + public ToolboxMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public ToolboxMenu(MenuType type, int id, Inventory inv, ToolboxBlockEntity be) { + super(type, id, inv, be); + be.startOpen(player); + } + + public static ToolboxMenu create(int id, Inventory inv, ToolboxBlockEntity be) { + return new ToolboxMenu(AllMenuTypes.TOOLBOX.get(), id, inv, be); + } + + @Override + protected ToolboxBlockEntity createOnClient(FriendlyByteBuf extraData) { + BlockPos readBlockPos = extraData.readBlockPos(); + CompoundTag readNbt = extraData.readNbt(); + + ClientLevel world = Minecraft.getInstance().level; + BlockEntity blockEntity = world.getBlockEntity(readBlockPos); + if (blockEntity instanceof ToolboxBlockEntity) { + ToolboxBlockEntity toolbox = (ToolboxBlockEntity) blockEntity; + toolbox.readClient(readNbt); + return toolbox; + } + + return null; + } + + @Override + public ItemStack quickMoveStack(Player player, int index) { + Slot clickedSlot = getSlot(index); + if (!clickedSlot.hasItem()) + return ItemStack.EMPTY; + + ItemStack stack = clickedSlot.getItem(); + int size = contentHolder.inventory.getSlots(); + boolean success = false; + if (index < size) { + success = !moveItemStackTo(stack, size, slots.size(), false); + contentHolder.inventory.onContentsChanged(index); + } else + success = !moveItemStackTo(stack, 0, size - 1, false); + + return success ? ItemStack.EMPTY : stack; + } + + @Override + protected void initAndReadInventory(ToolboxBlockEntity contentHolder) { + + } + + @Override + public void clicked(int index, int flags, ClickType type, Player player) { + int size = contentHolder.inventory.getSlots(); + + if (index >= 0 && index < size) { + ItemStack itemInClickedSlot = getSlot(index).getItem(); + ItemStack carried = getCarried(); + + if (type == ClickType.PICKUP && !carried.isEmpty() && !itemInClickedSlot.isEmpty() + && ToolboxInventory.canItemsShareCompartment(itemInClickedSlot, carried)) { + int subIndex = index % STACKS_PER_COMPARTMENT; + if (subIndex != STACKS_PER_COMPARTMENT - 1) { + clicked(index - subIndex + STACKS_PER_COMPARTMENT - 1, flags, type, player); + return; + } + } + + if (type == ClickType.PICKUP && carried.isEmpty() && itemInClickedSlot.isEmpty()) + if (!player.level.isClientSide) { + contentHolder.inventory.filters.set(index / STACKS_PER_COMPARTMENT, ItemStack.EMPTY); + contentHolder.sendData(); + } + + } + super.clicked(index, flags, type, player); + } + + @Override + public boolean canDragTo(Slot slot) { + return slot.index > contentHolder.inventory.getSlots() && super.canDragTo(slot); + } + + public ItemStack getFilter(int compartment) { + return contentHolder.inventory.filters.get(compartment); + } + + public int totalCountInCompartment(int compartment) { + int count = 0; + int baseSlot = compartment * STACKS_PER_COMPARTMENT; + for (int i = 0; i < STACKS_PER_COMPARTMENT; i++) + count += getSlot(baseSlot + i).getItem() + .getCount(); + return count; + } + + public boolean renderPass; + + @Override + protected void addSlots() { + ToolboxInventory inventory = contentHolder.inventory; + + int x = 79; + int y = 37; + + int[] xOffsets = { x, x + 33, x + 66, x + 66 + 6, x + 66, x + 33, x, x - 6 }; + int[] yOffsets = { y, y - 6, y, y + 33, y + 66, y + 66 + 6, y + 66, y + 33 }; + + for (int compartment = 0; compartment < 8; compartment++) { + int baseIndex = compartment * STACKS_PER_COMPARTMENT; + + // Representative Slots + addSlot(new ToolboxSlot(this, inventory, baseIndex, xOffsets[compartment], yOffsets[compartment])); + + // Hidden Slots + for (int i = 1; i < STACKS_PER_COMPARTMENT; i++) + addSlot(new SlotItemHandler(inventory, baseIndex + i, -10000, -10000)); + } + + addPlayerSlots(8, 165); + } + + @Override + protected void saveData(ToolboxBlockEntity contentHolder) { + + } + + @Override + public void removed(Player playerIn) { + super.removed(playerIn); + if (!playerIn.level.isClientSide) + contentHolder.stopOpen(playerIn); + } + +} diff --git a/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxRenderer.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxRenderer.java new file mode 100644 index 0000000000..6905240f40 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxRenderer.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.equipment.toolbox; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class ToolboxRenderer extends SmartBlockEntityRenderer { + + public ToolboxRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(ToolboxBlockEntity blockEntity, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + BlockState blockState = blockEntity.getBlockState(); + Direction facing = blockState.getValue(ToolboxBlock.FACING) + .getOpposite(); + SuperByteBuffer lid = + CachedPartialBuffers.partial(AllPartialModels.TOOLBOX_LIDS.get(blockEntity.getColor()), blockState); + SuperByteBuffer drawer = CachedPartialBuffers.partial(AllPartialModels.TOOLBOX_DRAWER, blockState); + + float lidAngle = blockEntity.lid.getValue(partialTicks); + float drawerOffset = blockEntity.drawers.getValue(partialTicks); + + VertexConsumer builder = buffer.getBuffer(RenderType.cutoutMipped()); + lid.centre() + .rotateY(-facing.toYRot()) + .unCentre() + .translate(0, 6 / 16f, 12 / 16f) + .rotateX(135 * lidAngle) + .translate(0, -6 / 16f, -12 / 16f) + .light(light) + .renderInto(ms, builder); + + for (int offset : Iterate.zeroAndOne) { + drawer.centre() + .rotateY(-facing.toYRot()) + .unCentre() + .translate(0, offset * 1 / 8f, -drawerOffset * .175f * (2 - offset)) + .light(light) + .renderInto(ms, builder); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxScreen.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxScreen.java similarity index 88% rename from src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxScreen.java rename to src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxScreen.java index 9969f4f3de..f54f61aea1 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/toolbox/ToolboxScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.toolbox; +package com.simibubi.create.content.equipment.toolbox; import java.util.Collections; import java.util.List; @@ -7,14 +7,14 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.element.GuiGameElement; @@ -26,7 +26,7 @@ import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.ItemStack; -public class ToolboxScreen extends AbstractSimiContainerScreen { +public class ToolboxScreen extends AbstractSimiContainerScreen { protected static final AllGuiTextures BG = AllGuiTextures.TOOLBOX; protected static final AllGuiTextures PLAYER = AllGuiTextures.PLAYER_INVENTORY; @@ -38,8 +38,8 @@ public class ToolboxScreen extends AbstractSimiContainerScreen private List extraAreas = Collections.emptyList(); - public ToolboxScreen(ToolboxContainer container, Inventory inv, Component title) { - super(container, inv, title); + public ToolboxScreen(ToolboxMenu menu, Inventory inv, Component title) { + super(menu, inv, title); init(); } @@ -59,7 +59,7 @@ public class ToolboxScreen extends AbstractSimiContainerScreen disposeButton = new IconButton(leftPos + 30 + 81, topPos + 69, AllIcons.I_TOOLBOX); disposeButton.withCallback(() -> { - AllPackets.channel.sendToServer(new ToolboxDisposeAllPacket(menu.contentHolder.getBlockPos())); + AllPackets.getChannel().sendToServer(new ToolboxDisposeAllPacket(menu.contentHolder.getBlockPos())); }); disposeButton.setToolTip(CreateLang.translateDirect("toolbox.depositBox")); addRenderableWidget(disposeButton); @@ -82,7 +82,7 @@ public class ToolboxScreen extends AbstractSimiContainerScreen int y = topPos; BG.render(ms, x, y, this); - font.draw(ms, title, x + 15, y + 4, 0x442000); + font.draw(ms, title, x + 15, y + 4, 0x592424); int invX = leftPos; int invY = topPos + imageHeight - PLAYER.getHeight(); @@ -142,7 +142,7 @@ public class ToolboxScreen extends AbstractSimiContainerScreen .translate(0, -6 / 16f, 12 / 16f) .rotateX(-105 * menu.contentHolder.lid.getValue(partialTicks)) .translate(0, 6 / 16f, -12 / 16f); - PartialModelGuiElement.of(AllBlockPartials.TOOLBOX_LIDS.get(color)) + PartialModelGuiElement.of(AllPartialModels.TOOLBOX_LIDS.get(color)) .render(ms); ms.popPose(); @@ -150,7 +150,7 @@ public class ToolboxScreen extends AbstractSimiContainerScreen ms.pushPose(); ms.translate(0, -offset * 1 / 8f, menu.contentHolder.drawers.getValue(partialTicks) * -.175f * (2 - offset)); - PartialModelGuiElement.of(AllBlockPartials.TOOLBOX_DRAWER) + PartialModelGuiElement.of(AllPartialModels.TOOLBOX_DRAWER) .render(ms); ms.popPose(); } diff --git a/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxSlot.java b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxSlot.java new file mode 100644 index 0000000000..a87c215943 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/toolbox/ToolboxSlot.java @@ -0,0 +1,20 @@ +package com.simibubi.create.content.equipment.toolbox; + +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class ToolboxSlot extends SlotItemHandler { + + private ToolboxMenu toolboxMenu; + + public ToolboxSlot(ToolboxMenu menu, IItemHandler itemHandler, int index, int xPosition, int yPosition) { + super(itemHandler, index, xPosition, yPosition); + this.toolboxMenu = menu; + } + + @Override + public boolean isActive() { + return !toolboxMenu.renderPass && super.isActive(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java b/src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchable.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java rename to src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchable.java index 2b37978cd0..dc7730ba0a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java +++ b/src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchable.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.contraptions.wrench; +package com.simibubi.create.content.equipment.wrench; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; import net.createmod.catnip.utility.VoxelShaper; import net.minecraft.core.BlockPos; @@ -31,12 +31,12 @@ public interface IWrenchable { if (!rotated.canSurvive(world, context.getClickedPos())) return InteractionResult.PASS; - KineticTileEntity.switchToBlockState(world, context.getClickedPos(), updateAfterWrenched(rotated, context)); + KineticBlockEntity.switchToBlockState(world, context.getClickedPos(), updateAfterWrenched(rotated, context)); - BlockEntity te = context.getLevel() + BlockEntity be = context.getLevel() .getBlockEntity(context.getClickedPos()); - if (te instanceof GeneratingKineticTileEntity) { - ((GeneratingKineticTileEntity) te).reActivateSource = true; + if (be instanceof GeneratingKineticBlockEntity) { + ((GeneratingKineticBlockEntity) be).reActivateSource = true; } if (world.getBlockState(context.getClickedPos()) != state) diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchableWithBracket.java b/src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchableWithBracket.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchableWithBracket.java rename to src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchableWithBracket.java index 14bf177e1b..dd7f115fd2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchableWithBracket.java +++ b/src/main/java/com/simibubi/create/content/equipment/wrench/IWrenchableWithBracket.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.wrench; +package com.simibubi.create.content.equipment.wrench; import java.util.Optional; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidPropagator; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchEventHandler.java b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchEventHandler.java new file mode 100644 index 0000000000..dff633a2f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchEventHandler.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.equipment.wrench; + +import com.simibubi.create.AllItems; +import com.simibubi.create.AllTags.AllItemTags; + +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class WrenchEventHandler { + + @SubscribeEvent(priority = EventPriority.HIGH) + public static void useOwnWrenchLogicForCreateBlocks(PlayerInteractEvent.RightClickBlock event) { + Player player = event.getPlayer(); + ItemStack itemStack = event.getItemStack(); + + if (event.isCanceled()) + return; + if (event.getWorld() == null) + return; + if (player == null || !player.mayBuild()) + return; + if (itemStack.isEmpty()) + return; + if (AllItems.WRENCH.isIn(itemStack)) + return; + if (!AllItemTags.WRENCH.matches(itemStack.getItem())) + return; + + BlockState state = event.getWorld() + .getBlockState(event.getPos()); + Block block = state.getBlock(); + + if (!(block instanceof IWrenchable)) + return; + + BlockHitResult hitVec = event.getHitVec(); + UseOnContext context = new UseOnContext(player, event.getHand(), hitVec); + IWrenchable actor = (IWrenchable) block; + + InteractionResult result = + player.isShiftKeyDown() ? actor.onSneakWrenched(state, context) : actor.onWrenched(state, context); + event.setCanceled(true); + event.setCancellationResult(result); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItem.java b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItem.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItem.java rename to src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItem.java index 58cdb01d76..e1f200f4b8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/WrenchItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.wrench; +package com.simibubi.create.content.equipment.wrench; import java.util.function.Consumer; diff --git a/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItemRenderer.java new file mode 100644 index 0000000000..402db5e46f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/wrench/WrenchItemRenderer.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.equipment.wrench; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueHandler; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; +import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.world.item.ItemStack; + +public class WrenchItemRenderer extends CustomRenderedItemModelRenderer { + + protected static final PartialModel GEAR = new PartialModel(Create.asResource("item/wrench/gear")); + + @Override + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, + PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + renderer.render(model.getOriginalModel(), light); + + float xOffset = -1/16f; + ms.translate(-xOffset, 0, 0); + ms.mulPose(Vector3f.YP.rotationDegrees(ScrollValueHandler.getScroll(AnimationTickHolder.getPartialTicks()))); + ms.translate(xOffset, 0, 0); + + renderer.render(GEAR.get(), light); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ConfigureZapperPacket.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ConfigureZapperPacket.java similarity index 80% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ConfigureZapperPacket.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ConfigureZapperPacket.java index 99c842730e..6b90d8b2c7 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ConfigureZapperPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ConfigureZapperPacket.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; - -import java.util.function.Supplier; +package com.simibubi.create.content.equipment.zapper; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -32,9 +30,9 @@ public abstract class ConfigureZapperPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) { return; } @@ -43,7 +41,7 @@ public abstract class ConfigureZapperPacket extends SimplePacketBase { configureZapper(stack); } }); - context.get().setPacketHandled(true); + return true; } public abstract void configureZapper(ItemStack stack); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/PlacementPatterns.java b/src/main/java/com/simibubi/create/content/equipment/zapper/PlacementPatterns.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/PlacementPatterns.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/PlacementPatterns.java index 7321a737f7..5f482639da 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/PlacementPatterns.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/PlacementPatterns.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.List; import java.util.Random; diff --git a/src/main/java/com/simibubi/create/content/equipment/zapper/ShootGadgetPacket.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootGadgetPacket.java new file mode 100644 index 0000000000..8b624b98a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootGadgetPacket.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.equipment.zapper; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.network.NetworkEvent.Context; + +public abstract class ShootGadgetPacket extends SimplePacketBase { + + public Vec3 location; + public InteractionHand hand; + public boolean self; + + public ShootGadgetPacket(Vec3 location, InteractionHand hand, boolean self) { + this.location = location; + this.hand = hand; + this.self = self; + } + + public ShootGadgetPacket(FriendlyByteBuf buffer) { + hand = buffer.readBoolean() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + self = buffer.readBoolean(); + location = new Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + readAdditional(buffer); + } + + public final void write(FriendlyByteBuf buffer) { + buffer.writeBoolean(hand == InteractionHand.MAIN_HAND); + buffer.writeBoolean(self); + buffer.writeDouble(location.x); + buffer.writeDouble(location.y); + buffer.writeDouble(location.z); + writeAdditional(buffer); + } + + protected abstract void readAdditional(FriendlyByteBuf buffer); + + protected abstract void writeAdditional(FriendlyByteBuf buffer); + + @OnlyIn(Dist.CLIENT) + protected abstract void handleAdditional(); + + @OnlyIn(Dist.CLIENT) + protected abstract ShootableGadgetRenderHandler getHandler(); + + @Override + @OnlyIn(Dist.CLIENT) + public boolean handle(Context context) { + context.enqueueWork(() -> { + Entity renderViewEntity = Minecraft.getInstance() + .getCameraEntity(); + if (renderViewEntity == null) + return; + if (renderViewEntity.position() + .distanceTo(location) > 100) + return; + + ShootableGadgetRenderHandler handler = getHandler(); + handleAdditional(); + if (self) + handler.shoot(hand, location); + else + handler.playSound(hand, location); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetItemMethods.java similarity index 87% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetItemMethods.java index 85cdf59d0b..d03ff7a432 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetItemMethods.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.function.Function; import java.util.function.Predicate; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; @@ -29,8 +29,8 @@ public class ShootableGadgetItemMethods { public static void sendPackets(Player player, Function factory) { if (!(player instanceof ServerPlayer)) return; - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> player), factory.apply(false)); - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), factory.apply(true)); + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> player), factory.apply(false)); + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), factory.apply(true)); } public static boolean shouldSwap(Player player, ItemStack item, InteractionHand hand, Predicate predicate) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetRenderHandler.java similarity index 99% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetRenderHandler.java index 4c70d5dcc6..2f13914955 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ShootableGadgetRenderHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperBeamPacket.java similarity index 89% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperBeamPacket.java index 352728857a..e4b79c0f04 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperBeamPacket.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler.LaserBeam; +import com.simibubi.create.content.equipment.zapper.ZapperRenderHandler.LaserBeam; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.InteractionHand; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperInteractionHandler.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperInteractionHandler.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperInteractionHandler.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperInteractionHandler.java index 84c37ddf97..b38a796ce5 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperInteractionHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.Objects; @@ -78,9 +78,9 @@ public class ZapperInteractionHandler { newState = newState.setValue(BlockStateProperties.WATERLOGGED, false); CompoundTag data = null; - BlockEntity tile = player.level.getBlockEntity(pos); - if (tile != null) { - data = tile.saveWithFullMetadata(); + BlockEntity blockEntity = player.level.getBlockEntity(pos); + if (blockEntity != null) { + data = blockEntity.saveWithFullMetadata(); data.remove("x"); data.remove("y"); data.remove("z"); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItem.java similarity index 87% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItem.java index 261c9f68f4..7e4e0b5f7a 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItem.java @@ -1,19 +1,23 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.List; import javax.annotation.Nonnull; +import org.jetbrains.annotations.Nullable; + import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.item.ItemDescription; +import com.simibubi.create.foundation.item.CustomArmPoseItem; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.NBTProcessors; import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.NBTProcessors; import net.minecraft.ChatFormatting; +import net.minecraft.client.model.HumanoidModel.ArmPose; +import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; @@ -43,7 +47,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -public abstract class ZapperItem extends Item { +public abstract class ZapperItem extends Item implements CustomArmPoseItem { public ZapperItem(Properties properties) { super(properties.stacksTo(1)); @@ -58,10 +62,9 @@ public abstract class ZapperItem extends Item { .getCompound("BlockUsed")) .getBlock() .getName(); - ItemDescription.add(tooltip, - CreateLang.translateDirect("terrainzapper.usingBlock", - usedBlock.withStyle(ChatFormatting.GRAY)) - .withStyle(ChatFormatting.DARK_GRAY)); + tooltip.add(CreateLang.translateDirect("terrainzapper.usingBlock", + usedBlock.withStyle(ChatFormatting.GRAY)) + .withStyle(ChatFormatting.DARK_GRAY)); } } @@ -213,22 +216,31 @@ public abstract class ZapperItem extends Item { return UseAnim.NONE; } + @Override + @Nullable + public ArmPose getArmPose(ItemStack stack, AbstractClientPlayer player, InteractionHand hand) { + if (!player.swinging) { + return ArmPose.CROSSBOW_HOLD; + } + return null; + } + public static void configureSettings(ItemStack stack, PlacementPatterns pattern) { CompoundTag nbt = stack.getOrCreateTag(); NBTHelper.writeEnum(nbt, "Pattern", pattern); } - public static void setTileData(Level world, BlockPos pos, BlockState state, CompoundTag data, Player player) { + public static void setBlockEntityData(Level world, BlockPos pos, BlockState state, CompoundTag data, Player player) { if (data != null && AllBlockTags.SAFE_NBT.matches(state)) { - BlockEntity tile = world.getBlockEntity(pos); - if (tile != null) { - data = NBTProcessors.process(tile, data, !player.isCreative()); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity != null) { + data = NBTProcessors.process(blockEntity, data, !player.isCreative()); if (data == null) return; data.putInt("x", pos.getX()); data.putInt("y", pos.getY()); data.putInt("z", pos.getZ()); - tile.load(data); + blockEntity.load(data); } } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItemRenderer.java similarity index 87% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItemRenderer.java index 51bb9fd42f..ebbf7d4149 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperItemRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.CreateClient; @@ -16,10 +16,10 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.CrossCollisionBlock; import net.minecraft.world.level.block.state.BlockState; -public abstract class ZapperItemRenderer extends CustomRenderedItemModelRenderer { +public abstract class ZapperItemRenderer extends CustomRenderedItemModelRenderer { @Override - protected void render(ItemStack stack, M model, PartialItemModelRenderer renderer, TransformType transformType, + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, TransformType transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { // Block indicator if (transformType == TransformType.GUI && stack.hasTag() && stack.getTag() diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperLog.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperLog.java similarity index 89% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperLog.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperLog.java index ac17c5c194..d5d5fa88c6 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperLog.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperLog.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.LinkedList; import java.util.List; @@ -35,8 +35,8 @@ public class ZapperLog { activeWorld = world; List blocks = positions.stream().map(pos -> { - BlockEntity tileEntity = world.getBlockEntity(pos); - return new StructureBlockInfo(pos, world.getBlockState(pos), tileEntity == null ? null : tileEntity.saveWithFullMetadata()); + BlockEntity blockEntity = world.getBlockEntity(pos); + return new StructureBlockInfo(pos, world.getBlockState(pos), blockEntity == null ? null : blockEntity.saveWithFullMetadata()); }).collect(Collectors.toList()); log.add(0, blocks); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperRenderHandler.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperRenderHandler.java index 6984825791..131d2a1632 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperRenderHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.LinkedList; import java.util.List; @@ -39,7 +39,7 @@ public class ZapperRenderHandler extends ShootableGadgetRenderHandler { cachedBeams.forEach(beam -> { CatnipClient.OUTLINER.endChasingLine(beam, beam.start, beam.end, 1 - beam.itensity, false) - .disableNormals() + .disableLineNormals() .colored(0xffffff) .lineWidth(beam.itensity * 1 / 8f); }); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperScreen.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/ZapperScreen.java index 6a4026e0b4..ea651b59d6 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/ZapperScreen.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.curiosities.zapper; +package com.simibubi.create.content.equipment.zapper; import java.util.Vector; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; +import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.AbstractSimiScreen; @@ -117,7 +117,7 @@ public abstract class ZapperScreen extends AbstractSimiScreen { public void removed() { ConfigureZapperPacket packet = getConfigurationPacket(); packet.configureZapper(zapper); - AllPackets.channel.sendToServer(packet); + AllPackets.getChannel().sendToServer(packet); } protected void renderZapper(PoseStack ms, int x, int y) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/Brush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/Brush.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/Brush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/Brush.java index 1953dd6cc7..577fcba0e8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/Brush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/Brush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.Collection; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ConfigureWorldshaperPacket.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ConfigureWorldshaperPacket.java similarity index 87% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ConfigureWorldshaperPacket.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ConfigureWorldshaperPacket.java index 43931770d8..4830a0ee52 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ConfigureWorldshaperPacket.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ConfigureWorldshaperPacket.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; -import com.simibubi.create.content.curiosities.zapper.ConfigureZapperPacket; -import com.simibubi.create.content.curiosities.zapper.PlacementPatterns; +import com.simibubi.create.content.equipment.zapper.ConfigureZapperPacket; +import com.simibubi.create.content.equipment.zapper.PlacementPatterns; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.InteractionHand; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CuboidBrush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CuboidBrush.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CuboidBrush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CuboidBrush.java index eb9b246bc9..9374530cf3 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CuboidBrush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CuboidBrush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CylinderBrush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CylinderBrush.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CylinderBrush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CylinderBrush.java index 1b9d2d9ccc..51c5008984 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/CylinderBrush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/CylinderBrush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/DynamicBrush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/DynamicBrush.java similarity index 98% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/DynamicBrush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/DynamicBrush.java index f9fda83654..e537b92af8 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/DynamicBrush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/DynamicBrush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.Collection; import java.util.HashSet; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/FlattenTool.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/FlattenTool.java similarity index 98% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/FlattenTool.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/FlattenTool.java index 1c16a03f90..fb2243f0ae 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/FlattenTool.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/FlattenTool.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/PlacementOptions.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/PlacementOptions.java similarity index 84% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/PlacementOptions.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/PlacementOptions.java index 8f096363d5..090a1849a1 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/PlacementOptions.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/PlacementOptions.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import com.simibubi.create.foundation.gui.AllIcons; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ShapedBrush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ShapedBrush.java similarity index 91% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ShapedBrush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ShapedBrush.java index f26117ef71..4e6b074ac5 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/ShapedBrush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/ShapedBrush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.Collection; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/SphereBrush.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/SphereBrush.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/SphereBrush.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/SphereBrush.java index c0531d4785..995afd4544 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/SphereBrush.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/SphereBrush.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainBrushes.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainBrushes.java similarity index 82% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainBrushes.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainBrushes.java index fa11468b6f..11b4a17191 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainBrushes.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainBrushes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; public enum TerrainBrushes { diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainTools.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainTools.java similarity index 84% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainTools.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainTools.java index 258485d338..562d402769 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/TerrainTools.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/TerrainTools.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.List; import javax.annotation.Nullable; -import com.simibubi.create.content.curiosities.zapper.ZapperItem; +import com.simibubi.create.content.equipment.zapper.ZapperItem; import com.simibubi.create.foundation.gui.AllIcons; import net.createmod.catnip.utility.lang.Lang; @@ -50,7 +50,7 @@ public enum TerrainTools { if (!isReplaceable(toReplace)) return; world.setBlockAndUpdate(p, paintedState); - ZapperItem.setTileData(world, p, paintedState, data, player); + ZapperItem.setBlockEntityData(world, p, paintedState, data, player); }); break; case Flatten: @@ -70,13 +70,13 @@ public enum TerrainTools { if (!isReplaceable(toReplace)) return; world.setBlockAndUpdate(p, paintedState); - ZapperItem.setTileData(world, p, paintedState, data, player); + ZapperItem.setBlockEntityData(world, p, paintedState, data, player); }); break; case Place: targetPositions.forEach(p -> { world.setBlockAndUpdate(p, paintedState); - ZapperItem.setTileData(world, p, paintedState, data, player); + ZapperItem.setBlockEntityData(world, p, paintedState, data, player); }); break; case Replace: @@ -85,7 +85,7 @@ public enum TerrainTools { if (isReplaceable(toReplace)) return; world.setBlockAndUpdate(p, paintedState); - ZapperItem.setTileData(world, p, paintedState, data, player); + ZapperItem.setBlockEntityData(world, p, paintedState, data, player); }); break; } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItem.java index 5084407f8d..ddf7e52607 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperItem.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItem.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import com.simibubi.create.content.curiosities.zapper.PlacementPatterns; -import com.simibubi.create.content.curiosities.zapper.ZapperItem; +import com.simibubi.create.content.equipment.zapper.PlacementPatterns; +import com.simibubi.create.content.equipment.zapper.ZapperItem; import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItemRenderer.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItemRenderer.java new file mode 100644 index 0000000000..8db6733592 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperItemRenderer.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.equipment.zapper.terrainzapper; + +import static java.lang.Math.max; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.zapper.ZapperItemRenderer; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.item.ItemStack; + +public class WorldshaperItemRenderer extends ZapperItemRenderer { + + protected static final PartialModel CORE = new PartialModel(Create.asResource("item/handheld_worldshaper/core")); + protected static final PartialModel CORE_GLOW = new PartialModel(Create.asResource("item/handheld_worldshaper/core_glow")); + protected static final PartialModel ACCELERATOR = new PartialModel(Create.asResource("item/handheld_worldshaper/accelerator")); + + @Override + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, + PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + super.render(stack, model, renderer, transformType, ms, buffer, light, overlay); + + float pt = AnimationTickHolder.getPartialTicks(); + float worldTime = AnimationTickHolder.getRenderTime() / 20; + + renderer.renderSolid(model.getOriginalModel(), light); + + LocalPlayer player = Minecraft.getInstance().player; + boolean leftHanded = player.getMainArm() == HumanoidArm.LEFT; + boolean mainHand = player.getMainHandItem() == stack; + boolean offHand = player.getOffhandItem() == stack; + float animation = getAnimationProgress(pt, leftHanded, mainHand); + + // Core glows + float multiplier; + if (mainHand || offHand) + multiplier = animation; + else + multiplier = Mth.sin(worldTime * 5); + + int lightItensity = (int) (15 * Mth.clamp(multiplier, 0, 1)); + int glowLight = LightTexture.pack(lightItensity, max(lightItensity, 4)); + renderer.renderSolidGlowing(CORE.get(), glowLight); + renderer.renderGlowing(CORE_GLOW.get(), glowLight); + + // Accelerator spins + float angle = worldTime * -25; + if (mainHand || offHand) + angle += 360 * animation; + + angle %= 360; + float offset = -.155f; + ms.translate(0, offset, 0); + ms.mulPose(Vector3f.ZP.rotationDegrees(angle)); + ms.translate(0, -offset, 0); + renderer.render(ACCELERATOR.get(), light); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperRenderHandler.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperRenderHandler.java index accfe71dad..e4481ff1b2 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperRenderHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.ArrayList; import java.util.Collection; @@ -33,7 +33,7 @@ public class WorldshaperRenderHandler { CatnipClient.OUTLINER.showCluster("terrainZapper", renderedPositions.get()) .colored(0xbfbfbf) - .disableNormals() + .disableLineNormals() .lineWidth(1 / 32f) .withFaceTexture(AllSpecialTextures.CHECKERED); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperScreen.java similarity index 96% rename from src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java rename to src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperScreen.java index 197c0cd0ad..b180e3aaf3 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/terrainzapper/WorldshaperScreen.java +++ b/src/main/java/com/simibubi/create/content/equipment/zapper/terrainzapper/WorldshaperScreen.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.curiosities.zapper.terrainzapper; +package com.simibubi.create.content.equipment.zapper.terrainzapper; import java.util.List; import java.util.Vector; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.curiosities.zapper.ConfigureZapperPacket; -import com.simibubi.create.content.curiosities.zapper.ZapperScreen; +import com.simibubi.create.content.equipment.zapper.ConfigureZapperPacket; +import com.simibubi.create.content.equipment.zapper.ZapperScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.widget.IconButton; @@ -31,7 +31,7 @@ public class WorldshaperScreen extends ZapperScreen { protected final Component placementSection = CreateLang.translateDirect("gui.terrainzapper.placement"); protected final Component toolSection = CreateLang.translateDirect("gui.terrainzapper.tool"); protected final List brushOptions = - CreateLang.translatedOptions("gui.terrainzapper.brush", "cuboid", "sphere", "cylinder", "surface", "cluster"); + CreateLang.translatedOptions("gui.terrainzapper.brush", "cuboid", "sphere", "cylinder", "surface", "cluster"); protected Vector toolButtons; protected Vector placementButtons; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FlowSource.java b/src/main/java/com/simibubi/create/content/fluids/FlowSource.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FlowSource.java rename to src/main/java/com/simibubi/create/content/fluids/FlowSource.java index 38fd948874..2e9339f182 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FlowSource.java +++ b/src/main/java/com/simibubi/create/content/fluids/FlowSource.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.lang.ref.WeakReference; import java.util.function.Predicate; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.BlockFace; import net.minecraft.world.level.Level; @@ -70,9 +70,9 @@ public abstract class FlowSource { public void manageSource(Level world) { if (fluidHandler.isPresent() && world.getGameTime() % 20 != 0) return; - BlockEntity tileEntity = world.getBlockEntity(location.getConnectedPos()); - if (tileEntity != null) - fluidHandler = tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + BlockEntity blockEntity = world.getBlockEntity(location.getConnectedPos()); + if (blockEntity != null) + fluidHandler = blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, location.getOppositeFace()); } @@ -96,11 +96,11 @@ public abstract class FlowSource { @Override public void manageSource(Level world) { - if (cached != null && cached.get() != null && !cached.get().tileEntity.isRemoved()) + if (cached != null && cached.get() != null && !cached.get().blockEntity.isRemoved()) return; cached = null; FluidTransportBehaviour fluidTransportBehaviour = - TileEntityBehaviour.get(world, location.getConnectedPos(), FluidTransportBehaviour.TYPE); + BlockEntityBehaviour.get(world, location.getConnectedPos(), FluidTransportBehaviour.TYPE); if (fluidTransportBehaviour != null) cached = new WeakReference<>(fluidTransportBehaviour); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidBottleItemHook.java b/src/main/java/com/simibubi/create/content/fluids/FluidBottleItemHook.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidBottleItemHook.java rename to src/main/java/com/simibubi/create/content/fluids/FluidBottleItemHook.java index e874810915..9a034dbab2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidBottleItemHook.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidBottleItemHook.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import com.simibubi.create.Create; @@ -22,8 +22,8 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @EventBusSubscriber public class FluidBottleItemHook extends Item { - public FluidBottleItemHook(Properties p_i48487_1_) { - super(p_i48487_1_); + private FluidBottleItemHook(Properties p) { + super(p); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java b/src/main/java/com/simibubi/create/content/fluids/FluidFX.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java rename to src/main/java/com/simibubi/create/content/fluids/FluidFX.java index 6dfd73e254..d642abecde 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidFX.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.util.Random; import com.simibubi.create.AllParticleTypes; -import com.simibubi.create.content.contraptions.fluids.particle.FluidParticleData; +import com.simibubi.create.content.fluids.particle.FluidParticleData; import com.simibubi.create.foundation.fluid.FluidHelper; import net.createmod.catnip.utility.VecHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java b/src/main/java/com/simibubi/create/content/fluids/FluidNetwork.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java rename to src/main/java/com/simibubi/create/content/fluids/FluidNetwork.java index fe90f1a49e..b5e70e6708 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidNetwork.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -13,10 +13,10 @@ import java.util.function.Supplier; import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.components.actors.PortableFluidInterfaceTileEntity.InterfaceFluidHandler; -import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow; +import com.simibubi.create.content.contraptions.actors.psi.PortableFluidInterfaceBlockEntity.InterfaceFluidHandler; +import com.simibubi.create.content.fluids.PipeConnection.Flow; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import net.createmod.catnip.utility.BlockFace; import net.createmod.catnip.utility.Iterate; @@ -185,7 +185,7 @@ public class FluidNetwork { int flowSpeed = transferSpeed; Map accumulatedFill = new IdentityHashMap<>(); - + for (boolean simulate : Iterate.trueAndFalse) { FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; @@ -214,9 +214,9 @@ public class FluidNetwork { return; if (simulate) flowSpeed = transfer.getAmount(); - + List>> availableOutputs = new ArrayList<>(targets); - + while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) { int dividedTransfer = transfer.getAmount() / availableOutputs.size(); int remainder = transfer.getAmount() % availableOutputs.size(); @@ -238,20 +238,20 @@ public class FluidNetwork { iterator.remove(); continue; } - + int simulatedTransfer = toTransfer; if (simulate) simulatedTransfer += accumulatedFill.getOrDefault(targetHandler, 0); - + FluidStack divided = transfer.copy(); divided.setAmount(simulatedTransfer); int fill = targetHandler.fill(divided, action); - + if (simulate) { accumulatedFill.put(targetHandler, Integer.valueOf(fill)); fill -= simulatedTransfer - toTransfer; } - + transfer.setAmount(transfer.getAmount() - fill); if (fill < simulatedTransfer) iterator.remove(); @@ -314,10 +314,10 @@ public class FluidNetwork { private FluidTransportBehaviour getFluidTransfer(BlockPos pos) { WeakReference weakReference = cache.get(pos); FluidTransportBehaviour behaviour = weakReference != null ? weakReference.get() : null; - if (behaviour != null && behaviour.tileEntity.isRemoved()) + if (behaviour != null && behaviour.blockEntity.isRemoved()) behaviour = null; if (behaviour == null) { - behaviour = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); + behaviour = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); if (behaviour != null) cache.put(pos, new WeakReference<>(behaviour)); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java b/src/main/java/com/simibubi/create/content/fluids/FluidPropagator.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java rename to src/main/java/com/simibubi/create/content/fluids/FluidPropagator.java index 6a33b275fb..2ede4e1b84 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidPropagator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.util.ArrayList; import java.util.HashSet; @@ -9,15 +9,17 @@ import javax.annotation.Nullable; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; -import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow; -import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.VanillaFluidTargets; +import com.simibubi.create.content.fluids.PipeConnection.Flow; +import com.simibubi.create.content.fluids.pipes.AxisPipeBlock; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.content.fluids.pipes.VanillaFluidTargets; +import com.simibubi.create.content.fluids.pump.PumpBlock; +import com.simibubi.create.content.fluids.pump.PumpBlockEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.CreateAdvancement; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.Pair; @@ -47,7 +49,7 @@ public class FluidPropagator { public static void propagateChangedPipe(LevelAccessor world, BlockPos pipePos, BlockState pipeState) { List> frontier = new ArrayList<>(); Set visited = new HashSet<>(); - Set> discoveredPumps = new HashSet<>(); + Set> discoveredPumps = new HashSet<>(); frontier.add(Pair.of(0, pipePos)); @@ -69,13 +71,13 @@ public class FluidPropagator { if (world instanceof Level l && !l.isLoaded(target)) continue; - BlockEntity tileEntity = world.getBlockEntity(target); + BlockEntity blockEntity = world.getBlockEntity(target); BlockState targetState = world.getBlockState(target); - if (tileEntity instanceof PumpTileEntity) { + if (blockEntity instanceof PumpBlockEntity) { if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.getValue(PumpBlock.FACING) .getAxis() != direction.getAxis()) continue; - discoveredPumps.add(Pair.of((PumpTileEntity) tileEntity, direction.getOpposite())); + discoveredPumps.add(Pair.of((PumpBlockEntity) blockEntity, direction.getOpposite())); continue; } if (visited.contains(target)) @@ -160,7 +162,7 @@ public class FluidPropagator { } public static FluidTransportBehaviour getPipe(BlockGetter reader, BlockPos pos) { - return TileEntityBehaviour.get(reader, pos, FluidTransportBehaviour.TYPE); + return BlockEntityBehaviour.get(reader, pos, FluidTransportBehaviour.TYPE); } public static boolean isOpenEnd(BlockGetter reader, BlockPos pos, Direction side) { @@ -195,15 +197,15 @@ public class FluidPropagator { } public static int getPumpRange() { - return AllConfigs.SERVER.fluids.mechanicalPumpRange.get(); + return AllConfigs.server().fluids.mechanicalPumpRange.get(); } public static boolean hasFluidCapability(BlockGetter world, BlockPos pos, Direction side) { - BlockEntity tileEntity = world.getBlockEntity(pos); - if (tileEntity == null) + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity == null) return false; LazyOptional capability = - tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); + blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); return capability.isPresent(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java b/src/main/java/com/simibubi/create/content/fluids/FluidReactions.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java rename to src/main/java/com/simibubi/create/content/fluids/FluidReactions.java index 60f93a5923..254e3476d7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidReactions.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import com.simibubi.create.AllFluids; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTransportBehaviour.java b/src/main/java/com/simibubi/create/content/fluids/FluidTransportBehaviour.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTransportBehaviour.java rename to src/main/java/com/simibubi/create/content/fluids/FluidTransportBehaviour.java index edec992a5c..82ba047df8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTransportBehaviour.java +++ b/src/main/java/com/simibubi/create/content/fluids/FluidTransportBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.util.Collection; import java.util.HashMap; @@ -9,10 +9,11 @@ import java.util.function.Predicate; import javax.annotation.Nullable; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock; +import com.simibubi.create.content.fluids.pump.PumpBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.WorldAttached; @@ -25,7 +26,7 @@ import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.fluids.FluidStack; -public abstract class FluidTransportBehaviour extends TileEntityBehaviour { +public abstract class FluidTransportBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); @@ -38,8 +39,8 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { public Map interfaces; public UpdatePhase phase; - public FluidTransportBehaviour(SmartTileEntity te) { - super(te); + public FluidTransportBehaviour(SmartBlockEntity be) { + super(be); phase = UpdatePhase.WAIT_FOR_PUMPS; } @@ -60,7 +61,7 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { super.tick(); Level world = getWorld(); BlockPos pos = getPos(); - boolean onServer = !world.isClientSide || tileEntity.isVirtual(); + boolean onServer = !world.isClientSide || blockEntity.isVirtual(); if (interfaces == null) return; @@ -88,7 +89,7 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { connection.manageSource(world, pos); } if (sendUpdate) - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); } if (phase == UpdatePhase.FLIP_FLOWS) { @@ -127,12 +128,12 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { for (PipeConnection connection : connections) { FluidStack internalFluid = singleSource != connection ? availableFlow : FluidStack.EMPTY; Predicate extractionPredicate = - extracted -> canPullFluidFrom(extracted, tileEntity.getBlockState(), connection.side); + extracted -> canPullFluidFrom(extracted, blockEntity.getBlockState(), connection.side); sendUpdate |= connection.manageFlows(world, pos, internalFluid, extractionPredicate); } if (sendUpdate) - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); } for (PipeConnection connection : connections) @@ -155,7 +156,7 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { } interfaces.values() - .forEach(connection -> connection.deserializeNBT(nbt, tileEntity.getBlockPos(), clientPacket)); + .forEach(connection -> connection.deserializeNBT(nbt, blockEntity.getBlockPos(), clientPacket)); } @Override @@ -206,13 +207,13 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { return; interfaces.get(side) .addPressure(inbound, pressure); - tileEntity.sendData(); + blockEntity.sendData(); } public void wipePressure() { if (interfaces != null) for (Direction d : Iterate.directions) { - if (!canHaveFlowToward(tileEntity.getBlockState(), d)) + if (!canHaveFlowToward(blockEntity.getBlockState(), d)) interfaces.remove(d); else interfaces.computeIfAbsent(d, PipeConnection::new); @@ -221,7 +222,7 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { createConnectionData(); interfaces.values() .forEach(PipeConnection::wipePressure); - tileEntity.sendData(); + blockEntity.sendData(); } private void createConnectionData() { @@ -229,7 +230,7 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { return; interfaces = new IdentityHashMap<>(); for (Direction d : Iterate.directions) - if (canHaveFlowToward(tileEntity.getBlockState(), d)) + if (canHaveFlowToward(blockEntity.getBlockState(), d)) interfaces.put(d, new PipeConnection(d)); } @@ -294,14 +295,14 @@ public abstract class FluidTransportBehaviour extends TileEntityBehaviour { new WorldAttached<>($ -> new HashMap<>()); public static void cacheFlows(LevelAccessor world, BlockPos pos) { - FluidTransportBehaviour pipe = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); + FluidTransportBehaviour pipe = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); if (pipe != null) interfaceTransfer.get(world) .put(pos, pipe.interfaces); } public static void loadFlows(LevelAccessor world, BlockPos pos) { - FluidTransportBehaviour newPipe = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); + FluidTransportBehaviour newPipe = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); if (newPipe != null) newPipe.interfaces = interfaceTransfer.get(world) .remove(pos); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java b/src/main/java/com/simibubi/create/content/fluids/OpenEndedPipe.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java rename to src/main/java/com/simibubi/create/content/fluids/OpenEndedPipe.java index cfa5d8b3c3..835a7c29b6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java +++ b/src/main/java/com/simibubi/create/content/fluids/OpenEndedPipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; @@ -8,12 +8,12 @@ import java.util.List; import javax.annotation.Nullable; import com.simibubi.create.AllFluids; -import com.simibubi.create.content.contraptions.fluids.pipes.VanillaFluidTargets; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.fluids.pipes.VanillaFluidTargets; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.BlockFace; import net.minecraft.core.BlockPos; @@ -25,6 +25,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; @@ -54,6 +55,7 @@ public class OpenEndedPipe extends FlowSource { registerEffectHandler(new MilkEffectHandler()); registerEffectHandler(new WaterEffectHandler()); registerEffectHandler(new LavaEffectHandler()); + registerEffectHandler(new TeaEffectHandler()); } private Level world; @@ -120,9 +122,9 @@ public class OpenEndedPipe extends FlowSource { return compound; } - public static OpenEndedPipe fromNBT(CompoundTag compound, BlockPos tilePos) { + public static OpenEndedPipe fromNBT(CompoundTag compound, BlockPos blockEntityPos) { BlockFace fromNBT = BlockFace.fromNBT(compound.getCompound("Location")); - OpenEndedPipe oep = new OpenEndedPipe(new BlockFace(tilePos, fromNBT.getFace())); + OpenEndedPipe oep = new OpenEndedPipe(new BlockFace(blockEntityPos, fromNBT.getFace())); oep.fluidHandler.readFromNBT(compound); oep.wasPulling = compound.getBoolean("Pulling"); return oep; @@ -217,7 +219,7 @@ public class OpenEndedPipe extends FlowSource { return true; } - if (!AllConfigs.SERVER.fluids.placeFluidSourceBlocks.get()) + if (!AllConfigs.server().fluids.pipesPlaceFluidSourceBlocks.get()) return true; world.setBlock(outputPos, fluid.getFluid() @@ -443,4 +445,23 @@ public class OpenEndedPipe extends FlowSource { } } + public static class TeaEffectHandler implements IEffectHandler { + @Override + public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) { + return fluid.getFluid().isSame(AllFluids.TEA.get()); + } + + @Override + public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) { + Level world = pipe.getWorld(); + if (world.getGameTime() % 5 != 0) + return; + List entities = world + .getEntitiesOfClass(LivingEntity.class, pipe.getAOE(), LivingEntity::isAffectedByPotions); + for (LivingEntity entity : entities) { + entity.addEffect(new MobEffectInstance(MobEffects.DIG_SPEED, 21, 0, false, false, false)); + } + } + } + } diff --git a/src/main/java/com/simibubi/create/content/fluids/PipeAttachmentModel.java b/src/main/java/com/simibubi/create/content/fluids/PipeAttachmentModel.java new file mode 100644 index 0000000000..1ced47ba52 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/PipeAttachmentModel.java @@ -0,0 +1,122 @@ +package com.simibubi.create.content.fluids; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.fluids.FluidTransportBehaviour.AttachmentTypes; +import com.simibubi.create.content.fluids.FluidTransportBehaviour.AttachmentTypes.ComponentPartials; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.model.BakedModelWrapperWithData; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap.Builder; +import net.minecraftforge.client.model.data.ModelProperty; + +public class PipeAttachmentModel extends BakedModelWrapperWithData { + + private static final ModelProperty PIPE_PROPERTY = new ModelProperty<>(); + + public PipeAttachmentModel(BakedModel template) { + super(template); + } + + @Override + protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, + IModelData blockEntityData) { + PipeModelData data = new PipeModelData(); + FluidTransportBehaviour transport = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); + BracketedBlockEntityBehaviour bracket = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); + + if (transport != null) + for (Direction d : Iterate.directions) + data.putAttachment(d, transport.getRenderedRimAttachment(world, pos, state, d)); + if (bracket != null) + data.putBracket(bracket.getBracket()); + + data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state)); + builder.withInitial(PIPE_PROPERTY, data); + } + + @Override + public List getQuads(BlockState state, Direction side, Random rand, IModelData data) { + List quads = super.getQuads(state, side, rand, data); + if (data.hasProperty(PIPE_PROPERTY)) { + PipeModelData pipeData = data.getData(PIPE_PROPERTY); + quads = new ArrayList<>(quads); + addQuads(quads, state, side, rand, data, pipeData); + } + return quads; + } + + private void addQuads(List quads, BlockState state, Direction side, Random rand, IModelData data, + PipeModelData pipeData) { + BakedModel bracket = pipeData.getBracket(); + if (bracket != null) + quads.addAll(bracket.getQuads(state, side, rand, data)); + for (Direction d : Iterate.directions) { + AttachmentTypes type = pipeData.getAttachment(d); + for (ComponentPartials partial : type.partials) { + quads.addAll(AllPartialModels.PIPE_ATTACHMENTS.get(partial) + .get(d) + .get() + .getQuads(state, side, rand, data)); + } + } + if (pipeData.isEncased()) + quads.addAll(AllPartialModels.FLUID_PIPE_CASING.get() + .getQuads(state, side, rand, data)); + } + + private static class PipeModelData { + private AttachmentTypes[] attachments; + private boolean encased; + private BakedModel bracket; + + public PipeModelData() { + attachments = new AttachmentTypes[6]; + Arrays.fill(attachments, AttachmentTypes.NONE); + } + + public void putBracket(BlockState state) { + if (state != null) { + this.bracket = Minecraft.getInstance() + .getBlockRenderer() + .getBlockModel(state); + } + } + + public BakedModel getBracket() { + return bracket; + } + + public void putAttachment(Direction face, AttachmentTypes rim) { + attachments[face.get3DDataValue()] = rim; + } + + public AttachmentTypes getAttachment(Direction face) { + return attachments[face.get3DDataValue()]; + } + + public void setEncased(boolean encased) { + this.encased = encased; + } + + public boolean isEncased() { + return encased; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java b/src/main/java/com/simibubi/create/content/fluids/PipeConnection.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java rename to src/main/java/com/simibubi/create/content/fluids/PipeConnection.java index 241a2e74e5..0f2a194ca5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeConnection.java +++ b/src/main/java/com/simibubi/create/content/fluids/PipeConnection.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import java.util.Optional; import java.util.Random; import java.util.function.Predicate; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.BlockFace; import net.createmod.catnip.utility.Couple; @@ -179,7 +179,7 @@ public class PipeConnection { } FluidTransportBehaviour behaviour = - TileEntityBehaviour.get(world, relative, FluidTransportBehaviour.TYPE); + BlockEntityBehaviour.get(world, relative, FluidTransportBehaviour.TYPE); source = Optional.of(behaviour == null ? new FlowSource.Blocked(location) : new FlowSource.OtherPipe(location)); return true; } @@ -201,7 +201,7 @@ public class PipeConnection { particleSplashNextTick = false; } - float flowSpeed = 1 / 32f + Mth.clamp(pressure.get(flow.inbound) / 512f, 0, 1) * 31 / 32f; + float flowSpeed = 1 / 32f + Mth.clamp(pressure.get(flow.inbound) / 128f, 0, 1) * 31 / 32f; flow.progress.setValue(Math.min(flow.progress.getValue() + flowSpeed, 1)); if (flow.progress.getValue() >= 1) flow.complete = true; @@ -237,7 +237,7 @@ public class PipeConnection { return source.orElse(null) instanceof OpenEndedPipe; } - public void deserializeNBT(CompoundTag tag, BlockPos tilePos, boolean clientPacket) { + public void deserializeNBT(CompoundTag tag, BlockPos blockEntityPos, boolean clientPacket) { CompoundTag connectionData = tag.getCompound(side.getName()); if (connectionData.contains("Pressure")) { @@ -248,7 +248,7 @@ public class PipeConnection { source = Optional.empty(); if (connectionData.contains("OpenEnd")) - source = Optional.of(OpenEndedPipe.fromNBT(connectionData.getCompound("OpenEnd"), tilePos)); + source = Optional.of(OpenEndedPipe.fromNBT(connectionData.getCompound("OpenEnd"), blockEntityPos)); if (connectionData.contains("Flow")) { CompoundTag flowData = connectionData.getCompound("Flow"); @@ -308,6 +308,10 @@ public class PipeConnection { this.pressure = this.pressure.mapWithContext((f, in) -> in == inbound ? f + pressure : f); } + public Couple getPressure() { + return pressure; + } + public boolean hasPressure() { return getInboundPressure() != 0 || getOutwardPressure() != 0; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/VirtualFluid.java b/src/main/java/com/simibubi/create/content/fluids/VirtualFluid.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/VirtualFluid.java rename to src/main/java/com/simibubi/create/content/fluids/VirtualFluid.java index 890fd90719..d7c086f111 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/VirtualFluid.java +++ b/src/main/java/com/simibubi/create/content/fluids/VirtualFluid.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids; +package com.simibubi.create.content.fluids; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; diff --git a/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlock.java b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlock.java new file mode 100644 index 0000000000..3ca89cfc21 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlock.java @@ -0,0 +1,156 @@ +package com.simibubi.create.content.fluids.drain; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.ComparatorUtil; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.fluid.FluidHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.Containers; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; + +public class ItemDrainBlock extends Block implements IWrenchable, IBE { + + public ItemDrainBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + ItemStack heldItem = player.getItemInHand(handIn); + + if (heldItem.getItem() instanceof BlockItem + && !heldItem.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY) + .isPresent()) + return InteractionResult.PASS; + + return onBlockEntityUse(worldIn, pos, be -> { + if (!heldItem.isEmpty()) { + be.internalTank.allowInsertion(); + InteractionResult tryExchange = tryExchange(worldIn, player, handIn, heldItem, be); + be.internalTank.forbidInsertion(); + if (tryExchange.consumesAction()) + return tryExchange; + } + + ItemStack heldItemStack = be.getHeldItemStack(); + if (!worldIn.isClientSide && !heldItemStack.isEmpty()) { + player.getInventory() + .placeItemBackInInventory(heldItemStack); + be.heldItem = null; + be.notifyUpdate(); + } + return InteractionResult.SUCCESS; + }); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + if (!(entityIn instanceof ItemEntity)) + return; + if (!entityIn.isAlive()) + return; + if (entityIn.level.isClientSide) + return; + + ItemEntity itemEntity = (ItemEntity) entityIn; + DirectBeltInputBehaviour inputBehaviour = + BlockEntityBehaviour.get(worldIn, entityIn.blockPosition(), DirectBeltInputBehaviour.TYPE); + if (inputBehaviour == null) + return; + Vec3 deltaMovement = entityIn.getDeltaMovement() + .multiply(1, 0, 1) + .normalize(); + Direction nearest = Direction.getNearest(deltaMovement.x, deltaMovement.y, deltaMovement.z); + ItemStack remainder = inputBehaviour.handleInsertion(itemEntity.getItem(), nearest, false); + itemEntity.setItem(remainder); + if (remainder.isEmpty()) + itemEntity.discard(); + } + + protected InteractionResult tryExchange(Level worldIn, Player player, InteractionHand handIn, ItemStack heldItem, + ItemDrainBlockEntity be) { + if (FluidHelper.tryEmptyItemIntoBE(worldIn, player, handIn, heldItem, be)) + return InteractionResult.SUCCESS; + if (GenericItemEmptying.canItemBeEmptied(worldIn, heldItem)) + return InteractionResult.SUCCESS; + return InteractionResult.PASS; + } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.CASING_13PX.get(Direction.UP); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) + return; + withBlockEntityDo(worldIn, pos, be -> { + ItemStack heldItemStack = be.getHeldItemStack(); + if (!heldItemStack.isEmpty()) + Containers.dropItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), heldItemStack); + }); + worldIn.removeBlockEntity(pos); + } + + @Override + public Class getBlockEntityClass() { + return ItemDrainBlockEntity.class; + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); + AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ITEM_DRAIN.get(); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { + return ComparatorUtil.levelOfSmartFluidTank(worldIn, pos); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlockEntity.java new file mode 100644 index 0000000000..ee1717a89c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainBlockEntity.java @@ -0,0 +1,302 @@ +package com.simibubi.create.content.fluids.drain; + +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.items.ItemHandlerHelper; + +public class ItemDrainBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + public static final int FILLING_TIME = 20; + + SmartFluidTankBehaviour internalTank; + TransportedItemStack heldItem; + protected int processingTicks; + Map> itemHandlers; + + public ItemDrainBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + itemHandlers = new IdentityHashMap<>(); + for (Direction d : Iterate.horizontalDirections) { + ItemDrainItemHandler itemDrainItemHandler = new ItemDrainItemHandler(this, d); + itemHandlers.put(d, LazyOptional.of(() -> itemDrainItemHandler)); + } + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this).allowingBeltFunnels() + .setInsertionHandler(this::tryInsertingFromSide)); + behaviours.add(internalTank = SmartFluidTankBehaviour.single(this, 1500) + .allowExtraction() + .forbidInsertion()); + registerAwardables(behaviours, AllAdvancements.DRAIN, AllAdvancements.CHAINED_DRAIN); + } + + private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { + ItemStack inserted = transportedStack.stack; + ItemStack returned = ItemStack.EMPTY; + + if (!getHeldItemStack().isEmpty()) + return inserted; + + if (inserted.getCount() > 1 && GenericItemEmptying.canItemBeEmptied(level, inserted)) { + returned = ItemHandlerHelper.copyStackWithSize(inserted, inserted.getCount() - 1); + inserted = ItemHandlerHelper.copyStackWithSize(inserted, 1); + } + + if (simulate) + return returned; + + transportedStack = transportedStack.copy(); + transportedStack.stack = inserted.copy(); + transportedStack.beltPosition = side.getAxis() + .isVertical() ? .5f : 0; + transportedStack.prevSideOffset = transportedStack.sideOffset; + transportedStack.prevBeltPosition = transportedStack.beltPosition; + setHeldItem(transportedStack, side); + setChanged(); + sendData(); + + return returned; + } + + public ItemStack getHeldItemStack() { + return heldItem == null ? ItemStack.EMPTY : heldItem.stack; + } + + @Override + public void tick() { + super.tick(); + + if (heldItem == null) { + processingTicks = 0; + return; + } + + boolean onClient = level.isClientSide && !isVirtual(); + + if (processingTicks > 0) { + heldItem.prevBeltPosition = .5f; + boolean wasAtBeginning = processingTicks == FILLING_TIME; + if (!onClient || processingTicks < FILLING_TIME) + processingTicks--; + if (!continueProcessing()) { + processingTicks = 0; + notifyUpdate(); + return; + } + if (wasAtBeginning != (processingTicks == FILLING_TIME)) + sendData(); + return; + } + + heldItem.prevBeltPosition = heldItem.beltPosition; + heldItem.prevSideOffset = heldItem.sideOffset; + + heldItem.beltPosition += itemMovementPerTick(); + if (heldItem.beltPosition > 1) { + heldItem.beltPosition = 1; + + if (onClient) + return; + + Direction side = heldItem.insertedFrom; + + ItemStack tryExportingToBeltFunnel = getBehaviour(DirectBeltInputBehaviour.TYPE) + .tryExportingToBeltFunnel(heldItem.stack, side.getOpposite(), false); + if (tryExportingToBeltFunnel != null) { + if (tryExportingToBeltFunnel.getCount() != heldItem.stack.getCount()) { + if (tryExportingToBeltFunnel.isEmpty()) + heldItem = null; + else + heldItem.stack = tryExportingToBeltFunnel; + notifyUpdate(); + return; + } + if (!tryExportingToBeltFunnel.isEmpty()) + return; + } + + BlockPos nextPosition = worldPosition.relative(side); + DirectBeltInputBehaviour directBeltInputBehaviour = + BlockEntityBehaviour.get(level, nextPosition, DirectBeltInputBehaviour.TYPE); + if (directBeltInputBehaviour == null) { + if (!BlockHelper.hasBlockSolidSide(level.getBlockState(nextPosition), level, nextPosition, + side.getOpposite())) { + ItemStack ejected = heldItem.stack; + Vec3 outPos = VecHelper.getCenterOf(worldPosition) + .add(Vec3.atLowerCornerOf(side.getNormal()) + .scale(.75)); + float movementSpeed = itemMovementPerTick(); + Vec3 outMotion = Vec3.atLowerCornerOf(side.getNormal()) + .scale(movementSpeed) + .add(0, 1 / 8f, 0); + outPos.add(outMotion.normalize()); + ItemEntity entity = new ItemEntity(level, outPos.x, outPos.y + 6 / 16f, outPos.z, ejected); + entity.setDeltaMovement(outMotion); + entity.setDefaultPickUpDelay(); + entity.hurtMarked = true; + level.addFreshEntity(entity); + + heldItem = null; + notifyUpdate(); + } + return; + } + + if (!directBeltInputBehaviour.canInsertFromSide(side)) + return; + + ItemStack returned = directBeltInputBehaviour.handleInsertion(heldItem.copy(), side, false); + + if (returned.isEmpty()) { + if (level.getBlockEntity(nextPosition) instanceof ItemDrainBlockEntity) + award(AllAdvancements.CHAINED_DRAIN); + heldItem = null; + notifyUpdate(); + return; + } + + if (returned.getCount() != heldItem.stack.getCount()) { + heldItem.stack = returned; + notifyUpdate(); + return; + } + + return; + } + + if (heldItem.prevBeltPosition < .5f && heldItem.beltPosition >= .5f) { + if (!GenericItemEmptying.canItemBeEmptied(level, heldItem.stack)) + return; + heldItem.beltPosition = .5f; + if (onClient) + return; + processingTicks = FILLING_TIME; + sendData(); + } + + } + + protected boolean continueProcessing() { + if (level.isClientSide && !isVirtual()) + return true; + if (processingTicks < 5) + return true; + if (!GenericItemEmptying.canItemBeEmptied(level, heldItem.stack)) + return false; + + Pair emptyItem = GenericItemEmptying.emptyItem(level, heldItem.stack, true); + FluidStack fluidFromItem = emptyItem.getFirst(); + + if (processingTicks > 5) { + internalTank.allowInsertion(); + if (internalTank.getPrimaryHandler() + .fill(fluidFromItem, FluidAction.SIMULATE) != fluidFromItem.getAmount()) { + internalTank.forbidInsertion(); + processingTicks = FILLING_TIME; + return true; + } + internalTank.forbidInsertion(); + return true; + } + + emptyItem = GenericItemEmptying.emptyItem(level, heldItem.stack.copy(), false); + award(AllAdvancements.DRAIN); + + // Process finished + ItemStack out = emptyItem.getSecond(); + if (!out.isEmpty()) + heldItem.stack = out; + else + heldItem = null; + internalTank.allowInsertion(); + internalTank.getPrimaryHandler() + .fill(fluidFromItem, FluidAction.EXECUTE); + internalTank.forbidInsertion(); + notifyUpdate(); + return true; + } + + private float itemMovementPerTick() { + return 1 / 8f; + } + + @Override + public void invalidate() { + super.invalidate(); + for (LazyOptional lazyOptional : itemHandlers.values()) + lazyOptional.invalidate(); + } + + public void setHeldItem(TransportedItemStack heldItem, Direction insertedFrom) { + this.heldItem = heldItem; + this.heldItem.insertedFrom = insertedFrom; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("ProcessingTicks", processingTicks); + if (heldItem != null) + compound.put("HeldItem", heldItem.serializeNBT()); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + heldItem = null; + processingTicks = compound.getInt("ProcessingTicks"); + if (compound.contains("HeldItem")) + heldItem = TransportedItemStack.read(compound.getCompound("HeldItem")); + super.read(compound, clientPacket); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (side != null && side.getAxis() + .isHorizontal() && isItemHandlerCap(cap)) + return itemHandlers.get(side) + .cast(); + + if (side != Direction.UP && isFluidHandlerCap(cap)) + return internalTank.getCapability() + .cast(); + + return super.getCapability(cap, side); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainItemHandler.java b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainItemHandler.java new file mode 100644 index 0000000000..d69e16c557 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainItemHandler.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.fluids.drain; + +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; + +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +public class ItemDrainItemHandler implements IItemHandler { + + private ItemDrainBlockEntity blockEntity; + private Direction side; + + public ItemDrainItemHandler(ItemDrainBlockEntity be, Direction side) { + this.blockEntity = be; + this.side = side; + } + + @Override + public int getSlots() { + return 1; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return blockEntity.getHeldItemStack(); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (!blockEntity.getHeldItemStack() + .isEmpty()) + return stack; + + ItemStack returned = ItemStack.EMPTY; + if (stack.getCount() > 1 && GenericItemEmptying.canItemBeEmptied(blockEntity.getLevel(), stack)) { + returned = ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - 1); + stack = ItemHandlerHelper.copyStackWithSize(stack, 1); + } + + if (!simulate) { + TransportedItemStack heldItem = new TransportedItemStack(stack); + heldItem.prevBeltPosition = 0; + blockEntity.setHeldItem(heldItem, side.getOpposite()); + blockEntity.notifyUpdate(); + } + + return returned; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + TransportedItemStack held = blockEntity.heldItem; + if (held == null) + return ItemStack.EMPTY; + + ItemStack stack = held.stack.copy(); + ItemStack extracted = stack.split(amount); + if (!simulate) { + blockEntity.heldItem.stack = stack; + if (stack.isEmpty()) + blockEntity.heldItem = null; + blockEntity.notifyUpdate(); + } + return extracted; + } + + @Override + public int getSlotLimit(int slot) { + return 64; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainRenderer.java b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainRenderer.java similarity index 75% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainRenderer.java rename to src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainRenderer.java index dfef7be46c..885f5aa91b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/ItemDrainRenderer.java +++ b/src/main/java/com/simibubi/create/content/fluids/drain/ItemDrainRenderer.java @@ -1,17 +1,17 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.drain; import java.util.Random; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; import com.simibubi.create.foundation.fluid.FluidRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import net.createmod.catnip.utility.VecHelper; import net.minecraft.client.Minecraft; @@ -28,28 +28,28 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraftforge.fluids.FluidStack; -public class ItemDrainRenderer extends SmartTileEntityRenderer { +public class ItemDrainRenderer extends SmartBlockEntityRenderer { public ItemDrainRenderer(BlockEntityRendererProvider.Context context) { super(context); } @Override - protected void renderSafe(ItemDrainTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(ItemDrainBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - renderFluid(te, partialTicks, ms, buffer, light); - renderItem(te, partialTicks, ms, buffer, light, overlay); + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + renderFluid(be, partialTicks, ms, buffer, light); + renderItem(be, partialTicks, ms, buffer, light, overlay); } - protected void renderItem(ItemDrainTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderItem(ItemDrainBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - TransportedItemStack transported = te.heldItem; + TransportedItemStack transported = be.heldItem; if (transported == null) return; TransformStack msr = TransformStack.cast(ms); - Vec3 itemPosition = VecHelper.getCenterOf(te.getBlockPos()); + Vec3 itemPosition = VecHelper.getCenterOf(be.getBlockPos()); Direction insertedFrom = transported.insertedFrom; if (!insertedFrom.getAxis() @@ -131,9 +131,9 @@ public class ItemDrainRenderer extends SmartTileEntityRenderer { + + public HosePulleyBlock(Properties properties) { + super(properties); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(HORIZONTAL_FACING) + .getClockWise() + .getAxis(); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Direction preferredHorizontalFacing = getPreferredHorizontalFacing(context); + return this.defaultBlockState() + .setValue(HORIZONTAL_FACING, + preferredHorizontalFacing != null ? preferredHorizontalFacing.getCounterClockWise() + : context.getHorizontalDirection() + .getOpposite()); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return state.getValue(HORIZONTAL_FACING) + .getClockWise() == face; + } + + public static boolean hasPipeTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return state.getValue(HORIZONTAL_FACING) + .getCounterClockWise() == face; + } + + @Override + public Direction getPreferredHorizontalFacing(BlockPlaceContext context) { + Direction fromParent = super.getPreferredHorizontalFacing(context); + if (fromParent != null) + return fromParent; + + Direction prefferedSide = null; + for (Direction facing : Iterate.horizontalDirections) { + BlockPos pos = context.getClickedPos() + .relative(facing); + BlockState blockState = context.getLevel() + .getBlockState(pos); + if (FluidPipeBlock.canConnectTo(context.getLevel(), pos, blockState, facing)) + if (prefferedSide != null && prefferedSide.getAxis() != facing.getAxis()) { + prefferedSide = null; + break; + } else + prefferedSide = facing; + } + return prefferedSide == null ? null : prefferedSide.getOpposite(); + } + + @Override + public Class getBlockEntityClass() { + return HosePulleyBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.HOSE_PULLEY.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyBlockEntity.java new file mode 100644 index 0000000000..7d8a095698 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyBlockEntity.java @@ -0,0 +1,194 @@ +package com.simibubi.create.content.fluids.hosePulley; + +import java.util.List; + +import com.simibubi.create.content.fluids.transfer.FluidDrainingBehaviour; +import com.simibubi.create.content.fluids.transfer.FluidFillingBehaviour; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.fluid.SmartFluidTank; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public class HosePulleyBlockEntity extends KineticBlockEntity { + + LerpedFloat offset; + boolean isMoving; + + private SmartFluidTank internalTank; + private LazyOptional capability; + private FluidDrainingBehaviour drainer; + private FluidFillingBehaviour filler; + private HosePulleyFluidHandler handler; + private boolean infinite; + + public HosePulleyBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + offset = LerpedFloat.linear() + .startWithValue(0); + isMoving = true; + internalTank = new SmartFluidTank(1500, this::onTankContentsChanged); + handler = new HosePulleyFluidHandler(internalTank, filler, drainer, + () -> worldPosition.below((int) Math.ceil(offset.getValue())), () -> !this.isMoving); + capability = LazyOptional.of(() -> handler); + } + + @Override + public void sendData() { + infinite = filler.isInfinite() || drainer.isInfinite(); + super.sendData(); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + boolean addToGoggleTooltip = super.addToGoggleTooltip(tooltip, isPlayerSneaking); + if (infinite) + TooltipHelper.addHint(tooltip, "hint.hose_pulley"); + return addToGoggleTooltip; + } + + @Override + public void addBehaviours(List behaviours) { + drainer = new FluidDrainingBehaviour(this); + filler = new FluidFillingBehaviour(this); + behaviours.add(drainer); + behaviours.add(filler); + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.HOSE_PULLEY, AllAdvancements.HOSE_PULLEY_LAVA); + } + + protected void onTankContentsChanged(FluidStack contents) {} + + @Override + public void onSpeedChanged(float previousSpeed) { + isMoving = true; + if (getSpeed() == 0) { + offset.forceNextSync(); + offset.setValue(Math.round(offset.getValue())); + isMoving = false; + } + + if (isMoving) { + float newOffset = offset.getValue() + getMovementSpeed(); + if (newOffset < 0) + isMoving = false; + if (!level.getBlockState(worldPosition.below((int) Math.ceil(newOffset))) + .getMaterial() + .isReplaceable()) { + isMoving = false; + } + if (isMoving) { + drainer.reset(); + filler.reset(); + } + } + + super.onSpeedChanged(previousSpeed); + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().expandTowards(0, -offset.getValue(), 0); + } + + @Override + public void tick() { + super.tick(); + float newOffset = offset.getValue() + getMovementSpeed(); + if (newOffset < 0) { + newOffset = 0; + isMoving = false; + } + if (!level.getBlockState(worldPosition.below((int) Math.ceil(newOffset))) + .getMaterial() + .isReplaceable()) { + newOffset = (int) newOffset; + isMoving = false; + } + if (getSpeed() == 0) + isMoving = false; + + offset.setValue(newOffset); + invalidateRenderBoundingBox(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (level.isClientSide) + return; + if (isMoving) + return; + + int ceil = (int) Math.ceil(offset.getValue() + getMovementSpeed()); + if (getMovementSpeed() > 0 && level.getBlockState(worldPosition.below(ceil)) + .getMaterial() + .isReplaceable()) { + isMoving = true; + drainer.reset(); + filler.reset(); + return; + } + + sendData(); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + if (clientPacket) + offset.forceNextSync(); + compound.put("Offset", offset.writeNBT()); + compound.put("Tank", internalTank.writeToNBT(new CompoundTag())); + super.write(compound, clientPacket); + if (clientPacket) + compound.putBoolean("Infinite", infinite); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + offset.readNBT(compound.getCompound("Offset"), clientPacket); + internalTank.readFromNBT(compound.getCompound("Tank")); + super.read(compound, clientPacket); + if (clientPacket) + infinite = compound.getBoolean("Infinite"); + } + + @Override + public void invalidate() { + super.invalidate(); + capability.invalidate(); + } + + public float getMovementSpeed() { + float movementSpeed = convertToLinear(getSpeed()); + if (level.isClientSide) + movementSpeed *= ServerSpeedProvider.get(); + return movementSpeed; + } + + public float getInterpolatedOffset(float pt) { + return offset.getValue(pt); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isFluidHandlerCap(cap) + && (side == null || HosePulleyBlock.hasPipeTowards(level, worldPosition, getBlockState(), side))) + return this.capability.cast(); + return super.getCapability(cap, side); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyFluidHandler.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java rename to src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyFluidHandler.java index 063a52eae1..5cb60d651e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/HosePulleyFluidHandler.java +++ b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyFluidHandler.java @@ -1,9 +1,11 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.hosePulley; import java.util.function.Supplier; import javax.annotation.Nullable; +import com.simibubi.create.content.fluids.transfer.FluidDrainingBehaviour; +import com.simibubi.create.content.fluids.transfer.FluidFillingBehaviour; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.SmartFluidTank; @@ -125,4 +127,8 @@ public class HosePulleyFluidHandler implements IFluidHandler { return internalTank.isFluidValid(tank, stack); } + public SmartFluidTank getInternalTank() { + return internalTank; + } + } diff --git a/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyRenderer.java b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyRenderer.java new file mode 100644 index 0000000000..2f9688c3e4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/hosePulley/HosePulleyRenderer.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.fluids.hosePulley; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.pulley.AbstractPulleyRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction.Axis; + +public class HosePulleyRenderer extends AbstractPulleyRenderer { + + public HosePulleyRenderer(BlockEntityRendererProvider.Context context) { + super(context, AllPartialModels.HOSE_HALF, AllPartialModels.HOSE_HALF_MAGNET); + } + + @Override + protected Axis getShaftAxis(HosePulleyBlockEntity be) { + return be.getBlockState() + .getValue(HosePulleyBlock.HORIZONTAL_FACING) + .getClockWise() + .getAxis(); + } + + @Override + protected PartialModel getCoil() { + return AllPartialModels.HOSE_COIL; + } + + @Override + protected SuperByteBuffer renderRope(HosePulleyBlockEntity be) { + return CachedPartialBuffers.partial(AllPartialModels.HOSE, be.getBlockState()); + } + + @Override + protected SuperByteBuffer renderMagnet(HosePulleyBlockEntity be) { + return CachedPartialBuffers.partial(AllPartialModels.HOSE_MAGNET, be.getBlockState()); + } + + @Override + protected float getOffset(HosePulleyBlockEntity be, float partialTicks) { + return be.getInterpolatedOffset(partialTicks); + } + + @Override + protected boolean isRunning(HosePulleyBlockEntity be) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java b/src/main/java/com/simibubi/create/content/fluids/particle/BasinFluidParticle.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java rename to src/main/java/com/simibubi/create/content/fluids/particle/BasinFluidParticle.java index d79e64abf1..6ab94e1eec 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java +++ b/src/main/java/com/simibubi/create/content/fluids/particle/BasinFluidParticle.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.fluids.particle; +package com.simibubi.create.content.fluids.particle; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Quaternion; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.processing.BasinTileEntity; +import com.simibubi.create.content.processing.basin.BasinBlockEntity; import net.createmod.catnip.utility.VecHelper; import net.minecraft.client.Camera; @@ -61,9 +61,9 @@ public class BasinFluidParticle extends FluidStackParticle { return; } - BlockEntity tileEntity = level.getBlockEntity(basinPos); - if (tileEntity instanceof BasinTileEntity) { - float totalUnits = ((BasinTileEntity) tileEntity).getTotalFluidUnits(0); + BlockEntity blockEntity = level.getBlockEntity(basinPos); + if (blockEntity instanceof BasinBlockEntity) { + float totalUnits = ((BasinBlockEntity) blockEntity).getTotalFluidUnits(0); if (totalUnits < 1) totalUnits = 0; float fluidLevel = Mth.clamp(totalUnits / 2000, 0, 1); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java b/src/main/java/com/simibubi/create/content/fluids/particle/FluidParticleData.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java rename to src/main/java/com/simibubi/create/content/fluids/particle/FluidParticleData.java index 1ccd4941b0..e48abd50d9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java +++ b/src/main/java/com/simibubi/create/content/fluids/particle/FluidParticleData.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.fluids.particle; +package com.simibubi.create.content.fluids.particle; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllParticleTypes; -import com.simibubi.create.content.contraptions.particle.ICustomParticleData; +import com.simibubi.create.foundation.particle.ICustomParticleData; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.client.particle.ParticleProvider; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java b/src/main/java/com/simibubi/create/content/fluids/particle/FluidStackParticle.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java rename to src/main/java/com/simibubi/create/content/fluids/particle/FluidStackParticle.java index 99b14533d1..f498f62171 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java +++ b/src/main/java/com/simibubi/create/content/fluids/particle/FluidStackParticle.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.fluids.particle; +package com.simibubi.create.content.fluids.particle; import com.simibubi.create.AllParticleTypes; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid; +import com.simibubi.create.content.fluids.potion.PotionFluid; import net.createmod.catnip.utility.theme.Color; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/AxisPipeBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/AxisPipeBlock.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/AxisPipeBlock.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/AxisPipeBlock.java index c40dc7958e..fdaa1536f8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/AxisPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/AxisPipeBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import java.util.Map; import java.util.Optional; @@ -6,12 +6,12 @@ import java.util.Random; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.equipment.wrench.IWrenchableWithBracket; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -134,7 +134,7 @@ public class AxisPipeBlock extends RotatedPillarBlock implements IWrenchableWith @Override public Optional removeBracket(BlockGetter world, BlockPos pos, boolean inOnReplacedContext) { - BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); + BracketedBlockEntityBehaviour behaviour = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); if (behaviour == null) return Optional.empty(); BlockState bracket = behaviour.removeBracket(inOnReplacedContext); diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/EncasedPipeBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/EncasedPipeBlock.java new file mode 100644 index 0000000000..847320e1fe --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/EncasedPipeBlock.java @@ -0,0 +1,197 @@ +package com.simibubi.create.content.fluids.pipes; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.DOWN; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.EAST; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.NORTH; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.SOUTH; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.UP; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WEST; + +import java.util.Map; +import java.util.Random; +import java.util.function.Supplier; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.encasing.EncasedBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.DebugPackets; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.ticks.TickPriority; + +public class EncasedPipeBlock extends Block + implements IWrenchable, ISpecialBlockItemRequirement, IBE, EncasedBlock, ITransformableBlock { + public static final Map FACING_TO_PROPERTY_MAP = PipeBlock.PROPERTY_BY_DIRECTION; + + private final Supplier casing; + + public EncasedPipeBlock(Properties properties, Supplier casing) { + super(properties); + this.casing = casing; + registerDefaultState(defaultBlockState().setValue(NORTH, false) + .setValue(SOUTH, false) + .setValue(DOWN, false) + .setValue(UP, false) + .setValue(WEST, false) + .setValue(EAST, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN); + super.createBlockStateDefinition(builder); + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); + AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + boolean blockTypeChanged = state.getBlock() != newState.getBlock(); + if (blockTypeChanged && !world.isClientSide) + FluidPropagator.propagateChangedPipe(world, pos, state); + if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) + world.removeBlockEntity(pos); + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { + if (!world.isClientSide && state != oldState) + world.scheduleTick(pos, this, 1, TickPriority.HIGH); + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { + return AllBlocks.FLUID_PIPE.asStack(); + } + + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block otherBlock, BlockPos neighborPos, + boolean isMoving) { + DebugPackets.sendNeighborsUpdatePacket(world, pos); + Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving); + if (d == null) + return; + if (!state.getValue(FACING_TO_PROPERTY_MAP.get(d))) + return; + world.scheduleTick(pos, this, 1, TickPriority.HIGH); + } + + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, Random r) { + FluidPropagator.propagateChangedPipe(world, pos, state); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + Level world = context.getLevel(); + BlockPos pos = context.getClickedPos(); + + if (world.isClientSide) + return InteractionResult.SUCCESS; + + context.getLevel() + .levelEvent(2001, context.getClickedPos(), Block.getId(state)); + BlockState equivalentPipe = transferSixWayProperties(state, AllBlocks.FLUID_PIPE.getDefaultState()); + + Direction firstFound = Direction.UP; + for (Direction d : Iterate.directions) + if (state.getValue(FACING_TO_PROPERTY_MAP.get(d))) { + firstFound = d; + break; + } + + FluidTransportBehaviour.cacheFlows(world, pos); + world.setBlockAndUpdate(pos, AllBlocks.FLUID_PIPE.get() + .updateBlockState(equivalentPipe, firstFound, null, world, pos)); + FluidTransportBehaviour.loadFlows(world, pos); + return InteractionResult.SUCCESS; + } + + public static BlockState transferSixWayProperties(BlockState from, BlockState to) { + for (Direction d : Iterate.directions) { + BooleanProperty property = FACING_TO_PROPERTY_MAP.get(d); + to = to.setValue(property, from.getValue(property)); + } + return to; + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement.of(AllBlocks.FLUID_PIPE.getDefaultState(), be); + } + + @Override + public Class getBlockEntityClass() { + return FluidPipeBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ENCASED_FLUID_PIPE.get(); + } + + @Override + public Block getCasing() { + return casing.get(); + } + + @Override + public void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand, + BlockHitResult ray) { + FluidTransportBehaviour.cacheFlows(level, pos); + level.setBlockAndUpdate(pos, + EncasedPipeBlock.transferSixWayProperties(state, defaultBlockState())); + FluidTransportBehaviour.loadFlows(level, pos); + } + + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return FluidPipeBlockRotation.rotate(pState, pRotation); + } + + @Override + public BlockState mirror(BlockState pState, Mirror pMirror) { + return FluidPipeBlockRotation.mirror(pState, pMirror); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + return FluidPipeBlockRotation.transform(state, transform); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlock.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlock.java index 6ec3424315..b9c624ff84 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import java.util.Arrays; import java.util.Optional; @@ -6,16 +6,19 @@ import java.util.Random; import javax.annotation.Nullable; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour; -import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.decoration.encasing.EncasableBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchableWithBracket; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -35,7 +38,9 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SimpleWaterloggedBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -49,8 +54,8 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.TickPriority; -public class FluidPipeBlock extends PipeBlock - implements SimpleWaterloggedBlock, IWrenchableWithBracket, ITE { +public class FluidPipeBlock extends PipeBlock implements SimpleWaterloggedBlock, IWrenchableWithBracket, + IBE, EncasableBlock, ITransformableBlock { private static final VoxelShape OCCLUSION_BOX = Block.box(4, 4, 4, 12, 12, 12); @@ -90,7 +95,7 @@ public class FluidPipeBlock extends PipeBlock if (clickedFace.getAxis() == axis) return InteractionResult.PASS; if (!world.isClientSide) { - withTileEntityDo(world, pos, fpte -> fpte.getBehaviour(FluidTransportBehaviour.TYPE).interfaces.values() + withBlockEntityDo(world, pos, fpte -> fpte.getBehaviour(FluidTransportBehaviour.TYPE).interfaces.values() .stream() .filter(pc -> pc != null && pc.hasFlow()) .findAny() @@ -113,18 +118,13 @@ public class FluidPipeBlock extends PipeBlock @Override public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult hit) { - if (!AllBlocks.COPPER_CASING.isIn(player.getItemInHand(hand))) - return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; - - FluidTransportBehaviour.cacheFlows(world, pos); - world.setBlockAndUpdate(pos, - EncasedPipeBlock.transferSixWayProperties(state, AllBlocks.ENCASED_FLUID_PIPE.getDefaultState())); - FluidTransportBehaviour.loadFlows(world, pos); - return InteractionResult.SUCCESS; + BlockHitResult ray) { + ItemStack heldItem = player.getItemInHand(hand); + InteractionResult result = tryEncase(state, world, pos, heldItem, player, hand, ray); + if (result.consumesAction()) + return result; + return InteractionResult.PASS; } public BlockState getAxisState(Axis axis) { @@ -185,9 +185,9 @@ public class FluidPipeBlock extends PipeBlock return true; if (VanillaFluidTargets.shouldPipesConnectTo(neighbour)) return true; - FluidTransportBehaviour transport = TileEntityBehaviour.get(world, neighbourPos, FluidTransportBehaviour.TYPE); - BracketedTileEntityBehaviour bracket = - TileEntityBehaviour.get(world, neighbourPos, BracketedTileEntityBehaviour.TYPE); + FluidTransportBehaviour transport = BlockEntityBehaviour.get(world, neighbourPos, FluidTransportBehaviour.TYPE); + BracketedBlockEntityBehaviour bracket = + BlockEntityBehaviour.get(world, neighbourPos, BracketedBlockEntityBehaviour.TYPE); if (isPipe(neighbour)) return bracket == null || !bracket.isBracketPresent() || FluidPropagator.getStraightPipeAxis(neighbour) == direction.getAxis(); @@ -259,7 +259,7 @@ public class FluidPipeBlock extends PipeBlock public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore, BlockAndTintGetter world, BlockPos pos) { - BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); + BracketedBlockEntityBehaviour bracket = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); if (bracket != null && bracket.isBracketPresent()) return state; @@ -307,8 +307,8 @@ public class FluidPipeBlock extends PipeBlock @Override public Optional removeBracket(BlockGetter world, BlockPos pos, boolean inOnReplacedContext) { - BracketedTileEntityBehaviour behaviour = - BracketedTileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE); + BracketedBlockEntityBehaviour behaviour = + BracketedBlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); if (behaviour == null) return Optional.empty(); BlockState bracket = behaviour.removeBracket(inOnReplacedContext); @@ -323,13 +323,13 @@ public class FluidPipeBlock extends PipeBlock } @Override - public Class getTileEntityClass() { - return FluidPipeTileEntity.class; + public Class getBlockEntityClass() { + return FluidPipeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.FLUID_PIPE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.FLUID_PIPE.get(); } @Override @@ -342,4 +342,19 @@ public class FluidPipeBlock extends PipeBlock return OCCLUSION_BOX; } + @Override + public BlockState rotate(BlockState pState, Rotation pRotation) { + return FluidPipeBlockRotation.rotate(pState, pRotation); + } + + @Override + public BlockState mirror(BlockState pState, Mirror pMirror) { + return FluidPipeBlockRotation.mirror(pState, pMirror); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + return FluidPipeBlockRotation.transform(state, transform); + } + } diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockEntity.java new file mode 100644 index 0000000000..a7021c604b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockEntity.java @@ -0,0 +1,86 @@ +package com.simibubi.create.content.fluids.pipes; + +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class FluidPipeBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity { + + public FluidPipeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new StandardPipeFluidTransportBehaviour(this)); + behaviours.add(new BracketedBlockEntityBehaviour(this, this::canHaveBracket)); + registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); + } + + @Override + public void transform(StructureTransform transform) { + BracketedBlockEntityBehaviour bracketBehaviour = getBehaviour(BracketedBlockEntityBehaviour.TYPE); + if (bracketBehaviour != null) { + bracketBehaviour.transformBracket(transform); + } + } + + private boolean canHaveBracket(BlockState state) { + return !(state.getBlock() instanceof EncasedPipeBlock); + } + + class StandardPipeFluidTransportBehaviour extends FluidTransportBehaviour { + + public StandardPipeFluidTransportBehaviour(SmartBlockEntity be) { + super(be); + } + + @Override + public boolean canHaveFlowToward(BlockState state, Direction direction) { + return (FluidPipeBlock.isPipe(state) || state.getBlock() instanceof EncasedPipeBlock) + && state.getValue(FluidPipeBlock.PROPERTY_BY_DIRECTION.get(direction)); + } + + @Override + public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, + Direction direction) { + AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); + + BlockPos offsetPos = pos.relative(direction); + BlockState otherState = world.getBlockState(offsetPos); + + if (state.getBlock() instanceof EncasedPipeBlock && attachment != AttachmentTypes.DRAIN) + return AttachmentTypes.NONE; + + if (attachment == AttachmentTypes.RIM && !FluidPipeBlock.isPipe(otherState) + && !AllBlocks.MECHANICAL_PUMP.has(otherState) && !AllBlocks.ENCASED_FLUID_PIPE.has(otherState)) { + FluidTransportBehaviour pipeBehaviour = + BlockEntityBehaviour.get(world, offsetPos, FluidTransportBehaviour.TYPE); + if (pipeBehaviour != null) + if (pipeBehaviour.canHaveFlowToward(otherState, direction.getOpposite())) + return AttachmentTypes.CONNECTION; + } + + if (attachment == AttachmentTypes.RIM && !FluidPipeBlock.shouldDrawRim(world, pos, state, direction)) + return AttachmentTypes.CONNECTION; + if (attachment == AttachmentTypes.NONE && state.getValue(FluidPipeBlock.PROPERTY_BY_DIRECTION.get(direction))) + return AttachmentTypes.CONNECTION; + return attachment; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockRotation.java b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockRotation.java new file mode 100644 index 0000000000..8f66ce1b73 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/FluidPipeBlockRotation.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.fluids.pipes; + +import java.util.Map; + +import com.simibubi.create.content.contraptions.StructureTransform; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.PipeBlock; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +public class FluidPipeBlockRotation { + + public static final Map FACING_TO_PROPERTY_MAP = PipeBlock.PROPERTY_BY_DIRECTION; + + public static BlockState rotate(BlockState state, Rotation rotation) { + BlockState rotated = state; + for (Direction direction : Iterate.horizontalDirections) + rotated = rotated.setValue(FACING_TO_PROPERTY_MAP.get(rotation.rotate(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return rotated; + } + + public static BlockState mirror(BlockState state, Mirror mirror) { + BlockState mirrored = state; + for (Direction direction : Iterate.horizontalDirections) + mirrored = mirrored.setValue(FACING_TO_PROPERTY_MAP.get(mirror.mirror(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return mirrored; + } + + public static BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) + state = mirror(state, transform.mirror); + + if (transform.rotationAxis == Direction.Axis.Y) + return rotate(state, transform.rotation); + + BlockState rotated = state; + for (Direction direction : Iterate.directions) + rotated = rotated.setValue(FACING_TO_PROPERTY_MAP.get(transform.rotateFacing(direction)), + state.getValue(FACING_TO_PROPERTY_MAP.get(direction))); + return rotated; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/GlassFluidPipeBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/GlassFluidPipeBlock.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/GlassFluidPipeBlock.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/GlassFluidPipeBlock.java index 8b697039a1..4752f03ae1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/GlassFluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/GlassFluidPipeBlock.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import javax.annotation.ParametersAreNonnullByDefault; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ import net.minecraft.world.level.pathfinder.PathComputationType; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class GlassFluidPipeBlock extends AxisPipeBlock implements ITE, SimpleWaterloggedBlock, ISpecialBlockItemRequirement { +public class GlassFluidPipeBlock extends AxisPipeBlock implements IBE, SimpleWaterloggedBlock, ISpecialBlockItemRequirement { public static final BooleanProperty ALT = BooleanProperty.create("alt"); @@ -74,8 +74,8 @@ public class GlassFluidPipeBlock extends AxisPipeBlock implements ITE getTileEntityClass() { - return StraightPipeTileEntity.class; + public Class getBlockEntityClass() { + return StraightPipeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.GLASS_FLUID_PIPE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.GLASS_FLUID_PIPE.get(); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/IAxisPipe.java b/src/main/java/com/simibubi/create/content/fluids/pipes/IAxisPipe.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/IAxisPipe.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/IAxisPipe.java index 8087248e58..f6e32dfc6d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/IAxisPipe.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/IAxisPipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import javax.annotation.Nullable; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlock.java index aed3f35aad..87719b2bd1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlock.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.FluidPropagator; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.createmod.catnip.utility.Iterate; @@ -37,7 +37,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.TickPriority; public class SmartFluidPipeBlock extends FaceAttachedHorizontalDirectionalBlock - implements ITE, IAxisPipe, IWrenchable, ProperWaterloggedBlock { + implements IBE, IAxisPipe, IWrenchable, ProperWaterloggedBlock { public SmartFluidPipeBlock(Properties p_i48339_1_) { super(p_i48339_1_); @@ -93,8 +93,7 @@ public class SmartFluidPipeBlock extends FaceAttachedHorizontalDirectionalBlock boolean blockTypeChanged = state.getBlock() != newState.getBlock(); if (blockTypeChanged && !world.isClientSide) FluidPropagator.propagateChangedPipe(world, pos, state); - if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) - world.removeBlockEntity(pos); + IBE.onRemove(state, world, pos, newState); } @Override @@ -175,13 +174,13 @@ public class SmartFluidPipeBlock extends FaceAttachedHorizontalDirectionalBlock } @Override - public Class getTileEntityClass() { - return SmartFluidPipeTileEntity.class; + public Class getBlockEntityClass() { + return SmartFluidPipeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SMART_FLUID_PIPE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SMART_FLUID_PIPE.get(); } } diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlockEntity.java new file mode 100644 index 0000000000..9ba2710bfb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeBlockEntity.java @@ -0,0 +1,101 @@ +package com.simibubi.create.content.fluids.pipes; + +import java.util.List; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.pipes.StraightPipeBlockEntity.StraightPipeFluidTransportBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fluids.FluidStack; + +public class SmartFluidPipeBlockEntity extends SmartBlockEntity { + + private FilteringBehaviour filter; + + public SmartFluidPipeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new SmartPipeBehaviour(this)); + behaviours.add(filter = new FilteringBehaviour(this, new SmartPipeFilterSlot()).forFluids() + .withCallback(this::onFilterChanged)); + registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); + } + + private void onFilterChanged(ItemStack newFilter) { + if (!level.isClientSide) + FluidPropagator.propagateChangedPipe(level, worldPosition, getBlockState()); + } + + class SmartPipeBehaviour extends StraightPipeFluidTransportBehaviour { + + public SmartPipeBehaviour(SmartBlockEntity be) { + super(be); + } + + @Override + public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) { + if (fluid.isEmpty() || filter != null && filter.test(fluid)) + return super.canPullFluidFrom(fluid, state, direction); + return false; + } + + @Override + public boolean canHaveFlowToward(BlockState state, Direction direction) { + return state.getBlock() instanceof SmartFluidPipeBlock + && SmartFluidPipeBlock.getPipeAxis(state) == direction.getAxis(); + } + + } + + class SmartPipeFilterSlot extends ValueBoxTransform { + + @Override + public Vec3 getLocalOffset(BlockState state) { + AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); + float y = face == AttachFace.CEILING ? 0.55f : face == AttachFace.WALL ? 11.4f : 15.45f; + float z = face == AttachFace.CEILING ? 4.6f : face == AttachFace.WALL ? 0.55f : 4.625f; + return VecHelper.rotateCentered(VecHelper.voxelSpace(8, y, z), angleY(state), Axis.Y); + } + + @Override + public float getScale() { + return super.getScale() * 1.02f; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); + TransformStack.cast(ms) + .rotateY(angleY(state)) + .rotateX(face == AttachFace.CEILING ? -45 : 45); + } + + protected float angleY(BlockState state) { + AttachFace face = state.getValue(SmartFluidPipeBlock.FACE); + float horizontalAngle = AngleHelper.horizontalAngle(state.getValue(SmartFluidPipeBlock.FACING)); + if (face == AttachFace.WALL) + horizontalAngle += 180; + return horizontalAngle; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeGenerator.java b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeGenerator.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeGenerator.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeGenerator.java index 4e688c80ac..30c39a1dee 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/SmartFluidPipeGenerator.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/SmartFluidPipeGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/StraightPipeBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/pipes/StraightPipeBlockEntity.java new file mode 100644 index 0000000000..de8a98ca84 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/StraightPipeBlockEntity.java @@ -0,0 +1,68 @@ +package com.simibubi.create.content.fluids.pipes; + +import java.util.List; + +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.fluids.pipes.valve.FluidValveBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class StraightPipeBlockEntity extends SmartBlockEntity { + + public StraightPipeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new StraightPipeFluidTransportBehaviour(this)); + behaviours.add(new BracketedBlockEntityBehaviour(this)); + registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); + } + + public static class StraightPipeFluidTransportBehaviour extends FluidTransportBehaviour { + + public StraightPipeFluidTransportBehaviour(SmartBlockEntity be) { + super(be); + } + + @Override + public boolean canHaveFlowToward(BlockState state, Direction direction) { + return state.hasProperty(AxisPipeBlock.AXIS) && state.getValue(AxisPipeBlock.AXIS) == direction.getAxis(); + } + + @Override + public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, + Direction direction) { + AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); + BlockState otherState = world.getBlockState(pos.relative(direction)); + + Axis axis = IAxisPipe.getAxisOf(state); + Axis otherAxis = IAxisPipe.getAxisOf(otherState); + + if (attachment == AttachmentTypes.RIM && state.getBlock() instanceof FluidValveBlock) + return AttachmentTypes.NONE; + if (attachment == AttachmentTypes.RIM && FluidPipeBlock.isPipe(otherState)) + return AttachmentTypes.PARTIAL_RIM; + if (axis == otherAxis && axis != null) + return AttachmentTypes.NONE; + + if (otherState.getBlock() instanceof FluidValveBlock + && FluidValveBlock.getPipeAxis(otherState) == direction.getAxis()) + return AttachmentTypes.NONE; + + return attachment.withoutConnector(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/TransparentStraightPipeRenderer.java b/src/main/java/com/simibubi/create/content/fluids/pipes/TransparentStraightPipeRenderer.java new file mode 100644 index 0000000000..ae77501251 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/TransparentStraightPipeRenderer.java @@ -0,0 +1,66 @@ +package com.simibubi.create.content.fluids.pipes; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.fluids.PipeConnection.Flow; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.fluid.FluidRenderer; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraftforge.fluids.FluidStack; + +public class TransparentStraightPipeRenderer extends SafeBlockEntityRenderer { + + public TransparentStraightPipeRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(StraightPipeBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + FluidTransportBehaviour pipe = be.getBehaviour(FluidTransportBehaviour.TYPE); + if (pipe == null) + return; + + for (Direction side : Iterate.directions) { + + Flow flow = pipe.getFlow(side); + if (flow == null) + continue; + FluidStack fluidStack = flow.fluid; + if (fluidStack.isEmpty()) + continue; + LerpedFloat progress = flow.progress; + if (progress == null) + continue; + + float value = progress.getValue(partialTicks); + boolean inbound = flow.inbound; + if (value == 1) { + if (inbound) { + Flow opposite = pipe.getFlow(side.getOpposite()); + if (opposite == null) + value -= 1e-6f; + } else { + FluidTransportBehaviour adjacent = BlockEntityBehaviour.get(be.getLevel(), be.getBlockPos() + .relative(side), FluidTransportBehaviour.TYPE); + if (adjacent == null) + value -= 1e-6f; + else { + Flow other = adjacent.getFlow(side.getOpposite()); + if (other == null || !other.inbound && !other.complete) + value -= 1e-6f; + } + } + } + + FluidRenderer.renderFluidStream(fluidStack, side, 3 / 16f, value, inbound, buffer, ms, light); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/VanillaFluidTargets.java b/src/main/java/com/simibubi/create/content/fluids/pipes/VanillaFluidTargets.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/VanillaFluidTargets.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/VanillaFluidTargets.java index 0b761d4e6c..d971b9b664 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/VanillaFluidTargets.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/VanillaFluidTargets.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.LEVEL_HONEY; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlock.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java rename to src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlock.java index 5d4ddf01de..af017eab77 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/pipes/FluidValveBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlock.java @@ -1,14 +1,16 @@ -package com.simibubi.create.content.contraptions.fluids.pipes; +package com.simibubi.create.content.fluids.pipes.valve; import java.util.Random; import javax.annotation.Nonnull; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.fluids.FluidPropagator; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.content.fluids.pipes.IAxisPipe; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.createmod.catnip.utility.Iterate; @@ -34,7 +36,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.TickPriority; public class FluidValveBlock extends DirectionalAxisKineticBlock - implements IAxisPipe, ITE, ProperWaterloggedBlock { + implements IAxisPipe, IBE, ProperWaterloggedBlock { public static final BooleanProperty ENABLED = BooleanProperty.create("enabled"); @@ -90,11 +92,10 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock @Override public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - boolean blockTypeChanged = state.getBlock() != newState.getBlock(); + boolean blockTypeChanged = !state.is(newState.getBlock()); if (blockTypeChanged && !world.isClientSide) FluidPropagator.propagateChangedPipe(world, pos, state); - if (state.hasBlockEntity() && (blockTypeChanged || !newState.hasBlockEntity())) - world.removeBlockEntity(pos); + super.onRemove(state, world, pos, newState, isMoving); } @Override @@ -138,13 +139,13 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock } @Override - public Class getTileEntityClass() { - return FluidValveTileEntity.class; + public Class getBlockEntityClass() { + return FluidValveBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.FLUID_VALVE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.FLUID_VALVE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlockEntity.java new file mode 100644 index 0000000000..e98113cf96 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveBlockEntity.java @@ -0,0 +1,105 @@ +package com.simibubi.create.content.fluids.pipes.valve; + +import java.util.List; + +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.pipes.StraightPipeBlockEntity.StraightPipeFluidTransportBehaviour; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.FluidStack; + +public class FluidValveBlockEntity extends KineticBlockEntity { + + LerpedFloat pointer; + + public FluidValveBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + pointer = LerpedFloat.linear() + .startWithValue(0) + .chase(0, 0, Chaser.LINEAR); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + float speed = getSpeed(); + pointer.chase(speed > 0 ? 1 : 0, getChaseSpeed(), Chaser.LINEAR); + sendData(); + } + + @Override + public void tick() { + super.tick(); + pointer.tickChaser(); + + if (level.isClientSide) + return; + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof FluidValveBlock)) + return; + boolean stateOpen = blockState.getValue(FluidValveBlock.ENABLED); + + if (stateOpen && pointer.getValue() == 0) { + switchToBlockState(level, worldPosition, blockState.setValue(FluidValveBlock.ENABLED, false)); + return; + } + if (!stateOpen && pointer.getValue() == 1) { + switchToBlockState(level, worldPosition, blockState.setValue(FluidValveBlock.ENABLED, true)); + return; + } + } + + private float getChaseSpeed() { + return Mth.clamp(Math.abs(getSpeed()) / 16 / 20, 0, 1); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.put("Pointer", pointer.writeNBT()); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + pointer.readNBT(compound.getCompound("Pointer"), clientPacket); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new ValvePipeBehaviour(this)); + registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); + } + + class ValvePipeBehaviour extends StraightPipeFluidTransportBehaviour { + + public ValvePipeBehaviour(SmartBlockEntity be) { + super(be); + } + + @Override + public boolean canHaveFlowToward(BlockState state, Direction direction) { + return FluidValveBlock.getPipeAxis(state) == direction.getAxis(); + } + + @Override + public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) { + if (state.hasProperty(FluidValveBlock.ENABLED) && state.getValue(FluidValveBlock.ENABLED)) + return super.canPullFluidFrom(fluid, state, direction); + return false; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveInstance.java b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveInstance.java new file mode 100644 index 0000000000..f2265ddc2a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveInstance.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.fluids.pipes.valve; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; + +public class FluidValveInstance extends ShaftInstance implements DynamicInstance { + + protected ModelData pointer; + protected boolean settled; + + protected final double xRot; + protected final double yRot; + protected final int pointerRotationOffset; + + public FluidValveInstance(MaterialManager dispatcher, FluidValveBlockEntity blockEntity) { + super(dispatcher, blockEntity); + + Direction facing = blockState.getValue(FluidValveBlock.FACING); + + yRot = AngleHelper.horizontalAngle(facing); + xRot = facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90; + + Direction.Axis pipeAxis = FluidValveBlock.getPipeAxis(blockState); + Direction.Axis shaftAxis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity); + + boolean twist = pipeAxis.isHorizontal() && shaftAxis == Direction.Axis.X || pipeAxis.isVertical(); + pointerRotationOffset = twist ? 90 : 0; + settled = false; + + pointer = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(AllPartialModels.FLUID_VALVE_POINTER, blockState).createInstance(); + + transformPointer(); + } + + @Override + public void beginFrame() { + if (blockEntity.pointer.settled() && settled) + return; + + transformPointer(); + } + + private void transformPointer() { + float value = blockEntity.pointer.getValue(AnimationTickHolder.getPartialTicks()); + float pointerRotation = Mth.lerp(value, 0, -90); + settled = (value == 0 || value == 1) && blockEntity.pointer.settled(); + + pointer.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotateY(yRot) + .rotateX(xRot) + .rotateY(pointerRotationOffset + pointerRotation) + .unCentre(); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, pointer); + } + + @Override + public void remove() { + super.remove(); + pointer.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveRenderer.java b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveRenderer.java new file mode 100644 index 0000000000..d490aebdc8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pipes/valve/FluidValveRenderer.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.fluids.pipes.valve; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class FluidValveRenderer extends KineticBlockEntityRenderer { + + public FluidValveRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(FluidValveBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + BlockState blockState = be.getBlockState(); + SuperByteBuffer pointer = CachedPartialBuffers.partial(AllPartialModels.FLUID_VALVE_POINTER, blockState); + Direction facing = blockState.getValue(FluidValveBlock.FACING); + + float pointerRotation = Mth.lerp(be.pointer.getValue(partialTicks), 0, -90); + Axis pipeAxis = FluidValveBlock.getPipeAxis(blockState); + Axis shaftAxis = getRotationAxisOf(be); + + int pointerRotationOffset = 0; + if (pipeAxis.isHorizontal() && shaftAxis == Axis.X || pipeAxis.isVertical()) + pointerRotationOffset = 90; + + pointer.centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(facing == Direction.UP ? 0 : facing == Direction.DOWN ? 180 : 90) + .rotateY(pointerRotationOffset + pointerRotation) + .unCentre() + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + + @Override + protected BlockState getRenderedBlockState(FluidValveBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java b/src/main/java/com/simibubi/create/content/fluids/potion/PotionFluid.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java rename to src/main/java/com/simibubi/create/content/fluids/potion/PotionFluid.java index bbc2bde227..8c2b318a84 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluid.java +++ b/src/main/java/com/simibubi/create/content/fluids/potion/PotionFluid.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.fluids.potion; +package com.simibubi.create.content.fluids.potion; import java.util.Collection; import java.util.List; import com.simibubi.create.AllFluids; -import com.simibubi.create.content.contraptions.fluids.VirtualFluid; +import com.simibubi.create.content.fluids.VirtualFluid; import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.utility.NBTHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java b/src/main/java/com/simibubi/create/content/fluids/potion/PotionFluidHandler.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java rename to src/main/java/com/simibubi/create/content/fluids/potion/PotionFluidHandler.java index fdf76d899c..625ec4fea9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/potion/PotionFluidHandler.java +++ b/src/main/java/com/simibubi/create/content/fluids/potion/PotionFluidHandler.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.fluids.potion; +package com.simibubi.create.content.fluids.potion; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.Lists; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid.BottleType; +import com.simibubi.create.content.fluids.potion.PotionFluid.BottleType; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidIngredient; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/recipe/PotionMixingRecipes.java b/src/main/java/com/simibubi/create/content/fluids/potion/PotionMixingRecipes.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/recipe/PotionMixingRecipes.java rename to src/main/java/com/simibubi/create/content/fluids/potion/PotionMixingRecipes.java index 4f91335b48..4d3230eba0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/recipe/PotionMixingRecipes.java +++ b/src/main/java/com/simibubi/create/content/fluids/potion/PotionMixingRecipes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.recipe; +package com.simibubi.create.content.fluids.potion; import java.util.ArrayList; import java.util.HashMap; @@ -8,11 +8,10 @@ import java.util.Map; import java.util.Set; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.mixer.MixingRecipe; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid.BottleType; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; -import com.simibubi.create.content.contraptions.processing.HeatCondition; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; +import com.simibubi.create.content.fluids.potion.PotionFluid.BottleType; +import com.simibubi.create.content.kinetics.mixer.MixingRecipe; +import com.simibubi.create.content.processing.recipe.HeatCondition; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; import com.simibubi.create.foundation.fluid.FluidIngredient; import net.minecraft.world.item.Item; diff --git a/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlock.java b/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlock.java new file mode 100644 index 0000000000..efadee0d36 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlock.java @@ -0,0 +1,196 @@ +package com.simibubi.create.content.fluids.pump; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.network.protocol.game.DebugPackets; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraft.world.ticks.TickPriority; + +public class PumpBlock extends DirectionalKineticBlock + implements SimpleWaterloggedBlock, ICogWheel, IBE { + + public PumpBlock(Properties p_i48415_1_) { + super(p_i48415_1_); + registerDefaultState(super.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); + } + + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + return originalState.setValue(FACING, originalState.getValue(FACING) + .getOpposite()); + } + + @Override + public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { + return super.updateAfterWrenched(newState, context); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(FACING) + .getAxis(); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.PUMP.get(state.getValue(FACING)); + } + + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block otherBlock, BlockPos neighborPos, + boolean isMoving) { + DebugPackets.sendNeighborsUpdatePacket(world, pos); + Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving); + if (d == null) + return; + if (!isOpenAt(state, d)) + return; + world.scheduleTick(pos, this, 1, TickPriority.HIGH); + } + + @Override + public FluidState getFluidState(BlockState state) { + return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) + : Fluids.EMPTY.defaultFluidState(); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(BlockStateProperties.WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, LevelAccessor world, + BlockPos pos, BlockPos neighbourPos) { + if (state.getValue(BlockStateProperties.WATERLOGGED)) + world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + return state; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState toPlace = super.getStateForPlacement(context); + Level level = context.getLevel(); + BlockPos pos = context.getClickedPos(); + Player player = context.getPlayer(); + toPlace = ProperWaterloggedBlock.withWater(level, toPlace, pos); + + Direction nearestLookingDirection = context.getNearestLookingDirection(); + Direction targetDirection = context.getPlayer() != null && context.getPlayer() + .isShiftKeyDown() ? nearestLookingDirection : nearestLookingDirection.getOpposite(); + Direction bestConnectedDirection = null; + double bestDistance = Double.MAX_VALUE; + + for (Direction d : Iterate.directions) { + BlockPos adjPos = pos.relative(d); + BlockState adjState = level.getBlockState(adjPos); + if (!FluidPipeBlock.canConnectTo(level, adjPos, adjState, d)) + continue; + double distance = Vec3.atLowerCornerOf(d.getNormal()) + .distanceTo(Vec3.atLowerCornerOf(targetDirection.getNormal())); + if (distance > bestDistance) + continue; + bestDistance = distance; + bestConnectedDirection = d; + } + + if (bestConnectedDirection == null) + return toPlace; + if (bestConnectedDirection.getAxis() == targetDirection.getAxis()) + return toPlace; + if (player.isSteppingCarefully() && bestConnectedDirection.getAxis() != targetDirection.getAxis()) + return toPlace; + + return toPlace.setValue(FACING, bestConnectedDirection); + } + + public static boolean isPump(BlockState state) { + return state.getBlock() instanceof PumpBlock; + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, world, pos, oldState, isMoving); + if (world.isClientSide) + return; + if (state != oldState) + world.scheduleTick(pos, this, 1, TickPriority.HIGH); + + if (isPump(state) && isPump(oldState) && state.getValue(FACING) == oldState.getValue(FACING) + .getOpposite()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof PumpBlockEntity)) + return; + PumpBlockEntity pump = (PumpBlockEntity) blockEntity; + pump.pressureUpdate = true; + } + } + + public static boolean isOpenAt(BlockState state, Direction d) { + return d.getAxis() == state.getValue(FACING) + .getAxis(); + } + + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, Random r) { + FluidPropagator.propagateChangedPipe(world, pos, state); + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + boolean blockTypeChanged = !state.is(newState.getBlock()); + if (blockTypeChanged && !world.isClientSide) + FluidPropagator.propagateChangedPipe(world, pos, state); + super.onRemove(state, world, pos, newState, isMoving); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + public Class getBlockEntityClass() { + return PumpBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_PUMP.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlockEntity.java new file mode 100644 index 0000000000..912394c3c6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pump/PumpBlockEntity.java @@ -0,0 +1,373 @@ +package com.simibubi.create.content.fluids.pump; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.simibubi.create.content.fluids.FluidPropagator; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.fluids.PipeConnection; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.BlockFace; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public class PumpBlockEntity extends KineticBlockEntity { + + Couple sidesToUpdate; + boolean pressureUpdate; + + // Backcompat- flips any pump blockstate that loads with reversed=true + boolean scheduleFlip; + + public PumpBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + sidesToUpdate = Couple.create(MutableBoolean::new); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(new PumpFluidTransferBehaviour(this)); + registerAwardables(behaviours, FluidPropagator.getSharedTriggers()); + registerAwardables(behaviours, AllAdvancements.PUMP); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide && !isVirtual()) + return; + + if (scheduleFlip) { + level.setBlockAndUpdate(worldPosition, + getBlockState().setValue(PumpBlock.FACING, getBlockState().getValue(PumpBlock.FACING) + .getOpposite())); + scheduleFlip = false; + } + + sidesToUpdate.forEachWithContext((update, isFront) -> { + if (update.isFalse()) + return; + update.setFalse(); + distributePressureTo(isFront ? getFront() : getFront().getOpposite()); + }); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + + if (Math.abs(previousSpeed) == Math.abs(getSpeed())) + return; + if (speed != 0) + award(AllAdvancements.PUMP); + if (level.isClientSide && !isVirtual()) + return; + + updatePressureChange(); + } + + public void updatePressureChange() { + pressureUpdate = false; + BlockPos frontPos = worldPosition.relative(getFront()); + BlockPos backPos = worldPosition.relative(getFront().getOpposite()); + FluidPropagator.propagateChangedPipe(level, frontPos, level.getBlockState(frontPos)); + FluidPropagator.propagateChangedPipe(level, backPos, level.getBlockState(backPos)); + + FluidTransportBehaviour behaviour = getBehaviour(FluidTransportBehaviour.TYPE); + if (behaviour != null) + behaviour.wipePressure(); + sidesToUpdate.forEach(MutableBoolean::setTrue); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (compound.getBoolean("Reversed")) + scheduleFlip = true; + } + + protected void distributePressureTo(Direction side) { + if (getSpeed() == 0) + return; + + BlockFace start = new BlockFace(worldPosition, side); + boolean pull = isPullingOnSide(isFront(side)); + Set targets = new HashSet<>(); + Map>> pipeGraph = new HashMap<>(); + + if (!pull) + FluidPropagator.resetAffectedFluidNetworks(level, worldPosition, side.getOpposite()); + + if (!hasReachedValidEndpoint(level, start, pull)) { + + pipeGraph.computeIfAbsent(worldPosition, $ -> Pair.of(0, new IdentityHashMap<>())) + .getSecond() + .put(side, pull); + pipeGraph.computeIfAbsent(start.getConnectedPos(), $ -> Pair.of(1, new IdentityHashMap<>())) + .getSecond() + .put(side.getOpposite(), !pull); + + List> frontier = new ArrayList<>(); + Set visited = new HashSet<>(); + int maxDistance = FluidPropagator.getPumpRange(); + frontier.add(Pair.of(1, start.getConnectedPos())); + + while (!frontier.isEmpty()) { + Pair entry = frontier.remove(0); + int distance = entry.getFirst(); + BlockPos currentPos = entry.getSecond(); + + if (!level.isLoaded(currentPos)) + continue; + if (visited.contains(currentPos)) + continue; + visited.add(currentPos); + BlockState currentState = level.getBlockState(currentPos); + FluidTransportBehaviour pipe = FluidPropagator.getPipe(level, currentPos); + if (pipe == null) + continue; + + for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) { + BlockFace blockFace = new BlockFace(currentPos, face); + BlockPos connectedPos = blockFace.getConnectedPos(); + + if (!level.isLoaded(connectedPos)) + continue; + if (blockFace.isEquivalent(start)) + continue; + if (hasReachedValidEndpoint(level, blockFace, pull)) { + pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) + .getSecond() + .put(face, pull); + targets.add(blockFace); + continue; + } + + FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(level, connectedPos); + if (pipeBehaviour == null) + continue; + if (pipeBehaviour instanceof PumpFluidTransferBehaviour) + continue; + if (visited.contains(connectedPos)) + continue; + if (distance + 1 >= maxDistance) { + pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) + .getSecond() + .put(face, pull); + targets.add(blockFace); + continue; + } + + pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>())) + .getSecond() + .put(face, pull); + pipeGraph.computeIfAbsent(connectedPos, $ -> Pair.of(distance + 1, new IdentityHashMap<>())) + .getSecond() + .put(face.getOpposite(), !pull); + frontier.add(Pair.of(distance + 1, connectedPos)); + } + } + } + + // DFS + Map> validFaces = new HashMap<>(); + searchForEndpointRecursively(pipeGraph, targets, validFaces, + new BlockFace(start.getPos(), start.getOppositeFace()), pull); + + float pressure = Math.abs(getSpeed()); + for (Set set : validFaces.values()) { + int parallelBranches = Math.max(1, set.size() - 1); + for (BlockFace face : set) { + BlockPos pipePos = face.getPos(); + Direction pipeSide = face.getFace(); + + if (pipePos.equals(worldPosition)) + continue; + + boolean inbound = pipeGraph.get(pipePos) + .getSecond() + .get(pipeSide); + FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(level, pipePos); + if (pipeBehaviour == null) + continue; + + pipeBehaviour.addPressure(pipeSide, inbound, pressure / parallelBranches); + } + } + + } + + protected boolean searchForEndpointRecursively(Map>> pipeGraph, + Set targets, Map> validFaces, BlockFace currentFace, boolean pull) { + BlockPos currentPos = currentFace.getPos(); + if (!pipeGraph.containsKey(currentPos)) + return false; + Pair> pair = pipeGraph.get(currentPos); + int distance = pair.getFirst(); + + boolean atLeastOneBranchSuccessful = false; + for (Direction nextFacing : Iterate.directions) { + if (nextFacing == currentFace.getFace()) + continue; + Map map = pair.getSecond(); + if (!map.containsKey(nextFacing)) + continue; + + BlockFace localTarget = new BlockFace(currentPos, nextFacing); + if (targets.contains(localTarget)) { + validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) + .add(localTarget); + atLeastOneBranchSuccessful = true; + continue; + } + + if (map.get(nextFacing) != pull) + continue; + if (!searchForEndpointRecursively(pipeGraph, targets, validFaces, + new BlockFace(currentPos.relative(nextFacing), nextFacing.getOpposite()), pull)) + continue; + + validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) + .add(localTarget); + atLeastOneBranchSuccessful = true; + } + + if (atLeastOneBranchSuccessful) + validFaces.computeIfAbsent(distance, $ -> new HashSet<>()) + .add(currentFace); + + return atLeastOneBranchSuccessful; + } + + private boolean hasReachedValidEndpoint(LevelAccessor world, BlockFace blockFace, boolean pull) { + BlockPos connectedPos = blockFace.getConnectedPos(); + BlockState connectedState = world.getBlockState(connectedPos); + BlockEntity blockEntity = world.getBlockEntity(connectedPos); + Direction face = blockFace.getFace(); + + // facing a pump + if (PumpBlock.isPump(connectedState) && connectedState.getValue(PumpBlock.FACING) + .getAxis() == face.getAxis() && blockEntity instanceof PumpBlockEntity) { + PumpBlockEntity pumpBE = (PumpBlockEntity) blockEntity; + return pumpBE.isPullingOnSide(pumpBE.isFront(blockFace.getOppositeFace())) != pull; + } + + // other pipe, no endpoint + FluidTransportBehaviour pipe = FluidPropagator.getPipe(world, connectedPos); + if (pipe != null && pipe.canHaveFlowToward(connectedState, blockFace.getOppositeFace())) + return false; + + // fluid handler endpoint + if (blockEntity != null) { + LazyOptional capability = + blockEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite()); + if (capability.isPresent()) + return true; + } + + // open endpoint + return FluidPropagator.isOpenEnd(world, blockFace.getPos(), face); + } + + public void updatePipesOnSide(Direction side) { + if (!isSideAccessible(side)) + return; + updatePipeNetwork(isFront(side)); + getBehaviour(FluidTransportBehaviour.TYPE).wipePressure(); + } + + protected boolean isFront(Direction side) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return false; + Direction front = blockState.getValue(PumpBlock.FACING); + boolean isFront = side == front; + return isFront; + } + + @Nullable + protected Direction getFront() { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return null; + return blockState.getValue(PumpBlock.FACING); + } + + protected void updatePipeNetwork(boolean front) { + sidesToUpdate.get(front) + .setTrue(); + } + + public boolean isSideAccessible(Direction side) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return false; + return blockState.getValue(PumpBlock.FACING) + .getAxis() == side.getAxis(); + } + + public boolean isPullingOnSide(boolean front) { + return !front; + } + + class PumpFluidTransferBehaviour extends FluidTransportBehaviour { + + public PumpFluidTransferBehaviour(SmartBlockEntity be) { + super(be); + } + + @Override + public void tick() { + super.tick(); + for (Entry entry : interfaces.entrySet()) { + boolean pull = isPullingOnSide(isFront(entry.getKey())); + Couple pressure = entry.getValue().getPressure(); + pressure.set(pull, Math.abs(getSpeed())); + pressure.set(!pull, 0f); + } + } + + @Override + public boolean canHaveFlowToward(BlockState state, Direction direction) { + return isSideAccessible(direction); + } + + @Override + public AttachmentTypes getRenderedRimAttachment(BlockAndTintGetter world, BlockPos pos, BlockState state, + Direction direction) { + AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction); + if (attachment == AttachmentTypes.RIM) + return AttachmentTypes.NONE; + return attachment; + } + + } +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pump/PumpCogInstance.java b/src/main/java/com/simibubi/create/content/fluids/pump/PumpCogInstance.java new file mode 100644 index 0000000000..629ec754a1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pump/PumpCogInstance.java @@ -0,0 +1,30 @@ +package com.simibubi.create.content.fluids.pump; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class PumpCogInstance extends SingleRotatingInstance implements DynamicInstance { + + public PumpCogInstance(MaterialManager materialManager, PumpBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + public void beginFrame() {} + + @Override + protected Instancer getModel() { + BlockState referenceState = blockEntity.getBlockState(); + Direction facing = referenceState.getValue(BlockStateProperties.FACING); + return getRotatingMaterial().getModel(AllPartialModels.MECHANICAL_PUMP_COG, referenceState, facing); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/pump/PumpRenderer.java b/src/main/java/com/simibubi/create/content/fluids/pump/PumpRenderer.java new file mode 100644 index 0000000000..550bc16780 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/pump/PumpRenderer.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.fluids.pump; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class PumpRenderer extends KineticBlockEntityRenderer { + + public PumpRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected SuperByteBuffer getRotatedModel(PumpBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacing(AllPartialModels.MECHANICAL_PUMP_COG, state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/spout/FillingBySpout.java b/src/main/java/com/simibubi/create/content/fluids/spout/FillingBySpout.java new file mode 100644 index 0000000000..bea104cb0d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/spout/FillingBySpout.java @@ -0,0 +1,97 @@ +package com.simibubi.create.content.fluids.spout; + +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.fluids.transfer.FillingRecipe; +import com.simibubi.create.content.fluids.transfer.GenericItemFilling; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.foundation.fluid.FluidIngredient; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.Level; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class FillingBySpout { + + private static final RecipeWrapper WRAPPER = new RecipeWrapper(new ItemStackHandler(1)); + + public static boolean canItemBeFilled(Level world, ItemStack stack) { + WRAPPER.setItem(0, stack); + + Optional assemblyRecipe = + SequencedAssemblyRecipe.getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class); + if (assemblyRecipe.isPresent()) + return true; + + if (AllRecipeTypes.FILLING.find(WRAPPER, world) + .isPresent()) + return true; + return GenericItemFilling.canItemBeFilled(world, stack); + } + + public static int getRequiredAmountForItem(Level world, ItemStack stack, FluidStack availableFluid) { + WRAPPER.setItem(0, stack); + + Optional assemblyRecipe = SequencedAssemblyRecipe.getRecipe(world, WRAPPER, + AllRecipeTypes.FILLING.getType(), FillingRecipe.class, matchItemAndFluid(world, availableFluid)); + if (assemblyRecipe.isPresent()) { + FluidIngredient requiredFluid = assemblyRecipe.get() + .getRequiredFluid(); + if (requiredFluid.test(availableFluid)) + return requiredFluid.getRequiredAmount(); + } + + for (Recipe recipe : world.getRecipeManager() + .getRecipesFor(AllRecipeTypes.FILLING.getType(), WRAPPER, world)) { + FillingRecipe fillingRecipe = (FillingRecipe) recipe; + FluidIngredient requiredFluid = fillingRecipe.getRequiredFluid(); + if (requiredFluid.test(availableFluid)) + return requiredFluid.getRequiredAmount(); + } + return GenericItemFilling.getRequiredAmountForItem(world, stack, availableFluid); + } + + public static ItemStack fillItem(Level world, int requiredAmount, ItemStack stack, FluidStack availableFluid) { + FluidStack toFill = availableFluid.copy(); + toFill.setAmount(requiredAmount); + + WRAPPER.setItem(0, stack); + + FillingRecipe fillingRecipe = SequencedAssemblyRecipe + .getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class, + matchItemAndFluid(world, availableFluid)) + .filter(fr -> fr.getRequiredFluid() + .test(toFill)) + .orElseGet(() -> { + for (Recipe recipe : world.getRecipeManager() + .getRecipesFor(AllRecipeTypes.FILLING.getType(), WRAPPER, world)) { + FillingRecipe fr = (FillingRecipe) recipe; + FluidIngredient requiredFluid = fr.getRequiredFluid(); + if (requiredFluid.test(toFill)) + return fr; + } + return null; + }); + + if (fillingRecipe != null) { + List results = fillingRecipe.rollResults(); + availableFluid.shrink(requiredAmount); + stack.shrink(1); + return results.isEmpty() ? ItemStack.EMPTY : results.get(0); + } + + return GenericItemFilling.fillItem(world, requiredAmount, stack, availableFluid); + } + + private static Predicate matchItemAndFluid(Level world, FluidStack availableFluid) { + return r -> r.matches(WRAPPER, world) && r.getRequiredFluid() + .test(availableFluid); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlock.java b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlock.java new file mode 100644 index 0000000000..b861fbdb1d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlock.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.fluids.spout; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.ComparatorUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class SpoutBlock extends Block implements IWrenchable, IBE { + + public SpoutBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.SPOUT; + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); + AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { + return ComparatorUtil.levelOfSmartFluidTank(worldIn, pos); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + public Class getBlockEntityClass() { + return SpoutBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SPOUT.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java new file mode 100644 index 0000000000..74847c093c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java @@ -0,0 +1,258 @@ +package com.simibubi.create.content.fluids.spout; + +import static com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult.HOLD; +import static com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult.PASS; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.AllItems; +import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.fluids.FluidFX; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.fluid.FluidHelper; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; + +public class SpoutBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + public static final int FILLING_TIME = 20; + protected BeltProcessingBehaviour beltProcessing; + + public int processingTicks; + public boolean sendSplash; + public BlockSpoutingBehaviour customProcess; + + SmartFluidTankBehaviour tank; + + private boolean createdSweetRoll, createdHoneyApple, createdChocolateBerries; + + public SpoutBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + processingTicks = -1; + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().expandTowards(0, -2, 0); + } + + @Override + public void addBehaviours(List behaviours) { + tank = SmartFluidTankBehaviour.single(this, 1000); + behaviours.add(tank); + + beltProcessing = new BeltProcessingBehaviour(this).whenItemEnters(this::onItemReceived) + .whileItemHeld(this::whenItemHeld); + behaviours.add(beltProcessing); + + registerAwardables(behaviours, AllAdvancements.SPOUT, AllAdvancements.FOODS); + } + + protected ProcessingResult onItemReceived(TransportedItemStack transported, + TransportedItemStackHandlerBehaviour handler) { + if (handler.blockEntity.isVirtual()) + return PASS; + if (!FillingBySpout.canItemBeFilled(level, transported.stack)) + return PASS; + if (tank.isEmpty()) + return HOLD; + if (FillingBySpout.getRequiredAmountForItem(level, transported.stack, getCurrentFluidInTank()) == -1) + return PASS; + return HOLD; + } + + protected ProcessingResult whenItemHeld(TransportedItemStack transported, + TransportedItemStackHandlerBehaviour handler) { + if (processingTicks != -1 && processingTicks != 5) + return HOLD; + if (!FillingBySpout.canItemBeFilled(level, transported.stack)) + return PASS; + if (tank.isEmpty()) + return HOLD; + FluidStack fluid = getCurrentFluidInTank(); + int requiredAmountForItem = FillingBySpout.getRequiredAmountForItem(level, transported.stack, fluid.copy()); + if (requiredAmountForItem == -1) + return PASS; + if (requiredAmountForItem > fluid.getAmount()) + return HOLD; + + if (processingTicks == -1) { + processingTicks = FILLING_TIME; + notifyUpdate(); + return HOLD; + } + + // Process finished + ItemStack out = FillingBySpout.fillItem(level, requiredAmountForItem, transported.stack, fluid); + if (!out.isEmpty()) { + List outList = new ArrayList<>(); + TransportedItemStack held = null; + TransportedItemStack result = transported.copy(); + result.stack = out; + if (!transported.stack.isEmpty()) + held = transported.copy(); + outList.add(result); + handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(outList, held)); + } + + award(AllAdvancements.SPOUT); + if (trackFoods()) { + createdChocolateBerries |= AllItems.CHOCOLATE_BERRIES.isIn(out); + createdHoneyApple |= AllItems.HONEYED_APPLE.isIn(out); + createdSweetRoll |= AllItems.SWEET_ROLL.isIn(out); + if (createdChocolateBerries && createdHoneyApple && createdSweetRoll) + award(AllAdvancements.FOODS); + } + + tank.getPrimaryHandler() + .setFluid(fluid); + sendSplash = true; + notifyUpdate(); + return HOLD; + } + + private FluidStack getCurrentFluidInTank() { + return tank.getPrimaryHandler() + .getFluid(); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + + compound.putInt("ProcessingTicks", processingTicks); + if (sendSplash && clientPacket) { + compound.putBoolean("Splash", true); + sendSplash = false; + } + + if (!trackFoods()) + return; + if (createdChocolateBerries) + NBTHelper.putMarker(compound, "ChocolateBerries"); + if (createdHoneyApple) + NBTHelper.putMarker(compound, "HoneyApple"); + if (createdSweetRoll) + NBTHelper.putMarker(compound, "SweetRoll"); + } + + private boolean trackFoods() { + return getBehaviour(AdvancementBehaviour.TYPE).isOwnerPresent(); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + processingTicks = compound.getInt("ProcessingTicks"); + + createdChocolateBerries = compound.contains("ChocolateBerries"); + createdHoneyApple = compound.contains("HoneyApple"); + createdSweetRoll = compound.contains("SweetRoll"); + + if (!clientPacket) + return; + if (compound.contains("Splash")) + spawnSplash(tank.getPrimaryTank() + .getRenderedFluid()); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && side != Direction.DOWN) + return tank.getCapability() + .cast(); + return super.getCapability(cap, side); + } + + public void tick() { + super.tick(); + + FluidStack currentFluidInTank = getCurrentFluidInTank(); + if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) { + BlockSpoutingBehaviour.forEach(behaviour -> { + if (customProcess != null) + return; + if (behaviour.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, true) > 0) { + processingTicks = FILLING_TIME; + customProcess = behaviour; + notifyUpdate(); + } + }); + } + + if (processingTicks >= 0) { + processingTicks--; + if (processingTicks == 5 && customProcess != null) { + int fillBlock = customProcess.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, false); + customProcess = null; + if (fillBlock > 0) { + tank.getPrimaryHandler() + .setFluid(FluidHelper.copyStackWithAmount(currentFluidInTank, + currentFluidInTank.getAmount() - fillBlock)); + sendSplash = true; + notifyUpdate(); + } + } + } + + if (processingTicks >= 8 && level.isClientSide) + spawnProcessingParticles(tank.getPrimaryTank() + .getRenderedFluid()); + } + + protected void spawnProcessingParticles(FluidStack fluid) { + if (isVirtual()) + return; + Vec3 vec = VecHelper.getCenterOf(worldPosition); + vec = vec.subtract(0, 8 / 16f, 0); + ParticleOptions particle = FluidFX.getFluidParticle(fluid); + level.addAlwaysVisibleParticle(particle, vec.x, vec.y, vec.z, 0, -.1f, 0); + } + + protected static int SPLASH_PARTICLE_COUNT = 20; + + protected void spawnSplash(FluidStack fluid) { + if (isVirtual()) + return; + Vec3 vec = VecHelper.getCenterOf(worldPosition); + vec = vec.subtract(0, 2 - 5 / 16f, 0); + ParticleOptions particle = FluidFX.getFluidParticle(fluid); + for (int i = 0; i < SPLASH_PARTICLE_COUNT; i++) { + Vec3 m = VecHelper.offsetRandomly(Vec3.ZERO, level.random, 0.125f); + m = new Vec3(m.x, Math.abs(m.y), m.z); + level.addAlwaysVisibleParticle(particle, vec.x, vec.y, vec.z, m.x, m.y, m.z); + } + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return containedFluidTooltip(tooltip, isPlayerSneaking, + getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } +} diff --git a/src/main/java/com/simibubi/create/content/fluids/spout/SpoutRenderer.java b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutRenderer.java new file mode 100644 index 0000000000..efc63e214a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutRenderer.java @@ -0,0 +1,94 @@ +package com.simibubi.create.content.fluids.spout; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.fluid.FluidRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.fluids.FluidStack; + +public class SpoutRenderer extends SafeBlockEntityRenderer { + + public SpoutRenderer(BlockEntityRendererProvider.Context context) { + } + + static final PartialModel[] BITS = + { AllPartialModels.SPOUT_TOP, AllPartialModels.SPOUT_MIDDLE, AllPartialModels.SPOUT_BOTTOM }; + + @Override + protected void renderSafe(SpoutBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + SmartFluidTankBehaviour tank = be.tank; + if (tank == null) + return; + + TankSegment primaryTank = tank.getPrimaryTank(); + FluidStack fluidStack = primaryTank.getRenderedFluid(); + float level = primaryTank.getFluidLevel() + .getValue(partialTicks); + + if (!fluidStack.isEmpty() && level != 0) { + boolean top = fluidStack.getFluid() + .getAttributes() + .isLighterThanAir(); + + level = Math.max(level, 0.175f); + float min = 2.5f / 16f; + float max = min + (11 / 16f); + float yOffset = (11 / 16f) * level; + + ms.pushPose(); + if (!top) ms.translate(0, yOffset, 0); + else ms.translate(0, max - min, 0); + + FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), + min, min - yOffset, min, + max, min, max, + buffer, ms, light, false); + + ms.popPose(); + } + + int processingTicks = be.processingTicks; + float processingPT = processingTicks - partialTicks; + float processingProgress = 1 - (processingPT - 5) / 10; + processingProgress = Mth.clamp(processingProgress, 0, 1); + float radius = 0; + + if (processingTicks != -1) { + radius = (float) (Math.pow(((2 * processingProgress) - 1), 2) - 1); + AABB bb = new AABB(0.5, .5, 0.5, 0.5, -1.2, 0.5).inflate(radius / 32f); + FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), (float) bb.minX, (float) bb.minY, (float) bb.minZ, + (float) bb.maxX, (float) bb.maxY, (float) bb.maxZ, buffer, ms, light, true); + } + + float squeeze = radius; + if (processingPT < 0) + squeeze = 0; + else if (processingPT < 2) + squeeze = Mth.lerp(processingPT / 2f, 0, -1); + else if (processingPT < 10) + squeeze = -1; + + ms.pushPose(); + for (PartialModel bit : BITS) { + CachedPartialBuffers.partial(bit, be.getBlockState()) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + ms.translate(0, -3 * squeeze / 32f, 0); + } + ms.popPose(); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerData.java b/src/main/java/com/simibubi/create/content/fluids/tank/BoilerData.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerData.java rename to src/main/java/com/simibubi/create/content/fluids/tank/BoilerData.java index c999da2449..30531e74a1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerData.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/BoilerData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; import java.util.Arrays; import java.util.HashSet; @@ -9,13 +9,13 @@ import org.jetbrains.annotations.NotNull; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.steam.SteamEngineBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleTileEntity; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlockEntity; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.kinetics.BlockStressValues; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineBlock; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.BlockStressValues; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.utility.CreateLang; @@ -66,7 +66,7 @@ public class BoilerData { public LerpedFloat gauge = LerpedFloat.linear(); - public void tick(FluidTankTileEntity controller) { + public void tick(FluidTankBlockEntity controller) { if (!isActive()) return; if (controller.getLevel().isClientSide) { @@ -97,7 +97,7 @@ public class BoilerData { waterSupply = Math.max(i, waterSupply); } - if (controller instanceof CreativeFluidTankTileEntity) + if (controller instanceof CreativeFluidTankBlockEntity) waterSupply = waterSupplyPerLevel * 20; if (getActualHeat(controller.getTotalTankSize()) == 18) @@ -171,6 +171,22 @@ public class BoilerData { tooltip.add(Components.immutableEmpty()); + if (attachedEngines > 0 && maxHeatForSize > 0 && maxHeatForWater == 0 && (passiveHeat ? 1 : activeHeat) > 0) { + CreateLang.translate("boiler.water_input_rate") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + CreateLang.number(waterSupply) + .style(ChatFormatting.BLUE) + .add(CreateLang.translate("generic.unit.millibuckets")) + .add(CreateLang.text(" / ") + .style(ChatFormatting.GRAY)) + .add(CreateLang.translate("boiler.per_tick", CreateLang.number(waterSupplyPerLevel) + .add(CreateLang.translate("generic.unit.millibuckets"))) + .style(ChatFormatting.DARK_GRAY)) + .forGoggles(tooltip, 1); + return true; + } + CreateLang.translate("tooltip.capacityProvided") .style(ChatFormatting.GRAY) .forGoggles(tooltip); @@ -250,10 +266,11 @@ public class BoilerData { } private MutableComponent bars(int level, ChatFormatting format) { - return Components.literal(Strings.repeat('|', level)).withStyle(format); + return Components.literal(Strings.repeat('|', level)) + .withStyle(format); } - public boolean evaluate(FluidTankTileEntity controller) { + public boolean evaluate(FluidTankBlockEntity controller) { BlockPos controllerPos = controller.getBlockPos(); Level level = controller.getLevel(); int prevEngines = attachedEngines; @@ -287,7 +304,7 @@ public class BoilerData { return prevEngines != attachedEngines || prevWhistles != attachedWhistles; } - public void checkPipeOrganAdvancement(FluidTankTileEntity controller) { + public void checkPipeOrganAdvancement(FluidTankBlockEntity controller) { if (!controller.getBehaviour(AdvancementBehaviour.TYPE) .isOwnerPresent()) return; @@ -310,8 +327,8 @@ public class BoilerData { if (AllBlocks.STEAM_WHISTLE.has(attachedState) && WhistleBlock.getAttachedDirection(attachedState) .getOpposite() == d) { - if (level.getBlockEntity(attachedPos)instanceof WhistleTileEntity wte) - whistlePitches.add(wte.getPitchId()); + if (level.getBlockEntity(attachedPos) instanceof WhistleBlockEntity wbe) + whistlePitches.add(wbe.getPitchId()); } } } @@ -322,7 +339,7 @@ public class BoilerData { controller.award(AllAdvancements.PIPE_ORGAN); } - public boolean updateTemperature(FluidTankTileEntity controller) { + public boolean updateTemperature(FluidTankBlockEntity controller) { BlockPos controllerPos = controller.getBlockPos(); Level level = controller.getLevel(); needsHeatLevelUpdate = false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerHeaters.java b/src/main/java/com/simibubi/create/content/fluids/tank/BoilerHeaters.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerHeaters.java rename to src/main/java/com/simibubi/create/content/fluids/tank/BoilerHeaters.java index 12bde6e818..7e54584251 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/BoilerHeaters.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/BoilerHeaters.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; import java.util.ArrayList; import java.util.List; @@ -7,9 +7,9 @@ import org.jetbrains.annotations.Nullable; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.foundation.utility.CreateRegistry; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.utility.AttachedRegistry; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; @@ -17,10 +17,9 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.IRegistryDelegate; public class BoilerHeaters { - private static final CreateRegistry BLOCK_HEATERS = new CreateRegistry<>(ForgeRegistries.BLOCKS); + private static final AttachedRegistry BLOCK_HEATERS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); private static final List GLOBAL_HEATERS = new ArrayList<>(); public static void registerHeater(ResourceLocation block, Heater heater) { @@ -31,11 +30,6 @@ public class BoilerHeaters { BLOCK_HEATERS.register(block, heater); } - @Deprecated(forRemoval = true) - public static void registerHeater(IRegistryDelegate block, Heater heater) { - registerHeater(block.name(), heater); - } - public static void registerHeaterProvider(HeaterProvider provider) { GLOBAL_HEATERS.add(provider); } diff --git a/src/main/java/com/simibubi/create/content/fluids/tank/CreativeFluidTankBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/tank/CreativeFluidTankBlockEntity.java new file mode 100644 index 0000000000..e0c5a55dc4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/tank/CreativeFluidTankBlockEntity.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.fluids.tank; + +import java.util.List; +import java.util.function.Consumer; + +import com.simibubi.create.foundation.fluid.SmartFluidTank; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.FluidStack; + +public class CreativeFluidTankBlockEntity extends FluidTankBlockEntity { + + public CreativeFluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected SmartFluidTank createInventory() { + return new CreativeSmartFluidTank(getCapacityMultiplier(), this::onFluidStackChanged); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return false; + } + + public static class CreativeSmartFluidTank extends SmartFluidTank { + + public CreativeSmartFluidTank(int capacity, Consumer updateCallback) { + super(capacity, updateCallback); + } + + @Override + public int getFluidAmount() { + return getFluid().isEmpty() ? 0 : getTankCapacity(0); + } + + public void setContainedFluid(FluidStack fluidStack) { + fluid = fluidStack.copy(); + if (!fluidStack.isEmpty()) + fluid.setAmount(getTankCapacity(0)); + onContentsChanged(); + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + return resource.getAmount(); + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction action) { + return super.drain(resource, FluidAction.SIMULATE); + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + return super.drain(maxDrain, FluidAction.SIMULATE); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankBlock.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java rename to src/main/java/com/simibubi/create/content/fluids/tank/FluidTankBlock.java index c76f4fb391..40d7ca62ca 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankBlock.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankBlock.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; -import com.simibubi.create.AllTileEntities; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.api.connectivity.ConnectivityHandler; -import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity.CreativeSmartFluidTank; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.fluids.transfer.GenericItemFilling; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.ComparatorUtil; import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidHelper.FluidExchange; -import com.simibubi.create.foundation.tileEntity.ComparatorUtil; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.core.BlockPos; @@ -57,7 +57,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; -public class FluidTankBlock extends Block implements IWrenchable, ITE { +public class FluidTankBlock extends Block implements IWrenchable, IBE { public static final BooleanProperty TOP = BooleanProperty.create("top"); public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom"); @@ -97,7 +97,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE tankCapability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + LazyOptional tankCapability = be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); if (!tankCapability.isPresent()) return InteractionResult.PASS; IFluidHandler fluidTank = tankCapability.orElse(null); FluidStack prevFluidInTank = fluidTank.getFluidInTank(0) .copy(); - if (FluidHelper.tryEmptyItemIntoTE(world, player, hand, heldItem, te)) + if (FluidHelper.tryEmptyItemIntoBE(world, player, hand, heldItem, be)) exchange = FluidExchange.ITEM_TO_TANK; - else if (FluidHelper.tryFillItemFromTE(world, player, hand, heldItem, te)) + else if (FluidHelper.tryFillItemFromBE(world, player, hand, heldItem, be)) exchange = FluidExchange.TANK_TO_ITEM; if (exchange == null) { - if (EmptyingByBasin.canItemBeEmptied(world, heldItem) + if (GenericItemEmptying.canItemBeEmptied(world, heldItem) || GenericItemFilling.canItemBeFilled(world, heldItem)) return InteractionResult.SUCCESS; return InteractionResult.PASS; @@ -187,7 +187,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE getTileEntityClass() { - return FluidTankTileEntity.class; + public Class getBlockEntityClass() { + return FluidTankBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return creative ? AllTileEntities.CREATIVE_FLUID_TANK.get() : AllTileEntities.FLUID_TANK.get(); + public BlockEntityType getBlockEntityType() { + return creative ? AllBlockEntityTypes.CREATIVE_FLUID_TANK.get() : AllBlockEntityTypes.FLUID_TANK.get(); } @Override @@ -355,8 +355,8 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE ComparatorUtil.fractionToRedstoneLevel(te.getFillState())) + return getBlockEntityOptional(worldIn, pos).map(FluidTankBlockEntity::getControllerBE) + .map(be -> ComparatorUtil.fractionToRedstoneLevel(be.getFillState())) .orElse(0); } @@ -364,13 +364,13 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE fluidCapability; + protected boolean forceFluidLevelUpdate; + protected FluidTank tankInventory; + protected BlockPos controller; + protected BlockPos lastKnownPos; + protected boolean updateConnectivity; + protected boolean window; + protected int luminosity; + protected int width; + protected int height; + + public BoilerData boiler; + + private static final int SYNC_RATE = 8; + protected int syncCooldown; + protected boolean queuedSync; + + // For rendering purposes only + private LerpedFloat fluidLevel; + + public FluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + tankInventory = createInventory(); + fluidCapability = LazyOptional.of(() -> tankInventory); + forceFluidLevelUpdate = true; + updateConnectivity = false; + window = true; + height = 1; + width = 1; + boiler = new BoilerData(); + refreshCapability(); + } + + protected SmartFluidTank createInventory() { + return new SmartFluidTank(getCapacityMultiplier(), this::onFluidStackChanged); + } + + protected void updateConnectivity() { + updateConnectivity = false; + if (level.isClientSide) + return; + if (!isController()) + return; + ConnectivityHandler.formMulti(this); + } + + @Override + public void tick() { + super.tick(); + if (syncCooldown > 0) { + syncCooldown--; + if (syncCooldown == 0 && queuedSync) + sendData(); + } + + if (lastKnownPos == null) + lastKnownPos = getBlockPos(); + else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) { + onPositionChanged(); + return; + } + + if (updateConnectivity) + updateConnectivity(); + if (fluidLevel != null) + fluidLevel.tickChaser(); + if (isController()) + boiler.tick(this); + } + + @Override + public BlockPos getLastKnownPos() { + return lastKnownPos; + } + + @Override + public boolean isController() { + return controller == null || worldPosition.getX() == controller.getX() + && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); + } + + @Override + public void initialize() { + super.initialize(); + sendData(); + if (level.isClientSide) + invalidateRenderBoundingBox(); + } + + private void onPositionChanged() { + removeController(true); + lastKnownPos = worldPosition; + } + + protected void onFluidStackChanged(FluidStack newFluidStack) { + if (!hasLevel()) + return; + + FluidAttributes attributes = newFluidStack.getFluid() + .getAttributes(); + int luminosity = (int) (attributes.getLuminosity(newFluidStack) / 1.2f); + boolean reversed = attributes.isLighterThanAir(); + int maxY = (int) ((getFillState() * height) + 1); + + for (int yOffset = 0; yOffset < height; yOffset++) { + boolean isBright = reversed ? (height - yOffset <= maxY) : (yOffset < maxY); + int actualLuminosity = isBright ? luminosity : luminosity > 0 ? 1 : 0; + + for (int xOffset = 0; xOffset < width; xOffset++) { + for (int zOffset = 0; zOffset < width; zOffset++) { + BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset); + FluidTankBlockEntity tankAt = ConnectivityHandler.partAt(getType(), level, pos); + if (tankAt == null) + continue; + level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState() + .getBlock()); + if (tankAt.luminosity == actualLuminosity) + continue; + tankAt.setLuminosity(actualLuminosity); + } + } + } + + if (!level.isClientSide) { + setChanged(); + sendData(); + } + + if (isVirtual()) { + if (fluidLevel == null) + fluidLevel = LerpedFloat.linear() + .startWithValue(getFillState()); + fluidLevel.chase(getFillState(), .5f, Chaser.EXP); + } + } + + protected void setLuminosity(int luminosity) { + if (level.isClientSide) + return; + if (this.luminosity == luminosity) + return; + this.luminosity = luminosity; + sendData(); + } + + @SuppressWarnings("unchecked") + @Override + public FluidTankBlockEntity getControllerBE() { + if (isController()) + return this; + BlockEntity blockEntity = level.getBlockEntity(controller); + if (blockEntity instanceof FluidTankBlockEntity) + return (FluidTankBlockEntity) blockEntity; + return null; + } + + public void applyFluidTankSize(int blocks) { + tankInventory.setCapacity(blocks * getCapacityMultiplier()); + int overflow = tankInventory.getFluidAmount() - tankInventory.getCapacity(); + if (overflow > 0) + tankInventory.drain(overflow, FluidAction.EXECUTE); + forceFluidLevelUpdate = true; + } + + public void removeController(boolean keepFluids) { + if (level.isClientSide) + return; + updateConnectivity = true; + if (!keepFluids) + applyFluidTankSize(1); + controller = null; + width = 1; + height = 1; + boiler.clear(); + onFluidStackChanged(tankInventory.getFluid()); + + BlockState state = getBlockState(); + if (FluidTankBlock.isTank(state)) { + state = state.setValue(FluidTankBlock.BOTTOM, true); + state = state.setValue(FluidTankBlock.TOP, true); + state = state.setValue(FluidTankBlock.SHAPE, window ? Shape.WINDOW : Shape.PLAIN); + getLevel().setBlock(worldPosition, state, 22); + } + + refreshCapability(); + setChanged(); + sendData(); + } + + public void toggleWindows() { + FluidTankBlockEntity be = getControllerBE(); + if (be == null) + return; + if (be.boiler.isActive()) + return; + be.setWindows(!be.window); + } + + public void updateBoilerTemperature() { + FluidTankBlockEntity be = getControllerBE(); + if (be == null) + return; + if (!be.boiler.isActive()) + return; + be.boiler.needsHeatLevelUpdate = true; + } + + public void sendDataImmediately() { + syncCooldown = 0; + queuedSync = false; + sendData(); + } + + @Override + public void sendData() { + if (syncCooldown > 0) { + queuedSync = true; + return; + } + super.sendData(); + queuedSync = false; + syncCooldown = SYNC_RATE; + } + + public void setWindows(boolean window) { + this.window = window; + for (int yOffset = 0; yOffset < height; yOffset++) { + for (int xOffset = 0; xOffset < width; xOffset++) { + for (int zOffset = 0; zOffset < width; zOffset++) { + + BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset); + BlockState blockState = level.getBlockState(pos); + if (!FluidTankBlock.isTank(blockState)) + continue; + + Shape shape = Shape.PLAIN; + if (window) { + // SIZE 1: Every tank has a window + if (width == 1) + shape = Shape.WINDOW; + // SIZE 2: Every tank has a corner window + if (width == 2) + shape = xOffset == 0 ? zOffset == 0 ? Shape.WINDOW_NW : Shape.WINDOW_SW + : zOffset == 0 ? Shape.WINDOW_NE : Shape.WINDOW_SE; + // SIZE 3: Tanks in the center have a window + if (width == 3 && abs(abs(xOffset) - abs(zOffset)) == 1) + shape = Shape.WINDOW; + } + + level.setBlock(pos, blockState.setValue(FluidTankBlock.SHAPE, shape), 22); + level.getChunkSource() + .getLightEngine() + .checkBlock(pos); + } + } + } + } + + public void updateBoilerState() { + if (!isController()) + return; + + boolean wasBoiler = boiler.isActive(); + boolean changed = boiler.evaluate(this); + + if (wasBoiler != boiler.isActive()) { + if (boiler.isActive()) + setWindows(false); + + for (int yOffset = 0; yOffset < height; yOffset++) + for (int xOffset = 0; xOffset < width; xOffset++) + for (int zOffset = 0; zOffset < width; zOffset++) + if (level.getBlockEntity( + worldPosition.offset(xOffset, yOffset, zOffset)) instanceof FluidTankBlockEntity fbe) + fbe.refreshCapability(); + } + + if (changed) { + notifyUpdate(); + boiler.checkPipeOrganAdvancement(this); + } + } + + @Override + public void setController(BlockPos controller) { + if (level.isClientSide && !isVirtual()) + return; + if (controller.equals(this.controller)) + return; + this.controller = controller; + refreshCapability(); + setChanged(); + sendData(); + } + + private void refreshCapability() { + LazyOptional oldCap = fluidCapability; + fluidCapability = LazyOptional.of(() -> handlerForCapability()); + oldCap.invalidate(); + } + + private IFluidHandler handlerForCapability() { + return isController() ? boiler.isActive() ? boiler.createHandler() : tankInventory + : getControllerBE() != null ? getControllerBE().handlerForCapability() : new FluidTank(0); + } + + @Override + public BlockPos getController() { + return isController() ? worldPosition : controller; + } + + @Override + protected AABB createRenderBoundingBox() { + if (isController()) + return super.createRenderBoundingBox().expandTowards(width - 1, height - 1, width - 1); + else + return super.createRenderBoundingBox(); + } + + @Nullable + public FluidTankBlockEntity getOtherFluidTankBlockEntity(Direction direction) { + BlockEntity otherBE = level.getBlockEntity(worldPosition.relative(direction)); + if (otherBE instanceof FluidTankBlockEntity) + return (FluidTankBlockEntity) otherBE; + return null; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + FluidTankBlockEntity controllerBE = getControllerBE(); + if (controllerBE == null) + return false; + if (controllerBE.boiler.addToGoggleTooltip(tooltip, isPlayerSneaking, controllerBE.getTotalTankSize())) + return true; + return containedFluidTooltip(tooltip, isPlayerSneaking, + controllerBE.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + + BlockPos controllerBefore = controller; + int prevSize = width; + int prevHeight = height; + int prevLum = luminosity; + + updateConnectivity = compound.contains("Uninitialized"); + luminosity = compound.getInt("Luminosity"); + controller = null; + lastKnownPos = null; + + if (compound.contains("LastKnownPos")) + lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos")); + if (compound.contains("Controller")) + controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); + + if (isController()) { + window = compound.getBoolean("Window"); + width = compound.getInt("Size"); + height = compound.getInt("Height"); + tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier()); + tankInventory.readFromNBT(compound.getCompound("TankContent")); + if (tankInventory.getSpace() < 0) + tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE); + } + + boiler.read(compound.getCompound("Boiler"), width * width * height); + + if (compound.contains("ForceFluidLevel") || fluidLevel == null) + fluidLevel = LerpedFloat.linear() + .startWithValue(getFillState()); + + if (!clientPacket) + return; + + boolean changeOfController = + controllerBefore == null ? controller != null : !controllerBefore.equals(controller); + if (changeOfController || prevSize != width || prevHeight != height) { + if (hasLevel()) + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + if (isController()) + tankInventory.setCapacity(getCapacityMultiplier() * getTotalTankSize()); + invalidateRenderBoundingBox(); + } + if (isController()) { + float fillState = getFillState(); + if (compound.contains("ForceFluidLevel") || fluidLevel == null) + fluidLevel = LerpedFloat.linear() + .startWithValue(fillState); + fluidLevel.chase(fillState, 0.5f, Chaser.EXP); + } + if (luminosity != prevLum && hasLevel()) + level.getChunkSource() + .getLightEngine() + .checkBlock(worldPosition); + + if (compound.contains("LazySync")) + fluidLevel.chase(fluidLevel.getChaseTarget(), 0.125f, Chaser.EXP); + } + + public float getFillState() { + return (float) tankInventory.getFluidAmount() / tankInventory.getCapacity(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (updateConnectivity) + compound.putBoolean("Uninitialized", true); + compound.put("Boiler", boiler.write()); + if (lastKnownPos != null) + compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos)); + if (!isController()) + compound.put("Controller", NbtUtils.writeBlockPos(controller)); + if (isController()) { + compound.putBoolean("Window", window); + compound.put("TankContent", tankInventory.writeToNBT(new CompoundTag())); + compound.putInt("Size", width); + compound.putInt("Height", height); + } + compound.putInt("Luminosity", luminosity); + super.write(compound, clientPacket); + + if (!clientPacket) + return; + if (forceFluidLevelUpdate) + compound.putBoolean("ForceFluidLevel", true); + if (queuedSync) + compound.putBoolean("LazySync", true); + forceFluidLevelUpdate = false; + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + if (!fluidCapability.isPresent()) + refreshCapability(); + if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + return fluidCapability.cast(); + return super.getCapability(cap, side); + } + + @Override + public void invalidate() { + super.invalidate(); + } + + @Override + public void addBehaviours(List behaviours) { + registerAwardables(behaviours, AllAdvancements.STEAM_ENGINE_MAXED, AllAdvancements.PIPE_ORGAN); + } + + public IFluidTank getTankInventory() { + return tankInventory; + } + + public int getTotalTankSize() { + return width * width * height; + } + + public static int getMaxSize() { + return MAX_SIZE; + } + + public static int getCapacityMultiplier() { + return AllConfigs.server().fluids.fluidTankCapacity.get() * 1000; + } + + public static int getMaxHeight() { + return AllConfigs.server().fluids.fluidTankMaxHeight.get(); + } + + public LerpedFloat getFluidLevel() { + return fluidLevel; + } + + public void setFluidLevel(LerpedFloat fluidLevel) { + this.fluidLevel = fluidLevel; + } + + @Override + public void preventConnectivityUpdate() { + updateConnectivity = false; + } + + @Override + public void notifyMultiUpdated() { + BlockState state = this.getBlockState(); + if (FluidTankBlock.isTank(state)) { // safety + state = state.setValue(FluidTankBlock.BOTTOM, getController().getY() == getBlockPos().getY()); + state = state.setValue(FluidTankBlock.TOP, getController().getY() + height - 1 == getBlockPos().getY()); + level.setBlock(getBlockPos(), state, 6); + } + if (isController()) + setWindows(window); + onFluidStackChanged(tankInventory.getFluid()); + updateBoilerState(); + setChanged(); + } + + @Override + public void setExtraData(@Nullable Object data) { + if (data instanceof Boolean) + window = (boolean) data; + } + + @Override + @Nullable + public Object getExtraData() { + return window; + } + + @Override + public Object modifyExtraData(Object data) { + if (data instanceof Boolean windows) { + windows |= window; + return windows; + } + return data; + } + + @Override + public Direction.Axis getMainConnectionAxis() { + return Direction.Axis.Y; + } + + @Override + public int getMaxLength(Direction.Axis longAxis, int width) { + if (longAxis == Direction.Axis.Y) + return getMaxHeight(); + return getMaxWidth(); + } + + @Override + public int getMaxWidth() { + return MAX_SIZE; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public void setHeight(int height) { + this.height = height; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public void setWidth(int width) { + this.width = width; + } + + @Override + public boolean hasTank() { + return true; + } + + @Override + public int getTankSize(int tank) { + return getCapacityMultiplier(); + } + + @Override + public void setTankSize(int tank, int blocks) { + applyFluidTankSize(blocks); + } + + @Override + public IFluidTank getTank(int tank) { + return tankInventory; + } + + @Override + public FluidStack getFluid(int tank) { + return tankInventory.getFluid() + .copy(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankCTBehaviour.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankCTBehaviour.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankCTBehaviour.java rename to src/main/java/com/simibubi/create/content/fluids/tank/FluidTankCTBehaviour.java index 845fecb94e..d197b6c97a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankCTBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankGenerator.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankGenerator.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankGenerator.java rename to src/main/java/com/simibubi/create/content/fluids/tank/FluidTankGenerator.java index fb366a8e99..183dff0deb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankGenerator.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankGenerator.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape; +import com.simibubi.create.content.fluids.tank.FluidTankBlock.Shape; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankItem.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankItem.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankItem.java rename to src/main/java/com/simibubi/create/content/fluids/tank/FluidTankItem.java index 22fb7387e9..b5df74db54 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankItem.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankItem.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.api.connectivity.ConnectivityHandler; import net.minecraft.core.BlockPos; @@ -49,7 +49,7 @@ public class FluidTankItem extends BlockItem { if (nbt.contains("TankContent")) { FluidStack fluid = FluidStack.loadFluidStackFromNBT(nbt.getCompound("TankContent")); if (!fluid.isEmpty()) { - fluid.setAmount(Math.min(FluidTankTileEntity.getCapacityMultiplier(), fluid.getAmount())); + fluid.setAmount(Math.min(FluidTankBlockEntity.getCapacityMultiplier(), fluid.getAmount())); nbt.put("TankContent", fluid.writeToNBT(new CompoundTag())); } } @@ -76,24 +76,24 @@ public class FluidTankItem extends BlockItem { if (!FluidTankBlock.isTank(placedOnState)) return; boolean creative = getBlock().equals(AllBlocks.CREATIVE_FLUID_TANK.get()); - FluidTankTileEntity tankAt = ConnectivityHandler.partAt( - creative ? AllTileEntities.CREATIVE_FLUID_TANK.get() : AllTileEntities.FLUID_TANK.get(), world, placedOnPos + FluidTankBlockEntity tankAt = ConnectivityHandler.partAt( + creative ? AllBlockEntityTypes.CREATIVE_FLUID_TANK.get() : AllBlockEntityTypes.FLUID_TANK.get(), world, placedOnPos ); if (tankAt == null) return; - FluidTankTileEntity controllerTE = tankAt.getControllerTE(); - if (controllerTE == null) + FluidTankBlockEntity controllerBE = tankAt.getControllerBE(); + if (controllerBE == null) return; - int width = controllerTE.width; + int width = controllerBE.width; if (width == 1) return; int tanksToPlace = 0; - BlockPos startPos = face == Direction.DOWN ? controllerTE.getBlockPos() + BlockPos startPos = face == Direction.DOWN ? controllerBE.getBlockPos() .below() - : controllerTE.getBlockPos() - .above(controllerTE.height); + : controllerBE.getBlockPos() + .above(controllerBE.height); if (startPos.getY() != pos.getY()) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankModel.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java rename to src/main/java/com/simibubi/create/content/fluids/tank/FluidTankModel.java index fe4285bfa8..32d95b9872 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankModel.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.tank; +package com.simibubi.create.content.fluids.tank; import java.util.ArrayList; import java.util.Arrays; @@ -42,11 +42,13 @@ public class FluidTankModel extends CTModel { } @Override - protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) { + protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, + IModelData blockEntityData) { + super.gatherModelData(builder, world, pos, state, blockEntityData); CullData cullData = new CullData(); for (Direction d : Iterate.horizontalDirections) cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d))); - return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData); + builder.withInitial(CULL_PROPERTY, cullData); } @Override @@ -65,7 +67,7 @@ public class FluidTankModel extends CTModel { return quads; } - private class CullData { + private static class CullData { boolean[] culledFaces; public CullData() { diff --git a/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankRenderer.java b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankRenderer.java new file mode 100644 index 0000000000..4b08035f57 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/tank/FluidTankRenderer.java @@ -0,0 +1,119 @@ +package com.simibubi.create.content.fluids.tank; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.fluid.FluidRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.templates.FluidTank; + +public class FluidTankRenderer extends SafeBlockEntityRenderer { + + public FluidTankRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(FluidTankBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (!be.isController()) + return; + if (!be.window) { + if (be.boiler.isActive()) + renderAsBoiler(be, partialTicks, ms, buffer, light, overlay); + return; + } + + LerpedFloat fluidLevel = be.getFluidLevel(); + if (fluidLevel == null) + return; + + float capHeight = 1 / 4f; + float tankHullWidth = 1 / 16f + 1 / 128f; + float minPuddleHeight = 1 / 16f; + float totalHeight = be.height - 2 * capHeight - minPuddleHeight; + + float level = fluidLevel.getValue(partialTicks); + if (level < 1 / (512f * totalHeight)) + return; + float clampedLevel = Mth.clamp(level * totalHeight, 0, totalHeight); + + FluidTank tank = be.tankInventory; + FluidStack fluidStack = tank.getFluid(); + + if (fluidStack.isEmpty()) + return; + + boolean top = fluidStack.getFluid() + .getAttributes() + .isLighterThanAir(); + + float xMin = tankHullWidth; + float xMax = xMin + be.width - 2 * tankHullWidth; + float yMin = totalHeight + capHeight + minPuddleHeight - clampedLevel; + float yMax = yMin + clampedLevel; + + if (top) { + yMin += totalHeight - clampedLevel; + yMax += totalHeight - clampedLevel; + } + + float zMin = tankHullWidth; + float zMax = zMin + be.width - 2 * tankHullWidth; + + ms.pushPose(); + ms.translate(0, clampedLevel - totalHeight, 0); + FluidRenderer.renderFluidBox(fluidStack.getFluid(), fluidStack.getAmount(), xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false); + ms.popPose(); + } + + protected void renderAsBoiler(FluidTankBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + ms.pushPose(); + TransformStack msr = TransformStack.cast(ms); + msr.translate(be.width / 2f, 0.5, be.width / 2f); + + float dialPivot = 5.75f / 16; + float progress = be.boiler.gauge.getValue(partialTicks); + + for (Direction d : Iterate.horizontalDirections) { + ms.pushPose(); + CachedPartialBuffers.partial(AllPartialModels.BOILER_GAUGE, blockState) + .rotateY(d.toYRot()) + .unCentre() + .translate(be.width / 2f - 6 / 16f, 0, 0) + .light(light) + .renderInto(ms, vb); + CachedPartialBuffers.partial(AllPartialModels.BOILER_GAUGE_DIAL, blockState) + .rotateY(d.toYRot()) + .unCentre() + .translate(be.width / 2f - 6 / 16f, 0, 0) + .translate(0, dialPivot, dialPivot) + .rotateX(-90 * progress) + .translate(0, -dialPivot, -dialPivot) + .light(light) + .renderInto(ms, vb); + ms.popPose(); + } + + ms.popPose(); + } + + @Override + public boolean shouldRenderOffScreen(FluidTankBlockEntity be) { + return be.isController(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java b/src/main/java/com/simibubi/create/content/fluids/transfer/EmptyingRecipe.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/EmptyingRecipe.java index 848d75fdeb..dbd492fd57 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/EmptyingRecipe.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/EmptyingRecipe.java @@ -1,7 +1,8 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.fluids.transfer; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; import net.minecraft.world.level.Level; import net.minecraftforge.fluids.FluidStack; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingRecipe.java b/src/main/java/com/simibubi/create/content/fluids/transfer/FillingRecipe.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingRecipe.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/FillingRecipe.java index cedd8551ef..373aff64f2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FillingRecipe.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/FillingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.transfer; import java.util.List; import java.util.Set; @@ -7,9 +7,9 @@ import java.util.function.Supplier; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.compat.jei.category.sequencedAssembly.SequencedAssemblySubCategory; -import com.simibubi.create.content.contraptions.itemAssembly.IAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.sequenced.IAssemblyRecipe; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidDrainingBehaviour.java b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidDrainingBehaviour.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidDrainingBehaviour.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/FluidDrainingBehaviour.java index 6badb7b44c..130809d9ec 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidDrainingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidDrainingBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.transfer; import java.util.ArrayList; import java.util.HashSet; @@ -9,9 +9,9 @@ import java.util.Set; import javax.annotation.Nullable; import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import it.unimi.dsi.fastutil.PriorityQueue; import it.unimi.dsi.fastutil.objects.ObjectHeapPriorityQueue; @@ -47,8 +47,8 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { Set validationVisited; Set newValidationSet; - public FluidDrainingBehaviour(SmartTileEntity te) { - super(te); + public FluidDrainingBehaviour(SmartBlockEntity be) { + super(be); validationVisited = new HashSet<>(); validationFrontier = new ArrayList<>(); validationSet = new HashSet<>(); @@ -83,10 +83,21 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { if (validationFrontier.isEmpty() && !queue.isEmpty() && !simulate && revalidateIn == 0) revalidate(root); + if (infinite) { + blockEntity.award(AllAdvancements.HOSE_PULLEY); + if (FluidHelper.isLava(fluid)) + blockEntity.award(AllAdvancements.HOSE_PULLEY_LAVA); + + playEffect(world, root, fluid, true); + return true; + } + while (!queue.isEmpty()) { // Dont dequeue here, so we can decide not to dequeue a valid entry when // simulating - BlockPos currentPos = queue.first().pos; + BlockPos currentPos = queue.first() + .pos(); + BlockState blockState = world.getBlockState(currentPos); BlockState emptied = blockState; Fluid fluid = Fluids.EMPTY; @@ -102,7 +113,7 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { fluid = flowingFluid.getFluid(); else { affectedArea = BBHelper.encapsulate(affectedArea, BoundingBox.fromCorners(currentPos, currentPos)); - if (!tileEntity.isVirtual()) + if (!blockEntity.isVirtual()) world.setBlock(currentPos, emptied, 2 | 16); queue.dequeue(); if (queue.isEmpty()) { @@ -135,15 +146,9 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { return true; playEffect(world, currentPos, fluid, true); - tileEntity.award(AllAdvancements.HOSE_PULLEY); + blockEntity.award(AllAdvancements.HOSE_PULLEY); - if (infinite) { - if (FluidHelper.isLava(fluid)) - tileEntity.award(AllAdvancements.HOSE_PULLEY_LAVA); - return true; - } - - if (!tileEntity.isVirtual()) + if (!blockEntity.isVirtual()) world.setBlock(currentPos, emptied, 2 | 16); affectedArea = BBHelper.encapsulate(affectedArea, currentPos); @@ -176,12 +181,12 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { infinite = false; setValidationTimer(); frontier.add(new BlockPosEntry(root, 0)); - tileEntity.sendData(); + blockEntity.sendData(); } protected boolean checkValid(Level world, BlockPos root) { BlockPos currentPos = root; - for (int timeout = 1000; timeout > 0 && !root.equals(tileEntity.getBlockPos()); timeout--) { + for (int timeout = 1000; timeout > 0 && !root.equals(blockEntity.getBlockPos()); timeout--) { FluidBlockType canPullFluidsFrom = canPullFluidsFrom(world.getBlockState(currentPos), currentPos); if (canPullFluidsFrom == FluidBlockType.FLOWING) { for (Direction d : Iterate.directions) { @@ -262,42 +267,46 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { } private void continueSearch() { - fluid = search(fluid, frontier, visited, (e, d) -> { - queue.enqueue(new BlockPosEntry(e, d)); - validationSet.add(e); - }, false); + try { + fluid = search(fluid, frontier, visited, (e, d) -> { + queue.enqueue(new BlockPosEntry(e, d)); + validationSet.add(e); + }, false); + } catch (ChunkNotLoadedException e) { + blockEntity.sendData(); + frontier.clear(); + visited.clear(); + } - Level world = getWorld(); int maxBlocks = maxBlocks(); - if (visited.size() > maxBlocks && canDrainInfinitely(fluid)) { + if (visited.size() > maxBlocks && canDrainInfinitely(fluid) && !queue.isEmpty()) { infinite = true; - // Find first block with valid fluid - while (true) { - BlockPos first = queue.first().pos; - if (canPullFluidsFrom(world.getBlockState(first), first) != FluidBlockType.SOURCE) { - queue.dequeue(); - continue; - } - break; - } - BlockPos firstValid = queue.first().pos; + BlockPos firstValid = queue.first() + .pos(); frontier.clear(); visited.clear(); queue.clear(); queue.enqueue(new BlockPosEntry(firstValid, 0)); - tileEntity.sendData(); + blockEntity.sendData(); return; } if (!frontier.isEmpty()) return; - tileEntity.sendData(); + blockEntity.sendData(); visited.clear(); } private void continueValidation() { - search(fluid, validationFrontier, validationVisited, (e, d) -> newValidationSet.add(e), false); + try { + search(fluid, validationFrontier, validationVisited, (e, d) -> newValidationSet.add(e), false); + } catch (ChunkNotLoadedException e) { + validationFrontier.clear(); + validationVisited.clear(); + setLongValidationTimer(); + return; + } int maxBlocks = maxBlocks(); if (validationVisited.size() > maxBlocks && canDrainInfinitely(fluid)) { @@ -331,7 +340,7 @@ public class FluidDrainingBehaviour extends FluidManipulationBehaviour { newValidationSet.clear(); validationFrontier.clear(); validationVisited.clear(); - tileEntity.sendData(); + blockEntity.sendData(); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidFillingBehaviour.java b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidFillingBehaviour.java similarity index 87% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidFillingBehaviour.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/FluidFillingBehaviour.java index 8a0c1157bf..bafd3448a5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidFillingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidFillingBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.transfer; import java.util.ArrayList; import java.util.HashSet; @@ -7,10 +7,10 @@ import java.util.Objects; import java.util.Set; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.infrastructure.config.AllConfigs; import it.unimi.dsi.fastutil.PriorityQueue; import it.unimi.dsi.fastutil.objects.ObjectHeapPriorityQueue; @@ -49,8 +49,8 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { List infinityCheckFrontier; Set infinityCheckVisited; - public FluidFillingBehaviour(SmartTileEntity te) { - super(te); + public FluidFillingBehaviour(SmartBlockEntity be) { + super(be); queue = new ObjectHeapPriorityQueue<>((p, p2) -> -comparePositions(p, p2)); revalidateIn = 1; infinityCheckFrontier = new ArrayList<>(); @@ -71,15 +71,23 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { } protected void continueValidation(Fluid fluid) { - search(fluid, infinityCheckFrontier, infinityCheckVisited, - (p, d) -> infinityCheckFrontier.add(new BlockPosEntry(p, d)), true); + try { + search(fluid, infinityCheckFrontier, infinityCheckVisited, + (p, d) -> infinityCheckFrontier.add(new BlockPosEntry(p, d)), true); + } catch (ChunkNotLoadedException e) { + infinityCheckFrontier.clear(); + infinityCheckVisited.clear(); + setLongValidationTimer(); + return; + } + int maxBlocks = maxBlocks(); if (infinityCheckVisited.size() > maxBlocks && maxBlocks != -1 && !fillInfinite()) { if (!infinite) { reset(); infinite = true; - tileEntity.sendData(); + blockEntity.sendData(); } infinityCheckFrontier.clear(); setLongValidationTimer(); @@ -129,7 +137,7 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { int maxBlocks = maxBlocks(); boolean evaporate = world.dimensionType() .ultraWarm() && FluidHelper.isTag(fluid, FluidTags.WATER); - boolean canPlaceSources = AllConfigs.SERVER.fluids.placeFluidSourceBlocks.get(); + boolean canPlaceSources = AllConfigs.server().fluids.fluidFillPlaceFluidSourceBlocks.get(); if ((!fillInfinite() && infinite) || evaporate || !canPlaceSources) { FluidState fluidState = world.getFluidState(rootPos); @@ -147,14 +155,14 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { world.playSound(null, i, j, k, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); } else if (!canPlaceSources) - tileEntity.award(AllAdvancements.HOSE_PULLEY); + blockEntity.award(AllAdvancements.HOSE_PULLEY); return true; } boolean success = false; for (int i = 0; !success && !queue.isEmpty() && i < searchedPerTick; i++) { BlockPosEntry entry = queue.first(); - BlockPos currentPos = entry.pos; + BlockPos currentPos = entry.pos(); if (visited.contains(currentPos)) { queue.dequeue(); @@ -183,13 +191,13 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { BlockState blockState = world.getBlockState(currentPos); if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && fluid.isSame(Fluids.WATER)) { - if (!tileEntity.isVirtual()) + if (!blockEntity.isVirtual()) world.setBlock(currentPos, updatePostWaterlogging(blockState.setValue(BlockStateProperties.WATERLOGGED, true)), 2 | 16); } else { replaceBlock(world, currentPos, blockState); - if (!tileEntity.isVirtual()) + if (!blockEntity.isVirtual()) world.setBlock(currentPos, FluidHelper.convertToStill(fluid) .defaultFluidState() .createLegacyBlock(), 2 | 16); @@ -223,12 +231,12 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { SpaceType nextSpaceType = getAtPos(world, offsetPos, fluid); if (nextSpaceType != SpaceType.BLOCKING) - queue.enqueue(new BlockPosEntry(offsetPos, entry.distance + 1)); + queue.enqueue(new BlockPosEntry(offsetPos, entry.distance() + 1)); } } if (!simulate && success) - tileEntity.award(AllAdvancements.HOSE_PULLEY); + blockEntity.award(AllAdvancements.HOSE_PULLEY); return success; } @@ -238,7 +246,7 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { queue.enqueue(new BlockPosEntry(root, 0)); infinite = false; setValidationTimer(); - tileEntity.sendData(); + blockEntity.sendData(); } enum SpaceType { @@ -268,8 +276,8 @@ public class FluidFillingBehaviour extends FluidManipulationBehaviour { } protected void replaceBlock(Level world, BlockPos pos, BlockState state) { - BlockEntity tileentity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; - Block.dropResources(state, world, pos, tileentity); + BlockEntity blockEntity = state.hasBlockEntity() ? world.getBlockEntity(pos) : null; + Block.dropResources(state, world, pos, blockEntity); } // From FlowingFluidBlock#isBlocked diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidManipulationBehaviour.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/FluidManipulationBehaviour.java index d6709d48b3..96d8c16908 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidManipulationBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.transfer; import java.util.ArrayList; import java.util.HashSet; @@ -7,14 +7,15 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Predicate; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllTags.AllFluidTags; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -33,16 +34,13 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.fluids.FluidStack; -public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { +public abstract class FluidManipulationBehaviour extends BlockEntityBehaviour { - protected static class BlockPosEntry { - public BlockPos pos; - public int distance; + public static record BlockPosEntry(BlockPos pos, int distance) { + }; - public BlockPosEntry(BlockPos pos, int distance) { - this.pos = pos; - this.distance = distance; - } + public static class ChunkNotLoadedException extends Exception { + private static final long serialVersionUID = 1L; } BoundingBox affectedArea; @@ -51,21 +49,25 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { protected boolean counterpartActed; // Search - static final int searchedPerTick = 256; + static final int searchedPerTick = 1024; static final int validationTimerMin = 160; List frontier; Set visited; int revalidateIn; - public FluidManipulationBehaviour(SmartTileEntity te) { - super(te); + public FluidManipulationBehaviour(SmartBlockEntity be) { + super(be); setValidationTimer(); infinite = false; visited = new HashSet<>(); frontier = new ArrayList<>(); } + public boolean isInfinite() { + return infinite; + } + public void counterpartActed() { counterpartActed = true; } @@ -85,15 +87,15 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } protected int maxRange() { - return AllConfigs.SERVER.fluids.hosePulleyRange.get(); + return AllConfigs.server().fluids.hosePulleyRange.get(); } protected int maxBlocks() { - return AllConfigs.SERVER.fluids.hosePulleyBlockThreshold.get(); + return AllConfigs.server().fluids.hosePulleyBlockThreshold.get(); } protected boolean fillInfinite() { - return AllConfigs.SERVER.fluids.fillInfinite.get(); + return AllConfigs.server().fluids.fillInfinite.get(); } public void reset() { @@ -143,7 +145,7 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } protected Fluid search(Fluid fluid, List frontier, Set visited, - BiConsumer add, boolean searchDownward) { + BiConsumer add, boolean searchDownward) throws ChunkNotLoadedException { Level world = getWorld(); int maxBlocks = maxBlocks(); int maxRange = canDrainInfinitely(fluid) ? maxRange() : maxRange() / 2; @@ -158,6 +160,9 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { continue; visited.add(currentPos); + if (!world.isLoaded(currentPos)) + throw new ChunkNotLoadedException(); + FluidState fluidState = world.getFluidState(currentPos); if (fluidState.isEmpty()) continue; @@ -175,6 +180,8 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { continue; BlockPos offsetPos = currentPos.relative(side); + if (!world.isLoaded(offsetPos)) + throw new ChunkNotLoadedException(); if (visited.contains(offsetPos)) continue; if (offsetPos.distSqr(rootPos) > maxRangeSq) @@ -196,7 +203,10 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } protected void playEffect(Level world, BlockPos pos, Fluid fluid, boolean fillSound) { - BlockPos splooshPos = pos == null ? tileEntity.getBlockPos() : pos; + if (fluid == null) + return; + + BlockPos splooshPos = pos == null ? blockEntity.getBlockPos() : pos; SoundEvent soundevent = fillSound ? fluid.getAttributes() .getFillSound() @@ -215,12 +225,14 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { protected boolean canDrainInfinitely(Fluid fluid) { if (fluid == null) return false; - return maxBlocks() != -1 && AllConfigs.SERVER.fluids.bottomlessFluidMode.get() + return maxBlocks() != -1 && AllConfigs.server().fluids.bottomlessFluidMode.get() .test(fluid); } @Override public void write(CompoundTag nbt, boolean clientPacket) { + if (infinite) + NBTHelper.putMarker(nbt, "Infinite"); if (rootPos != null) nbt.put("LastPos", NbtUtils.writeBlockPos(rootPos)); if (affectedArea != null) { @@ -234,6 +246,7 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { @Override public void read(CompoundTag nbt, boolean clientPacket) { + infinite = nbt.contains("Infinite"); if (nbt.contains("LastPos")) rootPos = NbtUtils.readBlockPos(nbt.getCompound("LastPos")); if (nbt.contains("AffectedAreaFrom") && nbt.contains("AffectedAreaTo")) @@ -243,30 +256,21 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } public enum BottomlessFluidMode implements Predicate { - ALLOW_ALL { - @Override - public boolean test(Fluid fluid) { - return true; - } - }, - DENY_ALL { - @Override - public boolean test(Fluid fluid) { - return false; - } - }, - ALLOW_BY_TAG { - @Override - public boolean test(Fluid fluid) { - return AllFluidTags.BOTTOMLESS_ALLOW.matches(fluid); - } - }, - DENY_BY_TAG { - @Override - public boolean test(Fluid fluid) { - return !AllFluidTags.BOTTOMLESS_DENY.matches(fluid); - } - }; + ALLOW_ALL(fluid -> true), + DENY_ALL(fluid -> false), + ALLOW_BY_TAG(fluid -> AllFluidTags.BOTTOMLESS_ALLOW.matches(fluid)), + DENY_BY_TAG(fluid -> !AllFluidTags.BOTTOMLESS_DENY.matches(fluid)); + + private final Predicate predicate; + + BottomlessFluidMode(Predicate predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(Fluid fluid) { + return predicate.test(fluid); + } } } diff --git a/src/main/java/com/simibubi/create/content/fluids/transfer/FluidSplashPacket.java b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidSplashPacket.java new file mode 100644 index 0000000000..d4cd729451 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/FluidSplashPacket.java @@ -0,0 +1,47 @@ +package com.simibubi.create.content.fluids.transfer; + +import com.simibubi.create.content.fluids.FluidFX; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class FluidSplashPacket extends SimplePacketBase { + + private BlockPos pos; + private FluidStack fluid; + + public FluidSplashPacket(BlockPos pos, FluidStack fluid) { + this.pos = pos; + this.fluid = fluid; + } + + public FluidSplashPacket(FriendlyByteBuf buffer) { + pos = buffer.readBlockPos(); + fluid = buffer.readFluidStack(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBlockPos(pos); + buffer.writeFluidStack(fluid); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + if (Minecraft.getInstance().player.position() + .distanceTo(new Vec3(pos.getX(), pos.getY(), pos.getZ())) > 100) + return; + FluidFX.splash(pos, fluid); + })); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemEmptying.java b/src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemEmptying.java new file mode 100644 index 0000000000..cef5f75b78 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemEmptying.java @@ -0,0 +1,83 @@ +package com.simibubi.create.content.fluids.transfer; + +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; + +import net.createmod.catnip.utility.Pair; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.PotionItem; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.Level; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.fluids.capability.IFluidHandlerItem; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class GenericItemEmptying { + + private static final RecipeWrapper WRAPPER = new RecipeWrapper(new ItemStackHandler(1)); + + public static boolean canItemBeEmptied(Level world, ItemStack stack) { + if (stack.getItem() instanceof PotionItem) + return true; + + WRAPPER.setItem(0, stack); + if (AllRecipeTypes.EMPTYING.find(WRAPPER, world) + .isPresent()) + return true; + + LazyOptional capability = + stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); + IFluidHandlerItem tank = capability.orElse(null); + if (tank == null) + return false; + for (int i = 0; i < tank.getTanks(); i++) { + if (tank.getFluidInTank(i) + .getAmount() > 0) + return true; + } + return false; + } + + public static Pair emptyItem(Level world, ItemStack stack, boolean simulate) { + FluidStack resultingFluid = FluidStack.EMPTY; + ItemStack resultingItem = ItemStack.EMPTY; + + if (stack.getItem() instanceof PotionItem) + return PotionFluidHandler.emptyPotion(stack, simulate); + + WRAPPER.setItem(0, stack); + Optional> recipe = AllRecipeTypes.EMPTYING.find(WRAPPER, world); + if (recipe.isPresent()) { + EmptyingRecipe emptyingRecipe = (EmptyingRecipe) recipe.get(); + List results = emptyingRecipe.rollResults(); + if (!simulate) + stack.shrink(1); + resultingItem = results.isEmpty() ? ItemStack.EMPTY : results.get(0); + resultingFluid = emptyingRecipe.getResultingFluid(); + return Pair.of(resultingFluid, resultingItem); + } + + ItemStack split = stack.copy(); + split.setCount(1); + LazyOptional capability = + split.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); + IFluidHandlerItem tank = capability.orElse(null); + if (tank == null) + return Pair.of(resultingFluid, resultingItem); + resultingFluid = tank.drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE); + resultingItem = tank.getContainer() + .copy(); + if (!simulate) + stack.shrink(1); + + return Pair.of(resultingFluid, resultingItem); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/GenericItemFilling.java b/src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemFilling.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/fluids/actors/GenericItemFilling.java rename to src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemFilling.java index e6ce73c75a..4a7ad0580e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/GenericItemFilling.java +++ b/src/main/java/com/simibubi/create/content/fluids/transfer/GenericItemFilling.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.fluids.actors; +package com.simibubi.create.content.fluids.transfer; import com.simibubi.create.AllFluids; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; import com.simibubi.create.foundation.fluid.FluidHelper; import net.minecraft.world.item.BucketItem; diff --git a/src/main/java/com/simibubi/create/foundation/block/BlockStressDefaults.java b/src/main/java/com/simibubi/create/content/kinetics/BlockStressDefaults.java similarity index 97% rename from src/main/java/com/simibubi/create/foundation/block/BlockStressDefaults.java rename to src/main/java/com/simibubi/create/content/kinetics/BlockStressDefaults.java index a816ac8a9e..b6f5b0c934 100644 --- a/src/main/java/com/simibubi/create/foundation/block/BlockStressDefaults.java +++ b/src/main/java/com/simibubi/create/content/kinetics/BlockStressDefaults.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.block; +package com.simibubi.create.content.kinetics; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/simibubi/create/foundation/block/BlockStressValues.java b/src/main/java/com/simibubi/create/content/kinetics/BlockStressValues.java similarity index 89% rename from src/main/java/com/simibubi/create/foundation/block/BlockStressValues.java rename to src/main/java/com/simibubi/create/content/kinetics/BlockStressValues.java index c7f90c7195..e53596b3eb 100644 --- a/src/main/java/com/simibubi/create/foundation/block/BlockStressValues.java +++ b/src/main/java/com/simibubi/create/content/kinetics/BlockStressValues.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.block; +package com.simibubi.create.content.kinetics; import java.util.HashMap; import java.util.Map; @@ -73,6 +73,16 @@ public class BlockStressValues { return BlockStressDefaults.DEFAULT_CAPACITIES.containsKey(blockId); } + @Nullable + public static Couple getGeneratedRPM(Block block) { + ResourceLocation blockId = CatnipServices.REGISTRIES.getKeyOrThrow(block); + IStressValueProvider provider = getProvider(blockId.getNamespace()); + if (provider != null) { + return provider.getGeneratedRPM(block); + } + return null; + } + public interface IStressValueProvider { /** * Gets the stress impact of a block. diff --git a/src/main/java/com/simibubi/create/content/kinetics/KineticDebugger.java b/src/main/java/com/simibubi/create/content/kinetics/KineticDebugger.java new file mode 100644 index 0000000000..d5f2d00c79 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/KineticDebugger.java @@ -0,0 +1,90 @@ +package com.simibubi.create.content.kinetics; + +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.render.SuperByteBufferCache; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class KineticDebugger { + + public static void tick() { + if (!isActive()) { + if (KineticBlockEntityRenderer.rainbowMode) { + KineticBlockEntityRenderer.rainbowMode = false; + SuperByteBufferCache.getInstance().invalidate(); + } + return; + } + + KineticBlockEntity be = getSelectedBE(); + if (be == null) + return; + + Level world = Minecraft.getInstance().level; + BlockPos toOutline = be.hasSource() ? be.source : be.getBlockPos(); + BlockState state = be.getBlockState(); + VoxelShape shape = world.getBlockState(toOutline) + .getBlockSupportShape(world, toOutline); + + if (be.getTheoreticalSpeed() != 0 && !shape.isEmpty()) + CatnipClient.OUTLINER.chaseAABB("kineticSource", shape.bounds() + .move(toOutline)) + .lineWidth(1 / 16f) + .colored(be.hasSource() ? Color.generateFromLong(be.network).getRGB() : 0xffcc00); + + if (state.getBlock() instanceof IRotate) { + Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); + Vec3 vec = Vec3.atLowerCornerOf(Direction.get(AxisDirection.POSITIVE, axis) + .getNormal()); + Vec3 center = VecHelper.getCenterOf(be.getBlockPos()); + CatnipClient.OUTLINER.showLine("rotationAxis", center.add(vec), center.subtract(vec)) + .lineWidth(1 / 16f); + } + + } + + public static boolean isActive() { + return isF3DebugModeActive() && AllConfigs.client().rainbowDebug.get(); + } + + public static boolean isF3DebugModeActive() { + return Minecraft.getInstance().options.renderDebug; + } + + public static KineticBlockEntity getSelectedBE() { + HitResult obj = Minecraft.getInstance().hitResult; + ClientLevel world = Minecraft.getInstance().level; + if (obj == null) + return null; + if (world == null) + return null; + if (!(obj instanceof BlockHitResult)) + return null; + + BlockHitResult ray = (BlockHitResult) obj; + BlockEntity be = world.getBlockEntity(ray.getBlockPos()); + if (!(be instanceof KineticBlockEntity)) + return null; + + return (KineticBlockEntity) be; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/KineticNetwork.java b/src/main/java/com/simibubi/create/content/kinetics/KineticNetwork.java new file mode 100644 index 0000000000..b1d154607d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/KineticNetwork.java @@ -0,0 +1,181 @@ +package com.simibubi.create.content.kinetics; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +public class KineticNetwork { + + public Long id; + public boolean initialized; + public Map sources; + public Map members; + + private float currentCapacity; + private float currentStress; + private float unloadedCapacity; + private float unloadedStress; + private int unloadedMembers; + + public KineticNetwork() { + sources = new HashMap<>(); + members = new HashMap<>(); + } + + public void initFromTE(float maxStress, float currentStress, int members) { + unloadedCapacity = maxStress; + unloadedStress = currentStress; + unloadedMembers = members; + initialized = true; + updateStress(); + updateCapacity(); + } + + public void addSilently(KineticBlockEntity be, float lastCapacity, float lastStress) { + if (members.containsKey(be)) + return; + if (be.isSource()) { + unloadedCapacity -= lastCapacity * getStressMultiplierForSpeed(be.getGeneratedSpeed()); + float addedStressCapacity = be.calculateAddedStressCapacity(); + sources.put(be, addedStressCapacity); + } + + unloadedStress -= lastStress * getStressMultiplierForSpeed(be.getTheoreticalSpeed()); + float stressApplied = be.calculateStressApplied(); + members.put(be, stressApplied); + + unloadedMembers--; + if (unloadedMembers < 0) + unloadedMembers = 0; + if (unloadedCapacity < 0) + unloadedCapacity = 0; + if (unloadedStress < 0) + unloadedStress = 0; + } + + public void add(KineticBlockEntity be) { + if (members.containsKey(be)) + return; + if (be.isSource()) + sources.put(be, be.calculateAddedStressCapacity()); + members.put(be, be.calculateStressApplied()); + updateFromNetwork(be); + be.networkDirty = true; + } + + public void updateCapacityFor(KineticBlockEntity be, float capacity) { + sources.put(be, capacity); + updateCapacity(); + } + + public void updateStressFor(KineticBlockEntity be, float stress) { + members.put(be, stress); + updateStress(); + } + + public void remove(KineticBlockEntity be) { + if (!members.containsKey(be)) + return; + if (be.isSource()) + sources.remove(be); + members.remove(be); + be.updateFromNetwork(0, 0, 0); + + if (members.isEmpty()) { + TorquePropagator.networks.get(be.getLevel()) + .remove(this.id); + return; + } + + members.keySet() + .stream() + .findFirst() + .map(member -> member.networkDirty = true); + } + + public void sync() { + for (KineticBlockEntity be : members.keySet()) + updateFromNetwork(be); + } + + private void updateFromNetwork(KineticBlockEntity be) { + be.updateFromNetwork(currentCapacity, currentStress, getSize()); + } + + public void updateCapacity() { + float newMaxStress = calculateCapacity(); + if (currentCapacity != newMaxStress) { + currentCapacity = newMaxStress; + sync(); + } + } + + public void updateStress() { + float newStress = calculateStress(); + if (currentStress != newStress) { + currentStress = newStress; + sync(); + } + } + + public void updateNetwork() { + float newStress = calculateStress(); + float newMaxStress = calculateCapacity(); + if (currentStress != newStress || currentCapacity != newMaxStress) { + currentStress = newStress; + currentCapacity = newMaxStress; + sync(); + } + } + + public float calculateCapacity() { + float presentCapacity = 0; + for (Iterator iterator = sources.keySet() + .iterator(); iterator.hasNext();) { + KineticBlockEntity be = iterator.next(); + if (be.getLevel() + .getBlockEntity(be.getBlockPos()) != be) { + iterator.remove(); + continue; + } + presentCapacity += getActualCapacityOf(be); + } + float newMaxStress = presentCapacity + unloadedCapacity; + return newMaxStress; + } + + public float calculateStress() { + float presentStress = 0; + for (Iterator iterator = members.keySet() + .iterator(); iterator.hasNext();) { + KineticBlockEntity be = iterator.next(); + if (be.getLevel() + .getBlockEntity(be.getBlockPos()) != be) { + iterator.remove(); + continue; + } + presentStress += getActualStressOf(be); + } + float newStress = presentStress + unloadedStress; + return newStress; + } + + public float getActualCapacityOf(KineticBlockEntity be) { + return sources.get(be) * getStressMultiplierForSpeed(be.getGeneratedSpeed()); + } + + public float getActualStressOf(KineticBlockEntity be) { + return members.get(be) * getStressMultiplierForSpeed(be.getTheoreticalSpeed()); + } + + private static float getStressMultiplierForSpeed(float speed) { + return Math.abs(speed); + } + + public int getSize() { + return unloadedMembers + members.size(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/RotationPropagator.java b/src/main/java/com/simibubi/create/content/kinetics/RotationPropagator.java new file mode 100644 index 0000000000..366a138eaf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/RotationPropagator.java @@ -0,0 +1,448 @@ +package com.simibubi.create.content.kinetics; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS; + +import java.util.LinkedList; +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.DirectionalShaftHalvesBlockEntity; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.chainDrive.ChainDriveBlock; +import com.simibubi.create.content.kinetics.gearbox.GearboxBlockEntity; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlock; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity; +import com.simibubi.create.content.kinetics.transmission.SplitShaftBlockEntity; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + + +public class RotationPropagator { + + private static final int MAX_FLICKER_SCORE = 128; + + /** + * Determines the change in rotation between two attached kinetic entities. For + * instance, an axis connection returns 1 while a 1-to-1 gear connection + * reverses the rotation and therefore returns -1. + * + * @param from + * @param to + * @return + */ + private static float getRotationSpeedModifier(KineticBlockEntity from, KineticBlockEntity to) { + final BlockState stateFrom = from.getBlockState(); + final BlockState stateTo = to.getBlockState(); + + Block fromBlock = stateFrom.getBlock(); + Block toBlock = stateTo.getBlock(); + if (!(fromBlock instanceof IRotate && toBlock instanceof IRotate)) + return 0; + + final IRotate definitionFrom = (IRotate) fromBlock; + final IRotate definitionTo = (IRotate) toBlock; + final BlockPos diff = to.getBlockPos() + .subtract(from.getBlockPos()); + final Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); + final Level world = from.getLevel(); + + boolean alignedAxes = true; + for (Axis axis : Axis.values()) + if (axis != direction.getAxis()) + if (axis.choose(diff.getX(), diff.getY(), diff.getZ()) != 0) + alignedAxes = false; + + boolean connectedByAxis = + alignedAxes && definitionFrom.hasShaftTowards(world, from.getBlockPos(), stateFrom, direction) + && definitionTo.hasShaftTowards(world, to.getBlockPos(), stateTo, direction.getOpposite()); + + boolean connectedByGears = ICogWheel.isSmallCog(stateFrom) + && ICogWheel.isSmallCog(stateTo); + + float custom = from.propagateRotationTo(to, stateFrom, stateTo, diff, connectedByAxis, connectedByGears); + if (custom != 0) + return custom; + + // Axis <-> Axis + if (connectedByAxis) { + float axisModifier = getAxisModifier(to, direction.getOpposite()); + if (axisModifier != 0) + axisModifier = 1 / axisModifier; + return getAxisModifier(from, direction) * axisModifier; + } + + // Attached Encased Belts + if (fromBlock instanceof ChainDriveBlock && toBlock instanceof ChainDriveBlock) { + boolean connected = ChainDriveBlock.areBlocksConnected(stateFrom, stateTo, direction); + return connected ? ChainDriveBlock.getRotationSpeedModifier(from, to) : 0; + } + + // Large Gear <-> Large Gear + if (isLargeToLargeGear(stateFrom, stateTo, diff)) { + Axis sourceAxis = stateFrom.getValue(AXIS); + Axis targetAxis = stateTo.getValue(AXIS); + int sourceAxisDiff = sourceAxis.choose(diff.getX(), diff.getY(), diff.getZ()); + int targetAxisDiff = targetAxis.choose(diff.getX(), diff.getY(), diff.getZ()); + + return sourceAxisDiff > 0 ^ targetAxisDiff > 0 ? -1 : 1; + } + + // Gear <-> Large Gear + if (ICogWheel.isLargeCog(stateFrom) && ICogWheel.isSmallCog(stateTo)) + if (isLargeToSmallCog(stateFrom, stateTo, definitionTo, diff)) + return -2f; + if (ICogWheel.isLargeCog(stateTo) && ICogWheel.isSmallCog(stateFrom)) + if (isLargeToSmallCog(stateTo, stateFrom, definitionFrom, diff)) + return -.5f; + + // Gear <-> Gear + if (connectedByGears) { + if (diff.distManhattan(BlockPos.ZERO) != 1) + return 0; + if (ICogWheel.isLargeCog(stateTo)) + return 0; + if (direction.getAxis() == definitionFrom.getRotationAxis(stateFrom)) + return 0; + if (definitionFrom.getRotationAxis(stateFrom) == definitionTo.getRotationAxis(stateTo)) + return -1; + } + + return 0; + } + + private static float getConveyedSpeed(KineticBlockEntity from, KineticBlockEntity to) { + final BlockState stateFrom = from.getBlockState(); + final BlockState stateTo = to.getBlockState(); + + // Rotation Speed Controller <-> Large Gear + if (isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos() + .subtract(from.getBlockPos()))) + return SpeedControllerBlockEntity.getConveyedSpeed(from, to, true); + if (isLargeCogToSpeedController(stateTo, stateFrom, from.getBlockPos() + .subtract(to.getBlockPos()))) + return SpeedControllerBlockEntity.getConveyedSpeed(to, from, false); + + float rotationSpeedModifier = getRotationSpeedModifier(from, to); + return from.getTheoreticalSpeed() * rotationSpeedModifier; + } + + private static boolean isLargeToLargeGear(BlockState from, BlockState to, BlockPos diff) { + if (!ICogWheel.isLargeCog(from) || !ICogWheel.isLargeCog(to)) + return false; + Axis fromAxis = from.getValue(AXIS); + Axis toAxis = to.getValue(AXIS); + if (fromAxis == toAxis) + return false; + for (Axis axis : Axis.values()) { + int axisDiff = axis.choose(diff.getX(), diff.getY(), diff.getZ()); + if (axis == fromAxis || axis == toAxis) { + if (axisDiff == 0) + return false; + + } else if (axisDiff != 0) + return false; + } + return true; + } + + private static float getAxisModifier(KineticBlockEntity be, Direction direction) { + if (!(be.hasSource()||be.isSource()) || !(be instanceof DirectionalShaftHalvesBlockEntity)) + return 1; + Direction source = ((DirectionalShaftHalvesBlockEntity) be).getSourceFacing(); + + if (be instanceof GearboxBlockEntity) + return direction.getAxis() == source.getAxis() ? direction == source ? 1 : -1 + : direction.getAxisDirection() == source.getAxisDirection() ? -1 : 1; + + if (be instanceof SplitShaftBlockEntity) + return ((SplitShaftBlockEntity) be).getRotationSpeedModifier(direction); + + return 1; + } + + private static boolean isLargeToSmallCog(BlockState from, BlockState to, IRotate defTo, BlockPos diff) { + Axis axisFrom = from.getValue(AXIS); + if (axisFrom != defTo.getRotationAxis(to)) + return false; + if (axisFrom.choose(diff.getX(), diff.getY(), diff.getZ()) != 0) + return false; + for (Axis axis : Axis.values()) { + if (axis == axisFrom) + continue; + if (Math.abs(axis.choose(diff.getX(), diff.getY(), diff.getZ())) != 1) + return false; + } + return true; + } + + private static boolean isLargeCogToSpeedController(BlockState from, BlockState to, BlockPos diff) { + if (!ICogWheel.isLargeCog(from) || !AllBlocks.ROTATION_SPEED_CONTROLLER.has(to)) + return false; + if (!diff.equals(BlockPos.ZERO.below())) + return false; + Axis axis = from.getValue(CogWheelBlock.AXIS); + if (axis.isVertical()) + return false; + if (to.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == axis) + return false; + return true; + } + + /** + * Insert the added position to the kinetic network. + * + * @param worldIn + * @param pos + */ + public static void handleAdded(Level worldIn, BlockPos pos, KineticBlockEntity addedTE) { + if (worldIn.isClientSide) + return; + if (!worldIn.isLoaded(pos)) + return; + propagateNewSource(addedTE); + } + + /** + * Search for sourceless networks attached to the given entity and update them. + * + * @param currentTE + */ + private static void propagateNewSource(KineticBlockEntity currentTE) { + BlockPos pos = currentTE.getBlockPos(); + Level world = currentTE.getLevel(); + + for (KineticBlockEntity neighbourTE : getConnectedNeighbours(currentTE)) { + float speedOfCurrent = currentTE.getTheoreticalSpeed(); + float speedOfNeighbour = neighbourTE.getTheoreticalSpeed(); + float newSpeed = getConveyedSpeed(currentTE, neighbourTE); + float oppositeSpeed = getConveyedSpeed(neighbourTE, currentTE); + + if (newSpeed == 0 && oppositeSpeed == 0) + continue; + + boolean incompatible = + Math.signum(newSpeed) != Math.signum(speedOfNeighbour) && (newSpeed != 0 && speedOfNeighbour != 0); + + boolean tooFast = Math.abs(newSpeed) > AllConfigs.server().kinetics.maxRotationSpeed.get() + || Math.abs(oppositeSpeed) > AllConfigs.server().kinetics.maxRotationSpeed.get(); + // Check for both the new speed and the opposite speed, just in case + + boolean speedChangedTooOften = currentTE.getFlickerScore() > MAX_FLICKER_SCORE; + if (tooFast || speedChangedTooOften) { + world.destroyBlock(pos, true); + return; + } + + // Opposite directions + if (incompatible) { + world.destroyBlock(pos, true); + return; + + // Same direction: overpower the slower speed + } else { + + // Neighbour faster, overpower the incoming tree + if (Math.abs(oppositeSpeed) > Math.abs(speedOfCurrent)) { + float prevSpeed = currentTE.getSpeed(); + currentTE.setSource(neighbourTE.getBlockPos()); + currentTE.setSpeed(getConveyedSpeed(neighbourTE, currentTE)); + currentTE.onSpeedChanged(prevSpeed); + currentTE.sendData(); + + propagateNewSource(currentTE); + return; + } + + // Current faster, overpower the neighbours' tree + if (Math.abs(newSpeed) >= Math.abs(speedOfNeighbour)) { + + // Do not overpower you own network -> cycle + if (!currentTE.hasNetwork() || currentTE.network.equals(neighbourTE.network)) { + float epsilon = Math.abs(speedOfNeighbour) / 256f / 256f; + if (Math.abs(newSpeed) > Math.abs(speedOfNeighbour) + epsilon) + world.destroyBlock(pos, true); + continue; + } + + if (currentTE.hasSource() && currentTE.source.equals(neighbourTE.getBlockPos())) + currentTE.removeSource(); + + float prevSpeed = neighbourTE.getSpeed(); + neighbourTE.setSource(currentTE.getBlockPos()); + neighbourTE.setSpeed(getConveyedSpeed(currentTE, neighbourTE)); + neighbourTE.onSpeedChanged(prevSpeed); + neighbourTE.sendData(); + propagateNewSource(neighbourTE); + continue; + } + } + + if (neighbourTE.getTheoreticalSpeed() == newSpeed) + continue; + + float prevSpeed = neighbourTE.getSpeed(); + neighbourTE.setSpeed(newSpeed); + neighbourTE.setSource(currentTE.getBlockPos()); + neighbourTE.onSpeedChanged(prevSpeed); + neighbourTE.sendData(); + propagateNewSource(neighbourTE); + + } + } + + /** + * Remove the given entity from the network. + * + * @param worldIn + * @param pos + * @param removedBE + */ + public static void handleRemoved(Level worldIn, BlockPos pos, KineticBlockEntity removedBE) { + if (worldIn.isClientSide) + return; + if (removedBE == null) + return; + if (removedBE.getTheoreticalSpeed() == 0) + return; + + for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedBE)) { + BlockState neighbourState = worldIn.getBlockState(neighbourPos); + if (!(neighbourState.getBlock() instanceof IRotate)) + continue; + BlockEntity blockEntity = worldIn.getBlockEntity(neighbourPos); + if (!(blockEntity instanceof KineticBlockEntity)) + continue; + + final KineticBlockEntity neighbourBE = (KineticBlockEntity) blockEntity; + if (!neighbourBE.hasSource() || !neighbourBE.source.equals(pos)) + continue; + + propagateMissingSource(neighbourBE); + } + + } + + /** + * Clear the entire subnetwork depending on the given entity and find a new + * source + * + * @param updateTE + */ + private static void propagateMissingSource(KineticBlockEntity updateTE) { + final Level world = updateTE.getLevel(); + + List potentialNewSources = new LinkedList<>(); + List frontier = new LinkedList<>(); + frontier.add(updateTE.getBlockPos()); + BlockPos missingSource = updateTE.hasSource() ? updateTE.source : null; + + while (!frontier.isEmpty()) { + final BlockPos pos = frontier.remove(0); + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof KineticBlockEntity)) + continue; + final KineticBlockEntity currentBE = (KineticBlockEntity) blockEntity; + + currentBE.removeSource(); + currentBE.sendData(); + + for (KineticBlockEntity neighbourBE : getConnectedNeighbours(currentBE)) { + if (neighbourBE.getBlockPos() + .equals(missingSource)) + continue; + if (!neighbourBE.hasSource()) + continue; + + if (!neighbourBE.source.equals(pos)) { + potentialNewSources.add(neighbourBE); + continue; + } + + if (neighbourBE.isSource()) + potentialNewSources.add(neighbourBE); + + frontier.add(neighbourBE.getBlockPos()); + } + } + + for (KineticBlockEntity newSource : potentialNewSources) { + if (newSource.hasSource() || newSource.isSource()) { + propagateNewSource(newSource); + return; + } + } + } + + private static KineticBlockEntity findConnectedNeighbour(KineticBlockEntity currentTE, BlockPos neighbourPos) { + BlockState neighbourState = currentTE.getLevel() + .getBlockState(neighbourPos); + if (!(neighbourState.getBlock() instanceof IRotate)) + return null; + if (!neighbourState.hasBlockEntity()) + return null; + BlockEntity neighbourBE = currentTE.getLevel() + .getBlockEntity(neighbourPos); + if (!(neighbourBE instanceof KineticBlockEntity)) + return null; + KineticBlockEntity neighbourKBE = (KineticBlockEntity) neighbourBE; + if (!(neighbourKBE.getBlockState() + .getBlock() instanceof IRotate)) + return null; + if (!isConnected(currentTE, neighbourKBE) && !isConnected(neighbourKBE, currentTE)) + return null; + return neighbourKBE; + } + + public static boolean isConnected(KineticBlockEntity from, KineticBlockEntity to) { + final BlockState stateFrom = from.getBlockState(); + final BlockState stateTo = to.getBlockState(); + return isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos() + .subtract(from.getBlockPos())) || getRotationSpeedModifier(from, to) != 0 + || from.isCustomConnection(to, stateFrom, stateTo); + } + + private static List getConnectedNeighbours(KineticBlockEntity be) { + List neighbours = new LinkedList<>(); + for (BlockPos neighbourPos : getPotentialNeighbourLocations(be)) { + final KineticBlockEntity neighbourBE = findConnectedNeighbour(be, neighbourPos); + if (neighbourBE == null) + continue; + + neighbours.add(neighbourBE); + } + return neighbours; + } + + private static List getPotentialNeighbourLocations(KineticBlockEntity be) { + List neighbours = new LinkedList<>(); + BlockPos blockPos = be.getBlockPos(); + Level level = be.getLevel(); + + if (!level.isLoaded(blockPos)) + return neighbours; + + for (Direction facing : Iterate.directions) { + BlockPos relative = blockPos.relative(facing); + if (level.isLoaded(relative)) + neighbours.add(relative); + } + + BlockState blockState = be.getBlockState(); + if (!(blockState.getBlock() instanceof IRotate)) + return neighbours; + IRotate block = (IRotate) blockState.getBlock(); + return be.addPropagationLocations(block, blockState, neighbours); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/TorquePropagator.java b/src/main/java/com/simibubi/create/content/kinetics/TorquePropagator.java new file mode 100644 index 0000000000..6950a30d6b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/TorquePropagator.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.kinetics; + +import java.util.HashMap; +import java.util.Map; + +import com.simibubi.create.Create; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.createmod.catnip.utility.WorldHelper; +import net.minecraft.world.level.LevelAccessor; + +public class TorquePropagator { + + static Map> networks = new HashMap<>(); + + public void onLoadWorld(LevelAccessor world) { + networks.put(world, new HashMap<>()); + Create.LOGGER.debug("Prepared Kinetic Network Space for " + WorldHelper.getDimensionID(world)); + } + + public void onUnloadWorld(LevelAccessor world) { + networks.remove(world); + Create.LOGGER.debug("Removed Kinetic Network Space for " + WorldHelper.getDimensionID(world)); + } + + public KineticNetwork getOrCreateNetworkFor(KineticBlockEntity be) { + Long id = be.network; + KineticNetwork network; + Map map = networks.computeIfAbsent(be.getLevel(), $ -> new HashMap<>()); + if (id == null) + return null; + + if (!map.containsKey(id)) { + network = new KineticNetwork(); + network.id = be.network; + map.put(id, network); + } + network = map.get(id); + return network; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/AbstractEncasedShaftBlock.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/AbstractEncasedShaftBlock.java index 229d200970..362cdbbb21 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/AbstractEncasedShaftBlock.java @@ -1,9 +1,7 @@ -package com.simibubi.create.content.contraptions.relays.encased; +package com.simibubi.create.content.kinetics.base; import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; - import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/BackHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/BackHalfShaftInstance.java new file mode 100644 index 0000000000..c530c8c860 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/BackHalfShaftInstance.java @@ -0,0 +1,17 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.MaterialManager; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class BackHalfShaftInstance extends HalfShaftInstance { + public BackHalfShaftInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Direction getShaftDirection() { + return blockState.getValue(BlockStateProperties.FACING).getOpposite(); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingKineticBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingKineticBlockEntity.java new file mode 100644 index 0000000000..a859defd0e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingKineticBlockEntity.java @@ -0,0 +1,158 @@ +package com.simibubi.create.content.kinetics.base; + +import java.util.concurrent.atomic.AtomicInteger; + +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.AirBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public abstract class BlockBreakingKineticBlockEntity extends KineticBlockEntity { + + public static final AtomicInteger NEXT_BREAKER_ID = new AtomicInteger(); + protected int ticksUntilNextProgress; + protected int destroyProgress; + protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet(); + protected BlockPos breakingPos; + + public BlockBreakingKineticBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + if (destroyProgress == -1) + destroyNextTick(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (ticksUntilNextProgress == -1) + destroyNextTick(); + } + + public void destroyNextTick() { + ticksUntilNextProgress = 1; + } + + protected abstract BlockPos getBreakingPos(); + + protected boolean shouldRun() { + return true; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("Progress", destroyProgress); + compound.putInt("NextTick", ticksUntilNextProgress); + if (breakingPos != null) + compound.put("Breaking", NbtUtils.writeBlockPos(breakingPos)); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + destroyProgress = compound.getInt("Progress"); + ticksUntilNextProgress = compound.getInt("NextTick"); + if (compound.contains("Breaking")) + breakingPos = NbtUtils.readBlockPos(compound.getCompound("Breaking")); + super.read(compound, clientPacket); + } + + @Override + public void invalidate() { + super.invalidate(); + if (!level.isClientSide && destroyProgress != 0) + level.destroyBlockProgress(breakerId, breakingPos, -1); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) + return; + if (!shouldRun()) + return; + if (getSpeed() == 0) + return; + + breakingPos = getBreakingPos(); + + if (ticksUntilNextProgress < 0) + return; + if (ticksUntilNextProgress-- > 0) + return; + + BlockState stateToBreak = level.getBlockState(breakingPos); + float blockHardness = stateToBreak.getDestroySpeed(level, breakingPos); + + if (!canBreak(stateToBreak, blockHardness)) { + if (destroyProgress != 0) { + destroyProgress = 0; + level.destroyBlockProgress(breakerId, breakingPos, -1); + } + return; + } + + float breakSpeed = getBreakSpeed(); + destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); + level.playSound(null, worldPosition, stateToBreak.getSoundType() + .getHitSound(), SoundSource.NEUTRAL, .25f, 1); + + if (destroyProgress >= 10) { + onBlockBroken(stateToBreak); + destroyProgress = 0; + ticksUntilNextProgress = -1; + level.destroyBlockProgress(breakerId, breakingPos, -1); + return; + } + + ticksUntilNextProgress = (int) (blockHardness / breakSpeed); + level.destroyBlockProgress(breakerId, breakingPos, (int) destroyProgress); + } + + public boolean canBreak(BlockState stateToBreak, float blockHardness) { + return isBreakable(stateToBreak, blockHardness); + } + + public static boolean isBreakable(BlockState stateToBreak, float blockHardness) { + return !(stateToBreak.getMaterial() + .isLiquid() || stateToBreak.getBlock() instanceof AirBlock || blockHardness == -1); + } + + public void onBlockBroken(BlockState stateToBreak) { + Vec3 vec = VecHelper.offsetRandomly(VecHelper.getCenterOf(breakingPos), level.random, .125f); + BlockHelper.destroyBlock(level, breakingPos, 1f, (stack) -> { + if (stack.isEmpty()) + return; + if (!level.getGameRules() + .getBoolean(GameRules.RULE_DOBLOCKDROPS)) + return; + if (level.restoringBlockSnapshots) + return; + + ItemEntity itementity = new ItemEntity(level, vec.x, vec.y, vec.z, stack); + itementity.setDefaultPickUpDelay(); + itementity.setDeltaMovement(Vec3.ZERO); + level.addFreshEntity(itementity); + }); + } + + protected float getBreakSpeed() { + return Math.abs(getSpeed() / 100f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingMovementBehaviour.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingMovementBehaviour.java index 70771c4294..72b6bd20cc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/BlockBreakingMovementBehaviour.java @@ -1,9 +1,11 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.kinetics.base; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; +import com.simibubi.create.content.trains.entity.CarriageContraption; import com.simibubi.create.foundation.utility.BlockHelper; import net.minecraft.core.BlockPos; @@ -28,7 +30,7 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour { public void startMoving(MovementContext context) { if (context.world.isClientSide) return; - context.data.putInt("BreakerId", -BlockBreakingKineticTileEntity.NEXT_BREAKER_ID.incrementAndGet()); + context.data.putInt("BreakerId", -BlockBreakingKineticBlockEntity.NEXT_BREAKER_ID.incrementAndGet()); } @Override @@ -40,9 +42,9 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour { damageEntities(context, pos, world); if (world.isClientSide) return; + if (!canBreak(world, pos, stateVisited)) return; - context.data.put("BreakingPos", NbtUtils.writeBlockPos(pos)); context.stall = true; } @@ -180,7 +182,7 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour { return; } - float breakSpeed = Mth.clamp(Math.abs(context.getAnimationSpeed()) / 500f, 1 / 128f, 16f); + float breakSpeed = getBlockBreakingSpeed(context); destroyProgress += Mth.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); world.playSound(null, breakingPos, stateToBreak.getSoundType() .getHitSound(), SoundSource.NEUTRAL, .25f, 1); @@ -199,7 +201,7 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour { context.stall = false; if (shouldDestroyStartBlock(stateToBreak)) - BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); + destroyBlock(context, breakingPos); onBlockBroken(context, ogPos, stateToBreak); ticksUntilNextProgress = -1; data.remove("Progress"); @@ -214,13 +216,26 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour { data.putInt("Progress", destroyProgress); } + protected void destroyBlock(MovementContext context, BlockPos breakingPos) { + BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); + } + + protected float getBlockBreakingSpeed(MovementContext context) { + float lowerLimit = 1 / 128f; + if (context.contraption instanceof MountedContraption) + lowerLimit = 1f; + if (context.contraption instanceof CarriageContraption) + lowerLimit = 2f; + return Mth.clamp(Math.abs(context.getAnimationSpeed()) / 500f, lowerLimit, 16f); + } + protected boolean shouldDestroyStartBlock(BlockState stateToBreak) { return true; } public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { float blockHardness = state.getDestroySpeed(world, breakingPos); - return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness); + return BlockBreakingKineticBlockEntity.isBreakable(state, blockHardness); } protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/CutoutRotatingInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/CutoutRotatingInstance.java new file mode 100644 index 0000000000..72b3767bea --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/CutoutRotatingInstance.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.foundation.render.AllMaterialSpecs; + +public class CutoutRotatingInstance extends SingleRotatingInstance { + public CutoutRotatingInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Material getRotatingMaterial() { + return materialManager.defaultCutout() + .material(AllMaterialSpecs.ROTATING); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalAxisKineticBlock.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/DirectionalAxisKineticBlock.java index 933f3d476b..bfcf0548fb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalAxisKineticBlock.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalKineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalKineticBlock.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/base/DirectionalKineticBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/DirectionalKineticBlock.java index 8b5b278833..5e650d74c0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalKineticBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalShaftHalvesBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalShaftHalvesBlockEntity.java new file mode 100644 index 0000000000..aa67359878 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/DirectionalShaftHalvesBlockEntity.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.kinetics.base; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class DirectionalShaftHalvesBlockEntity extends KineticBlockEntity { + + public DirectionalShaftHalvesBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public Direction getSourceFacing() { + BlockPos localSource = source.subtract(getBlockPos()); + return Direction.getNearest(localSource.getX(), localSource.getY(), localSource.getZ()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/GeneratingKineticBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/base/GeneratingKineticBlockEntity.java new file mode 100644 index 0000000000..bfe78a31cf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/GeneratingKineticBlockEntity.java @@ -0,0 +1,171 @@ +package com.simibubi.create.content.kinetics.base; + +import java.util.List; + +import com.simibubi.create.content.kinetics.KineticNetwork; +import com.simibubi.create.content.kinetics.base.IRotate.SpeedLevel; +import com.simibubi.create.content.kinetics.base.IRotate.StressImpact; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class GeneratingKineticBlockEntity extends KineticBlockEntity { + + public boolean reActivateSource; + + public GeneratingKineticBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + protected void notifyStressCapacityChange(float capacity) { + getOrCreateNetwork().updateCapacityFor(this, capacity); + } + + @Override + public void removeSource() { + if (hasSource() && isSource()) + reActivateSource = true; + super.removeSource(); + } + + @Override + public void setSource(BlockPos source) { + super.setSource(source); + BlockEntity blockEntity = level.getBlockEntity(source); + if (!(blockEntity instanceof KineticBlockEntity)) + return; + KineticBlockEntity sourceBE = (KineticBlockEntity) blockEntity; + if (reActivateSource && Math.abs(sourceBE.getSpeed()) >= Math.abs(getGeneratedSpeed())) + reActivateSource = false; + } + + @Override + public void tick() { + super.tick(); + if (reActivateSource) { + updateGeneratedRotation(); + reActivateSource = false; + } + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + boolean added = super.addToGoggleTooltip(tooltip, isPlayerSneaking); + if (!StressImpact.isEnabled()) + return added; + + float stressBase = calculateAddedStressCapacity(); + if (Mth.equal(stressBase, 0)) + return added; + + CreateLang.translate("gui.goggles.generator_stats") + .forGoggles(tooltip); + CreateLang.translate("tooltip.capacityProvided") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + float speed = getTheoreticalSpeed(); + if (speed != getGeneratedSpeed() && speed != 0) + stressBase *= getGeneratedSpeed() / speed; + speed = Math.abs(speed); + + float stressTotal = stressBase * speed; + + CreateLang.number(stressTotal) + .translate("generic.unit.stress") + .style(ChatFormatting.AQUA) + .space() + .add(CreateLang.translate("gui.goggles.at_current_speed") + .style(ChatFormatting.DARK_GRAY)) + .forGoggles(tooltip, 1); + + return true; + } + + public void updateGeneratedRotation() { + float speed = getGeneratedSpeed(); + float prevSpeed = this.speed; + + if (level == null || level.isClientSide) + return; + + if (prevSpeed != speed) { + if (!hasSource()) { + SpeedLevel levelBefore = SpeedLevel.of(this.speed); + SpeedLevel levelafter = SpeedLevel.of(speed); + if (levelBefore != levelafter) + effects.queueRotationIndicators(); + } + + applyNewSpeed(prevSpeed, speed); + } + + if (hasNetwork() && speed != 0) { + KineticNetwork network = getOrCreateNetwork(); + notifyStressCapacityChange(calculateAddedStressCapacity()); + getOrCreateNetwork().updateStressFor(this, calculateStressApplied()); + network.updateStress(); + } + + onSpeedChanged(prevSpeed); + sendData(); + } + + public void applyNewSpeed(float prevSpeed, float speed) { + + // Speed changed to 0 + if (speed == 0) { + if (hasSource()) { + notifyStressCapacityChange(0); + getOrCreateNetwork().updateStressFor(this, calculateStressApplied()); + return; + } + detachKinetics(); + setSpeed(0); + setNetwork(null); + return; + } + + // Now turning - create a new Network + if (prevSpeed == 0) { + setSpeed(speed); + setNetwork(createNetworkId()); + attachKinetics(); + return; + } + + // Change speed when overpowered by other generator + if (hasSource()) { + + // Staying below Overpowered speed + if (Math.abs(prevSpeed) >= Math.abs(speed)) { + if (Math.signum(prevSpeed) != Math.signum(speed)) + level.destroyBlock(worldPosition, true); + return; + } + + // Faster than attached network -> become the new source + detachKinetics(); + setSpeed(speed); + source = null; + setNetwork(createNetworkId()); + attachKinetics(); + return; + } + + // Reapply source + detachKinetics(); + setSpeed(speed); + attachKinetics(); + } + + public Long createNetworkId() { + return worldPosition.asLong(); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/HalfShaftInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/HalfShaftInstance.java new file mode 100644 index 0000000000..ce0b1f33df --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/HalfShaftInstance.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class HalfShaftInstance extends SingleRotatingInstance { + public HalfShaftInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + Direction dir = getShaftDirection(); + return getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, blockState, dir); + } + + protected Direction getShaftDirection() { + return blockState.getValue(BlockStateProperties.FACING); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalAxisKineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalAxisKineticBlock.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/base/HorizontalAxisKineticBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/HorizontalAxisKineticBlock.java index 053a3b22ed..63b245e63f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalAxisKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalAxisKineticBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalHalfShaftInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalHalfShaftInstance.java new file mode 100644 index 0000000000..297807d337 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalHalfShaftInstance.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.MaterialManager; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class HorizontalHalfShaftInstance extends HalfShaftInstance { + + public HorizontalHalfShaftInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Direction getShaftDirection() { + return blockState.getValue(BlockStateProperties.HORIZONTAL_FACING).getOpposite(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalKineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalKineticBlock.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/base/HorizontalKineticBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/HorizontalKineticBlock.java index 70286fd678..7f6e5b9300 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/HorizontalKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/HorizontalKineticBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/IRotate.java b/src/main/java/com/simibubi/create/content/kinetics/base/IRotate.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/base/IRotate.java rename to src/main/java/com/simibubi/create/content/kinetics/base/IRotate.java index cb5ee91420..e43981e609 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/IRotate.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/IRotate.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemDescription; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.lang.Lang; import net.createmod.catnip.utility.lang.LangBuilder; @@ -47,10 +47,10 @@ public interface IRotate extends IWrenchable { public float getSpeedValue() { switch (this) { case FAST: - return AllConfigs.SERVER.kinetics.fastSpeed.get() + return AllConfigs.server().kinetics.fastSpeed.get() .floatValue(); case MEDIUM: - return AllConfigs.SERVER.kinetics.mediumSpeed.get() + return AllConfigs.server().kinetics.mediumSpeed.get() .floatValue(); case SLOW: return 1; @@ -63,9 +63,9 @@ public interface IRotate extends IWrenchable { public static SpeedLevel of(float speed) { speed = Math.abs(speed); - if (speed >= AllConfigs.SERVER.kinetics.fastSpeed.get()) + if (speed >= AllConfigs.server().kinetics.fastSpeed.get()) return FAST; - if (speed >= AllConfigs.SERVER.kinetics.mediumSpeed.get()) + if (speed >= AllConfigs.server().kinetics.mediumSpeed.get()) return MEDIUM; if (speed >= 1) return SLOW; @@ -74,7 +74,7 @@ public interface IRotate extends IWrenchable { public static LangBuilder getFormattedSpeedText(float speed, boolean overstressed) { SpeedLevel speedLevel = of(speed); - LangBuilder builder = CreateLang.text(ItemDescription.makeProgressBar(3, speedLevel.ordinal())); + LangBuilder builder = CreateLang.text(TooltipHelper.makeProgressBar(3, speedLevel.ordinal())); builder.translate("tooltip.speedRequirement." + Lang.asId(speedLevel.name())) .space() @@ -129,12 +129,12 @@ public interface IRotate extends IWrenchable { } public static boolean isEnabled() { - return !AllConfigs.SERVER.kinetics.disableStress.get(); + return !AllConfigs.server().kinetics.disableStress.get(); } public static LangBuilder getFormattedStressText(double stressPercent) { StressImpact stressLevel = of(stressPercent); - return CreateLang.text(ItemDescription.makeProgressBar(3, Math.min(stressLevel.ordinal() + 1, 3))) + return CreateLang.text(TooltipHelper.makeProgressBar(3, Math.min(stressLevel.ordinal() + 1, 3))) .translate("tooltip.stressImpact." + Lang.asId(stressLevel.name())) .text(String.format(" (%s%%) ", (int) (stressPercent * 100))) .style(stressLevel.getRelativeColor()); diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlock.java new file mode 100644 index 0000000000..40882f34f5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlock.java @@ -0,0 +1,104 @@ +package com.simibubi.create.content.kinetics.base; + +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class KineticBlock extends Block implements IRotate { + + public KineticBlock(Properties properties) { + super(properties); + } + + @Override + public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + // onBlockAdded is useless for init, as sometimes the BE gets re-instantiated + + // however, if a block change occurs that does not change kinetic connections, + // we can prevent a major re-propagation here + + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (blockEntity instanceof KineticBlockEntity) { + KineticBlockEntity kineticBlockEntity = (KineticBlockEntity) blockEntity; + kineticBlockEntity.preventSpeedUpdate = 0; + + if (oldState.getBlock() != state.getBlock()) + return; + if (state.hasBlockEntity() != oldState.hasBlockEntity()) + return; + if (!areStatesKineticallyEquivalent(oldState, state)) + return; + + kineticBlockEntity.preventSpeedUpdate = 2; + } + } + + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + IBE.onRemove(pState, pLevel, pPos, pNewState); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return false; + } + + protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { + if (oldState.getBlock() != newState.getBlock()) + return false; + return getRotationAxis(newState) == getRotationAxis(oldState); + } + + @Override + public void updateIndirectNeighbourShapes(BlockState stateIn, LevelAccessor worldIn, BlockPos pos, int flags, + int count) { + if (worldIn.isClientSide()) + return; + + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (!(blockEntity instanceof KineticBlockEntity)) + return; + KineticBlockEntity kbe = (KineticBlockEntity) blockEntity; + + if (kbe.preventSpeedUpdate > 0) + return; + + // Remove previous information when block is added + kbe.warnOfMovement(); + kbe.clearKineticInformation(); + kbe.updateSpeed = true; + } + + @Override + public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + AdvancementBehaviour.setPlacedBy(worldIn, pos, placer); + if (worldIn.isClientSide) + return; + + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (!(blockEntity instanceof KineticBlockEntity)) + return; + + KineticBlockEntity kbe = (KineticBlockEntity) blockEntity; + kbe.effects.queueRotationIndicators(); + } + + public float getParticleTargetRadius() { + return .65f; + } + + public float getParticleInitialRadius() { + return .75f; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntity.java new file mode 100644 index 0000000000..2b2774dedd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntity.java @@ -0,0 +1,611 @@ +package com.simibubi.create.content.kinetics.base; + +import static net.minecraft.ChatFormatting.GOLD; +import static net.minecraft.ChatFormatting.GRAY; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.equipment.goggles.IHaveHoveringInformation; +import com.simibubi.create.content.kinetics.BlockStressValues; +import com.simibubi.create.content.kinetics.KineticNetwork; +import com.simibubi.create.content.kinetics.RotationPropagator; +import com.simibubi.create.content.kinetics.base.IRotate.SpeedLevel; +import com.simibubi.create.content.kinetics.base.IRotate.StressImpact; +import com.simibubi.create.content.kinetics.gearbox.GearboxBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity.SequenceContext; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.sound.SoundScapes; +import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.FontHelper.Palette; +import net.minecraft.ChatFormatting; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class KineticBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation, IHaveHoveringInformation { + + public @Nullable Long network; + public @Nullable BlockPos source; + public boolean networkDirty; + public boolean updateSpeed; + public int preventSpeedUpdate; + + protected KineticEffectHandler effects; + protected float speed; + protected float capacity; + protected float stress; + protected boolean overStressed; + protected boolean wasMoved; + + private int flickerTally; + private int networkSize; + private int validationCountdown; + protected float lastStressApplied; + protected float lastCapacityProvided; + + public SequenceContext sequenceContext; + + public KineticBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + effects = new KineticEffectHandler(this); + updateSpeed = true; + } + + @Override + public void initialize() { + if (hasNetwork() && !level.isClientSide) { + KineticNetwork network = getOrCreateNetwork(); + if (!network.initialized) + network.initFromTE(capacity, stress, networkSize); + network.addSilently(this, lastCapacityProvided, lastStressApplied); + } + + super.initialize(); + } + + @Override + public void tick() { + if (!level.isClientSide && needsSpeedUpdate()) + attachKinetics(); + + super.tick(); + effects.tick(); + + preventSpeedUpdate = 0; + + if (level.isClientSide) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio()); + return; + } + + if (validationCountdown-- <= 0) { + validationCountdown = AllConfigs.server().kinetics.kineticValidationFrequency.get(); + validateKinetics(); + } + + if (getFlickerScore() > 0) + flickerTally = getFlickerScore() - 1; + + if (networkDirty) { + if (hasNetwork()) + getOrCreateNetwork().updateNetwork(); + networkDirty = false; + } + } + + private void validateKinetics() { + if (hasSource()) { + if (!hasNetwork()) { + removeSource(); + return; + } + + if (!level.isLoaded(source)) + return; + + BlockEntity blockEntity = level.getBlockEntity(source); + KineticBlockEntity sourceBE = + blockEntity instanceof KineticBlockEntity ? (KineticBlockEntity) blockEntity : null; + if (sourceBE == null || sourceBE.speed == 0) { + removeSource(); + detachKinetics(); + return; + } + + return; + } + + if (speed != 0) { + if (getGeneratedSpeed() == 0) + speed = 0; + } + } + + public void updateFromNetwork(float maxStress, float currentStress, int networkSize) { + networkDirty = false; + this.capacity = maxStress; + this.stress = currentStress; + this.networkSize = networkSize; + boolean overStressed = maxStress < currentStress && StressImpact.isEnabled(); + setChanged(); + + if (overStressed != this.overStressed) { + float prevSpeed = getSpeed(); + this.overStressed = overStressed; + onSpeedChanged(prevSpeed); + sendData(); + } + } + + protected Block getStressConfigKey() { + return getBlockState().getBlock(); + } + + public float calculateStressApplied() { + float impact = (float) BlockStressValues.getImpact(getStressConfigKey()); + this.lastStressApplied = impact; + return impact; + } + + public float calculateAddedStressCapacity() { + float capacity = (float) BlockStressValues.getCapacity(getStressConfigKey()); + this.lastCapacityProvided = capacity; + return capacity; + } + + public void onSpeedChanged(float previousSpeed) { + boolean fromOrToZero = (previousSpeed == 0) != (getSpeed() == 0); + boolean directionSwap = !fromOrToZero && Math.signum(previousSpeed) != Math.signum(getSpeed()); + if (fromOrToZero || directionSwap) + flickerTally = getFlickerScore() + 5; + setChanged(); + } + + @Override + public void remove() { + if (!level.isClientSide) { + if (hasNetwork()) + getOrCreateNetwork().remove(this); + detachKinetics(); + } + super.remove(); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + compound.putFloat("Speed", speed); + if (sequenceContext != null && (!clientPacket || syncSequenceContext())) + compound.put("Sequence", sequenceContext.serializeNBT()); + + if (needsSpeedUpdate()) + compound.putBoolean("NeedsSpeedUpdate", true); + + if (hasSource()) + compound.put("Source", NbtUtils.writeBlockPos(source)); + + if (hasNetwork()) { + CompoundTag networkTag = new CompoundTag(); + networkTag.putLong("Id", this.network); + networkTag.putFloat("Stress", stress); + networkTag.putFloat("Capacity", capacity); + networkTag.putInt("Size", networkSize); + + if (lastStressApplied != 0) + networkTag.putFloat("AddedStress", lastStressApplied); + if (lastCapacityProvided != 0) + networkTag.putFloat("AddedCapacity", lastCapacityProvided); + + compound.put("Network", networkTag); + } + + super.write(compound, clientPacket); + } + + public boolean needsSpeedUpdate() { + return updateSpeed; + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + boolean overStressedBefore = overStressed; + clearKineticInformation(); + + // DO NOT READ kinetic information when placed after movement + if (wasMoved) { + super.read(compound, clientPacket); + return; + } + + speed = compound.getFloat("Speed"); + sequenceContext = SequenceContext.fromNBT(compound.getCompound("Sequence")); + + if (compound.contains("Source")) + source = NbtUtils.readBlockPos(compound.getCompound("Source")); + + if (compound.contains("Network")) { + CompoundTag networkTag = compound.getCompound("Network"); + network = networkTag.getLong("Id"); + stress = networkTag.getFloat("Stress"); + capacity = networkTag.getFloat("Capacity"); + networkSize = networkTag.getInt("Size"); + lastStressApplied = networkTag.getFloat("AddedStress"); + lastCapacityProvided = networkTag.getFloat("AddedCapacity"); + overStressed = capacity < stress && StressImpact.isEnabled(); + } + + super.read(compound, clientPacket); + + if (clientPacket && overStressedBefore != overStressed && speed != 0) + effects.triggerOverStressedEffect(); + + if (clientPacket) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + } + + public float getGeneratedSpeed() { + return 0; + } + + public boolean isSource() { + return getGeneratedSpeed() != 0; + } + + public float getSpeed() { + if (overStressed) + return 0; + return getTheoreticalSpeed(); + } + + public float getTheoreticalSpeed() { + return speed; + } + + public void setSpeed(float speed) { + this.speed = speed; + } + + public boolean hasSource() { + return source != null; + } + + public void setSource(BlockPos source) { + this.source = source; + if (level == null || level.isClientSide) + return; + + BlockEntity blockEntity = level.getBlockEntity(source); + if (!(blockEntity instanceof KineticBlockEntity sourceBE)) { + removeSource(); + return; + } + + setNetwork(sourceBE.network); + copySequenceContextFrom(sourceBE); + } + + protected void copySequenceContextFrom(KineticBlockEntity sourceBE) { + sequenceContext = sourceBE.sequenceContext; + } + + public void removeSource() { + float prevSpeed = getSpeed(); + + speed = 0; + source = null; + setNetwork(null); + sequenceContext = null; + + onSpeedChanged(prevSpeed); + } + + public void setNetwork(@Nullable Long networkIn) { + if (network == networkIn) + return; + if (network != null) + getOrCreateNetwork().remove(this); + + network = networkIn; + setChanged(); + + if (networkIn == null) + return; + + network = networkIn; + KineticNetwork network = getOrCreateNetwork(); + network.initialized = true; + network.add(this); + } + + public KineticNetwork getOrCreateNetwork() { + return Create.TORQUE_PROPAGATOR.getOrCreateNetworkFor(this); + } + + public boolean hasNetwork() { + return network != null; + } + + public void attachKinetics() { + updateSpeed = false; + RotationPropagator.handleAdded(level, worldPosition, this); + } + + public void detachKinetics() { + RotationPropagator.handleRemoved(level, worldPosition, this); + } + + public boolean isSpeedRequirementFulfilled() { + BlockState state = getBlockState(); + if (!(getBlockState().getBlock() instanceof IRotate)) + return true; + IRotate def = (IRotate) state.getBlock(); + SpeedLevel minimumRequiredSpeedLevel = def.getMinimumRequiredSpeedLevel(); + return Math.abs(getSpeed()) >= minimumRequiredSpeedLevel.getSpeedValue(); + } + + public static void switchToBlockState(Level world, BlockPos pos, BlockState state) { + if (world.isClientSide) + return; + + BlockEntity blockEntity = world.getBlockEntity(pos); + BlockState currentState = world.getBlockState(pos); + boolean isKinetic = blockEntity instanceof KineticBlockEntity; + + if (currentState == state) + return; + if (blockEntity == null || !isKinetic) { + world.setBlock(pos, state, 3); + return; + } + + KineticBlockEntity kineticBlockEntity = (KineticBlockEntity) blockEntity; + if (state.getBlock() instanceof KineticBlock + && !((KineticBlock) state.getBlock()).areStatesKineticallyEquivalent(currentState, state)) { + if (kineticBlockEntity.hasNetwork()) + kineticBlockEntity.getOrCreateNetwork() + .remove(kineticBlockEntity); + kineticBlockEntity.detachKinetics(); + kineticBlockEntity.removeSource(); + } + + world.setBlock(pos, state, 3); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { + boolean notFastEnough = !isSpeedRequirementFulfilled() && getSpeed() != 0; + + if (overStressed && AllConfigs.client().enableOverstressedTooltip.get()) { + CreateLang.translate("gui.stressometer.overstressed") + .style(GOLD) + .forGoggles(tooltip); + Component hint = CreateLang.translateDirect("gui.contraptions.network_overstressed"); + List cutString = TooltipHelper.cutTextComponent(hint, Palette.GRAY_AND_WHITE); + for (int i = 0; i < cutString.size(); i++) + CreateLang.builder() + .add(cutString.get(i) + .copy()) + .forGoggles(tooltip); + return true; + } + + if (notFastEnough) { + CreateLang.translate("tooltip.speedRequirement") + .style(GOLD) + .forGoggles(tooltip); + MutableComponent hint = + CreateLang.translateDirect("gui.contraptions.not_fast_enough", I18n.get(getBlockState().getBlock() + .getDescriptionId())); + List cutString = TooltipHelper.cutTextComponent(hint, Palette.GRAY_AND_WHITE); + for (int i = 0; i < cutString.size(); i++) + CreateLang.builder() + .add(cutString.get(i) + .copy()) + .forGoggles(tooltip); + return true; + } + + return false; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + boolean added = false; + + if (!StressImpact.isEnabled()) + return added; + float stressAtBase = calculateStressApplied(); + if (Mth.equal(stressAtBase, 0)) + return added; + + CreateLang.translate("gui.goggles.kinetic_stats") + .forGoggles(tooltip); + + addStressImpactStats(tooltip, stressAtBase); + + return true; + + } + + protected void addStressImpactStats(List tooltip, float stressAtBase) { + CreateLang.translate("tooltip.stressImpact") + .style(GRAY) + .forGoggles(tooltip); + + float stressTotal = stressAtBase * Math.abs(getTheoreticalSpeed()); + + CreateLang.number(stressTotal) + .translate("generic.unit.stress") + .style(ChatFormatting.AQUA) + .space() + .add(CreateLang.translate("gui.goggles.at_current_speed") + .style(ChatFormatting.DARK_GRAY)) + .forGoggles(tooltip, 1); + } + + public void clearKineticInformation() { + speed = 0; + source = null; + network = null; + overStressed = false; + stress = 0; + capacity = 0; + lastStressApplied = 0; + lastCapacityProvided = 0; + } + + public void warnOfMovement() { + wasMoved = true; + } + + public int getFlickerScore() { + return flickerTally; + } + + public static float convertToDirection(float axisSpeed, Direction d) { + return d.getAxisDirection() == AxisDirection.POSITIVE ? axisSpeed : -axisSpeed; + } + + public static float convertToLinear(float speed) { + return speed / 512f; + } + + public static float convertToAngular(float speed) { + return speed * 3 / 10f; + } + + public boolean isOverStressed() { + return overStressed; + } + + // Custom Propagation + + /** + * Specify ratio of transferred rotation from this kinetic component to a + * specific other. + * + * @param target other Kinetic BE to transfer to + * @param stateFrom this BE's blockstate + * @param stateTo other BE's blockstate + * @param diff difference in position (to.pos - from.pos) + * @param connectedViaAxes whether these kinetic blocks are connected via mutual + * IRotate.hasShaftTowards() + * @param connectedViaCogs whether these kinetic blocks are connected via mutual + * IRotate.hasIntegratedCogwheel() + * @return factor of rotation speed from this BE to other. 0 if no rotation is + * transferred, or the standard rules apply (integrated shafts/cogs) + */ + public float propagateRotationTo(KineticBlockEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, + boolean connectedViaAxes, boolean connectedViaCogs) { + return 0; + } + + /** + * Specify additional locations the rotation propagator should look for + * potentially connected components. Neighbour list contains offset positions in + * all 6 directions by default. + * + * @param block + * @param state + * @param neighbours + * @return + */ + public List addPropagationLocations(IRotate block, BlockState state, List neighbours) { + if (!canPropagateDiagonally(block, state)) + return neighbours; + + Axis axis = block.getRotationAxis(state); + BlockPos.betweenClosedStream(new BlockPos(-1, -1, -1), new BlockPos(1, 1, 1)) + .forEach(offset -> { + if (axis.choose(offset.getX(), offset.getY(), offset.getZ()) != 0) + return; + if (offset.distSqr(BlockPos.ZERO) != 2) + return; + neighbours.add(worldPosition.offset(offset)); + }); + return neighbours; + } + + /** + * Specify whether this component can propagate speed to the other in any + * circumstance. Shaft and cogwheel connections are already handled by internal + * logic. Does not have to be specified on both ends, it is assumed that this + * relation is symmetrical. + * + * @param other + * @param state + * @param otherState + * @return true if this and the other component should check their propagation + * factor and are not already connected via integrated cogs or shafts + */ + public boolean isCustomConnection(KineticBlockEntity other, BlockState state, BlockState otherState) { + return false; + } + + protected boolean canPropagateDiagonally(IRotate block, BlockState state) { + return ICogWheel.isSmallCog(state); + } + + @Override + public void requestModelDataUpdate() { + super.requestModelDataUpdate(); + if (!this.remove) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + } + + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + float componentSpeed = Math.abs(getSpeed()); + if (componentSpeed == 0) + return; + float pitch = Mth.clamp((componentSpeed / 256f) + .45f, .85f, 1f); + + if (isNoisy()) + SoundScapes.play(AmbienceGroup.KINETIC, worldPosition, pitch); + + Block block = getBlockState().getBlock(); + if (ICogWheel.isSmallCog(block) || ICogWheel.isLargeCog(block) || block instanceof GearboxBlock) + SoundScapes.play(AmbienceGroup.COG, worldPosition, pitch); + } + + protected boolean isNoisy() { + return true; + } + + public int getRotationAngleOffset(Axis axis) { + return 0; + } + + protected boolean syncSequenceContext() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityInstance.java new file mode 100644 index 0000000000..0cec4b1eca --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityInstance.java @@ -0,0 +1,97 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; +import com.simibubi.create.foundation.render.AllMaterialSpecs; + +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class KineticBlockEntityInstance extends BlockEntityInstance { + + protected final Direction.Axis axis; + + public KineticBlockEntityInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + axis = (blockState.getBlock() instanceof IRotate irotate) ? irotate.getRotationAxis(blockState) : Axis.Y; + } + + protected final void updateRotation(RotatingData instance) { + updateRotation(instance, getRotationAxis(), getBlockEntitySpeed()); + } + + protected final void updateRotation(RotatingData instance, Direction.Axis axis) { + updateRotation(instance, axis, getBlockEntitySpeed()); + } + + protected final void updateRotation(RotatingData instance, float speed) { + updateRotation(instance, getRotationAxis(), speed); + } + + protected final void updateRotation(RotatingData instance, Direction.Axis axis, float speed) { + instance.setRotationAxis(axis) + .setRotationOffset(getRotationOffset(axis)) + .setRotationalSpeed(speed) + .setColor(blockEntity); + } + + protected final RotatingData setup(RotatingData key) { + return setup(key, getRotationAxis(), getBlockEntitySpeed()); + } + + protected final RotatingData setup(RotatingData key, Direction.Axis axis) { + return setup(key, axis, getBlockEntitySpeed()); + } + + protected final RotatingData setup(RotatingData key, float speed) { + return setup(key, getRotationAxis(), speed); + } + + protected final RotatingData setup(RotatingData key, Direction.Axis axis, float speed) { + key.setRotationAxis(axis) + .setRotationalSpeed(speed) + .setRotationOffset(getRotationOffset(axis)) + .setColor(blockEntity) + .setPosition(getInstancePosition()); + + return key; + } + + protected float getRotationOffset(final Direction.Axis axis) { + float offset = ICogWheel.isLargeCog(blockState) ? 11.25f : 0; + double d = (((axis == Direction.Axis.X) ? 0 : pos.getX()) + ((axis == Direction.Axis.Y) ? 0 : pos.getY()) + + ((axis == Direction.Axis.Z) ? 0 : pos.getZ())) % 2; + if (d == 0) { + offset = 22.5f; + } + return offset; + } + + protected Direction.Axis getRotationAxis() { + return axis; + } + + protected float getBlockEntitySpeed() { + return blockEntity.getSpeed(); + } + + protected BlockState shaft() { + return shaft(getRotationAxis()); + } + + protected Material getRotatingMaterial() { + return materialManager.defaultSolid() + .material(AllMaterialSpecs.ROTATING); + } + + public static BlockState shaft(Direction.Axis axis) { + return AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, axis); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityRenderer.java new file mode 100644 index 0000000000..fc60effd45 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticBlockEntityRenderer.java @@ -0,0 +1,135 @@ +package com.simibubi.create.content.kinetics.base; + +import org.apache.commons.lang3.ArrayUtils; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.KineticDebugger; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.render.SuperByteBufferCache; +import net.createmod.catnip.utility.theme.Color; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class KineticBlockEntityRenderer extends SafeBlockEntityRenderer { + + public static final SuperByteBufferCache.Compartment KINETIC_BLOCK = new SuperByteBufferCache.Compartment<>(); + public static boolean rainbowMode = false; + + protected static final RenderType[] REVERSED_CHUNK_BUFFER_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); + static { + ArrayUtils.reverse(REVERSED_CHUNK_BUFFER_LAYERS); + } + + public KineticBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) return; + + BlockState state = getRenderedBlockState(be); + RenderType type = getRenderType(be, state); + if (type != null) + renderRotatingBuffer(be, getRotatedModel(be, state), ms, buffer.getBuffer(type), light); + } + + protected BlockState getRenderedBlockState(T be) { + return be.getBlockState(); + } + + protected RenderType getRenderType(T be, BlockState state) { + for (RenderType type : REVERSED_CHUNK_BUFFER_LAYERS) + if (ItemBlockRenderTypes.canRenderInLayer(state, type)) + return type; + return null; + } + + protected SuperByteBuffer getRotatedModel(T be, BlockState state) { + return CachedBlockBuffers.block(KINETIC_BLOCK, state); + } + + public static void renderRotatingKineticBlock(KineticBlockEntity be, BlockState renderedState, PoseStack ms, + VertexConsumer buffer, int light) { + SuperByteBuffer superByteBuffer = CachedBlockBuffers.block(KINETIC_BLOCK, renderedState); + renderRotatingBuffer(be, superByteBuffer, ms, buffer, light); + } + + public static void renderRotatingBuffer(KineticBlockEntity be, SuperByteBuffer superBuffer, PoseStack ms, + VertexConsumer buffer, int light) { + standardKineticRotationTransform(superBuffer, be, light).renderInto(ms, buffer); + } + + public static float getAngleForTe(KineticBlockEntity be, final BlockPos pos, Axis axis) { + float time = WorldTickHolder.getRenderTime(be.getLevel()); + float offset = getRotationOffsetForPosition(be, pos, axis); + float angle = ((time * be.getSpeed() * 3f / 10 + offset) % 360) / 180 * (float) Math.PI; + return angle; + } + + public static SuperByteBuffer standardKineticRotationTransform(SuperByteBuffer buffer, KineticBlockEntity be, + int light) { + final BlockPos pos = be.getBlockPos(); + Axis axis = ((IRotate) be.getBlockState() + .getBlock()).getRotationAxis(be.getBlockState()); + return kineticRotationTransform(buffer, be, axis, getAngleForTe(be, pos, axis), light); + } + + public static SuperByteBuffer kineticRotationTransform(SuperByteBuffer buffer, KineticBlockEntity be, Axis axis, + float angle, int light) { + buffer.light(light); + buffer.rotateCentered(Direction.get(AxisDirection.POSITIVE, axis), angle); + + if (KineticDebugger.isActive()) { + rainbowMode = true; + buffer.color(be.hasNetwork() ? Color.generateFromLong(be.network) : Color.WHITE); + } else { + float overStressedEffect = be.effects.overStressedEffect; + if (overStressedEffect != 0) + if (overStressedEffect > 0) + buffer.color(Color.WHITE.mixWith(Color.RED, overStressedEffect)); + else + buffer.color(Color.WHITE.mixWith(Color.SPRING_GREEN, -overStressedEffect)); + else + buffer.color(Color.WHITE); + } + + return buffer; + } + + public static float getRotationOffsetForPosition(KineticBlockEntity be, final BlockPos pos, final Axis axis) { + float offset = ICogWheel.isLargeCog(be.getBlockState()) ? 11.25f : 0; + double d = (((axis == Axis.X) ? 0 : pos.getX()) + ((axis == Axis.Y) ? 0 : pos.getY()) + + ((axis == Axis.Z) ? 0 : pos.getZ())) % 2; + if (d == 0) + offset = 22.5f; + return offset + be.getRotationAngleOffset(axis); + } + + public static BlockState shaft(Axis axis) { + return AllBlocks.SHAFT.getDefaultState() + .setValue(BlockStateProperties.AXIS, axis); + } + + public static Axis getRotationAxisOf(KineticBlockEntity be) { + return ((IRotate) be.getBlockState() + .getBlock()).getRotationAxis(be.getBlockState()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticEffectHandler.java b/src/main/java/com/simibubi/create/content/kinetics/base/KineticEffectHandler.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/base/KineticEffectHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/base/KineticEffectHandler.java index 4955f6c969..c9793865c8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticEffectHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/KineticEffectHandler.java @@ -1,9 +1,8 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; import java.util.Random; -import com.simibubi.create.content.contraptions.base.IRotate.SpeedLevel; -import com.simibubi.create.content.contraptions.particle.RotationIndicatorParticleData; +import com.simibubi.create.content.kinetics.base.IRotate.SpeedLevel; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -21,9 +20,9 @@ public class KineticEffectHandler { int overStressedTime; float overStressedEffect; int particleSpawnCountdown; - KineticTileEntity kte; + KineticBlockEntity kte; - public KineticEffectHandler(KineticTileEntity kte) { + public KineticEffectHandler(KineticBlockEntity kte) { this.kte = kte; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java b/src/main/java/com/simibubi/create/content/kinetics/base/RotatedPillarKineticBlock.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/base/RotatedPillarKineticBlock.java index 080f0922d9..68f0b5c34c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/RotatedPillarKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/RotatedPillarKineticBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base; +package com.simibubi.create.content.kinetics.base; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java b/src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticle.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java rename to src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticle.java index a2a94bce1a..5cd72cfa27 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticle.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticle.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.kinetics.base; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.content.contraptions.goggles.GogglesItem; +import com.simibubi.create.content.equipment.goggles.GogglesItem; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.theme.Color; diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticleData.java b/src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticleData.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticleData.java rename to src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticleData.java index 02502d5cda..7a249f6989 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/RotationIndicatorParticleData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/RotationIndicatorParticleData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.kinetics.base; import java.util.Locale; @@ -10,6 +10,7 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.codecs.PrimitiveCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllParticleTypes; +import com.simibubi.create.foundation.particle.ICustomParticleDataWithSprite; import net.minecraft.client.particle.ParticleEngine.SpriteParticleRegistration; import net.minecraft.core.Direction.Axis; diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/ShaftInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/ShaftInstance.java new file mode 100644 index 0000000000..6649249bb3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/ShaftInstance.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.MaterialManager; + +import net.minecraft.world.level.block.state.BlockState; + +public class ShaftInstance extends SingleRotatingInstance { + + public ShaftInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected BlockState getRenderedBlockState() { + return shaft(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/ShaftRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/base/ShaftRenderer.java new file mode 100644 index 0000000000..a0c722edfc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/ShaftRenderer.java @@ -0,0 +1,17 @@ +package com.simibubi.create.content.kinetics.base; + +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class ShaftRenderer extends KineticBlockEntityRenderer { + + public ShaftRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected BlockState getRenderedBlockState(KineticBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/SingleRotatingInstance.java b/src/main/java/com/simibubi/create/content/kinetics/base/SingleRotatingInstance.java new file mode 100644 index 0000000000..1a38e762a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/SingleRotatingInstance.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.kinetics.base; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.world.level.block.state.BlockState; + +public class SingleRotatingInstance extends KineticBlockEntityInstance { + + protected RotatingData rotatingModel; + + public SingleRotatingInstance(MaterialManager materialManager, T blockEntity) { + super(materialManager, blockEntity); + } + + @Override + public void init() { + rotatingModel = setup(getModel().createInstance()); + } + + @Override + public void update() { + updateRotation(rotatingModel); + } + + @Override + public void updateLight() { + relight(pos, rotatingModel); + } + + @Override + public void remove() { + rotatingModel.delete(); + } + + protected BlockState getRenderedBlockState() { + return blockState; + } + + protected Instancer getModel() { + return getRotatingMaterial().getModel(getRenderedBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltData.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltData.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltData.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltData.java index 3d4965de30..ae295ab0dc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import com.mojang.math.Quaternion; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltType.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltType.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltType.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltType.java index 65479c8447..abd89817e5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltType.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import com.jozufozu.flywheel.api.struct.Batched; import com.jozufozu.flywheel.api.struct.Instanced; @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.util.RenderMath; import com.mojang.math.Quaternion; -import com.simibubi.create.content.contraptions.KineticDebugger; +import com.simibubi.create.content.kinetics.KineticDebugger; import com.simibubi.create.foundation.render.AllInstanceFormats; import com.simibubi.create.foundation.render.AllProgramSpecs; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltWriterUnsafe.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltWriterUnsafe.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltWriterUnsafe.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltWriterUnsafe.java index 1cf570be5e..002e25e3ab 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/BeltWriterUnsafe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/BeltWriterUnsafe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticData.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticData.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticData.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticData.java index 16faae5eda..be580ba20d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticData.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import com.jozufozu.flywheel.core.materials.BasicData; import com.mojang.math.Vector3f; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; import net.createmod.catnip.utility.theme.Color; import net.minecraft.core.BlockPos; @@ -38,9 +38,9 @@ public class KineticData extends BasicData { return this; } - public KineticData setColor(KineticTileEntity te) { - if (te.hasNetwork()) { - setColor(Color.generateFromLong(te.network)); + public KineticData setColor(KineticBlockEntity blockEntity) { + if (blockEntity.hasNetwork()) { + setColor(Color.generateFromLong(blockEntity.network)); }else { setColor(0xFF, 0xFF, 0xFF); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticWriterUnsafe.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticWriterUnsafe.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticWriterUnsafe.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticWriterUnsafe.java index d450b1d6a7..3787e73d79 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/KineticWriterUnsafe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/KineticWriterUnsafe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingData.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingData.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingData.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingData.java index 2431f86b56..5d66aebbcd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import com.mojang.math.Vector3f; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingType.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingType.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingType.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingType.java index b9bcaf258e..971a89b012 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingType.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import com.jozufozu.flywheel.api.struct.Batched; import com.jozufozu.flywheel.api.struct.Instanced; @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.util.RenderMath; import com.mojang.math.Vector3f; -import com.simibubi.create.content.contraptions.KineticDebugger; +import com.simibubi.create.content.kinetics.KineticDebugger; import com.simibubi.create.foundation.render.AllInstanceFormats; import com.simibubi.create.foundation.render.AllProgramSpecs; diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingWriterUnsafe.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingWriterUnsafe.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingWriterUnsafe.java rename to src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingWriterUnsafe.java index b57e21d2a1..8b043be7a4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/flwdata/RotatingWriterUnsafe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/RotatingWriterUnsafe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.base.flwdata; +package com.simibubi.create.content.kinetics.base.flwdata; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/package-info.java b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/package-info.java new file mode 100644 index 0000000000..9e9a5554f1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/base/flwdata/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.simibubi.create.content.kinetics.base.flwdata; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlock.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlock.java index b845f4745c..eace612a6a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlock.java @@ -1,42 +1,45 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; import java.util.function.Consumer; import org.apache.commons.lang3.mutable.MutableBoolean; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlicer.Feedback; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.equipment.armor.DivingBootsItem; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity.CasingType; +import com.simibubi.create.content.kinetics.belt.BeltSlicer.Feedback; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.BeltMovementHandler.TransportedEntityInfo; +import com.simibubi.create.content.kinetics.belt.transport.BeltTunnelInteractionHandler; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler; import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import net.createmod.catnip.utility.Iterate; import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.core.NonNullList; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; @@ -46,7 +49,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; @@ -67,10 +69,12 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.levelgen.DebugLevelSource; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.shapes.CollisionContext; @@ -84,7 +88,8 @@ import net.minecraftforge.common.Tags; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -public class BeltBlock extends HorizontalKineticBlock implements ITE, ISpecialBlockItemRequirement, ITransformableBlock { +public class BeltBlock extends HorizontalKineticBlock + implements IBE, ISpecialBlockItemRequirement, ITransformableBlock, ProperWaterloggedBlock { public static final Property SLOPE = EnumProperty.create("slope", BeltSlope.class); public static final Property PART = EnumProperty.create("part", BeltPart.class); @@ -94,7 +99,8 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE p_149666_2_) { - p_149666_2_.add(AllItems.BELT_CONNECTOR.asStack()); - } - @Override protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { return super.areStatesKineticallyEquivalent(oldState, newState) @@ -117,7 +118,7 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE getDrops(BlockState state, net.minecraft.world.level.storage.loot.LootContext.Builder builder) { List drops = super.getDrops(state, builder); - BlockEntity tileEntity = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY); - if (tileEntity instanceof BeltTileEntity && ((BeltTileEntity) tileEntity).hasPulley()) + BlockEntity blockEntity = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY); + if (blockEntity instanceof BeltBlockEntity && ((BeltBlockEntity) blockEntity).hasPulley()) drops.addAll(AllBlocks.SHAFT.getDefaultState() .getDrops(builder)); return drops; @@ -150,9 +151,9 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE { + withBlockEntityDo(worldIn, pos, be -> { ItemEntity itemEntity = (ItemEntity) entityIn; - IItemHandler handler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + IItemHandler handler = be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) .orElse(null); if (handler == null) return; @@ -221,7 +221,7 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE te.applyColor(DyeColor.getColor(heldItem))); - return InteractionResult.SUCCESS; - } + if (isDye || hasWater) + return onBlockEntityUse(world, pos, + be -> be.applyColor(DyeColor.getColor(heldItem)) ? InteractionResult.SUCCESS : InteractionResult.PASS); if (isConnector) return BeltSlicer.useConnector(state, world, pos, player, handIn, hit, new Feedback()); if (isWrench) return BeltSlicer.useWrench(state, world, pos, player, handIn, hit, new Feedback()); - BeltTileEntity belt = BeltHelper.getSegmentTE(world, pos); + BeltBlockEntity belt = BeltHelper.getSegmentBE(world, pos); if (belt == null) return InteractionResult.PASS; if (isHand) { - BeltTileEntity controllerBelt = belt.getControllerTE(); + BeltBlockEntity controllerBelt = belt.getControllerBE(); if (controllerBelt == null) return InteractionResult.PASS; if (world.isClientSide) @@ -299,21 +297,19 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE te.setCasingType(CasingType.BRASS)); + withBlockEntityDo(world, pos, be -> be.setCasingType(CasingType.BRASS)); + updateCoverProperty(world, pos, world.getBlockState(pos)); return InteractionResult.SUCCESS; } if (AllBlocks.ANDESITE_CASING.isIn(heldItem)) { - if (world.isClientSide) - return InteractionResult.SUCCESS; - withTileEntityDo(world, pos, te -> te.setCasingType(CasingType.ANDESITE)); + withBlockEntityDo(world, pos, be -> be.setCasingType(CasingType.ANDESITE)); + updateCoverProperty(world, pos, world.getBlockState(pos)); return InteractionResult.SUCCESS; } @@ -329,14 +325,14 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE te.setCasingType(CasingType.NONE)); + withBlockEntityDo(world, pos, be -> be.setCasingType(CasingType.NONE)); return InteractionResult.SUCCESS; } if (state.getValue(PART) == BeltPart.PULLEY) { if (world.isClientSide) return InteractionResult.SUCCESS; - KineticTileEntity.switchToBlockState(world, pos, state.setValue(PART, BeltPart.MIDDLE)); + KineticBlockEntity.switchToBlockState(world, pos, state.setValue(PART, BeltPart.MIDDLE)); if (player != null && !player.isCreative()) player.getInventory() .placeItemBackInInventory(AllBlocks.SHAFT.asStack()); @@ -348,7 +344,7 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE builder) { - builder.add(SLOPE, PART, CASING); + builder.add(SLOPE, PART, CASING, WATERLOGGED); super.createBlockStateDefinition(builder); } @@ -371,12 +367,12 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE { + return getBlockEntityOptional(worldIn, pos).map(be -> { Entity entity = ((EntityCollisionContext) context).getEntity(); if (entity == null) return shape; - BeltTileEntity controller = te.getControllerTE(); + BeltBlockEntity controller = be.getControllerBE(); if (controller == null) return shape; if (controller.passengers == null || !controller.passengers.containsKey(entity)) @@ -428,20 +424,20 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE bbe.setCovered(isBlockCoveringBelt(world, pos.above()))); + } + + public static boolean isBlockCoveringBelt(LevelAccessor world, BlockPos pos) { + BlockState blockState = world.getBlockState(pos); + VoxelShape collisionShape = blockState.getCollisionShape(world, pos); + if (collisionShape.isEmpty()) + return false; + AABB bounds = collisionShape.bounds(); + if (bounds.getXsize() < .5f || bounds.getZsize() < .5f) + return false; + if (bounds.minY > 0) + return false; + if (AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(blockState)) + return false; + if (FunnelBlock.isFunnel(blockState) && FunnelBlock.getFunnelFacing(blockState) != Direction.UP) + return false; + if (blockState.getBlock() instanceof BeltTunnelBlock) + return false; + return true; + } + private void updateTunnelConnections(LevelAccessor world, BlockPos pos) { Block tunnelBlock = world.getBlockState(pos) .getBlock(); @@ -552,22 +570,18 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE getBlockEntityClass() { + return BeltBlockEntity.class; } @Override - public Class getTileEntityClass() { - return BeltTileEntity.class; + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BELT.get(); } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.BELT.get(); - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { List required = new ArrayList<>(); if (state.getValue(PART) != BeltPart.MIDDLE) required.add(AllBlocks.SHAFT.asStack()); @@ -695,17 +709,19 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof BeltTileEntity belt) { - for (BlockPos beltPos : BeltBlock.getBeltChain(level, belt.getController())) { - renderer.destroyBlockProgress(beltPos.hashCode(), beltPos, progress); - } + if (blockEntity instanceof BeltBlockEntity belt) { + return new HashSet<>(BeltBlock.getBeltChain(level, belt.getController())); } - return false; + return null; } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java new file mode 100644 index 0000000000..ceb6eb27a3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltBlockEntity.java @@ -0,0 +1,674 @@ +package com.simibubi.create.content.kinetics.belt; + +import static com.simibubi.create.content.kinetics.belt.BeltPart.MIDDLE; +import static com.simibubi.create.content.kinetics.belt.BeltSlope.HORIZONTAL; +import static net.minecraft.core.Direction.AxisDirection.NEGATIVE; +import static net.minecraft.core.Direction.AxisDirection.POSITIVE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import com.jozufozu.flywheel.light.LightListener; +import com.jozufozu.flywheel.light.LightUpdater; +import com.jozufozu.flywheel.util.box.GridAlignedBB; +import com.jozufozu.flywheel.util.box.ImmutableBox; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.BeltInventory; +import com.simibubi.create.content.kinetics.belt.transport.BeltMovementHandler; +import com.simibubi.create.content.kinetics.belt.transport.BeltMovementHandler.TransportedEntityInfo; +import com.simibubi.create.content.kinetics.belt.transport.BeltTunnelInteractionHandler; +import com.simibubi.create.content.kinetics.belt.transport.ItemHandlerBeltSegment; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.items.IItemHandler; + +public class BeltBlockEntity extends KineticBlockEntity { + + public Map passengers; + public Optional color; + public int beltLength; + public int index; + public Direction lastInsert; + public CasingType casing; + public boolean covered; + + protected BlockPos controller; + protected BeltInventory inventory; + protected LazyOptional itemHandler; + + public CompoundTag trackerUpdateTag; + + @OnlyIn(Dist.CLIENT) + public BeltLighter lighter; + + public static enum CasingType { + NONE, ANDESITE, BRASS; + } + + public BeltBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + controller = BlockPos.ZERO; + itemHandler = LazyOptional.empty(); + casing = CasingType.NONE; + color = Optional.empty(); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::canInsertFrom) + .setInsertionHandler(this::tryInsertingFromSide)); + behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) + .withStackPlacement(this::getWorldPositionOf)); + } + + @Override + public void tick() { + // Init belt + if (beltLength == 0) + BeltBlock.initBelt(level, worldPosition); + + super.tick(); + + if (!AllBlocks.BELT.has(level.getBlockState(worldPosition))) + return; + + initializeItemHandler(); + + // Move Items + if (!isController()) + return; + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + if (beltLength > 0 && lighter == null) { + lighter = new BeltLighter(); + } + }); + invalidateRenderBoundingBox(); + + getInventory().tick(); + + if (getSpeed() == 0) + return; + + // Move Entities + if (passengers == null) + passengers = new HashMap<>(); + + List toRemove = new ArrayList<>(); + passengers.forEach((entity, info) -> { + boolean canBeTransported = BeltMovementHandler.canBeTransported(entity); + boolean leftTheBelt = + info.getTicksSinceLastCollision() > ((getBlockState().getValue(BeltBlock.SLOPE) != HORIZONTAL) ? 3 : 1); + if (!canBeTransported || leftTheBelt) { + toRemove.add(entity); + return; + } + + info.tick(); + BeltMovementHandler.transportEntity(this, entity, info); + }); + toRemove.forEach(passengers::remove); + } + + @Override + public float calculateStressApplied() { + if (!isController()) + return 0; + return super.calculateStressApplied(); + } + + @Override + public AABB createRenderBoundingBox() { + if (!isController()) + return super.createRenderBoundingBox(); + else + return super.createRenderBoundingBox().inflate(beltLength + 1); + } + + protected void initializeItemHandler() { + if (level.isClientSide || itemHandler.isPresent()) + return; + if (beltLength == 0 || controller == null) + return; + if (!level.isLoaded(controller)) + return; + BlockEntity be = level.getBlockEntity(controller); + if (be == null || !(be instanceof BeltBlockEntity)) + return; + BeltInventory inventory = ((BeltBlockEntity) be).getInventory(); + if (inventory == null) + return; + IItemHandler handler = new ItemHandlerBeltSegment(inventory, index); + itemHandler = LazyOptional.of(() -> handler); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (!isItemHandlerCap(cap)) + return super.getCapability(cap, side); + if (!isRemoved() && !itemHandler.isPresent()) + initializeItemHandler(); + return itemHandler.cast(); + } + + @Override + public void destroy() { + super.destroy(); + if (isController()) + getInventory().ejectAll(); + } + + @Override + public void invalidate() { + super.invalidate(); + itemHandler.invalidate(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (controller != null) + compound.put("Controller", NbtUtils.writeBlockPos(controller)); + compound.putBoolean("IsController", isController()); + compound.putInt("Length", beltLength); + compound.putInt("Index", index); + NBTHelper.writeEnum(compound, "Casing", casing); + compound.putBoolean("Covered", covered); + + if (color.isPresent()) + NBTHelper.writeEnum(compound, "Dye", color.get()); + + if (isController()) + compound.put("Inventory", getInventory().write()); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + int prevBeltLength = beltLength; + super.read(compound, clientPacket); + + if (compound.getBoolean("IsController")) + controller = worldPosition; + + color = compound.contains("Dye") ? Optional.of(NBTHelper.readEnum(compound, "Dye", DyeColor.class)) + : Optional.empty(); + + if (!wasMoved) { + if (!isController()) + controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); + trackerUpdateTag = compound; + index = compound.getInt("Index"); + beltLength = compound.getInt("Length"); + if (prevBeltLength != beltLength) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + if (lighter != null) { + lighter.initializeLight(); + } + }); + } + } + + if (isController()) + getInventory().read(compound.getCompound("Inventory")); + + CasingType casingBefore = casing; + boolean coverBefore = covered; + casing = NBTHelper.readEnum(compound, "Casing", CasingType.class); + covered = compound.getBoolean("Covered"); + + if (!clientPacket) + return; + + if (casingBefore == casing && coverBefore == covered) + return; + if (!isVirtual()) + requestModelDataUpdate(); + if (hasLevel()) + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + } + + @Override + public void clearKineticInformation() { + super.clearKineticInformation(); + beltLength = 0; + index = 0; + controller = null; + trackerUpdateTag = new CompoundTag(); + } + + public boolean applyColor(DyeColor colorIn) { + if (colorIn == null) { + if (!color.isPresent()) + return false; + } else if (color.isPresent() && color.get() == colorIn) + return false; + if (level.isClientSide()) + return true; + + for (BlockPos blockPos : BeltBlock.getBeltChain(level, getController())) { + BeltBlockEntity belt = BeltHelper.getSegmentBE(level, blockPos); + if (belt == null) + continue; + belt.color = Optional.ofNullable(colorIn); + belt.setChanged(); + belt.sendData(); + } + + return true; + } + + public BeltBlockEntity getControllerBE() { + if (controller == null) + return null; + if (!level.isLoaded(controller)) + return null; + BlockEntity be = level.getBlockEntity(controller); + if (be == null || !(be instanceof BeltBlockEntity)) + return null; + return (BeltBlockEntity) be; + } + + public void setController(BlockPos controller) { + this.controller = controller; + } + + public BlockPos getController() { + return controller == null ? worldPosition : controller; + } + + public boolean isController() { + return controller != null && worldPosition.getX() == controller.getX() + && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); + } + + public float getBeltMovementSpeed() { + return getSpeed() / 480f; + } + + public float getDirectionAwareBeltMovementSpeed() { + int offset = getBeltFacing().getAxisDirection() + .getStep(); + if (getBeltFacing().getAxis() == Axis.X) + offset *= -1; + return getBeltMovementSpeed() * offset; + } + + public boolean hasPulley() { + if (!AllBlocks.BELT.has(getBlockState())) + return false; + return getBlockState().getValue(BeltBlock.PART) != MIDDLE; + } + + protected boolean isLastBelt() { + if (getSpeed() == 0) + return false; + + Direction direction = getBeltFacing(); + if (getBlockState().getValue(BeltBlock.SLOPE) == BeltSlope.VERTICAL) + return false; + + BeltPart part = getBlockState().getValue(BeltBlock.PART); + if (part == MIDDLE) + return false; + + boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection() + .getStep() == 1)) ^ direction.getAxis() == Axis.X; + return part == BeltPart.START ^ movingPositively; + } + + public Vec3i getMovementDirection(boolean firstHalf) { + return this.getMovementDirection(firstHalf, false); + } + + public Vec3i getBeltChainDirection() { + return this.getMovementDirection(true, true); + } + + protected Vec3i getMovementDirection(boolean firstHalf, boolean ignoreHalves) { + if (getSpeed() == 0) + return BlockPos.ZERO; + + final BlockState blockState = getBlockState(); + final Direction beltFacing = blockState.getValue(BlockStateProperties.HORIZONTAL_FACING); + final BeltSlope slope = blockState.getValue(BeltBlock.SLOPE); + final BeltPart part = blockState.getValue(BeltBlock.PART); + final Axis axis = beltFacing.getAxis(); + + Direction movementFacing = Direction.get(axis == Axis.X ? NEGATIVE : POSITIVE, axis); + boolean notHorizontal = blockState.getValue(BeltBlock.SLOPE) != HORIZONTAL; + if (getSpeed() < 0) + movementFacing = movementFacing.getOpposite(); + Vec3i movement = movementFacing.getNormal(); + + boolean slopeBeforeHalf = (part == BeltPart.END) == (beltFacing.getAxisDirection() == POSITIVE); + boolean onSlope = notHorizontal && (part == MIDDLE || slopeBeforeHalf == firstHalf || ignoreHalves); + boolean movingUp = onSlope && slope == (movementFacing == beltFacing ? BeltSlope.UPWARD : BeltSlope.DOWNWARD); + + if (!onSlope) + return movement; + + return new Vec3i(movement.getX(), movingUp ? 1 : -1, movement.getZ()); + } + + public Direction getMovementFacing() { + Axis axis = getBeltFacing().getAxis(); + return Direction.fromAxisAndDirection(axis, getBeltMovementSpeed() < 0 ^ axis == Axis.X ? NEGATIVE : POSITIVE); + } + + protected Direction getBeltFacing() { + return getBlockState().getValue(BlockStateProperties.HORIZONTAL_FACING); + } + + public BeltInventory getInventory() { + if (!isController()) { + BeltBlockEntity controllerBE = getControllerBE(); + if (controllerBE != null) + return controllerBE.getInventory(); + return null; + } + if (inventory == null) { + inventory = new BeltInventory(this); + } + return inventory; + } + + private void applyToAllItems(float maxDistanceFromCenter, + Function processFunction) { + BeltBlockEntity controller = getControllerBE(); + if (controller == null) + return; + BeltInventory inventory = controller.getInventory(); + if (inventory != null) + inventory.applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction); + } + + private Vec3 getWorldPositionOf(TransportedItemStack transported) { + BeltBlockEntity controllerBE = getControllerBE(); + if (controllerBE == null) + return Vec3.ZERO; + return BeltHelper.getVectorForOffset(controllerBE, transported.beltPosition); + } + + public void setCasingType(CasingType type) { + if (casing == type) + return; + + BlockState blockState = getBlockState(); + boolean shouldBlockHaveCasing = type != CasingType.NONE; + + if (level.isClientSide) { + casing = type; + level.setBlock(worldPosition, blockState.setValue(BeltBlock.CASING, shouldBlockHaveCasing), 0); + requestModelDataUpdate(); + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 16); + return; + } + + if (casing != CasingType.NONE) + level.levelEvent(2001, worldPosition, + Block.getId(casing == CasingType.ANDESITE ? AllBlocks.ANDESITE_CASING.getDefaultState() + : AllBlocks.BRASS_CASING.getDefaultState())); + if (blockState.getValue(BeltBlock.CASING) != shouldBlockHaveCasing) + KineticBlockEntity.switchToBlockState(level, worldPosition, + blockState.setValue(BeltBlock.CASING, shouldBlockHaveCasing)); + casing = type; + setChanged(); + sendData(); + } + + private boolean canInsertFrom(Direction side) { + if (getSpeed() == 0) + return false; + BlockState state = getBlockState(); + if (state.hasProperty(BeltBlock.SLOPE) && (state.getValue(BeltBlock.SLOPE) == BeltSlope.SIDEWAYS + || state.getValue(BeltBlock.SLOPE) == BeltSlope.VERTICAL)) + return false; + return getMovementFacing() != side.getOpposite(); + } + + private ItemStack tryInsertingFromSide(TransportedItemStack transportedStack, Direction side, boolean simulate) { + BeltBlockEntity nextBeltController = getControllerBE(); + ItemStack inserted = transportedStack.stack; + ItemStack empty = ItemStack.EMPTY; + + if (nextBeltController == null) + return inserted; + BeltInventory nextInventory = nextBeltController.getInventory(); + if (nextInventory == null) + return inserted; + + BlockEntity teAbove = level.getBlockEntity(worldPosition.above()); + if (teAbove instanceof BrassTunnelBlockEntity) { + BrassTunnelBlockEntity tunnelBE = (BrassTunnelBlockEntity) teAbove; + if (tunnelBE.hasDistributionBehaviour()) { + if (!tunnelBE.getStackToDistribute() + .isEmpty()) + return inserted; + if (!tunnelBE.testFlapFilter(side.getOpposite(), inserted)) + return inserted; + if (!simulate) { + BeltTunnelInteractionHandler.flapTunnel(nextInventory, index, side.getOpposite(), true); + tunnelBE.setStackToDistribute(inserted, side.getOpposite()); + } + return empty; + } + } + + if (getSpeed() == 0) + return inserted; + if (getMovementFacing() == side.getOpposite()) + return inserted; + if (!nextInventory.canInsertAtFromSide(index, side)) + return inserted; + if (simulate) + return empty; + + transportedStack = transportedStack.copy(); + transportedStack.beltPosition = index + .5f - Math.signum(getDirectionAwareBeltMovementSpeed()) / 16f; + + Direction movementFacing = getMovementFacing(); + if (!side.getAxis() + .isVertical()) { + if (movementFacing != side) { + transportedStack.sideOffset = side.getAxisDirection() + .getStep() * .35f; + if (side.getAxis() == Axis.X) + transportedStack.sideOffset *= -1; + } else + transportedStack.beltPosition = getDirectionAwareBeltMovementSpeed() > 0 ? index : index + 1; + } + + transportedStack.prevSideOffset = transportedStack.sideOffset; + transportedStack.insertedAt = index; + transportedStack.insertedFrom = side; + transportedStack.prevBeltPosition = transportedStack.beltPosition; + + BeltTunnelInteractionHandler.flapTunnel(nextInventory, index, side.getOpposite(), true); + + nextInventory.addItem(transportedStack); + nextBeltController.setChanged(); + nextBeltController.sendData(); + return empty; + } + + @Override + public IModelData getModelData() { + return new ModelDataMap.Builder().withInitial(BeltModel.CASING_PROPERTY, casing) + .withInitial(BeltModel.COVER_PROPERTY, covered) + .build(); + } + + @Override + protected boolean canPropagateDiagonally(IRotate block, BlockState state) { + return state.hasProperty(BeltBlock.SLOPE) && (state.getValue(BeltBlock.SLOPE) == BeltSlope.UPWARD + || state.getValue(BeltBlock.SLOPE) == BeltSlope.DOWNWARD); + } + + @Override + public float propagateRotationTo(KineticBlockEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, + boolean connectedViaAxes, boolean connectedViaCogs) { + if (target instanceof BeltBlockEntity && !connectedViaAxes) + return getController().equals(((BeltBlockEntity) target).getController()) ? 1 : 0; + return 0; + } + + public void invalidateItemHandler() { + itemHandler.invalidate(); + } + + public boolean shouldRenderNormally() { + if (level == null) + return isController(); + BlockState state = getBlockState(); + return state != null && state.hasProperty(BeltBlock.PART) && state.getValue(BeltBlock.PART) == BeltPart.START; + } + + /** + * Hide this behavior in an inner class to avoid loading LightListener on servers. + */ + @OnlyIn(Dist.CLIENT) + class BeltLighter implements LightListener { + private byte[] light; + + public BeltLighter() { + initializeLight(); + LightUpdater.get(level) + .addListener(this); + } + + /** + * Get the number of belt segments represented by the lighter. + * @return The number of segments. + */ + public int lightSegments() { + return light == null ? 0 : light.length / 2; + } + + /** + * Get the light value for a given segment. + * @param segment The segment to get the light value for. + * @return The light value. + */ + public int getPackedLight(int segment) { + return light == null ? 0 : LightTexture.pack(light[segment * 2], light[segment * 2 + 1]); + } + + @Override + public GridAlignedBB getVolume() { + BlockPos endPos = BeltHelper.getPositionForOffset(BeltBlockEntity.this, beltLength - 1); + GridAlignedBB bb = GridAlignedBB.from(worldPosition, endPos); + bb.fixMinMax(); + return bb; + } + + @Override + public boolean isListenerInvalid() { + return remove; + } + + @Override + public void onLightUpdate(LightLayer type, ImmutableBox changed) { + if (remove) + return; + if (level == null) + return; + + GridAlignedBB beltVolume = getVolume(); + + if (beltVolume.intersects(changed)) { + if (type == LightLayer.BLOCK) + updateBlockLight(); + + if (type == LightLayer.SKY) + updateSkyLight(); + } + } + + private void initializeLight() { + light = new byte[beltLength * 2]; + + Vec3i vec = getBeltFacing().getNormal(); + BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + + MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); + for (int i = 0; i < beltLength * 2; i += 2) { + light[i] = (byte) level.getBrightness(LightLayer.BLOCK, pos); + light[i + 1] = (byte) level.getBrightness(LightLayer.SKY, pos); + pos.move(vec.getX(), verticality, vec.getZ()); + } + } + + private void updateBlockLight() { + Vec3i vec = getBeltFacing().getNormal(); + BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + + MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); + for (int i = 0; i < beltLength * 2; i += 2) { + light[i] = (byte) level.getBrightness(LightLayer.BLOCK, pos); + + pos.move(vec.getX(), verticality, vec.getZ()); + } + } + + private void updateSkyLight() { + Vec3i vec = getBeltFacing().getNormal(); + BeltSlope slope = getBlockState().getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + + MutableBlockPos pos = new MutableBlockPos(controller.getX(), controller.getY(), controller.getZ()); + for (int i = 1; i < beltLength * 2; i += 2) { + light[i] = (byte) level.getBrightness(LightLayer.SKY, pos); + + pos.move(vec.getX(), verticality, vec.getZ()); + } + } + } + + public void setCovered(boolean blockCoveringBelt) { + if (blockCoveringBelt == covered) + return; + covered = blockCoveringBelt; + notifyUpdate(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltGenerator.java similarity index 97% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltGenerator.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltGenerator.java index d190e6e301..633c59bc45 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltGenerator.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltHelper.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltHelper.java new file mode 100644 index 0000000000..01fcfca267 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltHelper.java @@ -0,0 +1,101 @@ +package com.simibubi.create.content.kinetics.belt; + +import com.simibubi.create.AllTags.AllItemTags; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; + +public class BeltHelper { + + public static boolean isItemUpright(ItemStack stack) { + return stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY) + .isPresent() || AllItemTags.UPRIGHT_ON_BELT.matches(stack); + } + + public static BeltBlockEntity getSegmentBE(LevelAccessor world, BlockPos pos) { + if (world instanceof Level l && !l.isLoaded(pos)) + return null; + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof BeltBlockEntity)) + return null; + return (BeltBlockEntity) blockEntity; + } + + public static BeltBlockEntity getControllerBE(LevelAccessor world, BlockPos pos) { + BeltBlockEntity segment = getSegmentBE(world, pos); + if (segment == null) + return null; + BlockPos controllerPos = segment.controller; + if (controllerPos == null) + return null; + return getSegmentBE(world, controllerPos); + } + + public static BeltBlockEntity getBeltForOffset(BeltBlockEntity controller, float offset) { + return getBeltAtSegment(controller, (int) Math.floor(offset)); + } + + public static BeltBlockEntity getBeltAtSegment(BeltBlockEntity controller, int segment) { + BlockPos pos = getPositionForOffset(controller, segment); + BlockEntity be = controller.getLevel() + .getBlockEntity(pos); + if (be == null || !(be instanceof BeltBlockEntity)) + return null; + return (BeltBlockEntity) be; + } + + public static BlockPos getPositionForOffset(BeltBlockEntity controller, int offset) { + BlockPos pos = controller.getBlockPos(); + Vec3i vec = controller.getBeltFacing() + .getNormal(); + BeltSlope slope = controller.getBlockState() + .getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + + return pos.offset(offset * vec.getX(), Mth.clamp(offset, 0, controller.beltLength - 1) * verticality, + offset * vec.getZ()); + } + + public static Vec3 getVectorForOffset(BeltBlockEntity controller, float offset) { + BeltSlope slope = controller.getBlockState() + .getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + float verticalMovement = verticality; + if (offset < .5) + verticalMovement = 0; + verticalMovement = verticalMovement * (Math.min(offset, controller.beltLength - .5f) - .5f); + Vec3 vec = VecHelper.getCenterOf(controller.getBlockPos()); + Vec3 horizontalMovement = Vec3.atLowerCornerOf(controller.getBeltFacing() + .getNormal()) + .scale(offset - .5f); + + if (slope == BeltSlope.VERTICAL) + horizontalMovement = Vec3.ZERO; + + vec = vec.add(horizontalMovement) + .add(0, verticalMovement, 0); + return vec; + } + + public static Vec3 getBeltVector(BlockState state) { + BeltSlope slope = state.getValue(BeltBlock.SLOPE); + int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; + Vec3 horizontalMovement = Vec3.atLowerCornerOf(state.getValue(BeltBlock.HORIZONTAL_FACING) + .getNormal()); + if (slope == BeltSlope.VERTICAL) + return new Vec3(0, state.getValue(BeltBlock.HORIZONTAL_FACING) + .getAxisDirection() + .getStep(), 0); + return new Vec3(0, verticality, 0).add(horizontalMovement); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltInstance.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltInstance.java index 83edc557b0..25b12ffb3d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import java.util.ArrayList; import java.util.function.Supplier; @@ -10,11 +10,11 @@ import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Quaternion; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.BeltData; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.BeltData; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; import com.simibubi.create.foundation.render.AllMaterialSpecs; import net.createmod.catnip.render.SpriteShiftEntry; @@ -23,7 +23,7 @@ import net.minecraft.core.Direction; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.LightLayer; -public class BeltInstance extends KineticTileInstance { +public class BeltInstance extends KineticBlockEntityInstance { boolean upward; boolean diagonal; @@ -36,8 +36,8 @@ public class BeltInstance extends KineticTileInstance { protected ArrayList keys; protected RotatingData pulleyKey; - public BeltInstance(MaterialManager materialManager, BeltTileEntity tile) { - super(materialManager, tile); + public BeltInstance(MaterialManager materialManager, BeltBlockEntity blockEntity) { + super(materialManager, blockEntity); if (!AllBlocks.BELT.has(blockState)) return; @@ -56,7 +56,7 @@ public class BeltInstance extends KineticTileInstance { BeltPart part = blockState.getValue(BeltBlock.PART); boolean start = part == BeltPart.START; boolean end = part == BeltPart.END; - DyeColor color = tile.color.orElse(null); + DyeColor color = blockEntity.color.orElse(null); for (boolean bottom : Iterate.trueAndFalse) { PartialModel beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom); @@ -71,7 +71,7 @@ public class BeltInstance extends KineticTileInstance { if (diagonal) break; } - if (tile.hasPulley()) { + if (blockEntity.hasPulley()) { Instancer pulleyModel = getPulleyModel(); pulleyKey = setup(pulleyModel.createInstance()); @@ -143,7 +143,7 @@ public class BeltInstance extends KineticTileInstance { return modelTransform; }; - return getRotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, blockState, dir, ms); + return getRotatingMaterial().getModel(AllPartialModels.BELT_PULLEY, blockState, dir, ms); } private Direction getOrientation() { diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/BeltModel.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltModel.java new file mode 100644 index 0000000000..e3ebb1a129 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltModel.java @@ -0,0 +1,93 @@ +package com.simibubi.create.content.kinetics.belt; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.AllSpriteShifts; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity.CasingType; +import com.simibubi.create.foundation.model.BakedQuadHelper; + +import net.createmod.catnip.render.SpriteShiftEntry; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelProperty; + +public class BeltModel extends BakedModelWrapper { + + public static final ModelProperty CASING_PROPERTY = new ModelProperty<>(); + public static final ModelProperty COVER_PROPERTY = new ModelProperty<>(); + + private static final SpriteShiftEntry SPRITE_SHIFT = AllSpriteShifts.ANDESIDE_BELT_CASING; + + public BeltModel(BakedModel template) { + super(template); + } + + @Override + public TextureAtlasSprite getParticleIcon(IModelData data) { + if (!data.hasProperty(CASING_PROPERTY)) + return super.getParticleIcon(data); + CasingType type = data.getData(CASING_PROPERTY); + if (type == CasingType.NONE || type == CasingType.BRASS) + return super.getParticleIcon(data); + return AllSpriteShifts.ANDESITE_CASING.getOriginal(); + } + + @Override + public List getQuads(BlockState state, Direction side, Random rand, IModelData extraData) { + List quads = super.getQuads(state, side, rand, extraData); + if (!extraData.hasProperty(CASING_PROPERTY)) + return quads; + + boolean cover = extraData.getData(COVER_PROPERTY); + CasingType type = extraData.getData(CASING_PROPERTY); + boolean brassCasing = type == CasingType.BRASS; + + if (type == CasingType.NONE || brassCasing && !cover) + return quads; + + quads = new ArrayList<>(quads); + + if (cover) { + boolean alongX = state.getValue(BeltBlock.HORIZONTAL_FACING) + .getAxis() == Axis.X; + BakedModel coverModel = + (brassCasing ? alongX ? AllPartialModels.BRASS_BELT_COVER_X : AllPartialModels.BRASS_BELT_COVER_Z + : alongX ? AllPartialModels.ANDESITE_BELT_COVER_X : AllPartialModels.ANDESITE_BELT_COVER_Z).get(); + quads.addAll(coverModel.getQuads(state, side, rand, extraData)); + } + + if (brassCasing) + return quads; + + for (int i = 0; i < quads.size(); i++) { + BakedQuad quad = quads.get(i); + TextureAtlasSprite original = quad.getSprite(); + if (original != SPRITE_SHIFT.getOriginal()) + continue; + + BakedQuad newQuad = BakedQuadHelper.clone(quad); + int[] vertexData = newQuad.getVertices(); + + for (int vertex = 0; vertex < 4; vertex++) { + float u = BakedQuadHelper.getU(vertexData, vertex); + float v = BakedQuadHelper.getV(vertexData, vertex); + BakedQuadHelper.setU(vertexData, vertex, SPRITE_SHIFT.getTargetU(u)); + BakedQuadHelper.setV(vertexData, vertex, SPRITE_SHIFT.getTargetV(v)); + } + + quads.set(i, newQuad); + } + + return quads; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltPart.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltPart.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltPart.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltPart.java index b3c4d366d4..d0228742b2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltPart.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltPart.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.util.StringRepresentable; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltRenderer.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltRenderer.java index f735b733a9..7e46a4a88d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltRenderer.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import java.util.Random; import java.util.function.Supplier; @@ -9,14 +9,14 @@ import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; import com.simibubi.create.foundation.render.CachedPartialBuffers; import com.simibubi.create.foundation.render.ShadowRenderHelper; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import net.createmod.catnip.render.SpriteShiftEntry; import net.createmod.catnip.render.SuperByteBuffer; @@ -40,23 +40,23 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -public class BeltRenderer extends SafeTileEntityRenderer { +public class BeltRenderer extends SafeBlockEntityRenderer { public BeltRenderer(BlockEntityRendererProvider.Context context) { } @Override - public boolean shouldRenderOffScreen(BeltTileEntity te) { - return te.isController(); + public boolean shouldRenderOffScreen(BeltBlockEntity be) { + return be.isController(); } @Override - protected void renderSafe(BeltTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(BeltBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - if (!Backend.canUseInstancing(te.getLevel())) { + if (!Backend.canUseInstancing(be.getLevel())) { - BlockState blockState = te.getBlockState(); + BlockState blockState = be.getBlockState(); if (!AllBlocks.BELT.has(blockState)) return; BeltSlope beltSlope = blockState.getValue(BeltBlock.SLOPE); @@ -75,7 +75,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { PoseStack localTransforms = new PoseStack(); TransformStack msr = TransformStack.cast(localTransforms); VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - float renderTick = WorldTickHolder.getRenderTime(te.getLevel()); + float renderTick = WorldTickHolder.getRenderTime(be.getLevel()); msr.centre() .rotateY(AngleHelper.horizontalAngle(facing) + (upward ? 180 : 0) + (sideways ? 270 : 0)) @@ -89,7 +89,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { end = b; } - DyeColor color = te.color.orElse(null); + DyeColor color = be.color.orElse(null); for (boolean bottom : Iterate.trueAndFalse) { @@ -101,8 +101,8 @@ public class BeltRenderer extends SafeTileEntityRenderer { SpriteShiftEntry spriteShift = getSpriteShiftEntry(color, diagonal, bottom); // UV shift - float speed = te.getSpeed(); - if (speed != 0 || te.color.isPresent()) { + float speed = be.getSpeed(); + if (speed != 0 || be.color.isPresent()) { float time = renderTick * axisDirection.getStep(); if (diagonal && (downward ^ alongX) || !sideways && !diagonal && alongX || sideways && axisDirection == AxisDirection.NEGATIVE) speed = -speed; @@ -126,7 +126,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { if (diagonal) break; } - if (te.hasPulley()) { + if (be.hasPulley()) { Direction dir = sideways ? Direction.UP : blockState.getValue(BeltBlock.HORIZONTAL_FACING).getClockWise(); Supplier matrixStackSupplier = () -> { @@ -140,12 +140,12 @@ public class BeltRenderer extends SafeTileEntityRenderer { return stack; }; - SuperByteBuffer superBuffer = CachedPartialBuffers.partialDirectional(AllBlockPartials.BELT_PULLEY, blockState, dir, matrixStackSupplier); - KineticTileEntityRenderer.standardKineticRotationTransform(superBuffer, te, light).renderInto(ms, vb); + SuperByteBuffer superBuffer = CachedPartialBuffers.partialDirectional(AllPartialModels.BELT_PULLEY, blockState, dir, matrixStackSupplier); + KineticBlockEntityRenderer.standardKineticRotationTransform(superBuffer, be, light).renderInto(ms, vb); } } - renderItems(te, partialTicks, ms, buffer, light, overlay); + renderItems(be, partialTicks, ms, buffer, light, overlay); } public static SpriteShiftEntry getSpriteShiftEntry(DyeColor color, boolean diagonal, boolean bottom) { @@ -159,44 +159,44 @@ public class BeltRenderer extends SafeTileEntityRenderer { public static PartialModel getBeltPartial(boolean diagonal, boolean start, boolean end, boolean bottom) { if (diagonal) { - if (start) return AllBlockPartials.BELT_DIAGONAL_START; - if (end) return AllBlockPartials.BELT_DIAGONAL_END; - return AllBlockPartials.BELT_DIAGONAL_MIDDLE; + if (start) return AllPartialModels.BELT_DIAGONAL_START; + if (end) return AllPartialModels.BELT_DIAGONAL_END; + return AllPartialModels.BELT_DIAGONAL_MIDDLE; } else if (bottom) { - if (start) return AllBlockPartials.BELT_START_BOTTOM; - if (end) return AllBlockPartials.BELT_END_BOTTOM; - return AllBlockPartials.BELT_MIDDLE_BOTTOM; + if (start) return AllPartialModels.BELT_START_BOTTOM; + if (end) return AllPartialModels.BELT_END_BOTTOM; + return AllPartialModels.BELT_MIDDLE_BOTTOM; } else { - if (start) return AllBlockPartials.BELT_START; - if (end) return AllBlockPartials.BELT_END; - return AllBlockPartials.BELT_MIDDLE; + if (start) return AllPartialModels.BELT_START; + if (end) return AllPartialModels.BELT_END; + return AllPartialModels.BELT_MIDDLE; } } - protected void renderItems(BeltTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderItems(BeltBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - if (!te.isController()) + if (!be.isController()) return; - if (te.beltLength == 0) + if (be.beltLength == 0) return; ms.pushPose(); - Direction beltFacing = te.getBeltFacing(); + Direction beltFacing = be.getBeltFacing(); Vec3i directionVec = beltFacing .getNormal(); Vec3 beltStartOffset = Vec3.atLowerCornerOf(directionVec).scale(-.5) .add(.5, 15 / 16f, .5); ms.translate(beltStartOffset.x, beltStartOffset.y, beltStartOffset.z); - BeltSlope slope = te.getBlockState() + BeltSlope slope = be.getBlockState() .getValue(BeltBlock.SLOPE); int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0; boolean slopeAlongX = beltFacing .getAxis() == Axis.X; - boolean onContraption = te.getLevel() instanceof WrappedWorld; + boolean onContraption = be.getLevel() instanceof WrappedWorld; - for (TransportedItemStack transported : te.getInventory() + for (TransportedItemStack transported : be.getInventory() .getTransportedItems()) { ms.pushPose(); TransformStack.cast(ms) @@ -206,7 +206,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { float sideOffset; float verticalMovement; - if (te.getSpeed() == 0) { + if (be.getSpeed() == 0) { offset = transported.beltPosition; sideOffset = transported.sideOffset; } else { @@ -217,12 +217,12 @@ public class BeltRenderer extends SafeTileEntityRenderer { if (offset < .5) verticalMovement = 0; else - verticalMovement = verticality * (Math.min(offset, te.beltLength - .5f) - .5f); + verticalMovement = verticality * (Math.min(offset, be.beltLength - .5f) - .5f); Vec3 offsetVec = Vec3.atLowerCornerOf(directionVec).scale(offset); if (verticalMovement != 0) offsetVec = offsetVec.add(0, verticalMovement, 0); boolean onSlope = - slope != BeltSlope.HORIZONTAL && Mth.clamp(offset, .5f, te.beltLength - .5f) == offset; + slope != BeltSlope.HORIZONTAL && Mth.clamp(offset, .5f, be.beltLength - .5f) == offset; boolean tiltForward = (slope == BeltSlope.DOWNWARD ^ beltFacing .getAxisDirection() == AxisDirection.POSITIVE) == (beltFacing .getAxis() == Axis.Z); @@ -237,11 +237,11 @@ public class BeltRenderer extends SafeTileEntityRenderer { sideOffset *= -1; ms.translate(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset); - int stackLight = onContraption ? light : getPackedLight(te, offset); + int stackLight = onContraption ? light : getPackedLight(be, offset); ItemRenderer itemRenderer = Minecraft.getInstance() .getItemRenderer(); boolean renderUpright = BeltHelper.isItemUpright(transported.stack); - boolean blockItem = itemRenderer.getModel(transported.stack, te.getLevel(), null, 0) + boolean blockItem = itemRenderer.getModel(transported.stack, be.getLevel(), null, 0) .isGui3d(); int count = (int) (Mth.log2((int) (transported.stack.getCount()))) / 2; Random r = new Random(transported.angle); @@ -267,7 +267,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { Entity renderViewEntity = Minecraft.getInstance().cameraEntity; if (renderViewEntity != null) { Vec3 positionVec = renderViewEntity.position(); - Vec3 vectorForOffset = BeltHelper.getVectorForOffset(te, offset); + Vec3 vectorForOffset = BeltHelper.getVectorForOffset(be, offset); Vec3 diff = vectorForOffset.subtract(positionVec); float yRot = (float) (Mth.atan2(diff.x, diff.z) + Math.PI); ms.mulPose(Vector3f.YP.rotation(yRot)); @@ -289,7 +289,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { } ms.scale(.5f, .5f, .5f); - itemRenderer.renderStatic(null, transported.stack, TransformType.FIXED, false, ms, buffer, te.getLevel(), stackLight, overlay, 0); + itemRenderer.renderStatic(null, transported.stack, TransformType.FIXED, false, ms, buffer, be.getLevel(), stackLight, overlay, 0); ms.popPose(); if (!renderUpright) { @@ -306,7 +306,7 @@ public class BeltRenderer extends SafeTileEntityRenderer { ms.popPose(); } - protected int getPackedLight(BeltTileEntity controller, float beltPos) { + protected int getPackedLight(BeltBlockEntity controller, float beltPos) { int segment = (int) Math.floor(beltPos); if (controller.lighter == null || segment >= controller.lighter.lightSegments() || segment < 0) return 0; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltShapes.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltShapes.java similarity index 99% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltShapes.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltShapes.java index 382d440ca7..634bef5d80 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltShapes.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltShapes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import static net.minecraft.world.level.block.Block.box; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlicer.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlicer.java index abe3394602..ed4fe5f12c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlicer.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlicer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import java.util.ArrayList; import java.util.Iterator; @@ -7,11 +7,12 @@ import java.util.Optional; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; -import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem; -import com.simibubi.create.content.contraptions.relays.belt.transport.BeltInventory; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity.CasingType; +import com.simibubi.create.content.kinetics.belt.item.BeltConnectorItem; +import com.simibubi.create.content.kinetics.belt.transport.BeltInventory; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.CatnipClient; @@ -53,8 +54,8 @@ public class BeltSlicer { public static InteractionResult useWrench(BlockState state, Level world, BlockPos pos, Player player, InteractionHand handIn, BlockHitResult hit, Feedback feedBack) { - BeltTileEntity controllerTE = BeltHelper.getControllerTE(world, pos); - if (controllerTE == null) + BeltBlockEntity controllerBE = BeltHelper.getControllerBE(world, pos); + if (controllerBE == null) return InteractionResult.PASS; if (state.getValue(BeltBlock.CASING) && hit.getDirection() != Direction.UP) return InteractionResult.PASS; @@ -62,13 +63,13 @@ public class BeltSlicer { .getAxis() != Axis.Y) return InteractionResult.PASS; - int beltLength = controllerTE.beltLength; + int beltLength = controllerBE.beltLength; if (beltLength == 2) return InteractionResult.FAIL; BlockPos beltVector = new BlockPos(BeltHelper.getBeltVector(state)); BeltPart part = state.getValue(BeltBlock.PART); - List beltChain = BeltBlock.getBeltChain(world, controllerTE.getBlockPos()); + List beltChain = BeltBlock.getBeltChain(world, controllerBE.getBlockPos()); boolean creative = player.isCreative(); // Shorten from End @@ -77,7 +78,7 @@ public class BeltSlicer { return InteractionResult.SUCCESS; for (BlockPos blockPos : beltChain) { - BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + BeltBlockEntity belt = BeltHelper.getSegmentBE(world, blockPos); if (belt == null) continue; belt.detachKinetics(); @@ -85,13 +86,14 @@ public class BeltSlicer { belt.beltLength = 0; } - BeltInventory inventory = controllerTE.inventory; + BeltInventory inventory = controllerBE.inventory; BlockPos next = part == BeltPart.END ? pos.subtract(beltVector) : pos.offset(beltVector); BlockState replacedState = world.getBlockState(next); - BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); - KineticTileEntity.switchToBlockState(world, next, - state.setValue(BeltBlock.CASING, segmentTE != null && segmentTE.casing != CasingType.NONE)); - world.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL | Block.UPDATE_MOVE_BY_PISTON); + BeltBlockEntity segmentBE = BeltHelper.getSegmentBE(world, next); + KineticBlockEntity.switchToBlockState(world, next, ProperWaterloggedBlock.withWater(world, + state.setValue(BeltBlock.CASING, segmentBE != null && segmentBE.casing != CasingType.NONE), next)); + world.setBlock(pos, ProperWaterloggedBlock.withWater(world, Blocks.AIR.defaultBlockState(), pos), + Block.UPDATE_ALL | Block.UPDATE_MOVE_BY_PISTON); world.removeBlockEntity(pos); world.levelEvent(2001, pos, Block.getId(state)); @@ -110,10 +112,10 @@ public class BeltSlicer { } // Transfer items to new controller - if (part == BeltPart.START && segmentTE != null && inventory != null) { - controllerTE.inventory = null; - segmentTE.inventory = null; - segmentTE.setController(next); + if (part == BeltPart.START && segmentBE != null && inventory != null) { + controllerBE.inventory = null; + segmentBE.inventory = null; + segmentBE.setController(next); for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { transportedItemStack.beltPosition -= 1; if (transportedItemStack.beltPosition <= 0) { @@ -124,7 +126,7 @@ public class BeltSlicer { entity.hurtMarked = true; world.addFreshEntity(entity); } else - segmentTE.getInventory() + segmentBE.getInventory() .addItem(transportedItemStack); } } @@ -132,12 +134,12 @@ public class BeltSlicer { return InteractionResult.SUCCESS; } - BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, pos); - if (segmentTE == null) + BeltBlockEntity segmentBE = BeltHelper.getSegmentBE(world, pos); + if (segmentBE == null) return InteractionResult.PASS; // Split in half - int hitSegment = segmentTE.index; + int hitSegment = segmentBE.index; Vec3 centerOf = VecHelper.getCenterOf(hit.getBlockPos()); Vec3 subtract = hit.getLocation() .subtract(centerOf); @@ -146,13 +148,13 @@ public class BeltSlicer { if (hitSegment == 0 || hitSegment == 1 && !towardPositive) return InteractionResult.FAIL; - if (hitSegment == controllerTE.beltLength - 1 || hitSegment == controllerTE.beltLength - 2 && towardPositive) + if (hitSegment == controllerBE.beltLength - 1 || hitSegment == controllerBE.beltLength - 2 && towardPositive) return InteractionResult.FAIL; // Look for shafts if (!creative) { int requiredShafts = 0; - if (!segmentTE.hasPulley()) + if (!segmentBE.hasPulley()) requiredShafts++; BlockState other = world.getBlockState(next); if (AllBlocks.BELT.has(other) && other.getValue(BeltBlock.PART) == BeltPart.MIDDLE) @@ -196,7 +198,7 @@ public class BeltSlicer { if (!world.isClientSide) { for (BlockPos blockPos : beltChain) { - BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + BeltBlockEntity belt = BeltHelper.getSegmentBE(world, blockPos); if (belt == null) continue; belt.detachKinetics(); @@ -204,16 +206,16 @@ public class BeltSlicer { belt.beltLength = 0; } - BeltInventory inventory = controllerTE.inventory; - KineticTileEntity.switchToBlockState(world, pos, + BeltInventory inventory = controllerBE.inventory; + KineticBlockEntity.switchToBlockState(world, pos, state.setValue(BeltBlock.PART, towardPositive ? BeltPart.END : BeltPart.START)); - KineticTileEntity.switchToBlockState(world, next, world.getBlockState(next) + KineticBlockEntity.switchToBlockState(world, next, world.getBlockState(next) .setValue(BeltBlock.PART, towardPositive ? BeltPart.START : BeltPart.END)); world.playSound(null, pos, SoundEvents.WOOL_HIT, player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS, 0.5F, 2.3F); // Transfer items to new controller - BeltTileEntity newController = towardPositive ? BeltHelper.getSegmentTE(world, next) : segmentTE; + BeltBlockEntity newController = towardPositive ? BeltHelper.getSegmentBE(world, next) : segmentBE; if (newController != null && inventory != null) { newController.inventory = null; newController.setController(newController.getBlockPos()); @@ -236,25 +238,25 @@ public class BeltSlicer { public static InteractionResult useConnector(BlockState state, Level world, BlockPos pos, Player player, InteractionHand handIn, BlockHitResult hit, Feedback feedBack) { - BeltTileEntity controllerTE = BeltHelper.getControllerTE(world, pos); - if (controllerTE == null) + BeltBlockEntity controllerBE = BeltHelper.getControllerBE(world, pos); + if (controllerBE == null) return InteractionResult.PASS; - int beltLength = controllerTE.beltLength; + int beltLength = controllerBE.beltLength; if (beltLength == BeltConnectorItem.maxLength()) return InteractionResult.FAIL; BlockPos beltVector = new BlockPos(BeltHelper.getBeltVector(state)); BeltPart part = state.getValue(BeltBlock.PART); Direction facing = state.getValue(BeltBlock.HORIZONTAL_FACING); - List beltChain = BeltBlock.getBeltChain(world, controllerTE.getBlockPos()); + List beltChain = BeltBlock.getBeltChain(world, controllerBE.getBlockPos()); boolean creative = player.isCreative(); if (!hoveringEnd(state, hit)) return InteractionResult.PASS; BlockPos next = part == BeltPart.START ? pos.subtract(beltVector) : pos.offset(beltVector); - BeltTileEntity mergedController = null; + BeltBlockEntity mergedController = null; int mergedBeltLength = 0; // Merge Belts / Extend at End @@ -266,7 +268,7 @@ public class BeltSlicer { if (!beltStatesCompatible(state, nextState)) return InteractionResult.FAIL; - mergedController = BeltHelper.getControllerTE(world, next); + mergedController = BeltHelper.getControllerBE(world, next); if (mergedController == null) return InteractionResult.FAIL; if (mergedController.beltLength + beltLength > BeltConnectorItem.maxLength()) @@ -276,9 +278,9 @@ public class BeltSlicer { if (!world.isClientSide) { boolean flipBelt = facing != nextState.getValue(BeltBlock.HORIZONTAL_FACING); - Optional color = controllerTE.color; + Optional color = controllerBE.color; for (BlockPos blockPos : BeltBlock.getBeltChain(world, mergedController.getBlockPos())) { - BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + BeltBlockEntity belt = BeltHelper.getSegmentBE(world, blockPos); if (belt == null) continue; belt.detachKinetics(); @@ -303,7 +305,7 @@ public class BeltSlicer { if (!world.isClientSide) { for (BlockPos blockPos : beltChain) { - BeltTileEntity belt = BeltHelper.getSegmentTE(world, blockPos); + BeltBlockEntity belt = BeltHelper.getSegmentBE(world, blockPos); if (belt == null) continue; belt.detachKinetics(); @@ -311,24 +313,26 @@ public class BeltSlicer { belt.beltLength = 0; } - BeltInventory inventory = controllerTE.inventory; - KineticTileEntity.switchToBlockState(world, pos, state.setValue(BeltBlock.PART, BeltPart.MIDDLE)); + BeltInventory inventory = controllerBE.inventory; + KineticBlockEntity.switchToBlockState(world, pos, state.setValue(BeltBlock.PART, BeltPart.MIDDLE)); if (mergedController == null) { // Attach at end - world.setBlock(next, state.setValue(BeltBlock.CASING, false), Block.UPDATE_ALL | Block.UPDATE_MOVE_BY_PISTON); - BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); - if (segmentTE != null) - segmentTE.color = controllerTE.color; + world.setBlock(next, + ProperWaterloggedBlock.withWater(world, state.setValue(BeltBlock.CASING, false), next), + Block.UPDATE_ALL | Block.UPDATE_MOVE_BY_PISTON); + BeltBlockEntity segmentBE = BeltHelper.getSegmentBE(world, next); + if (segmentBE != null) + segmentBE.color = controllerBE.color; world.playSound(null, pos, SoundEvents.WOOL_PLACE, player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS, 0.5F, 1F); // Transfer items to new controller - if (part == BeltPart.START && segmentTE != null && inventory != null) { - segmentTE.setController(next); + if (part == BeltPart.START && segmentBE != null && inventory != null) { + segmentBE.setController(next); for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { transportedItemStack.beltPosition += 1; - segmentTE.getInventory() + segmentBE.getInventory() .addItem(transportedItemStack); } } @@ -338,9 +342,9 @@ public class BeltSlicer { BeltInventory mergedInventory = mergedController.inventory; world.playSound(null, pos, SoundEvents.WOOL_HIT, player == null ? SoundSource.BLOCKS : SoundSource.PLAYERS, 0.5F, 1.3F); - BeltTileEntity segmentTE = BeltHelper.getSegmentTE(world, next); - KineticTileEntity.switchToBlockState(world, next, - state.setValue(BeltBlock.CASING, segmentTE != null && segmentTE.casing != CasingType.NONE) + BeltBlockEntity segmentBE = BeltHelper.getSegmentBE(world, next); + KineticBlockEntity.switchToBlockState(world, next, + state.setValue(BeltBlock.CASING, segmentBE != null && segmentBE.casing != CasingType.NONE) .setValue(BeltBlock.PART, BeltPart.MIDDLE)); if (!creative) { @@ -349,7 +353,7 @@ public class BeltSlicer { } // Transfer items to other controller - BlockPos search = controllerTE.getBlockPos(); + BlockPos search = controllerBE.getBlockPos(); for (int i = 0; i < 10000; i++) { BlockState blockState = world.getBlockState(search); if (!AllBlocks.BELT.has(blockState)) @@ -359,11 +363,11 @@ public class BeltSlicer { continue; } - BeltTileEntity newController = BeltHelper.getSegmentTE(world, search); + BeltBlockEntity newController = BeltHelper.getSegmentBE(world, search); - if (newController != controllerTE && inventory != null) { + if (newController != controllerBE && inventory != null) { newController.setController(search); - controllerTE.inventory = null; + controllerBE.inventory = null; for (TransportedItemStack transportedItemStack : inventory.getTransportedItems()) { transportedItemStack.beltPosition += mergedBeltLength; newController.getInventory() @@ -375,7 +379,7 @@ public class BeltSlicer { newController.setController(search); mergedController.inventory = null; for (TransportedItemStack transportedItemStack : mergedInventory.getTransportedItems()) { - if (newController == controllerTE) + if (newController == controllerBE) transportedItemStack.beltPosition += beltLength; newController.getInventory() .addItem(transportedItemStack); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlope.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlope.java index 71445af0b2..5f60199ca4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltSlope.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/BeltSlope.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt; +package com.simibubi.create.content.kinetics.belt; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.util.StringRepresentable; diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/BeltProcessingBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/BeltProcessingBehaviour.java new file mode 100644 index 0000000000..adfb35e394 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/BeltProcessingBehaviour.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.kinetics.belt.behaviour; + +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.funnel.AbstractFunnelBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; + +/** + * Behaviour for BlockEntities which can process items on belts or depots beneath + * them. Currently only supports placement location 2 spaces above the belt + * block. Example use: Mechanical Press + */ +public class BeltProcessingBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + public static enum ProcessingResult { + PASS, HOLD, REMOVE; + } + + private ProcessingCallback onItemEnter; + private ProcessingCallback continueProcessing; + + public BeltProcessingBehaviour(SmartBlockEntity be) { + super(be); + onItemEnter = (s, i) -> ProcessingResult.PASS; + continueProcessing = (s, i) -> ProcessingResult.PASS; + } + + public BeltProcessingBehaviour whenItemEnters(ProcessingCallback callback) { + onItemEnter = callback; + return this; + } + + public BeltProcessingBehaviour whileItemHeld(ProcessingCallback callback) { + continueProcessing = callback; + return this; + } + + public static boolean isBlocked(BlockGetter world, BlockPos processingSpace) { + BlockState blockState = world.getBlockState(processingSpace.above()); + if (AbstractFunnelBlock.isFunnel(blockState)) + return false; + return !blockState.getCollisionShape(world, processingSpace.above()) + .isEmpty(); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + public ProcessingResult handleReceivedItem(TransportedItemStack stack, + TransportedItemStackHandlerBehaviour inventory) { + return onItemEnter.apply(stack, inventory); + } + + public ProcessingResult handleHeldItem(TransportedItemStack stack, TransportedItemStackHandlerBehaviour inventory) { + return continueProcessing.apply(stack, inventory); + } + + @FunctionalInterface + public interface ProcessingCallback { + public ProcessingResult apply(TransportedItemStack stack, TransportedItemStackHandlerBehaviour inventory); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java new file mode 100644 index 0000000000..f48f69cf09 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/DirectBeltInputBehaviour.java @@ -0,0 +1,128 @@ +package com.simibubi.create.content.kinetics.belt.behaviour; + +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.content.logistics.funnel.FunnelBlockEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +/** + * Behaviour for BlockEntities to which belts can transfer items directly in a + * backup-friendly manner. Example uses: Basin, Saw, Depot + */ +public class DirectBeltInputBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + private InsertionCallback tryInsert; + private AvailabilityPredicate canInsert; + private Supplier supportsBeltFunnels; + + public DirectBeltInputBehaviour(SmartBlockEntity be) { + super(be); + tryInsert = this::defaultInsertionCallback; + canInsert = d -> true; + supportsBeltFunnels = () -> false; + } + + public DirectBeltInputBehaviour allowingBeltFunnelsWhen(Supplier pred) { + supportsBeltFunnels = pred; + return this; + } + + public DirectBeltInputBehaviour allowingBeltFunnels() { + supportsBeltFunnels = () -> true; + return this; + } + + public DirectBeltInputBehaviour onlyInsertWhen(AvailabilityPredicate pred) { + canInsert = pred; + return this; + } + + public DirectBeltInputBehaviour setInsertionHandler(InsertionCallback callback) { + tryInsert = callback; + return this; + } + + private ItemStack defaultInsertionCallback(TransportedItemStack inserted, Direction side, boolean simulate) { + LazyOptional lazy = blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side); + if (!lazy.isPresent()) + return inserted.stack; + return ItemHandlerHelper.insertItemStacked(lazy.orElse(null), inserted.stack.copy(), simulate); + } + + // TODO: verify that this side is consistent across all calls + public boolean canInsertFromSide(Direction side) { + return canInsert.test(side); + } + + public ItemStack handleInsertion(ItemStack stack, Direction side, boolean simulate) { + return handleInsertion(new TransportedItemStack(stack), side, simulate); + } + + public ItemStack handleInsertion(TransportedItemStack stack, Direction side, boolean simulate) { + return tryInsert.apply(stack, side, simulate); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + @FunctionalInterface + public interface InsertionCallback { + public ItemStack apply(TransportedItemStack stack, Direction side, boolean simulate); + } + + @FunctionalInterface + public interface AvailabilityPredicate { + public boolean test(Direction side); + } + + @Nullable + public ItemStack tryExportingToBeltFunnel(ItemStack stack, @Nullable Direction side, boolean simulate) { + BlockPos funnelPos = blockEntity.getBlockPos() + .above(); + Level world = getWorld(); + BlockState funnelState = world.getBlockState(funnelPos); + if (!(funnelState.getBlock() instanceof BeltFunnelBlock)) + return null; + if (funnelState.getValue(BeltFunnelBlock.SHAPE) != Shape.PULLING) + return null; + if (side != null && FunnelBlock.getFunnelFacing(funnelState) != side) + return null; + BlockEntity be = world.getBlockEntity(funnelPos); + if (!(be instanceof FunnelBlockEntity)) + return null; + if (funnelState.getValue(BeltFunnelBlock.POWERED)) + return stack; + ItemStack insert = FunnelBlock.tryInsert(world, funnelPos, stack, simulate); + if (insert.getCount() != stack.getCount() && !simulate) + ((FunnelBlockEntity) be).flap(true); + return insert; + } + + public boolean canSupportBeltFunnels() { + return supportsBeltFunnels.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/TransportedItemStackHandlerBehaviour.java similarity index 85% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/TransportedItemStackHandlerBehaviour.java index 9e745a4723..78623613f1 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/belt/TransportedItemStackHandlerBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/behaviour/TransportedItemStackHandlerBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.tileEntity.behaviour.belt; +package com.simibubi.create.content.kinetics.belt.behaviour; import java.util.List; import java.util.function.Function; @@ -6,16 +6,16 @@ import java.util.function.Function; import javax.annotation.Nullable; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.VecHelper; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; -public class TransportedItemStackHandlerBehaviour extends TileEntityBehaviour { +public class TransportedItemStackHandlerBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); @@ -84,10 +84,10 @@ public class TransportedItemStackHandlerBehaviour extends TileEntityBehaviour { } - public TransportedItemStackHandlerBehaviour(SmartTileEntity te, ProcessingCallback processingCallback) { - super(te); + public TransportedItemStackHandlerBehaviour(SmartBlockEntity be, ProcessingCallback processingCallback) { + super(be); this.processingCallback = processingCallback; - positionGetter = t -> VecHelper.getCenterOf(te.getBlockPos()); + positionGetter = t -> VecHelper.getCenterOf(be.getBlockPos()); } public TransportedItemStackHandlerBehaviour withStackPlacement(PositionGetter function) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorHandler.java b/src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorHandler.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorHandler.java index 14dbf2d309..5bd56d5368 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt.item; +package com.simibubi.create.content.kinetics.belt.item; import java.util.LinkedList; import java.util.List; @@ -6,8 +6,8 @@ import java.util.Random; import com.mojang.math.Vector3f; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; @@ -75,7 +75,7 @@ public class BeltConnectorHandler { return; if (!ShaftBlock.isShaft(world.getBlockState(selected))) selected = selected.relative(((BlockHitResult) rayTrace).getDirection()); - if (!selected.closerThan(first, AllConfigs.SERVER.kinetics.maxBeltLength.get())) + if (!selected.closerThan(first, AllConfigs.server().kinetics.maxBeltLength.get())) return; boolean canConnect = diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java b/src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorItem.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorItem.java index 6d808ccd79..f6d189b93e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/item/BeltConnectorItem.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/item/BeltConnectorItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt.item; +package com.simibubi.create.content.kinetics.belt.item; import java.util.LinkedList; import java.util.List; @@ -6,15 +6,16 @@ import java.util.List; import javax.annotation.Nonnull; import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltPart; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.elementary.AbstractSimpleShaftBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.AllCreativeModeTabs; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltPart; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -49,10 +50,10 @@ public class BeltConnectorItem extends BlockItem { } @Override - public void fillItemCategory(CreativeModeTab p_150895_1_, NonNullList p_150895_2_) { - if (p_150895_1_ == Create.BASE_CREATIVE_TAB) - return; - super.fillItemCategory(p_150895_1_, p_150895_2_); + public void fillItemCategory(CreativeModeTab pGroup, NonNullList pItems) { + // See CogWheelBlock.fillItemCategory() + if (pGroup != AllCreativeModeTabs.BASE_CREATIVE_TAB) + super.fillItemCategory(pGroup, pItems); } @Nonnull @@ -155,9 +156,10 @@ public class BeltConnectorItem extends BlockItem { .isReplaceable()) world.destroyBlock(pos, false); - KineticTileEntity.switchToBlockState(world, pos, beltBlock.setValue(BeltBlock.SLOPE, slope) - .setValue(BeltBlock.PART, part) - .setValue(BeltBlock.HORIZONTAL_FACING, facing)); + KineticBlockEntity.switchToBlockState(world, pos, + ProperWaterloggedBlock.withWater(world, beltBlock.setValue(BeltBlock.SLOPE, slope) + .setValue(BeltBlock.PART, part) + .setValue(BeltBlock.HORIZONTAL_FACING, facing), pos)); } if (!failed) @@ -243,16 +245,16 @@ public class BeltConnectorItem extends BlockItem { if (shaftAxis == Axis.Y && x != 0 && z != 0) return false; - BlockEntity tileEntity = world.getBlockEntity(first); - BlockEntity tileEntity2 = world.getBlockEntity(second); + BlockEntity blockEntity = world.getBlockEntity(first); + BlockEntity blockEntity2 = world.getBlockEntity(second); - if (!(tileEntity instanceof KineticTileEntity)) + if (!(blockEntity instanceof KineticBlockEntity)) return false; - if (!(tileEntity2 instanceof KineticTileEntity)) + if (!(blockEntity2 instanceof KineticBlockEntity)) return false; - float speed1 = ((KineticTileEntity) tileEntity).getTheoreticalSpeed(); - float speed2 = ((KineticTileEntity) tileEntity2).getTheoreticalSpeed(); + float speed1 = ((KineticBlockEntity) blockEntity).getTheoreticalSpeed(); + float speed2 = ((KineticBlockEntity) blockEntity2).getTheoreticalSpeed(); if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0) return false; @@ -273,7 +275,7 @@ public class BeltConnectorItem extends BlockItem { } public static Integer maxLength() { - return AllConfigs.SERVER.kinetics.maxBeltLength.get(); + return AllConfigs.server().kinetics.maxBeltLength.get(); } public static boolean validateAxis(Level world, BlockPos pos) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltCrusherInteractionHandler.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltCrusherInteractionHandler.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltCrusherInteractionHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltCrusherInteractionHandler.java index ea8f9e8d6f..a710973de6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltCrusherInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltCrusherInteractionHandler.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; +package com.simibubi.create.content.kinetics.belt.transport; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerBlock; -import com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelControllerBlock; +import com.simibubi.create.content.kinetics.crusher.CrushingWheelControllerBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -46,15 +46,15 @@ public class BeltCrusherInteractionHandler { return false; currentItem.beltPosition = crusherEntry; - BlockEntity te = world.getBlockEntity(crusherPos); - if (!(te instanceof CrushingWheelControllerTileEntity)) + BlockEntity be = world.getBlockEntity(crusherPos); + if (!(be instanceof CrushingWheelControllerBlockEntity)) return true; - CrushingWheelControllerTileEntity crusherTE = (CrushingWheelControllerTileEntity) te; + CrushingWheelControllerBlockEntity crusherBE = (CrushingWheelControllerBlockEntity) be; ItemStack toInsert = currentItem.stack.copy(); - ItemStack remainder = ItemHandlerHelper.insertItemStacked(crusherTE.inventory, toInsert, false); + ItemStack remainder = ItemHandlerHelper.insertItemStacked(crusherBE.inventory, toInsert, false); if (toInsert.equals(remainder, false)) return true; diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltFunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltFunnelInteractionHandler.java new file mode 100644 index 0000000000..db37e8afb2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltFunnelInteractionHandler.java @@ -0,0 +1,121 @@ +package com.simibubi.create.content.kinetics.belt.transport; + +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.content.logistics.funnel.FunnelBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.items.ItemHandlerHelper; + +public class BeltFunnelInteractionHandler { + + public static boolean checkForFunnels(BeltInventory beltInventory, TransportedItemStack currentItem, + float nextOffset) { + boolean beltMovementPositive = beltInventory.beltMovementPositive; + int firstUpcomingSegment = (int) Math.floor(currentItem.beltPosition); + int step = beltMovementPositive ? 1 : -1; + firstUpcomingSegment = Mth.clamp(firstUpcomingSegment, 0, beltInventory.belt.beltLength - 1); + + for (int segment = firstUpcomingSegment; beltMovementPositive ? segment <= nextOffset + : segment + 1 >= nextOffset; segment += step) { + BlockPos funnelPos = BeltHelper.getPositionForOffset(beltInventory.belt, segment) + .above(); + Level world = beltInventory.belt.getLevel(); + BlockState funnelState = world.getBlockState(funnelPos); + if (!(funnelState.getBlock() instanceof BeltFunnelBlock)) + continue; + Direction funnelFacing = funnelState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); + Direction movementFacing = beltInventory.belt.getMovementFacing(); + boolean blocking = funnelFacing == movementFacing.getOpposite(); + if (funnelFacing == movementFacing) + continue; + if (funnelState.getValue(BeltFunnelBlock.SHAPE) == Shape.PUSHING) + continue; + + float funnelEntry = segment + .5f; + if (funnelState.getValue(BeltFunnelBlock.SHAPE) == Shape.EXTENDED) + funnelEntry += .499f * (beltMovementPositive ? -1 : 1); + + boolean hasCrossed = nextOffset > funnelEntry && beltMovementPositive + || nextOffset < funnelEntry && !beltMovementPositive; + if (!hasCrossed) + return false; + if (blocking) + currentItem.beltPosition = funnelEntry; + + if (world.isClientSide || funnelState.getOptionalValue(BeltFunnelBlock.POWERED).orElse(false)) + if (blocking) + return true; + else + continue; + + BlockEntity be = world.getBlockEntity(funnelPos); + if (!(be instanceof FunnelBlockEntity)) + return true; + + FunnelBlockEntity funnelBE = (FunnelBlockEntity) be; + InvManipulationBehaviour inserting = funnelBE.getBehaviour(InvManipulationBehaviour.TYPE); + FilteringBehaviour filtering = funnelBE.getBehaviour(FilteringBehaviour.TYPE); + + if (inserting == null || filtering != null && !filtering.test(currentItem.stack)) + if (blocking) + return true; + else + continue; + + int amountToExtract = funnelBE.getAmountToExtract(); + ExtractionCountMode modeToExtract = funnelBE.getModeToExtract(); + + ItemStack toInsert = currentItem.stack.copy(); + if (amountToExtract > toInsert.getCount() && modeToExtract != ExtractionCountMode.UPTO) + if (blocking) + return true; + else + continue; + + if (amountToExtract != -1 && modeToExtract != ExtractionCountMode.UPTO) { + toInsert.setCount(Math.min(amountToExtract, toInsert.getCount())); + ItemStack remainder = inserting.simulate() + .insert(toInsert); + if (!remainder.isEmpty()) + if (blocking) + return true; + else + continue; + } + + ItemStack remainder = inserting.insert(toInsert); + if (toInsert.equals(remainder, false)) + if (blocking) + return true; + else + continue; + + int notFilled = currentItem.stack.getCount() - toInsert.getCount(); + if (!remainder.isEmpty()) { + remainder.grow(notFilled); + } else if (notFilled > 0) + remainder = ItemHandlerHelper.copyStackWithSize(currentItem.stack, notFilled); + + funnelBE.flap(true); + funnelBE.onTransfer(toInsert); + currentItem.stack = remainder; + beltInventory.belt.sendData(); + if (blocking) + return true; + } + + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltInventory.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltInventory.java index dbfecf2e0c..42b0939f60 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltInventory.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltInventory.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; +package com.simibubi.create.content.kinetics.belt.transport; -import static com.simibubi.create.content.contraptions.relays.belt.transport.BeltTunnelInteractionHandler.flapTunnel; +import static com.simibubi.create.content.kinetics.belt.transport.BeltTunnelInteractionHandler.flapTunnel; import java.util.Collections; import java.util.Iterator; @@ -8,16 +8,16 @@ import java.util.LinkedList; import java.util.List; import java.util.function.Function; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.ServerSpeedProvider; @@ -33,15 +33,15 @@ import net.minecraft.world.phys.Vec3; public class BeltInventory { - final BeltTileEntity belt; + final BeltBlockEntity belt; private final List items; final List toInsert; final List toRemove; boolean beltMovementPositive; final float SEGMENT_WINDOW = .75f; - public BeltInventory(BeltTileEntity te) { - this.belt = te; + public BeltInventory(BeltBlockEntity be) { + this.belt = be; items = new LinkedList<>(); toInsert = new LinkedList<>(); toRemove = new LinkedList<>(); @@ -184,7 +184,7 @@ public class BeltInventory { if (ending == Ending.INSERT) { DirectBeltInputBehaviour inputBehaviour = - TileEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE); + BlockEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE); if (inputBehaviour == null) continue; if (!inputBehaviour.canInsertFromSide(movementFacing)) @@ -284,12 +284,12 @@ public class BeltInventory { } protected BeltProcessingBehaviour getBeltProcessingAtSegment(int segment) { - return TileEntityBehaviour.get(belt.getLevel(), BeltHelper.getPositionForOffset(belt, segment) + return BlockEntityBehaviour.get(belt.getLevel(), BeltHelper.getPositionForOffset(belt, segment) .above(2), BeltProcessingBehaviour.TYPE); } protected TransportedItemStackHandlerBehaviour getTransportedItemStackHandlerAtSegment(int segment) { - return TileEntityBehaviour.get(belt.getLevel(), BeltHelper.getPositionForOffset(belt, segment), + return BlockEntityBehaviour.get(belt.getLevel(), BeltHelper.getPositionForOffset(belt, segment), TransportedItemStackHandlerBehaviour.TYPE); } @@ -311,7 +311,7 @@ public class BeltInventory { // return Ending.FUNNEL; DirectBeltInputBehaviour inputBehaviour = - TileEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE); + BlockEntityBehaviour.get(world, nextPosition, DirectBeltInputBehaviour.TYPE); if (inputBehaviour != null) return Ending.INSERT; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltMovementHandler.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltMovementHandler.java index 2b2777af1d..059975478f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltMovementHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; +package com.simibubi.create.content.kinetics.belt.transport; import static net.minecraft.core.Direction.AxisDirection.NEGATIVE; import static net.minecraft.core.Direction.AxisDirection.POSITIVE; @@ -7,10 +7,10 @@ import static net.minecraft.world.entity.MoverType.SELF; import java.util.List; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltPart; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltPart; +import com.simibubi.create.content.kinetics.belt.BeltSlope; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -65,18 +65,18 @@ public class BeltMovementHandler { return true; } - public static void transportEntity(BeltTileEntity beltTe, Entity entityIn, TransportedEntityInfo info) { + public static void transportEntity(BeltBlockEntity beltBE, Entity entityIn, TransportedEntityInfo info) { BlockPos pos = info.lastCollidedPos; - Level world = beltTe.getLevel(); - BlockEntity te = world.getBlockEntity(pos); - BlockEntity tileEntityBelowPassenger = world.getBlockEntity(entityIn.blockPosition()); + Level world = beltBE.getLevel(); + BlockEntity be = world.getBlockEntity(pos); + BlockEntity blockEntityBelowPassenger = world.getBlockEntity(entityIn.blockPosition()); BlockState blockState = info.lastCollidedState; Direction movementFacing = Direction.fromAxisAndDirection(blockState.getValue(BlockStateProperties.HORIZONTAL_FACING) - .getAxis(), beltTe.getSpeed() < 0 ? POSITIVE : NEGATIVE); + .getAxis(), beltBE.getSpeed() < 0 ? POSITIVE : NEGATIVE); - boolean collidedWithBelt = te instanceof BeltTileEntity; - boolean betweenBelts = tileEntityBelowPassenger instanceof BeltTileEntity && tileEntityBelowPassenger != te; + boolean collidedWithBelt = be instanceof BeltBlockEntity; + boolean betweenBelts = blockEntityBelowPassenger instanceof BeltBlockEntity && blockEntityBelowPassenger != be; // Don't fight other Belts if (!collidedWithBelt || betweenBelts) { @@ -84,9 +84,9 @@ public class BeltMovementHandler { } // Too slow - boolean notHorizontal = beltTe.getBlockState() + boolean notHorizontal = beltBE.getBlockState() .getValue(BeltBlock.SLOPE) != BeltSlope.HORIZONTAL; - if (Math.abs(beltTe.getSpeed()) < 1) + if (Math.abs(beltBE.getSpeed()) < 1) return; // Not on top @@ -101,7 +101,7 @@ public class BeltMovementHandler { final Direction beltFacing = blockState.getValue(BlockStateProperties.HORIZONTAL_FACING); final BeltSlope slope = blockState.getValue(BeltBlock.SLOPE); final Axis axis = beltFacing.getAxis(); - float movementSpeed = beltTe.getBeltMovementSpeed(); + float movementSpeed = beltBE.getBeltMovementSpeed(); final Direction movementDirection = Direction.get(axis == Axis.X ? NEGATIVE : POSITIVE, axis); Vec3i centeringDirection = Direction.get(POSITIVE, beltFacing.getClockWise() diff --git a/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltTunnelInteractionHandler.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltTunnelInteractionHandler.java new file mode 100644 index 0000000000..975c749443 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/BeltTunnelInteractionHandler.java @@ -0,0 +1,160 @@ +package com.simibubi.create.content.kinetics.belt.transport; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlockEntity; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BrassTunnelBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.redstone.displayLink.source.AccumulatedItemCountDisplaySource; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.items.ItemHandlerHelper; + +public class BeltTunnelInteractionHandler { + + public static boolean flapTunnelsAndCheckIfStuck(BeltInventory beltInventory, TransportedItemStack current, + float nextOffset) { + + int currentSegment = (int) current.beltPosition; + int upcomingSegment = (int) nextOffset; + + Direction movementFacing = beltInventory.belt.getMovementFacing(); + if (!beltInventory.beltMovementPositive && nextOffset == 0) + upcomingSegment = -1; + if (currentSegment == upcomingSegment) + return false; + + if (stuckAtTunnel(beltInventory, upcomingSegment, current.stack, movementFacing)) { + current.beltPosition = currentSegment + (beltInventory.beltMovementPositive ? .99f : .01f); + return true; + } + + Level world = beltInventory.belt.getLevel(); + boolean onServer = !world.isClientSide || beltInventory.belt.isVirtual(); + boolean removed = false; + BeltTunnelBlockEntity nextTunnel = getTunnelOnSegment(beltInventory, upcomingSegment); + int transferred = current.stack.getCount(); + + if (nextTunnel instanceof BrassTunnelBlockEntity) { + BrassTunnelBlockEntity brassTunnel = (BrassTunnelBlockEntity) nextTunnel; + if (brassTunnel.hasDistributionBehaviour()) { + if (!brassTunnel.canTakeItems()) + return true; + if (onServer) { + brassTunnel.setStackToDistribute(current.stack, movementFacing.getOpposite()); + current.stack = ItemStack.EMPTY; + beltInventory.belt.sendData(); + beltInventory.belt.setChanged(); + } + removed = true; + } + } else if (nextTunnel != null) { + BlockState blockState = nextTunnel.getBlockState(); + if (current.stack.getCount() > 1 && AllBlocks.ANDESITE_TUNNEL.has(blockState) + && BeltTunnelBlock.isJunction(blockState) + && movementFacing.getAxis() == blockState.getValue(BeltTunnelBlock.HORIZONTAL_AXIS)) { + + for (Direction d : Iterate.horizontalDirections) { + if (d.getAxis() == blockState.getValue(BeltTunnelBlock.HORIZONTAL_AXIS)) + continue; + if (!nextTunnel.flaps.containsKey(d)) + continue; + BlockPos outpos = nextTunnel.getBlockPos() + .below() + .relative(d); + if (!world.isLoaded(outpos)) + return true; + DirectBeltInputBehaviour behaviour = + BlockEntityBehaviour.get(world, outpos, DirectBeltInputBehaviour.TYPE); + if (behaviour == null) + continue; + if (!behaviour.canInsertFromSide(d)) + continue; + + ItemStack toinsert = ItemHandlerHelper.copyStackWithSize(current.stack, 1); + if (!behaviour.handleInsertion(toinsert, d, false) + .isEmpty()) + return true; + if (onServer) + flapTunnel(beltInventory, upcomingSegment, d, false); + + current.stack.shrink(1); + beltInventory.belt.sendData(); + if (current.stack.getCount() <= 1) + break; + } + } + } + + if (onServer) { + flapTunnel(beltInventory, currentSegment, movementFacing, false); + flapTunnel(beltInventory, upcomingSegment, movementFacing.getOpposite(), true); + + if (nextTunnel != null) + DisplayLinkBlock.sendToGatherers(world, nextTunnel.getBlockPos(), + (dgte, b) -> b.itemReceived(dgte, transferred), AccumulatedItemCountDisplaySource.class); + } + + if (removed) + return true; + + return false; + } + + public static boolean stuckAtTunnel(BeltInventory beltInventory, int offset, ItemStack stack, + Direction movementDirection) { + BeltBlockEntity belt = beltInventory.belt; + BlockPos pos = BeltHelper.getPositionForOffset(belt, offset) + .above(); + if (!(belt.getLevel() + .getBlockState(pos) + .getBlock() instanceof BrassTunnelBlock)) + return false; + BlockEntity be = belt.getLevel() + .getBlockEntity(pos); + if (be == null || !(be instanceof BrassTunnelBlockEntity)) + return false; + BrassTunnelBlockEntity tunnel = (BrassTunnelBlockEntity) be; + return !tunnel.canInsert(movementDirection.getOpposite(), stack); + } + + public static void flapTunnel(BeltInventory beltInventory, int offset, Direction side, boolean inward) { + BeltTunnelBlockEntity be = getTunnelOnSegment(beltInventory, offset); + if (be == null) + return; + be.flap(side, inward); + } + + protected static BeltTunnelBlockEntity getTunnelOnSegment(BeltInventory beltInventory, int offset) { + BeltBlockEntity belt = beltInventory.belt; + if (belt.getBlockState() + .getValue(BeltBlock.SLOPE) != BeltSlope.HORIZONTAL) + return null; + return getTunnelOnPosition(belt.getLevel(), BeltHelper.getPositionForOffset(belt, offset)); + } + + public static BeltTunnelBlockEntity getTunnelOnPosition(Level world, BlockPos pos) { + pos = pos.above(); + if (!(world.getBlockState(pos) + .getBlock() instanceof BeltTunnelBlock)) + return null; + BlockEntity be = world.getBlockEntity(pos); + if (be == null || !(be instanceof BeltTunnelBlockEntity)) + return null; + return ((BeltTunnelBlockEntity) be); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/ItemHandlerBeltSegment.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/ItemHandlerBeltSegment.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/ItemHandlerBeltSegment.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/transport/ItemHandlerBeltSegment.java index b356d04eba..3395f93934 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/ItemHandlerBeltSegment.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/ItemHandlerBeltSegment.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; +package com.simibubi.create.content.kinetics.belt.transport; import net.minecraft.world.item.ItemStack; import net.minecraftforge.items.IItemHandler; @@ -52,6 +52,8 @@ public class ItemHandlerBeltSegment implements IItemHandler { amount = Math.min(amount, transported.stack.getCount()); ItemStack extracted = simulate ? transported.stack.copy().split(amount) : transported.stack.split(amount); if (!simulate) { + if (transported.stack.isEmpty()) + this.beltInventory.toRemove.add(transported); this.beltInventory.belt.setChanged(); this.beltInventory.belt.sendData(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/TransportedItemStack.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java rename to src/main/java/com/simibubi/create/content/kinetics/belt/transport/TransportedItemStack.java index becba0f918..aec7c61f8f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/TransportedItemStack.java +++ b/src/main/java/com/simibubi/create/content/kinetics/belt/transport/TransportedItemStack.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.relays.belt.transport; +package com.simibubi.create.content.kinetics.belt.transport; import java.util.Random; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.fan.FanProcessing; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -25,7 +25,7 @@ public class TransportedItemStack implements Comparable { public float prevBeltPosition; public float prevSideOffset; - public InWorldProcessing.Type processedBy; + public FanProcessing.Type processedBy; public int processingTime; public TransportedItemStack(ItemStack stack) { diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveBlock.java b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveBlock.java new file mode 100644 index 0000000000..c6252b61a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveBlock.java @@ -0,0 +1,275 @@ +package com.simibubi.create.content.kinetics.chainDrive; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.PushReaction; + +public class ChainDriveBlock extends RotatedPillarKineticBlock + implements IBE, ITransformableBlock { + + public static final Property PART = EnumProperty.create("part", Part.class); + public static final BooleanProperty CONNECTED_ALONG_FIRST_COORDINATE = + DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; + + public ChainDriveBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(PART, Part.NONE)); + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) { + return false; + } + + @Override + public PushReaction getPistonPushReaction(BlockState state) { + return PushReaction.NORMAL; + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(PART, CONNECTED_ALONG_FIRST_COORDINATE)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Axis placedAxis = context.getNearestLookingDirection() + .getAxis(); + Axis axis = context.getPlayer() != null && context.getPlayer() + .isShiftKeyDown() ? placedAxis : getPreferredAxis(context); + if (axis == null) + axis = placedAxis; + + BlockState state = defaultBlockState().setValue(AXIS, axis); + for (Direction facing : Iterate.directions) { + if (facing.getAxis() == axis) + continue; + BlockPos pos = context.getClickedPos(); + BlockPos offset = pos.relative(facing); + state = updateShape(state, facing, context.getLevel() + .getBlockState(offset), context.getLevel(), pos, offset); + } + return state; + } + + @Override + public BlockState updateShape(BlockState stateIn, Direction face, BlockState neighbour, LevelAccessor worldIn, + BlockPos currentPos, BlockPos facingPos) { + Part part = stateIn.getValue(PART); + Axis axis = stateIn.getValue(AXIS); + boolean connectionAlongFirst = stateIn.getValue(CONNECTED_ALONG_FIRST_COORDINATE); + Axis connectionAxis = + connectionAlongFirst ? (axis == Axis.X ? Axis.Y : Axis.X) : (axis == Axis.Z ? Axis.Y : Axis.Z); + + Axis faceAxis = face.getAxis(); + boolean facingAlongFirst = axis == Axis.X ? faceAxis.isVertical() : faceAxis == Axis.X; + boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE; + + if (axis == faceAxis) + return stateIn; + + if (!(neighbour.getBlock() instanceof ChainDriveBlock)) { + if (facingAlongFirst != connectionAlongFirst || part == Part.NONE) + return stateIn; + if (part == Part.MIDDLE) + return stateIn.setValue(PART, positive ? Part.END : Part.START); + if ((part == Part.START) == positive) + return stateIn.setValue(PART, Part.NONE); + return stateIn; + } + + Part otherPart = neighbour.getValue(PART); + Axis otherAxis = neighbour.getValue(AXIS); + boolean otherConnection = neighbour.getValue(CONNECTED_ALONG_FIRST_COORDINATE); + Axis otherConnectionAxis = + otherConnection ? (otherAxis == Axis.X ? Axis.Y : Axis.X) : (otherAxis == Axis.Z ? Axis.Y : Axis.Z); + + if (neighbour.getValue(AXIS) == faceAxis) + return stateIn; + if (otherPart != Part.NONE && otherConnectionAxis != faceAxis) + return stateIn; + + if (part == Part.NONE) { + part = positive ? Part.START : Part.END; + connectionAlongFirst = axis == Axis.X ? faceAxis.isVertical() : faceAxis == Axis.X; + } else if (connectionAxis != faceAxis) { + return stateIn; + } + + if ((part == Part.START) != positive) + part = Part.MIDDLE; + + return stateIn.setValue(PART, part) + .setValue(CONNECTED_ALONG_FIRST_COORDINATE, connectionAlongFirst); + } + + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + if (originalState.getValue(PART) == Part.NONE) + return super.getRotatedBlockState(originalState, targetedFace); + return super.getRotatedBlockState(originalState, + Direction.get(AxisDirection.POSITIVE, getConnectionAxis(originalState))); + } + + @Override + public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { +// Blocks.AIR.getDefaultState() +// .updateNeighbors(context.getWorld(), context.getPos(), 1); + Axis axis = newState.getValue(AXIS); + newState = defaultBlockState().setValue(AXIS, axis); + if (newState.hasProperty(BlockStateProperties.POWERED)) + newState = newState.setValue(BlockStateProperties.POWERED, context.getLevel() + .hasNeighborSignal(context.getClickedPos())); + for (Direction facing : Iterate.directions) { + if (facing.getAxis() == axis) + continue; + BlockPos pos = context.getClickedPos(); + BlockPos offset = pos.relative(facing); + newState = updateShape(newState, facing, context.getLevel() + .getBlockState(offset), context.getLevel(), pos, offset); + } +// newState.updateNeighbors(context.getWorld(), context.getPos(), 1 | 2); + return newState; + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face.getAxis() == state.getValue(AXIS); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(AXIS); + } + + public static boolean areBlocksConnected(BlockState state, BlockState other, Direction facing) { + Part part = state.getValue(PART); + Axis connectionAxis = getConnectionAxis(state); + Axis otherConnectionAxis = getConnectionAxis(other); + + if (otherConnectionAxis != connectionAxis) + return false; + if (facing.getAxis() != connectionAxis) + return false; + if (facing.getAxisDirection() == AxisDirection.POSITIVE && (part == Part.MIDDLE || part == Part.START)) + return true; + if (facing.getAxisDirection() == AxisDirection.NEGATIVE && (part == Part.MIDDLE || part == Part.END)) + return true; + + return false; + } + + protected static Axis getConnectionAxis(BlockState state) { + Axis axis = state.getValue(AXIS); + boolean connectionAlongFirst = state.getValue(CONNECTED_ALONG_FIRST_COORDINATE); + Axis connectionAxis = + connectionAlongFirst ? (axis == Axis.X ? Axis.Y : Axis.X) : (axis == Axis.Z ? Axis.Y : Axis.Z); + return connectionAxis; + } + + public static float getRotationSpeedModifier(KineticBlockEntity from, KineticBlockEntity to) { + float fromMod = 1; + float toMod = 1; + if (from instanceof ChainGearshiftBlockEntity) + fromMod = ((ChainGearshiftBlockEntity) from).getModifier(); + if (to instanceof ChainGearshiftBlockEntity) + toMod = ((ChainGearshiftBlockEntity) to).getModifier(); + return fromMod / toMod; + } + + public enum Part implements StringRepresentable { + START, MIDDLE, END, NONE; + + @Override + public String getSerializedName() { + return Lang.asId(name()); + } + } + + @Override + public Class getBlockEntityClass() { + return KineticBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ENCASED_SHAFT.get(); + } + + @Override + public BlockState rotate(BlockState state, Rotation rot) { + return rotate(state, rot, Axis.Y); + } + + protected BlockState rotate(BlockState pState, Rotation rot, Axis rotAxis) { + Axis connectionAxis = getConnectionAxis(pState); + Direction direction = Direction.fromAxisAndDirection(connectionAxis, AxisDirection.POSITIVE); + Direction normal = Direction.fromAxisAndDirection(pState.getValue(AXIS), AxisDirection.POSITIVE); + for (int i = 0; i < rot.ordinal(); i++) { + direction = direction.getClockWise(rotAxis); + normal = normal.getClockWise(rotAxis); + } + + if (direction.getAxisDirection() == AxisDirection.NEGATIVE) + pState = reversePart(pState); + + Axis newAxis = normal.getAxis(); + Axis newConnectingDirection = direction.getAxis(); + boolean alongFirst = newAxis == Axis.X && newConnectingDirection == Axis.Y + || newAxis != Axis.X && newConnectingDirection == Axis.X; + + return pState.setValue(AXIS, newAxis) + .setValue(CONNECTED_ALONG_FIRST_COORDINATE, alongFirst); + } + + @Override + public BlockState mirror(BlockState pState, Mirror pMirror) { + Axis connectionAxis = getConnectionAxis(pState); + if (pMirror.mirror(Direction.fromAxisAndDirection(connectionAxis, AxisDirection.POSITIVE)) + .getAxisDirection() == AxisDirection.POSITIVE) + return pState; + return reversePart(pState); + } + + protected BlockState reversePart(BlockState pState) { + Part part = pState.getValue(PART); + if (part == Part.START) + return pState.setValue(PART, Part.END); + if (part == Part.END) + return pState.setValue(PART, Part.START); + return pState; + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + return rotate(mirror(state, transform.mirror), transform.rotation, transform.rotationAxis); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveGenerator.java new file mode 100644 index 0000000000..8518ef0cc0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainDriveGenerator.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.kinetics.chainDrive; + +import java.util.function.BiFunction; + +import com.simibubi.create.content.kinetics.chainDrive.ChainDriveBlock.Part; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.generators.ModelFile; + +public class ChainDriveGenerator extends SpecialBlockStateGen { + + private BiFunction modelFunc; + + public ChainDriveGenerator(BiFunction modelFunc) { + this.modelFunc = modelFunc; + } + + @Override + protected int getXRotation(BlockState state) { + ChainDriveBlock.Part part = state.getValue(ChainDriveBlock.PART); + boolean connectedAlongFirst = state.getValue(ChainDriveBlock.CONNECTED_ALONG_FIRST_COORDINATE); + Axis axis = state.getValue(ChainDriveBlock.AXIS); + + if (part == Part.NONE) + return axis == Axis.Y ? 90 : 0; + if (axis == Axis.X) + return (connectedAlongFirst ? 90 : 0) + (part == Part.START ? 180 : 0); + if (axis == Axis.Z) + return (connectedAlongFirst ? 0 : (part == Part.START ? 270 : 90)); + return 0; + } + + @Override + protected int getYRotation(BlockState state) { + ChainDriveBlock.Part part = state.getValue(ChainDriveBlock.PART); + boolean connectedAlongFirst = state.getValue(ChainDriveBlock.CONNECTED_ALONG_FIRST_COORDINATE); + Axis axis = state.getValue(ChainDriveBlock.AXIS); + + if (part == Part.NONE) + return axis == Axis.X ? 90 : 0; + if (axis == Axis.Z) + return (connectedAlongFirst && part == Part.END ? 270 : 90); + boolean flip = part == Part.END && !connectedAlongFirst || part == Part.START && connectedAlongFirst; + if (axis == Axis.Y) + return (connectedAlongFirst ? 90 : 0) + (flip ? 180 : 0); + return 0; + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + return modelFunc.apply(state, getModelSuffix(state)); + } + + protected String getModelSuffix(BlockState state) { + ChainDriveBlock.Part part = state.getValue(ChainDriveBlock.PART); + Axis axis = state.getValue(ChainDriveBlock.AXIS); + + if (part == Part.NONE) + return "single"; + + String orientation = axis == Axis.Y ? "vertical" : "horizontal"; + String section = part == Part.MIDDLE ? "middle" : "end"; + return section + "_" + orientation; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlock.java new file mode 100644 index 0000000000..ea6550ab85 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlock.java @@ -0,0 +1,68 @@ +package com.simibubi.create.content.kinetics.chainDrive; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +public class ChainGearshiftBlock extends ChainDriveBlock { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + public ChainGearshiftBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(POWERED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(POWERED)); + } + + @Override + public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, worldIn, pos, oldState, isMoving); + if (oldState.getBlock() == state.getBlock()) + return; + withBlockEntityDo(worldIn, pos, kbe -> ((ChainGearshiftBlockEntity) kbe).neighbourChanged()); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return super.getStateForPlacement(context).setValue(POWERED, context.getLevel() + .hasNeighborSignal(context.getClickedPos())); + } + + @Override + protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { + return super.areStatesKineticallyEquivalent(oldState, newState) + && oldState.getValue(POWERED) == newState.getValue(POWERED); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + if (worldIn.isClientSide) + return; + + withBlockEntityDo(worldIn, pos, kbe -> ((ChainGearshiftBlockEntity) kbe).neighbourChanged()); + + boolean previouslyPowered = state.getValue(POWERED); + if (previouslyPowered != worldIn.hasNeighborSignal(pos)) + worldIn.setBlock(pos, state.cycle(POWERED), 18); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ADJUSTABLE_CHAIN_GEARSHIFT.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlockEntity.java new file mode 100644 index 0000000000..8470887da1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/chainDrive/ChainGearshiftBlockEntity.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.kinetics.chainDrive; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class ChainGearshiftBlockEntity extends KineticBlockEntity { + + int signal; + boolean signalChanged; + + public ChainGearshiftBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + signal = 0; + setLazyTickRate(40); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("Signal", signal); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + signal = compound.getInt("Signal"); + super.read(compound, clientPacket); + } + + public float getModifier() { + return getModifierForSignal(signal); + } + + public void neighbourChanged() { + if (!hasLevel()) + return; + int power = level.getBestNeighborSignal(worldPosition); + if (power != signal) + signalChanged = true; + } + + @Override + public void lazyTick() { + super.lazyTick(); + neighbourChanged(); + } + + @Override + public void tick() { + super.tick(); + if (level.isClientSide) + return; + if (signalChanged) { + signalChanged = false; + analogSignalChanged(level.getBestNeighborSignal(worldPosition)); + } + } + + protected void analogSignalChanged(int newSignal) { + detachKinetics(); + removeSource(); + signal = newSignal; + attachKinetics(); + } + + protected float getModifierForSignal(int newPower) { + if (newPower == 0) + return 1; + return 1 + ((newPower + 1) / 16f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockBlock.java b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlock.java index 2421f03ba8..8b1bf74fdd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlock.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.clock; +package com.simibubi.create.content.kinetics.clock; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -21,7 +21,7 @@ import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class CuckooClockBlock extends HorizontalKineticBlock implements ITE { +public class CuckooClockBlock extends HorizontalKineticBlock implements IBE { private boolean mysterious; @@ -79,13 +79,13 @@ public class CuckooClockBlock extends HorizontalKineticBlock implements ITE getTileEntityClass() { - return CuckooClockTileEntity.class; + public Class getBlockEntityClass() { + return CuckooClockBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CUCKOO_CLOCK.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CUCKOO_CLOCK.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlockEntity.java new file mode 100644 index 0000000000..d8b8183b12 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockBlockEntity.java @@ -0,0 +1,194 @@ +package com.simibubi.create.content.kinetics.clock; + +import java.util.List; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class CuckooClockBlockEntity extends KineticBlockEntity { + + public static DamageSource CUCKOO_SURPRISE = new DamageSource("create.cuckoo_clock_explosion").setExplosion(); + + public LerpedFloat hourHand = LerpedFloat.angular(); + public LerpedFloat minuteHand = LerpedFloat.angular(); + public LerpedFloat animationProgress = LerpedFloat.linear(); + public Animation animationType; + private boolean sendAnimationUpdate; + + enum Animation { + PIG, CREEPER, SURPRISE, NONE; + } + + public CuckooClockBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + animationType = Animation.NONE; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.CUCKOO_CLOCK); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket && compound.contains("Animation")) { + animationType = NBTHelper.readEnum(compound, "Animation", Animation.class); + animationProgress.startWithValue(0); + } + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (clientPacket && sendAnimationUpdate) + NBTHelper.writeEnum(compound, "Animation", animationType); + sendAnimationUpdate = false; + super.write(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + if (getSpeed() == 0) + return; + + + boolean isNatural = level.dimensionType().natural(); + int dayTime = (int) ((level.getDayTime() * (isNatural ? 1 : 24)) % 24000); + int hours = (dayTime / 1000 + 6) % 24; + int minutes = (dayTime % 1000) * 60 / 1000; + + if (!isNatural) { + if (level.isClientSide) { + moveHands(hours, minutes); + + if (AnimationTickHolder.getTicks() % 6 == 0) + playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 2f); + else if (AnimationTickHolder.getTicks() % 3 == 0) + playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 1.5f); + } + return; + } + + if (!level.isClientSide) { + if (animationType == Animation.NONE) { + if (hours == 12 && minutes < 5) + startAnimation(Animation.PIG); + if (hours == 18 && minutes < 36 && minutes > 31) + startAnimation(Animation.CREEPER); + } else { + float value = animationProgress.getValue(); + animationProgress.setValue(value + 1); + if (value > 100) + animationType = Animation.NONE; + + if (animationType == Animation.SURPRISE && Mth.equal(animationProgress.getValue(), 50)) { + Vec3 center = VecHelper.getCenterOf(worldPosition); + level.destroyBlock(worldPosition, false); + level.explode(null, CUCKOO_SURPRISE, null, center.x, center.y, center.z, 3, false, + Explosion.BlockInteraction.BREAK); + } + + } + } + + if (level.isClientSide) { + moveHands(hours, minutes); + + if (animationType == Animation.NONE) { + if (AnimationTickHolder.getTicks() % 32 == 0) + playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 2f); + else if (AnimationTickHolder.getTicks() % 16 == 0) + playSound(SoundEvents.NOTE_BLOCK_HAT, 1 / 16f, 1.5f); + } else { + + boolean isSurprise = animationType == Animation.SURPRISE; + float value = animationProgress.getValue(); + animationProgress.setValue(value + 1); + if (value > 100) + animationType = null; + + // sounds + + if (value == 1) + playSound(SoundEvents.NOTE_BLOCK_CHIME, 2, .5f); + if (value == 21) + playSound(SoundEvents.NOTE_BLOCK_CHIME, 2, 0.793701f); + + if (value > 30 && isSurprise) { + Vec3 pos = VecHelper.offsetRandomly(VecHelper.getCenterOf(this.worldPosition), level.random, .5f); + level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y, pos.z, 0, 0, 0); + } + if (value == 40 && isSurprise) + playSound(SoundEvents.TNT_PRIMED, 1f, 1f); + + int step = isSurprise ? 3 : 15; + for (int phase = 30; phase <= 60; phase += step) { + if (value == phase - step / 3) + playSound(SoundEvents.CHEST_OPEN, 1 / 16f, 2f); + if (value == phase) { + if (animationType == Animation.PIG) + playSound(SoundEvents.PIG_AMBIENT, 1 / 4f, 1f); + else + playSound(SoundEvents.CREEPER_HURT, 1 / 4f, 3f); + } + if (value == phase + step / 3) + playSound(SoundEvents.CHEST_CLOSE, 1 / 16f, 2f); + + } + + } + + return; + } + } + + public void startAnimation(Animation animation) { + animationType = animation; + if (animation != null && CuckooClockBlock.containsSurprise(getBlockState())) + animationType = Animation.SURPRISE; + animationProgress.startWithValue(0); + sendAnimationUpdate = true; + + if (animation == Animation.CREEPER) + awardIfNear(AllAdvancements.CUCKOO_CLOCK, 32); + + sendData(); + } + + public void moveHands(int hours, int minutes) { + float hourTarget = (float) (360 / 12 * (hours % 12)); + float minuteTarget = (float) (360 / 60 * minutes); + + hourHand.chase(hourTarget, .2f, Chaser.EXP); + minuteHand.chase(minuteTarget, .2f, Chaser.EXP); + + hourHand.tickChaser(); + minuteHand.tickChaser(); + } + + private void playSound(SoundEvent sound, float volume, float pitch) { + Vec3 vec = VecHelper.getCenterOf(worldPosition); + level.playLocalSound(vec.x, vec.y, vec.z, sound, SoundSource.BLOCKS, volume, pitch, false); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockRenderer.java new file mode 100644 index 0000000000..bdd8bee89c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/clock/CuckooClockRenderer.java @@ -0,0 +1,119 @@ +package com.simibubi.create.content.kinetics.clock; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.clock.CuckooClockBlockEntity.Animation; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class CuckooClockRenderer extends KineticBlockEntityRenderer { + + public CuckooClockRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(CuckooClockBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + if (!(be instanceof CuckooClockBlockEntity)) + return; + + BlockState blockState = be.getBlockState(); + Direction direction = blockState.getValue(CuckooClockBlock.HORIZONTAL_FACING); + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + // Render Hands + SuperByteBuffer hourHand = CachedPartialBuffers.partial(AllPartialModels.CUCKOO_HOUR_HAND, blockState); + SuperByteBuffer minuteHand = CachedPartialBuffers.partial(AllPartialModels.CUCKOO_MINUTE_HAND, blockState); + float hourAngle = be.hourHand.getValue(partialTicks); + float minuteAngle = be.minuteHand.getValue(partialTicks); + rotateHand(hourHand, hourAngle, direction).light(light) + .renderInto(ms, vb); + rotateHand(minuteHand, minuteAngle, direction).light(light) + .renderInto(ms, vb); + + // Doors + SuperByteBuffer leftDoor = CachedPartialBuffers.partial(AllPartialModels.CUCKOO_LEFT_DOOR, blockState); + SuperByteBuffer rightDoor = CachedPartialBuffers.partial(AllPartialModels.CUCKOO_RIGHT_DOOR, blockState); + float angle = 0; + float offset = 0; + + if (be.animationType != null) { + float value = be.animationProgress.getValue(partialTicks); + int step = be.animationType == Animation.SURPRISE ? 3 : 15; + for (int phase = 30; phase <= 60; phase += step) { + float local = value - phase; + if (local < -step / 3) + continue; + else if (local < 0) + angle = Mth.lerp(((value - (phase - 5)) / 5), 0, 135); + else if (local < step / 3) + angle = 135; + else if (local < 2 * step / 3) + angle = Mth.lerp(((value - (phase + 5)) / 5), 135, 0); + + } + } + + rotateDoor(leftDoor, angle, true, direction).light(light) + .renderInto(ms, vb); + rotateDoor(rightDoor, angle, false, direction).light(light) + .renderInto(ms, vb); + + // Figure + if (be.animationType != Animation.NONE) { + offset = -(angle / 135) * 1 / 2f + 10 / 16f; + PartialModel partialModel = (be.animationType == Animation.PIG ? AllPartialModels.CUCKOO_PIG : AllPartialModels.CUCKOO_CREEPER); + SuperByteBuffer figure = + CachedPartialBuffers.partial(partialModel, blockState); + figure.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(direction.getCounterClockWise()))); + figure.translate(offset, 0, 0); + figure.light(light) + .renderInto(ms, vb); + } + + } + + @Override + protected SuperByteBuffer getRotatedModel(CuckooClockBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, state, state + .getValue(CuckooClockBlock.HORIZONTAL_FACING) + .getOpposite()); + } + + private SuperByteBuffer rotateHand(SuperByteBuffer buffer, float angle, Direction facing) { + float pivotX = 2 / 16f; + float pivotY = 6 / 16f; + float pivotZ = 8 / 16f; + buffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getCounterClockWise()))); + buffer.translate(pivotX, pivotY, pivotZ); + buffer.rotate(Direction.EAST, AngleHelper.rad(angle)); + buffer.translate(-pivotX, -pivotY, -pivotZ); + return buffer; + } + + private SuperByteBuffer rotateDoor(SuperByteBuffer buffer, float angle, boolean left, Direction facing) { + float pivotX = 2 / 16f; + float pivotY = 0; + float pivotZ = (left ? 6 : 10) / 16f; + buffer.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getCounterClockWise()))); + buffer.translate(pivotX, pivotY, pivotZ); + buffer.rotate(Direction.UP, AngleHelper.rad(angle) * (left ? -1 : 1)); + buffer.translate(-pivotX, -pivotY, -pivotZ); + return buffer; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/ConnectedInputHandler.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/ConnectedInputHandler.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/crafter/ConnectedInputHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/crafter/ConnectedInputHandler.java index ae6ae78dab..1f38ee5ce9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/ConnectedInputHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/ConnectedInputHandler.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.crafter; +package com.simibubi.create.content.kinetics.crafter; -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; +import static com.simibubi.create.content.kinetics.base.HorizontalKineticBlock.HORIZONTAL_FACING; import java.util.ArrayList; import java.util.Arrays; @@ -53,8 +53,8 @@ public class ConnectedInputHandler { } public static void toggleConnection(Level world, BlockPos pos, BlockPos pos2) { - MechanicalCrafterTileEntity crafter1 = CrafterHelper.getCrafter(world, pos); - MechanicalCrafterTileEntity crafter2 = CrafterHelper.getCrafter(world, pos2); + MechanicalCrafterBlockEntity crafter1 = CrafterHelper.getCrafter(world, pos); + MechanicalCrafterBlockEntity crafter2 = CrafterHelper.getCrafter(world, pos2); if (crafter1 == null || crafter2 == null) return; @@ -65,7 +65,7 @@ public class ConnectedInputHandler { .offset(crafter2.input.data.get(0)); if (controllerPos1.equals(controllerPos2)) { - MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1); + MechanicalCrafterBlockEntity controller = CrafterHelper.getCrafter(world, controllerPos1); Set positions = controller.input.data.stream() .map(controllerPos1::offset) @@ -114,7 +114,7 @@ public class ConnectedInputHandler { crafter2.connectivityChanged(); } - public static void initAndAddAll(Level world, MechanicalCrafterTileEntity crafter, Collection positions) { + public static void initAndAddAll(Level world, MechanicalCrafterBlockEntity crafter, Collection positions) { crafter.input = new ConnectedInput(); positions.forEach(splitPos -> { modifyAndUpdate(world, splitPos, input -> { @@ -124,8 +124,8 @@ public class ConnectedInputHandler { }); } - public static void connectControllers(Level world, MechanicalCrafterTileEntity crafter1, - MechanicalCrafterTileEntity crafter2) { + public static void connectControllers(Level world, MechanicalCrafterBlockEntity crafter1, + MechanicalCrafterBlockEntity crafter2) { crafter1.input.data.forEach(offset -> { BlockPos connectedPos = crafter1.getBlockPos() @@ -150,11 +150,11 @@ public class ConnectedInputHandler { } private static void modifyAndUpdate(Level world, BlockPos pos, Consumer callback) { - BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof MechanicalCrafterTileEntity)) + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof MechanicalCrafterBlockEntity)) return; - MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te; + MechanicalCrafterBlockEntity crafter = (MechanicalCrafterBlockEntity) blockEntity; callback.accept(crafter.input); crafter.setChanged(); crafter.connectivityChanged(); diff --git a/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterCTBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterCTBehaviour.java new file mode 100644 index 0000000000..b6a7758cac --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterCTBehaviour.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.kinetics.crafter; + +import static com.simibubi.create.content.kinetics.base.HorizontalKineticBlock.HORIZONTAL_FACING; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllSpriteShifts; +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class CrafterCTBehaviour extends ConnectedTextureBehaviour.Base { + + @Override + public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, + Direction face) { + if (state.getBlock() != other.getBlock()) + return false; + if (state.getValue(HORIZONTAL_FACING) != other.getValue(HORIZONTAL_FACING)) + return false; + return CrafterHelper.areCraftersConnected(reader, pos, otherPos); + } + + @Override + protected boolean reverseUVs(BlockState state, Direction direction) { + if (!direction.getAxis() + .isVertical()) + return false; + Direction facing = state.getValue(HORIZONTAL_FACING); + if (facing.getAxis() == direction.getAxis()) + return false; + + boolean isNegative = facing.getAxisDirection() == AxisDirection.NEGATIVE; + if (direction == Direction.DOWN && facing.getAxis() == Axis.Z) + return !isNegative; + return isNegative; + } + + @Override + public CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite) { + Direction facing = state.getValue(HORIZONTAL_FACING); + boolean isFront = facing.getAxis() == direction.getAxis(); + boolean isVertical = direction.getAxis() + .isVertical(); + boolean facingX = facing.getAxis() == Axis.X; + return isFront ? AllSpriteShifts.BRASS_CASING + : isVertical && !facingX ? AllSpriteShifts.CRAFTER_OTHERSIDE : AllSpriteShifts.CRAFTER_SIDE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterHelper.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterHelper.java new file mode 100644 index 0000000000..54c4176612 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/CrafterHelper.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.kinetics.crafter; + +import com.simibubi.create.content.kinetics.crafter.ConnectedInputHandler.ConnectedInput; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class CrafterHelper { + + public static MechanicalCrafterBlockEntity getCrafter(BlockAndTintGetter reader, BlockPos pos) { + BlockEntity blockEntity = reader.getBlockEntity(pos); + if (!(blockEntity instanceof MechanicalCrafterBlockEntity)) + return null; + return (MechanicalCrafterBlockEntity) blockEntity; + } + + public static ConnectedInputHandler.ConnectedInput getInput(BlockAndTintGetter reader, BlockPos pos) { + MechanicalCrafterBlockEntity crafter = getCrafter(reader, pos); + return crafter == null ? null : crafter.input; + } + + public static boolean areCraftersConnected(BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos) { + ConnectedInput input1 = getInput(reader, pos); + ConnectedInput input2 = getInput(reader, otherPos); + + if (input1 == null || input2 == null) + return false; + if (input1.data.isEmpty() || input2.data.isEmpty()) + return false; + try { + if (pos.offset(input1.data.get(0)) + .equals(otherPos.offset(input2.data.get(0)))) + return true; + } catch (IndexOutOfBoundsException e) { + // race condition. data somehow becomes empty between the last 2 if statements + } + + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlock.java index 349ebb176c..4f9562d77c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlock.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.contraptions.components.crafter; +package com.simibubi.create.content.kinetics.crafter; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.crafter.ConnectedInputHandler.ConnectedInput; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity.Phase; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.Pointing; @@ -42,7 +42,7 @@ import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; public class MechanicalCrafterBlock extends HorizontalKineticBlock - implements ITE, ICogWheel { + implements IBE, ICogWheel { public static final EnumProperty POINTING = EnumProperty.create("pointing", Pointing.class); @@ -89,14 +89,14 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() == newState.getBlock()) { if (getTargetDirection(state) != getTargetDirection(newState)) { - MechanicalCrafterTileEntity crafter = CrafterHelper.getCrafter(worldIn, pos); + MechanicalCrafterBlockEntity crafter = CrafterHelper.getCrafter(worldIn, pos); if (crafter != null) crafter.blockChanged(); } } - if (state.hasBlockEntity() && state.getBlock() != newState.getBlock()) { - MechanicalCrafterTileEntity crafter = CrafterHelper.getCrafter(worldIn, pos); + if (state.hasBlockEntity() && !state.is(newState.getBlock())) { + MechanicalCrafterBlockEntity crafter = CrafterHelper.getCrafter(worldIn, pos); if (crafter != null) { if (crafter.covered) Block.popResource(worldIn, pos, AllItems.CRAFTER_SLOT_COVER.asStack()); @@ -121,9 +121,9 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock ConnectedInputHandler.toggleConnection(worldIn, pos, otherPos); } - - worldIn.removeBlockEntity(pos); } + + super.onRemove(state, worldIn, pos, newState, isMoving); } public static Pointing pointingFromFacing(Direction pointingFace, Direction blockFacing) { @@ -145,7 +145,7 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock public InteractionResult onWrenched(BlockState state, UseOnContext context) { if (context.getClickedFace() == state.getValue(HORIZONTAL_FACING)) { if (!context.getLevel().isClientSide) - KineticTileEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), + KineticBlockEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), state.cycle(POINTING)); return InteractionResult.SUCCESS; } @@ -156,8 +156,8 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock @Override public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, BlockHitResult hit) { - BlockEntity te = worldIn.getBlockEntity(pos); - if (!(te instanceof MechanicalCrafterTileEntity crafter)) + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (!(blockEntity instanceof MechanicalCrafterBlockEntity crafter)) return InteractionResult.PASS; ItemStack heldItem = player.getItemInHand(handIn); @@ -236,7 +236,7 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock @Override public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) { - InvManipulationBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + InvManipulationBehaviour behaviour = BlockEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); if (behaviour != null) behaviour.onNeighborChanged(fromPos); } @@ -279,13 +279,13 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock } @Override - public Class getTileEntityClass() { - return MechanicalCrafterTileEntity.class; + public Class getBlockEntityClass() { + return MechanicalCrafterBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_CRAFTER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_CRAFTER.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlockEntity.java new file mode 100644 index 0000000000..4936033abc --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterBlockEntity.java @@ -0,0 +1,542 @@ +package com.simibubi.create.content.kinetics.crafter; + +import static com.simibubi.create.content.kinetics.base.HorizontalKineticBlock.HORIZONTAL_FACING; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.crafter.ConnectedInputHandler.ConnectedInput; +import com.simibubi.create.content.kinetics.crafter.RecipeGridHandler.GroupedItems; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction.EdgeInteractionBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.item.SmartInventory; + +import net.createmod.catnip.utility.BlockFace; +import net.createmod.catnip.utility.Pointing; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; + +public class MechanicalCrafterBlockEntity extends KineticBlockEntity { + + enum Phase { + IDLE, ACCEPTING, ASSEMBLING, EXPORTING, WAITING, CRAFTING, INSERTING; + } + + public static class Inventory extends SmartInventory { + + private MechanicalCrafterBlockEntity blockEntity; + + public Inventory(MechanicalCrafterBlockEntity blockEntity) { + super(1, blockEntity, 1, false); + this.blockEntity = blockEntity; + forbidExtraction(); + whenContentsChanged(slot -> { + if (getItem(slot).isEmpty()) + return; + if (blockEntity.phase == Phase.IDLE) + blockEntity.checkCompletedRecipe(false); + }); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (blockEntity.phase != Phase.IDLE) + return stack; + if (blockEntity.covered) + return stack; + ItemStack insertItem = super.insertItem(slot, stack, simulate); + if (insertItem.getCount() != stack.getCount() && !simulate) + blockEntity.getLevel() + .playSound(null, blockEntity.getBlockPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .5f); + return insertItem; + } + + } + + protected Inventory inventory; + protected GroupedItems groupedItems = new GroupedItems(); + protected ConnectedInput input = new ConnectedInput(); + protected LazyOptional invSupplier = + LazyOptional.of(() -> input.getItemHandler(level, worldPosition)); + protected boolean reRender; + protected Phase phase; + protected int countDown; + protected boolean covered; + protected boolean wasPoweredBefore; + + protected GroupedItems groupedItemsBeforeCraft; // for rendering on client + private InvManipulationBehaviour inserting; + private EdgeInteractionBehaviour connectivity; + + private ItemStack scriptedResult = ItemStack.EMPTY; + + public MechanicalCrafterBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(20); + phase = Phase.IDLE; + groupedItemsBeforeCraft = new GroupedItems(); + inventory = new Inventory(this); + + // Does not get serialized due to active checking in tick + wasPoweredBefore = true; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + inserting = new InvManipulationBehaviour(this, this::getTargetFace); + connectivity = new EdgeInteractionBehaviour(this, ConnectedInputHandler::toggleConnection) + .connectivity(ConnectedInputHandler::shouldConnect) + .require(AllItems.WRENCH.get()); + behaviours.add(inserting); + behaviours.add(connectivity); + registerAwardables(behaviours, AllAdvancements.CRAFTER, AllAdvancements.CRAFTER_LAZY); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + if (!Mth.equal(getSpeed(), 0)) { + award(AllAdvancements.CRAFTER); + if (Math.abs(getSpeed()) < 5) + award(AllAdvancements.CRAFTER_LAZY); + } + } + + public void blockChanged() { + removeBehaviour(InvManipulationBehaviour.TYPE); + inserting = new InvManipulationBehaviour(this, this::getTargetFace); + attachBehaviourLate(inserting); + } + + public BlockFace getTargetFace(Level world, BlockPos pos, BlockState state) { + return new BlockFace(pos, MechanicalCrafterBlock.getTargetDirection(state)); + } + + public Direction getTargetDirection() { + return MechanicalCrafterBlock.getTargetDirection(getBlockState()); + } + + @Override + public void writeSafe(CompoundTag compound) { + super.writeSafe(compound); + if (input == null) + return; + + CompoundTag inputNBT = new CompoundTag(); + input.write(inputNBT); + compound.put("ConnectedInput", inputNBT); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.put("Inventory", inventory.serializeNBT()); + + CompoundTag inputNBT = new CompoundTag(); + input.write(inputNBT); + compound.put("ConnectedInput", inputNBT); + + CompoundTag groupedItemsNBT = new CompoundTag(); + groupedItems.write(groupedItemsNBT); + compound.put("GroupedItems", groupedItemsNBT); + + compound.putString("Phase", phase.name()); + compound.putInt("CountDown", countDown); + compound.putBoolean("Cover", covered); + + super.write(compound, clientPacket); + + if (clientPacket && reRender) { + compound.putBoolean("Redraw", true); + reRender = false; + } + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + Phase phaseBefore = phase; + GroupedItems before = this.groupedItems; + + inventory.deserializeNBT(compound.getCompound("Inventory")); + input.read(compound.getCompound("ConnectedInput")); + groupedItems = GroupedItems.read(compound.getCompound("GroupedItems")); + phase = Phase.IDLE; + String name = compound.getString("Phase"); + for (Phase phase : Phase.values()) + if (phase.name() + .equals(name)) + this.phase = phase; + countDown = compound.getInt("CountDown"); + covered = compound.getBoolean("Cover"); + super.read(compound, clientPacket); + if (!clientPacket) + return; + if (compound.contains("Redraw")) + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + if (phaseBefore != phase && phase == Phase.CRAFTING) + groupedItemsBeforeCraft = before; + if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) { + Direction facing = getBlockState().getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); + Vec3 vec = Vec3.atLowerCornerOf(facing.getNormal()) + .scale(.75) + .add(VecHelper.getCenterOf(worldPosition)); + Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState()); + vec = vec.add(Vec3.atLowerCornerOf(targetDirection.getNormal()) + .scale(1)); + level.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0); + } + } + + @Override + public void invalidate() { + super.invalidate(); + invSupplier.invalidate(); + } + + public int getCountDownSpeed() { + if (getSpeed() == 0) + return 0; + return Mth.clamp((int) Math.abs(getSpeed()), 4, 250); + } + + @Override + public void tick() { + super.tick(); + + if (phase == Phase.ACCEPTING) + return; + + boolean onClient = level.isClientSide; + boolean runLogic = !onClient || isVirtual(); + + if (wasPoweredBefore != level.hasNeighborSignal(worldPosition)) { + wasPoweredBefore = level.hasNeighborSignal(worldPosition); + if (wasPoweredBefore) { + if (!runLogic) + return; + checkCompletedRecipe(true); + } + } + + if (phase == Phase.ASSEMBLING) { + countDown -= getCountDownSpeed(); + if (countDown < 0) { + countDown = 0; + if (!runLogic) + return; + if (RecipeGridHandler.getTargetingCrafter(this) != null) { + phase = Phase.EXPORTING; + countDown = 1000; + sendData(); + return; + } + + ItemStack result = + isVirtual() ? scriptedResult : RecipeGridHandler.tryToApplyRecipe(level, groupedItems); + + if (result != null) { + List containers = new ArrayList<>(); + groupedItems.grid.values() + .forEach(stack -> { + if (stack.hasContainerItem()) + containers.add(stack.getContainerItem() + .copy()); + }); + + if (isVirtual()) + groupedItemsBeforeCraft = groupedItems; + + groupedItems = new GroupedItems(result); + for (int i = 0; i < containers.size(); i++) { + ItemStack stack = containers.get(i); + GroupedItems container = new GroupedItems(); + container.grid.put(Pair.of(i, 0), stack); + container.mergeOnto(groupedItems, Pointing.LEFT); + } + + phase = Phase.CRAFTING; + countDown = 2000; + sendData(); + return; + } + ejectWholeGrid(); + return; + } + } + + if (phase == Phase.EXPORTING) { + countDown -= getCountDownSpeed(); + + if (countDown < 0) { + countDown = 0; + if (!runLogic) + return; + + MechanicalCrafterBlockEntity targetingCrafter = RecipeGridHandler.getTargetingCrafter(this); + if (targetingCrafter == null) { + ejectWholeGrid(); + return; + } + + Pointing pointing = getBlockState().getValue(MechanicalCrafterBlock.POINTING); + groupedItems.mergeOnto(targetingCrafter.groupedItems, pointing); + groupedItems = new GroupedItems(); + + float pitch = targetingCrafter.groupedItems.grid.size() * 1 / 16f + .5f; + AllSoundEvents.CRAFTER_CLICK.playOnServer(level, worldPosition, 1, pitch); + + phase = Phase.WAITING; + countDown = 0; + sendData(); + targetingCrafter.continueIfAllPrecedingFinished(); + targetingCrafter.sendData(); + return; + } + } + + if (phase == Phase.CRAFTING) { + + if (onClient) { + Direction facing = getBlockState().getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); + float progress = countDown / 2000f; + Vec3 facingVec = Vec3.atLowerCornerOf(facing.getNormal()); + Vec3 vec = facingVec.scale(.65) + .add(VecHelper.getCenterOf(worldPosition)); + Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .125f) + .multiply(VecHelper.axisAlingedPlaneOf(facingVec)) + .normalize() + .scale(progress * .5f) + .add(vec); + if (progress > .5f) + level.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0); + + if (!groupedItemsBeforeCraft.grid.isEmpty() && progress < .5f) { + if (groupedItems.grid.containsKey(Pair.of(0, 0))) { + ItemStack stack = groupedItems.grid.get(Pair.of(0, 0)); + groupedItemsBeforeCraft = new GroupedItems(); + + for (int i = 0; i < 10; i++) { + Vec3 randVec = VecHelper.offsetRandomly(Vec3.ZERO, level.random, .125f) + .multiply(VecHelper.axisAlingedPlaneOf(facingVec)) + .normalize() + .scale(.25f); + Vec3 offset2 = randVec.add(vec); + randVec = randVec.scale(.35f); + level.addParticle(new ItemParticleOption(ParticleTypes.ITEM, stack), offset2.x, offset2.y, + offset2.z, randVec.x, randVec.y, randVec.z); + } + } + } + } + + int prev = countDown; + countDown -= getCountDownSpeed(); + + if (countDown < 1000 && prev >= 1000) { + AllSoundEvents.CRAFTER_CLICK.playOnServer(level, worldPosition, 1, 2); + AllSoundEvents.CRAFTER_CRAFT.playOnServer(level, worldPosition); + } + + if (countDown < 0) { + countDown = 0; + if (!runLogic) + return; + tryInsert(); + return; + } + } + + if (phase == Phase.INSERTING) { + if (runLogic && isTargetingBelt()) + tryInsert(); + return; + } + } + + protected boolean isTargetingBelt() { + DirectBeltInputBehaviour behaviour = getTargetingBelt(); + return behaviour != null && behaviour.canInsertFromSide(getTargetDirection()); + } + + protected DirectBeltInputBehaviour getTargetingBelt() { + BlockPos targetPos = worldPosition.relative(getTargetDirection()); + return BlockEntityBehaviour.get(level, targetPos, DirectBeltInputBehaviour.TYPE); + } + + public void tryInsert() { + if (!inserting.hasInventory() && !isTargetingBelt()) { + ejectWholeGrid(); + return; + } + + boolean chagedPhase = phase != Phase.INSERTING; + final List> inserted = new LinkedList<>(); + + DirectBeltInputBehaviour behaviour = getTargetingBelt(); + for (Entry, ItemStack> entry : groupedItems.grid.entrySet()) { + Pair pair = entry.getKey(); + ItemStack stack = entry.getValue(); + BlockFace face = getTargetFace(level, worldPosition, getBlockState()); + + ItemStack remainder = behaviour == null ? inserting.insert(stack.copy()) + : behaviour.handleInsertion(stack, face.getFace(), false); + if (!remainder.isEmpty()) { + stack.setCount(remainder.getCount()); + continue; + } + + inserted.add(pair); + } + + inserted.forEach(groupedItems.grid::remove); + if (groupedItems.grid.isEmpty()) + ejectWholeGrid(); + else + phase = Phase.INSERTING; + if (!inserted.isEmpty() || chagedPhase) + sendData(); + } + + public void ejectWholeGrid() { + List chain = RecipeGridHandler.getAllCraftersOfChain(this); + if (chain == null) + return; + chain.forEach(MechanicalCrafterBlockEntity::eject); + } + + public void eject() { + BlockState blockState = getBlockState(); + boolean present = AllBlocks.MECHANICAL_CRAFTER.has(blockState); + Vec3 vec = present ? Vec3.atLowerCornerOf(blockState.getValue(HORIZONTAL_FACING) + .getNormal()) + .scale(.75f) : Vec3.ZERO; + Vec3 ejectPos = VecHelper.getCenterOf(worldPosition) + .add(vec); + groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack)); + if (!inventory.getItem(0) + .isEmpty()) + dropItem(ejectPos, inventory.getItem(0)); + phase = Phase.IDLE; + groupedItems = new GroupedItems(); + inventory.setStackInSlot(0, ItemStack.EMPTY); + sendData(); + } + + public void dropItem(Vec3 ejectPos, ItemStack stack) { + ItemEntity itemEntity = new ItemEntity(level, ejectPos.x, ejectPos.y, ejectPos.z, stack); + itemEntity.setDefaultPickUpDelay(); + level.addFreshEntity(itemEntity); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (level.isClientSide && !isVirtual()) + return; + if (phase == Phase.IDLE && craftingItemPresent()) + checkCompletedRecipe(false); + if (phase == Phase.INSERTING) + tryInsert(); + } + + public boolean craftingItemPresent() { + return !inventory.getItem(0) + .isEmpty(); + } + + public boolean craftingItemOrCoverPresent() { + return !inventory.getItem(0) + .isEmpty() || covered; + } + + protected void checkCompletedRecipe(boolean poweredStart) { + if (getSpeed() == 0) + return; + if (level.isClientSide && !isVirtual()) + return; + List chain = RecipeGridHandler.getAllCraftersOfChainIf(this, + poweredStart ? MechanicalCrafterBlockEntity::craftingItemPresent + : MechanicalCrafterBlockEntity::craftingItemOrCoverPresent, + poweredStart); + if (chain == null) + return; + chain.forEach(MechanicalCrafterBlockEntity::begin); + } + + protected void begin() { + phase = Phase.ACCEPTING; + groupedItems = new GroupedItems(inventory.getItem(0)); + inventory.setStackInSlot(0, ItemStack.EMPTY); + if (RecipeGridHandler.getPrecedingCrafters(this) + .isEmpty()) { + phase = Phase.ASSEMBLING; + countDown = 500; + } + sendData(); + } + + protected void continueIfAllPrecedingFinished() { + List preceding = RecipeGridHandler.getPrecedingCrafters(this); + if (preceding == null) { + ejectWholeGrid(); + return; + } + + for (MechanicalCrafterBlockEntity blockEntity : preceding) + if (blockEntity.phase != Phase.WAITING) + return; + + phase = Phase.ASSEMBLING; + countDown = Math.max(100, getCountDownSpeed() + 1); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return invSupplier.cast(); + return super.getCapability(cap, side); + } + + public void connectivityChanged() { + reRender = true; + sendData(); + invSupplier.invalidate(); + invSupplier = LazyOptional.of(() -> input.getItemHandler(level, worldPosition)); + } + + public Inventory getInventory() { + return inventory; + } + + public void setScriptedResult(ItemStack scriptedResult) { + this.scriptedResult = scriptedResult; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterRenderer.java new file mode 100644 index 0000000000..b97cb95b7b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCrafterRenderer.java @@ -0,0 +1,223 @@ +package com.simibubi.create.content.kinetics.crafter; + +import static com.simibubi.create.content.kinetics.base.HorizontalKineticBlock.HORIZONTAL_FACING; +import static com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer.standardKineticRotationTransform; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.AllSpriteShifts; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity.Phase; +import com.simibubi.create.content.kinetics.crafter.RecipeGridHandler.GroupedItems; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Pointing; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class MechanicalCrafterRenderer extends SafeBlockEntityRenderer { + + public MechanicalCrafterRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(MechanicalCrafterBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + ms.pushPose(); + Direction facing = be.getBlockState() + .getValue(HORIZONTAL_FACING); + Vec3 vec = Vec3.atLowerCornerOf(facing.getNormal()) + .scale(.58) + .add(.5, .5, .5); + + if (be.phase == Phase.EXPORTING) { + Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(be.getBlockState()); + float progress = + Mth.clamp((1000 - be.countDown + be.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); + vec = vec.add(Vec3.atLowerCornerOf(targetDirection.getNormal()) + .scale(progress * .75f)); + } + + ms.translate(vec.x, vec.y, vec.z); + ms.scale(1 / 2f, 1 / 2f, 1 / 2f); + float yRot = AngleHelper.horizontalAngle(facing); + ms.mulPose(Vector3f.YP.rotationDegrees(yRot)); + renderItems(be, partialTicks, ms, buffer, light, overlay); + ms.popPose(); + + renderFast(be, partialTicks, ms, buffer, light); + } + + public void renderItems(MechanicalCrafterBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + if (be.phase == Phase.IDLE) { + ItemStack stack = be.getInventory() + .getItem(0); + if (!stack.isEmpty()) { + ms.pushPose(); + ms.translate(0, 0, -1 / 256f); + ms.mulPose(Vector3f.YP.rotationDegrees(180)); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); + ms.popPose(); + } + } else { + // render grouped items + GroupedItems items = be.groupedItems; + float distance = .5f; + + ms.pushPose(); + + if (be.phase == Phase.CRAFTING) { + items = be.groupedItemsBeforeCraft; + items.calcStats(); + float progress = + Mth.clamp((2000 - be.countDown + be.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); + float earlyProgress = Mth.clamp(progress * 2, 0, 1); + float lateProgress = Mth.clamp(progress * 2 - 1, 0, 1); + + ms.scale(1 - lateProgress, 1 - lateProgress, 1 - lateProgress); + Vec3 centering = + new Vec3(-items.minX + (-items.width + 1) / 2f, -items.minY + (-items.height + 1) / 2f, 0) + .scale(earlyProgress); + ms.translate(centering.x * .5f, centering.y * .5f, 0); + distance += (-4 * (progress - .5f) * (progress - .5f) + 1) * .25f; + } + + boolean onlyRenderFirst = be.phase == Phase.INSERTING || be.phase == Phase.CRAFTING && be.countDown < 1000; + final float spacing = distance; + items.grid.forEach((pair, stack) -> { + if (onlyRenderFirst && (pair.getLeft() + .intValue() != 0 + || pair.getRight() + .intValue() != 0)) + return; + + ms.pushPose(); + Integer x = pair.getKey(); + Integer y = pair.getValue(); + ms.translate(x * spacing, y * spacing, 0); + + int offset = 0; + if (be.phase == Phase.EXPORTING && be.getBlockState().hasProperty(MechanicalCrafterBlock.POINTING)) { + Pointing value = be.getBlockState().getValue(MechanicalCrafterBlock.POINTING); + offset = value == Pointing.UP ? -1 : value == Pointing.LEFT ? 2 : value == Pointing.RIGHT ? -2 : 1; + } + + TransformStack.cast(ms) + .rotateY(180) + .translate(0, 0, (x + y * 3 + offset * 9) / 1024f ); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); + ms.popPose(); + }); + + ms.popPose(); + + if (be.phase == Phase.CRAFTING) { + items = be.groupedItems; + float progress = + Mth.clamp((1000 - be.countDown + be.getCountDownSpeed() * partialTicks) / 1000f, 0, 1); + float earlyProgress = Mth.clamp(progress * 2, 0, 1); + float lateProgress = Mth.clamp(progress * 2 - 1, 0, 1); + + ms.mulPose(Vector3f.ZP.rotationDegrees(earlyProgress * 2 * 360)); + float upScaling = earlyProgress * 1.125f; + float downScaling = 1 + (1 - lateProgress) * .125f; + ms.scale(upScaling, upScaling, upScaling); + ms.scale(downScaling, downScaling, downScaling); + + items.grid.forEach((pair, stack) -> { + if (pair.getLeft() + .intValue() != 0 + || pair.getRight() + .intValue() != 0) + return; + ms.pushPose(); + ms.mulPose(Vector3f.YP.rotationDegrees(180)); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(stack, TransformType.FIXED, light, overlay, ms, buffer, 0); + ms.popPose(); + }); + } + + } + } + + public void renderFast(MechanicalCrafterBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light) { + BlockState blockState = be.getBlockState(); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + if (!Backend.canUseInstancing(be.getLevel())) { + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.SHAFTLESS_COGWHEEL, blockState); + standardKineticRotationTransform(superBuffer, be, light); + superBuffer.rotateCentered(Direction.UP, (float) (blockState.getValue(HORIZONTAL_FACING) + .getAxis() != Direction.Axis.X ? 0 : Math.PI / 2)); + superBuffer.rotateCentered(Direction.EAST, (float) (Math.PI / 2)); + superBuffer.renderInto(ms, vb); + } + + Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(blockState); + BlockPos pos = be.getBlockPos(); + + if ((be.covered || be.phase != Phase.IDLE) && be.phase != Phase.CRAFTING && be.phase != Phase.INSERTING) { + SuperByteBuffer lidBuffer = renderAndTransform(AllPartialModels.MECHANICAL_CRAFTER_LID, blockState); + lidBuffer.light(light) + .renderInto(ms, vb); + } + + if (MechanicalCrafterBlock.isValidTarget(be.getLevel(), pos.relative(targetDirection), blockState)) { + SuperByteBuffer beltBuffer = renderAndTransform(AllPartialModels.MECHANICAL_CRAFTER_BELT, blockState); + SuperByteBuffer beltFrameBuffer = + renderAndTransform(AllPartialModels.MECHANICAL_CRAFTER_BELT_FRAME, blockState); + + if (be.phase == Phase.EXPORTING) { + int textureIndex = (int) ((be.getCountDownSpeed() / 128f * AnimationTickHolder.getTicks())); + beltBuffer.shiftUVtoSheet(AllSpriteShifts.CRAFTER_THINGIES, (textureIndex % 4) / 4f, 0, 1); + } + + beltBuffer.light(light) + .renderInto(ms, vb); + beltFrameBuffer.light(light) + .renderInto(ms, vb); + + } else { + SuperByteBuffer arrowBuffer = renderAndTransform(AllPartialModels.MECHANICAL_CRAFTER_ARROW, blockState); + arrowBuffer.light(light) + .renderInto(ms, vb); + } + + } + + private SuperByteBuffer renderAndTransform(PartialModel renderBlock, BlockState crafterState) { + SuperByteBuffer buffer = CachedPartialBuffers.partial(renderBlock, crafterState); + float xRot = crafterState.getValue(MechanicalCrafterBlock.POINTING) + .getXRotation(); + float yRot = AngleHelper.horizontalAngle(crafterState.getValue(HORIZONTAL_FACING)); + buffer.rotateCentered(Direction.UP, (float) ((yRot + 90) / 180 * Math.PI)); + buffer.rotateCentered(Direction.EAST, (float) ((xRot) / 180 * Math.PI)); + return buffer; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingInventory.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingInventory.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingInventory.java rename to src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingInventory.java index 239c9c7b69..391e8c5c59 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingInventory.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingInventory.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components.crafter; +package com.simibubi.create.content.kinetics.crafter; import org.apache.commons.lang3.tuple.Pair; -import com.simibubi.create.content.contraptions.components.crafter.RecipeGridHandler.GroupedItems; +import com.simibubi.create.content.kinetics.crafter.RecipeGridHandler.GroupedItems; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingRecipe.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingRecipe.java index 4c29e9f83f..2550ebbb7b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCraftingRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/MechanicalCraftingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.crafter; +package com.simibubi.create.content.kinetics.crafter; import com.google.gson.JsonObject; import com.simibubi.create.AllRecipeTypes; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/RecipeGridHandler.java similarity index 75% rename from src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/crafter/RecipeGridHandler.java index 65254b1c14..853a494700 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/RecipeGridHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/RecipeGridHandler.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.components.crafter; +package com.simibubi.create.content.kinetics.crafter; -import static com.simibubi.create.content.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING; +import static com.simibubi.create.content.kinetics.base.HorizontalKineticBlock.HORIZONTAL_FACING; import java.util.ArrayList; import java.util.HashMap; @@ -15,7 +15,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.Pointing; @@ -34,20 +34,20 @@ import net.minecraft.world.level.block.state.BlockState; public class RecipeGridHandler { - public static List getAllCraftersOfChain(MechanicalCrafterTileEntity root) { + public static List getAllCraftersOfChain(MechanicalCrafterBlockEntity root) { return getAllCraftersOfChainIf(root, Predicates.alwaysTrue()); } - public static List getAllCraftersOfChainIf(MechanicalCrafterTileEntity root, - Predicate test) { + public static List getAllCraftersOfChainIf(MechanicalCrafterBlockEntity root, + Predicate test) { return getAllCraftersOfChainIf(root, test, false); } - public static List getAllCraftersOfChainIf(MechanicalCrafterTileEntity root, - Predicate test, boolean poweredStart) { - List crafters = new ArrayList<>(); - List> frontier = new ArrayList<>(); - Set visited = new HashSet<>(); + public static List getAllCraftersOfChainIf(MechanicalCrafterBlockEntity root, + Predicate test, boolean poweredStart) { + List crafters = new ArrayList<>(); + List> frontier = new ArrayList<>(); + Set visited = new HashSet<>(); frontier.add(Pair.of(root, null)); boolean powered = false; @@ -55,9 +55,9 @@ public class RecipeGridHandler { boolean allEmpty = true; while (!frontier.isEmpty()) { - Pair pair = frontier.remove(0); - MechanicalCrafterTileEntity current = pair.getKey(); - MechanicalCrafterTileEntity last = pair.getValue(); + Pair pair = frontier.remove(0); + MechanicalCrafterBlockEntity current = pair.getKey(); + MechanicalCrafterBlockEntity last = pair.getValue(); if (visited.contains(current)) return null; @@ -72,10 +72,10 @@ public class RecipeGridHandler { crafters.add(current); visited.add(current); - MechanicalCrafterTileEntity target = getTargetingCrafter(current); + MechanicalCrafterBlockEntity target = getTargetingCrafter(current); if (target != last && target != null) frontier.add(Pair.of(target, current)); - for (MechanicalCrafterTileEntity preceding : getPrecedingCrafters(current)) + for (MechanicalCrafterBlockEntity preceding : getPrecedingCrafters(current)) if (preceding != last) frontier.add(Pair.of(preceding, current)); } @@ -83,29 +83,29 @@ public class RecipeGridHandler { return empty && !powered || allEmpty ? null : crafters; } - public static MechanicalCrafterTileEntity getTargetingCrafter(MechanicalCrafterTileEntity crafter) { + public static MechanicalCrafterBlockEntity getTargetingCrafter(MechanicalCrafterBlockEntity crafter) { BlockState state = crafter.getBlockState(); if (!isCrafter(state)) return null; BlockPos targetPos = crafter.getBlockPos() .relative(MechanicalCrafterBlock.getTargetDirection(state)); - MechanicalCrafterTileEntity targetTE = CrafterHelper.getCrafter(crafter.getLevel(), targetPos); - if (targetTE == null) + MechanicalCrafterBlockEntity targetBE = CrafterHelper.getCrafter(crafter.getLevel(), targetPos); + if (targetBE == null) return null; - BlockState targetState = targetTE.getBlockState(); + BlockState targetState = targetBE.getBlockState(); if (!isCrafter(targetState)) return null; if (state.getValue(HORIZONTAL_FACING) != targetState.getValue(HORIZONTAL_FACING)) return null; - return targetTE; + return targetBE; } - public static List getPrecedingCrafters(MechanicalCrafterTileEntity crafter) { + public static List getPrecedingCrafters(MechanicalCrafterBlockEntity crafter) { BlockPos pos = crafter.getBlockPos(); Level world = crafter.getLevel(); - List crafters = new ArrayList<>(); + List crafters = new ArrayList<>(); BlockState blockState = crafter.getBlockState(); if (!isCrafter(blockState)) return crafters; @@ -126,11 +126,11 @@ public class RecipeGridHandler { continue; if (blockFacing != neighbourState.getValue(HORIZONTAL_FACING)) continue; - MechanicalCrafterTileEntity te = CrafterHelper.getCrafter(world, neighbourPos); - if (te == null) + MechanicalCrafterBlockEntity be = CrafterHelper.getCrafter(world, neighbourPos); + if (be == null) continue; - crafters.add(te); + crafters.add(be); } return crafters; @@ -144,7 +144,7 @@ public class RecipeGridHandler { items.calcStats(); CraftingContainer craftinginventory = new MechanicalCraftingInventory(items); ItemStack result = null; - if (AllConfigs.SERVER.recipes.allowRegularCraftingInCrafter.get()) + if (AllConfigs.server().recipes.allowRegularCraftingInCrafter.get()) result = world.getRecipeManager() .getRecipeFor(RecipeType.CRAFTING, craftinginventory, world) .filter(r -> isRecipeAllowed(r, craftinginventory)) @@ -165,7 +165,7 @@ public class RecipeGridHandler { numItems++; } } - if (numItems > AllConfigs.SERVER.recipes.maxFireworkIngredientsInCrafter.get()) { + if (numItems > AllConfigs.server().recipes.maxFireworkIngredientsInCrafter.get()) { return false; } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/crafter/ShaftlessCogwheelInstance.java b/src/main/java/com/simibubi/create/content/kinetics/crafter/ShaftlessCogwheelInstance.java new file mode 100644 index 0000000000..4b7e70c455 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crafter/ShaftlessCogwheelInstance.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.kinetics.crafter; + +import java.util.function.Supplier; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.Direction; + +public class ShaftlessCogwheelInstance extends SingleRotatingInstance { + + public ShaftlessCogwheelInstance(MaterialManager materialManager, KineticBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + Direction facing = blockState.getValue(MechanicalCrafterBlock.HORIZONTAL_FACING); + + return getRotatingMaterial().getModel(AllPartialModels.SHAFTLESS_COGWHEEL, blockState, facing, rotateToFace(facing)); + } + + private Supplier rotateToFace(Direction facing) { + return () -> { + PoseStack stack = new PoseStack(); + TransformStack stacker = TransformStack.cast(stack) + .centre(); + + if (facing.getAxis() == Direction.Axis.X) stacker.rotateZ(90); + else if (facing.getAxis() == Direction.Axis.Z) stacker.rotateX(90); + + stacker.unCentre(); + return stack; + }; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlock.java index fe89e184ec..7e6ce97464 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlock.java @@ -1,14 +1,13 @@ -package com.simibubi.create.content.contraptions.components.crank; +package com.simibubi.create.content.kinetics.crank; -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Couple; import net.minecraft.core.BlockPos; @@ -32,11 +31,9 @@ import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; public class HandCrankBlock extends DirectionalKineticBlock - implements ITE, ProperWaterloggedBlock { + implements IBE, ProperWaterloggedBlock { public HandCrankBlock(Properties properties) { super(properties); @@ -53,11 +50,6 @@ public class HandCrankBlock extends DirectionalKineticBlock super.createBlockStateDefinition(builder.add(WATERLOGGED)); } - @OnlyIn(Dist.CLIENT) - public PartialModel getRenderedHandle() { - return AllBlockPartials.HAND_CRANK_HANDLE; - } - public int getRotationSpeed() { return 32; } @@ -70,8 +62,13 @@ public class HandCrankBlock extends DirectionalKineticBlock @Override public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, BlockHitResult hit) { - withTileEntityDo(worldIn, pos, te -> te.turn(player.isShiftKeyDown())); - player.causeFoodExhaustion(getRotationSpeed() * AllConfigs.SERVER.kinetics.crankHungerMultiplier.getF()); + if (player.isSpectator()) + return InteractionResult.PASS; + + withBlockEntityDo(worldIn, pos, be -> be.turn(player.isShiftKeyDown())); + if (!player.getItemInHand(handIn) + .is(AllItems.EXTENDO_GRIP.get())) + player.causeFoodExhaustion(getRotationSpeed() * AllConfigs.server().kinetics.crankHungerMultiplier.getF()); if (player.getFoodData() .getFoodLevel() == 0) @@ -114,14 +111,14 @@ public class HandCrankBlock extends DirectionalKineticBlock } } } - + @Override public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { updateWater(pLevel, pState, pCurrentPos); return pState; } - + @Override public FluidState getFluidState(BlockState pState) { return fluidState(pState); @@ -140,13 +137,13 @@ public class HandCrankBlock extends DirectionalKineticBlock } @Override - public Class getTileEntityClass() { - return HandCrankTileEntity.class; + public Class getBlockEntityClass() { + return HandCrankBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.HAND_CRANK.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.HAND_CRANK.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlockEntity.java new file mode 100644 index 0000000000..4e8a7eb755 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankBlockEntity.java @@ -0,0 +1,134 @@ +package com.simibubi.create.content.kinetics.crank; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class HandCrankBlockEntity extends GeneratingKineticBlockEntity { + + public int inUse; + public boolean backwards; + public float independentAngle; + public float chasingVelocity; + + public HandCrankBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public void turn(boolean back) { + boolean update = false; + + if (getGeneratedSpeed() == 0 || back != backwards) + update = true; + + inUse = 10; + this.backwards = back; + if (update && !level.isClientSide) + updateGeneratedRotation(); + } + + public float getIndependentAngle(float partialTicks) { + return (independentAngle + partialTicks * chasingVelocity) / 360; + } + + @Override + public float getGeneratedSpeed() { + Block block = getBlockState().getBlock(); + if (!(block instanceof HandCrankBlock)) + return 0; + HandCrankBlock crank = (HandCrankBlock) block; + int speed = (inUse == 0 ? 0 : clockwise() ? -1 : 1) * crank.getRotationSpeed(); + return convertToDirection(speed, getBlockState().getValue(HandCrankBlock.FACING)); + } + + protected boolean clockwise() { + return backwards; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("InUse", inUse); + compound.putBoolean("Backwards", backwards); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + inUse = compound.getInt("InUse"); + backwards = compound.getBoolean("Backwards"); + super.read(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + + float actualSpeed = getSpeed(); + chasingVelocity += ((actualSpeed * 10 / 3f) - chasingVelocity) * .25f; + independentAngle += chasingVelocity; + + if (inUse > 0) { + inUse--; + + if (inUse == 0 && !level.isClientSide) { + sequenceContext = null; + updateGeneratedRotation(); + } + } + } + + @OnlyIn(Dist.CLIENT) + public SuperByteBuffer getRenderedHandle() { + BlockState blockState = getBlockState(); + Direction facing = blockState.getOptionalValue(HandCrankBlock.FACING) + .orElse(Direction.UP); + return CachedPartialBuffers.partialFacing(AllPartialModels.HAND_CRANK_HANDLE, blockState, facing.getOpposite()); + } + + @OnlyIn(Dist.CLIENT) + public Instancer getRenderedHandleInstance(Material material) { + BlockState blockState = getBlockState(); + Direction facing = blockState.getOptionalValue(HandCrankBlock.FACING) + .orElse(Direction.UP); + return material.getModel(AllPartialModels.HAND_CRANK_HANDLE, blockState, facing.getOpposite()); + } + + @OnlyIn(Dist.CLIENT) + public boolean shouldRenderShaft() { + return true; + } + + @Override + protected Block getStressConfigKey() { + return AllBlocks.HAND_CRANK.has(getBlockState()) ? AllBlocks.HAND_CRANK.get() + : AllBlocks.COPPER_VALVE_HANDLE.get(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + super.tickAudio(); + if (inUse > 0 && AnimationTickHolder.getTicks() % 10 == 0) { + if (!AllBlocks.HAND_CRANK.has(getBlockState())) + return; + AllSoundEvents.CRANKING.playAt(level, worldPosition, (inUse) / 2.5f, .65f + (10 - inUse) / 10f, true); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankInstance.java b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankInstance.java new file mode 100644 index 0000000000..0b10f3e48b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankInstance.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.kinetics.crank; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class HandCrankInstance extends SingleRotatingInstance implements DynamicInstance { + + private ModelData crank; + private Direction facing; + + public HandCrankInstance(MaterialManager modelManager, HandCrankBlockEntity blockEntity) { + super(modelManager, blockEntity); + facing = blockState.getValue(BlockStateProperties.FACING); + Instancer model = blockEntity.getRenderedHandleInstance(getTransformMaterial()); + crank = model.createInstance(); + rotateCrank(); + } + + @Override + public void beginFrame() { + if (crank == null) + return; + + rotateCrank(); + } + + private void rotateCrank() { + Direction.Axis axis = facing.getAxis(); + float angle = blockEntity.getIndependentAngle(AnimationTickHolder.getPartialTicks()); + + crank.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotate(Direction.get(Direction.AxisDirection.POSITIVE, axis), angle) + .unCentre(); + } + + @Override + public void init() { + if (blockEntity.shouldRenderShaft()) + super.init(); + } + + @Override + public void remove() { + if (blockEntity.shouldRenderShaft()) + super.remove(); + if (crank != null) + crank.delete(); + } + + @Override + public void update() { + if (blockEntity.shouldRenderShaft()) + super.update(); + } + + @Override + public void updateLight() { + if (blockEntity.shouldRenderShaft()) + super.updateLight(); + if (crank != null) + relight(pos, crank); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankRenderer.java new file mode 100644 index 0000000000..bfea5c3c24 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/HandCrankRenderer.java @@ -0,0 +1,35 @@ +package com.simibubi.create.content.kinetics.crank; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; + +public class HandCrankRenderer extends KineticBlockEntityRenderer { + + public HandCrankRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(HandCrankBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (be.shouldRenderShaft()) + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) + return; + + Direction facing = be.getBlockState() + .getValue(FACING); + kineticRotationTransform(be.getRenderedHandle(), be, facing.getAxis(), be.getIndependentAngle(partialTicks), + light).renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlock.java b/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlock.java new file mode 100644 index 0000000000..4784547fd0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlock.java @@ -0,0 +1,128 @@ +package com.simibubi.create.content.kinetics.crank; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllShapes; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@ParametersAreNonnullByDefault +@EventBusSubscriber +public class ValveHandleBlock extends HandCrankBlock { + + private final DyeColor color; + private final boolean inCreativeTab; + + public static ValveHandleBlock copper(Properties properties) { + return new ValveHandleBlock(properties, null, true); + } + + public static ValveHandleBlock dyed(Properties properties, DyeColor color) { + return new ValveHandleBlock(properties, color, false); + } + + private ValveHandleBlock(Properties properties, DyeColor color, boolean inCreativeTab) { + super(properties); + this.color = color; + this.inCreativeTab = inCreativeTab; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.VALVE_HANDLE.get(pState.getValue(FACING)); + } + + @SubscribeEvent(priority = EventPriority.LOW) + public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) { + BlockPos pos = event.getPos(); + Level level = event.getWorld(); + Player player = event.getPlayer(); + BlockState blockState = level.getBlockState(pos); + + if (!(blockState.getBlock() instanceof ValveHandleBlock vhb)) + return; + if (AllItems.WRENCH.isIn(player.getItemInHand(event.getHand())) && player.isSteppingCarefully()) + return; + + if (vhb.clicked(level, pos, blockState, player, event.getHand())) { + event.setCanceled(true); + event.setCancellationResult(InteractionResult.SUCCESS); + } + } + + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + if (!(pNewState.getBlock() instanceof ValveHandleBlock)) + super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); + } + + public boolean clicked(Level level, BlockPos pos, BlockState blockState, Player player, InteractionHand hand) { + ItemStack heldItem = player.getItemInHand(hand); + DyeColor color = DyeColor.getColor(heldItem); + + if (color != null && color != this.color) { + if (!level.isClientSide) + level.setBlockAndUpdate(pos, + BlockHelper.copyProperties(blockState, AllBlocks.DYED_VALVE_HANDLES.get(color) + .getDefaultState())); + return true; + } + + onBlockEntityUse(level, pos, + hcbe -> (hcbe instanceof ValveHandleBlockEntity vhbe) && vhbe.activate(player.isSteppingCarefully()) + ? InteractionResult.SUCCESS + : InteractionResult.PASS); + return true; + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + return InteractionResult.PASS; + } + + @Override + public void fillItemCategory(CreativeModeTab group, NonNullList p_149666_2_) { + if (group != CreativeModeTab.TAB_SEARCH && !inCreativeTab) + return; + super.fillItemCategory(group, p_149666_2_); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.VALVE_HANDLE.get(); + } + + @Override + public int getRotationSpeed() { + return 32; + } + + public static Couple getSpeedRange() { + return Couple.create(32, 32); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlockEntity.java new file mode 100644 index 0000000000..630af9411b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crank/ValveHandleBlockEntity.java @@ -0,0 +1,229 @@ +package com.simibubi.create.content.kinetics.crank; + +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencedGearshiftBlockEntity.SequenceContext; +import com.simibubi.create.content.kinetics.transmission.sequencer.SequencerInstructions; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class ValveHandleBlockEntity extends HandCrankBlockEntity { + + public ScrollValueBehaviour angleInput; + public int cooldown; + + protected int startAngle; + protected int targetAngle; + protected int totalUseTicks; + + public ValveHandleBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(angleInput = new ValveHandleScrollValueBehaviour(this).between(-180, 180)); + angleInput.onlyActiveWhen(this::showValue); + angleInput.setValue(45); + } + + @Override + protected boolean clockwise() { + return angleInput.getValue() < 0 ^ backwards; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("TotalUseTicks", totalUseTicks); + compound.putInt("StartAngle", startAngle); + compound.putInt("TargetAngle", targetAngle); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + totalUseTicks = compound.getInt("TotalUseTicks"); + startAngle = compound.getInt("StartAngle"); + targetAngle = compound.getInt("TargetAngle"); + } + + @Override + public void tick() { + super.tick(); + if (inUse == 0 && cooldown > 0) + cooldown--; + independentAngle = level.isClientSide() ? getIndependentAngle(0) : 0; + } + + @Override + public float getIndependentAngle(float partialTicks) { + if (inUse == 0 && source != null && getSpeed() != 0) + return KineticBlockEntityRenderer.getAngleForTe(this, worldPosition, + KineticBlockEntityRenderer.getRotationAxisOf(this)); + + int step = getBlockState().getOptionalValue(ValveHandleBlock.FACING) + .orElse(Direction.SOUTH) + .getAxisDirection() + .getStep(); + + return (inUse > 0 && totalUseTicks > 0 + ? Mth.lerp(Math.min(totalUseTicks, totalUseTicks - inUse + partialTicks) / (float) totalUseTicks, + startAngle, targetAngle) + : targetAngle) * Mth.DEG_TO_RAD * (backwards ? -1 : 1) * step; + } + + public boolean showValue() { + return inUse == 0; + } + + public boolean activate(boolean sneak) { + if (getTheoreticalSpeed() != 0) + return false; + if (inUse > 0 || cooldown > 0) + return false; + if (level.isClientSide) + return true; + + // Always overshoot, target will stop early + int value = angleInput.getValue(); + int target = Math.abs(value); + int rotationSpeed = AllBlocks.COPPER_VALVE_HANDLE.get() + .getRotationSpeed(); + double degreesPerTick = KineticBlockEntity.convertToAngular(rotationSpeed); + inUse = (int) Math.ceil(target / degreesPerTick) + 2; + + startAngle = (int) ((independentAngle) % 90 + 360) % 90; + targetAngle = Math.round((startAngle + (target > 135 ? 180 : 90) * Mth.sign(value)) / 90f) * 90; + totalUseTicks = inUse; + backwards = sneak; + + sequenceContext = SequenceContext.fromGearshift(SequencerInstructions.TURN_ANGLE, rotationSpeed, target); + updateGeneratedRotation(); + cooldown = 4; + + return true; + } + + @Override + protected void copySequenceContextFrom(KineticBlockEntity sourceBE) {} + + @Override + @OnlyIn(Dist.CLIENT) + public SuperByteBuffer getRenderedHandle() { + return CachedBlockBuffers.block(getBlockState()); + } + + @Override + @OnlyIn(Dist.CLIENT) + public Instancer getRenderedHandleInstance(Material material) { + return material.getModel(getBlockState()); + } + + @Override + @OnlyIn(Dist.CLIENT) + public boolean shouldRenderShaft() { + return false; + } + + public static class ValveHandleScrollValueBehaviour extends ScrollValueBehaviour { + + public ValveHandleScrollValueBehaviour(SmartBlockEntity be) { + super(CreateLang.translateDirect("kinetics.valve_handle.rotated_angle"), be, new ValveHandleValueBox()); + withFormatter(v -> String.valueOf(Math.abs(v)) + CreateLang.translateDirect("generic.unit.degrees") + .getString()); + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + ImmutableList rows = ImmutableList.of(Components.literal("\u27f3") + .withStyle(ChatFormatting.BOLD), + Components.literal("\u27f2") + .withStyle(ChatFormatting.BOLD)); + return new ValueSettingsBoard(label, 180, 45, rows, new ValueSettingsFormatter(this::formatValue)); + } + + @Override + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlHeld) { + int value = Math.max(1, valueSetting.value()); + if (!valueSetting.equals(getValueSettings())) + playFeedbackSound(this); + setValue(valueSetting.row() == 0 ? -value : value); + } + + @Override + public ValueSettings getValueSettings() { + return new ValueSettings(value < 0 ? 0 : 1, Math.abs(value)); + } + + public MutableComponent formatValue(ValueSettings settings) { + return CreateLang.number(Math.max(1, Math.abs(settings.value()))) + .add(CreateLang.translateDirect("generic.unit.degrees")) + .component(); + } + + @Override + public void onShortInteract(Player player, InteractionHand hand, Direction side) { + BlockState blockState = blockEntity.getBlockState(); + if (blockState.getBlock() instanceof ValveHandleBlock vhb) + vhb.clicked(getWorld(), getPos(), blockState, player, hand); + } + + } + + public static class ValveHandleValueBox extends ValueBoxTransform.Sided { + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + return direction == state.getValue(ValveHandleBlock.FACING); + } + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 8, 4.5); + } + + @Override + public boolean testHit(BlockState state, Vec3 localHit) { + Vec3 offset = getLocalOffset(state); + if (offset == null) + return false; + return localHit.distanceTo(offset) < scale / 1.5f; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/crusher/AbstractCrushingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/AbstractCrushingRecipe.java new file mode 100644 index 0000000000..effcf39bc8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/AbstractCrushingRecipe.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.kinetics.crusher; + +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.foundation.recipe.IRecipeTypeInfo; + +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public abstract class AbstractCrushingRecipe extends ProcessingRecipe { + + public AbstractCrushingRecipe(IRecipeTypeInfo recipeType, ProcessingRecipeParams params) { + super(recipeType, params); + } + + @Override + protected int getMaxInputCount() { + return 1; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingRecipe.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingRecipe.java index 5833d160b2..73a6c2b22b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingRecipe.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.crusher; +package com.simibubi.create.content.kinetics.crusher; import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; import net.minecraft.world.level.Level; import net.minecraftforge.items.wrapper.RecipeWrapper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlock.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlock.java index 8b5957b077..1488286ce9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.components.crusher; +package com.simibubi.create.content.kinetics.crusher; -import static com.simibubi.create.content.contraptions.components.crusher.CrushingWheelControllerBlock.VALID; +import static com.simibubi.create.content.kinetics.crusher.CrushingWheelControllerBlock.VALID; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -24,7 +24,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class CrushingWheelBlock extends RotatedPillarKineticBlock implements ITE { +public class CrushingWheelBlock extends RotatedPillarKineticBlock implements IBE { public CrushingWheelBlock(Properties properties) { super(properties); @@ -47,17 +47,14 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock implements ITE @Override public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - for (Direction d : Iterate.directions) { if (d.getAxis() == state.getValue(AXIS)) continue; if (AllBlocks.CRUSHING_WHEEL_CONTROLLER.has(worldIn.getBlockState(pos.relative(d)))) - worldIn.setBlockAndUpdate(pos.relative(d), Blocks.AIR.defaultBlockState()); + worldIn.removeBlock(pos.relative(d), isMoving); } - if (state.hasBlockEntity() && state.getBlock() != newState.getBlock()) { - worldIn.removeBlockEntity(pos); - } + super.onRemove(state, worldIn, pos, newState, isMoving); } public void updateControllers(BlockState state, Level world, BlockPos pos, Direction side) { @@ -83,14 +80,14 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock implements ITE if (AllBlocks.CRUSHING_WHEEL.has(otherState)) { controllerShouldExist = true; - CrushingWheelTileEntity te = getTileEntity(world, pos); - CrushingWheelTileEntity otherTe = getTileEntity(world, otherWheelPos); + CrushingWheelBlockEntity be = getBlockEntity(world, pos); + CrushingWheelBlockEntity otherBE = getBlockEntity(world, otherWheelPos); - if (te != null && otherTe != null && (te.getSpeed() > 0) != (otherTe.getSpeed() > 0) - && te.getSpeed() != 0) { + if (be != null && otherBE != null && (be.getSpeed() > 0) != (otherBE.getSpeed() > 0) + && be.getSpeed() != 0) { Axis wheelAxis = state.getValue(AXIS); Axis sideAxis = side.getAxis(); - int controllerADO = Math.round(Math.signum(te.getSpeed())) * side.getAxisDirection() + int controllerADO = Math.round(Math.signum(be.getSpeed())) * side.getAxisDirection() .getStep(); Vec3 controllerDirVec = new Vec3(wheelAxis == Axis.X ? 1 : 0, wheelAxis == Axis.Y ? 1 : 0, wheelAxis == Axis.Z ? 1 : 0).cross( @@ -135,7 +132,7 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock implements ITE if (entityIn.getY() < pos.getY() + 1.25f || !entityIn.isOnGround()) return; - float speed = getTileEntityOptional(worldIn, pos).map(CrushingWheelTileEntity::getSpeed) + float speed = getBlockEntityOptional(worldIn, pos).map(CrushingWheelBlockEntity::getSpeed) .orElse(0f); double x = 0; @@ -186,13 +183,13 @@ public class CrushingWheelBlock extends RotatedPillarKineticBlock implements ITE } @Override - public Class getTileEntityClass() { - return CrushingWheelTileEntity.class; + public Class getBlockEntityClass() { + return CrushingWheelBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CRUSHING_WHEEL.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CRUSHING_WHEEL.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlockEntity.java new file mode 100644 index 0000000000..c69e488687 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelBlockEntity.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.kinetics.crusher; + +import java.util.List; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.event.entity.living.LivingDropsEvent; +import net.minecraftforge.event.entity.living.LootingLevelEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class CrushingWheelBlockEntity extends KineticBlockEntity { + + public static final DamageSource DAMAGE_SOURCE = new DamageSource("create.crush").bypassArmor() + .setScalesWithDifficulty(); + + public CrushingWheelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(20); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.CRUSHING_WHEEL, AllAdvancements.CRUSHER_MAXED); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + fixControllers(); + } + + public void fixControllers() { + for (Direction d : Iterate.directions) + ((CrushingWheelBlock) getBlockState().getBlock()).updateControllers(getBlockState(), getLevel(), getBlockPos(), + d); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).inflate(1); + } + + @Override + public void lazyTick() { + super.lazyTick(); + fixControllers(); + } + + @SubscribeEvent + public static void crushingIsFortunate(LootingLevelEvent event) { + if (event.getDamageSource() != DAMAGE_SOURCE) + return; + event.setLootingLevel(2); //This does not currently increase mob drops. It seems like this only works for damage done by an entity. + } + + @SubscribeEvent + public static void handleCrushedMobDrops(LivingDropsEvent event) { + if (event.getSource() != CrushingWheelBlockEntity.DAMAGE_SOURCE) + return; + Vec3 outSpeed = Vec3.ZERO; + for (ItemEntity outputItem : event.getDrops()) { + outputItem.setDeltaMovement(outSpeed); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerBlock.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlock.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlock.java index 65f3adb91c..b13882afc4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.components.crusher; +package com.simibubi.create.content.kinetics.crusher; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.item.ItemHelper; import net.createmod.catnip.utility.Iterate; @@ -38,7 +38,7 @@ import net.minecraft.world.phys.shapes.EntityCollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -public class CrushingWheelControllerBlock extends DirectionalBlock implements ITE { +public class CrushingWheelControllerBlock extends DirectionalBlock implements IBE { public CrushingWheelControllerBlock(Properties p_i48440_1_) { super(p_i48440_1_); @@ -72,8 +72,8 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT checkEntityForProcessing(worldIn, pos, entityIn); - withTileEntityDo(worldIn, pos, te -> { - if (te.processingEntity == entityIn) + withBlockEntityDo(worldIn, pos, be -> { + if (be.processingEntity == entityIn) entityIn.makeStuckInBlock(state, new Vec3(axis == Axis.X ? (double) 0.05F : 0.25D, axis == Axis.Y ? (double) 0.05F : 0.25D, axis == Axis.Z ? (double) 0.05F : 0.25D)); @@ -81,10 +81,10 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT } public void checkEntityForProcessing(Level worldIn, BlockPos pos, Entity entityIn) { - CrushingWheelControllerTileEntity te = getTileEntity(worldIn, pos); - if (te == null) + CrushingWheelControllerBlockEntity be = getBlockEntity(worldIn, pos); + if (be == null) return; - if (te.crushingspeed == 0) + if (be.crushingspeed == 0) return; // if (entityIn instanceof ItemEntity) // ((ItemEntity) entityIn).setPickUpDelay(10); @@ -93,7 +93,7 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT if (pos.equals(NbtUtils.readBlockPos(data.getCompound("BypassCrushingWheel")))) return; } - if (te.isOccupied()) + if (be.isOccupied()) return; boolean isPlayer = entityIn instanceof Player; if (isPlayer && ((Player) entityIn).isCreative()) @@ -101,7 +101,7 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT if (isPlayer && entityIn.level.getDifficulty() == Difficulty.PEACEFUL) return; - te.startCrushing(entityIn); + be.startCrushing(entityIn); } @Override @@ -130,11 +130,11 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT } public void updateSpeed(BlockState state, LevelAccessor world, BlockPos pos) { - withTileEntityDo(world, pos, te -> { + withBlockEntityDo(world, pos, be -> { if (!state.getValue(VALID)) { - if (te.crushingspeed != 0) { - te.crushingspeed = 0; - te.sendData(); + if (be.crushingspeed != 0) { + be.crushingspeed = 0; + be.sendData(); } return; } @@ -145,15 +145,15 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT continue; if (neighbour.getValue(BlockStateProperties.AXIS) == d.getAxis()) continue; - BlockEntity adjTe = world.getBlockEntity(pos.relative(d)); - if (!(adjTe instanceof CrushingWheelTileEntity cwte)) + BlockEntity adjBE = world.getBlockEntity(pos.relative(d)); + if (!(adjBE instanceof CrushingWheelBlockEntity cwbe)) continue; - te.crushingspeed = Math.abs(cwte.getSpeed() / 50f); - te.sendData(); + be.crushingspeed = Math.abs(cwbe.getSpeed() / 50f); + be.sendData(); - cwte.award(AllAdvancements.CRUSHING_WHEEL); - if (cwte.getSpeed() > 255) - cwte.award(AllAdvancements.CRUSHER_MAXED); + cwbe.award(AllAdvancements.CRUSHING_WHEEL); + if (cwbe.getSpeed() > 255) + cwbe.award(AllAdvancements.CRUSHER_MAXED); break; } @@ -179,8 +179,8 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT // than falling back through. return Shapes.empty(); - CrushingWheelControllerTileEntity te = getTileEntity(worldIn, pos); - if (te != null && te.processingEntity == entity) + CrushingWheelControllerBlockEntity be = getBlockEntity(worldIn, pos); + if (be != null && be.processingEntity == entity) return Shapes.empty(); return standardShape; @@ -191,18 +191,18 @@ public class CrushingWheelControllerBlock extends DirectionalBlock implements IT if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) return; - withTileEntityDo(worldIn, pos, te -> ItemHelper.dropContents(worldIn, pos, te.inventory)); + withBlockEntityDo(worldIn, pos, be -> ItemHelper.dropContents(worldIn, pos, be.inventory)); worldIn.removeBlockEntity(pos); } @Override - public Class getTileEntityClass() { - return CrushingWheelControllerTileEntity.class; + public Class getBlockEntityClass() { + return CrushingWheelControllerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CRUSHING_WHEEL_CONTROLLER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CRUSHING_WHEEL_CONTROLLER.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlockEntity.java new file mode 100644 index 0000000000..e6b357f68f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/crusher/CrushingWheelControllerBlockEntity.java @@ -0,0 +1,375 @@ +package com.simibubi.create.content.kinetics.crusher; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Random; +import java.util.UUID; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.processing.recipe.ProcessingInventory; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.sound.SoundScapes; +import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class CrushingWheelControllerBlockEntity extends SmartBlockEntity { + + public Entity processingEntity; + private UUID entityUUID; + protected boolean searchForEntity; + + public ProcessingInventory inventory; + protected LazyOptional handler = LazyOptional.of(() -> inventory); + private RecipeWrapper wrapper; + public float crushingspeed; + + public CrushingWheelControllerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inventory = new ProcessingInventory(this::itemInserted) { + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return super.isItemValid(slot, stack) && processingEntity == null; + } + + }; + wrapper = new RecipeWrapper(inventory); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)); + } + + private boolean supportsDirectBeltInput(Direction side) { + BlockState blockState = getBlockState(); + if (blockState == null) + return false; + Direction direction = blockState.getValue(CrushingWheelControllerBlock.FACING); + return direction == Direction.DOWN || direction == side; + } + + @Override + public void tick() { + super.tick(); + if (searchForEntity) { + searchForEntity = false; + List search = level.getEntities((Entity) null, new AABB(getBlockPos()), + e -> entityUUID.equals(e.getUUID())); + if (search.isEmpty()) + clear(); + else + processingEntity = search.get(0); + } + + if (!isOccupied()) + return; + if (crushingspeed == 0) + return; + + if (level.isClientSide) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.tickAudio()); + + float speed = crushingspeed * 4; + + Vec3 centerPos = VecHelper.getCenterOf(worldPosition); + Direction facing = getBlockState().getValue(CrushingWheelControllerBlock.FACING); + int offset = facing.getAxisDirection() + .getStep(); + Vec3 outSpeed = new Vec3((facing.getAxis() == Axis.X ? 0.25D : 0.0D) * offset, + offset == 1 ? (facing.getAxis() == Axis.Y ? 0.5D : 0.0D) : 0.0D // Increased upwards speed so upwards + // crushing wheels shoot out the item + // properly. + , (facing.getAxis() == Axis.Z ? 0.25D : 0.0D) * offset); // No downwards speed, so downwards crushing wheels + // drop the items as before. + Vec3 outPos = centerPos.add((facing.getAxis() == Axis.X ? .55f * offset : 0f), + (facing.getAxis() == Axis.Y ? .55f * offset : 0f), (facing.getAxis() == Axis.Z ? .55f * offset : 0f)); + + if (!hasEntity()) { + + float processingSpeed = + Mth.clamp((speed) / (!inventory.appliedRecipe ? Mth.log2(inventory.getStackInSlot(0) + .getCount()) : 1), .25f, 20); + inventory.remainingTime -= processingSpeed; + spawnParticles(inventory.getStackInSlot(0)); + + if (level.isClientSide) + return; + + if (inventory.remainingTime < 20 && !inventory.appliedRecipe) { + applyRecipe(); + inventory.appliedRecipe = true; + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); + return; + } + + if (inventory.remainingTime > 0) { + return; + } + inventory.remainingTime = 0; + + // Output Items + if (facing != Direction.UP) { + BlockPos nextPos = worldPosition.offset(facing.getAxis() == Axis.X ? 1f * offset : 0f, (-1f), + facing.getAxis() == Axis.Z ? 1f * offset : 0f); + DirectBeltInputBehaviour behaviour = + BlockEntityBehaviour.get(level, nextPos, DirectBeltInputBehaviour.TYPE); + if (behaviour != null) { + boolean changed = false; + if (!behaviour.canInsertFromSide(facing)) + return; + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stack = inventory.getStackInSlot(slot); + if (stack.isEmpty()) + continue; + ItemStack remainder = behaviour.handleInsertion(stack, facing, false); + if (remainder.equals(stack, false)) + continue; + inventory.setStackInSlot(slot, remainder); + changed = true; + } + if (changed) { + setChanged(); + sendData(); + } + return; + } + } + + // Eject Items + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stack = inventory.getStackInSlot(slot); + if (stack.isEmpty()) + continue; + ItemEntity entityIn = new ItemEntity(level, outPos.x, outPos.y, outPos.z, stack); + entityIn.setDeltaMovement(outSpeed); + entityIn.getPersistentData() + .put("BypassCrushingWheel", NbtUtils.writeBlockPos(worldPosition)); + level.addFreshEntity(entityIn); + } + inventory.clear(); + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); + + return; + } + + if (!processingEntity.isAlive() || !processingEntity.getBoundingBox() + .intersects(new AABB(worldPosition).inflate(.5f))) { + clear(); + return; + } + + double xMotion = ((worldPosition.getX() + .5f) - processingEntity.getX()) / 2f; + double zMotion = ((worldPosition.getZ() + .5f) - processingEntity.getZ()) / 2f; + if (processingEntity.isShiftKeyDown()) + xMotion = zMotion = 0; + double movement = Math.max(-speed / 4f, -.5f) * -offset; + processingEntity.setDeltaMovement( + new Vec3(facing.getAxis() == Axis.X ? movement : xMotion, facing.getAxis() == Axis.Y ? movement : 0f // Do + // not + // move + // entities + // upwards + // or + // downwards + // for + // horizontal + // crushers, + , facing.getAxis() == Axis.Z ? movement : zMotion)); // Or they'll only get their feet crushed. + + if (level.isClientSide) + return; + + if (!(processingEntity instanceof ItemEntity)) { + Vec3 entityOutPos = outPos.add(facing.getAxis() == Axis.X ? .5f * offset : 0f, + facing.getAxis() == Axis.Y ? .5f * offset : 0f, facing.getAxis() == Axis.Z ? .5f * offset : 0f); + int crusherDamage = AllConfigs.server().kinetics.crushingDamage.get(); + + if (processingEntity instanceof LivingEntity) { + if ((((LivingEntity) processingEntity).getHealth() - crusherDamage <= 0) // Takes LivingEntity instances + // as exception, so it can + // move them before it would + // kill them. + && (((LivingEntity) processingEntity).hurtTime <= 0)) { // This way it can actually output the items + // to the right spot. + processingEntity.setPos(entityOutPos.x, entityOutPos.y, entityOutPos.z); + } + } + processingEntity.hurt(CrushingWheelBlockEntity.DAMAGE_SOURCE, crusherDamage); + if (!processingEntity.isAlive()) { + processingEntity.setPos(entityOutPos.x, entityOutPos.y, entityOutPos.z); + } + return; + } + + ItemEntity itemEntity = (ItemEntity) processingEntity; + itemEntity.setPickUpDelay(20); + if (facing.getAxis() == Axis.Y) { + if (processingEntity.getY() * -offset < (centerPos.y - .25f) * -offset) { + intakeItem(itemEntity); + } + } else if (facing.getAxis() == Axis.Z) { + if (processingEntity.getZ() * -offset < (centerPos.z - .25f) * -offset) { + intakeItem(itemEntity); + } + } else { + if (processingEntity.getX() * -offset < (centerPos.x - .25f) * -offset) { + intakeItem(itemEntity); + } + } + } + + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + float pitch = Mth.clamp((crushingspeed / 256f) + .45f, .85f, 1f); + if (entityUUID == null && inventory.getStackInSlot(0) + .isEmpty()) + return; + SoundScapes.play(AmbienceGroup.CRUSHING, worldPosition, pitch); + } + + private void intakeItem(ItemEntity itemEntity) { + inventory.clear(); + inventory.setStackInSlot(0, itemEntity.getItem() + .copy()); + itemInserted(inventory.getStackInSlot(0)); + itemEntity.discard(); + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2 | 16); + } + + protected void spawnParticles(ItemStack stack) { + if (stack == null || stack.isEmpty()) + return; + + ParticleOptions particleData = null; + if (stack.getItem() instanceof BlockItem) + particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() + .defaultBlockState()); + else + particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); + + Random r = level.random; + for (int i = 0; i < 4; i++) + level.addParticle(particleData, worldPosition.getX() + r.nextFloat(), worldPosition.getY() + r.nextFloat(), + worldPosition.getZ() + r.nextFloat(), 0, 0, 0); + } + + private void applyRecipe() { + Optional> recipe = findRecipe(); + + List list = new ArrayList<>(); + if (recipe.isPresent()) { + int rolls = inventory.getStackInSlot(0) + .getCount(); + inventory.clear(); + for (int roll = 0; roll < rolls; roll++) { + List rolledResults = recipe.get() + .rollResults(); + for (int i = 0; i < rolledResults.size(); i++) { + ItemStack stack = rolledResults.get(i); + ItemHelper.addToList(stack, list); + } + } + for (int slot = 0; slot < list.size() && slot + 1 < inventory.getSlots(); slot++) + inventory.setStackInSlot(slot + 1, list.get(slot)); + } else { + inventory.clear(); + } + + } + + public Optional> findRecipe() { + Optional> crushingRecipe = AllRecipeTypes.CRUSHING.find(wrapper, level); + if (!crushingRecipe.isPresent()) + crushingRecipe = AllRecipeTypes.MILLING.find(wrapper, level); + return crushingRecipe; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (hasEntity()) + compound.put("Entity", NbtUtils.createUUID(entityUUID)); + compound.put("Inventory", inventory.serializeNBT()); + compound.putFloat("Speed", crushingspeed); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (compound.contains("Entity") && !isOccupied()) { + entityUUID = NbtUtils.loadUUID(NBTHelper.getINBT(compound, "Entity")); + this.searchForEntity = true; + } + crushingspeed = compound.getFloat("Speed"); + inventory.deserializeNBT(compound.getCompound("Inventory")); + } + + public void startCrushing(Entity entity) { + processingEntity = entity; + entityUUID = entity.getUUID(); + } + + private void itemInserted(ItemStack stack) { + Optional> recipe = findRecipe(); + inventory.remainingTime = recipe.isPresent() ? recipe.get() + .getProcessingDuration() : 100; + inventory.appliedRecipe = false; + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return handler.cast(); + return super.getCapability(cap, side); + } + + public void clear() { + processingEntity = null; + entityUUID = null; + } + + public boolean isOccupied() { + return hasEntity() || !inventory.isEmpty(); + } + + public boolean hasEntity() { + return processingEntity != null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/BeltDeployerCallbacks.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/BeltDeployerCallbacks.java new file mode 100644 index 0000000000..d86d052948 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/BeltDeployerCallbacks.java @@ -0,0 +1,175 @@ +package com.simibubi.create.content.kinetics.deployer; + +import static com.simibubi.create.content.kinetics.base.DirectionalKineticBlock.FACING; + +import java.util.List; +import java.util.stream.Collectors; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.sandPaper.SandPaperPolishingRecipe; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.State; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.advancement.CreateAdvancement; +import com.simibubi.create.foundation.recipe.RecipeApplier; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.items.ItemHandlerHelper; + +public class BeltDeployerCallbacks { + + public static ProcessingResult onItemReceived(TransportedItemStack s, TransportedItemStackHandlerBehaviour i, + DeployerBlockEntity blockEntity) { + + if (blockEntity.getSpeed() == 0) + return ProcessingResult.PASS; + if (blockEntity.mode == Mode.PUNCH) + return ProcessingResult.PASS; + BlockState blockState = blockEntity.getBlockState(); + if (!blockState.hasProperty(FACING) || blockState.getValue(FACING) != Direction.DOWN) + return ProcessingResult.PASS; + if (blockEntity.state != State.WAITING) + return ProcessingResult.HOLD; + if (blockEntity.redstoneLocked) + return ProcessingResult.PASS; + + DeployerFakePlayer player = blockEntity.getPlayer(); + ItemStack held = player == null ? ItemStack.EMPTY : player.getMainHandItem(); + + if (held.isEmpty()) + return ProcessingResult.HOLD; + if (blockEntity.getRecipe(s.stack) == null) + return ProcessingResult.PASS; + + blockEntity.start(); + return ProcessingResult.HOLD; + } + + public static ProcessingResult whenItemHeld(TransportedItemStack s, TransportedItemStackHandlerBehaviour i, + DeployerBlockEntity blockEntity) { + + if (blockEntity.getSpeed() == 0) + return ProcessingResult.PASS; + BlockState blockState = blockEntity.getBlockState(); + if (!blockState.hasProperty(FACING) || blockState.getValue(FACING) != Direction.DOWN) + return ProcessingResult.PASS; + + DeployerFakePlayer player = blockEntity.getPlayer(); + ItemStack held = player == null ? ItemStack.EMPTY : player.getMainHandItem(); + if (held.isEmpty()) + return ProcessingResult.HOLD; + + Recipe recipe = blockEntity.getRecipe(s.stack); + if (recipe == null) + return ProcessingResult.PASS; + + if (blockEntity.state == State.RETRACTING && blockEntity.timer == 1000) { + activate(s, i, blockEntity, recipe); + return ProcessingResult.HOLD; + } + + if (blockEntity.state == State.WAITING) { + if (blockEntity.redstoneLocked) + return ProcessingResult.PASS; + blockEntity.start(); + } + + return ProcessingResult.HOLD; + } + + public static void activate(TransportedItemStack transported, TransportedItemStackHandlerBehaviour handler, + DeployerBlockEntity blockEntity, Recipe recipe) { + + List collect = + RecipeApplier.applyRecipeOn(ItemHandlerHelper.copyStackWithSize(transported.stack, 1), recipe) + .stream() + .map(stack -> { + TransportedItemStack copy = transported.copy(); + boolean centered = BeltHelper.isItemUpright(stack); + copy.stack = stack; + copy.locked = true; + copy.angle = centered ? 180 : Create.RANDOM.nextInt(360); + return copy; + }) + .map(t -> { + t.locked = false; + return t; + }) + .collect(Collectors.toList()); + + blockEntity.award(AllAdvancements.DEPLOYER); + + TransportedItemStack left = transported.copy(); + blockEntity.player.spawnedItemEffects = transported.stack.copy(); + left.stack.shrink(1); + ItemStack resultItem = null; + + if (collect.isEmpty()) { + resultItem = left.stack.copy(); + handler.handleProcessingOnItem(transported, TransportedResult.convertTo(left)); + } else { + resultItem = collect.get(0).stack.copy(); + handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(collect, left)); + } + + ItemStack heldItem = blockEntity.player.getMainHandItem(); + boolean unbreakable = heldItem.hasTag() && heldItem.getTag() + .getBoolean("Unbreakable"); + boolean keepHeld = + recipe instanceof ItemApplicationRecipe && ((ItemApplicationRecipe) recipe).shouldKeepHeldItem(); + + if (!unbreakable && !keepHeld) { + if (heldItem.isDamageableItem()) + heldItem.hurtAndBreak(1, blockEntity.player, + s -> s.broadcastBreakEvent(InteractionHand.MAIN_HAND)); + else + heldItem.shrink(1); + } + + if (resultItem != null && !resultItem.isEmpty()) + awardAdvancements(blockEntity, resultItem); + + BlockPos pos = blockEntity.getBlockPos(); + Level world = blockEntity.getLevel(); + if (heldItem.isEmpty()) + world.playSound(null, pos, SoundEvents.ITEM_BREAK, SoundSource.BLOCKS, .25f, 1); + world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, .25f, .75f); + if (recipe instanceof SandPaperPolishingRecipe) + AllSoundEvents.SANDING_SHORT.playOnServer(world, pos, .35f, 1f); + + blockEntity.sendData(); + } + + private static void awardAdvancements(DeployerBlockEntity blockEntity, ItemStack created) { + CreateAdvancement advancement = null; + + if (AllBlocks.ANDESITE_CASING.isIn(created)) + advancement = AllAdvancements.ANDESITE_CASING; + else if (AllBlocks.BRASS_CASING.isIn(created)) + advancement = AllAdvancements.BRASS_CASING; + else if (AllBlocks.COPPER_CASING.isIn(created)) + advancement = AllAdvancements.COPPER_CASING; + else if (AllBlocks.RAILWAY_CASING.isIn(created)) + advancement = AllAdvancements.TRAIN_CASING; + else + return; + + blockEntity.award(advancement); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerActorInstance.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerActorInstance.java index 9b5fa3c3f3..eaf702af65 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerActorInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerActorInstance.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; -import static com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; -import static com.simibubi.create.content.contraptions.base.DirectionalKineticBlock.FACING; +import static com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.kinetics.base.DirectionalKineticBlock.FACING; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; @@ -11,12 +11,12 @@ import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; import com.simibubi.create.foundation.render.AllMaterialSpecs; import net.createmod.catnip.utility.AnimationTickHolder; @@ -50,7 +50,7 @@ public class DeployerActorInstance extends ActorInstance { .material(Materials.TRANSFORMED); BlockState state = context.state; - DeployerTileEntity.Mode mode = NBTHelper.readEnum(context.tileData, "Mode", DeployerTileEntity.Mode.class); + DeployerBlockEntity.Mode mode = NBTHelper.readEnum(context.blockEntityData, "Mode", DeployerBlockEntity.Mode.class); PartialModel handPose = DeployerRenderer.getHandPose(mode); stationaryTimer = context.data.contains("StationaryTimer"); @@ -61,13 +61,13 @@ public class DeployerActorInstance extends ActorInstance { xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; zRot = rotatePole ? 90 : 0; - pole = mat.getModel(AllBlockPartials.DEPLOYER_POLE, state).createInstance(); + pole = mat.getModel(AllPartialModels.DEPLOYER_POLE, state).createInstance(); hand = mat.getModel(handPose, state).createInstance(); Direction.Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); shaft = materialManager.defaultSolid() .material(AllMaterialSpecs.ROTATING) - .getModel(KineticTileInstance.shaft(axis)) + .getModel(KineticBlockEntityInstance.shaft(axis)) .createInstance(); int blockLight = localBlockLight(); @@ -83,7 +83,9 @@ public class DeployerActorInstance extends ActorInstance { @Override public void beginFrame() { double factor; - if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { + if (context.disabled) { + factor = 0; + } else if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { factor = Mth.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f; } else { Vec3 center = VecHelper.getCenterOf(new BlockPos(context.position)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerApplicationRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerApplicationRecipe.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerApplicationRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerApplicationRecipe.java index 68f13e021c..f2a111cc06 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerApplicationRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerApplicationRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; import java.util.List; import java.util.Set; @@ -8,10 +8,9 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.compat.jei.category.sequencedAssembly.SequencedAssemblySubCategory; -import com.simibubi.create.content.contraptions.itemAssembly.IAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.ItemApplicationRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.sequenced.IAssemblyRecipe; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.lang.Components; @@ -32,7 +31,7 @@ public class DeployerApplicationRecipe extends ItemApplicationRecipe implements @Override protected int getMaxOutputCount() { - return 2; + return 4; } public static DeployerApplicationRecipe convert(Recipe sandpaperRecipe) { diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlock.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlock.java new file mode 100644 index 0000000000..c98729ebb8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlock.java @@ -0,0 +1,209 @@ +package com.simibubi.create.content.kinetics.deployer; + +import java.util.List; +import java.util.function.Predicate; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.processing.AssemblyOperatorUseContext; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.createmod.catnip.utility.placement.PlacementOffset; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class DeployerBlock extends DirectionalAxisKineticBlock implements IBE { + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public DeployerBlock(Properties properties) { + super(properties); + } + + @Override + public PushReaction getPistonPushReaction(BlockState state) { + return PushReaction.NORMAL; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.DEPLOYER_INTERACTION.get(state.getValue(FACING)); + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.CASING_12PX.get(state.getValue(FACING)); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + Vec3 normal = Vec3.atLowerCornerOf(state.getValue(FACING) + .getNormal()); + Vec3 location = context.getClickLocation() + .subtract(Vec3.atCenterOf(context.getClickedPos()) + .subtract(normal.scale(.5))) + .multiply(normal); + if (location.length() > .75f) { + if (!context.getLevel().isClientSide) + withBlockEntityDo(context.getLevel(), context.getClickedPos(), DeployerBlockEntity::changeMode); + return InteractionResult.SUCCESS; + } + return super.onWrenched(state, context); + } + + @Override + public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + super.setPlacedBy(worldIn, pos, state, placer, stack); + if (placer instanceof ServerPlayer) + withBlockEntityDo(worldIn, pos, dbe -> dbe.owner = placer.getUUID()); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (!isMoving && !state.is(newState.getBlock())) + withBlockEntityDo(worldIn, pos, DeployerBlockEntity::discardPlayer); + super.onRemove(state, worldIn, pos, newState, isMoving); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + ItemStack heldByPlayer = player.getItemInHand(handIn) + .copy(); + + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldByPlayer) && placementHelper.getOffset(player, worldIn, state, pos, hit) + .placeInWorld(worldIn, (BlockItem) heldByPlayer.getItem(), player, handIn, hit) + .consumesAction()) + return InteractionResult.SUCCESS; + } + + if (AllItems.WRENCH.isIn(heldByPlayer)) + return InteractionResult.PASS; + + Vec3 normal = Vec3.atLowerCornerOf(state.getValue(FACING) + .getNormal()); + Vec3 location = hit.getLocation() + .subtract(Vec3.atCenterOf(pos) + .subtract(normal.scale(.5))) + .multiply(normal); + if (location.length() < .75f) + return InteractionResult.PASS; + if (worldIn.isClientSide) + return InteractionResult.SUCCESS; + + withBlockEntityDo(worldIn, pos, be -> { + ItemStack heldByDeployer = be.player.getMainHandItem() + .copy(); + if (heldByDeployer.isEmpty() && heldByPlayer.isEmpty()) + return; + + player.setItemInHand(handIn, heldByDeployer); + be.player.setItemInHand(InteractionHand.MAIN_HAND, heldByPlayer); + be.sendData(); + }); + + return InteractionResult.SUCCESS; + } + + @Override + public Class getBlockEntityClass() { + return DeployerBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.DEPLOYER.get(); + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, world, pos, oldState, isMoving); + withBlockEntityDo(world, pos, DeployerBlockEntity::redstoneUpdate); + } + + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, + boolean p_220069_6_) { + withBlockEntityDo(world, pos, DeployerBlockEntity::redstoneUpdate); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + protected Direction getFacingForPlacement(BlockPlaceContext context) { + if (context instanceof AssemblyOperatorUseContext) + return Direction.DOWN; + else + return super.getFacingForPlacement(context); + } + + @MethodsReturnNonnullByDefault + private static class PlacementHelper implements IPlacementHelper { + + @Override + public Predicate getItemPredicate() { + return AllBlocks.DEPLOYER::isIn; + } + + @Override + public Predicate getStatePredicate() { + return AllBlocks.DEPLOYER::has; + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, + BlockHitResult ray) { + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), + state.getValue(FACING) + .getAxis(), + dir -> world.getBlockState(pos.relative(dir)) + .getMaterial() + .isReplaceable()); + + if (directions.isEmpty()) + return PlacementOffset.fail(); + else { + return PlacementOffset.success(pos.relative(directions.get(0)), + s -> s.setValue(FACING, state.getValue(FACING)) + .setValue(AXIS_ALONG_FIRST_COORDINATE, state.getValue(AXIS_ALONG_FIRST_COORDINATE))); + } + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlockEntity.java new file mode 100644 index 0000000000..e54a1438c4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerBlockEntity.java @@ -0,0 +1,571 @@ +package com.simibubi.create.content.kinetics.deployer; + +import static com.simibubi.create.content.kinetics.base.DirectionalKineticBlock.FACING; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.equipment.sandPaper.SandPaperItem; +import com.simibubi.create.content.equipment.sandPaper.SandPaperPolishingRecipe.SandPaperInv; +import com.simibubi.create.content.kinetics.base.IRotate.StressImpact; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.ClipContext.Block; +import net.minecraft.world.level.ClipContext.Fluid; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class DeployerBlockEntity extends KineticBlockEntity { + + protected State state; + protected Mode mode; + protected ItemStack heldItem = ItemStack.EMPTY; + protected DeployerFakePlayer player; + protected int timer; + protected float reach; + protected boolean fistBump = false; + protected List overflowItems = new ArrayList<>(); + protected FilteringBehaviour filtering; + protected boolean redstoneLocked; + protected UUID owner; + private LazyOptional invHandler; + private ListTag deferredInventoryList; + + private LerpedFloat animatedOffset; + + public BeltProcessingBehaviour processingBehaviour; + + enum State { + WAITING, EXPANDING, RETRACTING, DUMPING; + } + + enum Mode { + PUNCH, USE + } + + public DeployerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + this.state = State.WAITING; + mode = Mode.USE; + heldItem = ItemStack.EMPTY; + redstoneLocked = false; + animatedOffset = LerpedFloat.linear() + .startWithValue(0); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + filtering = new FilteringBehaviour(this, new DeployerFilterSlot()); + behaviours.add(filtering); + processingBehaviour = + new BeltProcessingBehaviour(this).whenItemEnters((s, i) -> BeltDeployerCallbacks.onItemReceived(s, i, this)) + .whileItemHeld((s, i) -> BeltDeployerCallbacks.whenItemHeld(s, i, this)); + behaviours.add(processingBehaviour); + + registerAwardables(behaviours, AllAdvancements.TRAIN_CASING, AllAdvancements.ANDESITE_CASING, + AllAdvancements.BRASS_CASING, AllAdvancements.COPPER_CASING, AllAdvancements.FIST_BUMP, + AllAdvancements.DEPLOYER, AllAdvancements.SELF_DEPLOYING); + } + + @Override + public void initialize() { + super.initialize(); + initHandler(); + } + + private void initHandler() { + if (invHandler != null) + return; + if (level instanceof ServerLevel sLevel) { + player = new DeployerFakePlayer(sLevel, owner); + if (deferredInventoryList != null) { + player.getInventory() + .load(deferredInventoryList); + deferredInventoryList = null; + heldItem = player.getMainHandItem(); + sendData(); + } + Vec3 initialPos = VecHelper.getCenterOf(worldPosition.relative(getBlockState().getValue(FACING))); + player.setPos(initialPos.x, initialPos.y, initialPos.z); + } + invHandler = LazyOptional.of(this::createHandler); + } + + protected void onExtract(ItemStack stack) { + player.setItemInHand(InteractionHand.MAIN_HAND, stack.copy()); + sendData(); + setChanged(); + } + + protected int getTimerSpeed() { + return (int) (getSpeed() == 0 ? 0 : Mth.clamp(Math.abs(getSpeed() * 2), 8, 512)); + } + + @Override + public void tick() { + super.tick(); + + if (getSpeed() == 0) + return; + if (!level.isClientSide && player != null && player.blockBreakingProgress != null) { + if (level.isEmptyBlock(player.blockBreakingProgress.getKey())) { + level.destroyBlockProgress(player.getId(), player.blockBreakingProgress.getKey(), -1); + player.blockBreakingProgress = null; + } + } + if (timer > 0) { + timer -= getTimerSpeed(); + return; + } + if (level.isClientSide) + return; + + ItemStack stack = player.getMainHandItem(); + if (state == State.WAITING) { + if (!overflowItems.isEmpty()) { + timer = getTimerSpeed() * 10; + return; + } + + boolean changed = false; + Inventory inventory = player.getInventory(); + for (int i = 0; i < inventory.getContainerSize(); i++) { + if (overflowItems.size() > 10) + break; + ItemStack item = inventory.getItem(i); + if (item.isEmpty()) + continue; + if (item != stack || !filtering.test(item)) { + overflowItems.add(item); + inventory.setItem(i, ItemStack.EMPTY); + changed = true; + } + } + + if (changed) { + sendData(); + timer = getTimerSpeed() * 10; + return; + } + + Direction facing = getBlockState().getValue(FACING); + if (mode == Mode.USE + && !DeployerHandler.shouldActivate(stack, level, worldPosition.relative(facing, 2), facing)) { + timer = getTimerSpeed() * 10; + return; + } + + // Check for advancement conditions + if (mode == Mode.PUNCH && !fistBump && startFistBump(facing)) + return; + if (redstoneLocked) + return; + + start(); + return; + } + + if (state == State.EXPANDING) { + if (fistBump) + triggerFistBump(); + activate(); + + state = State.RETRACTING; + timer = 1000; + sendData(); + return; + } + + if (state == State.RETRACTING) { + state = State.WAITING; + timer = 500; + sendData(); + return; + } + + } + + protected void start() { + state = State.EXPANDING; + Vec3 movementVector = getMovementVector(); + Vec3 rayOrigin = VecHelper.getCenterOf(worldPosition) + .add(movementVector.scale(3 / 2f)); + Vec3 rayTarget = VecHelper.getCenterOf(worldPosition) + .add(movementVector.scale(5 / 2f)); + ClipContext rayTraceContext = new ClipContext(rayOrigin, rayTarget, Block.OUTLINE, Fluid.NONE, player); + BlockHitResult result = level.clip(rayTraceContext); + reach = (float) (.5f + Math.min(result.getLocation() + .subtract(rayOrigin) + .length(), .75f)); + timer = 1000; + sendData(); + } + + public boolean startFistBump(Direction facing) { + int i = 0; + DeployerBlockEntity partner = null; + + for (i = 2; i < 5; i++) { + BlockPos otherDeployer = worldPosition.relative(facing, i); + if (!level.isLoaded(otherDeployer)) + return false; + BlockEntity other = level.getBlockEntity(otherDeployer); + if (other instanceof DeployerBlockEntity dpe) { + partner = dpe; + break; + } + } + + if (partner == null) + return false; + + if (level.getBlockState(partner.getBlockPos()) + .getValue(FACING) + .getOpposite() != facing || partner.mode != Mode.PUNCH) + return false; + if (partner.getSpeed() == 0) + return false; + + for (DeployerBlockEntity be : Arrays.asList(this, partner)) { + be.fistBump = true; + be.reach = ((i - 2)) * .5f; + be.timer = 1000; + be.state = State.EXPANDING; + be.sendData(); + } + + return true; + } + + public void triggerFistBump() { + int i = 0; + DeployerBlockEntity deployerBlockEntity = null; + for (i = 2; i < 5; i++) { + BlockPos pos = worldPosition.relative(getBlockState().getValue(FACING), i); + if (!level.isLoaded(pos)) + return; + if (level.getBlockEntity(pos) instanceof DeployerBlockEntity dpe) { + deployerBlockEntity = dpe; + break; + } + } + + if (deployerBlockEntity == null) + return; + if (!deployerBlockEntity.fistBump || deployerBlockEntity.state != State.EXPANDING) + return; + if (deployerBlockEntity.timer > 0) + return; + + fistBump = false; + deployerBlockEntity.fistBump = false; + deployerBlockEntity.state = State.RETRACTING; + deployerBlockEntity.timer = 1000; + deployerBlockEntity.sendData(); + award(AllAdvancements.FIST_BUMP); + + BlockPos soundLocation = new BlockPos(Vec3.atCenterOf(worldPosition) + .add(Vec3.atCenterOf(deployerBlockEntity.getBlockPos())) + .scale(.5f)); + level.playSound(null, soundLocation, SoundEvents.PLAYER_ATTACK_NODAMAGE, SoundSource.BLOCKS, .75f, .75f); + } + + protected void activate() { + Vec3 movementVector = getMovementVector(); + Direction direction = getBlockState().getValue(FACING); + Vec3 center = VecHelper.getCenterOf(worldPosition); + BlockPos clickedPos = worldPosition.relative(direction, 2); + player.setXRot(direction == Direction.UP ? -90 : direction == Direction.DOWN ? 90 : 0); + player.setYRot(direction.toYRot()); + + if (direction == Direction.DOWN + && BlockEntityBehaviour.get(level, clickedPos, TransportedItemStackHandlerBehaviour.TYPE) != null) + return; // Belt processing handled in BeltDeployerCallbacks + + DeployerHandler.activate(player, center, clickedPos, movementVector, mode); + award(AllAdvancements.DEPLOYER); + + if (player != null) + heldItem = player.getMainHandItem(); + } + + protected Vec3 getMovementVector() { + if (!AllBlocks.DEPLOYER.has(getBlockState())) + return Vec3.ZERO; + return Vec3.atLowerCornerOf(getBlockState().getValue(FACING) + .getNormal()); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + state = NBTHelper.readEnum(compound, "State", State.class); + mode = NBTHelper.readEnum(compound, "Mode", Mode.class); + timer = compound.getInt("Timer"); + redstoneLocked = compound.getBoolean("Powered"); + if (compound.contains("Owner")) + owner = compound.getUUID("Owner"); + + deferredInventoryList = compound.getList("Inventory", Tag.TAG_COMPOUND); + overflowItems = NBTHelper.readItemList(compound.getList("Overflow", Tag.TAG_COMPOUND)); + if (compound.contains("HeldItem")) + heldItem = ItemStack.of(compound.getCompound("HeldItem")); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + fistBump = compound.getBoolean("Fistbump"); + reach = compound.getFloat("Reach"); + if (compound.contains("Particle")) { + ItemStack particleStack = ItemStack.of(compound.getCompound("Particle")); + SandPaperItem.spawnParticles(VecHelper.getCenterOf(worldPosition) + .add(getMovementVector().scale(reach + 1)), particleStack, this.level); + } + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + NBTHelper.writeEnum(compound, "Mode", mode); + NBTHelper.writeEnum(compound, "State", state); + compound.putInt("Timer", timer); + compound.putBoolean("Powered", redstoneLocked); + if (owner != null) + compound.putUUID("Owner", owner); + + if (player != null) { + ListTag invNBT = new ListTag(); + player.getInventory() + .save(invNBT); + compound.put("Inventory", invNBT); + compound.put("HeldItem", player.getMainHandItem() + .serializeNBT()); + compound.put("Overflow", NBTHelper.writeItemList(overflowItems)); + } else if (deferredInventoryList != null) { + compound.put("Inventory", deferredInventoryList); + } + + super.write(compound, clientPacket); + + if (!clientPacket) + return; + compound.putBoolean("Fistbump", fistBump); + compound.putFloat("Reach", reach); + if (player == null) + return; + compound.put("HeldItem", player.getMainHandItem() + .serializeNBT()); + if (player.spawnedItemEffects != null) { + compound.put("Particle", player.spawnedItemEffects.serializeNBT()); + player.spawnedItemEffects = null; + } + } + + @Override + public void writeSafe(CompoundTag tag) { + NBTHelper.writeEnum(tag, "Mode", mode); + super.writeSafe(tag); + } + + private IItemHandlerModifiable createHandler() { + return new DeployerItemHandler(this); + } + + public void redstoneUpdate() { + if (level.isClientSide) + return; + boolean blockPowered = level.hasNeighborSignal(worldPosition); + if (blockPowered == redstoneLocked) + return; + redstoneLocked = blockPowered; + sendData(); + } + + @OnlyIn(Dist.CLIENT) + public PartialModel getHandPose() { + return mode == Mode.PUNCH ? AllPartialModels.DEPLOYER_HAND_PUNCHING + : heldItem.isEmpty() ? AllPartialModels.DEPLOYER_HAND_POINTING : AllPartialModels.DEPLOYER_HAND_HOLDING; + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(3); + } + + public void discardPlayer() { + if (player == null) + return; + player.getInventory() + .dropAll(); + overflowItems.forEach(itemstack -> player.drop(itemstack, true, false)); + player.discard(); + player = null; + } + + @Override + public void invalidate() { + super.invalidate(); + if (invHandler != null) + invHandler.invalidate(); + } + + public void changeMode() { + mode = mode == Mode.PUNCH ? Mode.USE : Mode.PUNCH; + setChanged(); + sendData(); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) { + if (invHandler == null) + initHandler(); + return invHandler.cast(); + } + return super.getCapability(cap, side); + } + + @Override + public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { + if (super.addToTooltip(tooltip, isPlayerSneaking)) + return true; + if (getSpeed() == 0) + return false; + if (overflowItems.isEmpty()) + return false; + TooltipHelper.addHint(tooltip, "hint.full_deployer"); + return true; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + CreateLang.translate("tooltip.deployer.header") + .forGoggles(tooltip); + + CreateLang.translate("tooltip.deployer." + (mode == Mode.USE ? "using" : "punching")) + .style(ChatFormatting.YELLOW) + .forGoggles(tooltip); + + if (!heldItem.isEmpty()) + CreateLang.translate("tooltip.deployer.contains", Components.translatable(heldItem.getDescriptionId()) + .getString(), heldItem.getCount()) + .style(ChatFormatting.GREEN) + .forGoggles(tooltip); + + float stressAtBase = calculateStressApplied(); + if (StressImpact.isEnabled() && !Mth.equal(stressAtBase, 0)) { + tooltip.add(Components.immutableEmpty()); + addStressImpactStats(tooltip, stressAtBase); + } + + return true; + } + + @OnlyIn(Dist.CLIENT) + public float getHandOffset(float partialTicks) { + if (isVirtual()) + return animatedOffset.getValue(partialTicks); + + float progress = 0; + int timerSpeed = getTimerSpeed(); + PartialModel handPose = getHandPose(); + + if (state == State.EXPANDING) { + progress = 1 - (timer - partialTicks * timerSpeed) / 1000f; + if (fistBump) + progress *= progress; + } + if (state == State.RETRACTING) + progress = (timer - partialTicks * timerSpeed) / 1000f; + float handLength = handPose == AllPartialModels.DEPLOYER_HAND_POINTING ? 0 + : handPose == AllPartialModels.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; + float distance = Math.min(Mth.clamp(progress, 0, 1) * (reach + handLength), 21 / 16f); + + return distance; + } + + public void setAnimatedOffset(float offset) { + animatedOffset.setValue(offset); + } + + RecipeWrapper recipeInv = new RecipeWrapper(new ItemStackHandler(2)); + SandPaperInv sandpaperInv = new SandPaperInv(ItemStack.EMPTY); + + @Nullable + public Recipe getRecipe(ItemStack stack) { + if (player == null || level == null) + return null; + + ItemStack heldItemMainhand = player.getMainHandItem(); + if (heldItemMainhand.getItem() instanceof SandPaperItem) { + sandpaperInv.setItem(0, stack); + return AllRecipeTypes.SANDPAPER_POLISHING.find(sandpaperInv, level) + .orElse(null); + } + + recipeInv.setItem(0, stack); + recipeInv.setItem(1, heldItemMainhand); + + DeployerRecipeSearchEvent event = new DeployerRecipeSearchEvent(this, recipeInv); + + event.addRecipe(() -> SequencedAssemblyRecipe.getRecipe(level, event.getInventory(), + AllRecipeTypes.DEPLOYING.getType(), DeployerApplicationRecipe.class), 100); + event.addRecipe(() -> AllRecipeTypes.DEPLOYING.find(event.getInventory(), level), 50); + event.addRecipe(() -> AllRecipeTypes.ITEM_APPLICATION.find(event.getInventory(), level), 50); + + MinecraftForge.EVENT_BUS.post(event); + return event.getRecipe(); + } + + public DeployerFakePlayer getPlayer() { + return player; + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFakePlayer.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFakePlayer.java new file mode 100644 index 0000000000..1ae88a64d4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFakePlayer.java @@ -0,0 +1,230 @@ +package com.simibubi.create.content.kinetics.deployer; + +import java.util.Objects; +import java.util.OptionalInt; +import java.util.UUID; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.tuple.Pair; + +import com.mojang.authlib.GameProfile; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CKinetics; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.minecraft.core.BlockPos; +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.EntityDamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.UsernameCache; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.entity.EntityEvent; +import net.minecraftforge.event.entity.living.LivingDropsEvent; +import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; +import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class DeployerFakePlayer extends FakePlayer { + + private static final Connection NETWORK_MANAGER = new Connection(PacketFlow.CLIENTBOUND); + public static final UUID fallbackID = UUID.fromString("9e2faded-cafe-4ec2-c314-dad129ae971d"); + Pair blockBreakingProgress; + ItemStack spawnedItemEffects; + public boolean placedTracks; + public boolean onMinecartContraption; + private UUID owner; + + public DeployerFakePlayer(ServerLevel world, @Nullable UUID owner) { + super(world, new DeployerGameProfile(fallbackID, "Deployer", owner)); + connection = new FakePlayNetHandler(world.getServer(), this); + this.owner = owner; + } + + @Override + public OptionalInt openMenu(MenuProvider menuProvider) { + return OptionalInt.empty(); + } + + @Override + public Component getDisplayName() { + return CreateLang.translateDirect("block.deployer.damage_source_name"); + } + + @Override + @OnlyIn(Dist.CLIENT) + public float getEyeHeight(Pose poseIn) { + return 0; + } + + @Override + public Vec3 position() { + return new Vec3(getX(), getY(), getZ()); + } + + @Override + public float getCurrentItemAttackStrengthDelay() { + return 1 / 64f; + } + + @Override + public boolean canEat(boolean ignoreHunger) { + return false; + } + + @Override + public ItemStack eat(Level world, ItemStack stack) { + stack.shrink(1); + return stack; + } + + @Override + public boolean canBeAffected(MobEffectInstance pEffectInstance) { + return false; + } + + @Override + public UUID getUUID() { + return owner == null ? super.getUUID() : owner; + } + + @SubscribeEvent + public static void deployerHasEyesOnHisFeet(EntityEvent.Size event) { + if (event.getEntity() instanceof DeployerFakePlayer) + event.setNewEyeHeight(0); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) { + if (!(event.getSource() instanceof EntityDamageSource)) + return; + EntityDamageSource source = (EntityDamageSource) event.getSource(); + Entity trueSource = source.getEntity(); + if (trueSource != null && trueSource instanceof DeployerFakePlayer) { + DeployerFakePlayer fakePlayer = (DeployerFakePlayer) trueSource; + event.getDrops() + .forEach(stack -> fakePlayer.getInventory() + .placeItemBackInInventory(stack.getItem())); + event.setCanceled(true); + } + } + + @Override + protected void equipEventAndSound(ItemStack p_147219_) {} + + @Override + public void remove(RemovalReason p_150097_) { + if (blockBreakingProgress != null && !level.isClientSide) + level.destroyBlockProgress(getId(), blockBreakingProgress.getKey(), -1); + super.remove(p_150097_); + } + + @SubscribeEvent + public static void deployerKillsDoNotSpawnXP(LivingExperienceDropEvent event) { + if (event.getAttackingPlayer() instanceof DeployerFakePlayer) + event.setCanceled(true); + } + + @SubscribeEvent + public static void entitiesDontRetaliate(LivingSetAttackTargetEvent event) { + if (!(event.getTarget() instanceof DeployerFakePlayer)) + return; + LivingEntity entityLiving = event.getEntityLiving(); + if (!(entityLiving instanceof Mob)) + return; + Mob mob = (Mob) entityLiving; + + CKinetics.DeployerAggroSetting setting = AllConfigs.server().kinetics.ignoreDeployerAttacks.get(); + + switch (setting) { + case ALL: + mob.setTarget(null); + break; + case CREEPERS: + if (mob instanceof Creeper) + mob.setTarget(null); + break; + case NONE: + default: + } + } + + // Credit to Mekanism for this approach. Helps fake players get past claims and + // protection by other mods + private static class DeployerGameProfile extends GameProfile { + + private UUID owner; + + public DeployerGameProfile(UUID id, String name, UUID owner) { + super(id, name); + this.owner = owner; + } + + @Override + public UUID getId() { + return owner == null ? super.getId() : owner; + } + + @Override + public String getName() { + if (owner == null) + return super.getName(); + String lastKnownUsername = UsernameCache.getLastKnownUsername(owner); + return lastKnownUsername == null ? super.getName() : lastKnownUsername; + } + + @Override + public boolean equals(final Object o) { + if (this == o) + return true; + if (!(o instanceof GameProfile otherProfile)) + return false; + return Objects.equals(getId(), otherProfile.getId()) && Objects.equals(getName(), otherProfile.getName()); + } + + @Override + public int hashCode() { + UUID id = getId(); + String name = getName(); + int result = id == null ? 0 : id.hashCode(); + result = 31 * result + (name == null ? 0 : name.hashCode()); + return result; + } + } + + private static class FakePlayNetHandler extends ServerGamePacketListenerImpl { + public FakePlayNetHandler(MinecraftServer server, ServerPlayer playerIn) { + super(server, NETWORK_MANAGER, playerIn); + } + + @Override + public void send(Packet packetIn) {} + + @Override + public void send(Packet packetIn, GenericFutureListener> futureListeners) {} + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFilterSlot.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFilterSlot.java new file mode 100644 index 0000000000..efc746b76e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerFilterSlot.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.kinetics.deployer; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class DeployerFilterSlot extends ValueBoxTransform.Sided { + + @Override + public Vec3 getLocalOffset(BlockState state) { + Direction facing = state.getValue(DeployerBlock.FACING); + Vec3 vec = VecHelper.voxelSpace(8f, 8f, 15.5f); + + vec = VecHelper.rotateCentered(vec, AngleHelper.horizontalAngle(getSide()), Axis.Y); + vec = VecHelper.rotateCentered(vec, AngleHelper.verticalAngle(getSide()), Axis.X); + vec = vec.subtract(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(2 / 16f)); + + return vec; + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + Direction facing = state.getValue(DeployerBlock.FACING); + if (direction.getAxis() == facing.getAxis()) + return false; + if (((DeployerBlock) state.getBlock()).getRotationAxis(state) == direction.getAxis()) + return false; + return true; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + Direction facing = getSide(); + float xRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; + float yRot = AngleHelper.horizontalAngle(facing) + 180; + + if (facing.getAxis() == Axis.Y) + TransformStack.cast(ms) + .rotateY(180 + AngleHelper.horizontalAngle(state.getValue(DeployerBlock.FACING))); + + TransformStack.cast(ms) + .rotateY(yRot) + .rotateX(xRot); + } + + @Override + protected Vec3 getSouthLocation() { + return Vec3.ZERO; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerHandler.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerHandler.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerHandler.java index 36988c0b09..7c3d450f9a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; import static net.minecraftforge.eventbus.api.Event.Result.DEFAULT; import static net.minecraftforge.eventbus.api.Event.Result.DENY; @@ -13,13 +13,14 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.Multimap; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlockItem; -import com.simibubi.create.content.curiosities.tools.SandPaperItem; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.AllTags.AllItemTags; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockItem; +import com.simibubi.create.content.equipment.sandPaper.SandPaperItem; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import net.createmod.catnip.utility.worldWrappers.WrappedWorld; @@ -120,7 +121,7 @@ public class DeployerHandler { } if (!held.isEmpty() && facing == Direction.DOWN - && TileEntityBehaviour.get(world, targetPos, TransportedItemStackHandlerBehaviour.TYPE) != null) + && BlockEntityBehaviour.get(world, targetPos, TransportedItemStackHandlerBehaviour.TYPE) != null) return false; return true; @@ -180,12 +181,18 @@ public class DeployerHandler { .consumesAction()) success = true; } - if (!success && stack.isEdible() && entity instanceof Player) { - Player playerEntity = (Player) entity; - FoodProperties foodProperties = item.getFoodProperties(stack, player); - if (playerEntity.canEat(foodProperties.canAlwaysEat())) { - playerEntity.eat(world, stack); + if (!success && entity instanceof Player playerEntity) { + if (stack.isEdible()) { + FoodProperties foodProperties = item.getFoodProperties(stack, player); + if (playerEntity.canEat(foodProperties.canAlwaysEat())) { + playerEntity.eat(world, stack); + player.spawnedItemEffects = stack.copy(); + success = true; + } + } + if (AllItemTags.DEPLOYABLE_DRINK.matches(stack)) { player.spawnedItemEffects = stack.copy(); + player.setItemInHand(hand, stack.finishUsingItem(world, playerEntity)); success = true; } } @@ -229,8 +236,7 @@ public class DeployerHandler { LeftClickBlock event = ForgeHooks.onLeftClickBlock(player, clickedPos, face); if (event.isCanceled()) return; - if (BlockHelper.extinguishFire(world, player, clickedPos, face)) // FIXME: is there an equivalent in world, - // as there was in 1.15? + if (BlockHelper.extinguishFire(world, player, clickedPos, face)) return; if (event.getUseBlock() != DENY) clickedState.attack(world, clickedPos, player); @@ -320,6 +326,8 @@ public class DeployerHandler { } if (item == Items.ENDER_PEARL) return; + if (AllItemTags.DEPLOYABLE_DRINK.matches(item)) + return; // buckets create their own ray, We use a fake wall to contain the active area Level itemUseWorld = world; @@ -356,7 +364,7 @@ public class DeployerHandler { if (net.minecraftforge.common.ForgeHooks.onBlockBreakEvent(world, gameType, player, pos) == -1) return false; - BlockEntity tileentity = world.getBlockEntity(pos); + BlockEntity blockEntity = world.getBlockEntity(pos); if (player.getMainHandItem() .onBlockStartBreak(pos, player)) return false; @@ -390,7 +398,7 @@ public class DeployerHandler { if (!canHarvest) return true; - Block.getDrops(blockstate, world, pos, tileentity, player, prevHeldItem) + Block.getDrops(blockstate, world, pos, blockEntity, player, prevHeldItem) .forEach(item -> player.getInventory().placeItemBackInInventory(item)); blockstate.spawnAfterBreak(world, pos, prevHeldItem); return true; diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerInstance.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerInstance.java new file mode 100644 index 0000000000..bb929a9c76 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerInstance.java @@ -0,0 +1,132 @@ +package com.simibubi.create.content.kinetics.deployer; + +import static com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.kinetics.base.DirectionalKineticBlock.FACING; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.api.instance.TickableInstance; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.mojang.math.Quaternion; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.util.Mth; + +public class DeployerInstance extends ShaftInstance implements DynamicInstance, TickableInstance { + + final Direction facing; + final float yRot; + final float xRot; + final float zRot; + + protected final OrientedData pole; + + protected OrientedData hand; + + PartialModel currentHand; + float progress; + + public DeployerInstance(MaterialManager materialManager, DeployerBlockEntity blockEntity) { + super(materialManager, blockEntity); + + facing = blockState.getValue(FACING); + + boolean rotatePole = blockState.getValue(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Direction.Axis.Z; + + yRot = AngleHelper.horizontalAngle(facing); + xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; + zRot = rotatePole ? 90 : 0; + + pole = getOrientedMaterial().getModel(AllPartialModels.DEPLOYER_POLE, blockState).createInstance(); + + currentHand = this.blockEntity.getHandPose(); + + hand = getOrientedMaterial().getModel(currentHand, blockState).createInstance(); + + progress = getProgress(AnimationTickHolder.getPartialTicks()); + updateRotation(pole, hand, yRot, xRot, zRot); + updatePosition(); + } + + @Override + public void tick() { + PartialModel handPose = blockEntity.getHandPose(); + + if (currentHand != handPose) { + currentHand = handPose; + getOrientedMaterial().getModel(currentHand, blockState) + .stealInstance(hand); + } + } + + @Override + public void beginFrame() { + + float newProgress = getProgress(AnimationTickHolder.getPartialTicks()); + + if (Mth.equal(newProgress, progress)) return; + + progress = newProgress; + + updatePosition(); + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, hand, pole); + } + + @Override + public void remove() { + super.remove(); + hand.delete(); + pole.delete(); + } + + private float getProgress(float partialTicks) { + if (blockEntity.state == DeployerBlockEntity.State.EXPANDING) { + float f = 1 - (blockEntity.timer - partialTicks * blockEntity.getTimerSpeed()) / 1000f; + if (blockEntity.fistBump) + f *= f; + return f; + } + if (blockEntity.state == DeployerBlockEntity.State.RETRACTING) + return (blockEntity.timer - partialTicks * blockEntity.getTimerSpeed()) / 1000f; + return 0; + } + + private void updatePosition() { + float handLength = currentHand == AllPartialModels.DEPLOYER_HAND_POINTING ? 0 + : currentHand == AllPartialModels.DEPLOYER_HAND_HOLDING ? 4 / 16f : 3 / 16f; + float distance = Math.min(Mth.clamp(progress, 0, 1) * (blockEntity.reach + handLength), 21 / 16f); + Vec3i facingVec = facing.getNormal(); + BlockPos blockPos = getInstancePosition(); + + float x = blockPos.getX() + ((float) facingVec.getX()) * distance; + float y = blockPos.getY() + ((float) facingVec.getY()) * distance; + float z = blockPos.getZ() + ((float) facingVec.getZ()) * distance; + + pole.setPosition(x, y, z); + hand.setPosition(x, y, z); + } + + static void updateRotation(OrientedData pole, OrientedData hand, float yRot, float xRot, float zRot) { + + Quaternion q = Direction.UP.step().rotationDegrees(yRot); + q.mul(Direction.EAST.step().rotationDegrees(xRot)); + + hand.setRotation(q); + + q.mul(Direction.SOUTH.step().rotationDegrees(zRot)); + + pole.setRotation(q); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerItemHandler.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerItemHandler.java new file mode 100644 index 0000000000..ecabcf2ed3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerItemHandler.java @@ -0,0 +1,131 @@ +package com.simibubi.create.content.kinetics.deployer; + +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; + +public class DeployerItemHandler implements IItemHandlerModifiable { + + private DeployerBlockEntity be; + private DeployerFakePlayer player; + + public DeployerItemHandler(DeployerBlockEntity be) { + this.be = be; + this.player = be.player; + } + + @Override + public int getSlots() { + return 1 + be.overflowItems.size(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + return slot >= be.overflowItems.size() ? getHeld() : be.overflowItems.get(slot); + } + + public ItemStack getHeld() { + if (player == null) + return ItemStack.EMPTY; + return player.getMainHandItem(); + } + + public void set(ItemStack stack) { + if (player == null) + return; + if (be.getLevel().isClientSide) + return; + player.setItemInHand(InteractionHand.MAIN_HAND, stack); + be.setChanged(); + be.sendData(); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (slot < be.overflowItems.size()) + return stack; + if (!isItemValid(slot, stack)) + return stack; + + ItemStack held = getHeld(); + if (held.isEmpty()) { + if (!simulate) + set(stack); + return ItemStack.EMPTY; + } + + if (!ItemHandlerHelper.canItemStacksStack(held, stack)) + return stack; + + int space = held.getMaxStackSize() - held.getCount(); + ItemStack remainder = stack.copy(); + ItemStack split = remainder.split(space); + + if (space == 0) + return stack; + if (!simulate) { + held = held.copy(); + held.setCount(held.getCount() + split.getCount()); + set(held); + } + + return remainder; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (amount == 0) + return ItemStack.EMPTY; + + if (slot < be.overflowItems.size()) { + ItemStack itemStack = be.overflowItems.get(slot); + int toExtract = Math.min(amount, itemStack.getCount()); + ItemStack extracted = simulate ? itemStack.copy() : itemStack.split(toExtract); + extracted.setCount(toExtract); + if (!simulate && itemStack.isEmpty()) + be.overflowItems.remove(slot); + if (!simulate && !extracted.isEmpty()) + be.setChanged(); + return extracted; + } + + ItemStack held = getHeld(); + if (amount == 0 || held.isEmpty()) + return ItemStack.EMPTY; + if (!be.filtering.getFilter() + .isEmpty() && be.filtering.test(held)) + return ItemStack.EMPTY; + if (simulate) + return held.copy() + .split(amount); + + ItemStack toReturn = held.split(amount); + be.setChanged(); + be.sendData(); + return toReturn; + } + + @Override + public int getSlotLimit(int slot) { + return Math.min(getStackInSlot(slot).getMaxStackSize(), 64); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + FilteringBehaviour filteringBehaviour = be.getBehaviour(FilteringBehaviour.TYPE); + return filteringBehaviour == null || filteringBehaviour.test(stack); + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) { + if (slot < be.overflowItems.size()) { + be.overflowItems.set(slot, stack); + return; + } + set(stack); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java index b39881ee9a..8b75ce3aff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovementBehaviour.java @@ -1,7 +1,8 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; import java.util.Arrays; import java.util.List; +import java.util.UUID; import javax.annotation.Nullable; @@ -11,26 +12,24 @@ import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTags.AllBlockTags; -import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.filtering.SchematicInstances; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.schematics.SchematicInstances; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; import com.simibubi.create.foundation.utility.BlockHelper; -import com.simibubi.create.foundation.utility.NBTProcessors; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; @@ -47,7 +46,6 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.util.BlockSnapshot; @@ -108,8 +106,8 @@ public class DeployerMovementBehaviour implements MovementBehaviour { DeployerHandler.activate(player, vec, pos, facingVec, mode); if ((context.contraption instanceof MountedContraption || context.contraption instanceof CarriageContraption) - && player.placedTracks && context.tileData != null && context.tileData.contains("Owner")) - AllAdvancements.SELF_DEPLOYING.awardTo(world.getPlayerByUUID(context.tileData.getUUID("Owner"))); + && player.placedTracks && context.blockEntityData != null && context.blockEntityData.contains("Owner")) + AllAdvancements.SELF_DEPLOYING.awardTo(world.getPlayerByUUID(context.blockEntityData.getUUID("Owner"))); } protected void activateAsSchematicPrinter(MovementContext context, BlockPos pos, DeployerFakePlayer player, @@ -141,28 +139,20 @@ public class DeployerMovementBehaviour implements MovementBehaviour { ItemStack contextStack = requiredItems.isEmpty() ? ItemStack.EMPTY : requiredItems.get(0).stack; if (!context.contraption.hasUniversalCreativeCrate) { - IItemHandler iItemHandler = context.contraption.getSharedInventory(); + IItemHandler itemHandler = context.contraption.getSharedInventory(); for (ItemRequirement.StackRequirement required : requiredItems) { ItemStack stack= ItemHelper - .extract(iItemHandler, required::matches, ExtractionCountMode.EXACTLY, + .extract(itemHandler, required::matches, ExtractionCountMode.EXACTLY, required.stack.getCount(), true); if (stack.isEmpty()) return; } for (ItemRequirement.StackRequirement required : requiredItems) - contextStack = ItemHelper.extract(iItemHandler, required::matches, + contextStack = ItemHelper.extract(itemHandler, required::matches, ExtractionCountMode.EXACTLY, required.stack.getCount(), false); } - CompoundTag data = null; - if (AllBlockTags.SAFE_NBT.matches(blockState)) { - BlockEntity tile = schematicWorld.getBlockEntity(pos); - if (tile != null) { - data = tile.saveWithFullMetadata(); - data = NBTProcessors.process(tile, data, true); - } - } - + CompoundTag data = BlockHelper.prepareBlockEntityData(blockState, schematicWorld.getBlockEntity(pos)); BlockSnapshot blocksnapshot = BlockSnapshot.create(world.dimension(), world, pos); BlockHelper.placeSchematicBlock(world, blockState, pos, contextStack, data); if (ForgeEventFactory.onBlockPlace(player, blocksnapshot, Direction.UP)) @@ -221,7 +211,7 @@ public class DeployerMovementBehaviour implements MovementBehaviour { return; cancelStall(context); - context.tileData.put("Inventory", player.getInventory() + context.blockEntityData.put("Inventory", player.getInventory() .save(new ListTag())); player.discard(); } @@ -274,25 +264,26 @@ public class DeployerMovementBehaviour implements MovementBehaviour { private DeployerFakePlayer getPlayer(MovementContext context) { if (!(context.temporaryData instanceof DeployerFakePlayer) && context.world instanceof ServerLevel) { - DeployerFakePlayer deployerFakePlayer = new DeployerFakePlayer((ServerLevel) context.world); + UUID owner = context.blockEntityData.contains("Owner") ? context.blockEntityData.getUUID("Owner") : null; + DeployerFakePlayer deployerFakePlayer = new DeployerFakePlayer((ServerLevel) context.world, owner); deployerFakePlayer.onMinecartContraption = context.contraption instanceof MountedContraption; deployerFakePlayer.getInventory() - .load(context.tileData.getList("Inventory", Tag.TAG_COMPOUND)); + .load(context.blockEntityData.getList("Inventory", Tag.TAG_COMPOUND)); if (context.data.contains("HeldItem")) deployerFakePlayer.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.of(context.data.getCompound("HeldItem"))); - context.tileData.remove("Inventory"); + context.blockEntityData.remove("Inventory"); context.temporaryData = deployerFakePlayer; } return (DeployerFakePlayer) context.temporaryData; } private ItemStack getFilter(MovementContext context) { - return ItemStack.of(context.tileData.getCompound("Filter")); + return ItemStack.of(context.blockEntityData.getCompound("Filter")); } private Mode getMode(MovementContext context) { - return NBTHelper.readEnum(context.tileData, "Mode", Mode.class); + return NBTHelper.readEnum(context.blockEntityData, "Mode", Mode.class); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovingInteraction.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovingInteraction.java new file mode 100644 index 0000000000..c27643b2f7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerMovingInteraction.java @@ -0,0 +1,69 @@ +package com.simibubi.create.content.kinetics.deployer; + +import java.util.UUID; + +import org.apache.commons.lang3.tuple.MutablePair; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.contraptions.mounted.MountedContraption; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; + +public class DeployerMovingInteraction extends MovingInteractionBehaviour { + + @Override + public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, + AbstractContraptionEntity contraptionEntity) { + MutablePair actor = contraptionEntity.getContraption() + .getActorAt(localPos); + if (actor == null || actor.right == null) + return false; + + MovementContext ctx = actor.right; + ItemStack heldStack = player.getItemInHand(activeHand); + if (heldStack.getItem() + .equals(AllItems.WRENCH.get())) { + DeployerBlockEntity.Mode mode = NBTHelper.readEnum(ctx.blockEntityData, "Mode", DeployerBlockEntity.Mode.class); + NBTHelper.writeEnum(ctx.blockEntityData, "Mode", + mode == DeployerBlockEntity.Mode.PUNCH ? DeployerBlockEntity.Mode.USE : DeployerBlockEntity.Mode.PUNCH); + + } else { + if (ctx.world.isClientSide) + return true; // we'll try again on the server side + DeployerFakePlayer fake = null; + + if (!(ctx.temporaryData instanceof DeployerFakePlayer) && ctx.world instanceof ServerLevel) { + UUID owner = ctx.blockEntityData.contains("Owner") ? ctx.blockEntityData.getUUID("Owner") : null; + DeployerFakePlayer deployerFakePlayer = new DeployerFakePlayer((ServerLevel) ctx.world, owner); + deployerFakePlayer.onMinecartContraption = ctx.contraption instanceof MountedContraption; + deployerFakePlayer.getInventory() + .load(ctx.blockEntityData.getList("Inventory", Tag.TAG_COMPOUND)); + ctx.temporaryData = fake = deployerFakePlayer; + ctx.blockEntityData.remove("Inventory"); + } else + fake = (DeployerFakePlayer) ctx.temporaryData; + + if (fake == null) + return false; + + ItemStack deployerItem = fake.getMainHandItem(); + player.setItemInHand(activeHand, deployerItem.copy()); + fake.setItemInHand(InteractionHand.MAIN_HAND, heldStack.copy()); + ctx.blockEntityData.put("HeldItem", heldStack.serializeNBT()); + ctx.data.put("HeldItem", heldStack.serializeNBT()); + } +// if (index >= 0) +// setContraptionActorData(contraptionEntity, index, info, ctx); + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRecipeSearchEvent.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRecipeSearchEvent.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRecipeSearchEvent.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRecipeSearchEvent.java index e1c6db1fae..42f1dfd47b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerRecipeSearchEvent.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRecipeSearchEvent.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; import java.util.Optional; import java.util.function.Supplier; @@ -11,14 +11,14 @@ import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.items.wrapper.RecipeWrapper; public class DeployerRecipeSearchEvent extends Event { - private final DeployerTileEntity tileEntity; + private final DeployerBlockEntity blockEntity; private final RecipeWrapper inventory; @Nullable Recipe recipe = null; private int maxPriority = 0; - public DeployerRecipeSearchEvent(DeployerTileEntity tileEntity, RecipeWrapper inventory) { - this.tileEntity = tileEntity; + public DeployerRecipeSearchEvent(DeployerBlockEntity blockEntity, RecipeWrapper inventory) { + this.blockEntity = blockEntity; this.inventory = inventory; } @@ -27,8 +27,8 @@ public class DeployerRecipeSearchEvent extends Event { return true; } - public DeployerTileEntity getTileEntity() { - return tileEntity; + public DeployerBlockEntity getBlockEntity() { + return blockEntity; } public RecipeWrapper getInventory() { diff --git a/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRenderer.java new file mode 100644 index 0000000000..c71f5ce2a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/DeployerRenderer.java @@ -0,0 +1,233 @@ +package com.simibubi.create.content.kinetics.deployer; + +import static com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE; +import static com.simibubi.create.content.kinetics.base.DirectionalKineticBlock.FACING; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.deployer.DeployerBlockEntity.Mode; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.util.Mth; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class DeployerRenderer extends SafeBlockEntityRenderer { + + public DeployerRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(DeployerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + renderItem(be, partialTicks, ms, buffer, light, overlay); + FilteringRenderer.renderOnBlockEntity(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) return; + + renderComponents(be, partialTicks, ms, buffer, light, overlay); + } + + protected void renderItem(DeployerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (be.heldItem.isEmpty()) return; + + BlockState deployerState = be.getBlockState(); + Vec3 offset = getHandOffset(be, partialTicks, deployerState).add(VecHelper.getCenterOf(BlockPos.ZERO)); + ms.pushPose(); + ms.translate(offset.x, offset.y, offset.z); + + Direction facing = deployerState.getValue(FACING); + boolean punching = be.mode == Mode.PUNCH; + + float yRot = AngleHelper.horizontalAngle(facing) + 180; + float xRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; + boolean displayMode = facing == Direction.UP && be.getSpeed() == 0 && !punching; + + ms.mulPose(Vector3f.YP.rotationDegrees(yRot)); + if (!displayMode) { + ms.mulPose(Vector3f.XP.rotationDegrees(xRot)); + ms.translate(0, 0, -11 / 16f); + } + + if (punching) + ms.translate(0, 1 / 8f, -1 / 16f); + + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + + TransformType transform = TransformType.NONE; + boolean isBlockItem = (be.heldItem.getItem() instanceof BlockItem) + && itemRenderer.getModel(be.heldItem, be.getLevel(), null, 0) + .isGui3d(); + + if (displayMode) { + float scale = isBlockItem ? 1.25f : 1; + ms.translate(0, isBlockItem ? 9 / 16f : 11 / 16f, 0); + ms.scale(scale, scale, scale); + transform = TransformType.GROUND; + ms.mulPose(Vector3f.YP.rotationDegrees(WorldTickHolder.getRenderTime(be.getLevel()))); + + } else { + float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f; + ms.scale(scale, scale, scale); + transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED; + } + + itemRenderer.renderStatic(be.heldItem, transform, light, overlay, ms, buffer, 0); + ms.popPose(); + } + + protected void renderComponents(DeployerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + if (!Backend.canUseInstancing(be.getLevel())) { + KineticBlockEntityRenderer.renderRotatingKineticBlock(be, getRenderedBlockState(be), ms, vb, light); + } + + BlockState blockState = be.getBlockState(); + Vec3 offset = getHandOffset(be, partialTicks, blockState); + + SuperByteBuffer pole = CachedPartialBuffers.partial(AllPartialModels.DEPLOYER_POLE, blockState); + SuperByteBuffer hand = CachedPartialBuffers.partial(be.getHandPose(), blockState); + + transform(pole.translate(offset.x, offset.y, offset.z), blockState, true) + .light(light) + .renderInto(ms, vb); + transform(hand.translate(offset.x, offset.y, offset.z), blockState, false) + .light(light) + .renderInto(ms, vb); + } + + protected Vec3 getHandOffset(DeployerBlockEntity be, float partialTicks, BlockState blockState) { + float distance = be.getHandOffset(partialTicks); + return Vec3.atLowerCornerOf(blockState.getValue(FACING).getNormal()).scale(distance); + } + + protected BlockState getRenderedBlockState(KineticBlockEntity be) { + return KineticBlockEntityRenderer.shaft(KineticBlockEntityRenderer.getRotationAxisOf(be)); + } + + private static SuperByteBuffer transform(SuperByteBuffer buffer, BlockState deployerState, boolean axisDirectionMatters) { + Direction facing = deployerState.getValue(FACING); + + float yRot = AngleHelper.horizontalAngle(facing); + float xRot = facing == Direction.UP ? 270 : facing == Direction.DOWN ? 90 : 0; + float zRot = + axisDirectionMatters && (deployerState.getValue(AXIS_ALONG_FIRST_COORDINATE) ^ facing.getAxis() == Axis.Z) ? 90 + : 0; + + buffer.rotateCentered(Direction.UP, (float) ((yRot) / 180 * Math.PI)); + buffer.rotateCentered(Direction.EAST, (float) ((xRot) / 180 * Math.PI)); + buffer.rotateCentered(Direction.SOUTH, (float) ((zRot) / 180 * Math.PI)); + return buffer; + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + VertexConsumer builder = buffer.getBuffer(RenderType.solid()); + BlockState blockState = context.state; + Mode mode = NBTHelper.readEnum(context.blockEntityData, "Mode", Mode.class); + PartialModel handPose = getHandPose(mode); + + float speed = (float) context.getAnimationSpeed(); + if (context.contraption.stalled) + speed = 0; + + SuperByteBuffer shaft = CachedBlockBuffers.block(AllBlocks.SHAFT.getDefaultState()); + SuperByteBuffer pole = CachedPartialBuffers.partial(AllPartialModels.DEPLOYER_POLE, blockState); + SuperByteBuffer hand = CachedPartialBuffers.partial(handPose, blockState); + + double factor; + if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) { + factor = Mth.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f; + } else { + Vec3 center = VecHelper.getCenterOf(new BlockPos(context.position)); + double distance = context.position.distanceTo(center); + double nextDistance = context.position.add(context.motion) + .distanceTo(center); + factor = .5f - Mth.clamp(Mth.lerp(AnimationTickHolder.getPartialTicks(), distance, nextDistance), 0, 1); + } + + Vec3 offset = Vec3.atLowerCornerOf(blockState.getValue(FACING) + .getNormal()).scale(factor); + + PoseStack m = matrices.getModel(); + m.pushPose(); + + m.pushPose(); + Axis axis = Axis.Y; + if (context.state.getBlock() instanceof IRotate) { + IRotate def = (IRotate) context.state.getBlock(); + axis = def.getRotationAxis(context.state); + } + + float time = WorldTickHolder.getRenderTime(context.world) / 20; + float angle = (time * speed) % 360; + + TransformStack.cast(m) + .centre() + .rotateY(axis == Axis.Z ? 90 : 0) + .rotateZ(axis.isHorizontal() ? 90 : 0) + .unCentre(); + shaft.transform(m); + shaft.rotateCentered(Direction.get(AxisDirection.POSITIVE, Axis.Y), angle); + m.popPose(); + + if (!context.disabled) + m.translate(offset.x, offset.y, offset.z); + pole.transform(m); + hand.transform(m); + + transform(pole, blockState, true); + transform(hand, blockState, false); + + shaft.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), builder); + pole.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), builder); + hand.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), builder); + + m.popPose(); + } + + static PartialModel getHandPose(DeployerBlockEntity.Mode mode) { + return mode == DeployerBlockEntity.Mode.PUNCH ? AllPartialModels.DEPLOYER_HAND_PUNCHING : AllPartialModels.DEPLOYER_HAND_POINTING; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/ItemApplicationRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/ItemApplicationRecipe.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/processing/ItemApplicationRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/ItemApplicationRecipe.java index a1fe53f371..a57cb1374e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/ItemApplicationRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/ItemApplicationRecipe.java @@ -1,8 +1,9 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.kinetics.deployer; import com.google.gson.JsonObject; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.GsonHelper; @@ -34,7 +35,7 @@ public class ItemApplicationRecipe extends ProcessingRecipe { @Override protected int getMaxOutputCount() { - return 9; + return 4; } public boolean shouldKeepHeldItem() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/ManualApplicationRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/deployer/ManualApplicationRecipe.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/deployer/ManualApplicationRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/deployer/ManualApplicationRecipe.java index 663d18a847..7dc3a278eb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/ManualApplicationRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/deployer/ManualApplicationRecipe.java @@ -1,14 +1,13 @@ -package com.simibubi.create.content.contraptions.components.deployer; +package com.simibubi.create.content.kinetics.deployer; import java.util.List; import java.util.Optional; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ItemApplicationRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.CreateAdvancement; import com.simibubi.create.foundation.utility.BlockHelper; @@ -43,8 +42,6 @@ public class ManualApplicationRecipe extends ItemApplicationRecipe { BlockPos pos = event.getPos(); BlockState blockState = level.getBlockState(pos); - if (level.isClientSide()) - return; if (heldItem.isEmpty()) return; if (blockState.isAir()) @@ -65,6 +62,12 @@ public class ManualApplicationRecipe extends ItemApplicationRecipe { if (foundRecipe.isEmpty()) return; + + event.setCancellationResult(InteractionResult.SUCCESS); + event.setCanceled(true); + + if (level.isClientSide()) + return; level.playSound(null, pos, SoundEvents.COPPER_BREAK, SoundSource.PLAYERS, 1, 1.45f); ManualApplicationRecipe recipe = (ManualApplicationRecipe) foundRecipe.get(); @@ -75,9 +78,11 @@ public class ManualApplicationRecipe extends ItemApplicationRecipe { recipe.rollResults() .forEach(stack -> Block.popResource(level, pos, stack)); + boolean creative = event.getPlayer() != null && event.getPlayer() + .isCreative(); boolean unbreakable = heldItem.hasTag() && heldItem.getTag() .getBoolean("Unbreakable"); - boolean keepHeld = recipe.shouldKeepHeldItem(); + boolean keepHeld = recipe.shouldKeepHeldItem() || creative; if (!unbreakable && !keepHeld) { if (heldItem.isDamageableItem()) @@ -87,9 +92,6 @@ public class ManualApplicationRecipe extends ItemApplicationRecipe { } awardAdvancements(event.getPlayer(), transformedBlock); - - event.setCancellationResult(InteractionResult.SUCCESS); - event.setCanceled(true); } private static void awardAdvancements(Player player, BlockState placed) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorInstance.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java rename to src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorInstance.java index 586510a9ab..a04500a74c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DrillActorInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillActorInstance.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.kinetics.drill; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.mojang.math.Quaternion; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.actors.flwdata.ActorData; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.actors.flwdata.ActorData; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; import com.simibubi.create.foundation.render.AllMaterialSpecs; import net.createmod.catnip.utility.VecHelper; @@ -39,7 +39,7 @@ public class DrillActorInstance extends ActorInstance { else eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0); - drillHead = material.getModel(AllBlockPartials.DRILL_HEAD, state).createInstance(); + drillHead = material.getModel(AllPartialModels.DRILL_HEAD, state).createInstance(); drillHead.setPosition(context.localPos) .setBlockLight(localBlockLight()) diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlock.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlock.java new file mode 100644 index 0000000000..32e632a969 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlock.java @@ -0,0 +1,201 @@ +package com.simibubi.create.content.kinetics.drill; + +import java.util.List; +import java.util.function.Predicate; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.createmod.catnip.utility.placement.PlacementOffset; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class DrillBlock extends DirectionalKineticBlock implements IBE, SimpleWaterloggedBlock { + public static DamageSource damageSourceDrill = new DamageSource("create.mechanical_drill").bypassArmor(); + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public DrillBlock(Properties properties) { + super(properties); + registerDefaultState(super.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, false)); + } + + @Override + public void entityInside(BlockState state, Level worldIn, BlockPos pos, Entity entityIn) { + if (entityIn instanceof ItemEntity) + return; + if (!new AABB(pos).deflate(.1f) + .intersects(entityIn.getBoundingBox())) + return; + withBlockEntityDo(worldIn, pos, be -> { + if (be.getSpeed() == 0) + return; + entityIn.hurt(damageSourceDrill, (float) getDamage(be.getSpeed())); + }); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.CASING_12PX.get(state.getValue(FACING)); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + withBlockEntityDo(worldIn, pos, DrillBlockEntity::destroyNextTick); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(FACING) + .getAxis(); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face == state.getValue(FACING) + .getOpposite(); + } + + @Override + public PushReaction getPistonPushReaction(BlockState state) { + return PushReaction.NORMAL; + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + public FluidState getFluidState(BlockState state) { + return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) : Fluids.EMPTY.defaultFluidState(); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(BlockStateProperties.WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, + LevelAccessor world, BlockPos pos, BlockPos neighbourPos) { + if (state.getValue(BlockStateProperties.WATERLOGGED)) + world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + return state; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + FluidState FluidState = context.getLevel().getFluidState(context.getClickedPos()); + return super.getStateForPlacement(context).setValue(BlockStateProperties.WATERLOGGED, Boolean.valueOf(FluidState.getType() == Fluids.WATER)); + } + + public static double getDamage(float speed) { + float speedAbs = Math.abs(speed); + double sub1 = Math.min(speedAbs / 16, 2); + double sub2 = Math.min(speedAbs / 32, 4); + double sub3 = Math.min(speedAbs / 64, 4); + return Mth.clamp(sub1 + sub2 + sub3, 1, 10); + } + + @Override + public Class getBlockEntityClass() { + return DrillBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.DRILL.get(); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + ItemStack heldItem = player.getItemInHand(hand); + + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldItem)) { + placementHelper.getOffset(player, world, state, pos, ray) + .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); + return InteractionResult.SUCCESS; + } + } + + return InteractionResult.PASS; + } + + @MethodsReturnNonnullByDefault + private static class PlacementHelper implements IPlacementHelper { + + @Override + public Predicate getItemPredicate() { + return AllBlocks.MECHANICAL_DRILL::isIn; + } + + @Override + public Predicate getStatePredicate() { + return AllBlocks.MECHANICAL_DRILL::has; + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, + BlockHitResult ray) { + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), + state.getValue(FACING) + .getAxis(), + dir -> world.getBlockState(pos.relative(dir)) + .getMaterial() + .isReplaceable()); + + if (directions.isEmpty()) + return PlacementOffset.fail(); + else { + return PlacementOffset.success(pos.relative(directions.get(0)), + s -> s.setValue(FACING, state.getValue(FACING))); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlockEntity.java new file mode 100644 index 0000000000..e8b3ffb5f7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillBlockEntity.java @@ -0,0 +1,20 @@ +package com.simibubi.create.content.kinetics.drill; + +import com.simibubi.create.content.kinetics.base.BlockBreakingKineticBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class DrillBlockEntity extends BlockBreakingKineticBlockEntity { + + public DrillBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected BlockPos getBreakingPos() { + return getBlockPos().relative(getBlockState().getValue(DrillBlock.FACING)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillInstance.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillInstance.java new file mode 100644 index 0000000000..8112622bf8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillInstance.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.kinetics.drill; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class DrillInstance extends SingleRotatingInstance { + + public DrillInstance(MaterialManager materialManager, DrillBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + BlockState referenceState = blockEntity.getBlockState(); + Direction facing = referenceState.getValue(BlockStateProperties.FACING); + return getRotatingMaterial().getModel(AllPartialModels.DRILL_HEAD, referenceState, facing); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillMovementBehaviour.java new file mode 100644 index 0000000000..184a86b1e6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillMovementBehaviour.java @@ -0,0 +1,69 @@ +package com.simibubi.create.content.kinetics.drill; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ActorInstance; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { + + @Override + public boolean isActive(MovementContext context) { + return super.isActive(context) + && !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(DrillBlock.FACING) + .getOpposite()); + } + + @Override + public Vec3 getActiveAreaOffset(MovementContext context) { + return Vec3.atLowerCornerOf(context.state.getValue(DrillBlock.FACING) + .getNormal()).scale(.65f); + } + + @Override + @OnlyIn(value = Dist.CLIENT) + public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + if (!ContraptionRenderDispatcher.canInstance()) + DrillRenderer.renderInContraption(context, renderWorld, matrices, buffer); + } + + @Override + public boolean hasSpecialInstancedRendering() { + return true; + } + + @Nullable + @Override + public ActorInstance createInstance(MaterialManager materialManager, VirtualRenderWorld simulationWorld, MovementContext context) { + return new DrillActorInstance(materialManager, simulationWorld, context); + } + + @Override + protected DamageSource getDamageSource() { + return DrillBlock.damageSourceDrill; + } + + @Override + public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { + return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos) + .isEmpty() && !AllTags.AllBlockTags.TRACKS.matches(state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/drill/DrillRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillRenderer.java new file mode 100644 index 0000000000..522fa0278b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/drill/DrillRenderer.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.kinetics.drill; + +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class DrillRenderer extends KineticBlockEntityRenderer { + + public DrillRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected SuperByteBuffer getRotatedModel(DrillBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacing(AllPartialModels.DRILL_HEAD, state); + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + BlockState state = context.state; + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.DRILL_HEAD, state); + Direction facing = state.getValue(DrillBlock.FACING); + + float speed = (float) (context.contraption.stalled + || !VecHelper.isVecPointingTowards(context.relativeMotion, facing + .getOpposite()) ? context.getAnimationSpeed() : 0); + float time = AnimationTickHolder.getRenderTime() / 20; + float angle = (float) (((time * speed) % 360)); + + superBuffer + .transform(matrices.getModel()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing)) + .rotateZ(angle) + .unCentre() + .light(matrices.getWorld(), + ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java b/src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrent.java similarity index 85% rename from src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrent.java index c715cc43a0..d182307869 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrent.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.fan; +package com.simibubi.create.content.kinetics.fan; import java.util.ArrayList; import java.util.Iterator; @@ -7,14 +7,13 @@ import java.util.List; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllTags; -import com.simibubi.create.content.contraptions.particle.AirFlowParticleData; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing.Type; +import com.simibubi.create.content.decoration.copycat.CopycatBlock; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.fan.FanProcessing.Type; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; @@ -30,6 +29,7 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; @@ -49,7 +49,7 @@ public class AirCurrent { public boolean pushing; public float maxDistance; - protected List> affectedItemHandlers = + protected List> affectedItemHandlers = new ArrayList<>(); protected List caughtEntities = new ArrayList<>(); @@ -69,7 +69,7 @@ public class AirCurrent { Vec3 pos = VecHelper.getCenterOf(source.getAirCurrentPos()) .add(Vec3.atLowerCornerOf(facing.getNormal()) .scale(offset)); - if (world.random.nextFloat() < AllConfigs.CLIENT.fanParticleDensity.get()) + if (world.random.nextFloat() < AllConfigs.client().fanParticleDensity.get()) world.addParticle(new AirFlowParticleData(source.getAirCurrentPos()), pos.x, pos.y, pos.z, 0, 0, 0); } @@ -110,7 +110,7 @@ public class AirCurrent { ((ServerPlayer) entity).connection.aboveGroundTickCount = 0; entityDistance -= .5f; - InWorldProcessing.Type processingType = getSegmentAt((float) entityDistance); + FanProcessing.Type processingType = getSegmentAt((float) entityDistance); if (processingType == null || processingType == Type.NONE) continue; @@ -120,9 +120,9 @@ public class AirCurrent { processingType.spawnParticlesForProcessing(world, entity.position()); continue; } - if (InWorldProcessing.canProcess(itemEntity, processingType)) - if (InWorldProcessing.applyProcessing(itemEntity, processingType) - && source instanceof EncasedFanTileEntity fan) + if (FanProcessing.canProcess(itemEntity, processingType)) + if (FanProcessing.applyProcessing(itemEntity, processingType) + && source instanceof EncasedFanBlockEntity fan) fan.award(AllAdvancements.FAN_PROCESSING); continue; } @@ -155,7 +155,7 @@ public class AirCurrent { AirCurrentSegment currentSegment = new AirCurrentSegment(); segments.clear(); currentSegment.startOffset = 0; - InWorldProcessing.Type type = Type.NONE; + FanProcessing.Type type = Type.NONE; int limit = (int) (maxDistance + .5f); int searchStart = pushing ? 0 : limit; @@ -164,7 +164,7 @@ public class AirCurrent { for (int i = searchStart; i * searchStep <= searchEnd * searchStep; i += searchStep) { BlockPos currentPos = start.relative(direction, i); - InWorldProcessing.Type newType = InWorldProcessing.Type.byBlock(world, currentPos); + FanProcessing.Type newType = FanProcessing.Type.byBlock(world, currentPos); if (newType != Type.NONE) type = newType; if (currentSegment.type != type || currentSegment.startOffset == 0) { @@ -214,7 +214,8 @@ public class AirCurrent { if (!world.isLoaded(currentPos)) break; BlockState state = world.getBlockState(currentPos); - if (shouldAlwaysPass(state)) + BlockState copycatState = CopycatBlock.getMaterial(world, currentPos); + if (shouldAlwaysPass(copycatState.isAir() ? state : copycatState)) continue; VoxelShape voxelshape = state.getCollisionShape(world, currentPos, CollisionContext.empty()); if (voxelshape.isEmpty()) @@ -265,9 +266,13 @@ public class AirCurrent { BlockPos pos = start.relative(direction, i) .below(offset); TransportedItemStackHandlerBehaviour behaviour = - TileEntityBehaviour.get(world, pos, TransportedItemStackHandlerBehaviour.TYPE); + BlockEntityBehaviour.get(world, pos, TransportedItemStackHandlerBehaviour.TYPE); + FanProcessing.Type typeAtHandler = type; + if (world.getFluidState(pos) + .is(Fluids.WATER)) + typeAtHandler = Type.SPLASHING; if (behaviour != null) - affectedItemHandlers.add(Pair.of(behaviour, type)); + affectedItemHandlers.add(Pair.of(behaviour, typeAtHandler)); if (direction.getAxis() .isVertical()) break; @@ -279,7 +284,7 @@ public class AirCurrent { for (Pair pair : affectedItemHandlers) { TransportedItemStackHandlerBehaviour handler = pair.getKey(); Level world = handler.getWorld(); - InWorldProcessing.Type processingType = pair.getRight(); + FanProcessing.Type processingType = pair.getRight(); handler.handleProcessingOnAllItems((transported) -> { if (world.isClientSide) { @@ -287,8 +292,8 @@ public class AirCurrent { processingType.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported)); return TransportedResult.doNothing(); } - TransportedResult applyProcessing = InWorldProcessing.applyProcessing(transported, world, processingType); - if (!applyProcessing.doesNothing() && source instanceof EncasedFanTileEntity fan) + TransportedResult applyProcessing = FanProcessing.applyProcessing(transported, world, processingType); + if (!applyProcessing.doesNothing() && source instanceof EncasedFanBlockEntity fan) fan.award(AllAdvancements.FAN_PROCESSING); return applyProcessing; }); @@ -299,7 +304,7 @@ public class AirCurrent { return AllTags.AllBlockTags.FAN_TRANSPARENT.matches(state); } - public InWorldProcessing.Type getSegmentAt(float offset) { + public FanProcessing.Type getSegmentAt(float offset) { for (AirCurrentSegment airCurrentSegment : segments) { if (offset > airCurrentSegment.endOffset && pushing) continue; @@ -307,11 +312,11 @@ public class AirCurrent { continue; return airCurrentSegment.type; } - return InWorldProcessing.Type.NONE; + return FanProcessing.Type.NONE; } public static class AirCurrentSegment { - InWorldProcessing.Type type; + FanProcessing.Type type; int startOffset; int endOffset; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrentSound.java b/src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrentSound.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrentSound.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrentSound.java index b4ef2ea95d..ad48114bb5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrentSound.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/AirCurrentSound.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.fan; +package com.simibubi.create.content.kinetics.fan; import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; import net.minecraft.sounds.SoundEvent; diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticle.java b/src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticle.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticle.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticle.java index efa52db3d3..7dbf4ba625 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticle.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticle.java @@ -1,10 +1,8 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.kinetics.fan; import javax.annotation.Nonnull; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.fan.IAirCurrentSource; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.theme.Color; @@ -99,9 +97,9 @@ public class AirFlowParticle extends SimpleAnimatedParticle { public void morphType(double distance) { if (source.getAirCurrent() == null) return; - InWorldProcessing.Type type = source.getAirCurrent().getSegmentAt((float) distance); + FanProcessing.Type type = source.getAirCurrent().getSegmentAt((float) distance); - if (type == InWorldProcessing.Type.SPLASHING) { + if (type == FanProcessing.Type.SPLASHING) { setColor(Color.mixColors(0x4499FF, 0x2277FF, level.random.nextFloat())); setAlpha(1f); selectSprite(level.random.nextInt(3)); @@ -113,7 +111,7 @@ public class AirFlowParticle extends SimpleAnimatedParticle { zd * .125f); } - if (type == InWorldProcessing.Type.SMOKING) { + if (type == FanProcessing.Type.SMOKING) { setColor(Color.mixColors(0x0, 0x555555, level.random.nextFloat())); setAlpha(1f); selectSprite(level.random.nextInt(3)); @@ -125,7 +123,7 @@ public class AirFlowParticle extends SimpleAnimatedParticle { zd * .125f); } - if (type == InWorldProcessing.Type.HAUNTING) { + if (type == FanProcessing.Type.HAUNTING) { setColor(Color.mixColors(0x0, 0x126568, level.random.nextFloat())); setAlpha(1f); selectSprite(level.random.nextInt(3)); @@ -137,7 +135,7 @@ public class AirFlowParticle extends SimpleAnimatedParticle { zd * .125f); } - if (type == InWorldProcessing.Type.BLASTING) { + if (type == FanProcessing.Type.BLASTING) { setColor(Color.mixColors(0xFF4400, 0xFF8855, level.random.nextFloat())); setAlpha(.5f); selectSprite(level.random.nextInt(3)); @@ -178,10 +176,10 @@ public class AirFlowParticle extends SimpleAnimatedParticle { public Particle createParticle(AirFlowParticleData data, ClientLevel worldIn, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { - BlockEntity te = worldIn.getBlockEntity(new BlockPos(data.posX, data.posY, data.posZ)); - if (!(te instanceof IAirCurrentSource)) - te = null; - return new AirFlowParticle(worldIn, (IAirCurrentSource) te, x, y, z, this.spriteSet); + BlockEntity be = worldIn.getBlockEntity(new BlockPos(data.posX, data.posY, data.posZ)); + if (!(be instanceof IAirCurrentSource)) + be = null; + return new AirFlowParticle(worldIn, (IAirCurrentSource) be, x, y, z, this.spriteSet); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticleData.java b/src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticleData.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticleData.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticleData.java index fa0954bee9..9655950b93 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/AirFlowParticleData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/AirFlowParticleData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.kinetics.fan; import java.util.Locale; @@ -7,6 +7,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllParticleTypes; +import com.simibubi.create.foundation.particle.ICustomParticleDataWithSprite; import net.minecraft.client.particle.ParticleEngine.SpriteParticleRegistration; import net.minecraft.core.Vec3i; diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlock.java b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlock.java new file mode 100644 index 0000000000..fa2562123d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlock.java @@ -0,0 +1,103 @@ +package com.simibubi.create.content.kinetics.fan; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.logistics.chute.AbstractChuteBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.worldWrappers.WrappedWorld; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class EncasedFanBlock extends DirectionalKineticBlock implements IBE { + + public EncasedFanBlock(Properties properties) { + super(properties); + } + + @Override + public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, worldIn, pos, oldState, isMoving); + blockUpdate(state, worldIn, pos); + } + + @Override + public void updateIndirectNeighbourShapes(BlockState stateIn, LevelAccessor worldIn, BlockPos pos, int flags, int count) { + super.updateIndirectNeighbourShapes(stateIn, worldIn, pos, flags, count); + blockUpdate(stateIn, worldIn, pos); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + blockUpdate(state, worldIn, pos); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Level world = context.getLevel(); + BlockPos pos = context.getClickedPos(); + Direction face = context.getClickedFace(); + + BlockState placedOn = world.getBlockState(pos.relative(face.getOpposite())); + BlockState placedOnOpposite = world.getBlockState(pos.relative(face)); + if (AbstractChuteBlock.isChute(placedOn)) + return defaultBlockState().setValue(FACING, face.getOpposite()); + if (AbstractChuteBlock.isChute(placedOnOpposite)) + return defaultBlockState().setValue(FACING, face); + + Direction preferredFacing = getPreferredFacing(context); + if (preferredFacing == null) + preferredFacing = context.getNearestLookingDirection(); + return defaultBlockState().setValue(FACING, context.getPlayer() != null && context.getPlayer() + .isShiftKeyDown() ? preferredFacing : preferredFacing.getOpposite()); + } + + protected void blockUpdate(BlockState state, LevelAccessor worldIn, BlockPos pos) { + if (worldIn instanceof WrappedWorld) + return; + notifyFanBlockEntity(worldIn, pos); + } + + protected void notifyFanBlockEntity(LevelAccessor world, BlockPos pos) { + withBlockEntityDo(world, pos, EncasedFanBlockEntity::blockInFrontChanged); + } + + @Override + public BlockState updateAfterWrenched(BlockState newState, UseOnContext context) { + blockUpdate(newState, context.getLevel(), context.getClickedPos()); + return newState; + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(FACING) + .getAxis(); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face == state.getValue(FACING) + .getOpposite(); + } + + @Override + public Class getBlockEntityClass() { + return EncasedFanBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ENCASED_FAN.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlockEntity.java new file mode 100644 index 0000000000..836b14a156 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanBlockEntity.java @@ -0,0 +1,154 @@ +package com.simibubi.create.content.kinetics.fan; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.logistics.chute.ChuteBlockEntity; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +@MethodsReturnNonnullByDefault +public class EncasedFanBlockEntity extends KineticBlockEntity implements IAirCurrentSource { + + public AirCurrent airCurrent; + protected int airCurrentUpdateCooldown; + protected int entitySearchCooldown; + protected boolean updateAirFlow; + + public EncasedFanBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + airCurrent = new AirCurrent(this); + updateAirFlow = true; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.ENCASED_FAN, AllAdvancements.FAN_PROCESSING); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket) + airCurrent.rebuild(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + } + + @Override + public AirCurrent getAirCurrent() { + return airCurrent; + } + + @Nullable + @Override + public Level getAirCurrentWorld() { + return level; + } + + @Override + public BlockPos getAirCurrentPos() { + return worldPosition; + } + + @Override + public Direction getAirflowOriginSide() { + return this.getBlockState() + .getValue(EncasedFanBlock.FACING); + } + + @Override + public Direction getAirFlowDirection() { + float speed = getSpeed(); + if (speed == 0) + return null; + Direction facing = getBlockState().getValue(BlockStateProperties.FACING); + speed = convertToDirection(speed, facing); + return speed > 0 ? facing : facing.getOpposite(); + } + + @Override + public void remove() { + super.remove(); + updateChute(); + } + + @Override + public boolean isSourceRemoved() { + return remove; + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + updateAirFlow = true; + updateChute(); + } + + public void updateChute() { + Direction direction = getBlockState().getValue(EncasedFanBlock.FACING); + if (!direction.getAxis() + .isVertical()) + return; + BlockEntity poweredChute = level.getBlockEntity(worldPosition.relative(direction)); + if (!(poweredChute instanceof ChuteBlockEntity)) + return; + ChuteBlockEntity chuteBE = (ChuteBlockEntity) poweredChute; + if (direction == Direction.DOWN) + chuteBE.updatePull(); + else + chuteBE.updatePush(1); + } + + public void blockInFrontChanged() { + updateAirFlow = true; + } + + @Override + public void tick() { + super.tick(); + + boolean server = !level.isClientSide || isVirtual(); + + if (server && airCurrentUpdateCooldown-- <= 0) { + airCurrentUpdateCooldown = AllConfigs.server().kinetics.fanBlockCheckRate.get(); + updateAirFlow = true; + } + + if (updateAirFlow) { + updateAirFlow = false; + airCurrent.rebuild(); + if (airCurrent.maxDistance > 0) + award(AllAdvancements.ENCASED_FAN); + sendData(); + } + + if (getSpeed() == 0) + return; + + if (entitySearchCooldown-- <= 0) { + entitySearchCooldown = 5; + airCurrent.findEntities(); + } + + airCurrent.tick(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanRenderer.java new file mode 100644 index 0000000000..63aebb703d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/EncasedFanRenderer.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.kinetics.fan; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; + +public class EncasedFanRenderer extends KineticBlockEntityRenderer { + + public EncasedFanRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(EncasedFanBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) return; + + Direction direction = be.getBlockState() + .getValue(FACING); + VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); + + int lightBehind = LevelRenderer.getLightColor(be.getLevel(), be.getBlockPos().relative(direction.getOpposite())); + int lightInFront = LevelRenderer.getLightColor(be.getLevel(), be.getBlockPos().relative(direction)); + + SuperByteBuffer shaftHalf = + CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), direction.getOpposite()); + SuperByteBuffer fanInner = + CachedPartialBuffers.partialFacing(AllPartialModels.ENCASED_FAN_INNER, be.getBlockState(), direction.getOpposite()); + + float time = WorldTickHolder.getRenderTime(be.getLevel()); + float speed = be.getSpeed() * 5; + if (speed > 0) + speed = Mth.clamp(speed, 80, 64 * 20); + if (speed < 0) + speed = Mth.clamp(speed, -64 * 20, -80); + float angle = (time * speed * 3 / 10f) % 360; + angle = angle / 180f * (float) Math.PI; + + standardKineticRotationTransform(shaftHalf, be, lightBehind).renderInto(ms, vb); + kineticRotationTransform(fanInner, be, direction.getAxis(), angle, lightInFront).renderInto(ms, vb); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/FanInstance.java b/src/main/java/com/simibubi/create/content/kinetics/fan/FanInstance.java new file mode 100644 index 0000000000..d509f08b32 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/FanInstance.java @@ -0,0 +1,67 @@ +package com.simibubi.create.content.kinetics.fan; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.foundation.render.AllMaterialSpecs; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; + +public class FanInstance extends KineticBlockEntityInstance { + + protected final RotatingData shaft; + protected final RotatingData fan; + final Direction direction; + private final Direction opposite; + + public FanInstance(MaterialManager materialManager, EncasedFanBlockEntity blockEntity) { + super(materialManager, blockEntity); + + direction = blockState.getValue(FACING); + + opposite = direction.getOpposite(); + shaft = getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, blockState, opposite).createInstance(); + fan = materialManager.defaultCutout() + .material(AllMaterialSpecs.ROTATING) + .getModel(AllPartialModels.ENCASED_FAN_INNER, blockState, opposite) + .createInstance(); + + setup(shaft); + setup(fan, getFanSpeed()); + } + + private float getFanSpeed() { + float speed = blockEntity.getSpeed() * 5; + if (speed > 0) + speed = Mth.clamp(speed, 80, 64 * 20); + if (speed < 0) + speed = Mth.clamp(speed, -64 * 20, -80); + return speed; + } + + @Override + public void update() { + updateRotation(shaft); + updateRotation(fan, getFanSpeed()); + } + + @Override + public void updateLight() { + BlockPos behind = pos.relative(opposite); + relight(behind, shaft); + + BlockPos inFront = pos.relative(direction); + relight(inFront, fan); + } + + @Override + public void remove() { + shaft.delete(); + fan.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/FanProcessing.java b/src/main/java/com/simibubi/create/content/kinetics/fan/FanProcessing.java new file mode 100644 index 0000000000..cac7800764 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/FanProcessing.java @@ -0,0 +1,452 @@ +package com.simibubi.create.content.kinetics.fan; + +import static com.simibubi.create.content.processing.burner.BlazeBurnerBlock.getHeatLevelOf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock; +import com.simibubi.create.foundation.recipe.RecipeApplier; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.horse.Horse; +import net.minecraft.world.entity.animal.horse.SkeletonHorse; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.AbstractCookingRecipe; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SmeltingRecipe; +import net.minecraft.world.item.crafting.SmokingRecipe; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CampfireBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class FanProcessing { + + private static final DamageSource FIRE_DAMAGE_SOURCE = new DamageSource("create.fan_fire").setScalesWithDifficulty() + .setIsFire(); + private static final DamageSource LAVA_DAMAGE_SOURCE = new DamageSource("create.fan_lava").setScalesWithDifficulty() + .setIsFire(); + + private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1)); + private static final SplashingWrapper SPLASHING_WRAPPER = new SplashingWrapper(); + private static final HauntingWrapper HAUNTING_WRAPPER = new HauntingWrapper(); + + public static boolean canProcess(ItemEntity entity, Type type) { + if (entity.getPersistentData() + .contains("CreateData")) { + CompoundTag compound = entity.getPersistentData() + .getCompound("CreateData"); + if (compound.contains("Processing")) { + CompoundTag processing = compound.getCompound("Processing"); + + if (Type.valueOf(processing.getString("Type")) != type) + return type.canProcess(entity.getItem(), entity.level); + else if (processing.getInt("Time") >= 0) + return true; + else if (processing.getInt("Time") == -1) + return false; + } + } + return type.canProcess(entity.getItem(), entity.level); + } + + public static boolean isWashable(ItemStack stack, Level world) { + SPLASHING_WRAPPER.setItem(0, stack); + Optional recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world); + return recipe.isPresent(); + } + + public static boolean isHauntable(ItemStack stack, Level world) { + HAUNTING_WRAPPER.setItem(0, stack); + Optional recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world); + return recipe.isPresent(); + } + + public static boolean applyProcessing(ItemEntity entity, Type type) { + if (decrementProcessingTime(entity, type) != 0) + return false; + List stacks = process(entity.getItem(), type, entity.level); + if (stacks == null) + return false; + if (stacks.isEmpty()) { + entity.discard(); + return false; + } + entity.setItem(stacks.remove(0)); + for (ItemStack additional : stacks) { + ItemEntity entityIn = new ItemEntity(entity.level, entity.getX(), entity.getY(), entity.getZ(), additional); + entityIn.setDeltaMovement(entity.getDeltaMovement()); + entity.level.addFreshEntity(entityIn); + } + return true; + } + + public static TransportedResult applyProcessing(TransportedItemStack transported, Level world, Type type) { + TransportedResult ignore = TransportedResult.doNothing(); + if (transported.processedBy != type) { + transported.processedBy = type; + int timeModifierForStackSize = ((transported.stack.getCount() - 1) / 16) + 1; + int processingTime = + (int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1; + transported.processingTime = processingTime; + if (!type.canProcess(transported.stack, world)) + transported.processingTime = -1; + return ignore; + } + if (transported.processingTime == -1) + return ignore; + if (transported.processingTime-- > 0) + return ignore; + + List stacks = process(transported.stack, type, world); + if (stacks == null) + return ignore; + + List transportedStacks = new ArrayList<>(); + for (ItemStack additional : stacks) { + TransportedItemStack newTransported = transported.getSimilar(); + newTransported.stack = additional.copy(); + transportedStacks.add(newTransported); + } + return TransportedResult.convertTo(transportedStacks); + } + + private static List process(ItemStack stack, Type type, Level world) { + if (type == Type.SPLASHING) { + SPLASHING_WRAPPER.setItem(0, stack); + Optional recipe = AllRecipeTypes.SPLASHING.find(SPLASHING_WRAPPER, world); + if (recipe.isPresent()) + return RecipeApplier.applyRecipeOn(stack, recipe.get()); + return null; + } + if (type == Type.HAUNTING) { + HAUNTING_WRAPPER.setItem(0, stack); + Optional recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world); + if (recipe.isPresent()) + return RecipeApplier.applyRecipeOn(stack, recipe.get()); + return null; + } + + RECIPE_WRAPPER.setItem(0, stack); + Optional smokingRecipe = world.getRecipeManager() + .getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, world); + + if (type == Type.BLASTING) { + RECIPE_WRAPPER.setItem(0, stack); + Optional smeltingRecipe = world.getRecipeManager() + .getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, world); + if (!smeltingRecipe.isPresent()) { + RECIPE_WRAPPER.setItem(0, stack); + smeltingRecipe = world.getRecipeManager() + .getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, world); + } + + if (smeltingRecipe.isPresent()) { + if (!smokingRecipe.isPresent() || !ItemStack.isSame(smokingRecipe.get() + .getResultItem(), + smeltingRecipe.get() + .getResultItem())) { + return RecipeApplier.applyRecipeOn(stack, smeltingRecipe.get()); + } + } + + return Collections.emptyList(); + } + + if (type == Type.SMOKING && smokingRecipe.isPresent()) + return RecipeApplier.applyRecipeOn(stack, smokingRecipe.get()); + + return null; + } + + private static int decrementProcessingTime(ItemEntity entity, Type type) { + CompoundTag nbt = entity.getPersistentData(); + + if (!nbt.contains("CreateData")) + nbt.put("CreateData", new CompoundTag()); + CompoundTag createData = nbt.getCompound("CreateData"); + + if (!createData.contains("Processing")) + createData.put("Processing", new CompoundTag()); + CompoundTag processing = createData.getCompound("Processing"); + + if (!processing.contains("Type") || Type.valueOf(processing.getString("Type")) != type) { + processing.putString("Type", type.name()); + int timeModifierForStackSize = ((entity.getItem() + .getCount() - 1) / 16) + 1; + int processingTime = + (int) (AllConfigs.server().kinetics.fanProcessingTime.get() * timeModifierForStackSize) + 1; + processing.putInt("Time", processingTime); + } + + int value = processing.getInt("Time") - 1; + processing.putInt("Time", value); + return value; + } + + public enum Type { + SPLASHING { + @Override + public void spawnParticlesForProcessing(Level level, Vec3 pos) { + if (level.random.nextInt(8) != 0) + return; + Vector3f color = new Color(0x0055FF).asVectorF(); + level.addParticle(new DustParticleOptions(color, 1), pos.x + (level.random.nextFloat() - .5f) * .5f, + pos.y + .5f, pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + level.addParticle(ParticleTypes.SPIT, pos.x + (level.random.nextFloat() - .5f) * .5f, pos.y + .5f, + pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0); + } + + @Override + public void affectEntity(Entity entity, Level level) { + if (level.isClientSide) + return; + + if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM + || entity.getType() == EntityType.BLAZE) { + entity.hurt(DamageSource.DROWN, 2); + } + if (entity.isOnFire()) { + entity.clearFire(); + level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, + SoundSource.NEUTRAL, 0.7F, 1.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F); + } + } + + @Override + public boolean canProcess(ItemStack stack, Level level) { + return isWashable(stack, level); + } + }, + SMOKING { + @Override + public void spawnParticlesForProcessing(Level level, Vec3 pos) { + if (level.random.nextInt(8) != 0) + return; + level.addParticle(ParticleTypes.POOF, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0); + } + + @Override + public void affectEntity(Entity entity, Level level) { + if (level.isClientSide) + return; + + if (!entity.fireImmune()) { + entity.setSecondsOnFire(2); + entity.hurt(FIRE_DAMAGE_SOURCE, 2); + } + } + + @Override + public boolean canProcess(ItemStack stack, Level level) { + RECIPE_WRAPPER.setItem(0, stack); + Optional recipe = level.getRecipeManager() + .getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level); + return recipe.isPresent(); + } + }, + HAUNTING { + @Override + public void spawnParticlesForProcessing(Level level, Vec3 pos) { + if (level.random.nextInt(8) != 0) + return; + pos = pos.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) + .multiply(1, 0.05f, 1) + .normalize() + .scale(0.15f)); + level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, pos.x, pos.y + .45f, pos.z, 0, 0, 0); + if (level.random.nextInt(2) == 0) + level.addParticle(ParticleTypes.SMOKE, pos.x, pos.y + .25f, pos.z, 0, 0, 0); + } + + @Override + public void affectEntity(Entity entity, Level level) { + if (level.isClientSide) { + if (entity instanceof Horse) { + Vec3 p = entity.getPosition(0); + Vec3 v = p.add(0, 0.5f, 0) + .add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) + .multiply(1, 0.2f, 1) + .normalize() + .scale(1f)); + level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0); + if (level.random.nextInt(3) == 0) + level.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z, + (level.random.nextFloat() - .5f) * .5f, 0.1f, (level.random.nextFloat() - .5f) * .5f); + } + return; + } + + if (entity instanceof LivingEntity livingEntity) { + livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false)); + livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false)); + } + if (entity instanceof Horse horse) { + int progress = horse.getPersistentData() + .getInt("CreateHaunting"); + if (progress < 100) { + if (progress % 10 == 0) { + level.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL, + 1f, 1.5f * progress / 100f); + } + horse.getPersistentData() + .putInt("CreateHaunting", progress + 1); + return; + } + + level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, + SoundSource.NEUTRAL, 1.25f, 0.65f); + + SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(level); + CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag()); + serializeNBT.remove("UUID"); + if (!horse.getArmor() + .isEmpty()) + horse.spawnAtLocation(horse.getArmor()); + + skeletonHorse.deserializeNBT(serializeNBT); + skeletonHorse.setPos(horse.getPosition(0)); + level.addFreshEntity(skeletonHorse); + horse.discard(); + } + } + + @Override + public boolean canProcess(ItemStack stack, Level level) { + return isHauntable(stack, level); + } + }, + BLASTING { + @Override + public void spawnParticlesForProcessing(Level level, Vec3 pos) { + if (level.random.nextInt(8) != 0) + return; + level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0); + } + + @Override + public void affectEntity(Entity entity, Level level) { + if (level.isClientSide) + return; + + if (!entity.fireImmune()) { + entity.setSecondsOnFire(10); + entity.hurt(LAVA_DAMAGE_SOURCE, 4); + } + } + + @Override + public boolean canProcess(ItemStack stack, Level level) { + RECIPE_WRAPPER.setItem(0, stack); + Optional smeltingRecipe = level.getRecipeManager() + .getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level); + + if (smeltingRecipe.isPresent()) + return true; + + RECIPE_WRAPPER.setItem(0, stack); + Optional blastingRecipe = level.getRecipeManager() + .getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level); + + if (blastingRecipe.isPresent()) + return true; + + return !stack.getItem() + .isFireResistant(); + } + }, + NONE { + @Override + public void spawnParticlesForProcessing(Level level, Vec3 pos) {} + + @Override + public void affectEntity(Entity entity, Level level) {} + + @Override + public boolean canProcess(ItemStack stack, Level level) { + return false; + } + }; + + public abstract boolean canProcess(ItemStack stack, Level level); + + public abstract void spawnParticlesForProcessing(Level level, Vec3 pos); + + public abstract void affectEntity(Entity entity, Level level); + + public static Type byBlock(BlockGetter reader, BlockPos pos) { + FluidState fluidState = reader.getFluidState(pos); + if (fluidState.getType() == Fluids.WATER || fluidState.getType() == Fluids.FLOWING_WATER) + return Type.SPLASHING; + BlockState blockState = reader.getBlockState(pos); + Block block = blockState.getBlock(); + if (block == Blocks.SOUL_FIRE + || block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT) + .orElse(false) + || AllBlocks.LIT_BLAZE_BURNER.has(blockState) + && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE) + .map(flame -> flame == LitBlazeBurnerBlock.FlameType.SOUL) + .orElse(false)) + return Type.HAUNTING; + if (block == Blocks.FIRE + || blockState.is(BlockTags.CAMPFIRES) && blockState.getOptionalValue(CampfireBlock.LIT) + .orElse(false) + || AllBlocks.LIT_BLAZE_BURNER.has(blockState) + && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE) + .map(flame -> flame == LitBlazeBurnerBlock.FlameType.REGULAR) + .orElse(false) + || getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING) + return Type.SMOKING; + if (block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) + return Type.BLASTING; + return Type.NONE; + } + } + + public static class SplashingWrapper extends RecipeWrapper { + public SplashingWrapper() { + super(new ItemStackHandler(1)); + } + } + + public static class HauntingWrapper extends RecipeWrapper { + public HauntingWrapper() { + super(new ItemStackHandler(1)); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/HauntingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/fan/HauntingRecipe.java new file mode 100644 index 0000000000..43dbc81d08 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/HauntingRecipe.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.kinetics.fan; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; + +import net.minecraft.world.level.Level; + +@ParametersAreNonnullByDefault +public class HauntingRecipe extends ProcessingRecipe { + + public HauntingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.HAUNTING, params); + } + + @Override + public boolean matches(FanProcessing.HauntingWrapper inv, Level worldIn) { + if (inv.isEmpty()) + return false; + return ingredients.get(0) + .test(inv.getItem(0)); + } + + @Override + protected int getMaxInputCount() { + return 1; + } + + @Override + protected int getMaxOutputCount() { + return 12; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/IAirCurrentSource.java b/src/main/java/com/simibubi/create/content/kinetics/fan/IAirCurrentSource.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/fan/IAirCurrentSource.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/IAirCurrentSource.java index 2db3fb22d2..0f232411b2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/IAirCurrentSource.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/IAirCurrentSource.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.fan; +package com.simibubi.create.content.kinetics.fan; import javax.annotation.Nullable; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CKinetics; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CKinetics; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public interface IAirCurrentSource { default float getMaxDistance() { float speed = Math.abs(this.getSpeed()); - CKinetics config = AllConfigs.SERVER.kinetics; + CKinetics config = AllConfigs.server().kinetics; float distanceFactor = Math.min(speed / config.fanRotationArgmax.get(), 1); float pushDistance = Mth.lerp(distanceFactor, 3, config.fanPushDistance.get()); float pullDistance = Mth.lerp(distanceFactor, 3f, config.fanPullDistance.get()); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleBlock.java b/src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlock.java index f5aae9ac1c..d64f14dd8e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.fan; +package com.simibubi.create.content.kinetics.fan; import javax.annotation.ParametersAreNonnullByDefault; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.minecraft.MethodsReturnNonnullByDefault; @@ -26,7 +26,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class NozzleBlock extends WrenchableDirectionalBlock implements ITE { +public class NozzleBlock extends WrenchableDirectionalBlock implements IBE { public NozzleBlock(Properties p_i48415_1_) { super(p_i48415_1_); @@ -63,9 +63,9 @@ public class NozzleBlock extends WrenchableDirectionalBlock implements ITE getTileEntityClass() { - return NozzleTileEntity.class; + public Class getBlockEntityClass() { + return NozzleBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.NOZZLE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.NOZZLE.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlockEntity.java new file mode 100644 index 0000000000..55f6022765 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/NozzleBlockEntity.java @@ -0,0 +1,191 @@ +package com.simibubi.create.content.kinetics.fan; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.ClipContext.Block; +import net.minecraft.world.level.ClipContext.Fluid; +import net.minecraft.world.level.Explosion.BlockInteraction; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class NozzleBlockEntity extends SmartBlockEntity { + + private List pushingEntities = new ArrayList<>(); + private float range; + private boolean pushing; + private BlockPos fanPos; + + public NozzleBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(5); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + if (!clientPacket) + return; + compound.putFloat("Range", range); + compound.putBoolean("Pushing", pushing); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (!clientPacket) + return; + range = compound.getFloat("Range"); + pushing = compound.getBoolean("Pushing"); + } + + @Override + public void initialize() { + fanPos = worldPosition.relative(getBlockState().getValue(NozzleBlock.FACING) + .getOpposite()); + super.initialize(); + } + + @Override + public void tick() { + super.tick(); + + float range = calcRange(); + if (this.range != range) + setRange(range); + + Vec3 center = VecHelper.getCenterOf(worldPosition); + if (level.isClientSide && range != 0) { + if (level.random.nextInt( + Mth.clamp((AllConfigs.server().kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) { + Vec3 start = VecHelper.offsetRandomly(center, level.random, pushing ? 1 : range / 2); + Vec3 motion = center.subtract(start) + .normalize() + .scale(Mth.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1)); + level.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z); + } + } + + for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + Vec3 diff = entity.position() + .subtract(center); + + if (!(entity instanceof Player) && level.isClientSide) + continue; + + double distance = diff.length(); + if (distance > range || entity.isShiftKeyDown() || AirCurrent.isPlayerCreativeFlying(entity)) { + iterator.remove(); + continue; + } + + if (!pushing && distance < 1.5f) + continue; + + float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f; + Vec3 pushVec = diff.normalize() + .scale((range - distance) * (pushing ? 1 : -1)); + entity.setDeltaMovement(entity.getDeltaMovement() + .add(pushVec.scale(factor))); + entity.fallDistance = 0; + entity.hurtMarked = true; + } + + } + + public void setRange(float range) { + this.range = range; + if (range == 0) + pushingEntities.clear(); + sendData(); + } + + private float calcRange() { + BlockEntity be = level.getBlockEntity(fanPos); + if (!(be instanceof IAirCurrentSource)) + return 0; + + IAirCurrentSource source = (IAirCurrentSource) be; + if (source.getAirCurrent() == null) + return 0; + if (source.getSpeed() == 0) + return 0; + pushing = source.getAirFlowDirection() == source.getAirflowOriginSide(); + return source.getMaxDistance(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + + if (range == 0) + return; + + Vec3 center = VecHelper.getCenterOf(worldPosition); + AABB bb = new AABB(center, center).inflate(range / 2f); + + for (Entity entity : level.getEntitiesOfClass(Entity.class, bb)) { + Vec3 diff = entity.position() + .subtract(center); + + double distance = diff.length(); + if (distance > range || entity.isShiftKeyDown() || AirCurrent.isPlayerCreativeFlying(entity)) + continue; + + boolean canSee = canSee(entity); + if (!canSee) { + pushingEntities.remove(entity); + continue; + } + + if (!pushingEntities.contains(entity)) + pushingEntities.add(entity); + } + + for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + if (entity.isAlive()) + continue; + iterator.remove(); + } + + if (!pushing && pushingEntities.size() > 256 && !level.isClientSide) { + level.explode(null, center.x, center.y, center.z, 2, BlockInteraction.NONE); + for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + entity.discard(); + iterator.remove(); + } + } + + } + + private boolean canSee(Entity entity) { + ClipContext context = new ClipContext(entity.position(), VecHelper.getCenterOf(worldPosition), + Block.COLLIDER, Fluid.NONE, entity); + return worldPosition.equals(level.clip(context) + .getBlockPos()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/fan/SplashingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/fan/SplashingRecipe.java new file mode 100644 index 0000000000..b8734ae538 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/fan/SplashingRecipe.java @@ -0,0 +1,37 @@ +package com.simibubi.create.content.kinetics.fan; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.kinetics.fan.FanProcessing.SplashingWrapper; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; + +import net.minecraft.world.level.Level; + +@ParametersAreNonnullByDefault +public class SplashingRecipe extends ProcessingRecipe { + + public SplashingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.SPLASHING, params); + } + + @Override + public boolean matches(SplashingWrapper inv, Level worldIn) { + if (inv.isEmpty()) + return false; + return ingredients.get(0) + .test(inv.getItem(0)); + } + + @Override + protected int getMaxInputCount() { + return 1; + } + + @Override + protected int getMaxOutputCount() { + return 12; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlock.java new file mode 100644 index 0000000000..6cff991ce0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlock.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.kinetics.flywheel; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class FlywheelBlock extends RotatedPillarKineticBlock implements IBE { + + public FlywheelBlock(Properties properties) { + super(properties); + } + + @Override + public Class getBlockEntityClass() { + return FlywheelBlockEntity.class; + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return AllShapes.LARGE_GEAR.get(pState.getValue(AXIS)); + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.ENTITYBLOCK_ANIMATED; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.FLYWHEEL.get(); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face.getAxis() == getRotationAxis(state); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(AXIS); + } + + @Override + public float getParticleTargetRadius() { + return 2f; + } + + @Override + public float getParticleInitialRadius() { + return 1.75f; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlockEntity.java new file mode 100644 index 0000000000..20ead39149 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelBlockEntity.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.kinetics.flywheel; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class FlywheelBlockEntity extends KineticBlockEntity { + + LerpedFloat visualSpeed = LerpedFloat.linear(); + float angle; + + public FlywheelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket) + visualSpeed.chase(getGeneratedSpeed(), 1 / 64f, Chaser.EXP); + } + + @Override + public void tick() { + super.tick(); + + if (!level.isClientSide) + return; + + float targetSpeed = getSpeed(); + visualSpeed.updateChaseTarget(targetSpeed); + visualSpeed.tickChaser(); + angle += visualSpeed.getValue() * 3 / 10f; + angle %= 360; + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelInstance.java b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelInstance.java new file mode 100644 index 0000000000..5da547b76c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelInstance.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.kinetics.flywheel; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; + +public class FlywheelInstance extends KineticBlockEntityInstance implements DynamicInstance { + + protected final RotatingData shaft; + protected final ModelData wheel; + protected float lastAngle = Float.NaN; + + public FlywheelInstance(MaterialManager materialManager, FlywheelBlockEntity blockEntity) { + super(materialManager, blockEntity); + + shaft = setup(getRotatingMaterial().getModel(shaft()) + .createInstance()); + wheel = getTransformMaterial().getModel(blockState) + .createInstance(); + + animate(blockEntity.angle); + } + + @Override + public void beginFrame() { + + float partialTicks = AnimationTickHolder.getPartialTicks(); + + float speed = blockEntity.visualSpeed.getValue(partialTicks) * 3 / 10f; + float angle = blockEntity.angle + speed * partialTicks; + + if (Math.abs(angle - lastAngle) < 0.001) + return; + + animate(angle); + + lastAngle = angle; + } + + private void animate(float angle) { + PoseStack ms = new PoseStack(); + TransformStack msr = TransformStack.cast(ms); + + msr.translate(getInstancePosition()); + msr.centre() + .rotate(Direction.get(Direction.AxisDirection.POSITIVE, axis), AngleHelper.rad(angle)) + .unCentre(); + + wheel.setTransform(ms); + } + + @Override + public void update() { + updateRotation(shaft); + } + + @Override + public void updateLight() { + relight(pos, shaft, wheel); + } + + @Override + public void remove() { + shaft.delete(); + wheel.delete(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelRenderer.java new file mode 100644 index 0000000000..b245b992dd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/flywheel/FlywheelRenderer.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.kinetics.flywheel; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class FlywheelRenderer extends KineticBlockEntityRenderer { + + public FlywheelRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(FlywheelBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) + return; + + BlockState blockState = be.getBlockState(); + + float speed = be.visualSpeed.getValue(partialTicks) * 3 / 10f; + float angle = be.angle + speed * partialTicks; + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + renderFlywheel(be, ms, light, blockState, angle, vb); + } + + private void renderFlywheel(FlywheelBlockEntity be, PoseStack ms, int light, BlockState blockState, float angle, + VertexConsumer vb) { + SuperByteBuffer wheel = CachedBlockBuffers.block(blockState); + kineticRotationTransform(wheel, be, getRotationAxisOf(be), AngleHelper.rad(angle), light); + wheel.renderInto(ms, vb); + } + + @Override + protected BlockState getRenderedBlockState(FlywheelBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlock.java index 99447d3518..1f7f6216f5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlock.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.contraptions.relays.advanced; +package com.simibubi.create.content.kinetics.gantry; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.utility.placement.PoleHelper; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.placement.PoleHelper; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.lang.Lang; @@ -47,7 +47,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class GantryShaftBlock extends DirectionalKineticBlock implements ITE { +public class GantryShaftBlock extends DirectionalKineticBlock implements IBE { public static final Property PART = EnumProperty.create("part", Part.class); public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -180,9 +180,9 @@ public class GantryShaftBlock extends DirectionalKineticBlock implements ITE getTileEntityClass() { - return GantryShaftTileEntity.class; + public Class getBlockEntityClass() { + return GantryShaftBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.GANTRY_SHAFT.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.GANTRY_SHAFT.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlockEntity.java new file mode 100644 index 0000000000..b4659fc3e2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gantry/GantryShaftBlockEntity.java @@ -0,0 +1,115 @@ +package com.simibubi.create.content.kinetics.gantry; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageBlock; +import com.simibubi.create.content.contraptions.gantry.GantryCarriageBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class GantryShaftBlockEntity extends KineticBlockEntity { + + public GantryShaftBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + } + + @Override + protected boolean syncSequenceContext() { + return true; + } + + public void checkAttachedCarriageBlocks() { + if (!canAssembleOn()) + return; + for (Direction d : Iterate.directions) { + if (d.getAxis() == getBlockState().getValue(GantryShaftBlock.FACING) + .getAxis()) + continue; + BlockPos offset = worldPosition.relative(d); + BlockState pinionState = level.getBlockState(offset); + if (!AllBlocks.GANTRY_CARRIAGE.has(pinionState)) + continue; + if (pinionState.getValue(GantryCarriageBlock.FACING) != d) + continue; + BlockEntity blockEntity = level.getBlockEntity(offset); + if (blockEntity instanceof GantryCarriageBlockEntity) + ((GantryCarriageBlockEntity) blockEntity).queueAssembly(); + } + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + checkAttachedCarriageBlocks(); + } + + @Override + public float propagateRotationTo(KineticBlockEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, + boolean connectedViaAxes, boolean connectedViaCogs) { + float defaultModifier = + super.propagateRotationTo(target, stateFrom, stateTo, diff, connectedViaAxes, connectedViaCogs); + + if (connectedViaAxes) + return defaultModifier; + if (!stateFrom.getValue(GantryShaftBlock.POWERED)) + return defaultModifier; + if (!AllBlocks.GANTRY_CARRIAGE.has(stateTo)) + return defaultModifier; + + Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); + if (stateTo.getValue(GantryCarriageBlock.FACING) != direction) + return defaultModifier; + return GantryCarriageBlockEntity.getGantryPinionModifier(stateFrom.getValue(GantryShaftBlock.FACING), + stateTo.getValue(GantryCarriageBlock.FACING)); + } + + @Override + public boolean isCustomConnection(KineticBlockEntity other, BlockState state, BlockState otherState) { + if (!AllBlocks.GANTRY_CARRIAGE.has(otherState)) + return false; + final BlockPos diff = other.getBlockPos() + .subtract(worldPosition); + Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ()); + return otherState.getValue(GantryCarriageBlock.FACING) == direction; + } + + public boolean canAssembleOn() { + BlockState blockState = getBlockState(); + if (!AllBlocks.GANTRY_SHAFT.has(blockState)) + return false; + if (blockState.getValue(GantryShaftBlock.POWERED)) + return false; + float speed = getPinionMovementSpeed(); + + switch (blockState.getValue(GantryShaftBlock.PART)) { + case END: + return speed < 0; + case MIDDLE: + return speed != 0; + case START: + return speed > 0; + case SINGLE: + default: + return false; + } + } + + public float getPinionMovementSpeed() { + BlockState blockState = getBlockState(); + if (!AllBlocks.GANTRY_SHAFT.has(blockState)) + return 0; + return Mth.clamp(convertToLinear(-getSpeed()), -.49f, .49f); + } + + @Override + protected boolean isNoisy() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeBlock.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlock.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlock.java index a9e08deafb..c2180d72f7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.relays.gauge; +package com.simibubi.create.content.kinetics.gauge; import java.util.Random; import com.mojang.math.Vector3f; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; @@ -32,7 +32,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class GaugeBlock extends DirectionalAxisKineticBlock implements ITE { +public class GaugeBlock extends DirectionalAxisKineticBlock implements IBE { public static final GaugeShaper GAUGE = GaugeShaper.make(); protected Type type; @@ -120,13 +120,13 @@ public class GaugeBlock extends DirectionalAxisKineticBlock implements ITE 1 ? 4 : 1; + int particleCount = gaugeBE.dialTarget > 1 ? 4 : 1; if (particleCount == 1 && rand.nextFloat() > 1 / 4f) continue; @@ -168,10 +168,10 @@ public class GaugeBlock extends DirectionalAxisKineticBlock implements ITE getTileEntityClass() { - return GaugeTileEntity.class; + public Class getBlockEntityClass() { + return GaugeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return type == Type.SPEED ? AllTileEntities.SPEEDOMETER.get() : AllTileEntities.STRESSOMETER.get(); + public BlockEntityType getBlockEntityType() { + return type == Type.SPEED ? AllBlockEntityTypes.SPEEDOMETER.get() : AllBlockEntityTypes.STRESSOMETER.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlockEntity.java new file mode 100644 index 0000000000..7b0abd829d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeBlockEntity.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.kinetics.gauge; + +import java.util.List; + +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class GaugeBlockEntity extends KineticBlockEntity implements IHaveGoggleInformation { + + public float dialTarget; + public float dialState; + public float prevDialState; + public int color; + + public GaugeBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putFloat("Value", dialTarget); + compound.putInt("Color", color); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + dialTarget = compound.getFloat("Value"); + color = compound.getInt("Color"); + super.read(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + prevDialState = dialState; + dialState += (dialTarget - dialState) * .125f; + if (dialState > 1 && level.random.nextFloat() < 1 / 2f) + dialState -= (dialState - 1) * level.random.nextFloat(); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + tooltip.add(componentSpacing.plainCopy().append(CreateLang.translateDirect("gui.gauge.info_header"))); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeGenerator.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeGenerator.java rename to src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeGenerator.java index 1d319e6e0c..079e033a46 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeGenerator.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.gauge; +package com.simibubi.create.content.kinetics.gauge; import com.simibubi.create.foundation.data.DirectionalAxisBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeInstance.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java rename to src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeInstance.java index 702ae2e72d..7fc2a0a3bb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.gauge; +package com.simibubi.create.content.kinetics.gauge; import java.util.ArrayList; @@ -8,9 +8,8 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.ShaftInstance; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.Couple; @@ -18,28 +17,27 @@ import net.createmod.catnip.utility.Iterate; import net.minecraft.core.Direction; import net.minecraft.util.Mth; -public abstract class GaugeInstance extends ShaftInstance implements DynamicInstance { +public abstract class GaugeInstance extends ShaftInstance implements DynamicInstance { protected final ArrayList faces; protected PoseStack ms; - protected GaugeInstance(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); + protected GaugeInstance(MaterialManager materialManager, GaugeBlockEntity blockEntity) { + super(materialManager, blockEntity); faces = new ArrayList<>(2); - GaugeTileEntity gaugeTile = (GaugeTileEntity) tile; GaugeBlock gaugeBlock = (GaugeBlock) blockState.getBlock(); - Instancer dialModel = getTransformMaterial().getModel(AllBlockPartials.GAUGE_DIAL, blockState); + Instancer dialModel = getTransformMaterial().getModel(AllPartialModels.GAUGE_DIAL, blockState); Instancer headModel = getHeadModel(); ms = new PoseStack(); TransformStack msr = TransformStack.cast(ms); msr.translate(getInstancePosition()); - float progress = Mth.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState); + float progress = Mth.lerp(AnimationTickHolder.getPartialTicks(), blockEntity.prevDialState, blockEntity.dialState); for (Direction facing : Iterate.directions) { if (!gaugeBlock.shouldRenderHeadOnFace(world, pos, blockState, facing)) @@ -59,12 +57,12 @@ public abstract class GaugeInstance extends ShaftInstance implements DynamicInst @Override public void beginFrame() { - GaugeTileEntity gaugeTile = (GaugeTileEntity) blockEntity; + GaugeBlockEntity gaugeBlockEntity = (GaugeBlockEntity) blockEntity; - if (Mth.equal(gaugeTile.prevDialState, gaugeTile.dialState)) + if (Mth.equal(gaugeBlockEntity.prevDialState, gaugeBlockEntity.dialState)) return; - float progress = Mth.lerp(AnimationTickHolder.getPartialTicks(), gaugeTile.prevDialState, gaugeTile.dialState); + float progress = Mth.lerp(AnimationTickHolder.getPartialTicks(), gaugeBlockEntity.prevDialState, gaugeBlockEntity.dialState); TransformStack msr = TransformStack.cast(ms); @@ -144,24 +142,24 @@ public abstract class GaugeInstance extends ShaftInstance implements DynamicInst } public static class Speed extends GaugeInstance { - public Speed(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); + public Speed(MaterialManager materialManager, GaugeBlockEntity blockEntity) { + super(materialManager, blockEntity); } @Override protected Instancer getHeadModel() { - return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_SPEED, blockState); + return getTransformMaterial().getModel(AllPartialModels.GAUGE_HEAD_SPEED, blockState); } } public static class Stress extends GaugeInstance { - public Stress(MaterialManager dispatcher, KineticTileEntity tile) { - super(dispatcher, tile); + public Stress(MaterialManager materialManager, GaugeBlockEntity blockEntity) { + super(materialManager, blockEntity); } @Override protected Instancer getHeadModel() { - return getTransformMaterial().getModel(AllBlockPartials.GAUGE_HEAD_STRESS, blockState); + return getTransformMaterial().getModel(AllPartialModels.GAUGE_HEAD_STRESS, blockState); } } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeObservedPacket.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeObservedPacket.java new file mode 100644 index 0000000000..bfcb0b6ffd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeObservedPacket.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.kinetics.gauge; + +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class GaugeObservedPacket extends BlockEntityConfigurationPacket { + + public GaugeObservedPacket(BlockPos pos) { + super(pos); + } + + public GaugeObservedPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) {} + + @Override + protected void readSettings(FriendlyByteBuf buffer) {} + + @Override + protected void applySettings(StressGaugeBlockEntity be) { + be.onObserved(); + } + + @Override + protected boolean causeUpdate() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeRenderer.java new file mode 100644 index 0000000000..da739f7681 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeRenderer.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.kinetics.gauge; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.ShaftRenderer; +import com.simibubi.create.content.kinetics.gauge.GaugeBlock.Type; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class GaugeRenderer extends ShaftRenderer { + + protected GaugeBlock.Type type; + + public static GaugeRenderer speed(BlockEntityRendererProvider.Context context) { + return new GaugeRenderer(context, Type.SPEED); + } + + public static GaugeRenderer stress(BlockEntityRendererProvider.Context context) { + return new GaugeRenderer(context, Type.STRESS); + } + + protected GaugeRenderer(BlockEntityRendererProvider.Context context, GaugeBlock.Type type) { + super(context); + this.type = type; + } + + @Override + protected void renderSafe(GaugeBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) return; + + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + BlockState gaugeState = be.getBlockState(); + GaugeBlockEntity gaugeBE = (GaugeBlockEntity) be; + + PartialModel partialModel = (type == Type.SPEED ? AllPartialModels.GAUGE_HEAD_SPEED : AllPartialModels.GAUGE_HEAD_STRESS); + SuperByteBuffer headBuffer = + CachedPartialBuffers.partial(partialModel, gaugeState); + SuperByteBuffer dialBuffer = CachedPartialBuffers.partial(AllPartialModels.GAUGE_DIAL, gaugeState); + + float dialPivot = 5.75f / 16; + float progress = Mth.lerp(partialTicks, gaugeBE.prevDialState, gaugeBE.dialState); + + for (Direction facing : Iterate.directions) { + if (!((GaugeBlock) gaugeState.getBlock()).shouldRenderHeadOnFace(be.getLevel(), be.getBlockPos(), gaugeState, + facing)) + continue; + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + rotateBufferTowards(dialBuffer, facing).translate(0, dialPivot, dialPivot) + .rotate(Direction.EAST, (float) (Math.PI / 2 * -progress)) + .translate(0, -dialPivot, -dialPivot) + .light(light) + .renderInto(ms, vb); + rotateBufferTowards(headBuffer, facing).light(light) + .renderInto(ms, vb); + } + } + + protected SuperByteBuffer rotateBufferTowards(SuperByteBuffer buffer, Direction target) { + return buffer.rotateCentered(Direction.UP, (float) ((-target.toYRot() - 90) / 180 * Math.PI)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeShaper.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeShaper.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeShaper.java rename to src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeShaper.java index 5a47c03465..fab8b9d149 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeShaper.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/GaugeShaper.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.gauge; +package com.simibubi.create.content.kinetics.gauge; import java.util.Arrays; diff --git a/src/main/java/com/simibubi/create/content/kinetics/gauge/SpeedGaugeBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/SpeedGaugeBlockEntity.java new file mode 100644 index 0000000000..9541f12087 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/SpeedGaugeBlockEntity.java @@ -0,0 +1,97 @@ +package com.simibubi.create.content.kinetics.gauge; + +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.kinetics.base.IRotate.SpeedLevel; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class SpeedGaugeBlockEntity extends GaugeBlockEntity { + + public AbstractComputerBehaviour computerBehaviour; + + public SpeedGaugeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + float speed = Math.abs(getSpeed()); + + dialTarget = getDialTarget(speed); + color = Color.mixColors(SpeedLevel.of(speed) + .getColor(), 0xffffff, .25f); + + setChanged(); + } + + public static float getDialTarget(float speed) { + speed = Math.abs(speed); + float medium = AllConfigs.server().kinetics.mediumSpeed.get() + .floatValue(); + float fast = AllConfigs.server().kinetics.fastSpeed.get() + .floatValue(); + float max = AllConfigs.server().kinetics.maxRotationSpeed.get() + .floatValue(); + float target = 0; + if (speed == 0) + target = 0; + else if (speed < medium) + target = Mth.lerp(speed / medium, 0, .45f); + else if (speed < fast) + target = Mth.lerp((speed - medium) / (fast - medium), .45f, .75f); + else + target = Mth.lerp((speed - fast) / (max - fast), .75f, 1.125f); + return target; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + super.addToGoggleTooltip(tooltip, isPlayerSneaking); + CreateLang.translate("gui.speedometer.title") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + SpeedLevel.getFormattedSpeedText(speed, isOverStressed()) + .forGoggles(tooltip); + return true; + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/gauge/StressGaugeBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/gauge/StressGaugeBlockEntity.java new file mode 100644 index 0000000000..a9687c3f05 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gauge/StressGaugeBlockEntity.java @@ -0,0 +1,169 @@ +package com.simibubi.create.content.kinetics.gauge; + +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.kinetics.base.IRotate.StressImpact; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.LangBuilder; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class StressGaugeBlockEntity extends GaugeBlockEntity { + + public AbstractComputerBehaviour computerBehaviour; + + static BlockPos lastSent; + + public StressGaugeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + registerAwardables(behaviours, AllAdvancements.STRESSOMETER, AllAdvancements.STRESSOMETER_MAXED); + } + + @Override + public void updateFromNetwork(float maxStress, float currentStress, int networkSize) { + super.updateFromNetwork(maxStress, currentStress, networkSize); + + if (!StressImpact.isEnabled()) + dialTarget = 0; + else if (isOverStressed()) + dialTarget = 1.125f; + else if (maxStress == 0) + dialTarget = 0; + else + dialTarget = currentStress / maxStress; + + if (dialTarget > 0) { + if (dialTarget < .5f) + color = Color.mixColors(0x00FF00, 0xFFFF00, dialTarget * 2); + else if (dialTarget < 1) + color = Color.mixColors(0xFFFF00, 0xFF0000, (dialTarget) * 2 - 1); + else + color = 0xFF0000; + } + + sendData(); + setChanged(); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + if (getSpeed() == 0) { + dialTarget = 0; + setChanged(); + return; + } + + updateFromNetwork(capacity, stress, getOrCreateNetwork().getSize()); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + if (!StressImpact.isEnabled()) + return false; + + super.addToGoggleTooltip(tooltip, isPlayerSneaking); + + double capacity = getNetworkCapacity(); + double stressFraction = getNetworkStress() / (capacity == 0 ? 1 : capacity); + + CreateLang.translate("gui.stressometer.title") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + if (getTheoreticalSpeed() == 0) + CreateLang.text(TooltipHelper.makeProgressBar(3, 0)) + .translate("gui.stressometer.no_rotation") + .style(ChatFormatting.DARK_GRAY) + .forGoggles(tooltip); + else { + StressImpact.getFormattedStressText(stressFraction) + .forGoggles(tooltip); + CreateLang.translate("gui.stressometer.capacity") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + double remainingCapacity = capacity - getNetworkStress(); + + LangBuilder su = CreateLang.translate("generic.unit.stress"); + LangBuilder stressTip = CreateLang.number(remainingCapacity) + .add(su) + .style(StressImpact.of(stressFraction) + .getRelativeColor()); + + if (remainingCapacity != capacity) + stressTip.text(ChatFormatting.GRAY, " / ") + .add(CreateLang.number(capacity) + .add(su) + .style(ChatFormatting.DARK_GRAY)); + + stressTip.forGoggles(tooltip, 1); + } + + if (!worldPosition.equals(lastSent)) + AllPackets.getChannel().sendToServer(new GaugeObservedPacket(lastSent = worldPosition)); + + return true; + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket && worldPosition != null && worldPosition.equals(lastSent)) + lastSent = null; + } + + public float getNetworkStress() { + return stress; + } + + public float getNetworkCapacity() { + return capacity; + } + + public void onObserved() { + award(AllAdvancements.STRESSOMETER); + if (Mth.equal(dialTarget, 1)) + award(AllAdvancements.STRESSOMETER_MAXED); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxBlock.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlock.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlock.java index c27808a411..05df62eb3e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; +package com.simibubi.create.content.kinetics.gearbox; import java.util.Arrays; import java.util.List; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -24,7 +24,7 @@ import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.level.storage.loot.LootContext.Builder; import net.minecraft.world.phys.HitResult; -public class GearboxBlock extends RotatedPillarKineticBlock implements ITE { +public class GearboxBlock extends RotatedPillarKineticBlock implements IBE { public GearboxBlock(Properties properties) { super(properties); @@ -75,12 +75,12 @@ public class GearboxBlock extends RotatedPillarKineticBlock implements ITE getTileEntityClass() { - return GearboxTileEntity.class; + public Class getBlockEntityClass() { + return GearboxBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.GEARBOX.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.GEARBOX.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlockEntity.java new file mode 100644 index 0000000000..ee7537cdaa --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxBlockEntity.java @@ -0,0 +1,20 @@ +package com.simibubi.create.content.kinetics.gearbox; + +import com.simibubi.create.content.kinetics.base.DirectionalShaftHalvesBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class GearboxBlockEntity extends DirectionalShaftHalvesBlockEntity { + + public GearboxBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected boolean isNoisy() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxInstance.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java rename to src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxInstance.java index 1fa8af6328..8bf8863753 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/GearboxInstance.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; +package com.simibubi.create.content.kinetics.gearbox; import java.util.EnumMap; import java.util.Map; @@ -7,9 +7,9 @@ import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -17,13 +17,13 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.state.properties.BlockStateProperties; -public class GearboxInstance extends KineticTileInstance { +public class GearboxInstance extends KineticBlockEntityInstance { protected final EnumMap keys; protected Direction sourceFacing; - public GearboxInstance(MaterialManager modelManager, GearboxTileEntity tile) { - super(modelManager, tile); + public GearboxInstance(MaterialManager materialManager, GearboxBlockEntity blockEntity) { + super(materialManager, blockEntity); keys = new EnumMap<>(Direction.class); @@ -40,13 +40,13 @@ public class GearboxInstance extends KineticTileInstance { if (boxAxis == axis) continue; - Instancer shaft = rotatingMaterial.getModel(AllBlockPartials.SHAFT_HALF, blockState, direction); + Instancer shaft = rotatingMaterial.getModel(AllPartialModels.SHAFT_HALF, blockState, direction); RotatingData key = shaft.createInstance(); key.setRotationAxis(Direction.get(Direction.AxisDirection.POSITIVE, axis).step()) .setRotationalSpeed(getSpeed(direction)) - .setRotationOffset(getRotationOffset(axis)).setColor(tile) + .setRotationOffset(getRotationOffset(axis)).setColor(blockEntity) .setPosition(getInstancePosition()) .setBlockLight(blockLight) .setSkyLight(skyLight); diff --git a/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxRenderer.java new file mode 100644 index 0000000000..5a87a77e20 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/GearboxRenderer.java @@ -0,0 +1,61 @@ +package com.simibubi.create.content.kinetics.gearbox; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class GearboxRenderer extends KineticBlockEntityRenderer { + + public GearboxRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(GearboxBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) return; + + final Axis boxAxis = be.getBlockState().getValue(BlockStateProperties.AXIS); + final BlockPos pos = be.getBlockPos(); + float time = WorldTickHolder.getRenderTime(be.getLevel()); + + for (Direction direction : Iterate.directions) { + final Axis axis = direction.getAxis(); + if (boxAxis == axis) + continue; + + SuperByteBuffer shaft = CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), direction); + float offset = getRotationOffsetForPosition(be, pos, axis); + float angle = (time * be.getSpeed() * 3f / 10) % 360; + + if (be.getSpeed() != 0 && be.hasSource()) { + BlockPos source = be.source.subtract(be.getBlockPos()); + Direction sourceFacing = Direction.getNearest(source.getX(), source.getY(), source.getZ()); + if (sourceFacing.getAxis() == direction.getAxis()) + angle *= sourceFacing == direction ? 1 : -1; + else if (sourceFacing.getAxisDirection() == direction.getAxisDirection()) + angle *= -1; + } + + angle += offset; + angle = angle / 180f * (float) Math.PI; + + kineticRotationTransform(shaft, be, axis, angle, light); + shaft.renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/VerticalGearboxItem.java b/src/main/java/com/simibubi/create/content/kinetics/gearbox/VerticalGearboxItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/VerticalGearboxItem.java rename to src/main/java/com/simibubi/create/content/kinetics/gearbox/VerticalGearboxItem.java index 1a89bf55e2..519bb1c02d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gearbox/VerticalGearboxItem.java +++ b/src/main/java/com/simibubi/create/content/kinetics/gearbox/VerticalGearboxItem.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.relays.gearbox; +package com.simibubi.create.content.kinetics.gearbox; import java.util.Map; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.kinetics.base.IRotate; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/AllArmInteractionPointTypes.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/AllArmInteractionPointTypes.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/AllArmInteractionPointTypes.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/AllArmInteractionPointTypes.java index ae7f00d928..10376fe4ac 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/AllArmInteractionPointTypes.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/AllArmInteractionPointTypes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import java.util.Optional; import java.util.function.Function; @@ -9,31 +9,32 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock; -import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterTileEntity; -import com.simibubi.create.content.contraptions.components.deployer.DeployerBlock; -import com.simibubi.create.content.contraptions.components.saw.SawBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; -import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock; -import com.simibubi.create.content.logistics.block.funnel.AbstractFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlock; +import com.simibubi.create.content.kinetics.crafter.MechanicalCrafterBlockEntity; +import com.simibubi.create.content.kinetics.deployer.DeployerBlock; +import com.simibubi.create.content.kinetics.saw.SawBlock; +import com.simibubi.create.content.logistics.chute.AbstractChuteBlock; +import com.simibubi.create.content.logistics.funnel.AbstractFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.content.logistics.funnel.FunnelBlockEntity; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.Containers; import net.minecraft.world.InteractionResultHolder; @@ -261,7 +262,7 @@ public class AllArmInteractionPointTypes { @Override public boolean canCreatePoint(Level level, BlockPos pos, BlockState state) { return AllBlocks.MECHANICAL_SAW.has(state) && state.getValue(SawBlock.FACING) == Direction.UP - && ((KineticTileEntity) level.getBlockEntity(pos)).getSpeed() != 0; + && ((KineticBlockEntity) level.getBlockEntity(pos)).getSpeed() != 0; } @Override @@ -376,11 +377,11 @@ public class AllArmInteractionPointTypes { @Override public void keepAlive() { super.keepAlive(); - BeltTileEntity beltTE = BeltHelper.getSegmentTE(level, pos); - if (beltTE == null) + BeltBlockEntity beltBE = BeltHelper.getSegmentBE(level, pos); + if (beltBE == null) return; TransportedItemStackHandlerBehaviour transport = - beltTE.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); + beltBE.getBehaviour(TransportedItemStackHandlerBehaviour.TYPE); if (transport == null) return; MutableBoolean found = new MutableBoolean(false); @@ -443,10 +444,10 @@ public class AllArmInteractionPointTypes { @Override public ItemStack extract(int slot, int amount, boolean simulate) { - BlockEntity te = level.getBlockEntity(pos); - if (!(te instanceof MechanicalCrafterTileEntity)) + BlockEntity be = level.getBlockEntity(pos); + if (!(be instanceof MechanicalCrafterBlockEntity)) return ItemStack.EMPTY; - MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te; + MechanicalCrafterBlockEntity crafter = (MechanicalCrafterBlockEntity) be; SmartInventory inventory = crafter.getInventory(); inventory.allowExtraction(); ItemStack extract = super.extract(slot, amount, simulate); @@ -501,16 +502,17 @@ public class AllArmInteractionPointTypes { @Override protected Vec3 getInteractionPositionVector() { + Direction funnelFacing = FunnelBlock.getFunnelFacing(cachedState); + Vec3i normal = funnelFacing != null ? funnelFacing.getNormal() : Vec3i.ZERO; return VecHelper.getCenterOf(pos) - .add(Vec3.atLowerCornerOf(FunnelBlock.getFunnelFacing(cachedState) - .getNormal()) + .add(Vec3.atLowerCornerOf(normal) .scale(-.15f)); } @Override protected Direction getInteractionDirection() { - return FunnelBlock.getFunnelFacing(cachedState) - .getOpposite(); + Direction funnelFacing = FunnelBlock.getFunnelFacing(cachedState); + return funnelFacing != null ? funnelFacing.getOpposite() : Direction.UP; } @Override @@ -523,8 +525,8 @@ public class AllArmInteractionPointTypes { @Override public ItemStack insert(ItemStack stack, boolean simulate) { - FilteringBehaviour filtering = TileEntityBehaviour.get(level, pos, FilteringBehaviour.TYPE); - InvManipulationBehaviour inserter = TileEntityBehaviour.get(level, pos, InvManipulationBehaviour.TYPE); + FilteringBehaviour filtering = BlockEntityBehaviour.get(level, pos, FilteringBehaviour.TYPE); + InvManipulationBehaviour inserter = BlockEntityBehaviour.get(level, pos, InvManipulationBehaviour.TYPE); if (cachedState.getOptionalValue(BlockStateProperties.POWERED) .orElse(false)) return stack; @@ -536,12 +538,12 @@ public class AllArmInteractionPointTypes { inserter.simulate(); ItemStack insert = inserter.insert(stack); if (!simulate && insert.getCount() != stack.getCount()) { - BlockEntity tileEntity = level.getBlockEntity(pos); - if (tileEntity instanceof FunnelTileEntity) { - FunnelTileEntity funnelTileEntity = (FunnelTileEntity) tileEntity; - funnelTileEntity.onTransfer(stack); - if (funnelTileEntity.hasFlap()) - funnelTileEntity.flap(true); + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof FunnelBlockEntity) { + FunnelBlockEntity funnelBlockEntity = (FunnelBlockEntity) blockEntity; + funnelBlockEntity.onTransfer(stack); + if (funnelBlockEntity.hasFlap()) + funnelBlockEntity.flap(true); } } return insert; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmAngleTarget.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmAngleTarget.java index 7da424500a..074a86d14f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmAngleTarget.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmAngleTarget.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; @@ -18,18 +18,15 @@ public class ArmAngleTarget { float headAngle; private ArmAngleTarget() { - lowerArmAngle = 155; - upperArmAngle = 60; - headAngle = -15; + lowerArmAngle = 135; + upperArmAngle = 45; + headAngle = 0; } public ArmAngleTarget(BlockPos armPos, Vec3 pointTarget, Direction clawFacing, boolean ceiling) { -// if (ceiling) -// clawFacing = clawFacing.getOpposite(); - Vec3 target = pointTarget; Vec3 origin = VecHelper.getCenterOf(armPos) - .add(0, ceiling ? -4 / 16f : 4 / 16f, 0); + .add(0, ceiling ? -6 / 16f : 6 / 16f, 0); Vec3 clawTarget = target; target = target.add(Vec3.atLowerCornerOf(clawFacing.getOpposite() .getNormal()) @@ -47,9 +44,9 @@ public class ArmAngleTarget { float alphaOffset = AngleHelper.deg(Mth.atan2(diff.y, horizontalDistance)); - float a = 18 / 16f; // lower arm length + float a = 14 / 16f; // lower arm length float a2 = a * a; - float b = 17 / 16f; // upper arm length + float b = 15 / 16f; // upper arm length float b2 = b * b; float diffLength = Mth.clamp(Mth.sqrt((float) (diff.y * diff.y + horizontalDistance * horizontalDistance)), 1 / 8f, a + b); diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlock.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlock.java new file mode 100644 index 0000000000..ea4c24eca4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlock.java @@ -0,0 +1,118 @@ +package com.simibubi.create.content.kinetics.mechanicalArm; + +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.KineticBlock; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmBlockEntity.Phase; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class ArmBlock extends KineticBlock implements IBE, ICogWheel { + + public static final BooleanProperty CEILING = BooleanProperty.create("ceiling"); + + public ArmBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(CEILING, false)); + } + + @Override + protected void createBlockStateDefinition(Builder p_206840_1_) { + super.createBlockStateDefinition(p_206840_1_.add(CEILING)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { + return defaultBlockState().setValue(CEILING, ctx.getClickedFace() == Direction.DOWN); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return state.getValue(CEILING) ? AllShapes.MECHANICAL_ARM_CEILING : AllShapes.MECHANICAL_ARM; + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, world, pos, oldState, isMoving); + withBlockEntityDo(world, pos, ArmBlockEntity::redstoneUpdate); + } + + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, + BlockPos p_220069_5_, boolean p_220069_6_) { + withBlockEntityDo(world, pos, ArmBlockEntity::redstoneUpdate); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return Axis.Y; + } + + @Override + public Class getBlockEntityClass() { + return ArmBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_ARM.get(); + } + + @Override + public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, + InteractionHand hand, BlockHitResult p_225533_6_) { + ItemStack heldItem = player.getItemInHand(hand); + + if (AllItems.GOGGLES.isIn(heldItem)) { + InteractionResult gogglesResult = onBlockEntityUse(world, pos, ate -> { + if (ate.goggles) + return InteractionResult.PASS; + ate.goggles = true; + ate.notifyUpdate(); + return InteractionResult.SUCCESS; + }); + if (gogglesResult.consumesAction()) + return gogglesResult; + } + + MutableBoolean success = new MutableBoolean(false); + withBlockEntityDo(world, pos, be -> { + if (be.heldItem.isEmpty()) + return; + success.setTrue(); + if (world.isClientSide) + return; + player.getInventory().placeItemBackInInventory(be.heldItem); + be.heldItem = ItemStack.EMPTY; + be.phase = Phase.SEARCH_INPUTS; + be.setChanged(); + be.sendData(); + }); + + return success.booleanValue() ? InteractionResult.SUCCESS : InteractionResult.PASS; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java new file mode 100644 index 0000000000..71fab71f9f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmBlockEntity.java @@ -0,0 +1,651 @@ +package com.simibubi.create.content.kinetics.mechanicalArm; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes.JukeboxPoint; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPoint.Mode; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.lang.Lang; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.SectionPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.JukeboxBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class ArmBlockEntity extends KineticBlockEntity implements ITransformableBlockEntity { + + // Server + List inputs; + List outputs; + ListTag interactionPointTag; + + // Both + float chasedPointProgress; + int chasedPointIndex; + ItemStack heldItem; + Phase phase; + boolean goggles; + + // Client + ArmAngleTarget previousTarget; + LerpedFloat lowerArmAngle; + LerpedFloat upperArmAngle; + LerpedFloat baseAngle; + LerpedFloat headAngle; + LerpedFloat clawAngle; + float previousBaseAngle; + boolean updateInteractionPoints; + + // + protected ScrollOptionBehaviour selectionMode; + protected int lastInputIndex = -1; + protected int lastOutputIndex = -1; + protected boolean redstoneLocked; + + public enum Phase { + SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, DANCING + } + + public ArmBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + inputs = new ArrayList<>(); + outputs = new ArrayList<>(); + interactionPointTag = new ListTag(); + heldItem = ItemStack.EMPTY; + phase = Phase.SEARCH_INPUTS; + previousTarget = ArmAngleTarget.NO_TARGET; + baseAngle = LerpedFloat.angular(); + baseAngle.startWithValue(previousTarget.baseAngle); + lowerArmAngle = LerpedFloat.angular(); + lowerArmAngle.startWithValue(previousTarget.lowerArmAngle); + upperArmAngle = LerpedFloat.angular(); + upperArmAngle.startWithValue(previousTarget.upperArmAngle); + headAngle = LerpedFloat.angular(); + headAngle.startWithValue(previousTarget.headAngle); + clawAngle = LerpedFloat.angular(); + previousBaseAngle = previousTarget.baseAngle; + updateInteractionPoints = true; + redstoneLocked = false; + goggles = false; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + + selectionMode = new ScrollOptionBehaviour(SelectionMode.class, + CreateLang.translateDirect("logistics.when_multiple_outputs_available"), this, new SelectionModeValueBox()); + behaviours.add(selectionMode); + + registerAwardables(behaviours, AllAdvancements.ARM_BLAZE_BURNER, AllAdvancements.ARM_MANY_TARGETS, + AllAdvancements.MECHANICAL_ARM, AllAdvancements.MUSICAL_ARM); + } + + @Override + public void tick() { + super.tick(); + initInteractionPoints(); + boolean targetReached = tickMovementProgress(); + + if (chasedPointProgress < 1) { + if (phase == Phase.MOVE_TO_INPUT) { + ArmInteractionPoint point = getTargetedInteractionPoint(); + if (point != null) + point.keepAlive(); + } + return; + } + if (level.isClientSide) + return; + + if (phase == Phase.MOVE_TO_INPUT) + collectItem(); + else if (phase == Phase.MOVE_TO_OUTPUT) + depositItem(); + else if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) + searchForItem(); + + if (targetReached) + lazyTick(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + + if (level.isClientSide) + return; + if (chasedPointProgress < .5f) + return; + if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) + checkForMusic(); + if (phase == Phase.SEARCH_OUTPUTS) + searchForDestination(); + } + + private void checkForMusic() { + boolean hasMusic = checkForMusicAmong(inputs) || checkForMusicAmong(outputs); + if (hasMusic != (phase == Phase.DANCING)) { + phase = hasMusic ? Phase.DANCING : Phase.SEARCH_INPUTS; + setChanged(); + sendData(); + } + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(3); + } + + private boolean checkForMusicAmong(List list) { + for (ArmInteractionPoint armInteractionPoint : list) { + if (!(armInteractionPoint instanceof AllArmInteractionPointTypes.JukeboxPoint)) + continue; + BlockState state = level.getBlockState(armInteractionPoint.getPos()); + if (state.getOptionalValue(JukeboxBlock.HAS_RECORD) + .orElse(false)) + return true; + } + return false; + } + + private boolean tickMovementProgress() { + boolean targetReachedPreviously = chasedPointProgress >= 1; + chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f; + if (chasedPointProgress > 1) + chasedPointProgress = 1; + if (!level.isClientSide) + return !targetReachedPreviously && chasedPointProgress >= 1; + + ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint(); + ArmAngleTarget previousTarget = this.previousTarget; + ArmAngleTarget target = targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET + : targetedInteractionPoint.getTargetAngles(worldPosition, isOnCeiling()); + + baseAngle.setValue(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle, + target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle)); + + // Arm's angles first backup to resting position and then continue + if (chasedPointProgress < .5f) + target = ArmAngleTarget.NO_TARGET; + else + previousTarget = ArmAngleTarget.NO_TARGET; + float progress = chasedPointProgress == 1 ? 1 : (chasedPointProgress % .5f) * 2; + + lowerArmAngle.setValue(Mth.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle)); + upperArmAngle.setValue(Mth.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle)); + headAngle.setValue(AngleHelper.angleLerp(progress, previousTarget.headAngle % 360, target.headAngle % 360)); + + return false; + } + + protected boolean isOnCeiling() { + BlockState state = getBlockState(); + return hasLevel() && state.getOptionalValue(ArmBlock.CEILING) + .orElse(false); + } + + @Override + public void destroy() { + super.destroy(); + if (!heldItem.isEmpty()) + Block.popResource(level, worldPosition, heldItem); + } + + @Nullable + private ArmInteractionPoint getTargetedInteractionPoint() { + if (chasedPointIndex == -1) + return null; + if (phase == Phase.MOVE_TO_INPUT && chasedPointIndex < inputs.size()) + return inputs.get(chasedPointIndex); + if (phase == Phase.MOVE_TO_OUTPUT && chasedPointIndex < outputs.size()) + return outputs.get(chasedPointIndex); + return null; + } + + protected void searchForItem() { + if (redstoneLocked) + return; + + boolean foundInput = false; + // for round robin, we start looking after the last used index, for default we + // start at 0; + int startIndex = selectionMode.get() == SelectionMode.PREFER_FIRST ? 0 : lastInputIndex + 1; + + // if we enforce round robin, only look at the next input in the list, + // otherwise, look at all inputs + int scanRange = selectionMode.get() == SelectionMode.FORCED_ROUND_ROBIN ? lastInputIndex + 2 : inputs.size(); + if (scanRange > inputs.size()) + scanRange = inputs.size(); + + InteractionPoints: for (int i = startIndex; i < scanRange; i++) { + ArmInteractionPoint armInteractionPoint = inputs.get(i); + if (!armInteractionPoint.isValid()) + continue; + for (int j = 0; j < armInteractionPoint.getSlotCount(); j++) { + if (getDistributableAmount(armInteractionPoint, j) == 0) + continue; + + selectIndex(true, i); + foundInput = true; + break InteractionPoints; + } + } + if (!foundInput && selectionMode.get() == SelectionMode.ROUND_ROBIN) { + // if we didn't find an input, but don't want to enforce round robin, reset the + // last index + lastInputIndex = -1; + } + if (lastInputIndex == inputs.size() - 1) { + // if we reached the last input in the list, reset the last index + lastInputIndex = -1; + } + } + + protected void searchForDestination() { + ItemStack held = heldItem.copy(); + + boolean foundOutput = false; + // for round robin, we start looking after the last used index, for default we + // start at 0; + int startIndex = selectionMode.get() == SelectionMode.PREFER_FIRST ? 0 : lastOutputIndex + 1; + + // if we enforce round robin, only look at the next index in the list, + // otherwise, look at all + int scanRange = selectionMode.get() == SelectionMode.FORCED_ROUND_ROBIN ? lastOutputIndex + 2 : outputs.size(); + if (scanRange > outputs.size()) + scanRange = outputs.size(); + + for (int i = startIndex; i < scanRange; i++) { + ArmInteractionPoint armInteractionPoint = outputs.get(i); + if (!armInteractionPoint.isValid()) + continue; + + ItemStack remainder = armInteractionPoint.insert(held, true); + if (remainder.equals(heldItem, false)) + continue; + + selectIndex(false, i); + foundOutput = true; + break; + } + + if (!foundOutput && selectionMode.get() == SelectionMode.ROUND_ROBIN) { + // if we didn't find an input, but don't want to enforce round robin, reset the + // last index + lastOutputIndex = -1; + } + if (lastOutputIndex == outputs.size() - 1) { + // if we reached the last input in the list, reset the last index + lastOutputIndex = -1; + } + } + + // input == true => select input, false => select output + private void selectIndex(boolean input, int index) { + phase = input ? Phase.MOVE_TO_INPUT : Phase.MOVE_TO_OUTPUT; + chasedPointIndex = index; + chasedPointProgress = 0; + if (input) + lastInputIndex = index; + else + lastOutputIndex = index; + sendData(); + setChanged(); + } + + protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) { + ItemStack stack = armInteractionPoint.extract(i, true); + ItemStack remainder = simulateInsertion(stack); + if (stack.sameItem(remainder)) { + return stack.getCount() - remainder.getCount(); + } else { + return stack.getCount(); + } + } + + private ItemStack simulateInsertion(ItemStack stack) { + for (ArmInteractionPoint armInteractionPoint : outputs) { + if (armInteractionPoint.isValid()) + stack = armInteractionPoint.insert(stack, true); + if (stack.isEmpty()) + break; + } + return stack; + } + + protected void depositItem() { + ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); + if (armInteractionPoint != null && armInteractionPoint.isValid()) { + ItemStack toInsert = heldItem.copy(); + ItemStack remainder = armInteractionPoint.insert(toInsert, false); + heldItem = remainder; + + if (armInteractionPoint instanceof JukeboxPoint && remainder.isEmpty()) + award(AllAdvancements.MUSICAL_ARM); + } + + phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + setChanged(); + + if (!level.isClientSide) + award(AllAdvancements.MECHANICAL_ARM); + } + + protected void collectItem() { + ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); + if (armInteractionPoint != null && armInteractionPoint.isValid()) + for (int i = 0; i < armInteractionPoint.getSlotCount(); i++) { + int amountExtracted = getDistributableAmount(armInteractionPoint, i); + if (amountExtracted == 0) + continue; + + ItemStack prevHeld = heldItem; + heldItem = armInteractionPoint.extract(i, amountExtracted, false); + phase = Phase.SEARCH_OUTPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + setChanged(); + + if (!prevHeld.sameItem(heldItem)) + level.playSound(null, worldPosition, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, .125f, + .5f + Create.RANDOM.nextFloat() * .25f); + return; + } + + phase = Phase.SEARCH_INPUTS; + chasedPointProgress = 0; + chasedPointIndex = -1; + sendData(); + setChanged(); + } + + public void redstoneUpdate() { + if (level.isClientSide) + return; + boolean blockPowered = level.hasNeighborSignal(worldPosition); + if (blockPowered == redstoneLocked) + return; + redstoneLocked = blockPowered; + sendData(); + if (!redstoneLocked) + searchForItem(); + } + + @Override + public void transform(StructureTransform transform) { + if (interactionPointTag == null) + return; + + for (Tag tag : interactionPointTag) { + ArmInteractionPoint.transformPos((CompoundTag) tag, transform); + } + + notifyUpdate(); + } + + // ClientLevel#hasChunk (and consequently #isAreaLoaded) always returns true, + // so manually check the ChunkSource to avoid weird behavior on the client side + protected boolean isAreaActuallyLoaded(BlockPos center, int range) { + if (!level.isAreaLoaded(center, range)) { + return false; + } + if (level.isClientSide) { + int minY = center.getY() - range; + int maxY = center.getY() + range; + if (maxY < level.getMinBuildHeight() || minY >= level.getMaxBuildHeight()) { + return false; + } + + int minX = center.getX() - range; + int minZ = center.getZ() - range; + int maxX = center.getX() + range; + int maxZ = center.getZ() + range; + + int minChunkX = SectionPos.blockToSectionCoord(minX); + int maxChunkX = SectionPos.blockToSectionCoord(maxX); + int minChunkZ = SectionPos.blockToSectionCoord(minZ); + int maxChunkZ = SectionPos.blockToSectionCoord(maxZ); + + ChunkSource chunkSource = level.getChunkSource(); + for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { + if (!chunkSource.hasChunk(chunkX, chunkZ)) { + return false; + } + } + } + } + return true; + } + + protected void initInteractionPoints() { + if (!updateInteractionPoints || interactionPointTag == null) + return; + if (!isAreaActuallyLoaded(worldPosition, getRange() + 1)) + return; + inputs.clear(); + outputs.clear(); + + boolean hasBlazeBurner = false; + for (Tag tag : interactionPointTag) { + ArmInteractionPoint point = ArmInteractionPoint.deserialize((CompoundTag) tag, level, worldPosition); + if (point == null) + continue; + if (point.getMode() == Mode.DEPOSIT) + outputs.add(point); + else if (point.getMode() == Mode.TAKE) + inputs.add(point); + hasBlazeBurner |= point instanceof AllArmInteractionPointTypes.BlazeBurnerPoint; + } + + if (!level.isClientSide) { + if (outputs.size() >= 10) + award(AllAdvancements.ARM_MANY_TARGETS); + if (hasBlazeBurner) + award(AllAdvancements.ARM_BLAZE_BURNER); + } + + updateInteractionPoints = false; + sendData(); + setChanged(); + } + + public void writeInteractionPoints(CompoundTag compound) { + if (updateInteractionPoints) { + compound.put("InteractionPoints", interactionPointTag); + } else { + ListTag pointsNBT = new ListTag(); + inputs.stream() + .map(aip -> aip.serialize(worldPosition)) + .forEach(pointsNBT::add); + outputs.stream() + .map(aip -> aip.serialize(worldPosition)) + .forEach(pointsNBT::add); + compound.put("InteractionPoints", pointsNBT); + } + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + + writeInteractionPoints(compound); + + NBTHelper.writeEnum(compound, "Phase", phase); + compound.putBoolean("Powered", redstoneLocked); + compound.putBoolean("Goggles", goggles); + compound.put("HeldItem", heldItem.serializeNBT()); + compound.putInt("TargetPointIndex", chasedPointIndex); + compound.putFloat("MovementProgress", chasedPointProgress); + } + + @Override + public void writeSafe(CompoundTag compound) { + super.writeSafe(compound); + + writeInteractionPoints(compound); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + int previousIndex = chasedPointIndex; + Phase previousPhase = phase; + ListTag interactionPointTagBefore = interactionPointTag; + + super.read(compound, clientPacket); + heldItem = ItemStack.of(compound.getCompound("HeldItem")); + phase = NBTHelper.readEnum(compound, "Phase", Phase.class); + chasedPointIndex = compound.getInt("TargetPointIndex"); + chasedPointProgress = compound.getFloat("MovementProgress"); + interactionPointTag = compound.getList("InteractionPoints", Tag.TAG_COMPOUND); + redstoneLocked = compound.getBoolean("Powered"); + + boolean hadGoggles = goggles; + goggles = compound.getBoolean("Goggles"); + + if (!clientPacket) + return; + + if (hadGoggles != goggles) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + + boolean ceiling = isOnCeiling(); + if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size()) + updateInteractionPoints = true; + if (previousIndex != chasedPointIndex || (previousPhase != phase)) { + ArmInteractionPoint previousPoint = null; + if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size()) + previousPoint = inputs.get(previousIndex); + if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size()) + previousPoint = outputs.get(previousIndex); + previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET + : previousPoint.getTargetAngles(worldPosition, ceiling); + if (previousPoint != null) + previousBaseAngle = previousTarget.baseAngle; + + ArmInteractionPoint targetedPoint = getTargetedInteractionPoint(); + if (targetedPoint != null) + targetedPoint.updateCachedState(); + } + } + + public static int getRange() { + return AllConfigs.server().logistics.mechanicalArmRange.get(); + } + + @Override + public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { + if (super.addToTooltip(tooltip, isPlayerSneaking)) + return true; + if (isPlayerSneaking) + return false; + if (!inputs.isEmpty()) + return false; + if (!outputs.isEmpty()) + return false; + + TooltipHelper.addHint(tooltip, "hint.mechanical_arm_no_targets"); + return true; + } + + public void setLevel(Level level) { + super.setLevel(level); + for (ArmInteractionPoint input : inputs) { + input.setLevel(level); + } + for (ArmInteractionPoint output : outputs) { + output.setLevel(level); + } + } + + private class SelectionModeValueBox extends CenteredSideValueBoxTransform { + + public SelectionModeValueBox() { + super((blockState, direction) -> !direction.getAxis() + .isVertical()); + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + int yPos = state.getValue(ArmBlock.CEILING) ? 16 - 3 : 3; + Vec3 location = VecHelper.voxelSpace(8, yPos, 15.5); + location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Direction.Axis.Y); + return location; + } + + @Override + public float getScale() { + return super.getScale(); + } + + } + + public enum SelectionMode implements INamedIconOptions { + ROUND_ROBIN(AllIcons.I_ARM_ROUND_ROBIN), + FORCED_ROUND_ROBIN(AllIcons.I_ARM_FORCED_ROUND_ROBIN), + PREFER_FIRST(AllIcons.I_ARM_PREFER_FIRST), + + ; + + private final String translationKey; + private final AllIcons icon; + + SelectionMode(AllIcons icon) { + this.icon = icon; + this.translationKey = "mechanical_arm.selection_mode." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInstance.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInstance.java new file mode 100644 index 0000000000..9c72d5a627 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInstance.java @@ -0,0 +1,208 @@ +package com.simibubi.create.content.kinetics.mechanicalArm; + +import java.util.ArrayList; + +import com.google.common.collect.Lists; +import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.theme.Color; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.util.Mth; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; + +public class ArmInstance extends SingleRotatingInstance implements DynamicInstance { + + final ModelData base; + final ModelData lowerBody; + final ModelData upperBody; + ModelData claw; + + private final ArrayList clawGrips; + + private final ArrayList models; + private final Boolean ceiling; + + private boolean firstRender = true; + + private float baseAngle = Float.NaN; + private float lowerArmAngle = Float.NaN; + private float upperArmAngle = Float.NaN; + private float headAngle = Float.NaN; + + public ArmInstance(MaterialManager materialManager, ArmBlockEntity blockEntity) { + super(materialManager, blockEntity); + + Material mat = getTransformMaterial(); + + base = mat.getModel(AllPartialModels.ARM_BASE, blockState) + .createInstance(); + lowerBody = mat.getModel(AllPartialModels.ARM_LOWER_BODY, blockState) + .createInstance(); + upperBody = mat.getModel(AllPartialModels.ARM_UPPER_BODY, blockState) + .createInstance(); + claw = mat + .getModel(blockEntity.goggles ? AllPartialModels.ARM_CLAW_BASE_GOGGLES : AllPartialModels.ARM_CLAW_BASE, + blockState) + .createInstance(); + + ModelData clawGrip1 = mat.getModel(AllPartialModels.ARM_CLAW_GRIP_UPPER, blockState) + .createInstance(); + ModelData clawGrip2 = mat.getModel(AllPartialModels.ARM_CLAW_GRIP_LOWER, blockState) + .createInstance(); + + clawGrips = Lists.newArrayList(clawGrip1, clawGrip2); + models = Lists.newArrayList(base, lowerBody, upperBody, claw, clawGrip1, clawGrip2); + ceiling = blockState.getValue(ArmBlock.CEILING); + + animateArm(false); + } + + @Override + public void beginFrame() { + if (blockEntity.phase == ArmBlockEntity.Phase.DANCING && blockEntity.getSpeed() != 0) { + animateArm(true); + firstRender = true; + return; + } + + float pt = AnimationTickHolder.getPartialTicks(); + + float baseAngleNow = blockEntity.baseAngle.getValue(pt); + float lowerArmAngleNow = blockEntity.lowerArmAngle.getValue(pt); + float upperArmAngleNow = blockEntity.upperArmAngle.getValue(pt); + float headAngleNow = blockEntity.headAngle.getValue(pt); + + boolean settled = Mth.equal(baseAngle, baseAngleNow) && Mth.equal(lowerArmAngle, lowerArmAngleNow) + && Mth.equal(upperArmAngle, upperArmAngleNow) && Mth.equal(headAngle, headAngleNow); + + this.baseAngle = baseAngleNow; + this.lowerArmAngle = lowerArmAngleNow; + this.upperArmAngle = upperArmAngleNow; + this.headAngle = headAngleNow; + + if (!settled || firstRender) + animateArm(false); + + if (firstRender) + firstRender = false; + } + + private void animateArm(boolean rave) { + float baseAngle; + float lowerArmAngle; + float upperArmAngle; + float headAngle; + int color; + + if (rave) { + float renderTick = + WorldTickHolder.getRenderTime(blockEntity.getLevel()) + (blockEntity.hashCode() % 64); + baseAngle = (renderTick * 10) % 360; + lowerArmAngle = Mth.lerp((Mth.sin(renderTick / 4) + 1) / 2, -45, 15); + upperArmAngle = Mth.lerp((Mth.sin(renderTick / 8) + 1) / 4, -45, 95); + headAngle = -lowerArmAngle; + color = Color.rainbowColor(AnimationTickHolder.getTicks() * 100) + .getRGB(); + } else { + baseAngle = this.baseAngle; + lowerArmAngle = this.lowerArmAngle - 135; + upperArmAngle = this.upperArmAngle - 90; + headAngle = this.headAngle; + color = 0xFFFFFF; + } + + PoseStack msLocal = new PoseStack(); + TransformStack msr = TransformStack.cast(msLocal); + msr.translate(getInstancePosition()); + msr.centre(); + + if (ceiling) + msr.rotateX(180); + + ArmRenderer.transformBase(msr, baseAngle); + base.setTransform(msLocal); + + ArmRenderer.transformLowerArm(msr, lowerArmAngle); + lowerBody.setTransform(msLocal) + .setColor(color); + + ArmRenderer.transformUpperArm(msr, upperArmAngle); + upperBody.setTransform(msLocal) + .setColor(color); + + ArmRenderer.transformHead(msr, headAngle); + + if (ceiling && blockEntity.goggles) + msr.rotateZ(180); + + claw.setTransform(msLocal); + + if (ceiling && blockEntity.goggles) + msr.rotateZ(180); + + ItemStack item = blockEntity.heldItem; + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + boolean hasItem = !item.isEmpty(); + boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) + && itemRenderer.getModel(item, Minecraft.getInstance().level, null, 0) + .isGui3d(); + + for (int index : Iterate.zeroAndOne) { + msLocal.pushPose(); + int flip = index * 2 - 1; + ArmRenderer.transformClawHalf(msr, hasItem, isBlockItem, flip); + clawGrips.get(index) + .setTransform(msLocal); + msLocal.popPose(); + } + } + + @Override + public void update() { + super.update(); + models.remove(claw); + claw.delete(); + claw = getTransformMaterial() + .getModel(blockEntity.goggles ? AllPartialModels.ARM_CLAW_BASE_GOGGLES : AllPartialModels.ARM_CLAW_BASE, + blockState) + .createInstance(); + models.add(claw); + updateLight(); + animateArm(false); + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos, models.stream()); + } + + @Override + protected Instancer getModel() { + return getRotatingMaterial().getModel(AllPartialModels.ARM_COG, blockEntity.getBlockState()); + } + + @Override + public void remove() { + super.remove(); + models.forEach(InstanceData::delete); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPoint.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPoint.java index 2b7a7219ed..7bb29e8e55 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPoint.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import javax.annotation.Nullable; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; +import com.simibubi.create.content.contraptions.StructureTransform; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; @@ -93,10 +93,10 @@ public class ArmInteractionPoint { @Nullable protected IItemHandler getHandler() { if (!cachedHandler.isPresent()) { - BlockEntity te = level.getBlockEntity(pos); - if (te == null) + BlockEntity be = level.getBlockEntity(pos); + if (be == null) return null; - cachedHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP); + cachedHandler = be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP); } return cachedHandler.orElse(null); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointHandler.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointHandler.java index 44c5c301a1..5c263d0e3a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import java.util.ArrayList; import java.util.Collection; @@ -7,8 +7,8 @@ import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.CatnipClient; @@ -96,7 +96,7 @@ public class ArmInteractionPointHandler { for (Iterator iterator = currentSelection.iterator(); iterator.hasNext();) { ArmInteractionPoint point = iterator.next(); if (point.getPos() - .closerThan(pos, ArmTileEntity.getRange())) + .closerThan(pos, ArmBlockEntity.getRange())) continue; iterator.remove(); removed++; @@ -124,7 +124,7 @@ public class ArmInteractionPointHandler { .sendStatus(player); } - AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection, pos)); + AllPackets.getChannel().sendToServer(new ArmPlacementPacket(currentSelection, pos)); currentSelection.clear(); currentItem = null; } @@ -163,8 +163,8 @@ public class ArmInteractionPointHandler { BlockHitResult result = (BlockHitResult) objectMouseOver; BlockPos pos = result.getBlockPos(); - BlockEntity te = Minecraft.getInstance().level.getBlockEntity(pos); - if (!(te instanceof ArmTileEntity)) { + BlockEntity be = Minecraft.getInstance().level.getBlockEntity(pos); + if (!(be instanceof ArmBlockEntity)) { lastBlockPos = -1; currentSelection.clear(); return; @@ -172,7 +172,7 @@ public class ArmInteractionPointHandler { if (lastBlockPos == -1 || lastBlockPos != pos.asLong()) { currentSelection.clear(); - ArmTileEntity arm = (ArmTileEntity) te; + ArmBlockEntity arm = (ArmBlockEntity) be; arm.inputs.forEach(ArmInteractionPointHandler::put); arm.outputs.forEach(ArmInteractionPointHandler::put); lastBlockPos = pos.asLong(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointType.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointType.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointType.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointType.java index 05a7fa3db9..6e345f4c4c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPointType.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmInteractionPointType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmItem.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java rename to src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmItem.java index ee43890980..8553cf7503 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmItem.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; +package com.simibubi.create.content.kinetics.mechanicalArm; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionResult; diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmPlacementPacket.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmPlacementPacket.java new file mode 100644 index 0000000000..1aa84b90e2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmPlacementPacket.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.kinetics.mechanicalArm; + +import java.util.Collection; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ArmPlacementPacket extends SimplePacketBase { + + private Collection points; + private ListTag receivedTag; + private BlockPos pos; + + public ArmPlacementPacket(Collection points, BlockPos pos) { + this.points = points; + this.pos = pos; + } + + public ArmPlacementPacket(FriendlyByteBuf buffer) { + CompoundTag nbt = buffer.readNbt(); + receivedTag = nbt.getList("Points", Tag.TAG_COMPOUND); + pos = buffer.readBlockPos(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + CompoundTag nbt = new CompoundTag(); + ListTag pointsNBT = new ListTag(); + points.stream() + .map(aip -> aip.serialize(pos)) + .forEach(pointsNBT::add); + nbt.put("Points", pointsNBT); + buffer.writeNbt(nbt); + buffer.writeBlockPos(pos); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + Level world = player.level; + if (world == null || !world.isLoaded(pos)) + return; + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof ArmBlockEntity)) + return; + + ArmBlockEntity arm = (ArmBlockEntity) blockEntity; + arm.interactionPointTag = receivedTag; + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmRenderer.java new file mode 100644 index 0000000000..ea5b159c97 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mechanicalArm/ArmRenderer.java @@ -0,0 +1,207 @@ +package com.simibubi.create.content.kinetics.mechanicalArm; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmBlockEntity.Phase; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.theme.Color; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.util.Mth; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; + +public class ArmRenderer extends KineticBlockEntityRenderer { + + public ArmRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(ArmBlockEntity be, float pt, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + super.renderSafe(be, pt, ms, buffer, light, overlay); + + ItemStack item = be.heldItem; + boolean hasItem = !item.isEmpty(); + boolean usingFlywheel = Backend.canUseInstancing(be.getLevel()); + + if (usingFlywheel && !hasItem) + return; + + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + + boolean isBlockItem = + hasItem && (item.getItem() instanceof BlockItem) && itemRenderer.getModel(item, be.getLevel(), null, 0) + .isGui3d(); + + VertexConsumer builder = buffer.getBuffer(be.goggles ? RenderType.cutout() : RenderType.solid()); + BlockState blockState = be.getBlockState(); + + PoseStack msLocal = new PoseStack(); + TransformStack msr = TransformStack.cast(msLocal); + + float baseAngle; + float lowerArmAngle; + float upperArmAngle; + float headAngle; + int color; + boolean inverted = blockState.getValue(ArmBlock.CEILING); + + boolean rave = be.phase == Phase.DANCING && be.getSpeed() != 0; + if (rave) { + float renderTick = WorldTickHolder.getRenderTime(be.getLevel()) + (be.hashCode() % 64); + baseAngle = (renderTick * 10) % 360; + lowerArmAngle = Mth.lerp((Mth.sin(renderTick / 4) + 1) / 2, -45, 15); + upperArmAngle = Mth.lerp((Mth.sin(renderTick / 8) + 1) / 4, -45, 95); + headAngle = -lowerArmAngle; + color = Color.rainbowColor(AnimationTickHolder.getTicks() * 100) + .getRGB(); + } else { + baseAngle = be.baseAngle.getValue(pt); + lowerArmAngle = be.lowerArmAngle.getValue(pt) - 135; + upperArmAngle = be.upperArmAngle.getValue(pt) - 90; + headAngle = be.headAngle.getValue(pt); + color = 0xFFFFFF; + } + + msr.centre(); + + if (inverted) + msr.rotateX(180); + + if (usingFlywheel) + doItemTransforms(msr, baseAngle, lowerArmAngle, upperArmAngle, headAngle); + else + renderArm(builder, ms, msLocal, msr, blockState, color, baseAngle, lowerArmAngle, upperArmAngle, headAngle, + be.goggles, inverted && be.goggles, hasItem, isBlockItem, light); + + if (hasItem) { + ms.pushPose(); + float itemScale = isBlockItem ? .5f : .625f; + msr.rotateX(90); + msLocal.translate(0, isBlockItem ? -9 / 16f : -10 / 16f, 0); + msLocal.scale(itemScale, itemScale, itemScale); + + ms.last() + .pose() + .multiply(msLocal.last() + .pose()); + + itemRenderer.renderStatic(item, TransformType.FIXED, light, overlay, ms, buffer, 0); + ms.popPose(); + } + + } + + private void renderArm(VertexConsumer builder, PoseStack ms, PoseStack msLocal, TransformStack msr, + BlockState blockState, int color, float baseAngle, float lowerArmAngle, float upperArmAngle, float headAngle, + boolean goggles, boolean inverted, boolean hasItem, boolean isBlockItem, int light) { + SuperByteBuffer base = CachedPartialBuffers.partial(AllPartialModels.ARM_BASE, blockState) + .light(light); + SuperByteBuffer lowerBody = CachedPartialBuffers.partial(AllPartialModels.ARM_LOWER_BODY, blockState) + .light(light); + SuperByteBuffer upperBody = CachedPartialBuffers.partial(AllPartialModels.ARM_UPPER_BODY, blockState) + .light(light); + SuperByteBuffer claw = CachedPartialBuffers + .partial(goggles ? AllPartialModels.ARM_CLAW_BASE_GOGGLES : AllPartialModels.ARM_CLAW_BASE, blockState) + .light(light); + SuperByteBuffer upperClawGrip = CachedPartialBuffers.partial(AllPartialModels.ARM_CLAW_GRIP_UPPER, + blockState) + .light(light); + SuperByteBuffer lowerClawGrip = CachedPartialBuffers.partial(AllPartialModels.ARM_CLAW_GRIP_LOWER, blockState) + .light(light); + + transformBase(msr, baseAngle); + base.transform(msLocal) + .renderInto(ms, builder); + + transformLowerArm(msr, lowerArmAngle); + lowerBody.color(color) + .transform(msLocal) + .renderInto(ms, builder); + + transformUpperArm(msr, upperArmAngle); + upperBody.color(color) + .transform(msLocal) + .renderInto(ms, builder); + + transformHead(msr, headAngle); + + if (inverted) + msr.rotateZ(180); + + claw.transform(msLocal) + .renderInto(ms, builder); + + if (inverted) + msr.rotateZ(180); + + for (int flip : Iterate.positiveAndNegative) { + msLocal.pushPose(); + transformClawHalf(msr, hasItem, isBlockItem, flip); + (flip > 0 ? lowerClawGrip : upperClawGrip).transform(msLocal) + .renderInto(ms, builder); + msLocal.popPose(); + } + } + + private void doItemTransforms(TransformStack msr, float baseAngle, float lowerArmAngle, float upperArmAngle, + float headAngle) { + + transformBase(msr, baseAngle); + transformLowerArm(msr, lowerArmAngle); + transformUpperArm(msr, upperArmAngle); + transformHead(msr, headAngle); + } + + public static void transformClawHalf(TransformStack msr, boolean hasItem, boolean isBlockItem, int flip) { + msr.translate(0, -flip * (hasItem ? isBlockItem ? 3 / 16f : 5 / 64f : 1 / 16f), -6 / 16d); + } + + public static void transformHead(TransformStack msr, float headAngle) { + msr.translate(0, 0, -15 / 16d); + msr.rotateX(headAngle - 45f); + } + + public static void transformUpperArm(TransformStack msr, float upperArmAngle) { + msr.translate(0, 0, -14 / 16d); + msr.rotateX(upperArmAngle - 90); + } + + public static void transformLowerArm(TransformStack msr, float lowerArmAngle) { + msr.translate(0, 2 / 16d, 0); + msr.rotateX(lowerArmAngle + 135); + } + + public static void transformBase(TransformStack msr, float baseAngle) { + msr.translate(0, 4 / 16d, 0); + msr.rotateY(baseAngle); + } + + @Override + public boolean shouldRenderOffScreen(ArmBlockEntity be) { + return true; + } + + @Override + protected SuperByteBuffer getRotatedModel(ArmBlockEntity be, BlockState state) { + return CachedPartialBuffers.partial(AllPartialModels.ARM_COG, state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/millstone/MillingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillingRecipe.java new file mode 100644 index 0000000000..9c3f836f1d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillingRecipe.java @@ -0,0 +1,31 @@ +package com.simibubi.create.content.kinetics.millstone; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.kinetics.crusher.AbstractCrushingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; + +import net.minecraft.world.level.Level; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +@ParametersAreNonnullByDefault +public class MillingRecipe extends AbstractCrushingRecipe { + + public MillingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.MILLING, params); + } + + @Override + public boolean matches(RecipeWrapper inv, Level worldIn) { + if (inv.isEmpty()) + return false; + return ingredients.get(0) + .test(inv.getItem(0)); + } + + @Override + protected int getMaxOutputCount() { + return 4; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneBlock.java b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlock.java similarity index 75% rename from src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlock.java index 7c504cf3ff..cdd795b240 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlock.java @@ -1,11 +1,10 @@ -package com.simibubi.create.content.contraptions.components.millstone; +package com.simibubi.create.content.kinetics.millstone; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.content.kinetics.base.KineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; @@ -32,7 +31,7 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; -public class MillstoneBlock extends KineticBlock implements ITE, ICogWheel { +public class MillstoneBlock extends KineticBlock implements IBE, ICogWheel { public MillstoneBlock(Properties properties) { super(properties); @@ -57,7 +56,7 @@ public class MillstoneBlock extends KineticBlock implements ITE { + withBlockEntityDo(worldIn, pos, millstone -> { boolean emptyOutput = true; IItemHandlerModifiable inv = millstone.outputInv; for (int slot = 0; slot < inv.getSlots(); slot++) { @@ -96,10 +95,10 @@ public class MillstoneBlock extends KineticBlock implements ITE { - ItemHelper.dropContents(worldIn, pos, te.inputInv); - ItemHelper.dropContents(worldIn, pos, te.outputInv); - }); - - worldIn.removeBlockEntity(pos); - } - } - @Override public Axis getRotationAxis(BlockState state) { return Axis.Y; } @Override - public Class getTileEntityClass() { - return MillstoneTileEntity.class; + public Class getBlockEntityClass() { + return MillstoneBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MILLSTONE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MILLSTONE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlockEntity.java new file mode 100644 index 0000000000..0996532d46 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneBlockEntity.java @@ -0,0 +1,238 @@ +package com.simibubi.create.content.kinetics.millstone; + +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.sound.SoundScapes; +import com.simibubi.create.foundation.sound.SoundScapes.AmbienceGroup; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.CombinedInvWrapper; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class MillstoneBlockEntity extends KineticBlockEntity { + + public ItemStackHandler inputInv; + public ItemStackHandler outputInv; + public LazyOptional capability; + public int timer; + private MillingRecipe lastRecipe; + + public MillstoneBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inputInv = new ItemStackHandler(1); + outputInv = new ItemStackHandler(9); + capability = LazyOptional.of(MillstoneInventoryHandler::new); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this)); + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.MILLSTONE); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + super.tickAudio(); + + if (getSpeed() == 0) + return; + if (inputInv.getStackInSlot(0) + .isEmpty()) + return; + + float pitch = Mth.clamp((Math.abs(getSpeed()) / 256f) + .45f, .85f, 1f); + SoundScapes.play(AmbienceGroup.MILLING, worldPosition, pitch); + } + + @Override + public void tick() { + super.tick(); + + if (getSpeed() == 0) + return; + for (int i = 0; i < outputInv.getSlots(); i++) + if (outputInv.getStackInSlot(i) + .getCount() == outputInv.getSlotLimit(i)) + return; + + if (timer > 0) { + timer -= getProcessingSpeed(); + + if (level.isClientSide) { + spawnParticles(); + return; + } + if (timer <= 0) + process(); + return; + } + + if (inputInv.getStackInSlot(0) + .isEmpty()) + return; + + RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); + if (lastRecipe == null || !lastRecipe.matches(inventoryIn, level)) { + Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, level); + if (!recipe.isPresent()) { + timer = 100; + sendData(); + } else { + lastRecipe = recipe.get(); + timer = lastRecipe.getProcessingDuration(); + sendData(); + } + return; + } + + timer = lastRecipe.getProcessingDuration(); + sendData(); + } + + @Override + public void invalidate() { + super.invalidate(); + capability.invalidate(); + } + + @Override + public void destroy() { + super.destroy(); + ItemHelper.dropContents(level, worldPosition, inputInv); + ItemHelper.dropContents(level, worldPosition, outputInv); + } + + private void process() { + RecipeWrapper inventoryIn = new RecipeWrapper(inputInv); + + if (lastRecipe == null || !lastRecipe.matches(inventoryIn, level)) { + Optional recipe = AllRecipeTypes.MILLING.find(inventoryIn, level); + if (!recipe.isPresent()) + return; + lastRecipe = recipe.get(); + } + + ItemStack stackInSlot = inputInv.getStackInSlot(0); + stackInSlot.shrink(1); + inputInv.setStackInSlot(0, stackInSlot); + lastRecipe.rollResults() + .forEach(stack -> ItemHandlerHelper.insertItemStacked(outputInv, stack, false)); + award(AllAdvancements.MILLSTONE); + + sendData(); + setChanged(); + } + + public void spawnParticles() { + ItemStack stackInSlot = inputInv.getStackInSlot(0); + if (stackInSlot.isEmpty()) + return; + + ItemParticleOption data = new ItemParticleOption(ParticleTypes.ITEM, stackInSlot); + float angle = level.random.nextFloat() * 360; + Vec3 offset = new Vec3(0, 0, 0.5f); + offset = VecHelper.rotate(offset, angle, Axis.Y); + Vec3 target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y); + + Vec3 center = offset.add(VecHelper.getCenterOf(worldPosition)); + target = VecHelper.offsetRandomly(target.subtract(offset), level.random, 1 / 128f); + level.addParticle(data, center.x, center.y, center.z, target.x, target.y, target.z); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("Timer", timer); + compound.put("InputInventory", inputInv.serializeNBT()); + compound.put("OutputInventory", outputInv.serializeNBT()); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + timer = compound.getInt("Timer"); + inputInv.deserializeNBT(compound.getCompound("InputInventory")); + outputInv.deserializeNBT(compound.getCompound("OutputInventory")); + super.read(compound, clientPacket); + } + + public int getProcessingSpeed() { + return Mth.clamp((int) Math.abs(getSpeed() / 16f), 1, 512); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return capability.cast(); + return super.getCapability(cap, side); + } + + private boolean canProcess(ItemStack stack) { + ItemStackHandler tester = new ItemStackHandler(1); + tester.setStackInSlot(0, stack); + RecipeWrapper inventoryIn = new RecipeWrapper(tester); + + if (lastRecipe != null && lastRecipe.matches(inventoryIn, level)) + return true; + return AllRecipeTypes.MILLING.find(inventoryIn, level) + .isPresent(); + } + + private class MillstoneInventoryHandler extends CombinedInvWrapper { + + public MillstoneInventoryHandler() { + super(inputInv, outputInv); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + if (outputInv == getHandlerFromIndex(getIndexForSlot(slot))) + return false; + return canProcess(stack) && super.isItemValid(slot, stack); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (outputInv == getHandlerFromIndex(getIndexForSlot(slot))) + return stack; + if (!isItemValid(slot, stack)) + return stack; + return super.insertItem(slot, stack, simulate); + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (inputInv == getHandlerFromIndex(getIndexForSlot(slot))) + return ItemStack.EMPTY; + return super.extractItem(slot, amount, simulate); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneCogInstance.java b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneCogInstance.java new file mode 100644 index 0000000000..545ebe8d20 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneCogInstance.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.kinetics.millstone; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +public class MillstoneCogInstance extends SingleRotatingInstance { + + public MillstoneCogInstance(MaterialManager materialManager, MillstoneBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + return getRotatingMaterial().getModel(AllPartialModels.MILLSTONE_COG, blockEntity.getBlockState()); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneRenderer.java new file mode 100644 index 0000000000..72c2f2f140 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/millstone/MillstoneRenderer.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.kinetics.millstone; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class MillstoneRenderer extends KineticBlockEntityRenderer { + + public MillstoneRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected SuperByteBuffer getRotatedModel(MillstoneBlockEntity be, BlockState state) { + return CachedPartialBuffers.partial(AllPartialModels.MILLSTONE_COG, state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/CompactingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/CompactingRecipe.java new file mode 100644 index 0000000000..b099bab9ad --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/CompactingRecipe.java @@ -0,0 +1,13 @@ +package com.simibubi.create.content.kinetics.mixer; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; + +public class CompactingRecipe extends BasinRecipe { + + public CompactingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.COMPACTING, params); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerBlock.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlock.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlock.java index f53f53a6f6..62d9870844 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlock.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.contraptions.components.mixer; +package com.simibubi.create.content.kinetics.mixer; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.KineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -20,7 +20,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.EntityCollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class MechanicalMixerBlock extends KineticBlock implements ITE, ICogWheel { +public class MechanicalMixerBlock extends KineticBlock implements IBE, ICogWheel { public MechanicalMixerBlock(Properties properties) { super(properties); @@ -66,13 +66,13 @@ public class MechanicalMixerBlock extends KineticBlock implements ITE getTileEntityClass() { - return MechanicalMixerTileEntity.class; + public Class getBlockEntityClass() { + return MechanicalMixerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_MIXER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_MIXER.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlockEntity.java new file mode 100644 index 0000000000..e65e4daa12 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerBlockEntity.java @@ -0,0 +1,314 @@ +package com.simibubi.create.content.kinetics.mixer; + +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.fluids.FluidFX; +import com.simibubi.create.content.fluids.potion.PotionMixingRecipes; +import com.simibubi.create.content.kinetics.press.MechanicalPressBlockEntity; +import com.simibubi.create.content.processing.basin.BasinBlockEntity; +import com.simibubi.create.content.processing.basin.BasinOperatingBlockEntity; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.advancement.CreateAdvancement; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.crafting.IShapedRecipe; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class MechanicalMixerBlockEntity extends BasinOperatingBlockEntity { + + private static final Object shapelessOrMixingRecipesKey = new Object(); + + public int runningTicks; + public int processingTicks; + public boolean running; + + public MechanicalMixerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public float getRenderedHeadOffset(float partialTicks) { + int localTick; + float offset = 0; + if (running) { + if (runningTicks < 20) { + localTick = runningTicks; + float num = (localTick + partialTicks) / 20f; + num = ((2 - Mth.cos((float) (num * Math.PI))) / 2); + offset = num - .5f; + } else if (runningTicks <= 20) { + offset = 1; + } else { + localTick = 40 - runningTicks; + float num = (localTick - partialTicks) / 20f; + num = ((2 - Mth.cos((float) (num * Math.PI))) / 2); + offset = num - .5f; + } + } + return offset + 7 / 16f; + } + + public float getRenderedHeadRotationSpeed(float partialTicks) { + float speed = getSpeed(); + if (running) { + if (runningTicks < 15) { + return speed; + } + if (runningTicks <= 20) { + return speed * 2; + } + return speed; + } + return speed / 2; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.MIXER); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).expandTowards(0, -1.5, 0); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + running = compound.getBoolean("Running"); + runningTicks = compound.getInt("Ticks"); + super.read(compound, clientPacket); + + if (clientPacket && hasLevel()) + getBasin().ifPresent(bte -> bte.setAreFluidsMoving(running && runningTicks <= 20)); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putInt("Ticks", runningTicks); + super.write(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + + if (runningTicks >= 40) { + running = false; + runningTicks = 0; + basinChecker.scheduleUpdate(); + return; + } + + float speed = Math.abs(getSpeed()); + if (running && level != null) { + if (level.isClientSide && runningTicks == 20) + renderParticles(); + + if ((!level.isClientSide || isVirtual()) && runningTicks == 20) { + if (processingTicks < 0) { + float recipeSpeed = 1; + if (currentRecipe instanceof ProcessingRecipe) { + int t = ((ProcessingRecipe) currentRecipe).getProcessingDuration(); + if (t != 0) + recipeSpeed = t / 100f; + } + + processingTicks = Mth.clamp((Mth.log2((int) (512 / speed))) * Mth.ceil(recipeSpeed * 15) + 1, 1, 512); + + Optional basin = getBasin(); + if (basin.isPresent()) { + Couple tanks = basin.get() + .getTanks(); + if (!tanks.getFirst() + .isEmpty() + || !tanks.getSecond() + .isEmpty()) + level.playSound(null, worldPosition, SoundEvents.BUBBLE_COLUMN_WHIRLPOOL_AMBIENT, + SoundSource.BLOCKS, .75f, speed < 65 ? .75f : 1.5f); + } + + } else { + processingTicks--; + if (processingTicks == 0) { + runningTicks++; + processingTicks = -1; + applyBasinRecipe(); + sendData(); + } + } + } + + if (runningTicks != 20) + runningTicks++; + } + } + + public void renderParticles() { + Optional basin = getBasin(); + if (!basin.isPresent() || level == null) + return; + + for (SmartInventory inv : basin.get() + .getInvs()) { + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getItem(slot); + if (stackInSlot.isEmpty()) + continue; + ItemParticleOption data = new ItemParticleOption(ParticleTypes.ITEM, stackInSlot); + spillParticle(data); + } + } + + for (SmartFluidTankBehaviour behaviour : basin.get() + .getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + spillParticle(FluidFX.getFluidParticle(tankSegment.getRenderedFluid())); + } + } + } + + protected void spillParticle(ParticleOptions data) { + float angle = level.random.nextFloat() * 360; + Vec3 offset = new Vec3(0, 0, 0.25f); + offset = VecHelper.rotate(offset, angle, Axis.Y); + Vec3 target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y) + .add(0, .25f, 0); + Vec3 center = offset.add(VecHelper.getCenterOf(worldPosition)); + target = VecHelper.offsetRandomly(target.subtract(offset), level.random, 1 / 128f); + level.addParticle(data, center.x, center.y - 1.75f, center.z, target.x, target.y, target.z); + } + + @Override + protected List> getMatchingRecipes() { + List> matchingRecipes = super.getMatchingRecipes(); + + if (!AllConfigs.server().recipes.allowBrewingInMixer.get()) + return matchingRecipes; + + Optional basin = getBasin(); + if (!basin.isPresent()) + return matchingRecipes; + + BasinBlockEntity basinBlockEntity = basin.get(); + if (basin.isEmpty()) + return matchingRecipes; + + IItemHandler availableItems = basinBlockEntity + .getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .orElse(null); + if (availableItems == null) + return matchingRecipes; + + for (int i = 0; i < availableItems.getSlots(); i++) { + ItemStack stack = availableItems.getStackInSlot(i); + if (stack.isEmpty()) + continue; + + List list = PotionMixingRecipes.BY_ITEM.get(stack.getItem()); + if (list == null) + continue; + for (MixingRecipe mixingRecipe : list) + if (matchBasinRecipe(mixingRecipe)) + matchingRecipes.add(mixingRecipe); + } + + return matchingRecipes; + } + + @Override + protected boolean matchStaticFilters(Recipe r) { + return ((r instanceof CraftingRecipe && !(r instanceof IShapedRecipe) + && AllConfigs.server().recipes.allowShapelessInMixer.get() && r.getIngredients() + .size() > 1 + && !MechanicalPressBlockEntity.canCompress(r)) && !AllRecipeTypes.shouldIgnoreInAutomation(r) + || r.getType() == AllRecipeTypes.MIXING.getType()); + } + + @Override + public void startProcessingBasin() { + if (running && runningTicks <= 20) + return; + super.startProcessingBasin(); + running = true; + runningTicks = 0; + } + + @Override + public boolean continueWithPreviousRecipe() { + runningTicks = 20; + return true; + } + + @Override + protected void onBasinRemoved() { + if (!running) + return; + runningTicks = 40; + running = false; + } + + @Override + protected Object getRecipeCacheKey() { + return shapelessOrMixingRecipesKey; + } + + @Override + protected boolean isRunning() { + return running; + } + + @Override + protected Optional getProcessedRecipeTrigger() { + return Optional.of(AllAdvancements.MIXER); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + super.tickAudio(); + + // SoundEvents.BLOCK_STONE_BREAK + boolean slow = Math.abs(getSpeed()) < 65; + if (slow && AnimationTickHolder.getTicks() % 2 == 0) + return; + if (runningTicks == 20) + AllSoundEvents.MIXING.playAt(level, worldPosition, .75f, 1, true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerRenderer.java new file mode 100644 index 0000000000..9cc933142d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MechanicalMixerRenderer.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.kinetics.mixer; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class MechanicalMixerRenderer extends KineticBlockEntityRenderer { + + public MechanicalMixerRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + public boolean shouldRenderOffScreen(MechanicalMixerBlockEntity be) { + return true; + } + + @Override + protected void renderSafe(MechanicalMixerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + BlockState blockState = be.getBlockState(); + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + SuperByteBuffer superBuffer = CachedPartialBuffers.partial(AllPartialModels.SHAFTLESS_COGWHEEL, blockState); + standardKineticRotationTransform(superBuffer, be, light).renderInto(ms, vb); + + float renderedHeadOffset = be.getRenderedHeadOffset(partialTicks); + float speed = be.getRenderedHeadRotationSpeed(partialTicks); + float time = WorldTickHolder.getRenderTime(be.getLevel()); + float angle = ((time * speed * 6 / 10f) % 360) / 180 * (float) Math.PI; + + SuperByteBuffer poleRender = CachedPartialBuffers.partial(AllPartialModels.MECHANICAL_MIXER_POLE, blockState); + poleRender.translate(0, -renderedHeadOffset, 0) + .light(light) + .renderInto(ms, vb); + + VertexConsumer vbCutout = buffer.getBuffer(RenderType.cutoutMipped()); + SuperByteBuffer headRender = CachedPartialBuffers.partial(AllPartialModels.MECHANICAL_MIXER_HEAD, blockState); + headRender.rotateCentered(Direction.UP, angle) + .translate(0, -renderedHeadOffset, 0) + .light(light) + .renderInto(ms, vbCutout); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerInstance.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerInstance.java new file mode 100644 index 0000000000..8664bc2dce --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixerInstance.java @@ -0,0 +1,90 @@ +package com.simibubi.create.content.kinetics.mixer; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogInstance; +import com.simibubi.create.foundation.render.AllMaterialSpecs; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.core.Direction; + +public class MixerInstance extends EncasedCogInstance implements DynamicInstance { + + private final RotatingData mixerHead; + private final OrientedData mixerPole; + private final MechanicalMixerBlockEntity mixer; + + public MixerInstance(MaterialManager materialManager, MechanicalMixerBlockEntity blockEntity) { + super(materialManager, blockEntity, false); + this.mixer = blockEntity; + + mixerHead = materialManager.defaultCutout() + .material(AllMaterialSpecs.ROTATING) + .getModel(AllPartialModels.MECHANICAL_MIXER_HEAD, blockState) + .createInstance(); + + mixerHead.setRotationAxis(Direction.Axis.Y); + + mixerPole = getOrientedMaterial() + .getModel(AllPartialModels.MECHANICAL_MIXER_POLE, blockState) + .createInstance(); + + + float renderedHeadOffset = getRenderedHeadOffset(); + + transformPole(renderedHeadOffset); + transformHead(renderedHeadOffset); + } + + @Override + protected Instancer getCogModel() { + return materialManager.defaultSolid() + .material(AllMaterialSpecs.ROTATING) + .getModel(AllPartialModels.SHAFTLESS_COGWHEEL, blockEntity.getBlockState()); + } + + @Override + public void beginFrame() { + + float renderedHeadOffset = getRenderedHeadOffset(); + + transformPole(renderedHeadOffset); + transformHead(renderedHeadOffset); + } + + private void transformHead(float renderedHeadOffset) { + float speed = mixer.getRenderedHeadRotationSpeed(AnimationTickHolder.getPartialTicks()); + + mixerHead.setPosition(getInstancePosition()) + .nudge(0, -renderedHeadOffset, 0) + .setRotationalSpeed(speed * 2); + } + + private void transformPole(float renderedHeadOffset) { + mixerPole.setPosition(getInstancePosition()) + .nudge(0, -renderedHeadOffset, 0); + } + + private float getRenderedHeadOffset() { + return mixer.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()); + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos.below(), mixerHead); + relight(pos, mixerPole); + } + + @Override + public void remove() { + super.remove(); + mixerHead.delete(); + mixerPole.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/mixer/MixingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixingRecipe.java new file mode 100644 index 0000000000..b7fcdd799b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/mixer/MixingRecipe.java @@ -0,0 +1,13 @@ +package com.simibubi.create.content.kinetics.mixer; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.content.processing.basin.BasinRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; + +public class MixingRecipe extends BasinRecipe { + + public MixingRecipe(ProcessingRecipeParams params) { + super(AllRecipeTypes.MIXING, params); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlock.java similarity index 78% rename from src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlock.java index 8c5a2f971a..caa6dcfb5b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlock.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.components.motor; +package com.simibubi.create.content.kinetics.motor; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -17,7 +17,7 @@ import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE { +public class CreativeMotorBlock extends DirectionalKineticBlock implements IBE { public CreativeMotorBlock(Properties properties) { super(properties); @@ -61,13 +61,13 @@ public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE getTileEntityClass() { - return CreativeMotorTileEntity.class; + public Class getBlockEntityClass() { + return CreativeMotorBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MOTOR.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MOTOR.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlockEntity.java new file mode 100644 index 0000000000..c57b5231f3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorBlockEntity.java @@ -0,0 +1,96 @@ +package com.simibubi.create.content.kinetics.motor; + +import java.util.List; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class CreativeMotorBlockEntity extends GeneratingKineticBlockEntity { + + public static final int DEFAULT_SPEED = 16; + public static final int MAX_SPEED = 256; + + protected ScrollValueBehaviour generatedSpeed; + + public CreativeMotorBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + int max = MAX_SPEED; + generatedSpeed = new KineticScrollValueBehaviour(CreateLang.translateDirect("kinetics.creative_motor.rotation_speed"), + this, new MotorValueBox()); + generatedSpeed.between(-max, max); + generatedSpeed.value = DEFAULT_SPEED; + generatedSpeed.withCallback(i -> this.updateGeneratedRotation()); + behaviours.add(generatedSpeed); + } + + @Override + public void initialize() { + super.initialize(); + if (!hasSource() || getGeneratedSpeed() > getTheoreticalSpeed()) + updateGeneratedRotation(); + } + + @Override + public float getGeneratedSpeed() { + if (!AllBlocks.CREATIVE_MOTOR.has(getBlockState())) + return 0; + return convertToDirection(generatedSpeed.getValue(), getBlockState().getValue(CreativeMotorBlock.FACING)); + } + + class MotorValueBox extends ValueBoxTransform.Sided { + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 8, 12.5); + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + Direction facing = state.getValue(CreativeMotorBlock.FACING); + return super.getLocalOffset(state).add(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(-1 / 16f)); + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + super.rotate(state, ms); + Direction facing = state.getValue(CreativeMotorBlock.FACING); + if (facing.getAxis() == Axis.Y) + return; + if (getSide() != Direction.UP) + return; + TransformStack.cast(ms) + .rotateZ(-AngleHelper.horizontalAngle(facing) + 180); + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + Direction facing = state.getValue(CreativeMotorBlock.FACING); + if (facing.getAxis() != Axis.Y && direction == Direction.DOWN) + return false; + return direction.getAxis() != facing.getAxis(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorGenerator.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorGenerator.java rename to src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorGenerator.java index f774f40353..d62a2bbbe6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorGenerator.java +++ b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.motor; +package com.simibubi.create.content.kinetics.motor; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; diff --git a/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorRenderer.java new file mode 100644 index 0000000000..4f7e83eb19 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/motor/CreativeMotorRenderer.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.kinetics.motor; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class CreativeMotorRenderer extends KineticBlockEntityRenderer { + + public CreativeMotorRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected SuperByteBuffer getRotatedModel(CreativeMotorBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/motor/KineticScrollValueBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/motor/KineticScrollValueBehaviour.java new file mode 100644 index 0000000000..5eb5ad51e4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/motor/KineticScrollValueBehaviour.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.kinetics.motor; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.BlockHitResult; + +public class KineticScrollValueBehaviour extends ScrollValueBehaviour { + + public KineticScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot) { + super(label, be, slot); + withFormatter(v -> String.valueOf(Math.abs(v))); + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + ImmutableList rows = ImmutableList.of(Components.literal("\u27f3") + .withStyle(ChatFormatting.BOLD), + Components.literal("\u27f2") + .withStyle(ChatFormatting.BOLD)); + ValueSettingsFormatter formatter = new ValueSettingsFormatter(this::formatSettings); + return new ValueSettingsBoard(label, 256, 32, rows, formatter); + } + + @Override + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlHeld) { + int value = Math.max(1, valueSetting.value()); + if (!valueSetting.equals(getValueSettings())) + playFeedbackSound(this); + setValue(valueSetting.row() == 0 ? -value : value); + } + + @Override + public ValueSettings getValueSettings() { + return new ValueSettings(value < 0 ? 0 : 1, Math.abs(value)); + } + + public MutableComponent formatSettings(ValueSettings settings) { + return CreateLang.number(Math.max(1, Math.abs(settings.value()))) + .add(CreateLang.text(settings.row() == 0 ? "\u27f3" : "\u27f2") + .style(ChatFormatting.BOLD)) + .component(); + } + + @Override + public String getClipboardKey() { + return "Speed"; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/press/BeltPressingCallbacks.java b/src/main/java/com/simibubi/create/content/kinetics/press/BeltPressingCallbacks.java new file mode 100644 index 0000000000..900aab84b3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/press/BeltPressingCallbacks.java @@ -0,0 +1,83 @@ +package com.simibubi.create.content.kinetics.press; + +import static com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult.HOLD; +import static com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult.PASS; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.simibubi.create.Create; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.kinetics.press.PressingBehaviour.Mode; + +import net.minecraft.world.item.ItemStack; + +public class BeltPressingCallbacks { + + static ProcessingResult onItemReceived(TransportedItemStack transported, + TransportedItemStackHandlerBehaviour handler, PressingBehaviour behaviour) { + if (behaviour.specifics.getKineticSpeed() == 0) + return PASS; + if (behaviour.running) + return HOLD; + if (!behaviour.specifics.tryProcessOnBelt(transported, null, true)) + return PASS; + + behaviour.start(Mode.BELT); + return HOLD; + } + + static ProcessingResult whenItemHeld(TransportedItemStack transported, TransportedItemStackHandlerBehaviour handler, + PressingBehaviour behaviour) { + + if (behaviour.specifics.getKineticSpeed() == 0) + return PASS; + if (!behaviour.running) + return PASS; + if (behaviour.runningTicks != PressingBehaviour.CYCLE / 2) + return HOLD; + + behaviour.particleItems.clear(); + ArrayList results = new ArrayList<>(); + if (!behaviour.specifics.tryProcessOnBelt(transported, results, false)) + return PASS; + + boolean bulk = behaviour.specifics.canProcessInBulk() || transported.stack.getCount() == 1; + + List collect = results.stream() + .map(stack -> { + TransportedItemStack copy = transported.copy(); + boolean centered = BeltHelper.isItemUpright(stack); + copy.stack = stack; + copy.locked = true; + copy.angle = centered ? 180 : Create.RANDOM.nextInt(360); + return copy; + }) + .collect(Collectors.toList()); + + if (bulk) { + if (collect.isEmpty()) + handler.handleProcessingOnItem(transported, TransportedResult.removeItem()); + else + handler.handleProcessingOnItem(transported, TransportedResult.convertTo(collect)); + + } else { + TransportedItemStack left = transported.copy(); + left.stack.shrink(1); + + if (collect.isEmpty()) + handler.handleProcessingOnItem(transported, TransportedResult.convertTo(left)); + else + handler.handleProcessingOnItem(transported, TransportedResult.convertToAndLeaveHeld(collect, left)); + } + + behaviour.blockEntity.sendData(); + return HOLD; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressBlock.java b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlock.java index 2c37125c56..a951421627 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.press; +package com.simibubi.create.content.kinetics.press; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -20,7 +20,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.EntityCollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class MechanicalPressBlock extends HorizontalKineticBlock implements ITE { +public class MechanicalPressBlock extends HorizontalKineticBlock implements IBE { public MechanicalPressBlock(Properties properties) { super(properties); @@ -61,13 +61,13 @@ public class MechanicalPressBlock extends HorizontalKineticBlock implements ITE< } @Override - public Class getTileEntityClass() { - return MechanicalPressTileEntity.class; + public Class getBlockEntityClass() { + return MechanicalPressBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_PRESS.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.MECHANICAL_PRESS.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlockEntity.java new file mode 100644 index 0000000000..c9466dae2d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressBlockEntity.java @@ -0,0 +1,254 @@ +package com.simibubi.create.content.kinetics.press; + +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.AllTags; +import com.simibubi.create.Create; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.kinetics.crafter.MechanicalCraftingRecipe; +import com.simibubi.create.content.kinetics.press.PressingBehaviour.Mode; +import com.simibubi.create.content.kinetics.press.PressingBehaviour.PressingBehaviourSpecifics; +import com.simibubi.create.content.processing.basin.BasinBlockEntity; +import com.simibubi.create.content.processing.basin.BasinOperatingBlockEntity; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.advancement.CreateAdvancement; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.foundation.recipe.RecipeApplier; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.Container; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.RecipeWrapper; + +public class MechanicalPressBlockEntity extends BasinOperatingBlockEntity implements PressingBehaviourSpecifics { + + private static final Object compressingRecipesKey = new Object(); + + public PressingBehaviour pressingBehaviour; + private int tracksCreated; + + public MechanicalPressBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).expandTowards(0, -1.5, 0) + .expandTowards(0, 1, 0); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + pressingBehaviour = new PressingBehaviour(this); + behaviours.add(pressingBehaviour); + + registerAwardables(behaviours, AllAdvancements.PRESS, AllAdvancements.COMPACTING, + AllAdvancements.TRACK_CRAFTING); + } + + public void onItemPressed(ItemStack result) { + award(AllAdvancements.PRESS); + if (AllTags.AllBlockTags.TRACKS.matches(result)) + tracksCreated += result.getCount(); + if (tracksCreated >= 1000) { + award(AllAdvancements.TRACK_CRAFTING); + tracksCreated = 0; + } + } + + public PressingBehaviour getPressingBehaviour() { + return pressingBehaviour; + } + + @Override + public boolean tryProcessInBasin(boolean simulate) { + applyBasinRecipe(); + + Optional basin = getBasin(); + if (basin.isPresent()) { + SmartInventory inputs = basin.get() + .getInputInventory(); + for (int slot = 0; slot < inputs.getSlots(); slot++) { + ItemStack stackInSlot = inputs.getItem(slot); + if (stackInSlot.isEmpty()) + continue; + pressingBehaviour.particleItems.add(stackInSlot); + } + } + + return true; + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + if (getBehaviour(AdvancementBehaviour.TYPE).isOwnerPresent()) + compound.putInt("TracksCreated", tracksCreated); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + tracksCreated = compound.getInt("TracksCreated"); + } + + @Override + public boolean tryProcessInWorld(ItemEntity itemEntity, boolean simulate) { + ItemStack item = itemEntity.getItem(); + Optional recipe = getRecipe(item); + if (!recipe.isPresent()) + return false; + if (simulate) + return true; + + ItemStack itemCreated = ItemStack.EMPTY; + pressingBehaviour.particleItems.add(item); + if (canProcessInBulk() || item.getCount() == 1) { + RecipeApplier.applyRecipeOn(itemEntity, recipe.get()); + itemCreated = itemEntity.getItem() + .copy(); + } else { + for (ItemStack result : RecipeApplier.applyRecipeOn(ItemHandlerHelper.copyStackWithSize(item, 1), + recipe.get())) { + if (itemCreated.isEmpty()) + itemCreated = result.copy(); + ItemEntity created = + new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), result); + created.setDefaultPickUpDelay(); + created.setDeltaMovement(VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, .05f)); + level.addFreshEntity(created); + } + item.shrink(1); + } + + if (!itemCreated.isEmpty()) + onItemPressed(itemCreated); + return true; + } + + @Override + public boolean tryProcessOnBelt(TransportedItemStack input, List outputList, boolean simulate) { + Optional recipe = getRecipe(input.stack); + if (!recipe.isPresent()) + return false; + if (simulate) + return true; + pressingBehaviour.particleItems.add(input.stack); + List outputs = RecipeApplier.applyRecipeOn( + canProcessInBulk() ? input.stack : ItemHandlerHelper.copyStackWithSize(input.stack, 1), recipe.get()); + + for (ItemStack created : outputs) { + if (!created.isEmpty()) { + onItemPressed(created); + break; + } + } + + outputList.addAll(outputs); + return true; + } + + @Override + public void onPressingCompleted() { + if (pressingBehaviour.onBasin() && matchBasinRecipe(currentRecipe) + && getBasin().filter(BasinBlockEntity::canContinueProcessing) + .isPresent()) + startProcessingBasin(); + else + basinChecker.scheduleUpdate(); + } + + private static final RecipeWrapper pressingInv = new RecipeWrapper(new ItemStackHandler(1)); + + public Optional getRecipe(ItemStack item) { + Optional assemblyRecipe = + SequencedAssemblyRecipe.getRecipe(level, item, AllRecipeTypes.PRESSING.getType(), PressingRecipe.class); + if (assemblyRecipe.isPresent()) + return assemblyRecipe; + + pressingInv.setItem(0, item); + return AllRecipeTypes.PRESSING.find(pressingInv, level); + } + + public static boolean canCompress(Recipe recipe) { + if (!(recipe instanceof CraftingRecipe) || !AllConfigs.server().recipes.allowShapedSquareInPress.get()) + return false; + NonNullList ingredients = recipe.getIngredients(); + return (ingredients.size() == 4 || ingredients.size() == 9) && ItemHelper.matchAllIngredients(ingredients); + } + + @Override + protected boolean matchStaticFilters(Recipe recipe) { + return (recipe instanceof CraftingRecipe && !(recipe instanceof MechanicalCraftingRecipe) && canCompress(recipe) + && !AllRecipeTypes.shouldIgnoreInAutomation(recipe)) + || recipe.getType() == AllRecipeTypes.COMPACTING.getType(); + } + + @Override + public float getKineticSpeed() { + return getSpeed(); + } + + @Override + public boolean canProcessInBulk() { + return AllConfigs.server().recipes.bulkPressing.get(); + } + + @Override + protected Object getRecipeCacheKey() { + return compressingRecipesKey; + } + + @Override + public int getParticleAmount() { + return 15; + } + + @Override + public void startProcessingBasin() { + if (pressingBehaviour.running && pressingBehaviour.runningTicks <= PressingBehaviour.CYCLE / 2) + return; + super.startProcessingBasin(); + pressingBehaviour.start(Mode.BASIN); + } + + @Override + protected void onBasinRemoved() { + pressingBehaviour.particleItems.clear(); + pressingBehaviour.running = false; + pressingBehaviour.runningTicks = 0; + sendData(); + } + + @Override + protected boolean isRunning() { + return pressingBehaviour.running; + } + + @Override + protected Optional getProcessedRecipeTrigger() { + return Optional.of(AllAdvancements.COMPACTING); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressRenderer.java new file mode 100644 index 0000000000..51945c6af7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/press/MechanicalPressRenderer.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.kinetics.press; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.state.BlockState; + +public class MechanicalPressRenderer extends KineticBlockEntityRenderer { + + public MechanicalPressRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + public boolean shouldRenderOffScreen(MechanicalPressBlockEntity be) { + return true; + } + + @Override + protected void renderSafe(MechanicalPressBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) + return; + + BlockState blockState = be.getBlockState(); + PressingBehaviour pressingBehaviour = be.getPressingBehaviour(); + float renderedHeadOffset = + pressingBehaviour.getRenderedHeadOffset(partialTicks) * pressingBehaviour.mode.headOffset; + + SuperByteBuffer headRender = CachedPartialBuffers.partialFacing(AllPartialModels.MECHANICAL_PRESS_HEAD, blockState, + blockState.getValue(HORIZONTAL_FACING)); + headRender.translate(0, -renderedHeadOffset, 0) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + + @Override + protected BlockState getRenderedBlockState(MechanicalPressBlockEntity be) { + return shaft(getRotationAxisOf(be)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/press/PressInstance.java b/src/main/java/com/simibubi/create/content/kinetics/press/PressInstance.java new file mode 100644 index 0000000000..a7e655a450 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/press/PressInstance.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.kinetics.press; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.oriented.OrientedData; +import com.mojang.math.Quaternion; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; + +public class PressInstance extends ShaftInstance implements DynamicInstance { + + private final OrientedData pressHead; + + public PressInstance(MaterialManager materialManager, MechanicalPressBlockEntity blockEntity) { + super(materialManager, blockEntity); + + pressHead = materialManager.defaultSolid() + .material(Materials.ORIENTED) + .getModel(AllPartialModels.MECHANICAL_PRESS_HEAD, blockState) + .createInstance(); + + Quaternion q = Vector3f.YP + .rotationDegrees(AngleHelper.horizontalAngle(blockState.getValue(MechanicalPressBlock.HORIZONTAL_FACING))); + + pressHead.setRotation(q); + + transformModels(); + } + + @Override + public void beginFrame() { + transformModels(); + } + + private void transformModels() { + float renderedHeadOffset = getRenderedHeadOffset(blockEntity); + + pressHead.setPosition(getInstancePosition()) + .nudge(0, -renderedHeadOffset, 0); + } + + private float getRenderedHeadOffset(MechanicalPressBlockEntity press) { + PressingBehaviour pressingBehaviour = press.getPressingBehaviour(); + return pressingBehaviour.getRenderedHeadOffset(AnimationTickHolder.getPartialTicks()) + * pressingBehaviour.mode.headOffset; + } + + @Override + public void updateLight() { + super.updateLight(); + + relight(pos, pressHead); + } + + @Override + public void remove() { + super.remove(); + pressHead.delete(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/press/PressingBehaviour.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/press/PressingBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/press/PressingBehaviour.java index d95a2222e2..02bb5383af 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/press/PressingBehaviour.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.components.press; +package com.simibubi.create.content.kinetics.press; import java.util.ArrayList; import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; @@ -59,9 +59,9 @@ public class PressingBehaviour extends BeltProcessingBehaviour { public float getKineticSpeed(); } - public PressingBehaviour(T te) { - super(te); - this.specifics = te; + public PressingBehaviour(T be) { + super(be); + this.specifics = be; mode = Mode.WORLD; entityScanCooldown = ENTITY_SCAN; whenItemEnters((s, i) -> BeltPressingCallbacks.onItemReceived(s, i, this)); @@ -113,7 +113,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { prevRunningTicks = 0; runningTicks = 0; particleItems.clear(); - tileEntity.sendData(); + blockEntity.sendData(); } public boolean inWorld() { @@ -141,7 +141,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { if (entityScanCooldown <= 0) { entityScanCooldown = ENTITY_SCAN; - if (TileEntityBehaviour.get(level, worldPosition.below(2), + if (BlockEntityBehaviour.get(level, worldPosition.below(2), TransportedItemStackHandlerBehaviour.TYPE) != null) return; if (AllBlocks.BASIN.has(level.getBlockState(worldPosition.below(2)))) @@ -181,7 +181,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { .75f + (Math.abs(specifics.getKineticSpeed()) / 1024f)); if (!level.isClientSide) - tileEntity.sendData(); + blockEntity.sendData(); } if (!level.isClientSide && runningTicks > CYCLE) { @@ -189,7 +189,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { running = false; particleItems.clear(); specifics.onPressingCompleted(); - tileEntity.sendData(); + blockEntity.sendData(); return; } @@ -198,7 +198,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { if (prevRunningTicks < CYCLE / 2 && runningTicks >= CYCLE / 2) { runningTicks = CYCLE / 2; // Pause the ticks until a packet is received - if (level.isClientSide && !tileEntity.isVirtual()) + if (level.isClientSide && !blockEntity.isVirtual()) runningTicks = -(CYCLE / 2); } } @@ -209,7 +209,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { return; particleItems.clear(); if (specifics.tryProcessInBasin(false)) - tileEntity.sendData(); + blockEntity.sendData(); } protected void applyInWorld() { @@ -231,7 +231,7 @@ public class PressingBehaviour extends BeltProcessingBehaviour { entityScanCooldown = 0; if (specifics.tryProcessInWorld(itemEntity, false)) - tileEntity.sendData(); + blockEntity.sendData(); if (!bulk) break; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/press/PressingRecipe.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/press/PressingRecipe.java index d063ac1ee4..f5fb538614 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/PressingRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/press/PressingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.press; +package com.simibubi.create.content.kinetics.press; import java.util.List; import java.util.Set; @@ -9,9 +9,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.compat.jei.category.sequencedAssembly.SequencedAssemblySubCategory; -import com.simibubi.create.content.contraptions.itemAssembly.IAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.sequenced.IAssemblyRecipe; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/CuttingRecipe.java b/src/main/java/com/simibubi/create/content/kinetics/saw/CuttingRecipe.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/components/saw/CuttingRecipe.java rename to src/main/java/com/simibubi/create/content/kinetics/saw/CuttingRecipe.java index 85d9c23da5..5fdd8f3ccc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/CuttingRecipe.java +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/CuttingRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.saw; +package com.simibubi.create.content.kinetics.saw; import java.util.List; import java.util.Set; @@ -9,9 +9,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.compat.jei.category.sequencedAssembly.SequencedAssemblySubCategory; -import com.simibubi.create.content.contraptions.itemAssembly.IAssemblyRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.content.processing.sequenced.IAssemblyRecipe; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlock.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlock.java new file mode 100644 index 0000000000..5fe067003c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlock.java @@ -0,0 +1,259 @@ +package com.simibubi.create.content.kinetics.saw; + +import java.util.List; +import java.util.function.Predicate; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.kinetics.drill.DrillBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.placement.IPlacementHelper; +import net.createmod.catnip.utility.placement.PlacementHelpers; +import net.createmod.catnip.utility.placement.PlacementOffset; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class SawBlock extends DirectionalAxisKineticBlock implements IBE { + public static DamageSource damageSourceSaw = new DamageSource("create.mechanical_saw").bypassArmor(); + + public static final BooleanProperty FLIPPED = BooleanProperty.create("flipped"); + + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public SawBlock(Properties properties) { + super(properties); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(FLIPPED)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState stateForPlacement = super.getStateForPlacement(context); + Direction facing = stateForPlacement.getValue(FACING); + return stateForPlacement.setValue(FLIPPED, facing.getAxis() == Axis.Y && context.getHorizontalDirection() + .getAxisDirection() == AxisDirection.POSITIVE); + } + + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + BlockState newState = super.getRotatedBlockState(originalState, targetedFace); + if (newState.getValue(FACING) + .getAxis() != Axis.Y) + return newState; + if (targetedFace.getAxis() != Axis.Y) + return newState; + if (!originalState.getValue(AXIS_ALONG_FIRST_COORDINATE)) + newState = newState.cycle(FLIPPED); + return newState; + } + + @Override + public BlockState rotate(BlockState state, Rotation rot) { + BlockState newState = super.rotate(state, rot); + if (state.getValue(FACING) + .getAxis() != Axis.Y) + return newState; + + if (rot.ordinal() % 2 == 1 && (rot == Rotation.CLOCKWISE_90) != state.getValue(AXIS_ALONG_FIRST_COORDINATE)) + newState = newState.cycle(FLIPPED); + if (rot == Rotation.CLOCKWISE_180) + newState = newState.cycle(FLIPPED); + + return newState; + } + + @Override + public BlockState mirror(BlockState state, Mirror mirrorIn) { + BlockState newState = super.mirror(state, mirrorIn); + if (state.getValue(FACING) + .getAxis() != Axis.Y) + return newState; + + boolean alongX = state.getValue(AXIS_ALONG_FIRST_COORDINATE); + if (alongX && mirrorIn == Mirror.FRONT_BACK) + newState = newState.cycle(FLIPPED); + if (!alongX && mirrorIn == Mirror.LEFT_RIGHT) + newState = newState.cycle(FLIPPED); + + return newState; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.CASING_12PX.get(state.getValue(FACING)); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + ItemStack heldItem = player.getItemInHand(handIn); + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldItem) && placementHelper.getOffset(player, worldIn, state, pos, hit) + .placeInWorld(worldIn, (BlockItem) heldItem.getItem(), player, handIn, hit) + .consumesAction()) + return InteractionResult.SUCCESS; + } + + if (player.isSpectator() || !player.getItemInHand(handIn) + .isEmpty()) + return InteractionResult.PASS; + if (state.getOptionalValue(FACING) + .orElse(Direction.WEST) != Direction.UP) + return InteractionResult.PASS; + + return onBlockEntityUse(worldIn, pos, be -> { + for (int i = 0; i < be.inventory.getSlots(); i++) { + ItemStack heldItemStack = be.inventory.getStackInSlot(i); + if (!worldIn.isClientSide && !heldItemStack.isEmpty()) + player.getInventory() + .placeItemBackInInventory(heldItemStack); + } + be.inventory.clear(); + be.notifyUpdate(); + return InteractionResult.SUCCESS; + }); + } + + @Override + public void entityInside(BlockState state, Level worldIn, BlockPos pos, Entity entityIn) { + if (entityIn instanceof ItemEntity) + return; + if (!new AABB(pos).deflate(.1f) + .intersects(entityIn.getBoundingBox())) + return; + withBlockEntityDo(worldIn, pos, be -> { + if (be.getSpeed() == 0) + return; + entityIn.hurt(damageSourceSaw, (float) DrillBlock.getDamage(be.getSpeed())); + }); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + if (!(entityIn instanceof ItemEntity)) + return; + if (entityIn.level.isClientSide) + return; + + BlockPos pos = entityIn.blockPosition(); + withBlockEntityDo(entityIn.level, pos, be -> { + if (be.getSpeed() == 0) + return; + be.insertItem((ItemEntity) entityIn); + }); + } + + @Override + public PushReaction getPistonPushReaction(BlockState state) { + return PushReaction.NORMAL; + } + + public static boolean isHorizontal(BlockState state) { + return state.getValue(FACING) + .getAxis() + .isHorizontal(); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return isHorizontal(state) ? state.getValue(FACING) + .getAxis() : super.getRotationAxis(state); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return isHorizontal(state) ? face == state.getValue(FACING) + .getOpposite() : super.hasShaftTowards(world, pos, state, face); + } + + @Override + public Class getBlockEntityClass() { + return SawBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SAW.get(); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @MethodsReturnNonnullByDefault + private static class PlacementHelper implements IPlacementHelper { + + @Override + public Predicate getItemPredicate() { + return AllBlocks.MECHANICAL_SAW::isIn; + } + + @Override + public Predicate getStatePredicate() { + return state -> AllBlocks.MECHANICAL_SAW.has(state); + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, + BlockHitResult ray) { + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(), + state.getValue(FACING) + .getAxis(), + dir -> world.getBlockState(pos.relative(dir)) + .getMaterial() + .isReplaceable()); + + if (directions.isEmpty()) + return PlacementOffset.fail(); + else { + return PlacementOffset.success(pos.relative(directions.get(0)), + s -> s.setValue(FACING, state.getValue(FACING)) + .setValue(AXIS_ALONG_FIRST_COORDINATE, state.getValue(AXIS_ALONG_FIRST_COORDINATE)) + .setValue(FLIPPED, state.getValue(FLIPPED))); + } + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlockEntity.java new file mode 100644 index 0000000000..b241061351 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawBlockEntity.java @@ -0,0 +1,508 @@ +package com.simibubi.create.content.kinetics.saw; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Random; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllRecipeTypes; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.base.BlockBreakingKineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.processing.recipe.ProcessingInventory; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.recipe.RecipeConditions; +import com.simibubi.create.foundation.recipe.RecipeFinder; +import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue; +import com.simibubi.create.foundation.utility.TreeCutter; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.StonecutterRecipe; +import net.minecraft.world.level.block.BambooBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CactusBlock; +import net.minecraft.world.level.block.ChorusPlantBlock; +import net.minecraft.world.level.block.KelpBlock; +import net.minecraft.world.level.block.KelpPlantBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.StemGrownBlock; +import net.minecraft.world.level.block.SugarCaneBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class SawBlockEntity extends BlockBreakingKineticBlockEntity { + + private static final Object cuttingRecipesKey = new Object(); + public static final Supplier> woodcuttingRecipeType = + Suppliers.memoize(() -> Registry.RECIPE_TYPE.get(new ResourceLocation("druidcraft", "woodcutting"))); + + public ProcessingInventory inventory; + private int recipeIndex; + private final LazyOptional invProvider; + private FilteringBehaviour filtering; + + private ItemStack playEvent; + + public SawBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inventory = new ProcessingInventory(this::start).withSlotLimit(!AllConfigs.server().recipes.bulkCutting.get()); + inventory.remainingTime = -1; + recipeIndex = 0; + invProvider = LazyOptional.of(() -> inventory); + playEvent = ItemStack.EMPTY; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + filtering = new FilteringBehaviour(this, new SawFilterSlot()).forRecipes(); + behaviours.add(filtering); + behaviours.add(new DirectBeltInputBehaviour(this).allowingBeltFunnelsWhen(this::canProcess)); + registerAwardables(behaviours, AllAdvancements.SAW_PROCESSING); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.put("Inventory", inventory.serializeNBT()); + compound.putInt("RecipeIndex", recipeIndex); + super.write(compound, clientPacket); + + if (!clientPacket || playEvent.isEmpty()) + return; + compound.put("PlayEvent", playEvent.serializeNBT()); + playEvent = ItemStack.EMPTY; + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + inventory.deserializeNBT(compound.getCompound("Inventory")); + recipeIndex = compound.getInt("RecipeIndex"); + if (compound.contains("PlayEvent")) + playEvent = ItemStack.of(compound.getCompound("PlayEvent")); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).inflate(.125f); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void tickAudio() { + super.tickAudio(); + if (getSpeed() == 0) + return; + + if (!playEvent.isEmpty()) { + boolean isWood = false; + Item item = playEvent.getItem(); + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + isWood = block.getSoundType(block.defaultBlockState(), level, worldPosition, null) == SoundType.WOOD; + } + spawnEventParticles(playEvent); + playEvent = ItemStack.EMPTY; + if (!isWood) + AllSoundEvents.SAW_ACTIVATE_STONE.playAt(level, worldPosition, 3, 1, true); + else + AllSoundEvents.SAW_ACTIVATE_WOOD.playAt(level, worldPosition, 3, 1, true); + return; + } + } + + @Override + public void tick() { + if (shouldRun() && ticksUntilNextProgress < 0) + destroyNextTick(); + super.tick(); + + if (!canProcess()) + return; + if (getSpeed() == 0) + return; + if (inventory.remainingTime == -1) { + if (!inventory.isEmpty() && !inventory.appliedRecipe) + start(inventory.getStackInSlot(0)); + return; + } + + float processingSpeed = Mth.clamp(Math.abs(getSpeed()) / 24, 1, 128); + inventory.remainingTime -= processingSpeed; + + if (inventory.remainingTime > 0) + spawnParticles(inventory.getStackInSlot(0)); + + if (inventory.remainingTime < 5 && !inventory.appliedRecipe) { + if (level.isClientSide && !isVirtual()) + return; + playEvent = inventory.getStackInSlot(0); + applyRecipe(); + inventory.appliedRecipe = true; + inventory.recipeDuration = 20; + inventory.remainingTime = 20; + sendData(); + return; + } + + Vec3 itemMovement = getItemMovementVec(); + Direction itemMovementFacing = Direction.getNearest(itemMovement.x, itemMovement.y, itemMovement.z); + if (inventory.remainingTime > 0) + return; + inventory.remainingTime = 0; + + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stack = inventory.getStackInSlot(slot); + if (stack.isEmpty()) + continue; + ItemStack tryExportingToBeltFunnel = getBehaviour(DirectBeltInputBehaviour.TYPE) + .tryExportingToBeltFunnel(stack, itemMovementFacing.getOpposite(), false); + if (tryExportingToBeltFunnel != null) { + if (tryExportingToBeltFunnel.getCount() != stack.getCount()) { + inventory.setStackInSlot(slot, tryExportingToBeltFunnel); + notifyUpdate(); + return; + } + if (!tryExportingToBeltFunnel.isEmpty()) + return; + } + } + + BlockPos nextPos = worldPosition.offset(itemMovement.x, itemMovement.y, itemMovement.z); + DirectBeltInputBehaviour behaviour = BlockEntityBehaviour.get(level, nextPos, DirectBeltInputBehaviour.TYPE); + if (behaviour != null) { + boolean changed = false; + if (!behaviour.canInsertFromSide(itemMovementFacing)) + return; + if (level.isClientSide && !isVirtual()) + return; + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stack = inventory.getStackInSlot(slot); + if (stack.isEmpty()) + continue; + ItemStack remainder = behaviour.handleInsertion(stack, itemMovementFacing, false); + if (remainder.equals(stack, false)) + continue; + inventory.setStackInSlot(slot, remainder); + changed = true; + } + if (changed) { + setChanged(); + sendData(); + } + return; + } + + // Eject Items + Vec3 outPos = VecHelper.getCenterOf(worldPosition) + .add(itemMovement.scale(.5f) + .add(0, .5, 0)); + Vec3 outMotion = itemMovement.scale(.0625) + .add(0, .125, 0); + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stack = inventory.getStackInSlot(slot); + if (stack.isEmpty()) + continue; + ItemEntity entityIn = new ItemEntity(level, outPos.x, outPos.y, outPos.z, stack); + entityIn.setDeltaMovement(outMotion); + level.addFreshEntity(entityIn); + } + inventory.clear(); + level.updateNeighbourForOutputSignal(worldPosition, getBlockState().getBlock()); + inventory.remainingTime = -1; + sendData(); + } + + @Override + public void invalidate() { + super.invalidate(); + invProvider.invalidate(); + } + + @Override + public void destroy() { + super.destroy(); + ItemHelper.dropContents(level, worldPosition, inventory); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && side != Direction.DOWN) + return invProvider.cast(); + return super.getCapability(cap, side); + } + + protected void spawnEventParticles(ItemStack stack) { + if (stack == null || stack.isEmpty()) + return; + + ParticleOptions particleData = null; + if (stack.getItem() instanceof BlockItem) + particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() + .defaultBlockState()); + else + particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); + + Random r = level.random; + Vec3 v = VecHelper.getCenterOf(this.worldPosition) + .add(0, 5 / 16f, 0); + for (int i = 0; i < 10; i++) { + Vec3 m = VecHelper.offsetRandomly(new Vec3(0, 0.25f, 0), r, .125f); + level.addParticle(particleData, v.x, v.y, v.z, m.x, m.y, m.y); + } + } + + protected void spawnParticles(ItemStack stack) { + if (stack == null || stack.isEmpty()) + return; + + ParticleOptions particleData = null; + float speed = 1; + if (stack.getItem() instanceof BlockItem) + particleData = new BlockParticleOption(ParticleTypes.BLOCK, ((BlockItem) stack.getItem()).getBlock() + .defaultBlockState()); + else { + particleData = new ItemParticleOption(ParticleTypes.ITEM, stack); + speed = .125f; + } + + Random r = level.random; + Vec3 vec = getItemMovementVec(); + Vec3 pos = VecHelper.getCenterOf(this.worldPosition); + float offset = inventory.recipeDuration != 0 ? (float) (inventory.remainingTime) / inventory.recipeDuration : 0; + offset /= 2; + if (inventory.appliedRecipe) + offset -= .5f; + level.addParticle(particleData, pos.x() + -vec.x * offset, pos.y() + .45f, pos.z() + -vec.z * offset, + -vec.x * speed, r.nextFloat() * speed, -vec.z * speed); + } + + public Vec3 getItemMovementVec() { + boolean alongX = !getBlockState().getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE); + int offset = getSpeed() < 0 ? -1 : 1; + return new Vec3(offset * (alongX ? 1 : 0), 0, offset * (alongX ? 0 : -1)); + } + + private void applyRecipe() { + List> recipes = getRecipes(); + if (recipes.isEmpty()) + return; + if (recipeIndex >= recipes.size()) + recipeIndex = 0; + + Recipe recipe = recipes.get(recipeIndex); + + int rolls = inventory.getStackInSlot(0) + .getCount(); + inventory.clear(); + + List list = new ArrayList<>(); + for (int roll = 0; roll < rolls; roll++) { + List results = new LinkedList(); + if (recipe instanceof CuttingRecipe) + results = ((CuttingRecipe) recipe).rollResults(); + else if (recipe instanceof StonecutterRecipe || recipe.getType() == woodcuttingRecipeType.get()) + results.add(recipe.getResultItem() + .copy()); + + for (int i = 0; i < results.size(); i++) { + ItemStack stack = results.get(i); + ItemHelper.addToList(stack, list); + } + } + + for (int slot = 0; slot < list.size() && slot + 1 < inventory.getSlots(); slot++) + inventory.setStackInSlot(slot + 1, list.get(slot)); + + award(AllAdvancements.SAW_PROCESSING); + } + + private List> getRecipes() { + Optional assemblyRecipe = SequencedAssemblyRecipe.getRecipe(level, inventory.getStackInSlot(0), + AllRecipeTypes.CUTTING.getType(), CuttingRecipe.class); + if (assemblyRecipe.isPresent() && filtering.test(assemblyRecipe.get() + .getResultItem())) + return ImmutableList.of(assemblyRecipe.get()); + + Predicate> types = RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType(), + AllConfigs.server().recipes.allowStonecuttingOnSaw.get() ? RecipeType.STONECUTTING : null, + AllConfigs.server().recipes.allowWoodcuttingOnSaw.get() ? woodcuttingRecipeType.get() : null); + + List> startedSearch = RecipeFinder.get(cuttingRecipesKey, level, types); + return startedSearch.stream() + .filter(RecipeConditions.outputMatchesFilter(filtering)) + .filter(RecipeConditions.firstIngredientMatches(inventory.getStackInSlot(0))) + .filter(r -> !AllRecipeTypes.shouldIgnoreInAutomation(r)) + .collect(Collectors.toList()); + } + + public void insertItem(ItemEntity entity) { + if (!canProcess()) + return; + if (!inventory.isEmpty()) + return; + if (!entity.isAlive()) + return; + if (level.isClientSide) + return; + + inventory.clear(); + ItemStack remainder = inventory.insertItem(0, entity.getItem() + .copy(), false); + if (remainder.isEmpty()) + entity.discard(); + else + entity.setItem(remainder); + } + + public void start(ItemStack inserted) { + if (!canProcess()) + return; + if (inventory.isEmpty()) + return; + if (level.isClientSide && !isVirtual()) + return; + + List> recipes = getRecipes(); + boolean valid = !recipes.isEmpty(); + int time = 50; + + if (recipes.isEmpty()) { + inventory.remainingTime = inventory.recipeDuration = 10; + inventory.appliedRecipe = false; + sendData(); + return; + } + + if (valid) { + recipeIndex++; + if (recipeIndex >= recipes.size()) + recipeIndex = 0; + } + + Recipe recipe = recipes.get(recipeIndex); + if (recipe instanceof CuttingRecipe) { + time = ((CuttingRecipe) recipe).getProcessingDuration(); + } + + inventory.remainingTime = time * Math.max(1, (inserted.getCount() / 5)); + inventory.recipeDuration = inventory.remainingTime; + inventory.appliedRecipe = false; + sendData(); + } + + protected boolean canProcess() { + return getBlockState().getValue(SawBlock.FACING) == Direction.UP; + } + + // Block Breaker + + @Override + protected boolean shouldRun() { + return getBlockState().getValue(SawBlock.FACING) + .getAxis() + .isHorizontal(); + } + + @Override + protected BlockPos getBreakingPos() { + return getBlockPos().relative(getBlockState().getValue(SawBlock.FACING)); + } + + @Override + public void onBlockBroken(BlockState stateToBreak) { + Optional dynamicTree = + TreeCutter.findDynamicTree(stateToBreak.getBlock(), breakingPos); + if (dynamicTree.isPresent()) { + dynamicTree.get() + .destroyBlocks(level, null, this::dropItemFromCutTree); + return; + } + + super.onBlockBroken(stateToBreak); + TreeCutter.findTree(level, breakingPos) + .destroyBlocks(level, null, this::dropItemFromCutTree); + } + + public void dropItemFromCutTree(BlockPos pos, ItemStack stack) { + float distance = (float) Math.sqrt(pos.distSqr(breakingPos)); + Vec3 dropPos = VecHelper.getCenterOf(pos); + ItemEntity entity = new ItemEntity(level, dropPos.x, dropPos.y, dropPos.z, stack); + entity.setDeltaMovement(Vec3.atLowerCornerOf(breakingPos.subtract(this.worldPosition)) + .scale(distance / 20f)); + level.addFreshEntity(entity); + } + + @Override + public boolean canBreak(BlockState stateToBreak, float blockHardness) { + boolean sawable = isSawable(stateToBreak); + return super.canBreak(stateToBreak, blockHardness) && sawable; + } + + public static boolean isSawable(BlockState stateToBreak) { + if (stateToBreak.is(BlockTags.SAPLINGS)) + return false; + if (TreeCutter.isLog(stateToBreak) || (stateToBreak.is(BlockTags.LEAVES))) + return true; + Block block = stateToBreak.getBlock(); + if (block instanceof BambooBlock) + return true; + if (block instanceof StemGrownBlock) + return true; + if (block instanceof CactusBlock) + return true; + if (block instanceof SugarCaneBlock) + return true; + if (block instanceof KelpPlantBlock) + return true; + if (block instanceof KelpBlock) + return true; + if (block instanceof ChorusPlantBlock) + return true; + if (TreeCutter.canDynamicTreeCutFrom(block)) + return true; + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/saw/SawFilterSlot.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawFilterSlot.java new file mode 100644 index 0000000000..3e3cfdd473 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawFilterSlot.java @@ -0,0 +1,33 @@ +package com.simibubi.create.content.kinetics.saw; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class SawFilterSlot extends ValueBoxTransform { + + @Override + public Vec3 getLocalOffset(BlockState state) { + if (state.getValue(SawBlock.FACING) != Direction.UP) + return null; + int offset = state.getValue(SawBlock.FLIPPED) ? -3 : 3; + Vec3 x = VecHelper.voxelSpace(8, 12.5f, 8 + offset); + Vec3 z = VecHelper.voxelSpace(8 + offset, 12.5f, 8); + return state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? z : x; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + int yRot = (state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? 90 : 0) + + (state.getValue(SawBlock.FLIPPED) ? 0 : 180); + TransformStack.cast(ms) + .rotateY(yRot) + .rotateX(90); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawGenerator.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/saw/SawGenerator.java rename to src/main/java/com/simibubi/create/content/kinetics/saw/SawGenerator.java index 20e459310b..90e90dfb19 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawGenerator.java +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.saw; +package com.simibubi.create.content.kinetics.saw; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; @@ -22,7 +22,7 @@ public class SawGenerator extends SpecialBlockStateGen { boolean axisAlongFirst = state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE); if (facing.getAxis() .isVertical()) - return axisAlongFirst ? 90 : 0; + return (axisAlongFirst ? 270 : 0) + (state.getValue(SawBlock.FLIPPED) ? 180 : 0); return horizontalAngle(facing); } diff --git a/src/main/java/com/simibubi/create/content/kinetics/saw/SawInstance.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawInstance.java new file mode 100644 index 0000000000..9f0662d192 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawInstance.java @@ -0,0 +1,32 @@ +package com.simibubi.create.content.kinetics.saw; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class SawInstance extends SingleRotatingInstance { + + public SawInstance(MaterialManager materialManager, SawBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + protected Instancer getModel() { + if (blockState.getValue(BlockStateProperties.FACING) + .getAxis() + .isHorizontal()) { + BlockState referenceState = blockState.rotate(blockEntity.getLevel(), blockEntity.getBlockPos(), Rotation.CLOCKWISE_180); + Direction facing = referenceState.getValue(BlockStateProperties.FACING); + return getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, referenceState, facing); + } else { + return getRotatingMaterial().getModel(shaft()); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawMovementBehaviour.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/saw/SawMovementBehaviour.java index 3bf582af12..59396b21f8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawMovementBehaviour.java @@ -1,13 +1,11 @@ -package com.simibubi.create.content.contraptions.components.actors; +package com.simibubi.create.content.kinetics.saw; import java.util.Optional; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.saw.SawBlock; -import com.simibubi.create.content.contraptions.components.saw.SawRenderer; -import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue; import com.simibubi.create.foundation.utility.TreeCutter; @@ -30,8 +28,9 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean isActive(MovementContext context) { - return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(SawBlock.FACING) - .getOpposite()); + return super.isActive(context) + && !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(SawBlock.FACING) + .getOpposite()); } @Override @@ -58,7 +57,7 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) { - return super.canBreak(world, breakingPos, state) && SawTileEntity.isSawable(state); + return super.canBreak(world, breakingPos, state) && SawBlockEntity.isSawable(state); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/saw/SawRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/saw/SawRenderer.java new file mode 100644 index 0000000000..b7e20ec575 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/saw/SawRenderer.java @@ -0,0 +1,206 @@ +package com.simibubi.create.content.kinetics.saw; + +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class SawRenderer extends SafeBlockEntityRenderer { + + public SawRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(SawBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + renderBlade(be, ms, buffer, light); + renderItems(be, partialTicks, ms, buffer, light, overlay); + FilteringRenderer.renderOnBlockEntity(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) + return; + + renderShaft(be, ms, buffer, light, overlay); + } + + protected void renderBlade(SawBlockEntity be, PoseStack ms, MultiBufferSource buffer, int light) { + BlockState blockState = be.getBlockState(); + PartialModel partial; + float speed = be.getSpeed(); + boolean rotate = false; + + if (SawBlock.isHorizontal(blockState)) { + if (speed > 0) { + partial = AllPartialModels.SAW_BLADE_HORIZONTAL_ACTIVE; + } else if (speed < 0) { + partial = AllPartialModels.SAW_BLADE_HORIZONTAL_REVERSED; + } else { + partial = AllPartialModels.SAW_BLADE_HORIZONTAL_INACTIVE; + } + } else { + if (be.getSpeed() > 0) { + partial = AllPartialModels.SAW_BLADE_VERTICAL_ACTIVE; + } else if (speed < 0) { + partial = AllPartialModels.SAW_BLADE_VERTICAL_REVERSED; + } else { + partial = AllPartialModels.SAW_BLADE_VERTICAL_INACTIVE; + } + + if (blockState.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE)) + rotate = true; + } + + SuperByteBuffer superBuffer = CachedPartialBuffers.partialFacing(partial, blockState); + if (rotate) { + superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(90)); + } + superBuffer.color(0xFFFFFF) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + } + + protected void renderShaft(SawBlockEntity be, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + KineticBlockEntityRenderer.renderRotatingBuffer(be, getRotatedModel(be), ms, + buffer.getBuffer(RenderType.solid()), light); + } + + protected void renderItems(SawBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + boolean processingMode = be.getBlockState() + .getValue(SawBlock.FACING) == Direction.UP; + if (processingMode && !be.inventory.isEmpty()) { + boolean alongZ = !be.getBlockState() + .getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE); + ms.pushPose(); + + boolean moving = be.inventory.recipeDuration != 0; + float offset = moving ? (float) (be.inventory.remainingTime) / be.inventory.recipeDuration : 0; + float processingSpeed = Mth.clamp(Math.abs(be.getSpeed()) / 32, 1, 128); + if (moving) { + offset = Mth + .clamp(offset + ((-partialTicks + .5f) * processingSpeed) / be.inventory.recipeDuration, 0.125f, 1f); + if (!be.inventory.appliedRecipe) + offset += 1; + offset /= 2; + } + + if (be.getSpeed() == 0) + offset = .5f; + if (be.getSpeed() < 0 ^ alongZ) + offset = 1 - offset; + + for (int i = 0; i < be.inventory.getSlots(); i++) { + ItemStack stack = be.inventory.getStackInSlot(i); + if (stack.isEmpty()) + continue; + + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + BakedModel modelWithOverrides = itemRenderer.getModel(stack, be.getLevel(), null, 0); + boolean blockItem = modelWithOverrides.isGui3d(); + + ms.translate(alongZ ? offset : .5, blockItem ? .925f : 13f / 16f, alongZ ? .5 : offset); + + ms.scale(.5f, .5f, .5f); + if (alongZ) + ms.mulPose(Vector3f.YP.rotationDegrees(90)); + ms.mulPose(Vector3f.XP.rotationDegrees(90)); + itemRenderer.renderStatic(stack, ItemTransforms.TransformType.FIXED, light, overlay, ms, buffer, 0); + break; + } + + ms.popPose(); + } + } + + protected SuperByteBuffer getRotatedModel(KineticBlockEntity be) { + BlockState state = be.getBlockState(); + if (state.getValue(FACING) + .getAxis() + .isHorizontal()) + return CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, + state.rotate(be.getLevel(), be.getBlockPos(), Rotation.CLOCKWISE_180)); + return CachedBlockBuffers.block(KineticBlockEntityRenderer.KINETIC_BLOCK, + getRenderedBlockState(be)); + } + + protected BlockState getRenderedBlockState(KineticBlockEntity be) { + return KineticBlockEntityRenderer.shaft(KineticBlockEntityRenderer.getRotationAxisOf(be)); + } + + public static void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, + ContraptionMatrices matrices, MultiBufferSource buffer) { + BlockState state = context.state; + Direction facing = state.getValue(SawBlock.FACING); + + Vec3 facingVec = Vec3.atLowerCornerOf(context.state.getValue(SawBlock.FACING) + .getNormal()); + facingVec = context.rotation.apply(facingVec); + + Direction closestToFacing = Direction.getNearest(facingVec.x, facingVec.y, facingVec.z); + + boolean horizontal = closestToFacing.getAxis() + .isHorizontal(); + boolean backwards = VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()); + boolean moving = context.getAnimationSpeed() != 0; + boolean shouldAnimate = + (context.contraption.stalled && horizontal) || (!context.contraption.stalled && !backwards && moving); + + SuperByteBuffer superBuffer; + if (SawBlock.isHorizontal(state)) { + if (shouldAnimate) + superBuffer = CachedPartialBuffers.partial(AllPartialModels.SAW_BLADE_HORIZONTAL_ACTIVE, state); + else + superBuffer = CachedPartialBuffers.partial(AllPartialModels.SAW_BLADE_HORIZONTAL_INACTIVE, state); + } else { + if (shouldAnimate) + superBuffer = CachedPartialBuffers.partial(AllPartialModels.SAW_BLADE_VERTICAL_ACTIVE, state); + else + superBuffer = CachedPartialBuffers.partial(AllPartialModels.SAW_BLADE_VERTICAL_INACTIVE, state); + } + + superBuffer.transform(matrices.getModel()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing)); + + if (!SawBlock.isHorizontal(state)) { + superBuffer.rotateZ(state.getValue(SawBlock.AXIS_ALONG_FIRST_COORDINATE) ? 90 : 0); + } + + superBuffer.unCentre() + .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) + .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.cutoutMipped())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractShaftBlock.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractShaftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractShaftBlock.java index a24d12d78c..cca9ba71cb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/AbstractShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractShaftBlock.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.relays.elementary; +package com.simibubi.create.content.kinetics.simpleRelays; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.minecraft.core.BlockPos; @@ -20,7 +20,7 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.pathfinder.PathComputationType; public abstract class AbstractShaftBlock extends RotatedPillarKineticBlock - implements ITE, ProperWaterloggedBlock { + implements IBE, ProperWaterloggedBlock { public AbstractShaftBlock(Properties properties) { super(properties); @@ -33,8 +33,8 @@ public abstract class AbstractShaftBlock extends RotatedPillarKineticBlock } @Override - public Class getTileEntityClass() { - return KineticTileEntity.class; + public Class getBlockEntityClass() { + return KineticBlockEntity.class; } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractSimpleShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractSimpleShaftBlock.java new file mode 100644 index 0000000000..d4ad89d447 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/AbstractSimpleShaftBlock.java @@ -0,0 +1,61 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import java.util.Optional; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.content.equipment.wrench.IWrenchableWithBracket; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; + +public abstract class AbstractSimpleShaftBlock extends AbstractShaftBlock implements IWrenchableWithBracket { + + public AbstractSimpleShaftBlock(Properties properties) { + super(properties); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return IWrenchableWithBracket.super.onWrenched(state, context); + } + + @Override + public PushReaction getPistonPushReaction(BlockState state) { + return PushReaction.NORMAL; + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + if (state != newState && !isMoving) + removeBracket(world, pos, true).ifPresent(stack -> Block.popResource(world, pos, stack)); + super.onRemove(state, world, pos, newState, isMoving); + } + + @Override + public Optional removeBracket(BlockGetter world, BlockPos pos, boolean inOnReplacedContext) { + BracketedBlockEntityBehaviour behaviour = BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); + if (behaviour == null) + return Optional.empty(); + BlockState bracket = behaviour.removeBracket(inOnReplacedContext); + if (bracket == null) + return Optional.empty(); + return Optional.of(new ItemStack(bracket.getBlock())); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BRACKETED_KINETIC.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntity.java new file mode 100644 index 0000000000..ad1191d6d6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntity.java @@ -0,0 +1,35 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import java.util.List; + +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class BracketedKineticBlockEntity extends SimpleKineticBlockEntity implements ITransformableBlockEntity { + + public BracketedKineticBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours + .add(new BracketedBlockEntityBehaviour(this, state -> state.getBlock() instanceof AbstractSimpleShaftBlock)); + super.addBehaviours(behaviours); + } + + @Override + public void transform(StructureTransform transform) { + BracketedBlockEntityBehaviour bracketBehaviour = getBehaviour(BracketedBlockEntityBehaviour.TYPE); + if (bracketBehaviour != null) { + bracketBehaviour.transformBracket(transform); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityInstance.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityInstance.java new file mode 100644 index 0000000000..1a7da7d639 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityInstance.java @@ -0,0 +1,92 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.base.SingleRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; + +public class BracketedKineticBlockEntityInstance extends SingleRotatingInstance { + + protected RotatingData additionalShaft; + + public BracketedKineticBlockEntityInstance(MaterialManager materialManager, BracketedKineticBlockEntity blockEntity) { + super(materialManager, blockEntity); + } + + @Override + public void init() { + super.init(); + if (!ICogWheel.isLargeCog(blockEntity.getBlockState())) + return; + + // Large cogs sometimes have to offset their teeth by 11.25 degrees in order to + // mesh properly + + float speed = blockEntity.getSpeed(); + Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity); + BlockPos pos = blockEntity.getBlockPos(); + float offset = BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos); + Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); + Instancer half = getRotatingMaterial().getModel(AllPartialModels.COGWHEEL_SHAFT, blockState, + facing, () -> this.rotateToAxis(axis)); + + additionalShaft = setup(half.createInstance(), speed); + additionalShaft.setRotationOffset(offset); + } + + @Override + protected Instancer getModel() { + if (!ICogWheel.isLargeCog(blockEntity.getBlockState())) + return super.getModel(); + + Axis axis = KineticBlockEntityRenderer.getRotationAxisOf(blockEntity); + Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); + return getRotatingMaterial().getModel(AllPartialModels.SHAFTLESS_LARGE_COGWHEEL, blockState, facing, + () -> this.rotateToAxis(axis)); + } + + private PoseStack rotateToAxis(Axis axis) { + Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); + PoseStack poseStack = new PoseStack(); + TransformStack.cast(poseStack) + .centre() + .rotateToFace(facing) + .multiply(Vector3f.XN.rotationDegrees(-90)) + .unCentre(); + return poseStack; + } + + @Override + public void update() { + super.update(); + if (additionalShaft != null) { + updateRotation(additionalShaft); + additionalShaft.setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos)); + } + } + + @Override + public void updateLight() { + super.updateLight(); + if (additionalShaft != null) + relight(pos, additionalShaft); + } + + @Override + public void remove() { + super.remove(); + if (additionalShaft != null) + additionalShaft.delete(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityRenderer.java new file mode 100644 index 0000000000..25f2dcce20 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockEntityRenderer.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; + +public class BracketedKineticBlockEntityRenderer extends KineticBlockEntityRenderer { + + public BracketedKineticBlockEntityRenderer(Context context) { + super(context); + } + + @Override + protected void renderSafe(BracketedKineticBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) + return; + + if (!AllBlocks.LARGE_COGWHEEL.has(be.getBlockState())) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + return; + } + + // Large cogs sometimes have to offset their teeth by 11.25 degrees in order to + // mesh properly + + Axis axis = getRotationAxisOf(be); + Direction facing = Direction.fromAxisAndDirection(axis, AxisDirection.POSITIVE); + renderRotatingBuffer(be, + CachedPartialBuffers.partialFacingVertical(AllPartialModels.SHAFTLESS_LARGE_COGWHEEL, be.getBlockState(), facing), + ms, buffer.getBuffer(RenderType.solid()), light); + + float angle = getAngleForLargeCogShaft(be, axis); + SuperByteBuffer shaft = + CachedPartialBuffers.partialFacingVertical(AllPartialModels.COGWHEEL_SHAFT, be.getBlockState(), facing); + kineticRotationTransform(shaft, be, axis, angle, light); + shaft.renderInto(ms, buffer.getBuffer(RenderType.solid())); + + } + + public static float getAngleForLargeCogShaft(SimpleKineticBlockEntity be, Axis axis) { + BlockPos pos = be.getBlockPos(); + float offset = getShaftAngleOffset(axis, pos); + float time = WorldTickHolder.getRenderTime(be.getLevel()); + float angle = ((time * be.getSpeed() * 3f / 10 + offset) % 360) / 180 * (float) Math.PI; + return angle; + } + + public static float getShaftAngleOffset(Axis axis, BlockPos pos) { + float offset = 0; + double d = (((axis == Axis.X) ? 0 : pos.getX()) + ((axis == Axis.Y) ? 0 : pos.getY()) + + ((axis == Axis.Z) ? 0 : pos.getZ())) % 2; + if (d == 0) + offset = 22.5f; + return offset; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockModel.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockModel.java new file mode 100644 index 0000000000..db07f582bb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/BracketedKineticBlockModel.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; +import com.simibubi.create.content.decoration.bracket.BracketedBlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap; +import net.minecraftforge.client.model.data.ModelProperty; + +public class BracketedKineticBlockModel extends BakedModelWrapper { + + private static final ModelProperty BRACKET_PROPERTY = new ModelProperty<>(); + + public BracketedKineticBlockModel(BakedModel template) { + super(template); + } + + @Override + public IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state, IModelData blockEntityData) { + if (VirtualEmptyModelData.is(blockEntityData)) + return blockEntityData; + BracketedModelData data = new BracketedModelData(); + BracketedBlockEntityBehaviour attachmentBehaviour = + BlockEntityBehaviour.get(world, pos, BracketedBlockEntityBehaviour.TYPE); + if (attachmentBehaviour != null) + data.putBracket(attachmentBehaviour.getBracket()); + return new ModelDataMap.Builder().withInitial(BRACKET_PROPERTY, data) + .build(); + } + + @Override + public List getQuads(BlockState state, Direction side, Random rand, IModelData data) { + if (!VirtualEmptyModelData.is(data)) { + if (data.hasProperty(BRACKET_PROPERTY)) { + BracketedModelData pipeData = data.getData(BRACKET_PROPERTY); + BakedModel bracket = pipeData.getBracket(); + if (bracket != null) + return bracket.getQuads(state, side, rand, data); + } + return Collections.emptyList(); + } + return super.getQuads(state, side, rand, data); + } + + private static class BracketedModelData { + private BakedModel bracket; + + public void putBracket(BlockState state) { + if (state != null) { + this.bracket = Minecraft.getInstance() + .getBlockRenderer() + .getBlockModel(state); + } + } + + public BakedModel getBracket() { + return bracket; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogWheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogWheelBlock.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogWheelBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogWheelBlock.java index 1d6ad96e4f..5fd901e1e9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogWheelBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogWheelBlock.java @@ -1,13 +1,14 @@ -package com.simibubi.create.content.contraptions.relays.elementary; +package com.simibubi.create.content.kinetics.simpleRelays; import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllCreativeModeTabs; +import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogwheelBlock; +import com.simibubi.create.content.decoration.encasing.EncasableBlock; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlock; import com.simibubi.create.foundation.advancement.AllAdvancements; import net.createmod.catnip.utility.Iterate; @@ -16,10 +17,12 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.NonNullList; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; @@ -35,7 +38,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class CogWheelBlock extends AbstractSimpleShaftBlock implements ICogWheel { +public class CogWheelBlock extends AbstractSimpleShaftBlock implements ICogWheel, EncasableBlock { boolean isLarge; @@ -62,6 +65,14 @@ public class CogWheelBlock extends AbstractSimpleShaftBlock implements ICogWheel return !isLarge; } + @Override + public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) { + super.fillItemCategory(pTab, pItems); + // Ensure the belt item is added after large cogwheels in the creative tab + if (AllBlocks.LARGE_COGWHEEL.is(this) && pTab == AllCreativeModeTabs.BASE_CREATIVE_TAB) + pItems.add(AllItems.BELT_CONNECTOR.asStack()); + } + @Override public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { return (isLarge ? AllShapes.LARGE_GEAR : AllShapes.SMALL_GEAR).get(state.getValue(AXIS)); @@ -122,38 +133,9 @@ public class CogWheelBlock extends AbstractSimpleShaftBlock implements ICogWheel return InteractionResult.PASS; ItemStack heldItem = player.getItemInHand(hand); - EncasedCogwheelBlock[] encasedBlocks = isLarge - ? new EncasedCogwheelBlock[] { AllBlocks.ANDESITE_ENCASED_LARGE_COGWHEEL.get(), - AllBlocks.BRASS_ENCASED_LARGE_COGWHEEL.get() } - : new EncasedCogwheelBlock[] { AllBlocks.ANDESITE_ENCASED_COGWHEEL.get(), - AllBlocks.BRASS_ENCASED_COGWHEEL.get() }; - - for (EncasedCogwheelBlock encasedCog : encasedBlocks) { - if (!encasedCog.getCasing() - .isIn(heldItem)) - continue; - - if (world.isClientSide) - return InteractionResult.SUCCESS; - - BlockState encasedState = encasedCog.defaultBlockState() - .setValue(AXIS, state.getValue(AXIS)); - - for (Direction d : Iterate.directionsInAxis(state.getValue(AXIS))) { - BlockState adjacentState = world.getBlockState(pos.relative(d)); - if (!(adjacentState.getBlock() instanceof IRotate)) - continue; - IRotate def = (IRotate) adjacentState.getBlock(); - if (!def.hasShaftTowards(world, pos.relative(d), adjacentState, d.getOpposite())) - continue; - encasedState = - encasedState.cycle(d.getAxisDirection() == AxisDirection.POSITIVE ? EncasedCogwheelBlock.TOP_SHAFT - : EncasedCogwheelBlock.BOTTOM_SHAFT); - } - - KineticTileEntity.switchToBlockState(world, pos, encasedState); - return InteractionResult.SUCCESS; - } + InteractionResult result = tryEncase(state, world, pos, heldItem, player, hand, ray); + if (result.consumesAction()) + return result; return InteractionResult.PASS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogwheelBlockItem.java similarity index 95% rename from src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogwheelBlockItem.java index 92a96642ae..5a1799fe87 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/CogwheelBlockItem.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.relays.elementary; +package com.simibubi.create.content.kinetics.simpleRelays; -import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; +import static com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock.AXIS; import java.util.List; import java.util.function.Predicate; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.placement.IPlacementHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ICogWheel.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ICogWheel.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ICogWheel.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ICogWheel.java index 619dbb390b..b62373f6d3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ICogWheel.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ICogWheel.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.relays.elementary; +package com.simibubi.create.content.kinetics.simpleRelays; -import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.kinetics.base.IRotate; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ShaftBlock.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ShaftBlock.java index 60e78e8d5a..67d695e241 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/ShaftBlock.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.relays.elementary; +package com.simibubi.create.content.kinetics.simpleRelays; import java.util.function.Predicate; import com.google.common.base.Predicates; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.steam.PoweredShaftBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; -import com.simibubi.create.content.curiosities.girder.GirderEncasedShaftBlock; -import com.simibubi.create.foundation.utility.placement.PoleHelper; +import com.simibubi.create.content.decoration.encasing.EncasableBlock; +import com.simibubi.create.content.decoration.girder.GirderEncasedShaftBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.steamEngine.PoweredShaftBlock; +import com.simibubi.create.foundation.placement.PoleHelper; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementHelpers; @@ -31,7 +31,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class ShaftBlock extends AbstractSimpleShaftBlock { +public class ShaftBlock extends AbstractSimpleShaftBlock implements EncasableBlock { public static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -77,23 +77,12 @@ public class ShaftBlock extends AbstractSimpleShaftBlock { return InteractionResult.PASS; ItemStack heldItem = player.getItemInHand(hand); - for (EncasedShaftBlock encasedShaft : new EncasedShaftBlock[] { AllBlocks.ANDESITE_ENCASED_SHAFT.get(), - AllBlocks.BRASS_ENCASED_SHAFT.get() }) { - - if (!encasedShaft.getCasing() - .isIn(heldItem)) - continue; - - if (world.isClientSide) - return InteractionResult.SUCCESS; - - KineticTileEntity.switchToBlockState(world, pos, encasedShaft.defaultBlockState() - .setValue(AXIS, state.getValue(AXIS))); - return InteractionResult.SUCCESS; - } + InteractionResult result = tryEncase(state, world, pos, heldItem, player, hand, ray); + if (result.consumesAction()) + return result; if (AllBlocks.METAL_GIRDER.isIn(heldItem) && state.getValue(AXIS) != Axis.Y) { - KineticTileEntity.switchToBlockState(world, pos, AllBlocks.METAL_GIRDER_ENCASED_SHAFT.getDefaultState() + KineticBlockEntity.switchToBlockState(world, pos, AllBlocks.METAL_GIRDER_ENCASED_SHAFT.getDefaultState() .setValue(WATERLOGGED, state.getValue(WATERLOGGED)) .setValue(GirderEncasedShaftBlock.HORIZONTAL_AXIS, state.getValue(AXIS) == Axis.Z ? Axis.Z : Axis.X)); if (!world.isClientSide && !player.isCreative()) { @@ -135,7 +124,7 @@ public class ShaftBlock extends AbstractSimpleShaftBlock { @Override public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, - BlockHitResult ray) { + BlockHitResult ray) { PlacementOffset offset = super.getOffset(player, world, state, pos, ray); if (offset.isSuccessful()) offset.withTransform(offset.getTransform() diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/SimpleKineticBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/SimpleKineticBlockEntity.java new file mode 100644 index 0000000000..493b0f227c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/SimpleKineticBlockEntity.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.kinetics.simpleRelays; + +import java.util.List; + +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class SimpleKineticBlockEntity extends KineticBlockEntity { + + public SimpleKineticBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).inflate(1); + } + + @Override + public List addPropagationLocations(IRotate block, BlockState state, List neighbours) { + if (!ICogWheel.isLargeCog(state)) + return super.addPropagationLocations(block, state, neighbours); + + BlockPos.betweenClosedStream(new BlockPos(-1, -1, -1), new BlockPos(1, 1, 1)) + .forEach(offset -> { + if (offset.distSqr(BlockPos.ZERO) == 2) + neighbours.add(worldPosition.offset(offset)); + }); + return neighbours; + } + + @Override + protected boolean isNoisy() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogCTBehaviour.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogCTBehaviour.java similarity index 89% rename from src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogCTBehaviour.java rename to src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogCTBehaviour.java index 832047bd00..cfd78d7af0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/EncasedCogCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogCTBehaviour.java @@ -1,11 +1,12 @@ -package com.simibubi.create.content.contraptions.relays.encased; +package com.simibubi.create.content.kinetics.simpleRelays.encased; -import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; +import static com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock.AXIS; import org.jetbrains.annotations.Nullable; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; +import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import net.createmod.catnip.utility.Couple; diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogInstance.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogInstance.java new file mode 100644 index 0000000000..a102bb7387 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogInstance.java @@ -0,0 +1,111 @@ +package com.simibubi.create.content.kinetics.simpleRelays.encased; + +import java.util.Optional; + +import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class EncasedCogInstance extends KineticBlockEntityInstance { + + private boolean large; + + protected RotatingData rotatingModel; + protected Optional rotatingTopShaft; + protected Optional rotatingBottomShaft; + + public static EncasedCogInstance small(MaterialManager modelManager, KineticBlockEntity blockEntity) { + return new EncasedCogInstance(modelManager, blockEntity, false); + } + + public static EncasedCogInstance large(MaterialManager modelManager, KineticBlockEntity blockEntity) { + return new EncasedCogInstance(modelManager, blockEntity, true); + } + + public EncasedCogInstance(MaterialManager modelManager, KineticBlockEntity blockEntity, boolean large) { + super(modelManager, blockEntity); + this.large = large; + } + + @Override + public void init() { + rotatingModel = setup(getCogModel().createInstance()); + + Block block = blockState.getBlock(); + if (!(block instanceof IRotate)) + return; + + IRotate def = (IRotate) block; + rotatingTopShaft = Optional.empty(); + rotatingBottomShaft = Optional.empty(); + + for (Direction d : Iterate.directionsInAxis(axis)) { + if (!def.hasShaftTowards(blockEntity.getLevel(), blockEntity.getBlockPos(), blockState, d)) + continue; + RotatingData data = setup(getRotatingMaterial().getModel(AllPartialModels.SHAFT_HALF, blockState, d) + .createInstance()); + if (large) + data.setRotationOffset(BracketedKineticBlockEntityRenderer.getShaftAngleOffset(axis, pos)); + if (d.getAxisDirection() == AxisDirection.POSITIVE) + rotatingTopShaft = Optional.of(data); + else + rotatingBottomShaft = Optional.of(data); + } + } + + @Override + public void update() { + updateRotation(rotatingModel); + rotatingTopShaft.ifPresent(this::updateRotation); + rotatingBottomShaft.ifPresent(this::updateRotation); + } + + @Override + public void updateLight() { + relight(pos, rotatingModel); + rotatingTopShaft.ifPresent(d -> relight(pos, d)); + rotatingBottomShaft.ifPresent(d -> relight(pos, d)); + } + + @Override + public void remove() { + rotatingModel.delete(); + rotatingTopShaft.ifPresent(InstanceData::delete); + rotatingBottomShaft.ifPresent(InstanceData::delete); + } + + protected Instancer getCogModel() { + BlockState referenceState = blockEntity.getBlockState(); + Direction facing = + Direction.fromAxisAndDirection(referenceState.getValue(BlockStateProperties.AXIS), AxisDirection.POSITIVE); + PartialModel partial = large ? AllPartialModels.SHAFTLESS_LARGE_COGWHEEL : AllPartialModels.SHAFTLESS_COGWHEEL; + + return getRotatingMaterial().getModel(partial, referenceState, facing, () -> { + PoseStack poseStack = new PoseStack(); + TransformStack.cast(poseStack) + .centre() + .rotateToFace(facing) + .multiply(Vector3f.XN.rotationDegrees(90)) + .unCentre(); + return poseStack; + }); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogRenderer.java new file mode 100644 index 0000000000..c1d67927c7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogRenderer.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.kinetics.simpleRelays.encased; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.simpleRelays.BracketedKineticBlockEntityRenderer; +import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class EncasedCogRenderer extends KineticBlockEntityRenderer { + + private boolean large; + + public static EncasedCogRenderer small(BlockEntityRendererProvider.Context context) { + return new EncasedCogRenderer(context, false); + } + + public static EncasedCogRenderer large(BlockEntityRendererProvider.Context context) { + return new EncasedCogRenderer(context, true); + } + + public EncasedCogRenderer(BlockEntityRendererProvider.Context context, boolean large) { + super(context); + this.large = large; + } + + @Override + protected void renderSafe(SimpleKineticBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + if (Backend.canUseInstancing(be.getLevel())) + return; + + BlockState blockState = be.getBlockState(); + Block block = blockState.getBlock(); + if (!(block instanceof IRotate)) + return; + IRotate def = (IRotate) block; + + Axis axis = getRotationAxisOf(be); + BlockPos pos = be.getBlockPos(); + float angle = large ? BracketedKineticBlockEntityRenderer.getAngleForLargeCogShaft(be, axis) + : getAngleForTe(be, pos, axis); + + for (Direction d : Iterate.directionsInAxis(getRotationAxisOf(be))) { + if (!def.hasShaftTowards(be.getLevel(), be.getBlockPos(), blockState, d)) + continue; + SuperByteBuffer shaft = CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), d); + kineticRotationTransform(shaft, be, axis, angle, light); + shaft.renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + } + + @Override + protected SuperByteBuffer getRotatedModel(SimpleKineticBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacingVertical( + large ? AllPartialModels.SHAFTLESS_LARGE_COGWHEEL : AllPartialModels.SHAFTLESS_COGWHEEL, state, + Direction.fromAxisAndDirection(state.getValue(EncasedCogwheelBlock.AXIS), AxisDirection.POSITIVE)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogwheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogwheelBlock.java new file mode 100644 index 0000000000..d15be80197 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedCogwheelBlock.java @@ -0,0 +1,295 @@ +package com.simibubi.create.content.kinetics.simpleRelays.encased; + +import java.util.function.Supplier; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.encasing.EncasedBlock; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.content.kinetics.simpleRelays.SimpleKineticBlockEntity; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VoxelShaper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.NonNullList; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +public class EncasedCogwheelBlock extends RotatedPillarKineticBlock + implements ICogWheel, IBE, ISpecialBlockItemRequirement, ITransformableBlock, EncasedBlock { + + public static final BooleanProperty TOP_SHAFT = BooleanProperty.create("top_shaft"); + public static final BooleanProperty BOTTOM_SHAFT = BooleanProperty.create("bottom_shaft"); + + protected final boolean isLarge; + private final Supplier casing; + + public EncasedCogwheelBlock(Properties properties, boolean large, Supplier casing) { + super(properties); + isLarge = large; + this.casing = casing; + registerDefaultState(defaultBlockState().setValue(TOP_SHAFT, false) + .setValue(BOTTOM_SHAFT, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(TOP_SHAFT, BOTTOM_SHAFT)); + } + + @Override + public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { + if (target instanceof BlockHitResult) + return ((BlockHitResult) target).getDirection() + .getAxis() != getRotationAxis(state) + ? isLarge ? AllBlocks.LARGE_COGWHEEL.asStack() : AllBlocks.COGWHEEL.asStack() + : getCasing().asItem().getDefaultInstance(); + return super.getCloneItemStack(state, target, world, pos, player); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState placedOn = context.getLevel() + .getBlockState(context.getClickedPos() + .relative(context.getClickedFace() + .getOpposite())); + BlockState stateForPlacement = super.getStateForPlacement(context); + if (ICogWheel.isSmallCog(placedOn)) + stateForPlacement = + stateForPlacement.setValue(AXIS, ((IRotate) placedOn.getBlock()).getRotationAxis(placedOn)); + return stateForPlacement; + } + + @Override + public boolean skipRendering(BlockState pState, BlockState pAdjacentBlockState, Direction pDirection) { + return pState.getBlock() == pAdjacentBlockState.getBlock() + && pState.getValue(AXIS) == pAdjacentBlockState.getValue(AXIS); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + if (context.getClickedFace() + .getAxis() != state.getValue(AXIS)) + return super.onWrenched(state, context); + + Level level = context.getLevel(); + if (level.isClientSide) + return InteractionResult.SUCCESS; + + BlockPos pos = context.getClickedPos(); + KineticBlockEntity.switchToBlockState(level, pos, state.cycle(context.getClickedFace() + .getAxisDirection() == AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT)); + playRotateSound(level, pos); + return InteractionResult.SUCCESS; + } + + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + originalState = swapShaftsForRotation(originalState, Rotation.CLOCKWISE_90, targetedFace.getAxis()); + return originalState.setValue(RotatedPillarKineticBlock.AXIS, + VoxelShaper + .axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS)) + .getClockWise(targetedFace.getAxis()) + .getAxis()); + } + + @Override + public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { + if (context.getLevel().isClientSide) + return InteractionResult.SUCCESS; + context.getLevel() + .levelEvent(2001, context.getClickedPos(), Block.getId(state)); + KineticBlockEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), + (isLarge ? AllBlocks.LARGE_COGWHEEL : AllBlocks.COGWHEEL).getDefaultState() + .setValue(AXIS, state.getValue(AXIS))); + return InteractionResult.SUCCESS; + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face.getAxis() == state.getValue(AXIS) + && state.getValue(face.getAxisDirection() == AxisDirection.POSITIVE ? TOP_SHAFT : BOTTOM_SHAFT); + } + + @Override + protected boolean areStatesKineticallyEquivalent(BlockState oldState, BlockState newState) { + if (newState.getBlock() instanceof EncasedCogwheelBlock + && oldState.getBlock() instanceof EncasedCogwheelBlock) { + if (newState.getValue(TOP_SHAFT) != oldState.getValue(TOP_SHAFT)) + return false; + if (newState.getValue(BOTTOM_SHAFT) != oldState.getValue(BOTTOM_SHAFT)) + return false; + } + return super.areStatesKineticallyEquivalent(oldState, newState); + } + + @Override + public boolean isSmallCog() { + return !isLarge; + } + + @Override + public boolean isLargeCog() { + return isLarge; + } + + @Override + public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { + return CogWheelBlock.isValidCogwheelPosition(ICogWheel.isLargeCog(state), worldIn, pos, state.getValue(AXIS)); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(AXIS); + } + + public BlockState swapShafts(BlockState state) { + boolean bottom = state.getValue(BOTTOM_SHAFT); + boolean top = state.getValue(TOP_SHAFT); + state = state.setValue(BOTTOM_SHAFT, top); + state = state.setValue(TOP_SHAFT, bottom); + return state; + } + + public BlockState swapShaftsForRotation(BlockState state, Rotation rotation, Direction.Axis rotationAxis) { + if (rotation == Rotation.NONE) { + return state; + } + + Direction.Axis axis = state.getValue(AXIS); + if (axis == rotationAxis) { + return state; + } + + if (rotation == Rotation.CLOCKWISE_180) { + return swapShafts(state); + } + + boolean clockwise = rotation == Rotation.CLOCKWISE_90; + + if (rotationAxis == Direction.Axis.X) { + if ( axis == Direction.Axis.Z && !clockwise + || axis == Direction.Axis.Y && clockwise) { + return swapShafts(state); + } + } else if (rotationAxis == Direction.Axis.Y) { + if ( axis == Direction.Axis.X && !clockwise + || axis == Direction.Axis.Z && clockwise) { + return swapShafts(state); + } + } else if (rotationAxis == Direction.Axis.Z) { + if ( axis == Direction.Axis.Y && !clockwise + || axis == Direction.Axis.X && clockwise) { + return swapShafts(state); + } + } + + return state; + } + + @Override + public BlockState mirror(BlockState state, Mirror mirror) { + Direction.Axis axis = state.getValue(AXIS); + if (axis == Direction.Axis.X && mirror == Mirror.FRONT_BACK + || axis == Direction.Axis.Z && mirror == Mirror.LEFT_RIGHT) { + return swapShafts(state); + } + return state; + } + + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + state = swapShaftsForRotation(state, rotation, Direction.Axis.Y); + return super.rotate(state, rotation); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) { + state = mirror(state, transform.mirror); + } + + if (transform.rotationAxis == Direction.Axis.Y) { + return rotate(state, transform.rotation); + } + + state = swapShaftsForRotation(state, transform.rotation, transform.rotationAxis); + state = state.setValue(AXIS, transform.rotateAxis(state.getValue(AXIS))); + return state; + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement + .of(isLarge ? AllBlocks.LARGE_COGWHEEL.getDefaultState() : AllBlocks.COGWHEEL.getDefaultState(), be); + } + + @Override + public Class getBlockEntityClass() { + return SimpleKineticBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return isLarge ? AllBlockEntityTypes.ENCASED_LARGE_COGWHEEL.get() : AllBlockEntityTypes.ENCASED_COGWHEEL.get(); + } + + @Override + public Block getCasing() { + return casing.get(); + } + + @Override + public void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand, + BlockHitResult ray) { + BlockState encasedState = defaultBlockState() + .setValue(AXIS, state.getValue(AXIS)); + + for (Direction d : Iterate.directionsInAxis(state.getValue(AXIS))) { + BlockState adjacentState = level.getBlockState(pos.relative(d)); + if (!(adjacentState.getBlock() instanceof IRotate)) + continue; + IRotate def = (IRotate) adjacentState.getBlock(); + if (!def.hasShaftTowards(level, pos.relative(d), adjacentState, d.getOpposite())) + continue; + encasedState = + encasedState.cycle(d.getAxisDirection() == AxisDirection.POSITIVE ? EncasedCogwheelBlock.TOP_SHAFT + : EncasedCogwheelBlock.BOTTOM_SHAFT); + } + + KineticBlockEntity.switchToBlockState(level, pos, encasedState); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedShaftBlock.java new file mode 100644 index 0000000000..26f7f65d16 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/simpleRelays/encased/EncasedShaftBlock.java @@ -0,0 +1,91 @@ +package com.simibubi.create.content.kinetics.simpleRelays.encased; + +import java.util.function.Supplier; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.decoration.encasing.EncasedBlock; +import com.simibubi.create.content.kinetics.base.AbstractEncasedShaftBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +public class EncasedShaftBlock extends AbstractEncasedShaftBlock + implements IBE, ISpecialBlockItemRequirement, EncasedBlock { + + private final Supplier casing; + + public EncasedShaftBlock(Properties properties, Supplier casing) { + super(properties); + this.casing = casing; + } + + @Override + public void fillItemCategory(CreativeModeTab pTab, NonNullList pItems) {} + + @Override + public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { + if (context.getLevel().isClientSide) + return InteractionResult.SUCCESS; + context.getLevel() + .levelEvent(2001, context.getClickedPos(), Block.getId(state)); + KineticBlockEntity.switchToBlockState(context.getLevel(), context.getClickedPos(), + AllBlocks.SHAFT.getDefaultState() + .setValue(AXIS, state.getValue(AXIS))); + return InteractionResult.SUCCESS; + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { + if (target instanceof BlockHitResult) + return ((BlockHitResult) target).getDirection() + .getAxis() == getRotationAxis(state) ? AllBlocks.SHAFT.asStack() : getCasing().asItem().getDefaultInstance(); + return super.getCloneItemStack(state, target, world, pos, player); + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement.of(AllBlocks.SHAFT.getDefaultState(), be); + } + + @Override + public Class getBlockEntityClass() { + return KineticBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ENCASED_SHAFT.get(); + } + + @Override + public Block getCasing() { + return casing.get(); + } + + @Override + public void handleEncasing(BlockState state, Level level, BlockPos pos, ItemStack heldItem, Player player, InteractionHand hand, + BlockHitResult ray) { + KineticBlockEntity.switchToBlockState(level, pos, defaultBlockState() + .setValue(RotatedPillarKineticBlock.AXIS, state.getValue(RotatedPillarKineticBlock.AXIS))); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlock.java similarity index 82% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlock.java index 5af86e511c..b32472cad0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlock.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.contraptions.relays.advanced; +package com.simibubi.create.content.kinetics.speedController; import java.util.function.Predicate; import javax.annotation.ParametersAreNonnullByDefault; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementHelpers; @@ -35,7 +35,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ITE { +public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements IBE { private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -58,7 +58,7 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos neighbourPos, boolean p_220069_6_) { if (neighbourPos.equals(pos.above())) - withTileEntityDo(world, pos, SpeedControllerTileEntity::updateBracket); + withBlockEntityDo(world, pos, SpeedControllerBlockEntity::updateBracket); } @Override @@ -108,12 +108,12 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements } @Override - public Class getTileEntityClass() { - return SpeedControllerTileEntity.class; + public Class getBlockEntityClass() { + return SpeedControllerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ROTATION_SPEED_CONTROLLER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ROTATION_SPEED_CONTROLLER.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlockEntity.java new file mode 100644 index 0000000000..1f26390f52 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerBlockEntity.java @@ -0,0 +1,173 @@ +package com.simibubi.create.content.kinetics.speedController; + +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.kinetics.RotationPropagator; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.motor.KineticScrollValueBehaviour; +import com.simibubi.create.content.kinetics.simpleRelays.CogWheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class SpeedControllerBlockEntity extends KineticBlockEntity { + + public static final int DEFAULT_SPEED = 16; + public ScrollValueBehaviour targetSpeed; + public AbstractComputerBehaviour computerBehaviour; + + boolean hasBracket; + + public SpeedControllerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + hasBracket = false; + } + + @Override + public void lazyTick() { + super.lazyTick(); + updateBracket(); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + Integer max = AllConfigs.server().kinetics.maxRotationSpeed.get(); + + targetSpeed = new KineticScrollValueBehaviour(CreateLang.translateDirect("kinetics.speed_controller.rotation_speed"), + this, new ControllerValueBoxTransform()); + targetSpeed.between(-max, max); + targetSpeed.value = DEFAULT_SPEED; + targetSpeed.withCallback(i -> this.updateTargetRotation()); + behaviours.add(targetSpeed); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + + registerAwardables(behaviours, AllAdvancements.SPEED_CONTROLLER); + } + + private void updateTargetRotation() { + if (hasNetwork()) + getOrCreateNetwork().remove(this); + RotationPropagator.handleRemoved(level, worldPosition, this); + removeSource(); + attachKinetics(); + + if (isCogwheelPresent() && getSpeed() != 0) + award(AllAdvancements.SPEED_CONTROLLER); + } + + public static float getConveyedSpeed(KineticBlockEntity cogWheel, KineticBlockEntity speedControllerIn, + boolean targetingController) { + if (!(speedControllerIn instanceof SpeedControllerBlockEntity)) + return 0; + + float speed = speedControllerIn.getTheoreticalSpeed(); + float wheelSpeed = cogWheel.getTheoreticalSpeed(); + float desiredOutputSpeed = getDesiredOutputSpeed(cogWheel, speedControllerIn, targetingController); + + float compareSpeed = targetingController ? speed : wheelSpeed; + if (desiredOutputSpeed >= 0 && compareSpeed >= 0) + return Math.max(desiredOutputSpeed, compareSpeed); + if (desiredOutputSpeed < 0 && compareSpeed < 0) + return Math.min(desiredOutputSpeed, compareSpeed); + + return desiredOutputSpeed; + } + + public static float getDesiredOutputSpeed(KineticBlockEntity cogWheel, KineticBlockEntity speedControllerIn, + boolean targetingController) { + SpeedControllerBlockEntity speedController = (SpeedControllerBlockEntity) speedControllerIn; + float targetSpeed = speedController.targetSpeed.getValue(); + float speed = speedControllerIn.getTheoreticalSpeed(); + float wheelSpeed = cogWheel.getTheoreticalSpeed(); + + if (targetSpeed == 0) + return 0; + if (targetingController && wheelSpeed == 0) + return 0; + if (!speedController.hasSource()) { + if (targetingController) + return targetSpeed; + return 0; + } + + boolean wheelPowersController = speedController.source.equals(cogWheel.getBlockPos()); + + if (wheelPowersController) { + if (targetingController) + return targetSpeed; + return wheelSpeed; + } + + if (targetingController) + return speed; + return targetSpeed; + } + + public void updateBracket() { + if (level != null && level.isClientSide) + hasBracket = isCogwheelPresent(); + } + + private boolean isCogwheelPresent() { + BlockState stateAbove = level.getBlockState(worldPosition.above()); + return ICogWheel.isDedicatedCogWheel(stateAbove.getBlock()) && ICogWheel.isLargeCog(stateAbove) + && stateAbove.getValue(CogWheelBlock.AXIS) + .isHorizontal(); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + + private class ControllerValueBoxTransform extends ValueBoxTransform.Sided { + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 11f, 15.5f); + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + if (direction.getAxis() + .isVertical()) + return false; + return state.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) != direction.getAxis(); + } + + @Override + public float getScale() { + return 0.5f; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerRenderer.java new file mode 100644 index 0000000000..f30087a0c7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/speedController/SpeedControllerRenderer.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.kinetics.speedController; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class SpeedControllerRenderer extends SmartBlockEntityRenderer { + + public SpeedControllerRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(SpeedControllerBlockEntity blockEntity, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + super.renderSafe(blockEntity, partialTicks, ms, buffer, light, overlay); + + VertexConsumer builder = buffer.getBuffer(RenderType.solid()); + if (!Backend.canUseInstancing(blockEntity.getLevel())) { + KineticBlockEntityRenderer.renderRotatingBuffer(blockEntity, getRotatedModel(blockEntity), ms, builder, light); + } + + if (!blockEntity.hasBracket) + return; + + BlockPos pos = blockEntity.getBlockPos(); + Level world = blockEntity.getLevel(); + BlockState blockState = blockEntity.getBlockState(); + boolean alongX = blockState.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == Axis.X; + + SuperByteBuffer bracket = CachedPartialBuffers.partial(AllPartialModels.SPEED_CONTROLLER_BRACKET, blockState); + bracket.translate(0, 1, 0); + bracket.rotateCentered(Direction.UP, + (float) (alongX ? Math.PI : Math.PI / 2)); + bracket.light(LevelRenderer.getLightColor(world, pos.above())); + bracket.renderInto(ms, builder); + } + + private SuperByteBuffer getRotatedModel(SpeedControllerBlockEntity blockEntity) { + return CachedBlockBuffers.block(KineticBlockEntityRenderer.KINETIC_BLOCK, + KineticBlockEntityRenderer.shaft(KineticBlockEntityRenderer.getRotationAxisOf(blockEntity))); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlock.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlock.java index 006985a1fd..dc53c08ec3 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/PoweredShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlock.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.contraptions.components.steam; +package com.simibubi.create.content.kinetics.steamEngine; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.AbstractShaftBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractShaftBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.placement.IPlacementHelper; @@ -42,8 +42,8 @@ public class PoweredShaftBlock extends AbstractShaftBlock { } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.POWERED_SHAFT.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.POWERED_SHAFT.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlockEntity.java new file mode 100644 index 0000000000..33c46cfd09 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/PoweredShaftBlockEntity.java @@ -0,0 +1,140 @@ +package com.simibubi.create.content.kinetics.steamEngine; + +import java.util.List; + +import com.simibubi.create.content.kinetics.BlockStressValues; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; + +import net.createmod.catnip.platform.CatnipServices; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.registries.ForgeRegistries; + +public class PoweredShaftBlockEntity extends GeneratingKineticBlockEntity { + + public BlockPos enginePos; + public float engineEfficiency; + public int movementDirection; + public int initialTicks; + public Block capacityKey; + + public PoweredShaftBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + movementDirection = 1; + initialTicks = 3; + } + + @Override + public void tick() { + super.tick(); + if (initialTicks > 0) + initialTicks--; + } + + public void update(BlockPos sourcePos, int direction, float efficiency) { + BlockPos key = worldPosition.subtract(sourcePos); + enginePos = key; + float prev = engineEfficiency; + engineEfficiency = efficiency; + int prevDirection = this.movementDirection; + if (Mth.equal(efficiency, prev) && prevDirection == direction) + return; + + capacityKey = level.getBlockState(sourcePos) + .getBlock(); + this.movementDirection = direction; + updateGeneratedRotation(); + } + + public void remove(BlockPos sourcePos) { + if (!isPoweredBy(sourcePos)) + return; + + enginePos = null; + engineEfficiency = 0; + movementDirection = 0; + capacityKey = null; + updateGeneratedRotation(); + } + + public boolean canBePoweredBy(BlockPos globalPos) { + return initialTicks == 0 && (enginePos == null || isPoweredBy(globalPos)); + } + + public boolean isPoweredBy(BlockPos globalPos) { + BlockPos key = worldPosition.subtract(globalPos); + return key.equals(enginePos); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("Direction", movementDirection); + if (initialTicks > 0) + compound.putInt("Warmup", initialTicks); + if (enginePos != null && capacityKey != null) { + compound.put("EnginePos", NbtUtils.writeBlockPos(enginePos)); + compound.putFloat("EnginePower", engineEfficiency); + compound.putString("EngineType", CatnipServices.REGISTRIES.getKeyOrThrow(capacityKey) + .toString()); + } + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + movementDirection = compound.getInt("Direction"); + initialTicks = compound.getInt("Warmup"); + enginePos = null; + engineEfficiency = 0; + if (compound.contains("EnginePos")) { + enginePos = NbtUtils.readBlockPos(compound.getCompound("EnginePos")); + engineEfficiency = compound.getFloat("EnginePower"); + capacityKey = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(compound.getString("EngineType"))); + } + } + + @Override + public float getGeneratedSpeed() { + return getCombinedCapacity() > 0 ? movementDirection * 16 * getSpeedModifier() : 0; + } + + private float getCombinedCapacity() { + return capacityKey == null ? 0 : (float) (engineEfficiency * BlockStressValues.getCapacity(capacityKey)); + } + + private int getSpeedModifier() { + return (int) (1 + (engineEfficiency >= 1 ? 3 : Math.min(2, Math.floor(engineEfficiency * 4)))); + } + + @Override + public float calculateAddedStressCapacity() { + float capacity = getCombinedCapacity() / getSpeedModifier(); + this.lastCapacityProvided = capacity; + return capacity; + } + + @Override + public int getRotationAngleOffset(Axis axis) { + int combinedCoords = axis.choose(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ()); + return super.getRotationAngleOffset(axis) + (combinedCoords % 2 == 0 ? 180 : 0); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + return false; + } + + public boolean addToEngineTooltip(List tooltip, boolean isPlayerSneaking) { + return super.addToGoggleTooltip(tooltip, isPlayerSneaking); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineBlock.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlock.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlock.java index 711d1c372d..75c3b104da 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlock.java @@ -1,17 +1,17 @@ -package com.simibubi.create.content.contraptions.components.steam; +package com.simibubi.create.content.kinetics.steamEngine; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; import java.util.function.Predicate; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.tank.FluidTankBlock; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.utility.BlockHelper; import net.createmod.catnip.utility.Couple; @@ -48,7 +48,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; public class SteamEngineBlock extends FaceAttachedHorizontalDirectionalBlock - implements SimpleWaterloggedBlock, IWrenchable, ITE { + implements SimpleWaterloggedBlock, IWrenchable, IBE { private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -163,13 +163,13 @@ public class SteamEngineBlock extends FaceAttachedHorizontalDirectionalBlock } @Override - public Class getTileEntityClass() { - return SteamEngineTileEntity.class; + public Class getBlockEntityClass() { + return SteamEngineBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.STEAM_ENGINE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.STEAM_ENGINE.get(); } @MethodsReturnNonnullByDefault diff --git a/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlockEntity.java new file mode 100644 index 0000000000..25e3fe5b4f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineBlockEntity.java @@ -0,0 +1,269 @@ +package com.simibubi.create.content.kinetics.steamEngine; + +import java.lang.ref.WeakReference; +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlockEntity.RotationDirection; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class SteamEngineBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + protected ScrollOptionBehaviour movementDirection; + + public WeakReference target; + public WeakReference source; + + public SteamEngineBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + source = new WeakReference<>(null); + target = new WeakReference<>(null); + } + + @Override + public void addBehaviours(List behaviours) { + movementDirection = new ScrollOptionBehaviour<>(RotationDirection.class, + CreateLang.translateDirect("contraptions.windmill.rotation_direction"), this, new SteamEngineValueBox()); + movementDirection.onlyActiveWhen(() -> { + PoweredShaftBlockEntity shaft = getShaft(); + return shaft == null || !shaft.hasSource(); + }); + movementDirection.withCallback($ -> onDirectionChanged()); + behaviours.add(movementDirection); + + registerAwardables(behaviours, AllAdvancements.STEAM_ENGINE); + } + + private void onDirectionChanged() {} + + @Override + public void tick() { + super.tick(); + FluidTankBlockEntity tank = getTank(); + PoweredShaftBlockEntity shaft = getShaft(); + + if (tank == null || shaft == null) { + if (level.isClientSide()) + return; + if (shaft == null) + return; + if (!shaft.getBlockPos() + .subtract(worldPosition) + .equals(shaft.enginePos)) + return; + if (shaft.engineEfficiency == 0) + return; + Direction facing = SteamEngineBlock.getFacing(getBlockState()); + if (level.isLoaded(worldPosition.relative(facing.getOpposite()))) + shaft.update(worldPosition, 0, 0); + return; + } + + boolean verticalTarget = false; + BlockState shaftState = shaft.getBlockState(); + Axis targetAxis = Axis.X; + if (shaftState.getBlock()instanceof IRotate ir) + targetAxis = ir.getRotationAxis(shaftState); + verticalTarget = targetAxis == Axis.Y; + + BlockState blockState = getBlockState(); + if (!AllBlocks.STEAM_ENGINE.has(blockState)) + return; + Direction facing = SteamEngineBlock.getFacing(blockState); + if (facing.getAxis() == Axis.Y) + facing = blockState.getValue(SteamEngineBlock.FACING); + + float efficiency = Mth.clamp(tank.boiler.getEngineEfficiency(tank.getTotalTankSize()), 0, 1); + if (efficiency > 0) + + award(AllAdvancements.STEAM_ENGINE); + + int conveyedSpeedLevel = + efficiency == 0 ? 1 : verticalTarget ? 1 : (int) GeneratingKineticBlockEntity.convertToDirection(1, facing); + if (targetAxis == Axis.Z) + conveyedSpeedLevel *= -1; + if (movementDirection.get() == RotationDirection.COUNTER_CLOCKWISE) + conveyedSpeedLevel *= -1; + + float shaftSpeed = shaft.getTheoreticalSpeed(); + if (shaft.hasSource() && shaftSpeed != 0 && conveyedSpeedLevel != 0 + && (shaftSpeed > 0) != (conveyedSpeedLevel > 0)) { + movementDirection.setValue(1 - movementDirection.get() + .ordinal()); + conveyedSpeedLevel *= -1; + } + + shaft.update(worldPosition, conveyedSpeedLevel, efficiency); + + if (!level.isClientSide) + return; + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::spawnParticles); + } + + @Override + public void remove() { + PoweredShaftBlockEntity shaft = getShaft(); + if (shaft != null) + shaft.remove(worldPosition); + super.remove(); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); + } + + public PoweredShaftBlockEntity getShaft() { + PoweredShaftBlockEntity shaft = target.get(); + if (shaft == null || shaft.isRemoved() || !shaft.canBePoweredBy(worldPosition)) { + if (shaft != null) + target = new WeakReference<>(null); + Direction facing = SteamEngineBlock.getFacing(getBlockState()); + BlockEntity anyShaftAt = level.getBlockEntity(worldPosition.relative(facing, 2)); + if (anyShaftAt instanceof PoweredShaftBlockEntity ps && ps.canBePoweredBy(worldPosition)) + target = new WeakReference<>(shaft = ps); + } + return shaft; + } + + public FluidTankBlockEntity getTank() { + FluidTankBlockEntity tank = source.get(); + if (tank == null || tank.isRemoved()) { + if (tank != null) + source = new WeakReference<>(null); + Direction facing = SteamEngineBlock.getFacing(getBlockState()); + BlockEntity be = level.getBlockEntity(worldPosition.relative(facing.getOpposite())); + if (be instanceof FluidTankBlockEntity tankBe) + source = new WeakReference<>(tank = tankBe); + } + if (tank == null) + return null; + return tank.getControllerBE(); + } + + float prevAngle = 0; + + @OnlyIn(Dist.CLIENT) + private void spawnParticles() { + Float targetAngle = getTargetAngle(); + PoweredShaftBlockEntity ste = target.get(); + if (ste == null) + return; + if (!ste.isPoweredBy(worldPosition) || ste.engineEfficiency == 0) + return; + if (targetAngle == null) + return; + + float angle = AngleHelper.deg(targetAngle); + angle += (angle < 0) ? -180 + 75 : 360 - 75; + angle %= 360; + + PoweredShaftBlockEntity shaft = getShaft(); + if (shaft == null || shaft.getSpeed() == 0) + return; + + if (angle >= 0 && !(prevAngle > 180 && angle < 180)) { + prevAngle = angle; + return; + } + if (angle < 0 && !(prevAngle < -180 && angle > -180)) { + prevAngle = angle; + return; + } + + FluidTankBlockEntity sourceBE = source.get(); + if (sourceBE != null) { + FluidTankBlockEntity controller = sourceBE.getControllerBE(); + if (controller != null && controller.boiler != null) { + float volume = 3f / Math.max(2, controller.boiler.attachedEngines / 6); + float pitch = 1.18f - level.random.nextFloat() * .25f; + level.playLocalSound(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), + SoundEvents.CANDLE_EXTINGUISH, SoundSource.BLOCKS, volume, pitch, false); + AllSoundEvents.STEAM.playAt(level, worldPosition, volume / 16, .8f, false); + } + } + + Direction facing = SteamEngineBlock.getFacing(getBlockState()); + + Vec3 offset = VecHelper.rotate(new Vec3(0, 0, 1).add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1) + .multiply(1, 1, 0) + .normalize() + .scale(.5f)), AngleHelper.verticalAngle(facing), Axis.X); + offset = VecHelper.rotate(offset, AngleHelper.horizontalAngle(facing), Axis.Y); + Vec3 v = offset.scale(.5f) + .add(Vec3.atCenterOf(worldPosition)); + Vec3 m = offset.subtract(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(.75f)); + level.addParticle(new SteamJetParticleData(1), v.x, v.y, v.z, m.x, m.y, m.z); + + prevAngle = angle; + } + + @Nullable + @OnlyIn(Dist.CLIENT) + public Float getTargetAngle() { + float angle = 0; + BlockState blockState = getBlockState(); + if (!AllBlocks.STEAM_ENGINE.has(blockState)) + return null; + + Direction facing = SteamEngineBlock.getFacing(blockState); + PoweredShaftBlockEntity shaft = getShaft(); + Axis facingAxis = facing.getAxis(); + Axis axis = Axis.Y; + + if (shaft == null) + return null; + + axis = KineticBlockEntityRenderer.getRotationAxisOf(shaft); + angle = KineticBlockEntityRenderer.getAngleForTe(shaft, shaft.getBlockPos(), axis); + + if (axis == facingAxis) + return null; + if (axis.isHorizontal() && (facingAxis == Axis.X ^ facing.getAxisDirection() == AxisDirection.POSITIVE)) + angle *= -1; + if (axis == Axis.X && facing == Direction.DOWN) + angle *= -1; + return angle; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + PoweredShaftBlockEntity shaft = getShaft(); + return shaft == null ? false : shaft.addToEngineTooltip(tooltip, isPlayerSneaking); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineInstance.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineInstance.java new file mode 100644 index 0000000000..3e63ca7515 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineInstance.java @@ -0,0 +1,103 @@ +package com.simibubi.create.content.kinetics.steamEngine; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; + +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; + +public class SteamEngineInstance extends BlockEntityInstance implements DynamicInstance { + + protected final ModelData piston; + protected final ModelData linkage; + protected final ModelData connector; + + public SteamEngineInstance(MaterialManager materialManager, SteamEngineBlockEntity blockEntity) { + super(materialManager, blockEntity); + + piston = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(AllPartialModels.ENGINE_PISTON, blockState) + .createInstance(); + linkage = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(AllPartialModels.ENGINE_LINKAGE, blockState) + .createInstance(); + connector = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(AllPartialModels.ENGINE_CONNECTOR, blockState) + .createInstance(); + } + + @Override + public void beginFrame() { + Float angle = blockEntity.getTargetAngle(); + if (angle == null) { + piston.setEmptyTransform(); + linkage.setEmptyTransform(); + connector.setEmptyTransform(); + return; + } + + Direction facing = SteamEngineBlock.getFacing(blockState); + Axis facingAxis = facing.getAxis(); + Axis axis = Axis.Y; + + PoweredShaftBlockEntity shaft = blockEntity.getShaft(); + if (shaft != null) + axis = KineticBlockEntityRenderer.getRotationAxisOf(shaft); + + boolean roll90 = facingAxis.isHorizontal() && axis == Axis.Y || facingAxis.isVertical() && axis == Axis.Z; + float sine = Mth.sin(angle); + float sine2 = Mth.sin(angle - Mth.HALF_PI); + float piston = ((1 - sine) / 4) * 24 / 16f; + + transformed(this.piston, facing, roll90) + .translate(0, piston, 0); + + transformed(linkage, facing, roll90) + .centre() + .translate(0, 1, 0) + .unCentre() + .translate(0, piston, 0) + .translate(0, 4 / 16f, 8 / 16f) + .rotateX(sine2 * 23f) + .translate(0, -4 / 16f, -8 / 16f); + + transformed(connector, facing, roll90) + .translate(0, 2, 0) + .centre() + .rotateXRadians(-angle + Mth.HALF_PI) + .unCentre(); + } + + protected ModelData transformed(ModelData modelData, Direction facing, boolean roll90) { + return modelData.loadIdentity() + .translate(getInstancePosition()) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing) + 90) + .rotateY(roll90 ? -90 : 0) + .unCentre(); + } + + @Override + public void updateLight() { + relight(pos, piston, linkage, connector); + } + + @Override + protected void remove() { + piston.delete(); + linkage.delete(); + connector.delete(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineRenderer.java new file mode 100644 index 0000000000..58ccb1d949 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineRenderer.java @@ -0,0 +1,91 @@ +package com.simibubi.create.content.kinetics.steamEngine; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class SteamEngineRenderer extends SafeBlockEntityRenderer { + + public SteamEngineRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(SteamEngineBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) + return; + + Float angle = be.getTargetAngle(); + if (angle == null) + return; + + BlockState blockState = be.getBlockState(); + Direction facing = SteamEngineBlock.getFacing(blockState); + Axis facingAxis = facing.getAxis(); + Axis axis = Axis.Y; + + PoweredShaftBlockEntity shaft = be.getShaft(); + if (shaft != null) + axis = KineticBlockEntityRenderer.getRotationAxisOf(shaft); + + boolean roll90 = facingAxis.isHorizontal() && axis == Axis.Y || facingAxis.isVertical() && axis == Axis.Z; + float sine = Mth.sin(angle); + float sine2 = Mth.sin(angle - Mth.HALF_PI); + float piston = ((1 - sine) / 4) * 24 / 16f; + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + transformed(AllPartialModels.ENGINE_PISTON, blockState, facing, roll90) + .translate(0, piston, 0) + .light(light) + .renderInto(ms, vb); + + transformed(AllPartialModels.ENGINE_LINKAGE, blockState, facing, roll90) + .centre() + .translate(0, 1, 0) + .unCentre() + .translate(0, piston, 0) + .translate(0, 4 / 16f, 8 / 16f) + .rotateX(sine2 * 23f) + .translate(0, -4 / 16f, -8 / 16f) + .light(light) + .renderInto(ms, vb); + + transformed(AllPartialModels.ENGINE_CONNECTOR, blockState, facing, roll90) + .translate(0, 2, 0) + .centre() + .rotateXRadians(-angle + Mth.HALF_PI) + .unCentre() + .light(light) + .renderInto(ms, vb); + } + + private SuperByteBuffer transformed(PartialModel model, BlockState blockState, Direction facing, boolean roll90) { + return CachedPartialBuffers.partial(model, blockState) + .centre() + .rotateY(AngleHelper.horizontalAngle(facing)) + .rotateX(AngleHelper.verticalAngle(facing) + 90) + .rotateY(roll90 ? -90 : 0) + .unCentre(); + } + + @Override + public int getViewDistance() { + return 128; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineValueBox.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineValueBox.java new file mode 100644 index 0000000000..58802b69be --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamEngineValueBox.java @@ -0,0 +1,87 @@ +package com.simibubi.create.content.kinetics.steamEngine; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.Pointing; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class SteamEngineValueBox extends ValueBoxTransform.Sided { + + @Override + protected boolean isSideActive(BlockState state, Direction side) { + Direction engineFacing = SteamEngineBlock.getFacing(state); + if (engineFacing.getAxis() == side.getAxis()) + return false; + + float roll = 0; + for (Pointing p : Pointing.values()) + if (p.getCombinedDirection(engineFacing) == side) + roll = p.getXRotation(); + if (engineFacing == Direction.UP) + roll += 180; + + boolean recessed = roll % 180 == 0; + if (engineFacing.getAxis() == Axis.Y) + recessed ^= state.getValue(SteamEngineBlock.FACING) + .getAxis() == Axis.X; + + return !recessed; + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + Direction side = getSide(); + Direction engineFacing = SteamEngineBlock.getFacing(state); + + float roll = 0; + for (Pointing p : Pointing.values()) + if (p.getCombinedDirection(engineFacing) == side) + roll = p.getXRotation(); + if (engineFacing == Direction.UP) + roll += 180; + + float horizontalAngle = AngleHelper.horizontalAngle(engineFacing); + float verticalAngle = AngleHelper.verticalAngle(engineFacing); + Vec3 local = VecHelper.voxelSpace(8, 14.5, 9); + + local = VecHelper.rotateCentered(local, roll, Axis.Z); + local = VecHelper.rotateCentered(local, horizontalAngle, Axis.Y); + local = VecHelper.rotateCentered(local, verticalAngle, Axis.X); + + return local; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + Direction facing = SteamEngineBlock.getFacing(state); + + if (facing.getAxis() == Axis.Y) { + super.rotate(state, ms); + return; + } + + float roll = 0; + for (Pointing p : Pointing.values()) + if (p.getCombinedDirection(facing) == getSide()) + roll = p.getXRotation(); + + float yRot = AngleHelper.horizontalAngle(facing) + (facing == Direction.DOWN ? 180 : 0); + TransformStack.cast(ms) + .rotateY(yRot) + .rotateX(facing == Direction.DOWN ? -90 : 90) + .rotateY(roll); + } + + @Override + protected Vec3 getSouthLocation() { + return Vec3.ZERO; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticle.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticle.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticle.java rename to src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticle.java index 5f1f70c1f5..e2017a0b9d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticle.java +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticle.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.steam; +package com.simibubi.create.content.kinetics.steamEngine; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Quaternion; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticleData.java b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticleData.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticleData.java rename to src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticleData.java index 6b20e0405c..263eccb5eb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamJetParticleData.java +++ b/src/main/java/com/simibubi/create/content/kinetics/steamEngine/SteamJetParticleData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.steam; +package com.simibubi.create.content.kinetics.steamEngine; import java.util.Locale; @@ -7,7 +7,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllParticleTypes; -import com.simibubi.create.content.contraptions.particle.ICustomParticleDataWithSprite; +import com.simibubi.create.foundation.particle.ICustomParticleDataWithSprite; import net.minecraft.client.particle.ParticleEngine.SpriteParticleRegistration; import net.minecraft.core.particles.ParticleOptions; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchBlock.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlock.java similarity index 77% rename from src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlock.java index 9ad3151631..8f356d778b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/ClutchBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlock.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.contraptions.relays.encased; +package com.simibubi.create.content.kinetics.transmission; -import com.simibubi.create.AllTileEntities; +import com.simibubi.create.AllBlockEntityTypes; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; @@ -28,8 +28,8 @@ public class ClutchBlock extends GearshiftBlock { } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CLUTCH.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CLUTCH.get(); } } diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlockEntity.java new file mode 100644 index 0000000000..86c10d86e3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/ClutchBlockEntity.java @@ -0,0 +1,24 @@ +package com.simibubi.create.content.kinetics.transmission; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class ClutchBlockEntity extends SplitShaftBlockEntity { + + public ClutchBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public float getRotationSpeedModifier(Direction face) { + if (hasSource()) { + if (face != getSourceFacing() && getBlockState().getValue(BlockStateProperties.POWERED)) + return 0; + } + return 1; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlock.java new file mode 100644 index 0000000000..f93b5438ba --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlock.java @@ -0,0 +1,87 @@ +package com.simibubi.create.content.kinetics.transmission; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.kinetics.RotationPropagator; +import com.simibubi.create.content.kinetics.base.AbstractEncasedShaftBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.ticks.TickPriority; + +public class GearshiftBlock extends AbstractEncasedShaftBlock implements IBE { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + public GearshiftBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(POWERED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(POWERED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return super.getStateForPlacement(context).setValue(POWERED, + context.getLevel().hasNeighborSignal(context.getClickedPos())); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + if (worldIn.isClientSide) + return; + + boolean previouslyPowered = state.getValue(POWERED); + if (previouslyPowered != worldIn.hasNeighborSignal(pos)) { + detachKinetics(worldIn, pos, true); + worldIn.setBlock(pos, state.cycle(POWERED), 2); + } + } + + @Override + public Class getBlockEntityClass() { + return SplitShaftBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.GEARSHIFT.get(); + } + + public void detachKinetics(Level worldIn, BlockPos pos, boolean reAttachNextTick) { + BlockEntity be = worldIn.getBlockEntity(pos); + if (be == null || !(be instanceof KineticBlockEntity)) + return; + RotationPropagator.handleRemoved(worldIn, pos, (KineticBlockEntity) be); + + // Re-attach next tick + if (reAttachNextTick) + worldIn.scheduleTick(pos, this, 0, TickPriority.EXTREMELY_HIGH); + } + + @Override + public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { + BlockEntity be = worldIn.getBlockEntity(pos); + if (be == null || !(be instanceof KineticBlockEntity)) + return; + KineticBlockEntity kte = (KineticBlockEntity) be; + RotationPropagator.handleAdded(worldIn, pos, kte); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlockEntity.java new file mode 100644 index 0000000000..7147a07d25 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/GearshiftBlockEntity.java @@ -0,0 +1,24 @@ +package com.simibubi.create.content.kinetics.transmission; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public class GearshiftBlockEntity extends SplitShaftBlockEntity { + + public GearshiftBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public float getRotationSpeedModifier(Direction face) { + if (hasSource()) { + if (face != getSourceFacing() && getBlockState().getValue(BlockStateProperties.POWERED)) + return -1; + } + return 1; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftBlockEntity.java new file mode 100644 index 0000000000..9c3d8e8f07 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftBlockEntity.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.kinetics.transmission; + +import com.simibubi.create.content.kinetics.base.DirectionalShaftHalvesBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class SplitShaftBlockEntity extends DirectionalShaftHalvesBlockEntity { + + public SplitShaftBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public abstract float getRotationSpeedModifier(Direction face); + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftInstance.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftInstance.java new file mode 100644 index 0000000000..2cd36310e5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftInstance.java @@ -0,0 +1,64 @@ +package com.simibubi.create.content.kinetics.transmission; + +import java.util.ArrayList; + +import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.Material; +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; + +public class SplitShaftInstance extends KineticBlockEntityInstance { + + protected final ArrayList keys; + + public SplitShaftInstance(MaterialManager modelManager, SplitShaftBlockEntity blockEntity) { + super(modelManager, blockEntity); + + keys = new ArrayList<>(2); + + float speed = blockEntity.getSpeed(); + + Material rotatingMaterial = getRotatingMaterial(); + + for (Direction dir : Iterate.directionsInAxis(getRotationAxis())) { + + Instancer half = rotatingMaterial.getModel(AllPartialModels.SHAFT_HALF, blockState, dir); + + float splitSpeed = speed * blockEntity.getRotationSpeedModifier(dir); + + keys.add(setup(half.createInstance(), splitSpeed)); + } + } + + @Override + public void update() { + Block block = blockState.getBlock(); + final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(blockState); + + Direction[] directions = Iterate.directionsInAxis(boxAxis); + + for (int i : Iterate.zeroAndOne) { + updateRotation(keys.get(i), blockEntity.getSpeed() * blockEntity.getRotationSpeedModifier(directions[i])); + } + } + + @Override + public void updateLight() { + relight(pos, keys.stream()); + } + + @Override + public void remove() { + keys.forEach(InstanceData::delete); + keys.clear(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftRenderer.java new file mode 100644 index 0000000000..9fd010e2f7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/SplitShaftRenderer.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.kinetics.transmission; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.Iterate; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.Block; + +public class SplitShaftRenderer extends KineticBlockEntityRenderer { + + public SplitShaftRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(SplitShaftBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + if (Backend.canUseInstancing(be.getLevel())) return; + + Block block = be.getBlockState().getBlock(); + final Axis boxAxis = ((IRotate) block).getRotationAxis(be.getBlockState()); + final BlockPos pos = be.getBlockPos(); + float time = WorldTickHolder.getRenderTime(be.getLevel()); + + for (Direction direction : Iterate.directions) { + Axis axis = direction.getAxis(); + if (boxAxis != axis) + continue; + + float offset = getRotationOffsetForPosition(be, pos, axis); + float angle = (time * be.getSpeed() * 3f / 10) % 360; + float modifier = be.getRotationSpeedModifier(direction); + + angle *= modifier; + angle += offset; + angle = angle / 180f * (float) Math.PI; + + SuperByteBuffer superByteBuffer = + CachedPartialBuffers.partialFacing(AllPartialModels.SHAFT_HALF, be.getBlockState(), direction); + kineticRotationTransform(superByteBuffer, be, axis, angle, light); + superByteBuffer.renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/ConfigureSequencedGearshiftPacket.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/ConfigureSequencedGearshiftPacket.java new file mode 100644 index 0000000000..4c00bd0a1e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/ConfigureSequencedGearshiftPacket.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.kinetics.transmission.sequencer; + +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigureSequencedGearshiftPacket extends BlockEntityConfigurationPacket { + + private ListTag instructions; + + public ConfigureSequencedGearshiftPacket(BlockPos pos, ListTag instructions) { + super(pos); + this.instructions = instructions; + } + + public ConfigureSequencedGearshiftPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + instructions = buffer.readNbt().getList("data", Tag.TAG_COMPOUND); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + CompoundTag tag = new CompoundTag(); + tag.put("data", instructions); + buffer.writeNbt(tag); + } + + @Override + protected void applySettings(SequencedGearshiftBlockEntity be) { + if (be.computerBehaviour.hasAttachedComputer()) + return; + + be.run(-1); + be.instructions = Instruction.deserializeAll(instructions); + be.sendData(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/Instruction.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java rename to src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/Instruction.java index e7600dc5d0..a4d4a95227 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/Instruction.java +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/Instruction.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; +package com.simibubi.create.content.kinetics.transmission.sequencer; import java.util.Vector; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.nbt.CompoundTag; @@ -19,36 +19,35 @@ public class Instruction { } public Instruction(SequencerInstructions instruction, int value) { + this(instruction, InstructionSpeedModifiers.FORWARD, value); + } + + public Instruction(SequencerInstructions instruction, InstructionSpeedModifiers speedModifier, int value) { this.instruction = instruction; - speedModifier = InstructionSpeedModifiers.FORWARD; + this.speedModifier = speedModifier; this.value = value; } int getDuration(float currentProgress, float speed) { speed *= speedModifier.value; speed = Math.abs(speed); - double target = value - currentProgress; switch (instruction) { + // Always overshoot, target will stop early case TURN_ANGLE: - double degreesPerTick = KineticTileEntity.convertToAngular(speed); - int ticks = (int) (target / degreesPerTick); - double degreesErr = target - degreesPerTick*ticks; - return ticks + (degreesPerTick > 2*degreesErr ? 0 : 1); - + double degreesPerTick = KineticBlockEntity.convertToAngular(speed); + return (int) Math.ceil(target / degreesPerTick) + 2; case TURN_DISTANCE: - double metersPerTick = KineticTileEntity.convertToLinear(speed); - int offset = speed > 0 && speedModifier.value < 0 ? 1 : 2; - return (int) (target / metersPerTick + offset); + double metersPerTick = KineticBlockEntity.convertToLinear(speed); + return (int) Math.ceil(target / metersPerTick) + 2; + // Timing instructions case DELAY: return (int) target; - case AWAIT: return -1; - case END: default: break; @@ -58,13 +57,13 @@ public class Instruction { } float getTickProgress(float speed) { - switch(instruction) { + switch (instruction) { case TURN_ANGLE: - return KineticTileEntity.convertToAngular(speed); + return KineticBlockEntity.convertToAngular(speed); case TURN_DISTANCE: - return KineticTileEntity.convertToLinear(speed); + return KineticBlockEntity.convertToLinear(speed); case DELAY: return 1; diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/InstructionSpeedModifiers.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/InstructionSpeedModifiers.java new file mode 100644 index 0000000000..8c9c0f0269 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/InstructionSpeedModifiers.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.kinetics.transmission.sequencer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.network.chat.Component; + +public enum InstructionSpeedModifiers { + + FORWARD_FAST(2, ">>"), FORWARD(1, "->"), BACK(-1, "<-"), BACK_FAST(-2, "<<"), + + ; + + String translationKey; + int value; + Component label; + + private InstructionSpeedModifiers(int modifier, Component label) { + this.label = label; + translationKey = "gui.sequenced_gearshift.speed." + Lang.asId(name()); + value = modifier; + } + private InstructionSpeedModifiers(int modifier, String label) { + this.label = Components.literal(label); + translationKey = "gui.sequenced_gearshift.speed." + Lang.asId(name()); + value = modifier; + } + + static List getOptions() { + List options = new ArrayList<>(); + for (InstructionSpeedModifiers entry : values()) + options.add(CreateLang.translateDirect(entry.translationKey)); + return options; + } + + public static InstructionSpeedModifiers getByModifier(int modifier) { + return Arrays.stream(InstructionSpeedModifiers.values()) + .filter(speedModifier -> speedModifier.value == modifier) + .findAny() + .orElse(InstructionSpeedModifiers.FORWARD); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/OnIsPoweredResult.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/OnIsPoweredResult.java new file mode 100644 index 0000000000..328dbad04b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/OnIsPoweredResult.java @@ -0,0 +1,6 @@ +package com.simibubi.create.content.kinetics.transmission.sequencer; + +public enum OnIsPoweredResult { + NOTHING, + CONTINUE +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlock.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlock.java index e732100a56..17ec0903ad 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlock.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; +package com.simibubi.create.content.kinetics.transmission.sequencer; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticBlock; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.kinetics.base.HorizontalAxisKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlock; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.gui.ScreenOpener; import net.minecraft.client.player.LocalPlayer; @@ -37,7 +37,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implements ITE, ITransformableBlock { +public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implements IBE, ITransformableBlock { public static final BooleanProperty VERTICAL = BooleanProperty.create("vertical"); public static final IntegerProperty STATE = IntegerProperty.create("state", 0, 5); @@ -70,7 +70,7 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random r) { boolean previouslyPowered = state.getValue(STATE) != 0; boolean isPowered = worldIn.hasNeighborSignal(pos); - withTileEntityDo(worldIn, pos, sgte -> sgte.onRedstoneUpdate(isPowered, previouslyPowered)); + withBlockEntityDo(worldIn, pos, sgte -> sgte.onRedstoneUpdate(isPowered, previouslyPowered)); } @Override @@ -99,14 +99,14 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen } DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> withTileEntityDo(worldIn, pos, te -> this.displayScreen(te, player))); + () -> () -> withBlockEntityDo(worldIn, pos, be -> this.displayScreen(be, player))); return InteractionResult.SUCCESS; } @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(SequencedGearshiftTileEntity te, Player player) { + protected void displayScreen(SequencedGearshiftBlockEntity be, Player player) { if (player instanceof LocalPlayer) - ScreenOpener.open(new SequencedGearshiftScreen(te)); + ScreenOpener.open(new SequencedGearshiftScreen(be)); } @Override @@ -148,13 +148,13 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen } @Override - public Class getTileEntityClass() { - return SequencedGearshiftTileEntity.class; + public Class getBlockEntityClass() { + return SequencedGearshiftBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SEQUENCED_GEARSHIFT.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SEQUENCED_GEARSHIFT.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlockEntity.java new file mode 100644 index 0000000000..f66683bde1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftBlockEntity.java @@ -0,0 +1,249 @@ +package com.simibubi.create.content.kinetics.transmission.sequencer; + +import java.util.List; +import java.util.Vector; + +import javax.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.transmission.SplitShaftBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class SequencedGearshiftBlockEntity extends SplitShaftBlockEntity { + + Vector instructions; + int currentInstruction; + int currentInstructionDuration; + float currentInstructionProgress; + int timer; + boolean poweredPreviously; + + public AbstractComputerBehaviour computerBehaviour; + + public record SequenceContext(SequencerInstructions instruction, double relativeValue) { + + public static SequenceContext fromGearshift(SequencerInstructions instruction, double kineticSpeed, + int absoluteValue) { + return instruction.needsPropagation() + ? new SequenceContext(instruction, kineticSpeed == 0 ? 0 : absoluteValue / kineticSpeed) + : null; + } + + public double getEffectiveValue(double speedAtTarget) { + return Math.abs(relativeValue * speedAtTarget); + } + + public CompoundTag serializeNBT() { + CompoundTag nbt = new CompoundTag(); + NBTHelper.writeEnum(nbt, "Mode", instruction); + nbt.putDouble("Value", relativeValue); + return nbt; + } + + public static SequenceContext fromNBT(CompoundTag nbt) { + if (nbt.isEmpty()) + return null; + return new SequenceContext(NBTHelper.readEnum(nbt, "Mode", SequencerInstructions.class), + nbt.getDouble("Value")); + } + + } + + public SequencedGearshiftBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + instructions = Instruction.createDefault(); + currentInstruction = -1; + currentInstructionDuration = -1; + currentInstructionProgress = 0; + timer = 0; + poweredPreviously = false; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + } + + @Override + public void tick() { + super.tick(); + + if (isIdle()) + return; + if (level.isClientSide) + return; + if (currentInstructionDuration < 0) + return; + if (timer < currentInstructionDuration) { + timer++; + currentInstructionProgress += getInstruction(currentInstruction).getTickProgress(speed); + return; + } + run(currentInstruction + 1); + } + + @Override + public void onSpeedChanged(float previousSpeed) { + super.onSpeedChanged(previousSpeed); + if (isIdle()) + return; + float currentSpeed = Math.abs(speed); + if (Math.abs(previousSpeed) == currentSpeed) + return; + Instruction instruction = getInstruction(currentInstruction); + if (instruction == null) + return; + if (getSpeed() == 0) + run(-1); + + // Update instruction time with regards to new speed + currentInstructionDuration = instruction.getDuration(currentInstructionProgress, getTheoreticalSpeed()); + timer = 0; + } + + public boolean isIdle() { + return currentInstruction == -1; + } + + public void onRedstoneUpdate(boolean isPowered, boolean isRunning) { + if (computerBehaviour.hasAttachedComputer()) + return; + if (!poweredPreviously && isPowered) + risingFlank(); + poweredPreviously = isPowered; + if (!isIdle()) + return; + if (isPowered == isRunning) + return; + if (!level.hasNeighborSignal(worldPosition)) { + level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, 0), 3); + return; + } + if (getSpeed() == 0) + return; + run(0); + } + + public void risingFlank() { + Instruction instruction = getInstruction(currentInstruction); + if (instruction == null) + return; + if (poweredPreviously) + return; + poweredPreviously = true; + + switch (instruction.onRedstonePulse()) { + case CONTINUE: + run(currentInstruction + 1); + break; + default: + break; + } + } + + public void run(int instructionIndex) { + Instruction instruction = getInstruction(instructionIndex); + if (instruction == null || instruction.instruction == SequencerInstructions.END) { + if (getModifier() != 0) + detachKinetics(); + currentInstruction = -1; + currentInstructionDuration = -1; + currentInstructionProgress = 0; + sequenceContext = null; + timer = 0; + if (!level.hasNeighborSignal(worldPosition)) + level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, 0), 3); + else + sendData(); + return; + } + + detachKinetics(); + currentInstructionDuration = instruction.getDuration(0, getTheoreticalSpeed()); + currentInstruction = instructionIndex; + currentInstructionProgress = 0; + sequenceContext = SequenceContext.fromGearshift(instruction.instruction, getTheoreticalSpeed() * getModifier(), + instruction.value); + timer = 0; + level.setBlock(worldPosition, getBlockState().setValue(SequencedGearshiftBlock.STATE, instructionIndex + 1), 3); + } + + public Instruction getInstruction(int instructionIndex) { + return instructionIndex >= 0 && instructionIndex < instructions.size() ? instructions.get(instructionIndex) + : null; + } + + @Override + protected void copySequenceContextFrom(KineticBlockEntity sourceBE) {} + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("InstructionIndex", currentInstruction); + compound.putInt("InstructionDuration", currentInstructionDuration); + compound.putFloat("InstructionProgress", currentInstructionProgress); + compound.putInt("Timer", timer); + compound.putBoolean("PrevPowered", poweredPreviously); + compound.put("Instructions", Instruction.serializeAll(instructions)); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + currentInstruction = compound.getInt("InstructionIndex"); + currentInstructionDuration = compound.getInt("InstructionDuration"); + currentInstructionProgress = compound.getFloat("InstructionProgress"); + poweredPreviously = compound.getBoolean("PrevPowered"); + timer = compound.getInt("Timer"); + instructions = Instruction.deserializeAll(compound.getList("Instructions", Tag.TAG_COMPOUND)); + super.read(compound, clientPacket); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + + @Override + public float getRotationSpeedModifier(Direction face) { + if (isVirtual()) + return 1; + return (!hasSource() || face == getSourceFacing()) ? 1 : getModifier(); + } + + public int getModifier() { + if (currentInstruction >= instructions.size()) + return 0; + return isIdle() ? 0 + : instructions.get(currentInstruction) + .getSpeedModifier(); + } + + public Vector getInstructions() { + return this.instructions; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftGenerator.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftGenerator.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftGenerator.java rename to src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftGenerator.java index 5c3ce90794..c27cc05a5a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftGenerator.java +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; +package com.simibubi.create.content.kinetics.transmission.sequencer; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftScreen.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftScreen.java new file mode 100644 index 0000000000..99ba2edc22 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencedGearshiftScreen.java @@ -0,0 +1,227 @@ +package com.simibubi.create.content.kinetics.transmission.sequencer; + +import java.util.Vector; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.compat.computercraft.ComputerScreen; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; + +public class SequencedGearshiftScreen extends AbstractSimiScreen { + + private final ItemStack renderedItem = AllBlocks.SEQUENCED_GEARSHIFT.asStack(); + private final AllGuiTextures background = AllGuiTextures.SEQUENCER; + private IconButton confirmButton; + private SequencedGearshiftBlockEntity be; + + private ListTag compareTag; + private Vector instructions; + + private Vector> inputs; + + public SequencedGearshiftScreen(SequencedGearshiftBlockEntity be) { + super(CreateLang.translateDirect("gui.sequenced_gearshift.title")); + this.instructions = be.instructions; + this.be = be; + compareTag = Instruction.serializeAll(instructions); + } + + @Override + protected void init() { + if (be.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen( + new ComputerScreen(title, this::renderAdditional, this, be.computerBehaviour::hasAttachedComputer)); + + setWindowSize(background.getWidth(), background.getHeight()); + setWindowOffset(-20, 0); + super.init(); + + int x = guiLeft; + int y = guiTop; + + inputs = new Vector<>(5); + for (int row = 0; row < inputs.capacity(); row++) + inputs.add(new Vector<>(3)); + + for (int row = 0; row < instructions.size(); row++) + initInputsOfRow(row, x, y); + + confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(() -> { + onClose(); + }); + addRenderableWidget(confirmButton); + } + + public void initInputsOfRow(int row, int backgroundX, int backgroundY) { + int x = backgroundX + 30; + int y = backgroundY + 20; + int rowHeight = 22; + + Vector rowInputs = inputs.get(row); + removeWidgets(rowInputs); + rowInputs.clear(); + int index = row; + Instruction instruction = instructions.get(row); + + ScrollInput type = + new SelectionScrollInput(x, y + rowHeight * row, 50, 18).forOptions(SequencerInstructions.getOptions()) + .calling(state -> instructionUpdated(index, state)) + .setState(instruction.instruction.ordinal()) + .titled(CreateLang.translateDirect("gui.sequenced_gearshift.instruction")); + ScrollInput value = + new ScrollInput(x + 58, y + rowHeight * row, 28, 18).calling(state -> instruction.value = state); + ScrollInput direction = new SelectionScrollInput(x + 88, y + rowHeight * row, 28, 18) + .forOptions(InstructionSpeedModifiers.getOptions()) + .calling(state -> instruction.speedModifier = InstructionSpeedModifiers.values()[state]) + .titled(CreateLang.translateDirect("gui.sequenced_gearshift.speed")); + + rowInputs.add(type); + rowInputs.add(value); + rowInputs.add(direction); + + addRenderableWidgets(rowInputs); + updateParamsOfRow(row); + } + + public void updateParamsOfRow(int row) { + Instruction instruction = instructions.get(row); + Vector rowInputs = inputs.get(row); + SequencerInstructions def = instruction.instruction; + boolean hasValue = def.hasValueParameter; + boolean hasModifier = def.hasSpeedParameter; + + ScrollInput value = rowInputs.get(1); + value.active = value.visible = hasValue; + if (hasValue) + value.withRange(1, def.maxValue + 1) + .titled(CreateLang.translateDirect(def.parameterKey)) + .withShiftStep(def.shiftStep) + .setState(instruction.value) + .onChanged(); + if (def == SequencerInstructions.DELAY) { + value.withStepFunction(context -> { + int v = context.currentValue; + if (!context.forward) + v--; + if (v < 20) + return context.shift ? 20 : 1; + return context.shift ? 100 : 20; + }); + } else + value.withStepFunction(value.standardStep()); + + ScrollInput modifier = rowInputs.get(2); + modifier.active = modifier.visible = hasModifier; + if (hasModifier) + modifier.setState(instruction.speedModifier.ordinal()); + } + + @Override + public void tick() { + super.tick(); + + if (be.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen( + new ComputerScreen(title, this::renderAdditional, this, be.computerBehaviour::hasAttachedComputer)); + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + + for (int row = 0; row < instructions.capacity(); row++) { + AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; + int yOffset = toDraw.getHeight() * row; + + toDraw.render(ms, x, y + 16 + yOffset, this); + } + + for (int row = 0; row < instructions.capacity(); row++) { + AllGuiTextures toDraw = AllGuiTextures.SEQUENCER_EMPTY; + int yOffset = toDraw.getHeight() * row; + if (row >= instructions.size()) { + toDraw.render(ms, x, y + 16 + yOffset, this); + continue; + } + + Instruction instruction = instructions.get(row); + SequencerInstructions def = instruction.instruction; + def.background.render(ms, x, y + 16 + yOffset, this); + + label(ms, 36, yOffset - 1, CreateLang.translateDirect(def.translationKey)); + if (def.hasValueParameter) { + String text = def.formatValue(instruction.value); + int stringWidth = font.width(text); + label(ms, 90 + (12 - stringWidth / 2), yOffset - 1, Components.literal(text)); + } + if (def.hasSpeedParameter) + label(ms, 127, yOffset - 1, instruction.speedModifier.label); + } + + font.draw(ms, title, x + (background.getWidth() - 8) / 2 - font.width(title) / 2, y + 4, 0x592424); + renderAdditional(ms, mouseX, mouseY, partialTicks, x, y, background); + } + + private void renderAdditional(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, + AllGuiTextures background) { + GuiGameElement.of(renderedItem).at(guiLeft + background.getWidth() + 6, guiTop + background.getHeight() - 56, 100) + .scale(5) + .render(ms); + } + + private void label(PoseStack ms, int x, int y, Component text) { + font.drawShadow(ms, text, guiLeft + x, guiTop + 26 + y, 0xFFFFEE); + } + + public void sendPacket() { + ListTag serialized = Instruction.serializeAll(instructions); + if (serialized.equals(compareTag)) + return; + AllPackets.getChannel() + .sendToServer(new ConfigureSequencedGearshiftPacket(be.getBlockPos(), serialized)); + } + + @Override + public void removed() { + sendPacket(); + } + + private void instructionUpdated(int index, int state) { + SequencerInstructions newValue = SequencerInstructions.values()[state]; + instructions.get(index).instruction = newValue; + instructions.get(index).value = newValue.defaultValue; + updateParamsOfRow(index); + if (newValue == SequencerInstructions.END) { + for (int i = instructions.size() - 1; i > index; i--) { + instructions.remove(i); + Vector rowInputs = inputs.get(i); + removeWidgets(rowInputs); + rowInputs.clear(); + } + } else { + if (index + 1 < instructions.capacity() && index + 1 == instructions.size()) { + instructions.add(new Instruction(SequencerInstructions.END)); + initInputsOfRow(index + 1, guiLeft, guiTop); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencerInstructions.java similarity index 92% rename from src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java rename to src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencerInstructions.java index b30479f207..85b69f1b24 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencerInstructions.java +++ b/src/main/java/com/simibubi/create/content/kinetics/transmission/sequencer/SequencerInstructions.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.relays.advanced.sequencer; +package com.simibubi.create.content.kinetics.transmission.sequencer; import java.util.ArrayList; import java.util.List; @@ -46,6 +46,10 @@ public enum SequencerInstructions { parameterKey = translationKey + "." + parameterName; } + public boolean needsPropagation() { + return this == TURN_ANGLE || this == TURN_DISTANCE; + } + static List getOptions() { List options = new ArrayList<>(); for (SequencerInstructions entry : values()) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableBlock.java b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlock.java similarity index 79% rename from src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableBlock.java rename to src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlock.java index b4bc2db988..c7b88bc7f7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableBlock.java +++ b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.turntable; +package com.simibubi.create.content.kinetics.turntable; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.kinetics.base.KineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -25,7 +25,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class TurntableBlock extends KineticBlock implements ITE { +public class TurntableBlock extends KineticBlock implements IBE { public TurntableBlock(Properties properties) { super(properties); @@ -50,8 +50,8 @@ public class TurntableBlock extends KineticBlock implements ITE { - float speed = ((KineticTileEntity) te).getSpeed() * 3 / 10; + withBlockEntityDo(worldIn, pos, be -> { + float speed = ((KineticBlockEntity) be).getSpeed() * 3 / 10; if (speed == 0) return; @@ -99,13 +99,13 @@ public class TurntableBlock extends KineticBlock implements ITE getTileEntityClass() { - return TurntableTileEntity.class; + public Class getBlockEntityClass() { + return TurntableBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TURNTABLE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TURNTABLE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlockEntity.java new file mode 100644 index 0000000000..c2fe73a86f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableBlockEntity.java @@ -0,0 +1,15 @@ +package com.simibubi.create.content.kinetics.turntable; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class TurntableBlockEntity extends KineticBlockEntity { + + public TurntableBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableHandler.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java rename to src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableHandler.java index 510384b50b..9cdf25f56f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/turntable/TurntableHandler.java +++ b/src/main/java/com/simibubi/create/content/kinetics/turntable/TurntableHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.turntable; +package com.simibubi.create.content.kinetics.turntable; import com.simibubi.create.AllBlocks; @@ -23,11 +23,11 @@ public class TurntableHandler { if (mc.isPaused()) return; - BlockEntity tileEntity = mc.level.getBlockEntity(pos); - if (!(tileEntity instanceof TurntableTileEntity)) + BlockEntity blockEntity = mc.level.getBlockEntity(pos); + if (!(blockEntity instanceof TurntableBlockEntity)) return; - TurntableTileEntity turnTable = (TurntableTileEntity) tileEntity; + TurntableBlockEntity turnTable = (TurntableBlockEntity) blockEntity; float speed = turnTable.getSpeed() * 3/10; if (speed == 0) diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlock.java new file mode 100644 index 0000000000..5e2a636d7d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlock.java @@ -0,0 +1,173 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; + +public class LargeWaterWheelBlock extends RotatedPillarKineticBlock implements IBE { + + public static final BooleanProperty EXTENSION = BooleanProperty.create("extension"); + + public LargeWaterWheelBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(EXTENSION, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(EXTENSION)); + } + + public Axis getAxisForPlacement(BlockPlaceContext context) { + return super.getStateForPlacement(context).getValue(AXIS); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState stateForPlacement = super.getStateForPlacement(context); + BlockPos pos = context.getClickedPos(); + Axis axis = stateForPlacement.getValue(AXIS); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + if (axis.choose(x, y, z) != 0) + continue; + BlockPos offset = new BlockPos(x, y, z); + if (offset.equals(BlockPos.ZERO)) + continue; + BlockState occupiedState = context.getLevel() + .getBlockState(pos.offset(offset)); + if (!occupiedState.getMaterial() + .isReplaceable()) + return null; + } + } + } + + if (context.getLevel() + .getBlockState(pos.relative(Direction.fromAxisAndDirection(axis, AxisDirection.NEGATIVE))) + .is(this)) + stateForPlacement = stateForPlacement.setValue(EXTENSION, true); + + return stateForPlacement; + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + return onBlockEntityUse(pLevel, pPos, wwt -> wwt.applyMaterialIfValid(pPlayer.getItemInHand(pHand))); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return InteractionResult.PASS; + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + if (pDirection != Direction.fromAxisAndDirection(pState.getValue(AXIS), AxisDirection.NEGATIVE)) + return pState; + return pState.setValue(EXTENSION, pNeighborState.is(this)); + } + + @Override + public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, level, pos, oldState, isMoving); + if (!level.getBlockTicks() + .hasScheduledTick(pos, this)) + level.scheduleTick(pos, this, 1); + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRandom) { + Axis axis = pState.getValue(AXIS); + for (Direction side : Iterate.directions) { + if (side.getAxis() == axis) + continue; + for (boolean secondary : Iterate.falseAndTrue) { + Direction targetSide = secondary ? side.getClockWise(axis) : side; + BlockPos structurePos = (secondary ? pPos.relative(side) : pPos).relative(targetSide); + BlockState occupiedState = pLevel.getBlockState(structurePos); + BlockState requiredStructure = AllBlocks.WATER_WHEEL_STRUCTURAL.getDefaultState() + .setValue(WaterWheelStructuralBlock.FACING, targetSide.getOpposite()); + if (occupiedState == requiredStructure) + continue; + if (!occupiedState.getMaterial() + .isReplaceable()) { + pLevel.destroyBlock(pPos, false); + return; + } + pLevel.setBlockAndUpdate(structurePos, requiredStructure); + } + } + withBlockEntityDo(pLevel, pPos, WaterWheelBlockEntity::determineAndApplyFlowScore); + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.ENTITYBLOCK_ANIMATED; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.LARGE_WATER_WHEEL.get(); + } + + @Override + public Class getBlockEntityClass() { + return LargeWaterWheelBlockEntity.class; + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return face.getAxis() == getRotationAxis(state); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(AXIS); + } + + @Override + public float getParticleTargetRadius() { + return 2.5f; + } + + @Override + public float getParticleInitialRadius() { + return 2.25f; + } + + public static Couple getSpeedRange() { + return Couple.create(4, 4); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockEntity.java new file mode 100644 index 0000000000..6d21f526d5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockEntity.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class LargeWaterWheelBlockEntity extends WaterWheelBlockEntity { + + public LargeWaterWheelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected int getSize() { + return 2; + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockItem.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockItem.java new file mode 100644 index 0000000000..5a91354a03 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/LargeWaterWheelBlockItem.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.utility.Pair; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class LargeWaterWheelBlockItem extends BlockItem { + + public LargeWaterWheelBlockItem(Block pBlock, Properties pProperties) { + super(pBlock, pProperties); + } + + @Override + public InteractionResult place(BlockPlaceContext ctx) { + InteractionResult result = super.place(ctx); + if (result != InteractionResult.FAIL) + return result; + Direction clickedFace = ctx.getClickedFace(); + if (clickedFace.getAxis() != ((LargeWaterWheelBlock) getBlock()).getAxisForPlacement(ctx)) + result = super.place(BlockPlaceContext.at(ctx, ctx.getClickedPos() + .relative(clickedFace), clickedFace)); + if (result == InteractionResult.FAIL && ctx.getLevel() + .isClientSide()) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> showBounds(ctx)); + return result; + } + + @OnlyIn(Dist.CLIENT) + public void showBounds(BlockPlaceContext context) { + BlockPos pos = context.getClickedPos(); + Axis axis = ((LargeWaterWheelBlock) getBlock()).getAxisForPlacement(context); + Vec3 contract = Vec3.atLowerCornerOf(Direction.get(AxisDirection.POSITIVE, axis) + .getNormal()); + if (!(context.getPlayer()instanceof LocalPlayer localPlayer)) + return; + CatnipClient.OUTLINER.showAABB(Pair.of("waterwheel", pos), new AABB(pos).inflate(1) + .deflate(contract.x, contract.y, contract.z)) + .colored(0xFF_ff5d6c); + CreateLang.translate("large_water_wheel.not_enough_space") + .color(0xFF_ff5d6c) + .sendStatus(localPlayer); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlock.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlock.java new file mode 100644 index 0000000000..185b1fc951 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlock.java @@ -0,0 +1,134 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.worldWrappers.WrappedWorld; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class WaterWheelBlock extends DirectionalKineticBlock implements IBE { + + public WaterWheelBlock(Properties properties) { + super(properties); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader worldIn, BlockPos pos) { + for (Direction direction : Iterate.directions) { + BlockPos neighbourPos = pos.relative(direction); + BlockState neighbourState = worldIn.getBlockState(neighbourPos); + if (!AllBlocks.WATER_WHEEL.has(neighbourState)) + continue; + Axis axis = state.getValue(FACING) + .getAxis(); + if (neighbourState.getValue(FACING) + .getAxis() != axis || axis != direction.getAxis()) + return false; + } + return true; + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + return onBlockEntityUse(pLevel, pPos, wwt -> wwt.applyMaterialIfValid(pPlayer.getItemInHand(pHand))); + } + + @Override + public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn, + BlockPos currentPos, BlockPos facingPos) { + if (worldIn instanceof WrappedWorld) + return stateIn; + if (worldIn.isClientSide()) + return stateIn; + if (!worldIn.getBlockTicks() + .hasScheduledTick(currentPos, this)) + worldIn.scheduleTick(currentPos, this, 1); + return stateIn; + } + + @Override + public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, worldIn, pos, oldState, isMoving); + if (worldIn.isClientSide()) + return; + if (!worldIn.getBlockTicks() + .hasScheduledTick(pos, this)) + worldIn.scheduleTick(pos, this, 1); + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRandom) { + withBlockEntityDo(pLevel, pPos, WaterWheelBlockEntity::determineAndApplyFlowScore); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState state = super.getStateForPlacement(context); + state.setValue(FACING, Direction.get(AxisDirection.POSITIVE, state.getValue(FACING) + .getAxis())); + return state; + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return state.getValue(FACING) + .getAxis() == face.getAxis(); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(FACING) + .getAxis(); + } + + @Override + public float getParticleTargetRadius() { + return 1.125f; + } + + @Override + public float getParticleInitialRadius() { + return 1f; + } + + @Override + public boolean hideStressImpact() { + return true; + } + + @Override + public Class getBlockEntityClass() { + return WaterWheelBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.WATER_WHEEL.get(); + } + + public static Couple getSpeedRange() { + return Couple.create(8, 8); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlockEntity.java new file mode 100644 index 0000000000..a8b3fd074d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelBlockEntity.java @@ -0,0 +1,219 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.fluid.FluidHelper; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.BubbleColumnBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class WaterWheelBlockEntity extends GeneratingKineticBlockEntity { + + public static final Map> SMALL_OFFSETS = new EnumMap<>(Axis.class); + public static final Map> LARGE_OFFSETS = new EnumMap<>(Axis.class); + + static { + for (Axis axis : Iterate.axes) { + HashSet offsets = new HashSet<>(); + for (Direction d : Iterate.directions) + if (d.getAxis() != axis) + offsets.add(BlockPos.ZERO.relative(d)); + SMALL_OFFSETS.put(axis, offsets); + + offsets = new HashSet<>(); + for (Direction d : Iterate.directions) { + if (d.getAxis() == axis) + continue; + BlockPos centralOffset = BlockPos.ZERO.relative(d, 2); + offsets.add(centralOffset); + for (Direction d2 : Iterate.directions) { + if (d2.getAxis() == axis) + continue; + if (d2.getAxis() == d.getAxis()) + continue; + offsets.add(centralOffset.relative(d2)); + } + } + LARGE_OFFSETS.put(axis, offsets); + } + } + + public int flowScore; + public BlockState material; + + public WaterWheelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + material = Blocks.SPRUCE_PLANKS.defaultBlockState(); + setLazyTickRate(60); + } + + protected int getSize() { + return 1; + } + + protected Set getOffsetsToCheck() { + return (getSize() == 1 ? SMALL_OFFSETS : LARGE_OFFSETS).get(getAxis()); + } + + public InteractionResult applyMaterialIfValid(ItemStack stack) { + if (!(stack.getItem()instanceof BlockItem blockItem)) + return InteractionResult.PASS; + BlockState material = blockItem.getBlock() + .defaultBlockState(); + if (material == this.material) + return InteractionResult.PASS; + if (!material.is(BlockTags.PLANKS)) + return InteractionResult.PASS; + if (level.isClientSide() && !isVirtual()) + return InteractionResult.SUCCESS; + this.material = material; + notifyUpdate(); + level.levelEvent(2001, worldPosition, Block.getId(material)); + return InteractionResult.SUCCESS; + } + + protected Axis getAxis() { + Axis axis = Axis.X; + BlockState blockState = getBlockState(); + if (blockState.getBlock()instanceof IRotate irotate) + axis = irotate.getRotationAxis(blockState); + return axis; + } + + @Override + public void lazyTick() { + super.lazyTick(); + + // Water can change flow direction without notifying neighbours + determineAndApplyFlowScore(); + } + + public void determineAndApplyFlowScore() { + Vec3 wheelPlane = + Vec3.atLowerCornerOf(new Vec3i(1, 1, 1).subtract(Direction.get(AxisDirection.POSITIVE, getAxis()) + .getNormal())); + + int flowScore = 0; + boolean lava = false; + for (BlockPos blockPos : getOffsetsToCheck()) { + BlockPos targetPos = blockPos.offset(worldPosition); + Vec3 flowAtPos = getFlowVectorAtPosition(targetPos).multiply(wheelPlane); + lava |= FluidHelper.isLava(level.getFluidState(targetPos) + .getType()); + + if (flowAtPos.lengthSqr() == 0) + continue; + + flowAtPos = flowAtPos.normalize(); + Vec3 normal = Vec3.atLowerCornerOf(blockPos) + .normalize(); + + Vec3 positiveMotion = VecHelper.rotate(normal, 90, getAxis()); + double dot = flowAtPos.dot(positiveMotion); + if (Math.abs(dot) > .5) + flowScore += Math.signum(dot); + } + + if (flowScore != 0 && !level.isClientSide()) + award(lava ? AllAdvancements.LAVA_WHEEL : AllAdvancements.WATER_WHEEL); + + setFlowScoreAndUpdate(flowScore); + } + + public Vec3 getFlowVectorAtPosition(BlockPos pos) { + FluidState fluid = level.getFluidState(pos); + Vec3 vec = fluid.getFlow(level, pos); + BlockState blockState = level.getBlockState(pos); + if (blockState.getBlock() == Blocks.BUBBLE_COLUMN) + vec = new Vec3(0, blockState.getValue(BubbleColumnBlock.DRAG_DOWN) ? -1 : 1, 0); + return vec; + } + + public void setFlowScoreAndUpdate(int score) { + if (flowScore == score) + return; + flowScore = score; + updateGeneratedRotation(); + setChanged(); + } + + private void redraw() { + if (!isVirtual()) + requestModelDataUpdate(); + if (hasLevel()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + level.getChunkSource() + .getLightEngine() + .checkBlock(worldPosition); + } + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.LAVA_WHEEL, AllAdvancements.WATER_WHEEL); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + flowScore = compound.getInt("FlowScore"); + + BlockState prevMaterial = material; + if (!compound.contains("Material")) + return; + + material = NbtUtils.readBlockState(compound.getCompound("Material")); + if (material.isAir()) + material = Blocks.SPRUCE_PLANKS.defaultBlockState(); + + if (clientPacket && prevMaterial != material) + redraw(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("FlowScore", flowScore); + compound.put("Material", NbtUtils.writeBlockState(material)); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).inflate(getSize()); + } + + @Override + public float getGeneratedSpeed() { + return Mth.clamp(flowScore, -1, 1) * 8 / getSize(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelInstance.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelInstance.java new file mode 100644 index 0000000000..6404d0f158 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelInstance.java @@ -0,0 +1,55 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.model.BlockModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.kinetics.base.CutoutRotatingInstance; +import com.simibubi.create.content.kinetics.base.flwdata.RotatingData; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; + +public class WaterWheelInstance extends CutoutRotatingInstance { + protected final boolean large; + protected final WaterWheelModelKey key; + + public WaterWheelInstance(MaterialManager materialManager, T blockEntity, boolean large) { + super(materialManager, blockEntity); + this.large = large; + key = new WaterWheelModelKey(large, getRenderedBlockState(), blockEntity.material); + } + + public static WaterWheelInstance standard(MaterialManager materialManager, T blockEntity) { + return new WaterWheelInstance<>(materialManager, blockEntity, false); + } + + public static WaterWheelInstance large(MaterialManager materialManager, T blockEntity) { + return new WaterWheelInstance<>(materialManager, blockEntity, true); + } + + @Override + public boolean shouldReset() { + return super.shouldReset() || key.material() != blockEntity.material; + } + + @Override + protected Instancer getModel() { + return getRotatingMaterial().model(key, () -> { + BakedModel model = WaterWheelRenderer.generateModel(key); + BlockState state = key.state(); + Direction dir; + if (key.large()) { + dir = Direction.fromAxisAndDirection(state.getValue(LargeWaterWheelBlock.AXIS), AxisDirection.POSITIVE); + } else { + dir = state.getValue(WaterWheelBlock.FACING); + } + PoseStack transform = CachedPartialBuffers.rotateToFaceVertical(dir).get(); + return BlockModel.of(model, Blocks.AIR.defaultBlockState(), transform); + }); + } +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelModelKey.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelModelKey.java new file mode 100644 index 0000000000..4999cb96db --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelModelKey.java @@ -0,0 +1,6 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import net.minecraft.world.level.block.state.BlockState; + +public record WaterWheelModelKey(boolean large, BlockState state, BlockState material) { +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelRenderer.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelRenderer.java new file mode 100644 index 0000000000..1024d66031 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelRenderer.java @@ -0,0 +1,151 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; + +import com.jozufozu.flywheel.core.StitchedSprite; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; +import com.simibubi.create.foundation.model.BakedModelHelper; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import net.createmod.catnip.platform.CatnipServices; +import net.createmod.catnip.render.SuperBufferFactory; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.render.SuperByteBufferCache; +import net.createmod.catnip.render.SuperByteBufferCache.Compartment; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.registries.ForgeRegistries; + +public class WaterWheelRenderer extends KineticBlockEntityRenderer { + public static final Compartment WATER_WHEEL = new Compartment<>(); + + public static final StitchedSprite OAK_PLANKS_TEMPLATE = new StitchedSprite(new ResourceLocation("block/oak_planks")); + public static final StitchedSprite OAK_LOG_TEMPLATE = new StitchedSprite(new ResourceLocation("block/oak_log")); + public static final StitchedSprite OAK_LOG_TOP_TEMPLATE = new StitchedSprite(new ResourceLocation("block/oak_log_top")); + + private static final String[] LOG_SUFFIXES = new String[] { "_log", "_stem" }; + + protected final boolean large; + + public WaterWheelRenderer(Context context, boolean large) { + super(context); + this.large = large; + } + + public static WaterWheelRenderer standard(Context context) { + return new WaterWheelRenderer<>(context, false); + } + + public static WaterWheelRenderer large(Context context) { + return new WaterWheelRenderer<>(context, true); + } + + @Override + protected SuperByteBuffer getRotatedModel(T be, BlockState state) { + WaterWheelModelKey key = new WaterWheelModelKey(large, state, be.material); + return SuperByteBufferCache.getInstance().get(WATER_WHEEL, key, () -> { + BakedModel model = generateModel(key); + BlockState state1 = key.state(); + Direction dir; + if (key.large()) { + dir = Direction.fromAxisAndDirection(state1.getValue(LargeWaterWheelBlock.AXIS), AxisDirection.POSITIVE); + } else { + dir = state1.getValue(WaterWheelBlock.FACING); + } + PoseStack transform = CachedPartialBuffers.rotateToFaceVertical(dir).get(); + return SuperBufferFactory.getInstance().createForBlock(model, Blocks.AIR.defaultBlockState(), transform); + }); + } + + public static BakedModel generateModel(WaterWheelModelKey key) { + BakedModel template; + if (key.large()) { + boolean extension = key.state() + .getValue(LargeWaterWheelBlock.EXTENSION); + if (extension) { + template = AllPartialModels.LARGE_WATER_WHEEL_EXTENSION.get(); + } else { + template = AllPartialModels.LARGE_WATER_WHEEL.get(); + } + } else { + template = AllPartialModels.WATER_WHEEL.get(); + } + + return generateModel(template, key.material()); + } + + public static BakedModel generateModel(BakedModel template, BlockState planksBlockState) { + Block planksBlock = planksBlockState.getBlock(); + ResourceLocation id = CatnipServices.REGISTRIES.getKeyOrThrow(planksBlock); + String path = id.getPath(); + + if (path.endsWith("_planks")) { + String namespace = id.getNamespace(); + String wood = path.substring(0, path.length() - 7); + BlockState logBlockState = getLogBlockState(namespace, wood); + + Map map = new Reference2ReferenceOpenHashMap<>(); + map.put(OAK_PLANKS_TEMPLATE.get(), getSpriteOnSide(planksBlockState, Direction.UP)); + map.put(OAK_LOG_TEMPLATE.get(), getSpriteOnSide(logBlockState, Direction.SOUTH)); + map.put(OAK_LOG_TOP_TEMPLATE.get(), getSpriteOnSide(logBlockState, Direction.UP)); + + return BakedModelHelper.generateModel(template, map::get); + } + + return BakedModelHelper.generateModel(template, sprite -> null); + } + + private static BlockState getLogBlockState(String namespace, String wood) { + for (String suffix : LOG_SUFFIXES) { + Optional state = + ForgeRegistries.BLOCKS.getHolder(new ResourceLocation(namespace, wood + suffix)) + .map(Holder::value) + .map(Block::defaultBlockState); + if (state.isPresent()) + return state.get(); + } + return Blocks.OAK_LOG.defaultBlockState(); + } + + private static TextureAtlasSprite getSpriteOnSide(BlockState state, Direction side) { + BakedModel model = Minecraft.getInstance() + .getBlockRenderer() + .getBlockModel(state); + if (model == null) + return null; + Random random = new Random(42L); + List quads = model.getQuads(state, side, random, EmptyModelData.INSTANCE); + if (!quads.isEmpty()) { + return quads.get(0) + .getSprite(); + } + random.setSeed(42L); + quads = model.getQuads(state, null, random, EmptyModelData.INSTANCE); + if (!quads.isEmpty()) { + for (BakedQuad quad : quads) { + if (quad.getDirection() == side) { + return quad.getSprite(); + } + } + } + return model.getParticleIcon(EmptyModelData.INSTANCE); + } + +} diff --git a/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelStructuralBlock.java b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelStructuralBlock.java new file mode 100644 index 0000000000..e3bf3827a2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/kinetics/waterwheel/WaterWheelStructuralBlock.java @@ -0,0 +1,209 @@ +package com.simibubi.create.content.kinetics.waterwheel; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.function.Consumer; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.equipment.goggles.IProxyHoveringInformation; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DirectionalBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.IBlockRenderProperties; + +public class WaterWheelStructuralBlock extends DirectionalBlock implements IWrenchable, IProxyHoveringInformation { + + public WaterWheelStructuralBlock(Properties p_52591_) { + super(p_52591_); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(FACING)); + } + + @Override + public RenderShape getRenderShape(BlockState pState) { + return RenderShape.INVISIBLE; + } + + @Override + public PushReaction getPistonPushReaction(BlockState pState) { + return PushReaction.BLOCK; + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return InteractionResult.PASS; + } + + @Override + public ItemStack getCloneItemStack(BlockGetter pLevel, BlockPos pPos, BlockState pState) { + return AllBlocks.LARGE_WATER_WHEEL.asStack(); + } + + @Override + public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { + BlockPos clickedPos = context.getClickedPos(); + Level level = context.getLevel(); + + if (stillValid(level, clickedPos, state, false)) { + BlockPos masterPos = getMaster(level, clickedPos, state); + context = new UseOnContext(level, context.getPlayer(), context.getHand(), context.getItemInHand(), + new BlockHitResult(context.getClickLocation(), context.getClickedFace(), masterPos, + context.isInside())); + state = level.getBlockState(masterPos); + } + + return IWrenchable.super.onSneakWrenched(state, context); + } + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + if (!stillValid(pLevel, pPos, pState, false)) + return InteractionResult.FAIL; + if (!(pLevel.getBlockEntity(getMaster(pLevel, pPos, pState))instanceof WaterWheelBlockEntity wwt)) + return InteractionResult.FAIL; + return wwt.applyMaterialIfValid(pPlayer.getItemInHand(pHand)); + } + + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + if (stillValid(pLevel, pPos, pState, false)) + pLevel.destroyBlock(getMaster(pLevel, pPos, pState), true); + } + + public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { + if (stillValid(pLevel, pPos, pState, false)) { + BlockPos masterPos = getMaster(pLevel, pPos, pState); + pLevel.destroyBlockProgress(masterPos.hashCode(), masterPos, -1); + if (!pLevel.isClientSide() && pPlayer.isCreative()) + pLevel.destroyBlock(masterPos, false); + } + super.playerWillDestroy(pLevel, pPos, pState, pPlayer); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel, + BlockPos pCurrentPos, BlockPos pFacingPos) { + if (stillValid(pLevel, pCurrentPos, pState, false)) { + BlockPos masterPos = getMaster(pLevel, pCurrentPos, pState); + if (!pLevel.getBlockTicks() + .hasScheduledTick(masterPos, AllBlocks.LARGE_WATER_WHEEL.get())) + pLevel.scheduleTick(masterPos, AllBlocks.LARGE_WATER_WHEEL.get(), 1); + return pState; + } + if (!(pLevel instanceof Level level) || level.isClientSide()) + return pState; + if (!level.getBlockTicks() + .hasScheduledTick(pCurrentPos, this)) + level.scheduleTick(pCurrentPos, this, 1); + return pState; + } + + public static BlockPos getMaster(BlockGetter level, BlockPos pos, BlockState state) { + Direction direction = state.getValue(FACING); + BlockPos targetedPos = pos.relative(direction); + BlockState targetedState = level.getBlockState(targetedPos); + if (targetedState.is(AllBlocks.WATER_WHEEL_STRUCTURAL.get())) + return getMaster(level, targetedPos, targetedState); + return targetedPos; + } + + public boolean stillValid(BlockGetter level, BlockPos pos, BlockState state, boolean directlyAdjacent) { + if (!state.is(this)) + return false; + + Direction direction = state.getValue(FACING); + BlockPos targetedPos = pos.relative(direction); + BlockState targetedState = level.getBlockState(targetedPos); + + if (!directlyAdjacent && stillValid(level, targetedPos, targetedState, true)) + return true; + return targetedState.getBlock() instanceof LargeWaterWheelBlock + && targetedState.getValue(LargeWaterWheelBlock.AXIS) != direction.getAxis(); + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRandom) { + if (!stillValid(pLevel, pPos, pState, false)) + pLevel.setBlockAndUpdate(pPos, Blocks.AIR.defaultBlockState()); + } + + @OnlyIn(Dist.CLIENT) + public void initializeClient(Consumer consumer) { + consumer.accept(new RenderProperties()); + } + + @Override + public boolean addLandingEffects(BlockState state1, ServerLevel level, BlockPos pos, BlockState state2, + LivingEntity entity, int numberOfParticles) { + return true; + } + + public static class RenderProperties implements IBlockRenderProperties, MultiPosDestructionHandler { + + @Override + public boolean addDestroyEffects(BlockState state, Level Level, BlockPos pos, ParticleEngine manager) { + return true; + } + + @Override + public boolean addHitEffects(BlockState state, Level level, HitResult target, ParticleEngine manager) { + if (target instanceof BlockHitResult bhr) { + BlockPos targetPos = bhr.getBlockPos(); + WaterWheelStructuralBlock waterWheelStructuralBlock = AllBlocks.WATER_WHEEL_STRUCTURAL.get(); + if (waterWheelStructuralBlock.stillValid(level, targetPos, state, false)) + manager.crack(WaterWheelStructuralBlock.getMaster(level, targetPos, state), bhr.getDirection()); + return true; + } + return IBlockRenderProperties.super.addHitEffects(state, level, target, manager); + } + + @Override + @Nullable + public Set getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress) { + WaterWheelStructuralBlock waterWheelStructuralBlock = AllBlocks.WATER_WHEEL_STRUCTURAL.get(); + if (!waterWheelStructuralBlock.stillValid(level, pos, blockState, false)) + return null; + HashSet set = new HashSet<>(); + set.add(WaterWheelStructuralBlock.getMaster(level, pos, blockState)); + return set; + } + } + + @Override + public BlockPos getInformationSource(Level level, BlockPos pos, BlockState state) { + return stillValid(level, pos, state, false) ? getMaster(level, pos, state) : pos; + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java b/src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundColor.java similarity index 95% rename from src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java rename to src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundColor.java index 1b9e1a44e6..ef5e35d5ca 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundColor.java +++ b/src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundColor.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.legacy; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.theme.Color; diff --git a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundItem.java b/src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundItem.java similarity index 87% rename from src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundItem.java rename to src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundItem.java index 4b66b0d05b..c39a87247b 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/ChromaticCompoundItem.java +++ b/src/main/java/com/simibubi/create/content/legacy/ChromaticCompoundItem.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.legacy; import java.util.Random; import org.apache.commons.lang3.mutable.MutableBoolean; import com.simibubi.create.AllItems; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CRecipes; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CRecipes; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.theme.Color; @@ -57,13 +57,13 @@ public class ChromaticCompoundItem extends Item { @Override public int getBarWidth(ItemStack stack) { - return Math.round(13.0F * getLight(stack) / AllConfigs.SERVER.recipes.lightSourceCountForRefinedRadiance.get()); + return Math.round(13.0F * getLight(stack) / AllConfigs.server().recipes.lightSourceCountForRefinedRadiance.get()); } @Override public int getBarColor(ItemStack stack) { return Color.mixColors(0x413c69, 0xFFFFFF, - getLight(stack) / (float) AllConfigs.SERVER.recipes.lightSourceCountForRefinedRadiance.get()); + getLight(stack) / (float) AllConfigs.server().recipes.lightSourceCountForRefinedRadiance.get()); } @Override @@ -77,7 +77,7 @@ public class ChromaticCompoundItem extends Item { CompoundTag itemData = entity.getItem() .getOrCreateTag(); Vec3 positionVec = entity.position(); - CRecipes config = AllConfigs.SERVER.recipes; + CRecipes config = AllConfigs.server().recipes; if (world.isClientSide) { int light = itemData.getInt("CollectingLight"); @@ -139,12 +139,12 @@ public class ChromaticCompoundItem extends Item { if (state.getLightBlock(world, testPos) >= 15 && state.getBlock() != Blocks.BEDROCK) break; if (state.getBlock() == Blocks.BEACON) { - BlockEntity te = world.getBlockEntity(testPos); + BlockEntity be = world.getBlockEntity(testPos); - if (!(te instanceof BeaconBlockEntity)) + if (!(be instanceof BeaconBlockEntity)) break; - BeaconBlockEntity bte = (BeaconBlockEntity) te; + BeaconBlockEntity bte = (BeaconBlockEntity) be; if (!bte.beamSections.isEmpty()) isOverBeacon = true; @@ -172,7 +172,7 @@ public class ChromaticCompoundItem extends Item { BlockState state = world.getBlockState(randomOffset); TransportedItemStackHandlerBehaviour behaviour = - TileEntityBehaviour.get(world, randomOffset, TransportedItemStackHandlerBehaviour.TYPE); + BlockEntityBehaviour.get(world, randomOffset, TransportedItemStackHandlerBehaviour.TYPE); // Find a placed light source if (behaviour == null) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/NoGravMagicalDohickyItem.java b/src/main/java/com/simibubi/create/content/legacy/NoGravMagicalDohickyItem.java similarity index 97% rename from src/main/java/com/simibubi/create/content/curiosities/NoGravMagicalDohickyItem.java rename to src/main/java/com/simibubi/create/content/legacy/NoGravMagicalDohickyItem.java index 6bdae263fc..adcf781ad2 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/NoGravMagicalDohickyItem.java +++ b/src/main/java/com/simibubi/create/content/legacy/NoGravMagicalDohickyItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.legacy; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.NonNullList; diff --git a/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java b/src/main/java/com/simibubi/create/content/legacy/RefinedRadianceItem.java similarity index 91% rename from src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java rename to src/main/java/com/simibubi/create/content/legacy/RefinedRadianceItem.java index 03ca5850bb..577f0051c5 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/RefinedRadianceItem.java +++ b/src/main/java/com/simibubi/create/content/legacy/RefinedRadianceItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.legacy; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.item.ItemEntity; diff --git a/src/main/java/com/simibubi/create/content/curiosities/ShadowSteelItem.java b/src/main/java/com/simibubi/create/content/legacy/ShadowSteelItem.java similarity index 93% rename from src/main/java/com/simibubi/create/content/curiosities/ShadowSteelItem.java rename to src/main/java/com/simibubi/create/content/legacy/ShadowSteelItem.java index fa7c42ca87..9d85d2b1a4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/ShadowSteelItem.java +++ b/src/main/java/com/simibubi/create/content/legacy/ShadowSteelItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.legacy; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; diff --git a/src/main/java/com/simibubi/create/content/logistics/IRedstoneLinkable.java b/src/main/java/com/simibubi/create/content/logistics/IRedstoneLinkable.java deleted file mode 100644 index dc1ffbd161..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/IRedstoneLinkable.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.simibubi.create.content.logistics; - -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler.Frequency; - -import net.createmod.catnip.utility.Couple; -import net.minecraft.core.BlockPos; - -public interface IRedstoneLinkable { - - public int getTransmittedStrength(); - - public void setReceivedStrength(int power); - - public boolean isListening(); - - public boolean isAlive(); - - public Couple getNetworkKey(); - - public BlockPos getLocation(); - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java deleted file mode 100644 index adf1f92b81..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelRenderer.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; - -public class BeltTunnelRenderer extends SmartTileEntityRenderer { - - public BeltTunnelRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(BeltTunnelTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(te.getLevel())) - return; - - SuperByteBuffer flapBuffer = CachedPartialBuffers.partial(AllBlockPartials.BELT_TUNNEL_FLAP, te.getBlockState()); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - Vec3 pivot = VecHelper.voxelSpace(0, 10, 1f); - TransformStack msr = TransformStack.cast(ms); - - for (Direction direction : Iterate.directions) { - if (!te.flaps.containsKey(direction)) - continue; - - float horizontalAngle = AngleHelper.horizontalAngle(direction.getOpposite()); - float f = te.flaps.get(direction) - .getValue(partialTicks); - - ms.pushPose(); - msr.centre() - .rotateY(horizontalAngle) - .unCentre(); - - for (int segment = 0; segment <= 3; segment++) { - ms.pushPose(); - float intensity = segment == 3 ? 1.5f : segment + 1; - float abs = Math.abs(f); - float flapAngle = Mth.sin((float) ((1 - abs) * Math.PI * intensity)) * 30 * f - * (direction.getAxis() == Axis.X ? 1 : -1); - if (f > 0) - flapAngle *= .5f; - - msr.translate(pivot) - .rotateX(flapAngle) - .translateBack(pivot); - flapBuffer.light(light) - .renderInto(ms, vb); - - ms.popPose(); - ms.translate(-3 / 16f, 0, 0); - } - ms.popPose(); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java deleted file mode 100644 index d0862593ea..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java +++ /dev/null @@ -1,212 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.tuple.Pair; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.packet.TunnelFlapPacket; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.IntTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class BeltTunnelTileEntity extends SmartTileEntity { - - public Map flaps; - public Set sides; - - protected LazyOptional cap = LazyOptional.empty(); - protected List> flapsToSend; - - public BeltTunnelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - flaps = new EnumMap<>(Direction.class); - sides = new HashSet<>(); - flapsToSend = new LinkedList<>(); - } - - @Override - public void setRemoved() { - super.setRemoved(); - cap.invalidate(); - } - - protected void writeFlapsAndSides(CompoundTag compound) { - ListTag flapsNBT = new ListTag(); - for (Direction direction : flaps.keySet()) - flapsNBT.add(IntTag.valueOf(direction.get3DDataValue())); - compound.put("Flaps", flapsNBT); - - ListTag sidesNBT = new ListTag(); - for (Direction direction : sides) - sidesNBT.add(IntTag.valueOf(direction.get3DDataValue())); - compound.put("Sides", sidesNBT); - } - - @Override - public void writeSafe(CompoundTag tag) { - writeFlapsAndSides(tag); - super.writeSafe(tag); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - writeFlapsAndSides(compound); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - Set newFlaps = new HashSet<>(6); - ListTag flapsNBT = compound.getList("Flaps", Tag.TAG_INT); - for (Tag inbt : flapsNBT) - if (inbt instanceof IntTag) - newFlaps.add(Direction.from3DDataValue(((IntTag) inbt).getAsInt())); - - sides.clear(); - ListTag sidesNBT = compound.getList("Sides", Tag.TAG_INT); - for (Tag inbt : sidesNBT) - if (inbt instanceof IntTag) - sides.add(Direction.from3DDataValue(((IntTag) inbt).getAsInt())); - - for (Direction d : Iterate.directions) - if (!newFlaps.contains(d)) - flaps.remove(d); - else if (!flaps.containsKey(d)) - flaps.put(d, createChasingFlap()); - - // Backwards compat - if (!compound.contains("Sides") && compound.contains("Flaps")) - sides.addAll(flaps.keySet()); - super.read(compound, clientPacket); - if (clientPacket) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - } - - private LerpedFloat createChasingFlap() { - return LerpedFloat.linear() - .startWithValue(.25f) - .chase(0, .05f, Chaser.EXP); - } - - public void updateTunnelConnections() { - flaps.clear(); - sides.clear(); - BlockState tunnelState = getBlockState(); - for (Direction direction : Iterate.horizontalDirections) { - if (direction.getAxis() != tunnelState.getValue(BlockStateProperties.HORIZONTAL_AXIS)) { - boolean positive = - direction.getAxisDirection() == AxisDirection.POSITIVE ^ direction.getAxis() == Axis.Z; - Shape shape = tunnelState.getValue(BeltTunnelBlock.SHAPE); - if (BeltTunnelBlock.isStraight(tunnelState)) - continue; - if (positive && shape == Shape.T_LEFT) - continue; - if (!positive && shape == Shape.T_RIGHT) - continue; - } - - sides.add(direction); - - // Flap might be occluded - BlockState nextState = level.getBlockState(worldPosition.relative(direction)); - if (nextState.getBlock() instanceof BeltTunnelBlock) - continue; - if (nextState.getBlock() instanceof BeltFunnelBlock) - if (nextState.getValue(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED - && nextState.getValue(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite()) - continue; - - flaps.put(direction, createChasingFlap()); - } - sendData(); - } - - public void flap(Direction side, boolean inward) { - if (level.isClientSide) { - if (flaps.containsKey(side)) - flaps.get(side) - .setValue(inward ^ side.getAxis() == Axis.Z ? -1 : 1); - return; - } - - flapsToSend.add(Pair.of(side, inward)); - } - - @Override - public void initialize() { - super.initialize(); - updateTunnelConnections(); - } - - @Override - public void tick() { - super.tick(); - if (!level.isClientSide) { - if (!flapsToSend.isEmpty()) - sendFlaps(); - return; - } - flaps.forEach((d, value) -> value.tickChaser()); - } - - private void sendFlaps() { - AllPackets.channel.send(packetTarget(), new TunnelFlapPacket(this, flapsToSend)); - - flapsToSend.clear(); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public LazyOptional getCapability(Capability capability, Direction side) { - if (capability != CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return super.getCapability(capability, side); - - if (!this.cap.isPresent()) { - if (AllBlocks.BELT.has(level.getBlockState(worldPosition.below()))) { - BlockEntity teBelow = level.getBlockEntity(worldPosition.below()); - if (teBelow != null) { - T capBelow = teBelow.getCapability(capability, Direction.UP) - .orElse(null); - if (capBelow != null) { - cap = LazyOptional.of(() -> capBelow) - .cast(); - } - } - } - } - return this.cap.cast(); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelBlock.java deleted file mode 100644 index dece4a44e5..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelBlock.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import java.util.List; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; - -public class BrassTunnelBlock extends BeltTunnelBlock { - - public BrassTunnelBlock(BlockBehaviour.Properties properties) { - super(properties); - } - - @Override - public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, - InteractionHand p_225533_5_, BlockHitResult p_225533_6_) { - return onTileEntityUse(world, pos, te -> { - if (!(te instanceof BrassTunnelTileEntity)) - return InteractionResult.PASS; - BrassTunnelTileEntity bte = (BrassTunnelTileEntity) te; - List stacksOfGroup = bte.grabAllStacksOfGroup(world.isClientSide); - if (stacksOfGroup.isEmpty()) - return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; - for (ItemStack itemStack : stacksOfGroup) - player.getInventory().placeItemBackInInventory(itemStack.copy()); - world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, - 1f + world.random.nextFloat()); - return InteractionResult.SUCCESS; - }); - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.BRASS_TUNNEL.get(); - } - - @Override - public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor worldIn, - BlockPos currentPos, BlockPos facingPos) { - return super.updateShape(state, facing, facingState, worldIn, currentPos, facingPos); - } - - @Override - public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.hasBlockEntity() && (state.getBlock() != newState.getBlock() || !newState.hasBlockEntity())) { - TileEntityBehaviour.destroy(level, pos, FilteringBehaviour.TYPE); - withTileEntityDo(level, pos, te -> { - if (!(te instanceof BrassTunnelTileEntity btte)) - return; - Block.popResource(level, pos, btte.stackToDistribute); - btte.stackEnteredFrom = null; - }); - level.removeBlockEntity(pos); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelCTBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelCTBehaviour.java deleted file mode 100644 index a903c74976..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelCTBehaviour.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import org.jetbrains.annotations.Nullable; - -import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; -import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -public class BrassTunnelCTBehaviour extends ConnectedTextureBehaviour.Base { - - @Override - public CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite) { - return direction == Direction.UP ? AllSpriteShifts.BRASS_TUNNEL_TOP : null; - } - - @Override - public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, - Direction face) { - int yDiff = otherPos.getY() - pos.getY(); - int zDiff = otherPos.getZ() - pos.getZ(); - if (yDiff != 0) - return false; - - BlockEntity te = reader.getBlockEntity(pos); - if (!(te instanceof BrassTunnelTileEntity)) - return false; - BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) te; - boolean leftSide = zDiff > 0; - return tunnelTE.isConnected(leftSide); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelFilterSlot.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelFilterSlot.java deleted file mode 100644 index 4ce492fcc9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelFilterSlot.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.world.phys.Vec3; - -public class BrassTunnelFilterSlot extends ValueBoxTransform.Sided { - - @Override - protected Vec3 getSouthLocation() { - return VecHelper.voxelSpace(8, 13, 15.5f); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java deleted file mode 100644 index c9d7b10175..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelItemHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; - -public class BrassTunnelItemHandler implements IItemHandler { - - private BrassTunnelTileEntity te; - - public BrassTunnelItemHandler(BrassTunnelTileEntity te) { - this.te = te; - } - - @Override - public int getSlots() { - return 1; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return te.stackToDistribute; - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (!te.hasDistributionBehaviour()) { - LazyOptional beltCapability = te.getBeltCapability(); - if (!beltCapability.isPresent()) - return stack; - return beltCapability.orElse(null).insertItem(slot, stack, simulate); - } - - if (!te.canTakeItems()) - return stack; - if (!simulate) - te.setStackToDistribute(stack, null); - return ItemStack.EMPTY; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - LazyOptional beltCapability = te.getBeltCapability(); - if (!beltCapability.isPresent()) - return ItemStack.EMPTY; - return beltCapability.orElse(null).extractItem(slot, amount, simulate); - } - - @Override - public int getSlotLimit(int slot) { - return te.stackToDistribute.isEmpty() ? 64 : te.stackToDistribute.getMaxStackSize(); - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java deleted file mode 100644 index 75b3acd97c..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java +++ /dev/null @@ -1,795 +0,0 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.SidedFilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.BlockHelper; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -public class BrassTunnelTileEntity extends BeltTunnelTileEntity implements IHaveGoggleInformation { - - SidedFilteringBehaviour filtering; - - boolean connectedLeft; - boolean connectedRight; - - ItemStack stackToDistribute; - Direction stackEnteredFrom; - - float distributionProgress; - int distributionDistanceLeft; - int distributionDistanceRight; - int previousOutputIndex; - - // - Couple>> distributionTargets; - - private boolean syncedOutputActive; - private Set syncSet; - - protected ScrollOptionBehaviour selectionMode; - private LazyOptional beltCapability; - private LazyOptional tunnelCapability; - - public BrassTunnelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - distributionTargets = Couple.create(ArrayList::new); - syncSet = new HashSet<>(); - stackToDistribute = ItemStack.EMPTY; - stackEnteredFrom = null; - beltCapability = LazyOptional.empty(); - tunnelCapability = LazyOptional.of(() -> new BrassTunnelItemHandler(this)); - previousOutputIndex = 0; - syncedOutputActive = false; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - behaviours.add(selectionMode = new ScrollOptionBehaviour<>(SelectionMode.class, - CreateLang.translateDirect("logistics.when_multiple_outputs_available"), this, - new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP))); - selectionMode.requiresWrench(); - - // Propagate settings across connected tunnels - selectionMode.withCallback(setting -> { - for (boolean side : Iterate.trueAndFalse) { - if (!isConnected(side)) - continue; - BrassTunnelTileEntity adjacent = getAdjacent(side); - if (adjacent != null) - adjacent.selectionMode.setValue(setting); - } - }); - } - - @Override - public void tick() { - super.tick(); - BeltTileEntity beltBelow = BeltHelper.getSegmentTE(level, worldPosition.below()); - - if (distributionProgress > 0) - distributionProgress--; - if (beltBelow == null || beltBelow.getSpeed() == 0) - return; - if (stackToDistribute.isEmpty() && !syncedOutputActive) - return; - if (level.isClientSide && !isVirtual()) - return; - - if (distributionProgress == -1) { - distributionTargets.forEach(List::clear); - distributionDistanceLeft = 0; - distributionDistanceRight = 0; - - syncSet.clear(); - List> validOutputs = gatherValidOutputs(); - if (selectionMode.get() == SelectionMode.SYNCHRONIZE) { - boolean allEmpty = true; - boolean allFull = true; - for (BrassTunnelTileEntity te : syncSet) { - boolean hasStack = !te.stackToDistribute.isEmpty(); - allEmpty &= !hasStack; - allFull &= hasStack; - } - final boolean notifySyncedOut = !allEmpty; - if (allFull || allEmpty) - syncSet.forEach(te -> te.syncedOutputActive = notifySyncedOut); - } - - if (validOutputs == null) - return; - if (stackToDistribute.isEmpty()) - return; - - for (Pair pair : validOutputs) { - BrassTunnelTileEntity tunnel = pair.getKey(); - Direction output = pair.getValue(); - if (insertIntoTunnel(tunnel, output, stackToDistribute, true) == null) - continue; - distributionTargets.get(!tunnel.flapFilterEmpty(output)) - .add(Pair.of(tunnel.worldPosition, output)); - int distance = tunnel.worldPosition.getX() + tunnel.worldPosition.getZ() - worldPosition.getX() - worldPosition.getZ(); - if (distance < 0) - distributionDistanceLeft = Math.max(distributionDistanceLeft, -distance); - else - distributionDistanceRight = Math.max(distributionDistanceRight, distance); - } - - if (distributionTargets.getFirst() - .isEmpty() - && distributionTargets.getSecond() - .isEmpty()) - return; - - if (selectionMode.get() != SelectionMode.SYNCHRONIZE || syncedOutputActive) { - distributionProgress = 10; - sendData(); - } - return; - } - - if (distributionProgress != 0) - return; - - distributionTargets.forEach(list -> { - if (stackToDistribute.isEmpty()) - return; - List> validTargets = new ArrayList<>(); - for (Pair pair : list) { - BlockPos tunnelPos = pair.getKey(); - Direction output = pair.getValue(); - if (tunnelPos.equals(worldPosition) && output == stackEnteredFrom) - continue; - BlockEntity te = level.getBlockEntity(tunnelPos); - if (!(te instanceof BrassTunnelTileEntity)) - continue; - validTargets.add(Pair.of((BrassTunnelTileEntity) te, output)); - } - distribute(validTargets); - distributionProgress = -1; - }); - } - - private static Random rand = new Random(); - private static Map, ItemStack> distributed = new IdentityHashMap<>(); - private static Set> full = new HashSet<>(); - - private void distribute(List> validTargets) { - int amountTargets = validTargets.size(); - if (amountTargets == 0) - return; - - distributed.clear(); - full.clear(); - - int indexStart = previousOutputIndex % amountTargets; - SelectionMode mode = selectionMode.get(); - boolean force = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.FORCED_SPLIT; - boolean split = mode == SelectionMode.FORCED_SPLIT || mode == SelectionMode.SPLIT; - boolean robin = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.ROUND_ROBIN; - - if (mode == SelectionMode.RANDOMIZE) - indexStart = rand.nextInt(amountTargets); - if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE) - indexStart = 0; - - ItemStack toDistribute = stackToDistribute.copy(); - for (boolean distributeAgain : Iterate.trueAndFalse) { - ItemStack toDistributeThisCycle = null; - int remainingOutputs = amountTargets; - int leftovers = 0; - - for (boolean simulate : Iterate.trueAndFalse) { - if (remainingOutputs == 0) - break; - - leftovers = 0; - int index = indexStart; - int stackSize = toDistribute.getCount(); - int splitStackSize = stackSize / remainingOutputs; - int splitRemainder = stackSize % remainingOutputs; - int visited = 0; - - toDistributeThisCycle = toDistribute.copy(); - if (!(force || split) && simulate) - continue; - - while (visited < amountTargets) { - Pair pair = validTargets.get(index); - BrassTunnelTileEntity tunnel = pair.getKey(); - Direction side = pair.getValue(); - index = (index + 1) % amountTargets; - visited++; - - if (full.contains(pair)) { - if (split && simulate) - remainingOutputs--; - continue; - } - - int count = split ? splitStackSize + (splitRemainder > 0 ? 1 : 0) : stackSize; - ItemStack toOutput = ItemHandlerHelper.copyStackWithSize(toDistributeThisCycle, count); - - // Grow by 1 to determine if target is full even after a successful transfer - boolean testWithIncreasedCount = distributed.containsKey(pair); - int increasedCount = testWithIncreasedCount ? distributed.get(pair) - .getCount() : 0; - if (testWithIncreasedCount) - toOutput.grow(increasedCount); - - ItemStack remainder = insertIntoTunnel(tunnel, side, toOutput, true); - - if (remainder == null || remainder.getCount() == (testWithIncreasedCount ? count + 1 : count)) { - if (force) - return; - if (split && simulate) - remainingOutputs--; - if (!simulate) - full.add(pair); - if (robin) - break; - continue; - } else if (!remainder.isEmpty() && !simulate) { - full.add(pair); - } - - if (!simulate) { - toOutput.shrink(remainder.getCount()); - distributed.put(pair, toOutput); - } - - leftovers += remainder.getCount(); - toDistributeThisCycle.shrink(count); - if (toDistributeThisCycle.isEmpty()) - break; - splitRemainder--; - if (!split) - break; - } - } - - toDistribute.setCount(toDistributeThisCycle.getCount() + leftovers); - if (leftovers == 0 && distributeAgain) - break; - if (!split) - break; - } - - int failedTransferrals = 0; - for (Entry, ItemStack> entry : distributed.entrySet()) { - Pair pair = entry.getKey(); - failedTransferrals += insertIntoTunnel(pair.getKey(), pair.getValue(), entry.getValue(), false).getCount(); - } - - toDistribute.grow(failedTransferrals); - stackToDistribute = ItemHandlerHelper.copyStackWithSize(stackToDistribute, toDistribute.getCount()); - if (stackToDistribute.isEmpty()) - stackEnteredFrom = null; - previousOutputIndex++; - previousOutputIndex %= amountTargets; - notifyUpdate(); - } - - public void setStackToDistribute(ItemStack stack, @Nullable Direction enteredFrom) { - stackToDistribute = stack; - stackEnteredFrom = enteredFrom; - distributionProgress = -1; - sendData(); - setChanged(); - } - - public ItemStack getStackToDistribute() { - return stackToDistribute; - } - - public List grabAllStacksOfGroup(boolean simulate) { - List list = new ArrayList<>(); - - ItemStack own = getStackToDistribute(); - if (!own.isEmpty()) { - list.add(own); - if (!simulate) - setStackToDistribute(ItemStack.EMPTY, null); - } - - for (boolean left : Iterate.trueAndFalse) { - BrassTunnelTileEntity adjacent = this; - while (adjacent != null) { - if (!level.isLoaded(adjacent.getBlockPos())) - return null; - adjacent = adjacent.getAdjacent(left); - if (adjacent == null) - continue; - ItemStack other = adjacent.getStackToDistribute(); - if (other.isEmpty()) - continue; - list.add(other); - if (!simulate) - adjacent.setStackToDistribute(ItemStack.EMPTY, null); - } - } - - return list; - } - - @Nullable - protected ItemStack insertIntoTunnel(BrassTunnelTileEntity tunnel, Direction side, ItemStack stack, - boolean simulate) { - if (stack.isEmpty()) - return stack; - if (!tunnel.testFlapFilter(side, stack)) - return null; - - BeltTileEntity below = BeltHelper.getSegmentTE(level, tunnel.worldPosition.below()); - if (below == null) - return null; - BlockPos offset = tunnel.getBlockPos() - .below() - .relative(side); - DirectBeltInputBehaviour sideOutput = TileEntityBehaviour.get(level, offset, DirectBeltInputBehaviour.TYPE); - if (sideOutput != null) { - if (!sideOutput.canInsertFromSide(side)) - return null; - ItemStack result = sideOutput.handleInsertion(stack, side, simulate); - if (result.isEmpty() && !simulate) - tunnel.flap(side, false); - return result; - } - - Direction movementFacing = below.getMovementFacing(); - if (side == movementFacing) - if (!BlockHelper.hasBlockSolidSide(level.getBlockState(offset), level, offset, side.getOpposite())) { - BeltTileEntity controllerTE = below.getControllerTE(); - if (controllerTE == null) - return null; - - if (!simulate) { - tunnel.flap(side, true); - ItemStack ejected = stack; - float beltMovementSpeed = below.getDirectionAwareBeltMovementSpeed(); - float movementSpeed = Math.max(Math.abs(beltMovementSpeed), 1 / 8f); - int additionalOffset = beltMovementSpeed > 0 ? 1 : 0; - Vec3 outPos = BeltHelper.getVectorForOffset(controllerTE, below.index + additionalOffset); - Vec3 outMotion = Vec3.atLowerCornerOf(side.getNormal()) - .scale(movementSpeed) - .add(0, 1 / 8f, 0); - outPos.add(outMotion.normalize()); - ItemEntity entity = new ItemEntity(level, outPos.x, outPos.y + 6 / 16f, outPos.z, ejected); - entity.setDeltaMovement(outMotion); - entity.setDefaultPickUpDelay(); - entity.hurtMarked = true; - level.addFreshEntity(entity); - } - - return ItemStack.EMPTY; - } - - return null; - } - - public boolean testFlapFilter(Direction side, ItemStack stack) { - if (filtering == null) - return false; - if (filtering.get(side) == null) { - FilteringBehaviour adjacentFilter = - TileEntityBehaviour.get(level, worldPosition.relative(side), FilteringBehaviour.TYPE); - if (adjacentFilter == null) - return true; - return adjacentFilter.test(stack); - } - return filtering.test(side, stack); - } - - public boolean flapFilterEmpty(Direction side) { - if (filtering == null) - return false; - if (filtering.get(side) == null) { - FilteringBehaviour adjacentFilter = - TileEntityBehaviour.get(level, worldPosition.relative(side), FilteringBehaviour.TYPE); - if (adjacentFilter == null) - return true; - return adjacentFilter.getFilter() - .isEmpty(); - } - return filtering.getFilter(side) - .isEmpty(); - } - - @Override - public void initialize() { - if (filtering == null) { - filtering = createSidedFilter(); - attachBehaviourLate(filtering); - } - super.initialize(); - } - - public boolean canInsert(Direction side, ItemStack stack) { - if (filtering != null && !filtering.test(side, stack)) - return false; - if (!hasDistributionBehaviour()) - return true; - if (!stackToDistribute.isEmpty()) - return false; - return true; - } - - public boolean hasDistributionBehaviour() { - if (flaps.isEmpty()) - return false; - if (connectedLeft || connectedRight) - return true; - BlockState blockState = getBlockState(); - if (!AllBlocks.BRASS_TUNNEL.has(blockState)) - return false; - Axis axis = blockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS); - for (Direction direction : flaps.keySet()) - if (direction.getAxis() != axis) - return true; - return false; - } - - private List> gatherValidOutputs() { - List> validOutputs = new ArrayList<>(); - boolean synchronize = selectionMode.get() == SelectionMode.SYNCHRONIZE; - addValidOutputsOf(this, validOutputs); - - for (boolean left : Iterate.trueAndFalse) { - BrassTunnelTileEntity adjacent = this; - while (adjacent != null) { - if (!level.isLoaded(adjacent.getBlockPos())) - return null; - adjacent = adjacent.getAdjacent(left); - if (adjacent == null) - continue; - addValidOutputsOf(adjacent, validOutputs); - } - } - - if (!syncedOutputActive && synchronize) - return null; - return validOutputs; - } - - private void addValidOutputsOf(BrassTunnelTileEntity tunnelTE, - List> validOutputs) { - syncSet.add(tunnelTE); - BeltTileEntity below = BeltHelper.getSegmentTE(level, tunnelTE.worldPosition.below()); - if (below == null) - return; - Direction movementFacing = below.getMovementFacing(); - BlockState blockState = getBlockState(); - if (!AllBlocks.BRASS_TUNNEL.has(blockState)) - return; - - boolean prioritizeSides = tunnelTE == this; - - for (boolean sidePass : Iterate.trueAndFalse) { - if (!prioritizeSides && sidePass) - continue; - for (Direction direction : Iterate.horizontalDirections) { - if (direction == movementFacing && below.getSpeed() == 0) - continue; - if (prioritizeSides && sidePass == (direction.getAxis() == movementFacing.getAxis())) - continue; - if (direction == movementFacing.getOpposite()) - continue; - if (!tunnelTE.sides.contains(direction)) - continue; - - BlockPos offset = tunnelTE.worldPosition.below() - .relative(direction); - - BlockState potentialFunnel = level.getBlockState(offset.above()); - if (potentialFunnel.getBlock() instanceof BeltFunnelBlock - && potentialFunnel.getValue(BeltFunnelBlock.SHAPE) == Shape.PULLING - && FunnelBlock.getFunnelFacing(potentialFunnel) == direction) - continue; - - DirectBeltInputBehaviour inputBehaviour = - TileEntityBehaviour.get(level, offset, DirectBeltInputBehaviour.TYPE); - if (inputBehaviour == null) { - if (direction == movementFacing) - if (!BlockHelper.hasBlockSolidSide(level.getBlockState(offset), level, offset, - direction.getOpposite())) - validOutputs.add(Pair.of(tunnelTE, direction)); - continue; - } - if (inputBehaviour.canInsertFromSide(direction)) - validOutputs.add(Pair.of(tunnelTE, direction)); - continue; - } - } - } - - @Override - public void addBehavioursDeferred(List behaviours) { - super.addBehavioursDeferred(behaviours); - filtering = createSidedFilter(); - behaviours.add(filtering); - } - - protected SidedFilteringBehaviour createSidedFilter() { - return new SidedFilteringBehaviour(this, new BrassTunnelFilterSlot(), this::makeFilter, - this::isValidFaceForFilter); - } - - private FilteringBehaviour makeFilter(Direction side, FilteringBehaviour filter) { - return filter; - } - - private boolean isValidFaceForFilter(Direction side) { - return sides.contains(side); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("SyncedOutput", syncedOutputActive); - compound.putBoolean("ConnectedLeft", connectedLeft); - compound.putBoolean("ConnectedRight", connectedRight); - - compound.put("StackToDistribute", stackToDistribute.serializeNBT()); - if (stackEnteredFrom != null) - NBTHelper.writeEnum(compound, "StackEnteredFrom", stackEnteredFrom); - - compound.putFloat("DistributionProgress", distributionProgress); - compound.putInt("PreviousIndex", previousOutputIndex); - compound.putInt("DistanceLeft", distributionDistanceLeft); - compound.putInt("DistanceRight", distributionDistanceRight); - - for (boolean filtered : Iterate.trueAndFalse) { - compound.put(filtered ? "FilteredTargets" : "Targets", - NBTHelper.writeCompoundList(distributionTargets.get(filtered), pair -> { - CompoundTag nbt = new CompoundTag(); - nbt.put("Pos", NbtUtils.writeBlockPos(pair.getKey())); - nbt.putInt("Face", pair.getValue() - .get3DDataValue()); - return nbt; - })); - } - - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - boolean wasConnectedLeft = connectedLeft; - boolean wasConnectedRight = connectedRight; - - syncedOutputActive = compound.getBoolean("SyncedOutput"); - connectedLeft = compound.getBoolean("ConnectedLeft"); - connectedRight = compound.getBoolean("ConnectedRight"); - - stackToDistribute = ItemStack.of(compound.getCompound("StackToDistribute")); - stackEnteredFrom = - compound.contains("StackEnteredFrom") ? NBTHelper.readEnum(compound, "StackEnteredFrom", Direction.class) - : null; - - distributionProgress = compound.getFloat("DistributionProgress"); - previousOutputIndex = compound.getInt("PreviousIndex"); - distributionDistanceLeft = compound.getInt("DistanceLeft"); - distributionDistanceRight = compound.getInt("DistanceRight"); - - for (boolean filtered : Iterate.trueAndFalse) { - distributionTargets.set(filtered, NBTHelper - .readCompoundList(compound.getList(filtered ? "FilteredTargets" : "Targets", Tag.TAG_COMPOUND), nbt -> { - BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")); - Direction face = Direction.from3DDataValue(nbt.getInt("Face")); - return Pair.of(pos, face); - })); - } - - super.read(compound, clientPacket); - - if (!clientPacket) - return; - if (wasConnectedLeft != connectedLeft || wasConnectedRight != connectedRight) { - requestModelDataUpdate(); - if (hasLevel()) - level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); - } - filtering.updateFilterPresence(); - } - - public boolean isConnected(boolean leftSide) { - return leftSide ? connectedLeft : connectedRight; - } - - @Override - public void updateTunnelConnections() { - super.updateTunnelConnections(); - boolean connectivityChanged = false; - boolean nowConnectedLeft = determineIfConnected(true); - boolean nowConnectedRight = determineIfConnected(false); - - if (connectedLeft != nowConnectedLeft) { - connectedLeft = nowConnectedLeft; - connectivityChanged = true; - BrassTunnelTileEntity adjacent = getAdjacent(true); - if (adjacent != null && !level.isClientSide) { - adjacent.updateTunnelConnections(); - adjacent.selectionMode.setValue(selectionMode.getValue()); - } - } - - if (connectedRight != nowConnectedRight) { - connectedRight = nowConnectedRight; - connectivityChanged = true; - BrassTunnelTileEntity adjacent = getAdjacent(false); - if (adjacent != null && !level.isClientSide) { - adjacent.updateTunnelConnections(); - adjacent.selectionMode.setValue(selectionMode.getValue()); - } - } - - if (filtering != null) - filtering.updateFilterPresence(); - if (connectivityChanged) - sendData(); - } - - protected boolean determineIfConnected(boolean leftSide) { - if (flaps.isEmpty()) - return false; - BrassTunnelTileEntity adjacentTunnelTE = getAdjacent(leftSide); - return adjacentTunnelTE != null && !adjacentTunnelTE.flaps.isEmpty(); - } - - @Nullable - protected BrassTunnelTileEntity getAdjacent(boolean leftSide) { - if (!hasLevel()) - return null; - - BlockState blockState = getBlockState(); - if (!AllBlocks.BRASS_TUNNEL.has(blockState)) - return null; - - Axis axis = blockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS); - Direction baseDirection = Direction.get(AxisDirection.POSITIVE, axis); - Direction direction = leftSide ? baseDirection.getCounterClockWise() : baseDirection.getClockWise(); - BlockPos adjacentPos = worldPosition.relative(direction); - BlockState adjacentBlockState = level.getBlockState(adjacentPos); - - if (!AllBlocks.BRASS_TUNNEL.has(adjacentBlockState)) - return null; - if (adjacentBlockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS) != axis) - return null; - BlockEntity adjacentTE = level.getBlockEntity(adjacentPos); - if (adjacentTE.isRemoved()) - return null; - if (!(adjacentTE instanceof BrassTunnelTileEntity)) - return null; - return (BrassTunnelTileEntity) adjacentTE; - } - - @Override - public void setRemoved() { - tunnelCapability.invalidate(); - super.setRemoved(); - } - - @Override - public LazyOptional getCapability(Capability capability, Direction side) { - if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return tunnelCapability.cast(); - return super.getCapability(capability, side); - } - - public LazyOptional getBeltCapability() { - if (!beltCapability.isPresent()) { - BlockEntity tileEntity = level.getBlockEntity(worldPosition.below()); - if (tileEntity != null) - beltCapability = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - } - return beltCapability; - } - - public enum SelectionMode implements INamedIconOptions { - SPLIT(AllIcons.I_TUNNEL_SPLIT), - FORCED_SPLIT(AllIcons.I_TUNNEL_FORCED_SPLIT), - ROUND_ROBIN(AllIcons.I_TUNNEL_ROUND_ROBIN), - FORCED_ROUND_ROBIN(AllIcons.I_TUNNEL_FORCED_ROUND_ROBIN), - PREFER_NEAREST(AllIcons.I_TUNNEL_PREFER_NEAREST), - RANDOMIZE(AllIcons.I_TUNNEL_RANDOMIZE), - SYNCHRONIZE(AllIcons.I_TUNNEL_SYNCHRONIZE), - - ; - - private final String translationKey; - private final AllIcons icon; - - SelectionMode(AllIcons icon) { - this.icon = icon; - this.translationKey = "tunnel.selection_mode." + Lang.asId(name()); - } - - @Override - public AllIcons getIcon() { - return icon; - } - - @Override - public String getTranslationKey() { - return translationKey; - } - } - - public boolean canTakeItems() { - return stackToDistribute.isEmpty() && !syncedOutputActive; - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - List allStacks = grabAllStacksOfGroup(true); - if (allStacks.isEmpty()) - return false; - - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.brass_tunnel.contains")) - .withStyle(ChatFormatting.WHITE)); - for (ItemStack item : allStacks) { - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.brass_tunnel.contains_entry", Components.translatable(item.getDescriptionId()) - .getString(), item.getCount())) - .withStyle(ChatFormatting.GRAY)); - } - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.brass_tunnel.retrieve")) - .withStyle(ChatFormatting.DARK_GRAY)); - - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java deleted file mode 100644 index 1fa2d1af34..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/AbstractChuteBlock.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import java.util.function.Consumer; - -import javax.annotation.Nullable; - -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.IBlockRenderProperties; -import net.minecraftforge.common.util.LazyOptional; - -public abstract class AbstractChuteBlock extends Block implements IWrenchable, ITE { - - public AbstractChuteBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - } - - @OnlyIn(Dist.CLIENT) - public void initializeClient(Consumer consumer) { - consumer.accept(new ReducedDestroyEffects()); - } - - public static boolean isChute(BlockState state) { - return state.getBlock() instanceof AbstractChuteBlock; - } - - public static boolean isOpenChute(BlockState state) { - return isChute(state) && ((AbstractChuteBlock) state.getBlock()).isOpen(state); - } - - public static boolean isTransparentChute(BlockState state) { - return isChute(state) && ((AbstractChuteBlock) state.getBlock()).isTransparent(state); - } - - @Nullable - public static Direction getChuteFacing(BlockState state) { - return !isChute(state) ? null : ((AbstractChuteBlock) state.getBlock()).getFacing(state); - } - - public Direction getFacing(BlockState state) { - return Direction.DOWN; - } - - public boolean isOpen(BlockState state) { - return true; - } - - public boolean isTransparent(BlockState state) { - return false; - } - - @Override - public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { - super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); - AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); - } - - @Override - public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { - super.updateEntityAfterFallOn(worldIn, entityIn); - if (!(entityIn instanceof ItemEntity)) - return; - if (entityIn.level.isClientSide) - return; - if (!entityIn.isAlive()) - return; - DirectBeltInputBehaviour input = TileEntityBehaviour.get(entityIn.level, new BlockPos(entityIn.position() - .add(0, 0.5f, 0)).below(), DirectBeltInputBehaviour.TYPE); - if (input == null) - return; - if (!input.canInsertFromSide(Direction.UP)) - return; - - ItemEntity itemEntity = (ItemEntity) entityIn; - ItemStack toInsert = itemEntity.getItem(); - ItemStack remainder = input.handleInsertion(toInsert, Direction.UP, false); - - if (remainder.isEmpty()) - itemEntity.discard(); - if (remainder.getCount() < toInsert.getCount()) - itemEntity.setItem(remainder); - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { - withTileEntityDo(world, pos, ChuteTileEntity::onAdded); - if (p_220082_5_) - return; - updateDiagonalNeighbour(state, world, pos); - } - - protected void updateDiagonalNeighbour(BlockState state, Level world, BlockPos pos) { - if (!isChute(state)) - return; - AbstractChuteBlock block = (AbstractChuteBlock) state.getBlock(); - Direction facing = block.getFacing(state); - BlockPos toUpdate = pos.below(); - if (facing.getAxis() - .isHorizontal()) - toUpdate = toUpdate.relative(facing.getOpposite()); - - BlockState stateToUpdate = world.getBlockState(toUpdate); - BlockState updated = updateChuteState(stateToUpdate, world.getBlockState(toUpdate.above()), world, toUpdate); - if (stateToUpdate != updated && !world.isClientSide) - world.setBlockAndUpdate(toUpdate, updated); - } - - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState p_196243_4_, boolean p_196243_5_) { - boolean differentBlock = state.getBlock() != p_196243_4_.getBlock(); - if (state.hasBlockEntity() && (differentBlock || !p_196243_4_.hasBlockEntity())) { - TileEntityBehaviour.destroy(world, pos, FilteringBehaviour.TYPE); - withTileEntityDo(world, pos, c -> c.onRemoved(state)); - world.removeBlockEntity(pos); - } - if (p_196243_5_ || !differentBlock) - return; - - updateDiagonalNeighbour(state, world, pos); - - for (Direction direction : Iterate.horizontalDirections) { - BlockPos toUpdate = pos.above() - .relative(direction); - BlockState stateToUpdate = world.getBlockState(toUpdate); - if (!isChute(stateToUpdate)) - continue; - BlockState updated = ((AbstractChuteBlock) stateToUpdate.getBlock()).updateChuteState(stateToUpdate, - world.getBlockState(toUpdate.above()), world, toUpdate); - if (stateToUpdate != updated && !world.isClientSide) - world.setBlockAndUpdate(toUpdate, updated); - } - } - - @Override - public BlockState updateShape(BlockState state, Direction direction, BlockState above, LevelAccessor world, - BlockPos pos, BlockPos p_196271_6_) { - if (direction != Direction.UP) - return state; - return updateChuteState(state, above, world, pos); - } - - @Override - public void neighborChanged(BlockState p_220069_1_, Level world, BlockPos pos, Block p_220069_4_, - BlockPos neighbourPos, boolean p_220069_6_) { - if (pos.below() - .equals(neighbourPos)) - withTileEntityDo(world, pos, ChuteTileEntity::blockBelowChanged); - else if (pos.above() - .equals(neighbourPos)) - withTileEntityDo(world, pos, chute -> chute.capAbove = LazyOptional.empty()); - } - - public abstract BlockState updateChuteState(BlockState state, BlockState above, BlockGetter world, BlockPos pos); - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return ChuteShapes.getShape(p_220053_1_); - } - - @Override - public VoxelShape getCollisionShape(BlockState p_220071_1_, BlockGetter p_220071_2_, BlockPos p_220071_3_, - CollisionContext p_220071_4_) { - return ChuteShapes.getCollisionShape(p_220071_1_); - } - - @Override - public Class getTileEntityClass() { - return ChuteTileEntity.class; - } - - @Override - public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult p_225533_6_) { - if (!player.getItemInHand(hand) - .isEmpty()) - return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; - - return onTileEntityUse(world, pos, te -> { - if (te.item.isEmpty()) - return InteractionResult.PASS; - player.getInventory().placeItemBackInInventory(te.item); - te.setItem(ItemStack.EMPTY); - return InteractionResult.SUCCESS; - }); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java deleted file mode 100644 index 15b02e528e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteBlock.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import java.util.HashMap; -import java.util.Map; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.pathfinder.PathComputationType; - -public class ChuteBlock extends AbstractChuteBlock { - - public static final Property SHAPE = EnumProperty.create("shape", Shape.class); - public static final DirectionProperty FACING = BlockStateProperties.FACING_HOPPER; - - public ChuteBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - registerDefaultState(defaultBlockState().setValue(SHAPE, Shape.NORMAL) - .setValue(FACING, Direction.DOWN)); - } - - public enum Shape implements StringRepresentable { - INTERSECTION, WINDOW, NORMAL; - - @Override - public String getSerializedName() { - return Lang.asId(name()); - } - } - - @Override - public Direction getFacing(BlockState state) { - return state.getValue(FACING); - } - - @Override - public boolean isOpen(BlockState state) { - return state.getValue(FACING) == Direction.DOWN || state.getValue(SHAPE) == Shape.INTERSECTION; - } - - @Override - public boolean isTransparent(BlockState state) { - return state.getValue(SHAPE) == Shape.WINDOW; - } - - @Override - public InteractionResult onWrenched(BlockState state, UseOnContext context) { - Shape shape = state.getValue(SHAPE); - boolean down = state.getValue(FACING) == Direction.DOWN; - if (!context.getLevel().isClientSide && down && shape != Shape.INTERSECTION) { - context.getLevel() - .setBlockAndUpdate(context.getClickedPos(), - state.setValue(SHAPE, shape == Shape.WINDOW ? Shape.NORMAL : Shape.WINDOW)); - } - return InteractionResult.SUCCESS; - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { - BlockState state = super.getStateForPlacement(ctx); - Direction face = ctx.getClickedFace(); - if (face.getAxis() - .isHorizontal() && !ctx.isSecondaryUseActive()) { - Level world = ctx.getLevel(); - BlockPos pos = ctx.getClickedPos(); - return updateChuteState(state.setValue(FACING, face), world.getBlockState(pos.above()), world, pos); - } - return state; - } - - @Override - protected void createBlockStateDefinition(Builder p_206840_1_) { - super.createBlockStateDefinition(p_206840_1_.add(SHAPE, FACING)); - } - - @Override - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { - BlockState above = world.getBlockState(pos.above()); - return !isChute(above) || getChuteFacing(above) == Direction.DOWN; - } - - @Override - public BlockState updateChuteState(BlockState state, BlockState above, BlockGetter world, BlockPos pos) { - if (!(state.getBlock() instanceof ChuteBlock)) - return state; - - Map connections = new HashMap<>(); - int amtConnections = 0; - Direction facing = state.getValue(FACING); - boolean vertical = facing == Direction.DOWN; - - if (!vertical) { - BlockState target = world.getBlockState(pos.below() - .relative(facing.getOpposite())); - if (!isChute(target)) - return state.setValue(FACING, Direction.DOWN) - .setValue(SHAPE, Shape.NORMAL); - } - - for (Direction direction : Iterate.horizontalDirections) { - BlockState diagonalInputChute = world.getBlockState(pos.above() - .relative(direction)); - boolean value = - diagonalInputChute.getBlock() instanceof ChuteBlock && diagonalInputChute.getValue(FACING) == direction; - connections.put(direction, value); - if (value) - amtConnections++; - } - - boolean noConnections = amtConnections == 0; - if (vertical) - return state.setValue(SHAPE, - noConnections ? state.getValue(SHAPE) == Shape.WINDOW ? Shape.WINDOW : Shape.NORMAL : Shape.INTERSECTION); - if (noConnections) - return state.setValue(SHAPE, Shape.INTERSECTION); - if (connections.get(Direction.NORTH) && connections.get(Direction.SOUTH)) - return state.setValue(SHAPE, Shape.INTERSECTION); - if (connections.get(Direction.EAST) && connections.get(Direction.WEST)) - return state.setValue(SHAPE, Shape.INTERSECTION); - if (amtConnections == 1 && connections.get(facing) && !(getChuteFacing(above) == Direction.DOWN) - && !(above.getBlock() instanceof FunnelBlock && FunnelBlock.getFunnelFacing(above) == Direction.DOWN)) - return state.setValue(SHAPE, Shape.NORMAL); - return state.setValue(SHAPE, Shape.INTERSECTION); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CHUTE.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItemHandler.java deleted file mode 100644 index b1bb46ff9e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItemHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; - -public class ChuteItemHandler implements IItemHandler { - - private ChuteTileEntity te; - - public ChuteItemHandler(ChuteTileEntity te) { - this.te = te; - } - - @Override - public int getSlots() { - return 1; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return te.item; - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (!te.canAcceptItem(stack)) - return stack; - if (!simulate) - te.setItem(stack); - return ItemStack.EMPTY; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - ItemStack remainder = te.item.copy(); - ItemStack split = remainder.split(amount); - if (!simulate) - te.setItem(remainder); - return split; - } - - @Override - public int getSlotLimit(int slot) { - return Math.min(64, getStackInSlot(slot).getMaxStackSize()); - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteRenderer.java deleted file mode 100644 index 169d45a91e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteRenderer.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; - -public class ChuteRenderer extends SafeTileEntityRenderer { - - public ChuteRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(ChuteTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, - int overlay) { - if (te.item.isEmpty()) - return; - BlockState blockState = te.getBlockState(); - if (blockState.getValue(ChuteBlock.FACING) != Direction.DOWN) - return; - if (blockState.getValue(ChuteBlock.SHAPE) != Shape.WINDOW - && (te.bottomPullDistance == 0 || te.itemPosition.getValue(partialTicks) > .5f)) - return; - - renderItem(te, partialTicks, ms, buffer, light, overlay); - } - - public static void renderItem(ChuteTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - TransformStack msr = TransformStack.cast(ms); - ms.pushPose(); - msr.centre(); - float itemScale = .5f; - float itemPosition = te.itemPosition.getValue(partialTicks); - ms.translate(0, -.5 + itemPosition, 0); - ms.scale(itemScale, itemScale, itemScale); - msr.rotateX(itemPosition * 180); - msr.rotateY(itemPosition * 180); - itemRenderer.renderStatic(te.item, TransformType.FIXED, light, overlay, ms, buffer, 0); - ms.popPose(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java deleted file mode 100644 index a3c2b5cacc..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java +++ /dev/null @@ -1,786 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import java.util.LinkedList; -import java.util.List; -import java.util.function.Predicate; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.fan.AirCurrent; -import com.simibubi.create.content.contraptions.components.fan.EncasedFanBlock; -import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.contraptions.particle.AirParticleData; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; -import com.simibubi.create.foundation.utility.BlockHelper; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ItemParticleOption; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.Containers; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -/* - * Commented Code: Chutes create air streams and act similarly to encased fans - * (Unfinished) - */ -public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInformation { // , IAirCurrentSource { - - // public AirCurrent airCurrent; - - float pull; - float push; - - ItemStack item; - LerpedFloat itemPosition; - ChuteItemHandler itemHandler; - LazyOptional lazyHandler; - boolean canPickUpItems; - - float bottomPullDistance; - float beltBelowOffset; - TransportedItemStackHandlerBehaviour beltBelow; - boolean updateAirFlow; - int airCurrentUpdateCooldown; - int entitySearchCooldown; - - LazyOptional capAbove; - LazyOptional capBelow; - - public ChuteTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - item = ItemStack.EMPTY; - itemPosition = LerpedFloat.linear(); - itemHandler = new ChuteItemHandler(this); - lazyHandler = LazyOptional.of(() -> itemHandler); - canPickUpItems = false; - capAbove = LazyOptional.empty(); - capBelow = LazyOptional.empty(); - bottomPullDistance = 0; - // airCurrent = new AirCurrent(this); - updateAirFlow = true; - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached())); - registerAwardables(behaviours, AllAdvancements.CHUTE); - } - - // Cached per-tick, useful when a lot of items are waiting on top of it - public boolean canDirectlyInsertCached() { - return canPickUpItems; - } - - private boolean canDirectlyInsert() { - BlockState blockState = getBlockState(); - BlockState blockStateAbove = level.getBlockState(worldPosition.above()); - if (!AbstractChuteBlock.isChute(blockState)) - return false; - if (AbstractChuteBlock.getChuteFacing(blockStateAbove) == Direction.DOWN) - return false; - if (getItemMotion() > 0 && getInputChutes().isEmpty()) - return false; - return AbstractChuteBlock.isOpenChute(blockState); - } - - @Override - public void initialize() { - super.initialize(); - onAdded(); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition).expandTowards(0, -3, 0); - } - - @Override - public void tick() { - super.tick(); - - if (!level.isClientSide) - canPickUpItems = canDirectlyInsert(); - - boolean clientSide = level != null && level.isClientSide && !isVirtual(); - float itemMotion = getItemMotion(); - if (itemMotion != 0 && level != null && level.isClientSide) - spawnParticles(itemMotion); - tickAirStreams(itemMotion); - - if (item.isEmpty() && !clientSide) { - if (itemMotion < 0) - handleInputFromAbove(); - if (itemMotion > 0) - handleInputFromBelow(); - return; - } - - float nextOffset = itemPosition.getValue() + itemMotion; - - if (itemMotion < 0) { - if (nextOffset < .5f) { - if (!handleDownwardOutput(true)) - nextOffset = .5f; - else if (nextOffset < 0) { - handleDownwardOutput(clientSide); - nextOffset = itemPosition.getValue(); - } - } - } else if (itemMotion > 0) { - if (nextOffset > .5f) { - if (!handleUpwardOutput(true)) - nextOffset = .5f; - else if (nextOffset > 1) { - handleUpwardOutput(clientSide); - nextOffset = itemPosition.getValue(); - } - } - } - - itemPosition.setValue(nextOffset); - } - - private void updateAirFlow(float itemSpeed) { - updateAirFlow = false; - // airCurrent.rebuild(); - if (itemSpeed > 0 && level != null && !level.isClientSide) { - float speed = pull - push; - beltBelow = null; - - float maxPullDistance; - if (speed >= 128) - maxPullDistance = 3; - else if (speed >= 64) - maxPullDistance = 2; - else if (speed >= 32) - maxPullDistance = 1; - else - maxPullDistance = Mth.lerp(speed / 32, 0, 1); - - if (AbstractChuteBlock.isChute(level.getBlockState(worldPosition.below()))) - maxPullDistance = 0; - float flowLimit = maxPullDistance; - if (flowLimit > 0) - flowLimit = AirCurrent.getFlowLimit(level, worldPosition, maxPullDistance, Direction.DOWN); - - for (int i = 1; i <= flowLimit + 1; i++) { - TransportedItemStackHandlerBehaviour behaviour = - TileEntityBehaviour.get(level, worldPosition.below(i), TransportedItemStackHandlerBehaviour.TYPE); - if (behaviour == null) - continue; - beltBelow = behaviour; - beltBelowOffset = i - 1; - break; - } - this.bottomPullDistance = Math.max(0, flowLimit); - } - sendData(); - } - - private void findEntities(float itemSpeed) { - // if (getSpeed() != 0) - // airCurrent.findEntities(); - if (bottomPullDistance <= 0 && !getItem().isEmpty() || itemSpeed <= 0 || level == null || level.isClientSide) - return; - if (!canCollectItemsFromBelow()) - return; - Vec3 center = VecHelper.getCenterOf(worldPosition); - AABB searchArea = new AABB(center.add(0, -bottomPullDistance - 0.5, 0), center.add(0, -0.5, 0)).inflate(.45f); - for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, searchArea)) { - if (!itemEntity.isAlive()) - continue; - ItemStack entityItem = itemEntity.getItem(); - if (!canAcceptItem(entityItem)) - continue; - setItem(entityItem.copy(), (float) (itemEntity.getBoundingBox() - .getCenter().y - worldPosition.getY())); - itemEntity.discard(); - break; - } - } - - private void extractFromBelt(float itemSpeed) { - if (itemSpeed <= 0 || level == null || level.isClientSide) - return; - if (getItem().isEmpty() && beltBelow != null) { - beltBelow.handleCenteredProcessingOnAllItems(.5f, ts -> { - if (canAcceptItem(ts.stack)) { - setItem(ts.stack.copy(), -beltBelowOffset); - return TransportedResult.removeItem(); - } - return TransportedResult.doNothing(); - }); - } - } - - private void tickAirStreams(float itemSpeed) { - if (!level.isClientSide && airCurrentUpdateCooldown-- <= 0) { - airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get(); - updateAirFlow = true; - } - - if (updateAirFlow) { - updateAirFlow(itemSpeed); - } - - if (entitySearchCooldown-- <= 0 && item.isEmpty()) { - entitySearchCooldown = 5; - findEntities(itemSpeed); - } - - extractFromBelt(itemSpeed); - // if (getSpeed() != 0) - // airCurrent.tick(); - } - - public void blockBelowChanged() { - updateAirFlow = true; - capBelow = LazyOptional.empty(); - } - - private void spawnParticles(float itemMotion) { - // todo: reduce the amount of particles - if (level == null) - return; - BlockState blockState = getBlockState(); - boolean up = itemMotion > 0; - float absMotion = up ? itemMotion : -itemMotion; - if (blockState == null || !AbstractChuteBlock.isChute(blockState)) - return; - if (push == 0 && pull == 0) - return; - - if (up && AbstractChuteBlock.isOpenChute(blockState) - && BlockHelper.noCollisionInSpace(level, worldPosition.above())) - spawnAirFlow(1, 2, absMotion, .5f); - - if (AbstractChuteBlock.getChuteFacing(blockState) != Direction.DOWN) - return; - - if (AbstractChuteBlock.isTransparentChute(blockState)) - spawnAirFlow(up ? 0 : 1, up ? 1 : 0, absMotion, 1); - - if (!up && BlockHelper.noCollisionInSpace(level, worldPosition.below())) - spawnAirFlow(0, -1, absMotion, .5f); - - if (up && canCollectItemsFromBelow() && bottomPullDistance > 0) { - spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); - spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); - } - } - - private void spawnAirFlow(float verticalStart, float verticalEnd, float motion, float drag) { - if (level == null) - return; - AirParticleData airParticleData = new AirParticleData(drag, motion); - Vec3 origin = Vec3.atLowerCornerOf(worldPosition); - float xOff = Create.RANDOM.nextFloat() * .5f + .25f; - float zOff = Create.RANDOM.nextFloat() * .5f + .25f; - Vec3 v = origin.add(xOff, verticalStart, zOff); - Vec3 d = origin.add(xOff, verticalEnd, zOff) - .subtract(v); - if (Create.RANDOM.nextFloat() < 2 * motion) - level.addAlwaysVisibleParticle(airParticleData, v.x, v.y, v.z, d.x, d.y, d.z); - } - - private void handleInputFromAbove() { - if (!capAbove.isPresent()) - capAbove = grabCapability(Direction.UP); - handleInput(capAbove.orElse(null), 1); - } - - private void handleInputFromBelow() { - if (!capBelow.isPresent()) - capBelow = grabCapability(Direction.DOWN); - handleInput(capBelow.orElse(null), 0); - } - - private void handleInput(IItemHandler inv, float startLocation) { - if (inv == null) - return; - Predicate canAccept = this::canAcceptItem; - int count = getExtractionAmount(); - ExtractionCountMode mode = getExtractionMode(); - if (mode == ExtractionCountMode.UPTO || !ItemHelper.extract(inv, canAccept, mode, count, true) - .isEmpty()) { - ItemStack extracted = ItemHelper.extract(inv, canAccept, mode, count, false); - if (!extracted.isEmpty()) - setItem(extracted, startLocation); - } - } - - private boolean handleDownwardOutput(boolean simulate) { - BlockState blockState = getBlockState(); - ChuteTileEntity targetChute = getTargetChute(blockState); - Direction direction = AbstractChuteBlock.getChuteFacing(blockState); - - if (level == null || direction == null || !this.canOutputItems()) - return false; - if (!capBelow.isPresent()) - capBelow = grabCapability(Direction.DOWN); - if (capBelow.isPresent()) { - if (level.isClientSide && !isVirtual()) - return false; - ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate); - ItemStack held = getItem(); - if (!simulate) - setItem(remainder, itemPosition.getValue(0)); - if (remainder.getCount() != held.getCount()) - return true; - if (direction == Direction.DOWN) - return false; - } - - if (targetChute != null) { - boolean canInsert = targetChute.canAcceptItem(item); - if (!simulate && canInsert) { - targetChute.setItem(item, direction == Direction.DOWN ? 1 : .51f); - setItem(ItemStack.EMPTY); - } - return canInsert; - } - - // Diagonal chutes cannot drop items - if (direction.getAxis() - .isHorizontal()) - return false; - - if (FunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.below())) == Direction.DOWN) - return false; - if (Block.canSupportRigidBlock(level, worldPosition.below())) - return false; - - if (!simulate) { - Vec3 dropVec = VecHelper.getCenterOf(worldPosition) - .add(0, -12 / 16f, 0); - ItemEntity dropped = new ItemEntity(level, dropVec.x, dropVec.y, dropVec.z, item.copy()); - dropped.setDefaultPickUpDelay(); - dropped.setDeltaMovement(0, -.25f, 0); - level.addFreshEntity(dropped); - setItem(ItemStack.EMPTY); - } - - return true; - } - - private boolean handleUpwardOutput(boolean simulate) { - BlockState stateAbove = level.getBlockState(worldPosition.above()); - - if (level == null || !this.canOutputItems()) - return false; - - if (AbstractChuteBlock.isOpenChute(getBlockState())) { - if (!capAbove.isPresent()) - capAbove = grabCapability(Direction.UP); - if (capAbove.isPresent()) { - if (level.isClientSide && !isVirtual() && !ChuteBlock.isChute(stateAbove)) - return false; - int countBefore = item.getCount(); - ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate); - if (!simulate) - item = remainder; - return countBefore != remainder.getCount(); - } - } - - ChuteTileEntity bestOutput = null; - List inputChutes = getInputChutes(); - for (ChuteTileEntity targetChute : inputChutes) { - if (!targetChute.canAcceptItem(item)) - continue; - float itemMotion = targetChute.getItemMotion(); - if (itemMotion < 0) - continue; - if (bestOutput == null || bestOutput.getItemMotion() < itemMotion) { - bestOutput = targetChute; - } - } - - if (bestOutput != null) { - if (!simulate) { - bestOutput.setItem(item, 0); - setItem(ItemStack.EMPTY); - } - return true; - } - - if (FunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == Direction.UP) - return false; - if (BlockHelper.hasBlockSolidSide(stateAbove, level, worldPosition.above(), Direction.DOWN)) - return false; - if (!inputChutes.isEmpty()) - return false; - - if (!simulate) { - Vec3 dropVec = VecHelper.getCenterOf(worldPosition) - .add(0, 8 / 16f, 0); - ItemEntity dropped = new ItemEntity(level, dropVec.x, dropVec.y, dropVec.z, item.copy()); - dropped.setDefaultPickUpDelay(); - dropped.setDeltaMovement(0, getItemMotion() * 2, 0); - level.addFreshEntity(dropped); - setItem(ItemStack.EMPTY); - } - return true; - } - - protected boolean canAcceptItem(ItemStack stack) { - return item.isEmpty(); - } - - protected int getExtractionAmount() { - return 16; - } - - protected ExtractionCountMode getExtractionMode() { - return ExtractionCountMode.UPTO; - } - - protected boolean canCollectItemsFromBelow() { - return true; - } - - protected boolean canOutputItems() { - return true; - } - - private LazyOptional grabCapability(Direction side) { - BlockPos pos = this.worldPosition.relative(side); - if (level == null) - return LazyOptional.empty(); - BlockEntity te = level.getBlockEntity(pos); - if (te == null) - return LazyOptional.empty(); - if (te instanceof ChuteTileEntity) { - if (side != Direction.DOWN || !(te instanceof SmartChuteTileEntity) || getItemMotion() > 0) - return LazyOptional.empty(); - } - return te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side.getOpposite()); - } - - public void setItem(ItemStack stack) { - setItem(stack, getItemMotion() < 0 ? 1 : 0); - } - - public void setItem(ItemStack stack, float insertionPos) { - item = stack; - itemPosition.startWithValue(insertionPos); - if (!level.isClientSide) { - notifyUpdate(); - award(AllAdvancements.CHUTE); - } - } - - @Override - public void setRemoved() { - super.setRemoved(); - if (lazyHandler != null) - lazyHandler.invalidate(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.put("Item", item.serializeNBT()); - compound.putFloat("ItemPosition", itemPosition.getValue()); - compound.putFloat("Pull", pull); - compound.putFloat("Push", push); - compound.putFloat("BottomAirFlowDistance", bottomPullDistance); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - ItemStack previousItem = item; - item = ItemStack.of(compound.getCompound("Item")); - itemPosition.startWithValue(compound.getFloat("ItemPosition")); - pull = compound.getFloat("Pull"); - push = compound.getFloat("Push"); - bottomPullDistance = compound.getFloat("BottomAirFlowDistance"); - super.read(compound, clientPacket); -// if (clientPacket) -// airCurrent.rebuild(); - - if (hasLevel() && level != null && level.isClientSide && !previousItem.equals(item, false) && !item.isEmpty()) { - if (level.random.nextInt(3) != 0) - return; - Vec3 p = VecHelper.getCenterOf(worldPosition); - p = VecHelper.offsetRandomly(p, level.random, .5f); - Vec3 m = Vec3.ZERO; - level.addParticle(new ItemParticleOption(ParticleTypes.ITEM, item), p.x, p.y, p.z, m.x, m.y, m.z); - } - } - - public float getItemMotion() { - // Chutes per second - final float fanSpeedModifier = 1 / 64f; - final float maxItemSpeed = 20f; - final float gravity = 4f; - - float motion = (push + pull) * fanSpeedModifier; - return (Mth.clamp(motion, -maxItemSpeed, maxItemSpeed) + (motion <= 0 ? -gravity : 0)) / 20f; - } - - public void onRemoved(BlockState chuteState) { - ChuteTileEntity targetChute = getTargetChute(chuteState); - List inputChutes = getInputChutes(); - if (!item.isEmpty() && level != null) - Containers.dropItemStack(level, worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), item); - setRemoved(); - if (targetChute != null) { - targetChute.updatePull(); - targetChute.propagatePush(); - } - inputChutes.forEach(c -> c.updatePush(inputChutes.size())); - } - - public void onAdded() { - refreshBlockState(); - updatePull(); - ChuteTileEntity targetChute = getTargetChute(getBlockState()); - if (targetChute != null) - targetChute.propagatePush(); - else - updatePush(1); - } - - public void updatePull() { - float totalPull = calculatePull(); - if (pull == totalPull) - return; - pull = totalPull; - updateAirFlow = true; - sendData(); - ChuteTileEntity targetChute = getTargetChute(getBlockState()); - if (targetChute != null) - targetChute.updatePull(); - } - - public void updatePush(int branchCount) { - float totalPush = calculatePush(branchCount); - if (push == totalPush) - return; - updateAirFlow = true; - push = totalPush; - sendData(); - propagatePush(); - } - - public void propagatePush() { - List inputs = getInputChutes(); - inputs.forEach(c -> c.updatePush(inputs.size())); - } - - protected float calculatePull() { - BlockState blockStateAbove = level.getBlockState(worldPosition.above()); - if (AllBlocks.ENCASED_FAN.has(blockStateAbove) - && blockStateAbove.getValue(EncasedFanBlock.FACING) == Direction.DOWN) { - BlockEntity te = level.getBlockEntity(worldPosition.above()); - if (te instanceof EncasedFanTileEntity && !te.isRemoved()) { - EncasedFanTileEntity fan = (EncasedFanTileEntity) te; - return fan.getSpeed(); - } - } - - float totalPull = 0; - for (Direction d : Iterate.directions) { - ChuteTileEntity inputChute = getInputChute(d); - if (inputChute == null) - continue; - totalPull += inputChute.pull; - } - return totalPull; - } - - protected float calculatePush(int branchCount) { - if (level == null) - return 0; - BlockState blockStateBelow = level.getBlockState(worldPosition.below()); - if (AllBlocks.ENCASED_FAN.has(blockStateBelow) - && blockStateBelow.getValue(EncasedFanBlock.FACING) == Direction.UP) { - BlockEntity te = level.getBlockEntity(worldPosition.below()); - if (te instanceof EncasedFanTileEntity && !te.isRemoved()) { - EncasedFanTileEntity fan = (EncasedFanTileEntity) te; - return fan.getSpeed(); - } - } - - ChuteTileEntity targetChute = getTargetChute(getBlockState()); - if (targetChute == null) - return 0; - return targetChute.push / branchCount; - } - - @Nullable - private ChuteTileEntity getTargetChute(BlockState state) { - if (level == null) - return null; - Direction targetDirection = AbstractChuteBlock.getChuteFacing(state); - if (targetDirection == null) - return null; - BlockPos chutePos = worldPosition.below(); - if (targetDirection.getAxis() - .isHorizontal()) - chutePos = chutePos.relative(targetDirection.getOpposite()); - BlockState chuteState = level.getBlockState(chutePos); - if (!AbstractChuteBlock.isChute(chuteState)) - return null; - BlockEntity te = level.getBlockEntity(chutePos); - if (te instanceof ChuteTileEntity) - return (ChuteTileEntity) te; - return null; - } - - private List getInputChutes() { - List inputs = new LinkedList<>(); - for (Direction d : Iterate.directions) { - ChuteTileEntity inputChute = getInputChute(d); - if (inputChute == null) - continue; - inputs.add(inputChute); - } - return inputs; - } - - @Nullable - private ChuteTileEntity getInputChute(Direction direction) { - if (level == null || direction == Direction.DOWN) - return null; - direction = direction.getOpposite(); - BlockPos chutePos = worldPosition.above(); - if (direction.getAxis() - .isHorizontal()) - chutePos = chutePos.relative(direction); - BlockState chuteState = level.getBlockState(chutePos); - Direction chuteFacing = AbstractChuteBlock.getChuteFacing(chuteState); - if (chuteFacing != direction) - return null; - BlockEntity te = level.getBlockEntity(chutePos); - if (te instanceof ChuteTileEntity && !te.isRemoved()) - return (ChuteTileEntity) te; - return null; - } - - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - boolean downward = getItemMotion() < 0; - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.chute.header"))); - if (pull == 0 && push == 0) - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.chute.no_fans_attached")) - .withStyle(ChatFormatting.GRAY)); - if (pull != 0) - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.chute.fans_" + (pull > 0 ? "pull_up" : "push_down")) - .withStyle(ChatFormatting.GRAY))); - if (push != 0) - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.chute.fans_" + (push > 0 ? "push_up" : "pull_down")) - .withStyle(ChatFormatting.GRAY))); - tooltip.add(componentSpacing.plainCopy() - .append("-> ") - .append(CreateLang.translateDirect("tooltip.chute.items_move_" + (downward ? "down" : "up")) - .withStyle(ChatFormatting.YELLOW))); - if (!item.isEmpty()) { - tooltip.add(componentSpacing.plainCopy() - .append(CreateLang.translateDirect("tooltip.chute.contains", Components.translatable(item.getDescriptionId()) - .getString(), item.getCount())) - .withStyle(ChatFormatting.GREEN)); - } - return true; - } - - @Override - public LazyOptional getCapability(Capability cap, @Nullable Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return lazyHandler.cast(); - return super.getCapability(cap, side); - } - - public ItemStack getItem() { - return item; - } - - // @Override - // @Nullable - // public AirCurrent getAirCurrent() { - // return airCurrent; - // } - // - // @Nullable - // @Override - // public World getAirCurrentWorld() { - // return world; - // } - // - // @Override - // public BlockPos getAirCurrentPos() { - // return pos; - // } - // - // @Override - // public float getSpeed() { - // if (getBlockState().get(ChuteBlock.SHAPE) == Shape.NORMAL && - // getBlockState().get(ChuteBlock.FACING) != Direction.DOWN) - // return 0; - // return pull + push; - // } - // - // @Override - // @Nullable - // public Direction getAirFlowDirection() { - // float speed = getSpeed(); - // if (speed == 0) - // return null; - // return speed > 0 ? Direction.UP : Direction.DOWN; - // } - // - // @Override - // public boolean isSourceRemoved() { - // return removed; - // } - // - // @Override - // public Direction getAirflowOriginSide() { - // return world != null && !(world.getTileEntity(pos.down()) instanceof - // IAirCurrentSource) - // && getBlockState().get(ChuteBlock.FACING) == Direction.DOWN ? Direction.DOWN - // : Direction.UP; - // } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteRenderer.java deleted file mode 100644 index f31cee7b8e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteRenderer.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; - -public class SmartChuteRenderer extends SmartTileEntityRenderer { - - public SmartChuteRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(SmartChuteTileEntity tileEntityIn, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - super.renderSafe(tileEntityIn, partialTicks, ms, buffer, light, overlay); - if (tileEntityIn.item.isEmpty()) - return; - if (tileEntityIn.itemPosition.getValue(partialTicks) > 0) - return; - ChuteRenderer.renderItem(tileEntityIn, partialTicks, ms, buffer, light, overlay); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteTileEntity.java deleted file mode 100644 index a740833cfe..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteTileEntity.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.simibubi.create.content.logistics.block.chute; - -import java.util.List; - -import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class SmartChuteTileEntity extends ChuteTileEntity { - - FilteringBehaviour filtering; - - public SmartChuteTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected boolean canAcceptItem(ItemStack stack) { - return super.canAcceptItem(stack) && canCollectItemsFromBelow() && filtering.test(stack); - } - - @Override - protected int getExtractionAmount() { - return filtering.isCountVisible() && !filtering.anyAmount() ? filtering.getAmount() : 64; - } - - @Override - protected ExtractionCountMode getExtractionMode() { - return filtering.isCountVisible() && !filtering.anyAmount() ? ExtractionCountMode.EXACTLY - : ExtractionCountMode.UPTO; - } - - @Override - protected boolean canCollectItemsFromBelow() { - BlockState blockState = getBlockState(); - return blockState.hasProperty(SmartChuteBlock.POWERED) && !blockState.getValue(SmartChuteBlock.POWERED); - } - - @Override - protected boolean canOutputItems() { - BlockState blockState = getBlockState(); - return blockState.hasProperty(SmartChuteBlock.POWERED) && !blockState.getValue(SmartChuteBlock.POWERED); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(filtering = - new FilteringBehaviour(this, new SmartChuteFilterSlotPositioning()).showCountWhen(this::isExtracting)); - super.addBehaviours(behaviours); - } - - private boolean isExtracting() { - boolean up = getItemMotion() < 0; - BlockPos chutePos = worldPosition.relative(up ? Direction.UP : Direction.DOWN); - BlockState blockState = level.getBlockState(chutePos); - return !AbstractChuteBlock.isChute(blockState) && !blockState.getMaterial() - .isReplaceable(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java deleted file mode 100644 index b6b42b325d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBlock.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class DepotBlock extends Block implements ITE, IWrenchable { - - public DepotBlock(Properties p_i48440_1_) { - super(p_i48440_1_); - } - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.DEPOT; - } - - @Override - public Class getTileEntityClass() { - return DepotTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.DEPOT.get(); - } - - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult ray) { - return SharedDepotBlockMethods.onUse(state, world, pos, player, hand, ray); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - SharedDepotBlockMethods.onReplaced(state, worldIn, pos, newState, isMoving); - } - - @Override - public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { - super.updateEntityAfterFallOn(worldIn, entityIn); - SharedDepotBlockMethods.onLanded(worldIn, entityIn); - } - - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return SharedDepotBlockMethods.getComparatorInputOverride(blockState, worldIn, pos); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java deleted file mode 100644 index e7b9a44734..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotItemHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; - -public class DepotItemHandler implements IItemHandler { - - private static final int MAIN_SLOT = 0; - private DepotBehaviour te; - - public DepotItemHandler(DepotBehaviour te) { - this.te = te; - } - - @Override - public int getSlots() { - return 9; - } - - @Override - public ItemStack getStackInSlot(int slot) { - return slot == MAIN_SLOT ? te.getHeldItemStack() : te.processingOutputBuffer.getStackInSlot(slot - 1); - } - - @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { - if (slot != MAIN_SLOT) - return stack; - if (!te.getHeldItemStack() - .isEmpty() && !te.canMergeItems()) - return stack; - if (!te.isOutputEmpty() && !te.canMergeItems()) - return stack; - - ItemStack remainder = te.insert(new TransportedItemStack(stack), simulate); - if (!simulate && remainder != stack) - te.tileEntity.notifyUpdate(); - return remainder; - } - - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) { - if (slot != MAIN_SLOT) - return te.processingOutputBuffer.extractItem(slot - 1, amount, simulate); - - TransportedItemStack held = te.heldItem; - if (held == null) - return ItemStack.EMPTY; - ItemStack stack = held.stack.copy(); - ItemStack extracted = stack.split(amount); - if (!simulate) { - te.heldItem.stack = stack; - if (stack.isEmpty()) - te.heldItem = null; - te.tileEntity.notifyUpdate(); - } - return extracted; - } - - @Override - public int getSlotLimit(int slot) { - return slot == MAIN_SLOT ? te.maxStackSize.get() : 64; - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - return slot == MAIN_SLOT && te.isItemValid(stack); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java deleted file mode 100644 index 308237dec1..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import java.util.List; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; - -public class DepotTileEntity extends SmartTileEntity { - - DepotBehaviour depotBehaviour; - - public DepotTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(depotBehaviour = new DepotBehaviour(this)); - depotBehaviour.addSubBehaviours(behaviours); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return depotBehaviour.getItemCapability(cap, side); - return super.getCapability(cap, side); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorAwardPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorAwardPacket.java deleted file mode 100644 index d9c698bbf7..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorAwardPacket.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; - -public class EjectorAwardPacket extends TileEntityConfigurationPacket { - - public EjectorAwardPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - public EjectorAwardPacket(BlockPos pos) { - super(pos); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) {} - - @Override - protected void readSettings(FriendlyByteBuf buffer) {} - - @Override - protected void applySettings(ServerPlayer player, EjectorTileEntity te) { - AllAdvancements.EJECTOR_MAXED.awardTo(player); - } - - @Override - protected void applySettings(EjectorTileEntity te) {} - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorBlock.java deleted file mode 100644 index ed026a63d9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorBlock.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import java.util.Optional; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.logistics.block.depot.EjectorTileEntity.State; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.networking.AllPackets; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -public class EjectorBlock extends HorizontalKineticBlock implements ITE { - - public EjectorBlock(Properties properties) { - super(properties); - } - - @Override - public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.DEPOT; - } - - @Override - public float getFriction(BlockState state, LevelReader world, BlockPos pos, Entity entity) { - return getTileEntityOptional(world, pos).filter(ete -> ete.state == State.LAUNCHING) - .map($ -> 1f) - .orElse(super.getFriction(state, world, pos, entity)); - } - - @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, - boolean p_220069_6_) { - withTileEntityDo(world, pos, EjectorTileEntity::updateSignal); - } - - @Override - public void fallOn(Level p_180658_1_, BlockState p_152427_, BlockPos p_180658_2_, Entity p_180658_3_, - float p_180658_4_) { - Optional tileEntityOptional = getTileEntityOptional(p_180658_1_, p_180658_2_); - if (tileEntityOptional.isPresent() && !p_180658_3_.isSuppressingBounce()) { - p_180658_3_.causeFallDamage(p_180658_4_, 1.0F, DamageSource.FALL); - return; - } - super.fallOn(p_180658_1_, p_152427_, p_180658_2_, p_180658_3_, p_180658_4_); - } - - @Override - public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { - super.updateEntityAfterFallOn(worldIn, entityIn); - BlockPos position = entityIn.blockPosition(); - if (!AllBlocks.WEIGHTED_EJECTOR.has(worldIn.getBlockState(position))) - return; - if (!entityIn.isAlive()) - return; - if (entityIn.isSuppressingBounce()) - return; - if (entityIn instanceof ItemEntity) { - SharedDepotBlockMethods.onLanded(worldIn, entityIn); - return; - } - - Optional teProvider = getTileEntityOptional(worldIn, position); - if (!teProvider.isPresent()) - return; - - EjectorTileEntity ejectorTileEntity = teProvider.get(); - if (ejectorTileEntity.getState() == State.RETRACTING) - return; - if (ejectorTileEntity.powered) - return; - if (ejectorTileEntity.launcher.getHorizontalDistance() == 0) - return; - - if (entityIn.isOnGround()) { - entityIn.setOnGround(false); - Vec3 center = VecHelper.getCenterOf(position) - .add(0, 7 / 16f, 0); - Vec3 positionVec = entityIn.position(); - double diff = center.distanceTo(positionVec); - entityIn.setDeltaMovement(0, -0.125, 0); - Vec3 vec = center.add(positionVec) - .scale(.5f); - if (diff > 4 / 16f) { - entityIn.setPos(vec.x, vec.y, vec.z); - return; - } - } - - ejectorTileEntity.activate(); - ejectorTileEntity.notifyUpdate(); - if (entityIn.level.isClientSide) - AllPackets.channel.sendToServer(new EjectorTriggerPacket(ejectorTileEntity.getBlockPos())); - } - - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult ray) { - if (AllItems.WRENCH.isIn(player.getItemInHand(hand))) - return InteractionResult.PASS; - return SharedDepotBlockMethods.onUse(state, world, pos, player, hand, ray); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - withTileEntityDo(worldIn, pos, EjectorTileEntity::dropFlyingItems); - SharedDepotBlockMethods.onReplaced(state, worldIn, pos, newState, isMoving); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return state.getValue(HORIZONTAL_FACING) - .getClockWise() - .getAxis(); - } - - @Override - public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { - return getRotationAxis(state) == face.getAxis(); - } - - @Override - public Class getTileEntityClass() { - return EjectorTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.WEIGHTED_EJECTOR.get(); - } - - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { - return SharedDepotBlockMethods.getComparatorInputOverride(blockState, worldIn, pos); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorElytraPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorElytraPacket.java deleted file mode 100644 index f2058d433e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorElytraPacket.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent.Context; - -public class EjectorElytraPacket extends SimplePacketBase { - - private BlockPos pos; - - public EjectorElytraPacket(BlockPos pos) { - this.pos = pos; - } - - public EjectorElytraPacket(FriendlyByteBuf buffer) { - pos = buffer.readBlockPos(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeBlockPos(pos); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - Level world = player.level; - if (world == null || !world.isLoaded(pos)) - return; - BlockEntity tileEntity = world.getBlockEntity(pos); - if (tileEntity instanceof EjectorTileEntity) - ((EjectorTileEntity) tileEntity).deployElytra(player); - }); - context.get() - .setPacketHandled(true); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorInstance.java deleted file mode 100644 index 146904adff..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorInstance.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.util.Mth; - -public class EjectorInstance extends ShaftInstance implements DynamicInstance { - - protected final EjectorTileEntity tile; - - protected final ModelData plate; - - private float lastProgress = Float.NaN; - - public EjectorInstance(MaterialManager dispatcher, EjectorTileEntity tile) { - super(dispatcher, tile); - this.tile = tile; - - plate = getTransformMaterial().getModel(AllBlockPartials.EJECTOR_TOP, blockState).createInstance(); - - pivotPlate(); - } - - @Override - public void beginFrame() { - float lidProgress = getLidProgress(); - - if (Mth.equal(lidProgress, lastProgress)) return; - - pivotPlate(lidProgress); - lastProgress = lidProgress; - } - - @Override - public void updateLight() { - super.updateLight(); - relight(pos, plate); - } - - @Override - public void remove() { - super.remove(); - plate.delete(); - } - - private void pivotPlate() { - pivotPlate(getLidProgress()); - } - - private float getLidProgress() { - return tile.getLidProgress(AnimationTickHolder.getPartialTicks()); - } - - private void pivotPlate(float lidProgress) { - float angle = lidProgress * 70; - - plate.loadIdentity() - .translate(getInstancePosition()) - .centre() - .rotateY(180 + AngleHelper.horizontalAngle(tile.getBlockState() - .getValue(EjectorBlock.HORIZONTAL_FACING))) - .unCentre() - .translate(EjectorRenderer.pivot) - .rotateX(-angle) - .translateBack(EjectorRenderer.pivot); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorPlacementPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorPlacementPacket.java deleted file mode 100644 index 3b56b438fa..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorPlacementPacket.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import java.util.function.Supplier; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.network.NetworkEvent.Context; - -public class EjectorPlacementPacket extends SimplePacketBase { - - private int h, v; - private BlockPos pos; - private Direction facing; - - public EjectorPlacementPacket(int h, int v, BlockPos pos, Direction facing) { - this.h = h; - this.v = v; - this.pos = pos; - this.facing = facing; - } - - public EjectorPlacementPacket(FriendlyByteBuf buffer) { - h = buffer.readInt(); - v = buffer.readInt(); - pos = buffer.readBlockPos(); - facing = Direction.from3DDataValue(buffer.readVarInt()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(h); - buffer.writeInt(v); - buffer.writeBlockPos(pos); - buffer.writeVarInt(facing.get3DDataValue()); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - Level world = player.level; - if (world == null || !world.isLoaded(pos)) - return; - BlockEntity tileEntity = world.getBlockEntity(pos); - BlockState state = world.getBlockState(pos); - if (tileEntity instanceof EjectorTileEntity) - ((EjectorTileEntity) tileEntity).setTarget(h, v); - if (AllBlocks.WEIGHTED_EJECTOR.has(state)) - world.setBlockAndUpdate(pos, state.setValue(EjectorBlock.HORIZONTAL_FACING, facing)); - }); - context.get() - .setPacketHandled(true); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorRenderer.java deleted file mode 100644 index 4df5815c1f..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorRenderer.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.IntAttached; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.flw.Rotate; -import net.createmod.catnip.utility.flw.Translate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class EjectorRenderer extends KineticTileEntityRenderer { - - static final Vec3 pivot = VecHelper.voxelSpace(0, 11.25, 0.75); - - public EjectorRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - public boolean shouldRenderOffScreen(KineticTileEntity p_188185_1_) { - return true; - } - - @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - EjectorTileEntity ejector = (EjectorTileEntity) te; - VertexConsumer vertexBuilder = buffer.getBuffer(RenderType.solid()); - float lidProgress = ((EjectorTileEntity) te).getLidProgress(partialTicks); - float angle = lidProgress * 70; - - if (!Backend.canUseInstancing(te.getLevel())) { - SuperByteBuffer model = CachedPartialBuffers.partial(AllBlockPartials.EJECTOR_TOP, te.getBlockState()); - applyLidAngle(te, angle, model); - model.light(light).renderInto(ms, vertexBuilder); - } - - TransformStack msr = TransformStack.cast(ms); - - float maxTime = - (float) (ejector.earlyTarget != null ? ejector.earlyTargetTime : ejector.launcher.getTotalFlyingTicks()); - for (IntAttached intAttached : ejector.launchedItems) { - float time = intAttached.getFirst() + partialTicks; - if (time > maxTime) - continue; - - ms.pushPose(); - Vec3 launchedItemLocation = ejector.getLaunchedItemLocation(time); - msr.translate(launchedItemLocation.subtract(Vec3.atLowerCornerOf(te.getBlockPos()))); - Vec3 itemRotOffset = VecHelper.voxelSpace(0, 3, 0); - msr.translate(itemRotOffset); - msr.rotateY(AngleHelper.horizontalAngle(ejector.getFacing())); - msr.rotateX(time * 40); - msr.translateBack(itemRotOffset); - Minecraft.getInstance() - .getItemRenderer() - .renderStatic(intAttached.getValue(), TransformType.GROUND, light, overlay, ms, buffer, 0); - ms.popPose(); - } - - DepotBehaviour behaviour = te.getBehaviour(DepotBehaviour.TYPE); - if (behaviour == null || behaviour.isEmpty()) - return; - - ms.pushPose(); - - //inlined #applyLidAngle - msr.centre() - .rotateY(180 + AngleHelper.horizontalAngle(te.getBlockState() - .getValue(EjectorBlock.HORIZONTAL_FACING))) - .unCentre() - .translate(pivot) - .rotateX(-angle) - .translateBack(pivot); - - msr.centre() - .rotateY(-180 - AngleHelper.horizontalAngle(te.getBlockState() - .getValue(EjectorBlock.HORIZONTAL_FACING))) - .unCentre(); - DepotRenderer.renderItemsOf(te, partialTicks, ms, buffer, light, overlay, behaviour); - ms.popPose(); - } - - static & Rotate> void applyLidAngle(KineticTileEntity te, float angle, T tr) { - applyLidAngle(te, pivot, angle, tr); - } - - static & Rotate> void applyLidAngle(KineticTileEntity te, Vec3 rotationOffset, float angle, T tr) { - tr.centre() - .rotateY(180 + AngleHelper.horizontalAngle(te.getBlockState() - .getValue(EjectorBlock.HORIZONTAL_FACING))) - .unCentre() - .translate(rotationOffset) - .rotateX(-angle) - .translateBack(rotationOffset); - } - - @Override - protected BlockState getRenderedBlockState(KineticTileEntity te) { - return shaft(getRotationAxisOf(te)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTileEntity.java deleted file mode 100644 index eecd04fe16..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTileEntity.java +++ /dev/null @@ -1,649 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.content.logistics.block.funnel.AbstractFunnelBlock; -import com.simibubi.create.content.logistics.block.funnel.FunnelBlock; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.IntAttached; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.nbt.Tag; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ElytraItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.ClipContext.Block; -import net.minecraft.world.level.ClipContext.Fluid; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.ObserverBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.PushReaction; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult.Type; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.ItemStackHandler; - -public class EjectorTileEntity extends KineticTileEntity { - - List> launchedItems; - ScrollValueBehaviour maxStackSize; - DepotBehaviour depotBehaviour; - EntityLauncher launcher; - LerpedFloat lidProgress; - boolean powered; - boolean launch; - State state; - - // item collision - @Nullable - Pair earlyTarget; - float earlyTargetTime; - // runtime stuff - int scanCooldown; - ItemStack trackedItem; - - public enum State { - CHARGED, LAUNCHING, RETRACTING; - } - - public EjectorTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - launcher = new EntityLauncher(1, 0); - lidProgress = LerpedFloat.linear() - .startWithValue(1); - this.state = State.RETRACTING; - launchedItems = new ArrayList<>(); - powered = false; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - behaviours.add(depotBehaviour = new DepotBehaviour(this)); - - maxStackSize = new ScrollValueBehaviour(CreateLang.translateDirect("weighted_ejector.stack_size"), this, new EjectorSlot()) - .between(0, 64) - .withFormatter(i -> i == 0 ? "*" : String.valueOf(i)) - .onlyActiveWhen(() -> state == State.CHARGED) - .requiresWrench(); - behaviours.add(maxStackSize); - - depotBehaviour.maxStackSize = () -> maxStackSize.getValue(); - depotBehaviour.canAcceptItems = () -> state == State.CHARGED; - depotBehaviour.canFunnelsPullFrom = side -> side != getFacing(); - depotBehaviour.enableMerging(); - depotBehaviour.addSubBehaviours(behaviours); - } - - @Override - public void initialize() { - super.initialize(); - updateSignal(); - } - - public void activate() { - launch = true; - nudgeEntities(); - } - - protected boolean cannotLaunch() { - return state != State.CHARGED && !(level.isClientSide && state == State.LAUNCHING); - } - - public void activateDeferred() { - if (cannotLaunch()) - return; - Direction facing = getFacing(); - List entities = - level.getEntitiesOfClass(Entity.class, new AABB(worldPosition).inflate(-1 / 16f, 0, -1 / 16f)); - - // Launch Items - boolean doLogic = !level.isClientSide || isVirtual(); - if (doLogic) - launchItems(); - - // Launch Entities - for (Entity entity : entities) { - boolean isPlayerEntity = entity instanceof Player; - if (!entity.isAlive()) - continue; - if (entity instanceof ItemEntity) - continue; - if (entity.getPistonPushReaction() == PushReaction.IGNORE) - continue; - - entity.setOnGround(false); - - if (isPlayerEntity != level.isClientSide) - continue; - - entity.setPos(worldPosition.getX() + .5f, worldPosition.getY() + 1, worldPosition.getZ() + .5f); - launcher.applyMotion(entity, facing); - - if (!isPlayerEntity) - continue; - - Player playerEntity = (Player) entity; - - if (launcher.getHorizontalDistance() * launcher.getHorizontalDistance() - + launcher.getVerticalDistance() * launcher.getVerticalDistance() >= 25 * 25) - AllPackets.channel.sendToServer(new EjectorAwardPacket(worldPosition)); - - if (!(playerEntity.getItemBySlot(EquipmentSlot.CHEST) - .getItem() instanceof ElytraItem)) - continue; - - playerEntity.setXRot(-35); - playerEntity.setYRot(facing.toYRot()); - playerEntity.setDeltaMovement(playerEntity.getDeltaMovement() - .scale(.75f)); - deployElytra(playerEntity); - AllPackets.channel.sendToServer(new EjectorElytraPacket(worldPosition)); - } - - if (doLogic) { - lidProgress.chase(1, .8f, Chaser.EXP); - state = State.LAUNCHING; - if (!level.isClientSide) { - level.playSound(null, worldPosition, SoundEvents.WOODEN_TRAPDOOR_CLOSE, SoundSource.BLOCKS, .35f, 1f); - level.playSound(null, worldPosition, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, .1f, 1.4f); - } - } - } - - public void deployElytra(Player playerEntity) { - EntityHack.setElytraFlying(playerEntity); - } - - protected void launchItems() { - ItemStack heldItemStack = depotBehaviour.getHeldItemStack(); - Direction funnelFacing = getFacing().getOpposite(); - - if (AbstractFunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == funnelFacing) { - DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE); - - if (depotBehaviour.heldItem != null) { - ItemStack remainder = directOutput.tryExportingToBeltFunnel(heldItemStack, funnelFacing, false); - if (remainder == null) - ; - else if (remainder.isEmpty()) - depotBehaviour.removeHeldItem(); - else if (!remainder.sameItem(heldItemStack)) - depotBehaviour.heldItem.stack = remainder; - } - - for (Iterator iterator = depotBehaviour.incoming.iterator(); iterator.hasNext();) { - TransportedItemStack transportedItemStack = iterator.next(); - ItemStack stack = transportedItemStack.stack; - ItemStack remainder = directOutput.tryExportingToBeltFunnel(stack, funnelFacing, false); - if (remainder == null) - ; - else if (remainder.isEmpty()) - iterator.remove(); - else if (!remainder.sameItem(stack)) - transportedItemStack.stack = remainder; - } - - ItemStackHandler outputs = depotBehaviour.processingOutputBuffer; - for (int i = 0; i < outputs.getSlots(); i++) { - ItemStack remainder = - directOutput.tryExportingToBeltFunnel(outputs.getStackInSlot(i), funnelFacing, false); - if (remainder != null) - outputs.setStackInSlot(i, remainder); - } - return; - } - - if (!level.isClientSide) - for (Direction d : Iterate.directions) { - BlockState blockState = level.getBlockState(worldPosition.relative(d)); - if (!(blockState.getBlock() instanceof ObserverBlock)) - continue; - if (blockState.getValue(ObserverBlock.FACING) != d.getOpposite()) - continue; - blockState.updateShape(d.getOpposite(), blockState, level, worldPosition.relative(d), worldPosition); - } - - if (depotBehaviour.heldItem != null) { - addToLaunchedItems(heldItemStack); - depotBehaviour.removeHeldItem(); - } - - for (TransportedItemStack transportedItemStack : depotBehaviour.incoming) - addToLaunchedItems(transportedItemStack.stack); - depotBehaviour.incoming.clear(); - - ItemStackHandler outputs = depotBehaviour.processingOutputBuffer; - for (int i = 0; i < outputs.getSlots(); i++) { - ItemStack extractItem = outputs.extractItem(i, 64, false); - if (!extractItem.isEmpty()) - addToLaunchedItems(extractItem); - } - } - - protected boolean addToLaunchedItems(ItemStack stack) { - if ((!level.isClientSide || isVirtual()) && trackedItem == null && scanCooldown == 0) { - scanCooldown = AllConfigs.SERVER.kinetics.ejectorScanInterval.get(); - trackedItem = stack; - } - return launchedItems.add(IntAttached.withZero(stack)); - } - - protected Direction getFacing() { - BlockState blockState = getBlockState(); - if (!AllBlocks.WEIGHTED_EJECTOR.has(blockState)) - return Direction.UP; - Direction facing = blockState.getValue(EjectorBlock.HORIZONTAL_FACING); - return facing; - } - - @Override - public void tick() { - super.tick(); - - boolean doLogic = !level.isClientSide || isVirtual(); - State prevState = state; - float totalTime = Math.max(3, (float) launcher.getTotalFlyingTicks()); - - if (scanCooldown > 0) - scanCooldown--; - - if (launch) { - launch = false; - activateDeferred(); - } - - for (Iterator> iterator = launchedItems.iterator(); iterator.hasNext();) { - IntAttached intAttached = iterator.next(); - boolean hit = false; - if (intAttached.getSecond() == trackedItem) - hit = scanTrajectoryForObstacles(intAttached.getFirst()); - float maxTime = earlyTarget != null ? Math.min(earlyTargetTime, totalTime) : totalTime; - if (hit || intAttached.exceeds((int) maxTime)) { - placeItemAtTarget(doLogic, maxTime, intAttached); - iterator.remove(); - } - intAttached.increment(); - } - - if (state == State.LAUNCHING) { - lidProgress.chase(1, .8f, Chaser.EXP); - lidProgress.tickChaser(); - if (lidProgress.getValue() > 1 - 1 / 16f && doLogic) { - state = State.RETRACTING; - lidProgress.setValue(1); - } - } - - if (state == State.CHARGED) { - lidProgress.setValue(0); - lidProgress.updateChaseSpeed(0); - if (doLogic) - ejectIfTriggered(); - } - - if (state == State.RETRACTING) { - if (lidProgress.getChaseTarget() == 1 && !lidProgress.settled()) { - lidProgress.tickChaser(); - } else { - lidProgress.updateChaseTarget(0); - lidProgress.updateChaseSpeed(0); - if (lidProgress.getValue() == 0 && doLogic) { - state = State.CHARGED; - lidProgress.setValue(0); - sendData(); - } - - float value = Mth.clamp(lidProgress.getValue() - getWindUpSpeed(), 0, 1); - lidProgress.setValue(value); - - int soundRate = (int) (1 / (getWindUpSpeed() * 5)) + 1; - float volume = .125f; - float pitch = 1.5f - lidProgress.getValue(); - if (((int) level.getGameTime()) % soundRate == 0 && doLogic) - level.playSound(null, worldPosition, SoundEvents.WOODEN_BUTTON_CLICK_OFF, SoundSource.BLOCKS, - volume, pitch); - } - } - - if (state != prevState) - notifyUpdate(); - } - - private boolean scanTrajectoryForObstacles(int time) { - if (time <= 2) - return false; - - Vec3 source = getLaunchedItemLocation(time); - Vec3 target = getLaunchedItemLocation(time + 1); - - BlockHitResult rayTraceBlocks = level.clip(new ClipContext(source, target, Block.COLLIDER, Fluid.NONE, null)); - boolean miss = rayTraceBlocks.getType() == Type.MISS; - - if (!miss && rayTraceBlocks.getType() == Type.BLOCK) { - BlockState blockState = level.getBlockState(rayTraceBlocks.getBlockPos()); - if (FunnelBlock.isFunnel(blockState) && blockState.hasProperty(FunnelBlock.EXTRACTING) - && blockState.getValue(FunnelBlock.EXTRACTING)) - miss = true; - } - - if (miss) { - if (earlyTarget != null && earlyTargetTime < time + 1) { - earlyTarget = null; - earlyTargetTime = 0; - } - return false; - } - - Vec3 vec = rayTraceBlocks.getLocation(); - earlyTarget = Pair.of(vec.add(Vec3.atLowerCornerOf(rayTraceBlocks.getDirection() - .getNormal()) - .scale(.25f)), rayTraceBlocks.getBlockPos()); - earlyTargetTime = (float) (time + (source.distanceTo(vec) / source.distanceTo(target))); - sendData(); - return true; - } - - protected void nudgeEntities() { - for (Entity entity : level.getEntitiesOfClass(Entity.class, - new AABB(worldPosition).inflate(-1 / 16f, 0, -1 / 16f))) { - if (!entity.isAlive()) - continue; - if (entity.getPistonPushReaction() == PushReaction.IGNORE) - continue; - if (!(entity instanceof Player)) - entity.setPos(entity.getX(), entity.getY() + .125f, entity.getZ()); - } - } - - protected void ejectIfTriggered() { - if (powered) - return; - int presentStackSize = depotBehaviour.getPresentStackSize(); - if (presentStackSize == 0) - return; - if (presentStackSize < maxStackSize.getValue()) - return; - if (depotBehaviour.heldItem != null && depotBehaviour.heldItem.beltPosition < .49f) - return; - - Direction funnelFacing = getFacing().getOpposite(); - ItemStack held = depotBehaviour.getHeldItemStack(); - if (AbstractFunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == funnelFacing) { - DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE); - if (depotBehaviour.heldItem != null) { - ItemStack tryFunnel = directOutput.tryExportingToBeltFunnel(held, funnelFacing, true); - if (tryFunnel == null || !tryFunnel.isEmpty()) - return; - } - } - - DirectBeltInputBehaviour targetOpenInv = getTargetOpenInv(); - - // Do not eject if target cannot accept held item - if (targetOpenInv != null && depotBehaviour.heldItem != null - && targetOpenInv.handleInsertion(held, Direction.UP, true) - .getCount() == held.getCount()) - return; - - activate(); - notifyUpdate(); - } - - protected void placeItemAtTarget(boolean doLogic, float maxTime, IntAttached intAttached) { - if (!doLogic) - return; - if (intAttached.getSecond() == trackedItem) - trackedItem = null; - - DirectBeltInputBehaviour targetOpenInv = getTargetOpenInv(); - if (targetOpenInv != null) { - ItemStack remainder = targetOpenInv.handleInsertion(intAttached.getValue(), Direction.UP, false); - intAttached.setSecond(remainder); - } - - if (intAttached.getValue() - .isEmpty()) - return; - - Vec3 ejectVec = earlyTarget != null ? earlyTarget.getFirst() : getLaunchedItemLocation(maxTime); - Vec3 ejectMotionVec = getLaunchedItemMotion(maxTime); - ItemEntity item = new ItemEntity(level, ejectVec.x, ejectVec.y, ejectVec.z, intAttached.getValue()); - item.setDeltaMovement(ejectMotionVec); - item.setDefaultPickUpDelay(); - level.addFreshEntity(item); - } - - public DirectBeltInputBehaviour getTargetOpenInv() { - BlockPos targetPos = earlyTarget != null ? earlyTarget.getSecond() - : worldPosition.above(launcher.getVerticalDistance()) - .relative(getFacing(), Math.max(1, launcher.getHorizontalDistance())); - return TileEntityBehaviour.get(level, targetPos, DirectBeltInputBehaviour.TYPE); - } - - public Vec3 getLaunchedItemLocation(float time) { - return launcher.getGlobalPos(time, getFacing().getOpposite(), worldPosition); - } - - public Vec3 getLaunchedItemMotion(float time) { - return launcher.getGlobalVelocity(time, getFacing().getOpposite(), worldPosition) - .scale(.5f); - } - - public void dropFlyingItems() { - for (IntAttached intAttached : launchedItems) { - Vec3 ejectVec = getLaunchedItemLocation(intAttached.getFirst()); - Vec3 ejectMotionVec = getLaunchedItemMotion(intAttached.getFirst()); - ItemEntity item = new ItemEntity(level, 0, 0, 0, intAttached.getValue()); - item.setPosRaw(ejectVec.x, ejectVec.y, ejectVec.z); - item.setDeltaMovement(ejectMotionVec); - item.setDefaultPickUpDelay(); - level.addFreshEntity(item); - } - launchedItems.clear(); - } - - public float getWindUpSpeed() { - int hd = launcher.getHorizontalDistance(); - int vd = launcher.getVerticalDistance(); - - float speedFactor = Math.abs(getSpeed()) / 256f; - float distanceFactor; - if (hd == 0 && vd == 0) - distanceFactor = 1; - else - distanceFactor = 1 * Mth.sqrt(hd * hd + vd * vd); - return speedFactor / distanceFactor; - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.putInt("HorizontalDistance", launcher.getHorizontalDistance()); - compound.putInt("VerticalDistance", launcher.getVerticalDistance()); - compound.putBoolean("Powered", powered); - NBTHelper.writeEnum(compound, "State", state); - compound.put("Lid", lidProgress.writeNBT()); - compound.put("LaunchedItems", - NBTHelper.writeCompoundList(launchedItems, ia -> ia.serializeNBT(ItemStack::serializeNBT))); - - if (earlyTarget != null) { - compound.put("EarlyTarget", VecHelper.writeNBT(earlyTarget.getFirst())); - compound.put("EarlyTargetPos", NbtUtils.writeBlockPos(earlyTarget.getSecond())); - compound.putFloat("EarlyTargetTime", earlyTargetTime); - } - } - - @Override - public void writeSafe(CompoundTag compound) { - super.writeSafe(compound); - compound.putInt("HorizontalDistance", launcher.getHorizontalDistance()); - compound.putInt("VerticalDistance", launcher.getVerticalDistance()); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - int horizontalDistance = compound.getInt("HorizontalDistance"); - int verticalDistance = compound.getInt("VerticalDistance"); - - if (launcher.getHorizontalDistance() != horizontalDistance - || launcher.getVerticalDistance() != verticalDistance) { - launcher.set(horizontalDistance, verticalDistance); - launcher.clamp(AllConfigs.SERVER.kinetics.maxEjectorDistance.get()); - } - - powered = compound.getBoolean("Powered"); - state = NBTHelper.readEnum(compound, "State", State.class); - lidProgress.readNBT(compound.getCompound("Lid"), false); - launchedItems = NBTHelper.readCompoundList(compound.getList("LaunchedItems", Tag.TAG_COMPOUND), - nbt -> IntAttached.read(nbt, ItemStack::of)); - - earlyTarget = null; - earlyTargetTime = 0; - if (compound.contains("EarlyTarget")) { - earlyTarget = Pair.of(VecHelper.readNBT(compound.getList("EarlyTarget", Tag.TAG_DOUBLE)), - NbtUtils.readBlockPos(compound.getCompound("EarlyTargetPos"))); - earlyTargetTime = compound.getFloat("EarlyTargetTime"); - } - - if (compound.contains("ForceAngle")) - lidProgress.startWithValue(compound.getFloat("ForceAngle")); - } - - public void updateSignal() { - boolean shoudPower = level.hasNeighborSignal(worldPosition); - if (shoudPower == powered) - return; - powered = shoudPower; - sendData(); - } - - public void setTarget(int horizontalDistance, int verticalDistance) { - launcher.set(Math.max(1, horizontalDistance), verticalDistance); - sendData(); - } - - public BlockPos getTargetPosition() { - BlockState blockState = getBlockState(); - if (!AllBlocks.WEIGHTED_EJECTOR.has(blockState)) - return worldPosition; - Direction facing = blockState.getValue(EjectorBlock.HORIZONTAL_FACING); - return worldPosition.relative(facing, launcher.getHorizontalDistance()) - .above(launcher.getVerticalDistance()); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return depotBehaviour.getItemCapability(cap, side); - return super.getCapability(cap, side); - } - - public float getLidProgress(float pt) { - return lidProgress.getValue(pt); - } - - public State getState() { - return state; - } - - @Override - @OnlyIn(Dist.CLIENT) - public AABB getRenderBoundingBox() { - return INFINITE_EXTENT_AABB; - } - - private static abstract class EntityHack extends Entity { - - public EntityHack(EntityType p_i48580_1_, Level p_i48580_2_) { - super(p_i48580_1_, p_i48580_2_); - } - - public static void setElytraFlying(Entity e) { - SynchedEntityData data = e.getEntityData(); - data.set(DATA_SHARED_FLAGS_ID, (byte) (data.get(DATA_SHARED_FLAGS_ID) | 1 << 7)); - } - - } - - private static class EjectorSlot extends ValueBoxTransform.Sided { - - @Override - protected Vec3 getLocalOffset(BlockState state) { - return new Vec3(.5, 13 / 16f, .5).add(VecHelper.rotate(new Vec3(0, 0, -.3), angle(state), Axis.Y)); - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - TransformStack.cast(ms) - .rotateY(angle(state)) - .rotateX(90); - } - - protected float angle(BlockState state) { - float horizontalAngle = AllBlocks.WEIGHTED_EJECTOR.has(state) - ? AngleHelper.horizontalAngle(state.getValue(EjectorBlock.HORIZONTAL_FACING)) - : 0; - return horizontalAngle; - } - - @Override - protected boolean isSideActive(BlockState state, Direction direction) { - return direction == Direction.UP; - } - - @Override - protected float getScale() { - return 0.2f; - } - - @Override - protected Vec3 getSouthLocation() { - return Vec3.ZERO; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTriggerPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTriggerPacket.java deleted file mode 100644 index 3427876931..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTriggerPacket.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; - -public class EjectorTriggerPacket extends TileEntityConfigurationPacket { - - public EjectorTriggerPacket(BlockPos pos) { - super(pos); - } - - public EjectorTriggerPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) {} - - @Override - protected void readSettings(FriendlyByteBuf buffer) {} - - @Override - protected void applySettings(EjectorTileEntity te) { - te.activate(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/SharedDepotBlockMethods.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/SharedDepotBlockMethods.java deleted file mode 100644 index 1cce72cbf5..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/SharedDepotBlockMethods.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.simibubi.create.content.logistics.block.depot; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.Containers; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.items.ItemStackHandler; - -public class SharedDepotBlockMethods { - - protected static DepotBehaviour get(BlockGetter worldIn, BlockPos pos) { - return TileEntityBehaviour.get(worldIn, pos, DepotBehaviour.TYPE); - } - - public static InteractionResult onUse(BlockState state, Level world, BlockPos pos, Player player, - InteractionHand hand, BlockHitResult ray) { - if (ray.getDirection() != Direction.UP) - return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; - - DepotBehaviour behaviour = get(world, pos); - if (behaviour == null) - return InteractionResult.PASS; - if (!behaviour.canAcceptItems.get()) - return InteractionResult.SUCCESS; - - ItemStack heldItem = player.getItemInHand(hand); - boolean wasEmptyHanded = heldItem.isEmpty(); - boolean shouldntPlaceItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem); - - ItemStack mainItemStack = behaviour.getHeldItemStack(); - if (!mainItemStack.isEmpty()) { - player.getInventory() - .placeItemBackInInventory(mainItemStack); - behaviour.removeHeldItem(); - world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, - 1f + Create.RANDOM.nextFloat()); - } - ItemStackHandler outputs = behaviour.processingOutputBuffer; - for (int i = 0; i < outputs.getSlots(); i++) - player.getInventory() - .placeItemBackInInventory(outputs.extractItem(i, 64, false)); - - if (!wasEmptyHanded && !shouldntPlaceItem) { - TransportedItemStack transported = new TransportedItemStack(heldItem); - transported.insertedFrom = player.getDirection(); - transported.prevBeltPosition = .25f; - transported.beltPosition = .25f; - behaviour.setHeldItem(transported); - player.setItemInHand(hand, ItemStack.EMPTY); - AllSoundEvents.DEPOT_SLIDE.playOnServer(world, pos); - } - - behaviour.tileEntity.notifyUpdate(); - return InteractionResult.SUCCESS; - } - - public static void onReplaced(BlockState state, Level worldIn, BlockPos pos, BlockState newState, - boolean isMoving) { - if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) - return; - DepotBehaviour behaviour = get(worldIn, pos); - if (behaviour == null) - return; - ItemHelper.dropContents(worldIn, pos, behaviour.processingOutputBuffer); - for (TransportedItemStack transportedItemStack : behaviour.incoming) - Containers.dropItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), transportedItemStack.stack); - if (!behaviour.getHeldItemStack() - .isEmpty()) - Containers.dropItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), behaviour.getHeldItemStack()); - worldIn.removeBlockEntity(pos); - } - - public static void onLanded(BlockGetter worldIn, Entity entityIn) { - if (!(entityIn instanceof ItemEntity)) - return; - if (!entityIn.isAlive()) - return; - if (entityIn.level.isClientSide) - return; - - ItemEntity itemEntity = (ItemEntity) entityIn; - DirectBeltInputBehaviour inputBehaviour = - TileEntityBehaviour.get(worldIn, entityIn.blockPosition(), DirectBeltInputBehaviour.TYPE); - if (inputBehaviour == null) - return; - ItemStack remainder = inputBehaviour.handleInsertion(itemEntity.getItem(), Direction.DOWN, false); - itemEntity.setItem(remainder); - if (remainder.isEmpty()) - itemEntity.discard(); - } - - public static int getComparatorInputOverride(BlockState blockState, Level worldIn, BlockPos pos) { - DepotBehaviour depotBehaviour = get(worldIn, pos); - if (depotBehaviour == null) - return 0; - float f = depotBehaviour.getPresentStackSize(); - Integer max = depotBehaviour.maxStackSize.get(); - f = f / (max == 0 ? 64 : max); - return Mth.clamp(Mth.floor(f * 14.0F) + (f > 0 ? 1 : 0), 0, 15); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeBlock.java deleted file mode 100644 index 3b1c7d2b83..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeBlock.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import com.simibubi.create.content.contraptions.wrench.IWrenchable; - -import net.minecraft.world.level.block.DiodeBlock; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class AbstractDiodeBlock extends DiodeBlock implements IWrenchable { - - public AbstractDiodeBlock(Properties builder) { - super(builder); - } - - @Override - public boolean isSignalSource(BlockState state) { - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeInstance.java deleted file mode 100644 index 331aec4159..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeInstance.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.TickableInstance; -import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.simibubi.create.AllBlockPartials; - -import net.createmod.catnip.utility.theme.Color; - -public class BrassDiodeInstance extends BlockEntityInstance implements TickableInstance { - - protected final ModelData indicator; - - protected int previousState; - - public BrassDiodeInstance(MaterialManager modelManager, BrassDiodeTileEntity tile) { - super(modelManager, tile); - - indicator = modelManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.FLEXPEATER_INDICATOR, blockState).createInstance(); - - indicator.loadIdentity() - .translate(getInstancePosition()) - .setColor(getColor()); - - previousState = tile.state; - } - - @Override - public void tick() { - if (previousState == blockEntity.state) return; - - indicator.setColor(getColor()); - - previousState = blockEntity.state; - } - - @Override - public void updateLight() { - relight(pos, indicator); - } - - @Override - public void remove() { - indicator.delete(); - } - - protected int getColor() { - return Color.mixColors(0x2c0300, 0xcd0000, blockEntity.getProgress()); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeRenderer.java deleted file mode 100644 index adf8983b26..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeRenderer.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.ColoredOverlayTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; - -public class BrassDiodeRenderer extends ColoredOverlayTileEntityRenderer { - - public BrassDiodeRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected int getColor(BrassDiodeTileEntity te, float partialTicks) { - return Color.mixColors(0x2C0300, 0xCD0000, te.getProgress()); - } - - @Override - protected SuperByteBuffer getOverlayBuffer(BrassDiodeTileEntity te) { - return CachedPartialBuffers.partial(AllBlockPartials.FLEXPEATER_INDICATOR, te.getBlockState()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeScrollSlot.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeScrollSlot.java deleted file mode 100644 index 3cd3011472..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeScrollSlot.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.Vec3; - -public class BrassDiodeScrollSlot extends ValueBoxTransform { - - @Override - protected Vec3 getLocalOffset(BlockState state) { - return VecHelper.voxelSpace(8, 3f, 8); - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - float yRot = AngleHelper.horizontalAngle(state.getValue(BlockStateProperties.HORIZONTAL_FACING)) + 180; - TransformStack.cast(ms) - .rotateY(yRot) - .rotateX(90); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeTileEntity.java deleted file mode 100644 index 28e2aec103..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeTileEntity.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import static com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock.POWERING; - -import java.util.List; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.DiodeBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class BrassDiodeTileEntity extends SmartTileEntity { - - protected int state; - ScrollValueBehaviour maxState; - - public BrassDiodeTileEntity(BlockEntityType tileEntityTypeIn, BlockPos pos, BlockState state) { - super(tileEntityTypeIn, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - maxState = new ScrollValueBehaviour(CreateLang.translateDirect("generic.delay"), this, new BrassDiodeScrollSlot()) - .between(2, 60 * 20 * 30); - maxState.withStepFunction(this::step); - maxState.withFormatter(this::format); - maxState.withUnit(this::getUnit); - maxState.withCallback(this::onMaxDelayChanged); - behaviours.add(maxState); - } - - public float getProgress() { - int max = Math.max(2, maxState.getValue()); - return Mth.clamp(state, 0, max) / (float) max; - } - - public boolean isIdle() { - return state == 0; - } - - @Override - public void tick() { - super.tick(); - boolean powered = getBlockState().getValue(DiodeBlock.POWERED); - boolean powering = getBlockState().getValue(POWERING); - boolean atMax = state >= maxState.getValue(); - boolean atMin = state <= 0; - updateState(powered, powering, atMax, atMin); - } - - protected abstract void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin); - - private void onMaxDelayChanged(int newMax) { - state = Mth.clamp(state, 0, newMax); - sendData(); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - state = compound.getInt("State"); - super.read(compound, clientPacket); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("State", state); - super.write(compound, clientPacket); - } - - private int step(StepContext context) { - int value = context.currentValue; - if (!context.forward) - value--; - - if (value < 20) - return 1; - if (value < 20 * 60) - return 20; - return 20 * 60; - } - - private String format(int value) { - if (value < 20) - return value + "t"; - if (value < 20 * 60) - return (value / 20) + "s"; - return (value / 20 / 60) + "m"; - } - - private Component getUnit(int value) { - if (value < 20) - return CreateLang.translateDirect("generic.unit.ticks"); - if (value < 20 * 60) - return CreateLang.translateDirect("generic.unit.seconds"); - return CreateLang.translateDirect("generic.unit.minutes"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseExtenderTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseExtenderTileEntity.java deleted file mode 100644 index b73cd24032..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseExtenderTileEntity.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import static com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock.POWERING; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class PulseExtenderTileEntity extends BrassDiodeTileEntity { - - public PulseExtenderTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin) { - if (atMin && !powered) - return; - if (atMin || powered) { - level.setBlockAndUpdate(worldPosition, getBlockState().setValue(POWERING, true)); - state = maxState.getValue(); - return; - } - - if (state == 1) { - if (powering && !level.isClientSide) - level.setBlockAndUpdate(worldPosition, getBlockState().setValue(POWERING, false)); - if (!powered) - state = 0; - return; - } - - if (!powered) - state--; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseRepeaterTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseRepeaterTileEntity.java deleted file mode 100644 index 330c7889ae..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PulseRepeaterTileEntity.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.simibubi.create.content.logistics.block.diodes; - -import static com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock.POWERING; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class PulseRepeaterTileEntity extends BrassDiodeTileEntity { - - public PulseRepeaterTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin) { - if (atMin && !powered) - return; - if (state > maxState.getValue() + 1) { - if (!powered && !powering) - state = 0; - return; - } - - state++; - if (level.isClientSide) - return; - - if (state == maxState.getValue() - 1 && !powering) - level.setBlockAndUpdate(worldPosition, getBlockState().cycle(POWERING)); - if (state == maxState.getValue() + 1 && powering) - level.setBlockAndUpdate(worldPosition, getBlockState().cycle(POWERING)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java b/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java deleted file mode 100644 index cc1b9ec343..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/AllDisplayBehaviours.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.block.display.source.DeathCounterDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.content.logistics.block.display.source.EnchantPowerDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.RedstonePowerDisplaySource; -import com.simibubi.create.content.logistics.block.display.source.ScoreboardDisplaySource; -import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; -import com.simibubi.create.content.logistics.block.display.target.LecternDisplayTarget; -import com.simibubi.create.content.logistics.block.display.target.SignDisplayTarget; -import com.simibubi.create.foundation.utility.CreateRegistry; -import com.tterrag.registrate.util.nullness.NonNullConsumer; - -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.core.BlockPos; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.IRegistryDelegate; - -public class AllDisplayBehaviours { - public static final Map GATHERER_BEHAVIOURS = new HashMap<>(); - - private static final CreateRegistry> SOURCES_BY_BLOCK = new CreateRegistry<>(ForgeRegistries.BLOCKS); - private static final CreateRegistry, List> SOURCES_BY_TILE = new CreateRegistry<>(ForgeRegistries.BLOCK_ENTITIES); - - private static final CreateRegistry TARGETS_BY_BLOCK = new CreateRegistry<>(ForgeRegistries.BLOCKS); - private static final CreateRegistry, DisplayTarget> TARGETS_BY_TILE = new CreateRegistry<>(ForgeRegistries.BLOCK_ENTITIES); - - public static DisplayBehaviour register(ResourceLocation id, DisplayBehaviour behaviour) { - behaviour.id = id; - GATHERER_BEHAVIOURS.put(id, behaviour); - return behaviour; - } - - public static void assignBlock(DisplayBehaviour behaviour, ResourceLocation block) { - if (behaviour instanceof DisplaySource source) { - List sources = SOURCES_BY_BLOCK.get(block); - if (sources == null) { - sources = new ArrayList<>(); - SOURCES_BY_BLOCK.register(block, sources); - } - sources.add(source); - } - if (behaviour instanceof DisplayTarget target) { - TARGETS_BY_BLOCK.register(block, target); - } - } - - public static void assignTile(DisplayBehaviour behaviour, ResourceLocation teType) { - if (behaviour instanceof DisplaySource source) { - List sources = SOURCES_BY_TILE.get(teType); - if (sources == null) { - sources = new ArrayList<>(); - SOURCES_BY_TILE.register(teType, sources); - } - sources.add(source); - } - if (behaviour instanceof DisplayTarget target) { - TARGETS_BY_TILE.register(teType, target); - } - } - - public static void assignBlock(DisplayBehaviour behaviour, Block block) { - if (behaviour instanceof DisplaySource source) { - List sources = SOURCES_BY_BLOCK.get(block); - if (sources == null) { - sources = new ArrayList<>(); - SOURCES_BY_BLOCK.register(block, sources); - } - sources.add(source); - } - if (behaviour instanceof DisplayTarget target) { - TARGETS_BY_BLOCK.register(block, target); - } - } - - public static void assignTile(DisplayBehaviour behaviour, BlockEntityType teType) { - if (behaviour instanceof DisplaySource source) { - List sources = SOURCES_BY_TILE.get(teType); - if (sources == null) { - sources = new ArrayList<>(); - SOURCES_BY_TILE.register(teType, sources); - } - sources.add(source); - } - if (behaviour instanceof DisplayTarget target) { - TARGETS_BY_TILE.register(teType, target); - } - } - - @Deprecated(forRemoval = true) - public static void assignBlock(DisplayBehaviour behaviour, IRegistryDelegate block) { - assignBlock(behaviour, block.name()); - } - - @Deprecated(forRemoval = true) - public static void assignTile(DisplayBehaviour behaviour, IRegistryDelegate> teType) { - assignTile(behaviour, teType.name()); - } - - public static NonNullConsumer assignDataBehaviour(DisplayBehaviour behaviour, - String... suffix) { - return b -> { - ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(b); - String idSuffix = behaviour instanceof DisplaySource ? "_source" : "_target"; - if (suffix.length > 0) - idSuffix += "_" + suffix[0]; - assignBlock(register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), - behaviour), registryName); - }; - } - - public static > NonNullConsumer assignDataBehaviourTE( - DisplayBehaviour behaviour, String... suffix) { - return b -> { - ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(b); - String idSuffix = behaviour instanceof DisplaySource ? "_source" : "_target"; - if (suffix.length > 0) - idSuffix += "_" + suffix[0]; - assignTile( - register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), - behaviour), - registryName); - }; - } - - // - - @Nullable - public static DisplaySource getSource(ResourceLocation resourceLocation) { - DisplayBehaviour available = GATHERER_BEHAVIOURS.getOrDefault(resourceLocation, null); - if (available instanceof DisplaySource source) - return source; - return null; - } - - @Nullable - public static DisplayTarget getTarget(ResourceLocation resourceLocation) { - DisplayBehaviour available = GATHERER_BEHAVIOURS.getOrDefault(resourceLocation, null); - if (available instanceof DisplayTarget target) - return target; - return null; - } - - // - - public static List sourcesOf(Block block) { - List sources = SOURCES_BY_BLOCK.get(block); - if (sources == null) { - return Collections.emptyList(); - } - return sources; - } - - public static List sourcesOf(BlockState state) { - return sourcesOf(state.getBlock()); - } - - public static List sourcesOf(BlockEntityType tileEntityType) { - List sources = SOURCES_BY_TILE.get(tileEntityType); - if (sources == null) { - return Collections.emptyList(); - } - return sources; - } - - public static List sourcesOf(BlockEntity tileEntity) { - return sourcesOf(tileEntity.getType()); - } - - @Nullable - public static DisplayTarget targetOf(Block block) { - return TARGETS_BY_BLOCK.get(block); - } - - @Nullable - public static DisplayTarget targetOf(BlockState state) { - return targetOf(state.getBlock()); - } - - @Nullable - public static DisplayTarget targetOf(BlockEntityType tileEntityType) { - return TARGETS_BY_TILE.get(tileEntityType); - } - - @Nullable - public static DisplayTarget targetOf(BlockEntity tileEntity) { - return targetOf(tileEntity.getType()); - } - - public static List sourcesOf(LevelAccessor level, BlockPos pos) { - BlockState blockState = level.getBlockState(pos); - BlockEntity blockEntity = level.getBlockEntity(pos); - - List sourcesOfBlock = sourcesOf(blockState); - List sourcesOfTE = blockEntity == null ? Collections.emptyList() : sourcesOf(blockEntity); - - if (sourcesOfTE.isEmpty()) - return sourcesOfBlock; - return sourcesOfTE; - } - - @Nullable - public static DisplayTarget targetOf(LevelAccessor level, BlockPos pos) { - BlockState blockState = level.getBlockState(pos); - BlockEntity blockEntity = level.getBlockEntity(pos); - - DisplayTarget targetOfBlock = targetOf(blockState); - DisplayTarget targetOfTE = blockEntity == null ? null : targetOf(blockEntity); - - if (targetOfTE == null) - return targetOfBlock; - return targetOfTE; - } - - // - - public static void registerDefaults() { - assignTile(register(Create.asResource("sign_display_target"), new SignDisplayTarget()), BlockEntityType.SIGN); - assignTile(register(Create.asResource("lectern_display_target"), new LecternDisplayTarget()), BlockEntityType.LECTERN); - assignBlock(register(Create.asResource("death_count_display_source"), new DeathCounterDisplaySource()), Blocks.RESPAWN_ANCHOR); - assignTile(register(Create.asResource("scoreboard_display_source"), new ScoreboardDisplaySource()), BlockEntityType.COMMAND_BLOCK); - assignTile(register(Create.asResource("enchant_power_display_source"), new EnchantPowerDisplaySource()), BlockEntityType.ENCHANTING_TABLE); - assignBlock(register(Create.asResource("redstone_power_display_source"), new RedstonePowerDisplaySource()), Blocks.TARGET); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayBehaviour.java deleted file mode 100644 index 712c85d6b5..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayBehaviour.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import net.minecraft.resources.ResourceLocation; - -public abstract class DisplayBehaviour { - - public ResourceLocation id; - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkConfigurationPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkConfigurationPacket.java deleted file mode 100644 index c83d6894ac..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkConfigurationPacket.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; - -public class DisplayLinkConfigurationPacket extends TileEntityConfigurationPacket { - - private CompoundTag configData; - private int targetLine; - - public DisplayLinkConfigurationPacket(BlockPos pos, CompoundTag configData, int targetLine) { - super(pos); - this.configData = configData; - this.targetLine = targetLine; - } - - public DisplayLinkConfigurationPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) { - buffer.writeNbt(configData); - buffer.writeInt(targetLine); - } - - @Override - protected void readSettings(FriendlyByteBuf buffer) { - configData = buffer.readNbt(); - targetLine = buffer.readInt(); - } - - @Override - protected void applySettings(DisplayLinkTileEntity te) { - te.targetLine = targetLine; - - if (!configData.contains("Id")) { - te.notifyUpdate(); - return; - } - - ResourceLocation id = new ResourceLocation(configData.getString("Id")); - DisplaySource source = AllDisplayBehaviours.getSource(id); - if (source == null) { - te.notifyUpdate(); - return; - } - - if (te.activeSource == null || te.activeSource != source) { - te.activeSource = source; - te.setSourceConfig(configData.copy()); - } else { - te.getSourceConfig() - .merge(configData); - } - - te.updateGatheredData(); - te.notifyUpdate(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkContext.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkContext.java deleted file mode 100644 index 49477f76b6..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkContext.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; - -public class DisplayLinkContext { - - private Level level; - private DisplayLinkTileEntity te; - - public Object flapDisplayContext; - - public DisplayLinkContext(Level level, DisplayLinkTileEntity te) { - this.level = level; - this.te = te; - } - - public Level level() { - return level; - } - - public DisplayLinkTileEntity te() { - return te; - } - - public BlockEntity getSourceTE() { - return level.getBlockEntity(getSourcePos()); - } - - public BlockPos getSourcePos() { - return te.getSourcePosition(); - } - - public BlockEntity getTargetTE() { - return level.getBlockEntity(getTargetPos()); - } - - public BlockPos getTargetPos() { - return te.getTargetPosition(); - } - - public CompoundTag sourceConfig() { - return te.getSourceConfig(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkRenderer.java deleted file mode 100644 index 31a08fa44c..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkRenderer.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.render.RenderTypes; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; - -public class DisplayLinkRenderer extends SafeTileEntityRenderer { - - public DisplayLinkRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(DisplayLinkTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - float glow = te.glow.getValue(partialTicks); - if (glow < .125f) - return; - - glow = (float) (1 - (2 * Math.pow(glow - .75f, 2))); - glow = Mth.clamp(glow, -1, 1); - - int color = (int) (200 * glow); - - BlockState blockState = te.getBlockState(); - TransformStack msr = TransformStack.cast(ms); - - Direction face = blockState.getOptionalValue(DisplayLinkBlock.FACING) - .orElse(Direction.UP); - - if (face.getAxis() - .isHorizontal()) - face = face.getOpposite(); - - ms.pushPose(); - - msr.centre() - .rotateY(AngleHelper.horizontalAngle(face)) - .rotateX(-AngleHelper.verticalAngle(face) - 90) - .unCentre(); - - CachedPartialBuffers.partial(AllBlockPartials.DISPLAY_LINK_TUBE, blockState) - .light(LightTexture.FULL_BRIGHT) - .renderInto(ms, buffer.getBuffer(RenderType.translucent())); - - SuperByteBuffer partial = CachedPartialBuffers.partial(AllBlockPartials.DISPLAY_LINK_GLOW, blockState); - partial - .light(LightTexture.FULL_BRIGHT) - .color(color, color, color, 255) - .disableDiffuse() - .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); - - ms.popPose(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java deleted file mode 100644 index 7e942312b7..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkTileEntity.java +++ /dev/null @@ -1,202 +0,0 @@ -package com.simibubi.create.content.logistics.block.display; - -import java.util.List; - -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class DisplayLinkTileEntity extends SmartTileEntity { - - protected BlockPos targetOffset; - - public DisplaySource activeSource; - private CompoundTag sourceConfig; - - public DisplayTarget activeTarget; - public int targetLine; - - public LerpedFloat glow; - private boolean sendPulse; - - public int refreshTicks; - - public DisplayLinkTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - targetOffset = BlockPos.ZERO; - sourceConfig = new CompoundTag(); - targetLine = 0; - glow = LerpedFloat.linear() - .startWithValue(0); - glow.chase(0, 0.5f, Chaser.EXP); - } - - @Override - public void tick() { - super.tick(); - - if (isVirtual()) { - glow.tickChaser(); - return; - } - - if (activeSource == null) - return; - if (level.isClientSide) { - glow.tickChaser(); - return; - } - - refreshTicks++; - if (refreshTicks < activeSource.getPassiveRefreshTicks()) - return; - tickSource(); - } - - public void tickSource() { - refreshTicks = 0; - if (getBlockState().getOptionalValue(DisplayLinkBlock.POWERED) - .orElse(true)) - return; - if (!level.isClientSide) - updateGatheredData(); - } - - public void onNoLongerPowered() { - if (activeSource == null) - return; - refreshTicks = 0; - activeSource.onSignalReset(new DisplayLinkContext(level, this)); - updateGatheredData(); - } - - public void updateGatheredData() { - BlockPos sourcePosition = getSourcePosition(); - BlockPos targetPosition = getTargetPosition(); - - if (!level.isLoaded(targetPosition) || !level.isLoaded(sourcePosition)) - return; - - DisplayTarget target = AllDisplayBehaviours.targetOf(level, targetPosition); - List sources = AllDisplayBehaviours.sourcesOf(level, sourcePosition); - boolean notify = false; - - if (activeTarget != target) { - activeTarget = target; - notify = true; - } - - if (activeSource != null && !sources.contains(activeSource)) { - activeSource = null; - sourceConfig = new CompoundTag(); - notify = true; - } - - if (notify) - notifyUpdate(); - if (activeSource == null || activeTarget == null) - return; - - DisplayLinkContext context = new DisplayLinkContext(level, this); - activeSource.transferData(context, activeTarget, targetLine); - sendPulse = true; - sendData(); - - award(AllAdvancements.DISPLAY_LINK); - } - - @Override - public void addBehaviours(List behaviours) { - registerAwardables(behaviours, AllAdvancements.DISPLAY_LINK, AllAdvancements.DISPLAY_BOARD); - } - - @Override - public void writeSafe(CompoundTag tag) { - super.writeSafe(tag); - writeGatheredData(tag); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - writeGatheredData(tag); - if (clientPacket && activeTarget != null) - tag.putString("TargetType", activeTarget.id.toString()); - if (clientPacket && sendPulse) { - sendPulse = false; - NBTHelper.putMarker(tag, "Pulse"); - } - } - - private void writeGatheredData(CompoundTag tag) { - tag.put("TargetOffset", NbtUtils.writeBlockPos(targetOffset)); - tag.putInt("TargetLine", targetLine); - - if (activeSource != null) { - CompoundTag data = sourceConfig.copy(); - data.putString("Id", activeSource.id.toString()); - tag.put("Source", data); - } - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - super.read(tag, clientPacket); - targetOffset = NbtUtils.readBlockPos(tag.getCompound("TargetOffset")); - targetLine = tag.getInt("TargetLine"); - - if (clientPacket && tag.contains("TargetType")) - activeTarget = AllDisplayBehaviours.getTarget(new ResourceLocation(tag.getString("TargetType"))); - if (clientPacket && tag.contains("Pulse")) - glow.setValue(2); - - if (!tag.contains("Source")) - return; - - CompoundTag data = tag.getCompound("Source"); - activeSource = AllDisplayBehaviours.getSource(new ResourceLocation(data.getString("Id"))); - sourceConfig = new CompoundTag(); - if (activeSource != null) - sourceConfig = data.copy(); - } - - public void target(BlockPos targetPosition) { - this.targetOffset = targetPosition.subtract(worldPosition); - } - - public BlockPos getSourcePosition() { - return worldPosition.relative(getDirection()); - } - - public CompoundTag getSourceConfig() { - return sourceConfig; - } - - public void setSourceConfig(CompoundTag sourceConfig) { - this.sourceConfig = sourceConfig; - } - - public Direction getDirection() { - return getBlockState().getOptionalValue(DisplayLinkBlock.FACING) - .orElse(Direction.UP) - .getOpposite(); - } - - public BlockPos getTargetPosition() { - return worldPosition.offset(targetOffset); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/AccumulatedItemCountDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/AccumulatedItemCountDisplaySource.java deleted file mode 100644 index e69e7eb7e2..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/AccumulatedItemCountDisplaySource.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.MutableComponent; - -public class AccumulatedItemCountDisplaySource extends NumericSingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - return Components.literal(String.valueOf(context.sourceConfig() - .getInt("Collected"))); - } - - public void itemReceived(DisplayLinkTileEntity te, int amount) { - if (te.getBlockState() - .getOptionalValue(DisplayLinkBlock.POWERED) - .orElse(true)) - return; - - int collected = te.getSourceConfig() - .getInt("Collected"); - te.getSourceConfig() - .putInt("Collected", collected + amount); - te.updateGatheredData(); - } - - @Override - protected String getTranslationKey() { - return "accumulate_items"; - } - - @Override - public int getPassiveRefreshTicks() { - return 200; - } - - @Override - public void onSignalReset(DisplayLinkContext context) { - context.sourceConfig() - .remove("Collected"); - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/EntityNameDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/EntityNameDisplaySource.java deleted file mode 100644 index 0f6375a739..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/EntityNameDisplaySource.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import java.util.List; - -import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; - -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.AABB; - -public class EntityNameDisplaySource extends SingleLineDisplaySource { - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - List seats = context.level().getEntitiesOfClass(SeatEntity.class, new AABB(context.getSourcePos())); - - if (seats.isEmpty()) - return EMPTY_LINE; - - SeatEntity seatEntity = seats.get(0); - List passengers = seatEntity.getPassengers(); - - if (passengers.isEmpty()) - return EMPTY_LINE; - - return passengers.get(0).getDisplayName().copy(); - } - - @Override - protected String getTranslationKey() { - return "entity_name"; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidAmountDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidAmountDisplaySource.java deleted file mode 100644 index cfd77cb107..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidAmountDisplaySource.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.TankManipulationBehaviour; -import com.simibubi.create.foundation.utility.FluidFormatter; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; - -public class FluidAmountDisplaySource extends SingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof ContentObserverTileEntity cote)) - return EMPTY_LINE; - - TankManipulationBehaviour tankManipulationBehaviour = cote.getBehaviour(TankManipulationBehaviour.OBSERVE); - FilteringBehaviour filteringBehaviour = cote.getBehaviour(FilteringBehaviour.TYPE); - IFluidHandler handler = tankManipulationBehaviour.getInventory(); - - if (handler == null) - return EMPTY_LINE; - - long collected = 0; - for (int i = 0; i < handler.getTanks(); i++) { - FluidStack stack = handler.getFluidInTank(i); - if (stack.isEmpty()) - continue; - if (!filteringBehaviour.test(stack)) - continue; - collected += stack.getAmount(); - } - - return Components.literal(FluidFormatter.asString(collected, false)); - } - - @Override - protected String getTranslationKey() { - return "fluid_amount"; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemCountDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemCountDisplaySource.java deleted file mode 100644 index 022bb582dc..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemCountDisplaySource.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.items.IItemHandler; - -public class ItemCountDisplaySource extends NumericSingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof ContentObserverTileEntity cote)) - return ZERO.copy(); - - InvManipulationBehaviour invManipulationBehaviour = cote.getBehaviour(InvManipulationBehaviour.TYPE); - FilteringBehaviour filteringBehaviour = cote.getBehaviour(FilteringBehaviour.TYPE); - IItemHandler handler = invManipulationBehaviour.getInventory(); - - if (handler == null) - return ZERO.copy(); - - int collected = 0; - for (int i = 0; i < handler.getSlots(); i++) { - ItemStack stack = handler.extractItem(i, handler.getSlotLimit(i), true); - if (stack.isEmpty()) - continue; - if (!filteringBehaviour.test(stack)) - continue; - collected += stack.getCount(); - } - - return Components.literal(String.valueOf(collected)); - } - - @Override - protected String getTranslationKey() { - return "count_items"; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemListDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemListDisplaySource.java deleted file mode 100644 index 2fe4620862..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemListDisplaySource.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import java.util.stream.Stream; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.foundation.item.CountedItemStackList; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.IntAttached; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.items.IItemHandler; - -public class ItemListDisplaySource extends ValueListDisplaySource { - - @Override - protected Stream> provideEntries(DisplayLinkContext context, int maxRows) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof ContentObserverTileEntity cote)) - return Stream.empty(); - - InvManipulationBehaviour invManipulationBehaviour = cote.getBehaviour(InvManipulationBehaviour.TYPE); - FilteringBehaviour filteringBehaviour = cote.getBehaviour(FilteringBehaviour.TYPE); - IItemHandler handler = invManipulationBehaviour.getInventory(); - - if (handler == null) - return Stream.empty(); - - return new CountedItemStackList(handler, filteringBehaviour).getTopNames(maxRows); - } - - @Override - protected String getTranslationKey() { - return "list_items"; - } - - @Override - protected boolean valueFirst() { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemNameDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemNameDisplaySource.java deleted file mode 100644 index 922b0a2062..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemNameDisplaySource.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import org.apache.commons.lang3.mutable.MutableObject; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; - -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.item.ItemStack; - -public class ItemNameDisplaySource extends SingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - DisplayLinkTileEntity gatherer = context.te(); - Direction direction = gatherer.getDirection(); - MutableBlockPos pos = gatherer.getSourcePosition() - .mutable(); - - MutableComponent combined = EMPTY_LINE.copy(); - - for (int i = 0; i < 32; i++) { - TransportedItemStackHandlerBehaviour behaviour = - TileEntityBehaviour.get(context.level(), pos, TransportedItemStackHandlerBehaviour.TYPE); - pos.move(direction); - - if (behaviour == null) - break; - - MutableObject stackHolder = new MutableObject<>(); - behaviour.handleCenteredProcessingOnAllItems(.25f, tis -> { - stackHolder.setValue(tis.stack); - return TransportedResult.doNothing(); - }); - - ItemStack stack = stackHolder.getValue(); - if (stack != null && !stack.isEmpty()) - combined = combined.append(stack.getHoverName()); - } - - return combined; - } - - @Override - protected String getTranslationKey() { - return "combine_item_names"; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } - - @Override - protected String getFlapDisplayLayoutName(DisplayLinkContext context) { - return "Number"; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticSpeedDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticSpeedDisplaySource.java deleted file mode 100644 index 44dfe19094..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticSpeedDisplaySource.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.network.chat.MutableComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class KineticSpeedDisplaySource extends NumericSingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - if (!(context.getSourceTE() instanceof SpeedGaugeTileEntity gaugeTile)) - return ZERO.copy(); - - boolean absoluteValue = context.sourceConfig() - .getInt("Directional") == 0; - float speed = absoluteValue ? Math.abs(gaugeTile.getSpeed()) : gaugeTile.getSpeed(); - return CreateLang.number(speed) - .space() - .translate("generic.unit.rpm") - .component(); - } - - @Override - protected String getTranslationKey() { - return "kinetic_speed"; - } - - @Override - @OnlyIn(Dist.CLIENT) - public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, - boolean isFirstLine) { - super.initConfigurationWidgets(context, builder, isFirstLine); - if (isFirstLine) - return; - - builder.addSelectionScrollInput(0, 95, (selectionScrollInput, label) -> { - selectionScrollInput - .forOptions(CreateLang.translatedOptions("display_source.kinetic_speed", "absolute", "directional")); - }, "Directional"); - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/NixieTubeDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/NixieTubeDisplaySource.java deleted file mode 100644 index d2e0fa28c7..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/NixieTubeDisplaySource.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.block.display.target.NixieTubeDisplayTarget; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; - -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.block.entity.BlockEntity; - -public class NixieTubeDisplaySource extends SingleLineDisplaySource { - - @Override - protected String getTranslationKey() { - return "nixie_tube"; - } - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof NixieTubeTileEntity nte)) - return EMPTY_LINE; - - MutableComponent text = nte.getFullText(); - - try { - String line = text.getString(); - Integer.valueOf(line); - context.flapDisplayContext = Boolean.TRUE; - } catch (NumberFormatException e) { - } - - return text; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return !(context.te().activeTarget instanceof NixieTubeDisplayTarget); - } - - @Override - protected String getFlapDisplayLayoutName(DisplayLinkContext context) { - if (isNumeric(context)) - return "Number"; - return super.getFlapDisplayLayoutName(context); - } - - @Override - protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { - if (isNumeric(context)) - return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "numeric", false, false); - return super.createSectionForValue(context, size); - } - - protected boolean isNumeric(DisplayLinkContext context) { - return context.flapDisplayContext == Boolean.TRUE; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/NumericSingleLineDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/NumericSingleLineDisplaySource.java deleted file mode 100644 index ec6591aacf..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/NumericSingleLineDisplaySource.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.Component; - -public abstract class NumericSingleLineDisplaySource extends SingleLineDisplaySource { - - protected static final Component ZERO = Components.literal("0"); - - @Override - protected String getFlapDisplayLayoutName(DisplayLinkContext context) { - return "Number"; - } - - @Override - protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { - return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "numeric", false, false); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ObservedTrainNameSource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/ObservedTrainNameSource.java deleted file mode 100644 index e58916197a..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ObservedTrainNameSource.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import java.util.UUID; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserver; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserverTileEntity; - -import net.minecraft.network.chat.MutableComponent; - -public class ObservedTrainNameSource extends SingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - if (!(context.getSourceTE() instanceof TrackObserverTileEntity observerTE)) - return EMPTY_LINE; - TrackObserver observer = observerTE.getObserver(); - if (observer == null) - return EMPTY_LINE; - UUID currentTrain = observer.getCurrentTrain(); - if (currentTrain == null) - return EMPTY_LINE; - Train train = Create.RAILWAYS.trains.get(currentTrain); - if (train == null) - return EMPTY_LINE; - return train.name.copy(); - } - - @Override - public int getPassiveRefreshTicks() { - return 400; - } - - @Override - protected String getTranslationKey() { - return "observed_train_name"; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StopWatchDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/StopWatchDisplaySource.java deleted file mode 100644 index 569207a96b..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StopWatchDisplaySource.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.MutableComponent; - -public class StopWatchDisplaySource extends SingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - if (!(context.getSourceTE()instanceof CuckooClockTileEntity ccte)) - return TimeOfDayDisplaySource.EMPTY_TIME; - if (ccte.getSpeed() == 0) - return TimeOfDayDisplaySource.EMPTY_TIME; - - if (!context.sourceConfig() - .contains("StartTime")) - onSignalReset(context); - - long started = context.sourceConfig() - .getLong("StartTime"); - long current = context.te() - .getLevel() - .getGameTime(); - - int diff = (int) (current - started); - int hours = (diff / 60 / 60 / 20); - int minutes = (diff / 60 / 20) % 60; - int seconds = (diff / 20) % 60; - - MutableComponent component = Components.literal((hours == 0 ? "" : (hours < 10 ? " " : "") + hours + ":") - + (minutes < 10 ? hours == 0 ? " " : "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds); - - return component; - } - - @Override - public void onSignalReset(DisplayLinkContext context) { - context.sourceConfig() - .putLong("StartTime", context.te() - .getLevel() - .getGameTime()); - } - - @Override - public int getPassiveRefreshTicks() { - return 20; - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return true; - } - - @Override - protected String getFlapDisplayLayoutName(DisplayLinkContext context) { - return "Instant"; - } - - @Override - protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { - return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "instant", false, false); - } - - @Override - protected String getTranslationKey() { - return "stop_watch"; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/TrainStatusDisplaySource.java b/src/main/java/com/simibubi/create/content/logistics/block/display/source/TrainStatusDisplaySource.java deleted file mode 100644 index cda2d9e849..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/TrainStatusDisplaySource.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.source; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; -import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime.State; - -import net.minecraft.network.chat.MutableComponent; - -public class TrainStatusDisplaySource extends SingleLineDisplaySource { - - @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - if (!(context.getSourceTE() instanceof StationTileEntity observerTE)) - return EMPTY_LINE; - GlobalStation observer = observerTE.getStation(); - if (observer == null) - return EMPTY_LINE; - Train currentTrain = observer.getPresentTrain(); - if (currentTrain == null) - return EMPTY_LINE; - - ScheduleRuntime runtime = currentTrain.runtime; - Schedule schedule = runtime.getSchedule(); - if (schedule == null) - return EMPTY_LINE; - if (runtime.paused) - return EMPTY_LINE; - if (runtime.state != State.POST_TRANSIT) - return EMPTY_LINE; - if (runtime.currentEntry == schedule.entries.size() - 1 && !schedule.cyclic) - return EMPTY_LINE; - - return runtime.getWaitingStatus(context.level()); - } - - @Override - protected boolean allowsLabeling(DisplayLinkContext context) { - return false; - } - - @Override - protected String getTranslationKey() { - return "train_status"; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayBoardTarget.java b/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayBoardTarget.java deleted file mode 100644 index b12501abe8..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayBoardTarget.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.target; - -import java.util.List; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.content.logistics.block.display.source.SingleLineDisplaySource; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class DisplayBoardTarget extends DisplayTarget { - - @Override - public void acceptText(int line, List text, DisplayLinkContext context) {} - - public void acceptFlapText(int line, List> text, DisplayLinkContext context) { - FlapDisplayTileEntity controller = getController(context); - if (controller == null) - return; - if (!controller.isSpeedRequirementFulfilled()) - return; - - DisplaySource source = context.te().activeSource; - List lines = controller.getLines(); - for (int i = 0; i + line < lines.size(); i++) { - - if (i == 0) - reserve(i + line, controller, context); - if (i > 0 && isReserved(i + line, controller, context)) - break; - - FlapDisplayLayout layout = lines.get(i + line); - - if (i >= text.size()) { - if (source instanceof SingleLineDisplaySource) - break; - controller.applyTextManually(i + line, null); - continue; - } - - source.loadFlapDisplayLayout(context, controller, layout, i); - - for (int sectionIndex = 0; sectionIndex < layout.getSections() - .size(); sectionIndex++) { - List textLine = text.get(i); - if (textLine.size() <= sectionIndex) - break; - layout.getSections() - .get(sectionIndex) - .setText(textLine.get(sectionIndex)); - } - } - - controller.sendData(); - } - - @Override - public boolean isReserved(int line, BlockEntity target, DisplayLinkContext context) { - return super.isReserved(line, target, context) - || target instanceof FlapDisplayTileEntity fdte && fdte.manualLines.length > line && fdte.manualLines[line]; - } - - @Override - public DisplayTargetStats provideStats(DisplayLinkContext context) { - FlapDisplayTileEntity controller = getController(context); - if (controller == null) - return new DisplayTargetStats(1, 1, this); - return new DisplayTargetStats(controller.ySize * 2, controller.getMaxCharCount(), this); - } - - private FlapDisplayTileEntity getController(DisplayLinkContext context) { - BlockEntity teIn = context.getTargetTE(); - if (!(teIn instanceof FlapDisplayTileEntity te)) - return null; - return te.getController(); - } - - @Override - @OnlyIn(Dist.CLIENT) - public AABB getMultiblockBounds(LevelAccessor level, BlockPos pos) { - AABB baseShape = super.getMultiblockBounds(level, pos); - BlockEntity te = level.getBlockEntity(pos); - - if (!(te instanceof FlapDisplayTileEntity fdte)) - return baseShape; - - FlapDisplayTileEntity controller = fdte.getController(); - if (controller == null) - return baseShape; - - Vec3i normal = controller.getDirection() - .getClockWise() - .getNormal(); - return baseShape.move(controller.getBlockPos() - .subtract(pos)) - .expandTowards(normal.getX() * (controller.xSize - 1), 1 - controller.ySize, - normal.getZ() * (controller.xSize - 1)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTargetStats.java b/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTargetStats.java deleted file mode 100644 index 4381fc0218..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTargetStats.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.simibubi.create.content.logistics.block.display.target; - -public record DisplayTargetStats(int maxRows, int maxColumns, DisplayTarget type) { - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/flap/package-info.java b/src/main/java/com/simibubi/create/content/logistics/block/flap/package-info.java deleted file mode 100644 index 2ec0735b81..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/flap/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.simibubi.create.content.logistics.block.flap; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java deleted file mode 100644 index 4726ef2b76..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractFunnelBlock.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import java.util.Random; -import java.util.function.Consumer; - -import javax.annotation.Nullable; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.IBlockRenderProperties; - -public abstract class AbstractFunnelBlock extends Block implements ITE, IWrenchable { - - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - - protected AbstractFunnelBlock(Properties p_i48377_1_) { - super(p_i48377_1_); - registerDefaultState(defaultBlockState().setValue(POWERED, false)); - } - - @OnlyIn(Dist.CLIENT) - public void initializeClient(Consumer consumer) { - consumer.accept(new ReducedDestroyEffects()); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - return defaultBlockState().setValue(POWERED, context.getLevel() - .hasNeighborSignal(context.getClickedPos())); - } - - @Override - public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { - return false; - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - super.createBlockStateDefinition(builder.add(POWERED)); - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - if (worldIn.isClientSide) - return; - InvManipulationBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); - if (behaviour != null) - behaviour.onNeighborChanged(fromPos); - if (!worldIn.getBlockTicks() - .willTickThisTick(pos, this)) - worldIn.scheduleTick(pos, this, 0); - } - - @Override - public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random r) { - boolean previouslyPowered = state.getValue(POWERED); - if (previouslyPowered != worldIn.hasNeighborSignal(pos)) - worldIn.setBlock(pos, state.cycle(POWERED), 2); - } - - public static ItemStack tryInsert(Level worldIn, BlockPos pos, ItemStack toInsert, boolean simulate) { - FilteringBehaviour filter = TileEntityBehaviour.get(worldIn, pos, FilteringBehaviour.TYPE); - InvManipulationBehaviour inserter = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); - if (inserter == null) - return toInsert; - if (filter != null && !filter.test(toInsert)) - return toInsert; - if (simulate) - inserter.simulate(); - ItemStack insert = inserter.insert(toInsert); - - if (!simulate && insert.getCount() != toInsert.getCount()) { - BlockEntity tileEntity = worldIn.getBlockEntity(pos); - if (tileEntity instanceof FunnelTileEntity) { - FunnelTileEntity funnelTileEntity = (FunnelTileEntity) tileEntity; - funnelTileEntity.onTransfer(toInsert); - if (funnelTileEntity.hasFlap()) - funnelTileEntity.flap(true); - } - } - return insert; - } - - @Override - public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { - Block block = world.getBlockState(pos.relative(getFunnelFacing(state).getOpposite())) - .getBlock(); - return !(block instanceof AbstractFunnelBlock); - } - - @Nullable - public static boolean isFunnel(BlockState state) { - return state.getBlock() instanceof AbstractFunnelBlock; - } - - @Nullable - public static Direction getFunnelFacing(BlockState state) { - if (!(state.getBlock() instanceof AbstractFunnelBlock)) - return null; - return ((AbstractFunnelBlock) state.getBlock()).getFacing(state); - } - - protected abstract Direction getFacing(BlockState state); - - @Override - public void onRemove(BlockState p_196243_1_, Level p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_, - boolean p_196243_5_) { - if (p_196243_1_.hasBlockEntity() && (p_196243_1_.getBlock() != p_196243_4_.getBlock() && !isFunnel(p_196243_4_) - || !p_196243_4_.hasBlockEntity())) { - TileEntityBehaviour.destroy(p_196243_2_, p_196243_3_, FilteringBehaviour.TYPE); - p_196243_2_.removeBlockEntity(p_196243_3_); - } - } - - @Override - public Class getTileEntityClass() { - return FunnelTileEntity.class; - } - - public BlockEntityType getTileEntityType() { - return AllTileEntities.FUNNEL.get(); - }; - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelGenerator.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelGenerator.java deleted file mode 100644 index 8e0ccaaea3..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelGenerator.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import com.simibubi.create.foundation.data.SpecialBlockStateGen; -import com.tterrag.registrate.providers.DataGenContext; -import com.tterrag.registrate.providers.RegistrateBlockstateProvider; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraftforge.client.model.generators.ModelFile; - -public class BeltFunnelGenerator extends SpecialBlockStateGen { - - private String type; - private ResourceLocation materialBlockTexture; - - public BeltFunnelGenerator(String type, ResourceLocation materialBlockTexture) { - this.type = type; - this.materialBlockTexture = materialBlockTexture; - } - - @Override - protected int getXRotation(BlockState state) { - return 0; - } - - @Override - protected int getYRotation(BlockState state) { - return horizontalAngle(state.getValue(BeltFunnelBlock.HORIZONTAL_FACING)) + 180; - } - - @Override - public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, - BlockState state) { - String shapeName = state.getValue(BeltFunnelBlock.SHAPE) - .getSerializedName(); - boolean powered = state.getOptionalValue(BlockStateProperties.POWERED).orElse(false); - String poweredSuffix = powered ? "_powered" : ""; - String name = ctx.getName() + "_" + shapeName + poweredSuffix; - - return prov.models() - .withExistingParent(name, prov.modLoc("block/belt_funnel/block_" + shapeName)) - .texture("particle", materialBlockTexture) - .texture("2", prov.modLoc("block/" + type + "_funnel_neutral")) - .texture("2_1", prov.modLoc("block/" + type + "_funnel_push")) - .texture("2_2", prov.modLoc("block/" + type + "_funnel_pull")) - .texture("3", prov.modLoc("block/" + type + "_funnel_back")) - .texture("5", prov.modLoc("block/" + type + "_funnel_tall" + poweredSuffix)) - .texture("6", prov.modLoc("block/" + type + "_funnel" + poweredSuffix)) - .texture("7", prov.modLoc("block/" + type + "_funnel_plating")); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java deleted file mode 100644 index 1d5f390ce9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelGenerator.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import com.simibubi.create.Create; -import com.simibubi.create.foundation.data.SpecialBlockStateGen; -import com.tterrag.registrate.providers.DataGenContext; -import com.tterrag.registrate.providers.RegistrateBlockstateProvider; -import com.tterrag.registrate.providers.RegistrateItemModelProvider; -import com.tterrag.registrate.util.nullness.NonNullBiConsumer; - -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.generators.BlockModelBuilder; -import net.minecraftforge.client.model.generators.ModelFile; - -public class FunnelGenerator extends SpecialBlockStateGen { - - private String type; - private ResourceLocation particleTexture; - private boolean hasFilter; - - public FunnelGenerator(String type, boolean hasFilter) { - this.type = type; - this.hasFilter = hasFilter; - this.particleTexture = Create.asResource("block/" + type + "_casing"); - } - - @Override - protected int getXRotation(BlockState state) { - return state.getValue(FunnelBlock.FACING) == Direction.DOWN ? 180 : 0; - } - - @Override - protected int getYRotation(BlockState state) { - return horizontalAngle(state.getValue(FunnelBlock.FACING)) + 180; - } - - @Override - public ModelFile getModel(DataGenContext c, RegistrateBlockstateProvider p, - BlockState s) { - String powered = s.getValue(FunnelBlock.POWERED) ? "_powered" : ""; - String closed = s.getValue(FunnelBlock.POWERED) ? "_closed" : "_open"; - String extracting = s.getValue(FunnelBlock.EXTRACTING) ? "_push" : "_pull"; - Direction facing = s.getValue(FunnelBlock.FACING); - boolean horizontal = facing.getAxis() - .isHorizontal(); - String parent = horizontal ? "horizontal" : hasFilter ? "vertical" : "vertical_filterless"; - - BlockModelBuilder model = p.models() - .withExistingParent("block/" + type + "_funnel_" + parent + extracting + powered, - p.modLoc("block/funnel/block_" + parent)) - .texture("particle", particleTexture) - .texture("7", p.modLoc("block/" + type + "_funnel_plating")) - .texture("5", p.modLoc("block/" + type + "_funnel_tall" + powered)) - .texture("2_2", p.modLoc("block/" + type + "_funnel" + extracting)) - .texture("3", p.modLoc("block/" + type + "_funnel_back")); - - if (horizontal) - return model.texture("6", p.modLoc("block/" + type + "_funnel" + powered)); - - return model.texture("8", particleTexture) - .texture("9", p.modLoc("block/" + type + "_funnel_slope")) - .texture("10", p.modLoc("block/funnel" + closed)); - } - - public static NonNullBiConsumer, RegistrateItemModelProvider> itemModel( - String type) { - ResourceLocation particleTexture = Create.asResource("block/" + type + "_casing"); - return (c, p) -> { - p.withExistingParent("item/" + type + "_funnel", p.modLoc("block/funnel/item")) - .texture("particle", particleTexture) - .texture("7", p.modLoc("block/" + type + "_funnel_plating")) - .texture("2", p.modLoc("block/" + type + "_funnel_neutral")) - .texture("6", p.modLoc("block/" + type + "_funnel")) - .texture("5", p.modLoc("block/" + type + "_funnel_tall")) - .texture("3", p.modLoc("block/" + type + "_funnel_back")); - }; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java deleted file mode 100644 index 3b3b29a722..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelInstance.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import java.util.ArrayList; - -import com.jozufozu.flywheel.api.InstanceData; -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.jozufozu.flywheel.core.PartialModel; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.block.flap.FlapData; -import com.simibubi.create.foundation.render.AllMaterialSpecs; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.minecraft.core.Direction; -import net.minecraft.world.level.LightLayer; - -public class FunnelInstance extends BlockEntityInstance implements DynamicInstance { - - private final ArrayList flaps; - - public FunnelInstance(MaterialManager modelManager, FunnelTileEntity tile) { - super(modelManager, tile); - - flaps = new ArrayList<>(4); - - if (!tile.hasFlap()) return; - - PartialModel flapPartial = (blockState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP - : AllBlockPartials.BELT_FUNNEL_FLAP); - Instancer model = modelManager.defaultSolid() - .material(AllMaterialSpecs.FLAPS) - .getModel(flapPartial, blockState); - - int blockLight = world.getBrightness(LightLayer.BLOCK, pos); - int skyLight = world.getBrightness(LightLayer.SKY, pos); - - Direction direction = FunnelBlock.getFunnelFacing(blockState); - - float flapness = tile.flap.getValue(AnimationTickHolder.getPartialTicks()); - float horizontalAngle = direction.getOpposite().toYRot(); - - for (int segment = 0; segment <= 3; segment++) { - float intensity = segment == 3 ? 1.5f : segment + 1; - float segmentOffset = -3 / 16f * segment; - - FlapData key = model.createInstance(); - - key.setPosition(getInstancePosition()) - .setSegmentOffset(segmentOffset, 0, -tile.getFlapOffset()) - .setBlockLight(blockLight) - .setSkyLight(skyLight) - .setHorizontalAngle(horizontalAngle) - .setFlapness(flapness) - .setFlapScale(-1) - .setPivotVoxelSpace(0, 10, 9.5f) - .setIntensity(intensity); - - flaps.add(key); - } - } - - @Override - public void beginFrame() { - if (flaps == null) return; - - float flapness = blockEntity.flap.getValue(AnimationTickHolder.getPartialTicks()); - - for (FlapData flap : flaps) { - flap.setFlapness(flapness); - } - } - - @Override - public void updateLight() { - if (flaps != null) - relight(pos, flaps.stream()); - } - - @Override - public void remove() { - if (flaps == null) return; - - flaps.forEach(InstanceData::delete); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java deleted file mode 100644 index 71b76a77a0..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelRenderer.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class FunnelRenderer extends SmartTileEntityRenderer { - - public FunnelRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(FunnelTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - - if (!te.hasFlap() || Backend.canUseInstancing(te.getLevel())) - return; - - BlockState blockState = te.getBlockState(); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - PartialModel partialModel = (blockState.getBlock() instanceof FunnelBlock ? AllBlockPartials.FUNNEL_FLAP - : AllBlockPartials.BELT_FUNNEL_FLAP); - SuperByteBuffer flapBuffer = CachedPartialBuffers.partial(partialModel, blockState); - Vec3 pivot = VecHelper.voxelSpace(0, 10, 9.5f); - TransformStack msr = TransformStack.cast(ms); - - float horizontalAngle = AngleHelper.horizontalAngle(FunnelBlock.getFunnelFacing(blockState) - .getOpposite()); - float f = te.flap.getValue(partialTicks); - - ms.pushPose(); - msr.centre() - .rotateY(horizontalAngle) - .unCentre(); - ms.translate(0, 0, -te.getFlapOffset()); - - for (int segment = 0; segment <= 3; segment++) { - ms.pushPose(); - - float intensity = segment == 3 ? 1.5f : segment + 1; - float abs = Math.abs(f); - float flapAngle = Mth.sin((float) ((1 - abs) * Math.PI * intensity)) * 30 * -f; - if (f > 0) - flapAngle *= .5f; - - msr.translate(pivot) - .rotateX(flapAngle) - .translateBack(pivot); - - flapBuffer.light(light) - .renderInto(ms, vb); - - ms.popPose(); - ms.translate(-3 / 16f, 0, 0); - } - ms.popPose(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java deleted file mode 100644 index 350b0e1ff0..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java +++ /dev/null @@ -1,346 +0,0 @@ -package com.simibubi.create.content.logistics.block.funnel; - -import java.lang.ref.WeakReference; -import java.util.List; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; -import com.simibubi.create.content.logistics.packet.FunnelFlapPacket; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.BlockFace; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - -public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringInformation { - - private FilteringBehaviour filtering; - private InvManipulationBehaviour invManipulation; - private int extractionCooldown; - - private WeakReference lastObserved; // In-world Extractors only - - LerpedFloat flap; - - static enum Mode { - INVALID, PAUSED, COLLECT, PUSHING_TO_BELT, TAKING_FROM_BELT, EXTRACT - } - - public FunnelTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - extractionCooldown = 0; - flap = createChasingFlap(); - } - - public Mode determineCurrentMode() { - BlockState state = getBlockState(); - if (!FunnelBlock.isFunnel(state)) - return Mode.INVALID; - if (state.getOptionalValue(BlockStateProperties.POWERED) - .orElse(false)) - return Mode.PAUSED; - if (state.getBlock() instanceof BeltFunnelBlock) { - Shape shape = state.getValue(BeltFunnelBlock.SHAPE); - if (shape == Shape.PULLING) - return Mode.TAKING_FROM_BELT; - if (shape == Shape.PUSHING) - return Mode.PUSHING_TO_BELT; - - BeltTileEntity belt = BeltHelper.getSegmentTE(level, worldPosition.below()); - if (belt != null) - return belt.getMovementFacing() == state.getValue(BeltFunnelBlock.HORIZONTAL_FACING) ? Mode.PUSHING_TO_BELT - : Mode.TAKING_FROM_BELT; - return Mode.INVALID; - } - if (state.getBlock() instanceof FunnelBlock) - return state.getValue(FunnelBlock.EXTRACTING) ? Mode.EXTRACT : Mode.COLLECT; - - return Mode.INVALID; - } - - @Override - public void tick() { - super.tick(); - flap.tickChaser(); - Mode mode = determineCurrentMode(); - if (level.isClientSide) - return; - - // Redstone resets the extraction cooldown - if (mode == Mode.PAUSED) - extractionCooldown = 0; - if (mode == Mode.TAKING_FROM_BELT) - return; - - if (extractionCooldown > 0) { - extractionCooldown--; - return; - } - - if (mode == Mode.PUSHING_TO_BELT) - activateExtractingBeltFunnel(); - if (mode == Mode.EXTRACT) - activateExtractor(); - } - - private void activateExtractor() { - BlockState blockState = getBlockState(); - Direction facing = AbstractFunnelBlock.getFunnelFacing(blockState); - - if (facing == null) - return; - - boolean trackingEntityPresent = true; - AABB area = getEntityOverflowScanningArea(); - - // Check if last item is still blocking the extractor - if (lastObserved == null) { - trackingEntityPresent = false; - } else { - ItemEntity lastEntity = lastObserved.get(); - if (lastEntity == null || !lastEntity.isAlive() || !lastEntity.getBoundingBox() - .intersects(area)) { - trackingEntityPresent = false; - lastObserved = null; - } - } - - if (trackingEntityPresent) - return; - - // Find other entities blocking the extract (only if necessary) - int amountToExtract = getAmountToExtract(); - ItemStack stack = invManipulation.simulate() - .extract(amountToExtract); - if (stack.isEmpty()) - return; - for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) { - lastObserved = new WeakReference<>(itemEntity); - return; - } - - // Extract - stack = invManipulation.extract(amountToExtract); - if (stack.isEmpty()) - return; - - flap(false); - onTransfer(stack); - - Vec3 outputPos = VecHelper.getCenterOf(worldPosition); - boolean vertical = facing.getAxis() - .isVertical(); - boolean up = facing == Direction.UP; - - outputPos = outputPos.add(Vec3.atLowerCornerOf(facing.getNormal()) - .scale(vertical ? up ? .15f : .5f : .25f)); - if (!vertical) - outputPos = outputPos.subtract(0, .45f, 0); - - Vec3 motion = Vec3.ZERO; - if (up) - motion = new Vec3(0, 4 / 16f, 0); - - ItemEntity item = new ItemEntity(level, outputPos.x, outputPos.y, outputPos.z, stack.copy()); - item.setDefaultPickUpDelay(); - item.setDeltaMovement(motion); - level.addFreshEntity(item); - lastObserved = new WeakReference<>(item); - - startCooldown(); - } - - static final AABB coreBB = - new AABB(VecHelper.CENTER_OF_ORIGIN, VecHelper.CENTER_OF_ORIGIN).inflate(.75f); - - private AABB getEntityOverflowScanningArea() { - Direction facing = AbstractFunnelBlock.getFunnelFacing(getBlockState()); - AABB bb = coreBB.move(worldPosition); - if (facing == null || facing == Direction.UP) - return bb; - return bb.expandTowards(0, -1, 0); - } - - private void activateExtractingBeltFunnel() { - BlockState blockState = getBlockState(); - Direction facing = blockState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); - DirectBeltInputBehaviour inputBehaviour = - TileEntityBehaviour.get(level, worldPosition.below(), DirectBeltInputBehaviour.TYPE); - - if (inputBehaviour == null) - return; - if (!inputBehaviour.canInsertFromSide(facing)) - return; - - int amountToExtract = getAmountToExtract(); - ItemStack stack = invManipulation.extract(amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true) - .isEmpty()); - if (stack.isEmpty()) - return; - flap(false); - onTransfer(stack); - inputBehaviour.handleInsertion(stack, facing, false); - startCooldown(); - } - - public int getAmountToExtract() { - if (!supportsAmountOnFilter()) - return -1; - int amountToExtract = invManipulation.getAmountFromFilter(); - if (!filtering.isActive()) - amountToExtract = 1; - return amountToExtract; - } - - private int startCooldown() { - return extractionCooldown = AllConfigs.SERVER.logistics.defaultExtractionTimer.get(); - } - - @Override - public void addBehaviours(List behaviours) { - invManipulation = - new InvManipulationBehaviour(this, (w, p, s) -> new BlockFace(p, AbstractFunnelBlock.getFunnelFacing(s) - .getOpposite())); - behaviours.add(invManipulation); - - filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()); - filtering.showCountWhen(this::supportsAmountOnFilter); - filtering.onlyActiveWhen(this::supportsFiltering); - behaviours.add(filtering); - - behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput) - .setInsertionHandler(this::handleDirectBeltInput)); - registerAwardables(behaviours, AllAdvancements.FUNNEL); - } - - private boolean supportsAmountOnFilter() { - BlockState blockState = getBlockState(); - boolean beltFunnelsupportsAmount = false; - if (blockState.getBlock() instanceof BeltFunnelBlock) { - Shape shape = blockState.getValue(BeltFunnelBlock.SHAPE); - if (shape == Shape.PUSHING) - beltFunnelsupportsAmount = true; - else - beltFunnelsupportsAmount = BeltHelper.getSegmentTE(level, worldPosition.below()) != null; - } - boolean extractor = blockState.getBlock() instanceof FunnelBlock && blockState.getValue(FunnelBlock.EXTRACTING); - return beltFunnelsupportsAmount || extractor; - } - - private boolean supportsDirectBeltInput(Direction side) { - BlockState blockState = getBlockState(); - if (blockState == null) - return false; - if (!(blockState.getBlock() instanceof FunnelBlock)) - return false; - if (blockState.getValue(FunnelBlock.EXTRACTING)) - return false; - return FunnelBlock.getFunnelFacing(blockState) == Direction.UP; - } - - private boolean supportsFiltering() { - BlockState blockState = getBlockState(); - return AllBlocks.BRASS_BELT_FUNNEL.has(blockState) || AllBlocks.BRASS_FUNNEL.has(blockState); - } - - private ItemStack handleDirectBeltInput(TransportedItemStack stack, Direction side, boolean simulate) { - ItemStack inserted = stack.stack; - if (!filtering.test(inserted)) - return inserted; - if (determineCurrentMode() == Mode.PAUSED) - return inserted; - if (simulate) - invManipulation.simulate(); - if (!simulate) - onTransfer(inserted); - return invManipulation.insert(inserted); - } - - public void flap(boolean inward) { - if (!level.isClientSide) { - AllPackets.channel.send(packetTarget(), new FunnelFlapPacket(this, inward)); - } else { - flap.setValue(inward ? 1 : -1); - AllSoundEvents.FUNNEL_FLAP.playAt(level, worldPosition, 1, 1, true); - } - } - - public boolean hasFlap() { - BlockState blockState = getBlockState(); - if (!AbstractFunnelBlock.getFunnelFacing(blockState) - .getAxis() - .isHorizontal()) - return false; - return true; - } - - public float getFlapOffset() { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof BeltFunnelBlock)) - return -1 / 16f; - switch (blockState.getValue(BeltFunnelBlock.SHAPE)) { - default: - case RETRACTED: - return 0; - case EXTENDED: - return 8 / 16f; - case PULLING: - case PUSHING: - return -2 / 16f; - } - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.putInt("TransferCooldown", extractionCooldown); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - extractionCooldown = compound.getInt("TransferCooldown"); - - if (clientPacket) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - } - - public void onTransfer(ItemStack stack) { - AllBlocks.CONTENT_OBSERVER.get() - .onFunnelTransfer(level, worldPosition, stack); - award(AllAdvancements.FUNNEL); - } - - private LerpedFloat createChasingFlap() { - return LerpedFloat.linear() - .startWithValue(.25f) - .chase(0, .05f, Chaser.EXP); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateTileEntity.java deleted file mode 100644 index 44ce5ca606..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateTileEntity.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.simibubi.create.content.logistics.block.inventories; - -import java.util.List; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class CrateTileEntity extends SmartTileEntity { - - public CrateTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) {} - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateBlock.java deleted file mode 100644 index df3ca8171e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateBlock.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.simibubi.create.content.logistics.block.inventories; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.world.level.block.entity.BlockEntityType; - -public class CreativeCrateBlock extends CrateBlock implements ITE { - - public CreativeCrateBlock(Properties p_i48415_1_) { - super(p_i48415_1_); - } - - @Override - public Class getTileEntityClass() { - return CreativeCrateTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CREATIVE_CRATE.get(); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateTileEntity.java deleted file mode 100644 index 57445bdf46..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CreativeCrateTileEntity.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.simibubi.create.content.logistics.block.inventories; - -import java.util.List; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class CreativeCrateTileEntity extends CrateTileEntity { - - public CreativeCrateTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inv = new BottomlessItemHandler(filtering::getFilter); - itemHandler = LazyOptional.of(() -> inv); - } - - FilteringBehaviour filtering; - LazyOptional itemHandler; - private BottomlessItemHandler inv; - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(filtering = createFilter()); - } - - @Override - public void setRemoved() { - super.setRemoved(); - if (itemHandler != null) - itemHandler.invalidate(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) - return itemHandler.cast(); - return super.getCapability(cap, side); - } - - public FilteringBehaviour createFilter() { - return new FilteringBehaviour(this, new ValueBoxTransform() { - - @Override - protected void rotate(BlockState state, PoseStack ms) { - TransformStack.cast(ms) - .rotateX(90); - } - - @Override - protected Vec3 getLocalOffset(BlockState state) { - return new Vec3(0.5, 13 / 16d, 0.5); - } - - protected float getScale() { - return super.getScale() * 1.5f; - }; - - }); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java deleted file mode 100644 index 4da21dfb95..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmBlock.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; - -import org.apache.commons.lang3.mutable.MutableBoolean; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.KineticBlock; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.world.Containers; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; - -public class ArmBlock extends KineticBlock implements ITE, ICogWheel { - - public static final BooleanProperty CEILING = BooleanProperty.create("ceiling"); - - public ArmBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(CEILING, false)); - } - - @Override - protected void createBlockStateDefinition(Builder p_206840_1_) { - super.createBlockStateDefinition(p_206840_1_.add(CEILING)); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { - return defaultBlockState().setValue(CEILING, ctx.getClickedFace() == Direction.DOWN); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return state.getValue(CEILING) ? AllShapes.MECHANICAL_ARM_CEILING : AllShapes.MECHANICAL_ARM; - } - - @Override - public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onPlace(state, world, pos, oldState, isMoving); - withTileEntityDo(world, pos, ArmTileEntity::redstoneUpdate); - } - - @Override - public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, - BlockPos p_220069_5_, boolean p_220069_6_) { - withTileEntityDo(world, pos, ArmTileEntity::redstoneUpdate); - } - - @Override - public Axis getRotationAxis(BlockState state) { - return Axis.Y; - } - - @Override - public Class getTileEntityClass() { - return ArmTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.MECHANICAL_ARM.get(); - } - - @Override - public void onRemove(BlockState p_196243_1_, Level world, BlockPos pos, BlockState p_196243_4_, - boolean p_196243_5_) { - if (p_196243_1_.hasBlockEntity() - && (p_196243_1_.getBlock() != p_196243_4_.getBlock() || !p_196243_4_.hasBlockEntity())) { - withTileEntityDo(world, pos, te -> { - if (!te.heldItem.isEmpty()) - Containers.dropItemStack(world, pos.getX(), pos.getY(), pos.getZ(), te.heldItem); - }); - world.removeBlockEntity(pos); - } - } - - @Override - public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, - InteractionHand p_225533_5_, BlockHitResult p_225533_6_) { - MutableBoolean success = new MutableBoolean(false); - withTileEntityDo(world, pos, te -> { - if (te.heldItem.isEmpty()) - return; - success.setTrue(); - if (world.isClientSide) - return; - player.getInventory().placeItemBackInInventory(te.heldItem); - te.heldItem = ItemStack.EMPTY; - te.phase = Phase.SEARCH_INPUTS; - te.setChanged(); - te.sendData(); - }); - - return success.booleanValue() ? InteractionResult.SUCCESS : InteractionResult.PASS; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java deleted file mode 100644 index 9ac0a575b3..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInstance.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; - -import java.util.ArrayList; - -import com.google.common.collect.Lists; -import com.jozufozu.flywheel.api.InstanceData; -import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.SingleRotatingInstance; -import com.simibubi.create.content.contraptions.base.flwdata.RotatingData; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.theme.Color; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.util.Mth; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; - -public class ArmInstance extends SingleRotatingInstance implements DynamicInstance { - - final ModelData base; - final ModelData lowerBody; - final ModelData upperBody; - final ModelData head; - final ModelData claw; - private final ArrayList clawGrips; - - private final ArrayList models; - private final ArmTileEntity arm; - private final Boolean ceiling; - - private boolean firstRender = true; - - private float baseAngle = Float.NaN; - private float lowerArmAngle = Float.NaN; - private float upperArmAngle = Float.NaN; - private float headAngle = Float.NaN; - - public ArmInstance(MaterialManager modelManager, ArmTileEntity tile) { - super(modelManager, tile); - - Material mat = getTransformMaterial(); - - base = mat.getModel(AllBlockPartials.ARM_BASE, blockState) - .createInstance(); - lowerBody = mat.getModel(AllBlockPartials.ARM_LOWER_BODY, blockState) - .createInstance(); - upperBody = mat.getModel(AllBlockPartials.ARM_UPPER_BODY, blockState) - .createInstance(); - head = mat.getModel(AllBlockPartials.ARM_HEAD, blockState) - .createInstance(); - claw = mat.getModel(AllBlockPartials.ARM_CLAW_BASE, blockState) - .createInstance(); - - Instancer clawHalfModel = mat.getModel(AllBlockPartials.ARM_CLAW_GRIP, blockState); - ModelData clawGrip1 = clawHalfModel.createInstance(); - ModelData clawGrip2 = clawHalfModel.createInstance(); - - clawGrips = Lists.newArrayList(clawGrip1, clawGrip2); - models = Lists.newArrayList(base, lowerBody, upperBody, head, claw, clawGrip1, clawGrip2); - arm = tile; - ceiling = blockState.getValue(ArmBlock.CEILING); - - animateArm(false); - } - - @Override - public void beginFrame() { - if (arm.phase == ArmTileEntity.Phase.DANCING && blockEntity.getSpeed() != 0) { - animateArm(true); - firstRender = true; - return; - } - - float pt = AnimationTickHolder.getPartialTicks(); - - float baseAngleNow = arm.baseAngle.getValue(pt); - float lowerArmAngleNow = arm.lowerArmAngle.getValue(pt); - float upperArmAngleNow = arm.upperArmAngle.getValue(pt); - float headAngleNow = arm.headAngle.getValue(pt); - - boolean settled = Mth.equal(baseAngle, baseAngleNow) && Mth.equal(lowerArmAngle, lowerArmAngleNow) - && Mth.equal(upperArmAngle, upperArmAngleNow) && Mth.equal(headAngle, headAngleNow); - - this.baseAngle = baseAngleNow; - this.lowerArmAngle = lowerArmAngleNow; - this.upperArmAngle = upperArmAngleNow; - this.headAngle = headAngleNow; - - if (!settled || firstRender) - animateArm(false); - - if (firstRender) - firstRender = false; - } - - private void animateArm(boolean rave) { - float baseAngle; - float lowerArmAngle; - float upperArmAngle; - float headAngle; - int color; - - if (rave) { - float renderTick = WorldTickHolder.getRenderTime(this.arm.getLevel()) + (blockEntity.hashCode() % 64); - baseAngle = (renderTick * 10) % 360; - lowerArmAngle = Mth.lerp((Mth.sin(renderTick / 4) + 1) / 2, -45, 15); - upperArmAngle = Mth.lerp((Mth.sin(renderTick / 8) + 1) / 4, -45, 95); - headAngle = -lowerArmAngle; - color = Color.rainbowColor(AnimationTickHolder.getTicks() * 100) - .getRGB(); - } else { - baseAngle = this.baseAngle; - lowerArmAngle = this.lowerArmAngle - 135; - upperArmAngle = this.upperArmAngle - 90; - headAngle = this.headAngle; - color = 0xFFFFFF; - } - - PoseStack msLocal = new PoseStack(); - TransformStack msr = TransformStack.cast(msLocal); - msr.translate(getInstancePosition()); - msr.centre(); - - if (ceiling) - msr.rotateX(180); - - ArmRenderer.transformBase(msr, baseAngle); - base.setTransform(msLocal); - - ArmRenderer.transformLowerArm(msr, lowerArmAngle); - lowerBody.setTransform(msLocal) - .setColor(color); - - ArmRenderer.transformUpperArm(msr, upperArmAngle); - upperBody.setTransform(msLocal) - .setColor(color); - - ArmRenderer.transformHead(msr, headAngle); - head.setTransform(msLocal); - - ArmRenderer.transformClaw(msr); - claw.setTransform(msLocal); - - ItemStack item = this.arm.heldItem; - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - boolean hasItem = !item.isEmpty(); - boolean isBlockItem = hasItem && (item.getItem() instanceof BlockItem) - && itemRenderer.getModel(item, Minecraft.getInstance().level, null, 0) - .isGui3d(); - - for (int index : Iterate.zeroAndOne) { - msLocal.pushPose(); - int flip = index * 2 - 1; - ArmRenderer.transformClawHalf(msr, hasItem, isBlockItem, flip); - clawGrips.get(index) - .setTransform(msLocal); - msLocal.popPose(); - } - } - - @Override - public void updateLight() { - super.updateLight(); - - relight(pos, models.stream()); - } - - @Override - protected Instancer getModel() { - return getRotatingMaterial().getModel(AllBlockPartials.ARM_COG, blockEntity.getBlockState()); - } - - @Override - public void remove() { - super.remove(); - models.forEach(InstanceData::delete); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java deleted file mode 100644 index afa3229bec..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmPlacementPacket.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; - -import java.util.Collection; -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ArmPlacementPacket extends SimplePacketBase { - - private Collection points; - private ListTag receivedTag; - private BlockPos pos; - - public ArmPlacementPacket(Collection points, BlockPos pos) { - this.points = points; - this.pos = pos; - } - - public ArmPlacementPacket(FriendlyByteBuf buffer) { - CompoundTag nbt = buffer.readNbt(); - receivedTag = nbt.getList("Points", Tag.TAG_COMPOUND); - pos = buffer.readBlockPos(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - CompoundTag nbt = new CompoundTag(); - ListTag pointsNBT = new ListTag(); - points.stream() - .map(aip -> aip.serialize(pos)) - .forEach(pointsNBT::add); - nbt.put("Points", pointsNBT); - buffer.writeNbt(nbt); - buffer.writeBlockPos(pos); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - Level world = player.level; - if (world == null || !world.isLoaded(pos)) - return; - BlockEntity tileEntity = world.getBlockEntity(pos); - if (!(tileEntity instanceof ArmTileEntity)) - return; - - ArmTileEntity arm = (ArmTileEntity) tileEntity; - arm.interactionPointTag = receivedTag; - }); - context.get() - .setPacketHandled(true); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java deleted file mode 100644 index 3e6a107528..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmRenderer.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity.Phase; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.theme.Color; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.util.Mth; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; - -public class ArmRenderer extends KineticTileEntityRenderer { - - public ArmRenderer(BlockEntityRendererProvider.Context context) { - super(context); - } - - @Override - protected void renderSafe(KineticTileEntity te, float pt, PoseStack ms, MultiBufferSource buffer, int light, - int overlay) { - super.renderSafe(te, pt, ms, buffer, light, overlay); - - ArmTileEntity arm = (ArmTileEntity) te; - ItemStack item = arm.heldItem; - boolean hasItem = !item.isEmpty(); - boolean usingFlywheel = Backend.canUseInstancing(te.getLevel()); - - if (usingFlywheel && !hasItem) - return; - - ItemRenderer itemRenderer = Minecraft.getInstance() - .getItemRenderer(); - - boolean isBlockItem = - hasItem && (item.getItem() instanceof BlockItem) && itemRenderer.getModel(item, te.getLevel(), null, 0) - .isGui3d(); - - VertexConsumer builder = buffer.getBuffer(RenderType.solid()); - BlockState blockState = te.getBlockState(); - - PoseStack msLocal = new PoseStack(); - TransformStack msr = TransformStack.cast(msLocal); - - float baseAngle; - float lowerArmAngle; - float upperArmAngle; - float headAngle; - int color; - - boolean rave = arm.phase == Phase.DANCING && te.getSpeed() != 0; - if (rave) { - float renderTick = WorldTickHolder.getRenderTime(te.getLevel()) + (te.hashCode() % 64); - baseAngle = (renderTick * 10) % 360; - lowerArmAngle = Mth.lerp((Mth.sin(renderTick / 4) + 1) / 2, -45, 15); - upperArmAngle = Mth.lerp((Mth.sin(renderTick / 8) + 1) / 4, -45, 95); - headAngle = -lowerArmAngle; - color = Color.rainbowColor(AnimationTickHolder.getTicks() * 100) - .getRGB(); - } else { - baseAngle = arm.baseAngle.getValue(pt); - lowerArmAngle = arm.lowerArmAngle.getValue(pt) - 135; - upperArmAngle = arm.upperArmAngle.getValue(pt) - 90; - headAngle = arm.headAngle.getValue(pt); - color = 0xFFFFFF; - } - - msr.centre(); - - if (blockState.getValue(ArmBlock.CEILING)) - msr.rotateX(180); - - if (usingFlywheel) - doItemTransforms(msr, baseAngle, lowerArmAngle, upperArmAngle, headAngle); - else - renderArm(builder, ms, msLocal, msr, blockState, color, baseAngle, lowerArmAngle, upperArmAngle, headAngle, - hasItem, isBlockItem, light); - - if (hasItem) { - ms.pushPose(); - float itemScale = isBlockItem ? .5f : .625f; - msr.rotateX(90); - msLocal.translate(0, -4 / 16f, 0); - msLocal.scale(itemScale, itemScale, itemScale); - - ms.last() - .pose() - .multiply(msLocal.last() - .pose()); - - itemRenderer.renderStatic(item, TransformType.FIXED, light, overlay, ms, buffer, 0); - ms.popPose(); - } - - } - - private void renderArm(VertexConsumer builder, PoseStack ms, PoseStack msLocal, TransformStack msr, - BlockState blockState, int color, float baseAngle, float lowerArmAngle, float upperArmAngle, float headAngle, - boolean hasItem, boolean isBlockItem, int light) { - SuperByteBuffer base = CachedPartialBuffers.partial(AllBlockPartials.ARM_BASE, blockState) - .light(light); - SuperByteBuffer lowerBody = CachedPartialBuffers.partial(AllBlockPartials.ARM_LOWER_BODY, blockState) - .light(light); - SuperByteBuffer upperBody = CachedPartialBuffers.partial(AllBlockPartials.ARM_UPPER_BODY, blockState) - .light(light); - SuperByteBuffer head = CachedPartialBuffers.partial(AllBlockPartials.ARM_HEAD, blockState) - .light(light); - SuperByteBuffer claw = CachedPartialBuffers.partial(AllBlockPartials.ARM_CLAW_BASE, blockState) - .light(light); - SuperByteBuffer clawGrip = CachedPartialBuffers.partial(AllBlockPartials.ARM_CLAW_GRIP, blockState); - - transformBase(msr, baseAngle); - base.transform(msLocal) - .renderInto(ms, builder); - - transformLowerArm(msr, lowerArmAngle); - lowerBody.color(color) - .transform(msLocal) - .renderInto(ms, builder); - - transformUpperArm(msr, upperArmAngle); - upperBody.color(color) - .transform(msLocal) - .renderInto(ms, builder); - - transformHead(msr, headAngle); - head.transform(msLocal) - .renderInto(ms, builder); - - transformClaw(msr); - claw.transform(msLocal) - .renderInto(ms, builder); - - for (int flip : Iterate.positiveAndNegative) { - msLocal.pushPose(); - transformClawHalf(msr, hasItem, isBlockItem, flip); - clawGrip.light(light) - .transform(msLocal) - .renderInto(ms, builder); - msLocal.popPose(); - } - } - - private void doItemTransforms(TransformStack msr, float baseAngle, float lowerArmAngle, float upperArmAngle, - float headAngle) { - - transformBase(msr, baseAngle); - transformLowerArm(msr, lowerArmAngle); - transformUpperArm(msr, upperArmAngle); - transformHead(msr, headAngle); - transformClaw(msr); - } - - public static void transformClawHalf(TransformStack msr, boolean hasItem, boolean isBlockItem, int flip) { - msr.translate(0, flip * 3 / 16d, -1 / 16d); - msr.rotateX(flip * (hasItem ? isBlockItem ? 0 : -35 : 0)); - } - - public static void transformClaw(TransformStack msr) { - msr.translate(0, 0, -4 / 16d); - } - - public static void transformHead(TransformStack msr, float headAngle) { - msr.translate(0, 11 / 16d, -11 / 16d); - msr.rotateX(headAngle); - } - - public static void transformUpperArm(TransformStack msr, float upperArmAngle) { - msr.translate(0, 12 / 16d, 12 / 16d); - msr.rotateX(upperArmAngle); - } - - public static void transformLowerArm(TransformStack msr, float lowerArmAngle) { - msr.translate(0, 1 / 16d, -2 / 16d); - msr.rotateX(lowerArmAngle); - msr.translate(0, -1 / 16d, 0); - } - - public static void transformBase(TransformStack msr, float baseAngle) { - msr.translate(0, 4 / 16d, 0); - msr.rotateY(baseAngle); - } - - @Override - public boolean shouldRenderOffScreen(KineticTileEntity te) { - return true; - } - - @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partial(AllBlockPartials.ARM_COG, state); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java deleted file mode 100644 index 795e6d2359..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ /dev/null @@ -1,632 +0,0 @@ -package com.simibubi.create.content.logistics.block.mechanicalArm; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.block.mechanicalArm.AllArmInteractionPointTypes.JukeboxPoint; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.lang.Lang; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.JukeboxBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class ArmTileEntity extends KineticTileEntity implements ITransformableTE { - - // Server - List inputs; - List outputs; - ListTag interactionPointTag; - - // Both - float chasedPointProgress; - int chasedPointIndex; - ItemStack heldItem; - Phase phase; - - // Client - ArmAngleTarget previousTarget; - LerpedFloat lowerArmAngle; - LerpedFloat upperArmAngle; - LerpedFloat baseAngle; - LerpedFloat headAngle; - LerpedFloat clawAngle; - float previousBaseAngle; - boolean updateInteractionPoints; - - // - protected ScrollOptionBehaviour selectionMode; - protected int lastInputIndex = -1; - protected int lastOutputIndex = -1; - protected boolean redstoneLocked; - - public enum Phase { - SEARCH_INPUTS, MOVE_TO_INPUT, SEARCH_OUTPUTS, MOVE_TO_OUTPUT, DANCING - } - - public ArmTileEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { - super(typeIn, pos, state); - inputs = new ArrayList<>(); - outputs = new ArrayList<>(); - interactionPointTag = new ListTag(); - heldItem = ItemStack.EMPTY; - phase = Phase.SEARCH_INPUTS; - previousTarget = ArmAngleTarget.NO_TARGET; - baseAngle = LerpedFloat.angular(); - baseAngle.startWithValue(previousTarget.baseAngle); - lowerArmAngle = LerpedFloat.angular(); - lowerArmAngle.startWithValue(previousTarget.lowerArmAngle); - upperArmAngle = LerpedFloat.angular(); - upperArmAngle.startWithValue(previousTarget.upperArmAngle); - headAngle = LerpedFloat.angular(); - headAngle.startWithValue(previousTarget.headAngle); - clawAngle = LerpedFloat.angular(); - previousBaseAngle = previousTarget.baseAngle; - updateInteractionPoints = true; - redstoneLocked = false; - } - - @Override - public void addBehaviours(List behaviours) { - super.addBehaviours(behaviours); - - selectionMode = new ScrollOptionBehaviour(SelectionMode.class, - CreateLang.translateDirect("logistics.when_multiple_outputs_available"), this, new SelectionModeValueBox()); - selectionMode.requiresWrench(); - behaviours.add(selectionMode); - - registerAwardables(behaviours, AllAdvancements.ARM_BLAZE_BURNER, AllAdvancements.ARM_MANY_TARGETS, - AllAdvancements.MECHANICAL_ARM, AllAdvancements.MUSICAL_ARM); - } - - @Override - public void tick() { - super.tick(); - initInteractionPoints(); - boolean targetReached = tickMovementProgress(); - - if (chasedPointProgress < 1) { - if (phase == Phase.MOVE_TO_INPUT) { - ArmInteractionPoint point = getTargetedInteractionPoint(); - if (point != null) - point.keepAlive(); - } - return; - } - if (level.isClientSide) - return; - - if (phase == Phase.MOVE_TO_INPUT) - collectItem(); - else if (phase == Phase.MOVE_TO_OUTPUT) - depositItem(); - else if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) - searchForItem(); - - if (targetReached) - lazyTick(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - - if (level.isClientSide) - return; - if (chasedPointProgress < .5f) - return; - if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) - checkForMusic(); - if (phase == Phase.SEARCH_OUTPUTS) - searchForDestination(); - } - - private void checkForMusic() { - boolean hasMusic = checkForMusicAmong(inputs) || checkForMusicAmong(outputs); - if (hasMusic != (phase == Phase.DANCING)) { - phase = hasMusic ? Phase.DANCING : Phase.SEARCH_INPUTS; - setChanged(); - sendData(); - } - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(3); - } - - private boolean checkForMusicAmong(List list) { - for (ArmInteractionPoint armInteractionPoint : list) { - if (!(armInteractionPoint instanceof AllArmInteractionPointTypes.JukeboxPoint)) - continue; - BlockState state = level.getBlockState(armInteractionPoint.getPos()); - if (state.getOptionalValue(JukeboxBlock.HAS_RECORD) - .orElse(false)) - return true; - } - return false; - } - - private boolean tickMovementProgress() { - boolean targetReachedPreviously = chasedPointProgress >= 1; - chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f; - if (chasedPointProgress > 1) - chasedPointProgress = 1; - if (!level.isClientSide) - return !targetReachedPreviously && chasedPointProgress >= 1; - - ArmInteractionPoint targetedInteractionPoint = getTargetedInteractionPoint(); - ArmAngleTarget previousTarget = this.previousTarget; - ArmAngleTarget target = targetedInteractionPoint == null ? ArmAngleTarget.NO_TARGET - : targetedInteractionPoint.getTargetAngles(worldPosition, isOnCeiling()); - - baseAngle.setValue(AngleHelper.angleLerp(chasedPointProgress, previousBaseAngle, - target == ArmAngleTarget.NO_TARGET ? previousBaseAngle : target.baseAngle)); - - // Arm's angles first backup to resting position and then continue - if (chasedPointProgress < .5f) - target = ArmAngleTarget.NO_TARGET; - else - previousTarget = ArmAngleTarget.NO_TARGET; - float progress = chasedPointProgress == 1 ? 1 : (chasedPointProgress % .5f) * 2; - - lowerArmAngle.setValue(Mth.lerp(progress, previousTarget.lowerArmAngle, target.lowerArmAngle)); - upperArmAngle.setValue(Mth.lerp(progress, previousTarget.upperArmAngle, target.upperArmAngle)); - headAngle.setValue(AngleHelper.angleLerp(progress, previousTarget.headAngle % 360, target.headAngle % 360)); - - return false; - } - - protected boolean isOnCeiling() { - BlockState state = getBlockState(); - return hasLevel() && state.getOptionalValue(ArmBlock.CEILING) - .orElse(false); - } - - @Nullable - private ArmInteractionPoint getTargetedInteractionPoint() { - if (chasedPointIndex == -1) - return null; - if (phase == Phase.MOVE_TO_INPUT && chasedPointIndex < inputs.size()) - return inputs.get(chasedPointIndex); - if (phase == Phase.MOVE_TO_OUTPUT && chasedPointIndex < outputs.size()) - return outputs.get(chasedPointIndex); - return null; - } - - protected void searchForItem() { - if (redstoneLocked) - return; - - boolean foundInput = false; - // for round robin, we start looking after the last used index, for default we - // start at 0; - int startIndex = selectionMode.get() == SelectionMode.PREFER_FIRST ? 0 : lastInputIndex + 1; - - // if we enforce round robin, only look at the next input in the list, - // otherwise, look at all inputs - int scanRange = selectionMode.get() == SelectionMode.FORCED_ROUND_ROBIN ? lastInputIndex + 2 : inputs.size(); - if (scanRange > inputs.size()) - scanRange = inputs.size(); - - InteractionPoints: for (int i = startIndex; i < scanRange; i++) { - ArmInteractionPoint armInteractionPoint = inputs.get(i); - if (!armInteractionPoint.isValid()) - continue; - for (int j = 0; j < armInteractionPoint.getSlotCount(); j++) { - if (getDistributableAmount(armInteractionPoint, j) == 0) - continue; - - selectIndex(true, i); - foundInput = true; - break InteractionPoints; - } - } - if (!foundInput && selectionMode.get() == SelectionMode.ROUND_ROBIN) { - // if we didn't find an input, but don't want to enforce round robin, reset the - // last index - lastInputIndex = -1; - } - if (lastInputIndex == inputs.size() - 1) { - // if we reached the last input in the list, reset the last index - lastInputIndex = -1; - } - } - - protected void searchForDestination() { - ItemStack held = heldItem.copy(); - - boolean foundOutput = false; - // for round robin, we start looking after the last used index, for default we - // start at 0; - int startIndex = selectionMode.get() == SelectionMode.PREFER_FIRST ? 0 : lastOutputIndex + 1; - - // if we enforce round robin, only look at the next index in the list, - // otherwise, look at all - int scanRange = selectionMode.get() == SelectionMode.FORCED_ROUND_ROBIN ? lastOutputIndex + 2 : outputs.size(); - if (scanRange > outputs.size()) - scanRange = outputs.size(); - - for (int i = startIndex; i < scanRange; i++) { - ArmInteractionPoint armInteractionPoint = outputs.get(i); - if (!armInteractionPoint.isValid()) - continue; - - ItemStack remainder = armInteractionPoint.insert(held, true); - if (remainder.equals(heldItem, false)) - continue; - - selectIndex(false, i); - foundOutput = true; - break; - } - - if (!foundOutput && selectionMode.get() == SelectionMode.ROUND_ROBIN) { - // if we didn't find an input, but don't want to enforce round robin, reset the - // last index - lastOutputIndex = -1; - } - if (lastOutputIndex == outputs.size() - 1) { - // if we reached the last input in the list, reset the last index - lastOutputIndex = -1; - } - } - - // input == true => select input, false => select output - private void selectIndex(boolean input, int index) { - phase = input ? Phase.MOVE_TO_INPUT : Phase.MOVE_TO_OUTPUT; - chasedPointIndex = index; - chasedPointProgress = 0; - if (input) - lastInputIndex = index; - else - lastOutputIndex = index; - sendData(); - setChanged(); - } - - protected int getDistributableAmount(ArmInteractionPoint armInteractionPoint, int i) { - ItemStack stack = armInteractionPoint.extract(i, true); - ItemStack remainder = simulateInsertion(stack); - if (stack.sameItem(remainder)) { - return stack.getCount() - remainder.getCount(); - } else { - return stack.getCount(); - } - } - - private ItemStack simulateInsertion(ItemStack stack) { - for (ArmInteractionPoint armInteractionPoint : outputs) { - if (armInteractionPoint.isValid()) - stack = armInteractionPoint.insert(stack, true); - if (stack.isEmpty()) - break; - } - return stack; - } - - protected void depositItem() { - ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); - if (armInteractionPoint != null && armInteractionPoint.isValid()) { - ItemStack toInsert = heldItem.copy(); - ItemStack remainder = armInteractionPoint.insert(toInsert, false); - heldItem = remainder; - - if (armInteractionPoint instanceof JukeboxPoint && remainder.isEmpty()) - award(AllAdvancements.MUSICAL_ARM); - } - - phase = heldItem.isEmpty() ? Phase.SEARCH_INPUTS : Phase.SEARCH_OUTPUTS; - chasedPointProgress = 0; - chasedPointIndex = -1; - sendData(); - setChanged(); - - if (!level.isClientSide) - award(AllAdvancements.MECHANICAL_ARM); - } - - protected void collectItem() { - ArmInteractionPoint armInteractionPoint = getTargetedInteractionPoint(); - if (armInteractionPoint != null && armInteractionPoint.isValid()) - for (int i = 0; i < armInteractionPoint.getSlotCount(); i++) { - int amountExtracted = getDistributableAmount(armInteractionPoint, i); - if (amountExtracted == 0) - continue; - - ItemStack prevHeld = heldItem; - heldItem = armInteractionPoint.extract(i, amountExtracted, false); - phase = Phase.SEARCH_OUTPUTS; - chasedPointProgress = 0; - chasedPointIndex = -1; - sendData(); - setChanged(); - - if (!prevHeld.sameItem(heldItem)) - level.playSound(null, worldPosition, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, .125f, - .5f + Create.RANDOM.nextFloat() * .25f); - return; - } - - phase = Phase.SEARCH_INPUTS; - chasedPointProgress = 0; - chasedPointIndex = -1; - sendData(); - setChanged(); - } - - public void redstoneUpdate() { - if (level.isClientSide) - return; - boolean blockPowered = level.hasNeighborSignal(worldPosition); - if (blockPowered == redstoneLocked) - return; - redstoneLocked = blockPowered; - sendData(); - if (!redstoneLocked) - searchForItem(); - } - - @Override - public void transform(StructureTransform transform) { - if (interactionPointTag == null) - return; - - for (Tag tag : interactionPointTag) { - ArmInteractionPoint.transformPos((CompoundTag) tag, transform); - } - - notifyUpdate(); - } - - // ClientLevel#hasChunk (and consequently #isAreaLoaded) always returns true, - // so manually check the ChunkSource to avoid weird behavior on the client side - protected boolean isAreaActuallyLoaded(BlockPos center, int range) { - if (!level.isAreaLoaded(center, range)) { - return false; - } - if (level.isClientSide) { - int minY = center.getY() - range; - int maxY = center.getY() + range; - if (maxY < level.getMinBuildHeight() || minY >= level.getMaxBuildHeight()) { - return false; - } - - int minX = center.getX() - range; - int minZ = center.getZ() - range; - int maxX = center.getX() + range; - int maxZ = center.getZ() + range; - - int minChunkX = SectionPos.blockToSectionCoord(minX); - int maxChunkX = SectionPos.blockToSectionCoord(maxX); - int minChunkZ = SectionPos.blockToSectionCoord(minZ); - int maxChunkZ = SectionPos.blockToSectionCoord(maxZ); - - ChunkSource chunkSource = level.getChunkSource(); - for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { - for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { - if (!chunkSource.hasChunk(chunkX, chunkZ)) { - return false; - } - } - } - } - return true; - } - - protected void initInteractionPoints() { - if (!updateInteractionPoints || interactionPointTag == null) - return; - if (!isAreaActuallyLoaded(worldPosition, getRange() + 1)) - return; - inputs.clear(); - outputs.clear(); - - boolean hasBlazeBurner = false; - for (Tag tag : interactionPointTag) { - ArmInteractionPoint point = ArmInteractionPoint.deserialize((CompoundTag) tag, level, worldPosition); - if (point == null) - continue; - if (point.getMode() == Mode.DEPOSIT) - outputs.add(point); - else if (point.getMode() == Mode.TAKE) - inputs.add(point); - hasBlazeBurner |= point instanceof AllArmInteractionPointTypes.BlazeBurnerPoint; - } - - if (!level.isClientSide) { - if (outputs.size() >= 10) - award(AllAdvancements.ARM_MANY_TARGETS); - if (hasBlazeBurner) - award(AllAdvancements.ARM_BLAZE_BURNER); - } - - updateInteractionPoints = false; - sendData(); - setChanged(); - } - - public void writeInteractionPoints(CompoundTag compound) { - if (updateInteractionPoints) { - compound.put("InteractionPoints", interactionPointTag); - } else { - ListTag pointsNBT = new ListTag(); - inputs.stream() - .map(aip -> aip.serialize(worldPosition)) - .forEach(pointsNBT::add); - outputs.stream() - .map(aip -> aip.serialize(worldPosition)) - .forEach(pointsNBT::add); - compound.put("InteractionPoints", pointsNBT); - } - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - - writeInteractionPoints(compound); - - NBTHelper.writeEnum(compound, "Phase", phase); - compound.putBoolean("Powered", redstoneLocked); - compound.put("HeldItem", heldItem.serializeNBT()); - compound.putInt("TargetPointIndex", chasedPointIndex); - compound.putFloat("MovementProgress", chasedPointProgress); - } - - @Override - public void writeSafe(CompoundTag compound) { - super.writeSafe(compound); - - writeInteractionPoints(compound); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - int previousIndex = chasedPointIndex; - Phase previousPhase = phase; - ListTag interactionPointTagBefore = interactionPointTag; - - super.read(compound, clientPacket); - heldItem = ItemStack.of(compound.getCompound("HeldItem")); - phase = NBTHelper.readEnum(compound, "Phase", Phase.class); - chasedPointIndex = compound.getInt("TargetPointIndex"); - chasedPointProgress = compound.getFloat("MovementProgress"); - interactionPointTag = compound.getList("InteractionPoints", Tag.TAG_COMPOUND); - redstoneLocked = compound.getBoolean("Powered"); - - if (!clientPacket) - return; - - boolean ceiling = isOnCeiling(); - if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size()) - updateInteractionPoints = true; - if (previousIndex != chasedPointIndex || (previousPhase != phase)) { - ArmInteractionPoint previousPoint = null; - if (previousPhase == Phase.MOVE_TO_INPUT && previousIndex < inputs.size()) - previousPoint = inputs.get(previousIndex); - if (previousPhase == Phase.MOVE_TO_OUTPUT && previousIndex < outputs.size()) - previousPoint = outputs.get(previousIndex); - previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET - : previousPoint.getTargetAngles(worldPosition, ceiling); - if (previousPoint != null) - previousBaseAngle = previousTarget.baseAngle; - - ArmInteractionPoint targetedPoint = getTargetedInteractionPoint(); - if (targetedPoint != null) - targetedPoint.updateCachedState(); - } - } - - public static int getRange() { - return AllConfigs.SERVER.logistics.mechanicalArmRange.get(); - } - - @Override - public boolean addToTooltip(List tooltip, boolean isPlayerSneaking) { - if (super.addToTooltip(tooltip, isPlayerSneaking)) - return true; - if (isPlayerSneaking) - return false; - if (!inputs.isEmpty()) - return false; - if (!outputs.isEmpty()) - return false; - - TooltipHelper.addHint(tooltip, "hint.mechanical_arm_no_targets"); - return true; - } - - public void setLevel(Level level) { - super.setLevel(level); - for (ArmInteractionPoint input : inputs) { - input.setLevel(level); - } - for (ArmInteractionPoint output : outputs) { - output.setLevel(level); - } - } - - private class SelectionModeValueBox extends CenteredSideValueBoxTransform { - - public SelectionModeValueBox() { - super((blockState, direction) -> !direction.getAxis() - .isVertical()); - } - - @Override - protected Vec3 getLocalOffset(BlockState state) { - int yPos = state.getValue(ArmBlock.CEILING) ? 16 - 3 : 3; - Vec3 location = VecHelper.voxelSpace(8, yPos, 15.95); - location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Direction.Axis.Y); - return location; - } - - @Override - protected float getScale() { - return .3f; - } - - } - - public enum SelectionMode implements INamedIconOptions { - ROUND_ROBIN(AllIcons.I_ARM_ROUND_ROBIN), - FORCED_ROUND_ROBIN(AllIcons.I_ARM_FORCED_ROUND_ROBIN), - PREFER_FIRST(AllIcons.I_ARM_PREFER_FIRST), - - ; - - private final String translationKey; - private final AllIcons icon; - - SelectionMode(AllIcons icon) { - this.icon = icon; - this.translationKey = "mechanical_arm.selection_mode." + Lang.asId(name()); - } - - @Override - public AllIcons getIcon() { - return icon; - } - - @Override - public String getTranslationKey() { - return translationKey; - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java deleted file mode 100644 index a3c7c83388..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverRenderer.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import com.jozufozu.flywheel.backend.Backend; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.catnip.utility.theme.Color; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.AttachFace; - -public class AnalogLeverRenderer extends SafeTileEntityRenderer { - - public AnalogLeverRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(AnalogLeverTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - if (Backend.canUseInstancing(te.getLevel())) return; - - BlockState leverState = te.getBlockState(); - float state = te.clientState.getValue(partialTicks); - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - // Handle - SuperByteBuffer handle = CachedPartialBuffers.partial(AllBlockPartials.ANALOG_LEVER_HANDLE, leverState); - float angle = (float) ((state / 15) * 90 / 180 * Math.PI); - transform(handle, leverState).translate(1 / 2f, 1 / 16f, 1 / 2f) - .rotate(Direction.EAST, angle) - .translate(-1 / 2f, -1 / 16f, -1 / 2f); - handle.light(light) - .renderInto(ms, vb); - - // Indicator - int color = Color.mixColors(0x2C0300, 0xCD0000, state / 15f); - SuperByteBuffer indicator = transform(CachedPartialBuffers.partial(AllBlockPartials.ANALOG_LEVER_INDICATOR, leverState), leverState); - indicator.light(light) - .color(color) - .renderInto(ms, vb); - } - - private SuperByteBuffer transform(SuperByteBuffer buffer, BlockState leverState) { - AttachFace face = leverState.getValue(AnalogLeverBlock.FACE); - float rX = face == AttachFace.FLOOR ? 0 : face == AttachFace.WALL ? 90 : 180; - float rY = AngleHelper.horizontalAngle(leverState.getValue(AnalogLeverBlock.FACING)); - buffer.rotateCentered(Direction.UP, (float) (rY / 180 * Math.PI)); - buffer.rotateCentered(Direction.EAST, (float) (rX / 180 * Math.PI)); - return buffer; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java deleted file mode 100644 index 55a19a514c..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.List; - -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class AnalogLeverTileEntity extends SmartTileEntity implements IHaveGoggleInformation { - - int state = 0; - int lastChange; - LerpedFloat clientState; - - public AnalogLeverTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - clientState = LerpedFloat.linear(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("State", state); - compound.putInt("ChangeTimer", lastChange); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - state = compound.getInt("State"); - lastChange = compound.getInt("ChangeTimer"); - clientState.chase(state, 0.2f, Chaser.EXP); - super.read(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - if (lastChange > 0) { - lastChange--; - if (lastChange == 0) - updateOutput(); - } - if (level.isClientSide) - clientState.tickChaser(); - } - - @Override - public void initialize() { - super.initialize(); - - } - - private void updateOutput() { - AnalogLeverBlock.updateNeighbors(getBlockState(), level, worldPosition); - } - - @Override - public void addBehaviours(List behaviours) { - } - - public void changeState(boolean back) { - int prevState = state; - state += back ? -1 : 1; - state = Mth.clamp(state, 0, 15); - if (prevState != state) - lastChange = 15; - sendData(); - } - - @Override - public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { - tooltip.add(componentSpacing.plainCopy().append(CreateLang.translateDirect("tooltip.analogStrength", this.state))); - - return true; - } - - public int getState() { - return state; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java deleted file mode 100644 index fe75390641..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.ticks.TickPriority; - -public class ContactMovementBehaviour implements MovementBehaviour { - - @Override - public Vec3 getActiveAreaOffset(MovementContext context) { - return Vec3.atLowerCornerOf(context.state.getValue(RedstoneContactBlock.FACING).getNormal()).scale(.65f); - } - - @Override - public void visitNewPosition(MovementContext context, BlockPos pos) { - BlockState block = context.state; - Level world = context.world; - - if (world.isClientSide) - return; - if (context.firstMovement) - return; - - deactivateLastVisitedContact(context); - BlockState visitedState = world.getBlockState(pos); - if (!AllBlocks.REDSTONE_CONTACT.has(visitedState)) - return; - - Vec3 contact = Vec3.atLowerCornerOf(block.getValue(RedstoneContactBlock.FACING).getNormal()); - contact = context.rotation.apply(contact); - Direction direction = Direction.getNearest(contact.x, contact.y, contact.z); - - if (!RedstoneContactBlock.hasValidContact(world, pos.relative(direction.getOpposite()), direction)) - return; - world.setBlockAndUpdate(pos, visitedState.setValue(RedstoneContactBlock.POWERED, true)); - context.data.put("lastContact", NbtUtils.writeBlockPos(pos)); - return; - } - - @Override - public void stopMoving(MovementContext context) { - deactivateLastVisitedContact(context); - } - - @Override - public void cancelStall(MovementContext context) { - MovementBehaviour.super.cancelStall(context); - deactivateLastVisitedContact(context); - } - - public void deactivateLastVisitedContact(MovementContext context) { - if (context.data.contains("lastContact")) { - BlockPos last = NbtUtils.readBlockPos(context.data.getCompound("lastContact")); - context.world.scheduleTick(last, AllBlocks.REDSTONE_CONTACT.get(), 1, TickPriority.NORMAL); - context.data.remove("lastContact"); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverBlock.java deleted file mode 100644 index d0005a7bb9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverBlock.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.Random; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class ContentObserverBlock extends HorizontalDirectionalBlock implements ITE, IWrenchable { - - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - - public ContentObserverBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(POWERED, false)); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.CONTENT_OBSERVER.get(state.getValue(FACING)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(POWERED, FACING); - super.createBlockStateDefinition(builder); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState state = defaultBlockState(); - Capability itemCap = CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; - Capability fluidCap = CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; - - Direction preferredFacing = null; - for (Direction face : Iterate.horizontalDirections) { - BlockPos offsetPos = context.getClickedPos() - .relative(face); - Level world = context.getLevel(); - boolean canDetect = false; - BlockEntity tileEntity = world.getBlockEntity(offsetPos); - - if (TileEntityBehaviour.get(tileEntity, TransportedItemStackHandlerBehaviour.TYPE) != null) - canDetect = true; - else if (TileEntityBehaviour.get(tileEntity, FluidTransportBehaviour.TYPE) != null) - canDetect = true; - else if (tileEntity != null && (tileEntity.getCapability(itemCap) - .isPresent() - || tileEntity.getCapability(fluidCap) - .isPresent())) - canDetect = true; - else if (tileEntity instanceof FunnelTileEntity) - canDetect = true; - - if (canDetect) { - if (preferredFacing != null) { - preferredFacing = null; - break; - } - preferredFacing = face; - } - - } - - if (preferredFacing != null) - return state.setValue(FACING, preferredFacing); - return state.setValue(FACING, context.getHorizontalDirection() - .getOpposite()); - } - - @Override - public boolean isSignalSource(BlockState state) { - return state.getValue(POWERED); - } - - @Override - public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { - return isSignalSource(blockState) && (side == null || side != blockState.getValue(FACING) - .getOpposite()) ? 15 : 0; - } - - @Override - public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { - worldIn.setBlock(pos, state.setValue(POWERED, false), 2); - worldIn.updateNeighborsAt(pos, this); - } - - @Override - public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { - return side != state.getValue(FACING) - .getOpposite(); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.hasBlockEntity() && state.getBlock() != newState.getBlock()) { - TileEntityBehaviour.destroy(worldIn, pos, FilteringBehaviour.TYPE); - worldIn.removeBlockEntity(pos); - } - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - InvManipulationBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); - if (behaviour != null) - behaviour.onNeighborChanged(fromPos); - } - - public void onFunnelTransfer(Level world, BlockPos funnelPos, ItemStack transferred) { - for (Direction direction : Iterate.horizontalDirections) { - BlockPos detectorPos = funnelPos.relative(direction); - BlockState detectorState = world.getBlockState(detectorPos); - if (!AllBlocks.CONTENT_OBSERVER.has(detectorState)) - continue; - if (detectorState.getValue(FACING) != direction.getOpposite()) - continue; - withTileEntityDo(world, detectorPos, te -> { - FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE); - if (filteringBehaviour == null) - return; - if (!filteringBehaviour.test(transferred)) - return; - te.activate(4); - }); - } - } - - @Override - public Class getTileEntityClass() { - return ContentObserverTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.CONTENT_OBSERVER.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverTileEntity.java deleted file mode 100644 index 363b1d0b1d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContentObserverTileEntity.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.List; - -import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; -import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.TankManipulationBehaviour; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class ContentObserverTileEntity extends SmartTileEntity { - - private static final int DEFAULT_DELAY = 6; - private FilteringBehaviour filtering; - private InvManipulationBehaviour observedInventory; - private TankManipulationBehaviour observedTank; - public int turnOffTicks = 0; - - public ContentObserverTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(20); - } - - @Override - public void addBehaviours(List behaviours) { - filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot()).moveText(new Vec3(0, 5, 0)); - behaviours.add(filtering); - - InterfaceProvider towardBlockFacing = InterfaceProvider.towardBlockFacing(); - behaviours.add(observedInventory = new InvManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); - behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); - } - - @Override - public void tick() { - super.tick(); - BlockState state = getBlockState(); - if (turnOffTicks > 0) { - turnOffTicks--; - if (turnOffTicks == 0) - level.scheduleTick(worldPosition, state.getBlock(), 1); - } - - if (!isActive()) - return; - - Direction facing = state.getValue(ContentObserverBlock.FACING); - BlockPos targetPos = worldPosition.relative(facing); - - // Detect items on belt - TransportedItemStackHandlerBehaviour behaviour = - TileEntityBehaviour.get(level, targetPos, TransportedItemStackHandlerBehaviour.TYPE); - if (behaviour != null) { - behaviour.handleCenteredProcessingOnAllItems(.45f, stack -> { - if (!filtering.test(stack.stack) || turnOffTicks == 6) - return TransportedResult.doNothing(); - activate(); - return TransportedResult.doNothing(); - }); - return; - } - - // Detect fluids in pipe - FluidTransportBehaviour fluidBehaviour = - TileEntityBehaviour.get(level, targetPos, FluidTransportBehaviour.TYPE); - if (fluidBehaviour != null) { - for (Direction side : Iterate.directions) { - Flow flow = fluidBehaviour.getFlow(side); - if (flow == null || !flow.inbound || !flow.complete) - continue; - if (!filtering.test(flow.fluid)) - continue; - activate(); - return; - } - return; - } - - if (!observedInventory.simulate() - .extract() - .isEmpty()) { - activate(); - return; - } - - if (!observedTank.simulate() - .extractAny() - .isEmpty()) { - activate(); - return; - } - } - - public void activate() { - activate(DEFAULT_DELAY); - } - - public void activate(int ticks) { - BlockState state = getBlockState(); - turnOffTicks = ticks; - if (state.getValue(ContentObserverBlock.POWERED)) - return; - level.setBlockAndUpdate(worldPosition, state.setValue(ContentObserverBlock.POWERED, true)); - level.updateNeighborsAt(worldPosition, state.getBlock()); - } - - private boolean isActive() { - return true; - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putInt("TurnOff", turnOffTicks); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - turnOffTicks = compound.getInt("TurnOff"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/FilteredDetectorFilterSlot.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/FilteredDetectorFilterSlot.java deleted file mode 100644 index 08921f17ab..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/FilteredDetectorFilterSlot.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class FilteredDetectorFilterSlot extends ValueBoxTransform { - Vec3 position = VecHelper.voxelSpace(8f, 15.5f, 11f); - - @Override - protected Vec3 getLocalOffset(BlockState state) { - return rotateHorizontally(state, position); - } - - @Override - protected void rotate(BlockState state, PoseStack ms) { - float yRot = AngleHelper.horizontalAngle(state.getValue(HorizontalDirectionalBlock.FACING)) + 180; - TransformStack.cast(ms) - .rotateY(yRot) - .rotateX(90); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java deleted file mode 100644 index 57c06c8d51..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.Random; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.block.redstone.DoubleFaceAttachedBlock.DoubleAttachFace; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.render.RenderTypes; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; -import com.simibubi.create.foundation.utility.DyeHelper; - -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.createmod.catnip.utility.theme.Color; -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.font.glyphs.BakedGlyph; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.MultiBufferSource.BufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Style; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class NixieTubeRenderer extends SafeTileEntityRenderer { - - private static Random r = new Random(); - - public NixieTubeRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(NixieTubeTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - ms.pushPose(); - BlockState blockState = te.getBlockState(); - DoubleAttachFace face = blockState.getValue(NixieTubeBlock.FACE); - float yRot = AngleHelper.horizontalAngle(blockState.getValue(NixieTubeBlock.FACING)) - 90 - + (face == DoubleAttachFace.WALL_REVERSED ? 180 : 0); - float xRot = face == DoubleAttachFace.WALL ? -90 : face == DoubleAttachFace.WALL_REVERSED ? 90 : 0; - - TransformStack msr = TransformStack.cast(ms); - msr.centre() - .rotateY(yRot) - .rotateZ(xRot) - .unCentre(); - - if (te.signalState != null) { - renderAsSignal(te, partialTicks, ms, buffer, light, overlay); - ms.popPose(); - return; - } - - msr.centre(); - - float height = face == DoubleAttachFace.CEILING ? 5 : 3; - float scale = 1 / 20f; - - Couple s = te.getDisplayedStrings(); - DyeColor color = NixieTubeBlock.colorOf(te.getBlockState()); - - ms.pushPose(); - ms.translate(-4 / 16f, 0, 0); - ms.scale(scale, -scale, scale); - drawTube(ms, buffer, s.getFirst(), height, color); - ms.popPose(); - - ms.pushPose(); - ms.translate(4 / 16f, 0, 0); - ms.scale(scale, -scale, scale); - drawTube(ms, buffer, s.getSecond(), height, color); - ms.popPose(); - - ms.popPose(); - } - - public static void drawTube(PoseStack ms, MultiBufferSource buffer, String c, float height, DyeColor color) { - Font fontRenderer = Minecraft.getInstance().font; - float charWidth = fontRenderer.width(c); - float shadowOffset = .5f; - float flicker = r.nextFloat(); - Couple couple = DyeHelper.DYE_TABLE.get(color); - int brightColor = couple.getFirst(); - int darkColor = couple.getSecond(); - int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4); - - ms.pushPose(); - ms.translate((charWidth - shadowOffset) / -2f, -height, 0); - drawChar(ms, buffer, c, flickeringBrightColor); - ms.pushPose(); - ms.translate(shadowOffset, shadowOffset, -1 / 16f); - drawChar(ms, buffer, c, darkColor); - ms.popPose(); - ms.popPose(); - - ms.pushPose(); - ms.scale(-1, 1, 1); - ms.translate((charWidth - shadowOffset) / -2f, -height, 0); - drawChar(ms, buffer, c, darkColor); - ms.pushPose(); - ms.translate(-shadowOffset, shadowOffset, -1 / 16f); - drawChar(ms, buffer, c, Color.mixColors(darkColor, 0, .35f)); - ms.popPose(); - ms.popPose(); - } - - private static void drawChar(PoseStack ms, MultiBufferSource buffer, String c, int color) { - Font fontRenderer = Minecraft.getInstance().font; - fontRenderer.drawInBatch(c, 0, 0, color, false, ms.last() - .pose(), buffer, false, 0, LightTexture.FULL_BRIGHT); - if (buffer instanceof BufferSource) { - BakedGlyph texturedglyph = fontRenderer.getFontSet(Style.DEFAULT_FONT) - .whiteGlyph(); - ((BufferSource) buffer).endBatch(texturedglyph.renderType(Font.DisplayMode.NORMAL)); - } - } - - private void renderAsSignal(NixieTubeTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - Direction facing = NixieTubeBlock.getFacing(blockState); - Vec3 observerVec = Minecraft.getInstance().cameraEntity.getEyePosition(partialTicks); - TransformStack msr = TransformStack.cast(ms); - - if (facing == Direction.DOWN) - msr.centre() - .rotateZ(180) - .unCentre(); - - boolean invertTubes = - facing == Direction.DOWN || blockState.getValue(NixieTubeBlock.FACE) == DoubleAttachFace.WALL_REVERSED; - - CachedPartialBuffers.partial(AllBlockPartials.SIGNAL_PANEL, blockState) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - - ms.pushPose(); - ms.translate(1 / 2f, 7.5f / 16f, 1 / 2f); - float renderTime = WorldTickHolder.getRenderTime(te.getLevel()); - - for (boolean first : Iterate.trueAndFalse) { - Vec3 lampVec = Vec3.atCenterOf(te.getBlockPos()); - Vec3 diff = lampVec.subtract(observerVec); - - if (first && !te.signalState.isRedLight(renderTime)) - continue; - if (!first && !te.signalState.isGreenLight(renderTime) && !te.signalState.isYellowLight(renderTime)) - continue; - - boolean flip = first == invertTubes; - boolean yellow = te.signalState.isYellowLight(renderTime); - - ms.pushPose(); - ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0); - - if (diff.lengthSqr() < 96 * 96) { - boolean vert = first ^ facing.getAxis() - .isHorizontal(); - float longSide = yellow ? 1 : 4; - float longSideGlow = yellow ? 2 : 5.125f; - - CachedPartialBuffers.partial(AllBlockPartials.SIGNAL_WHITE_CUBE, blockState) - .light(0xf000f0) - .disableDiffuse() - .scale(vert ? longSide : 1, vert ? 1 : longSide, 1) - .renderInto(ms, buffer.getBuffer(RenderType.translucent())); - - CachedPartialBuffers.partial( - first ? AllBlockPartials.SIGNAL_RED_GLOW - : yellow ? AllBlockPartials.SIGNAL_YELLOW_GLOW : AllBlockPartials.SIGNAL_WHITE_GLOW, - blockState) - .light(0xF000F0) - .disableDiffuse() - .scale(vert ? longSideGlow : 2, vert ? 2 : longSideGlow, 2) - .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); - } - - CachedPartialBuffers.partial( - first ? AllBlockPartials.SIGNAL_RED - : yellow ? AllBlockPartials.SIGNAL_YELLOW : AllBlockPartials.SIGNAL_WHITE, - blockState) - .light(0xF000F0) - .disableDiffuse() - .scale(1 + 1 / 16f) - .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); - - ms.popPose(); - } - ms.popPose(); - - } - - @Override - public int getViewDistance() { - return 128; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java deleted file mode 100644 index 2a51a71baa..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeTileEntity.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.Optional; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.DynamicComponent; - -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class NixieTubeTileEntity extends SmartTileEntity { - - private static final Couple EMPTY = Couple.create("", ""); - - private int redstoneStrength; - private Optional customText; - private int nixieIndex; - private Couple displayedStrings; - - private WeakReference cachedSignalTE; - public SignalState signalState; - - public NixieTubeTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - customText = Optional.empty(); - redstoneStrength = 0; - cachedSignalTE = new WeakReference<>(null); - } - - @Override - public void tick() { - super.tick(); - if (!level.isClientSide) - return; - - signalState = null; - SignalTileEntity signalTileEntity = cachedSignalTE.get(); - - if (signalTileEntity == null || signalTileEntity.isRemoved()) { - Direction facing = NixieTubeBlock.getFacing(getBlockState()); - BlockEntity blockEntity = level.getBlockEntity(worldPosition.relative(facing.getOpposite())); - if (blockEntity instanceof SignalTileEntity signal) { - signalState = signal.getState(); - cachedSignalTE = new WeakReference<>(signal); - } - return; - } - - signalState = signalTileEntity.getState(); - } - - @Override - public void initialize() { - if (level.isClientSide) - updateDisplayedStrings(); - } - - // - - public boolean reactsToRedstone() { - return customText.isEmpty(); - } - - public Couple getDisplayedStrings() { - if (displayedStrings == null) - return EMPTY; - return displayedStrings; - } - - public MutableComponent getFullText() { - return customText.map(DynamicComponent::get) - .orElse(Components.literal("" + redstoneStrength)); - } - - public void updateRedstoneStrength(int signalStrength) { - clearCustomText(); - redstoneStrength = signalStrength; - DisplayLinkBlock.notifyGatherers(level, worldPosition); - notifyUpdate(); - } - - public void displayCustomText(String tagElement, int nixiePositionInRow) { - if (tagElement == null) - return; - if (customText.filter(d -> d.sameAs(tagElement)) - .isPresent()) - return; - - DynamicComponent component = customText.orElseGet(DynamicComponent::new); - component.displayCustomText(level, worldPosition, tagElement); - customText = Optional.of(component); - nixieIndex = nixiePositionInRow; - DisplayLinkBlock.notifyGatherers(level, worldPosition); - notifyUpdate(); - } - - public void updateDisplayedStrings() { - if (signalState != null) - return; - customText.map(DynamicComponent::resolve) - .ifPresentOrElse( - fullText -> displayedStrings = - Couple.create(charOrEmpty(fullText, nixieIndex * 2), charOrEmpty(fullText, nixieIndex * 2 + 1)), - () -> displayedStrings = - Couple.create(redstoneStrength < 10 ? "0" : "1", String.valueOf(redstoneStrength % 10))); - } - - public void clearCustomText() { - nixieIndex = 0; - customText = Optional.empty(); - } - - // - - @Override - protected void read(CompoundTag nbt, boolean clientPacket) { - super.read(nbt, clientPacket); - - if (nbt.contains("CustomText")) { - DynamicComponent component = customText.orElseGet(DynamicComponent::new); - component.read(level, worldPosition, nbt); - - if (component.isValid()) { - customText = Optional.of(component); - nixieIndex = nbt.getInt("CustomTextIndex"); - } else { - customText = Optional.empty(); - nixieIndex = 0; - } - } - - if (customText.isEmpty()) - redstoneStrength = nbt.getInt("RedstoneStrength"); - if (clientPacket) - updateDisplayedStrings(); - } - - @Override - protected void write(CompoundTag nbt, boolean clientPacket) { - super.write(nbt, clientPacket); - - if (customText.isPresent()) { - nbt.putInt("CustomTextIndex", nixieIndex); - customText.get() - .write(nbt); - } else - nbt.putInt("RedstoneStrength", redstoneStrength); - } - - private String charOrEmpty(String string, int index) { - return string.length() <= index ? " " : string.substring(index, index + 1); - } - - @Override - public void addBehaviours(List behaviours) {} - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneContactBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneContactBlock.java deleted file mode 100644 index bb17964e98..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneContactBlock.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.Random; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; - -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; - -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -public class RedstoneContactBlock extends WrenchableDirectionalBlock { - - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - - public RedstoneContactBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(POWERED, false) - .setValue(FACING, Direction.UP)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(POWERED); - super.createBlockStateDefinition(builder); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState state = defaultBlockState().setValue(FACING, context.getNearestLookingDirection() - .getOpposite()); - Direction placeDirection = context.getClickedFace() - .getOpposite(); - - if ((context.getPlayer() != null && context.getPlayer() - .isShiftKeyDown()) || hasValidContact(context.getLevel(), context.getClickedPos(), placeDirection)) - state = state.setValue(FACING, placeDirection); - if (hasValidContact(context.getLevel(), context.getClickedPos(), state.getValue(FACING))) - state = state.setValue(POWERED, true); - - return state; - } - - @Override - public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn, - BlockPos currentPos, BlockPos facingPos) { - if (facing != stateIn.getValue(FACING)) - return stateIn; - boolean hasValidContact = hasValidContact(worldIn, currentPos, facing); - if (stateIn.getValue(POWERED) != hasValidContact) { - return stateIn.setValue(POWERED, hasValidContact); - } - return stateIn; - } - - @SuppressWarnings("deprecation") - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.getBlock() == this && newState.getBlock() == this) { - if (state == newState.cycle(POWERED)) - worldIn.updateNeighborsAt(pos, this); - } - super.onRemove(state, worldIn, pos, newState, isMoving); - } - - @Override - public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { - boolean hasValidContact = hasValidContact(worldIn, pos, state.getValue(FACING)); - if (state.getValue(POWERED) != hasValidContact) - worldIn.setBlockAndUpdate(pos, state.setValue(POWERED, hasValidContact)); - } - - public static boolean hasValidContact(LevelAccessor world, BlockPos pos, Direction direction) { - BlockState blockState = world.getBlockState(pos.relative(direction)); - return AllBlocks.REDSTONE_CONTACT.has(blockState) && blockState.getValue(FACING) == direction.getOpposite(); - } - - @Override - public boolean isSignalSource(BlockState state) { - return state.getValue(POWERED); - } - - @Override - public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { - if (side == null) - return true; - return state.getValue(FACING) != side.getOpposite(); - } - - @Override - public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) { - return state.getValue(POWERED) ? 15 : 0; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java deleted file mode 100644 index 408436d68f..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class RedstoneLinkTileEntity extends SmartTileEntity { - - private boolean receivedSignalChanged; - private int receivedSignal; - private int transmittedSignal; - private LinkBehaviour link; - private boolean transmitter; - - public RedstoneLinkTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void addBehavioursDeferred(List behaviours) { - createLink(); - behaviours.add(link); - } - - protected void createLink() { - Pair slots = - ValueBoxTransform.Dual.makeSlots(RedstoneLinkFrequencySlot::new); - link = transmitter ? LinkBehaviour.transmitter(this, slots, this::getSignal) - : LinkBehaviour.receiver(this, slots, this::setSignal); - } - - public int getSignal() { - return transmittedSignal; - } - - public void setSignal(int power) { - if (receivedSignal != power) - receivedSignalChanged = true; - receivedSignal = power; - } - - public void transmit(int strength) { - transmittedSignal = strength; - if (link != null) - link.notifySignalChange(); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - compound.putBoolean("Transmitter", transmitter); - compound.putInt("Receive", getReceivedSignal()); - compound.putBoolean("ReceivedChanged", receivedSignalChanged); - compound.putInt("Transmit", transmittedSignal); - super.write(compound, clientPacket); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - transmitter = compound.getBoolean("Transmitter"); - super.read(compound, clientPacket); - - receivedSignal = compound.getInt("Receive"); - receivedSignalChanged = compound.getBoolean("ReceivedChanged"); - if (level == null || level.isClientSide || !link.newPosition) - transmittedSignal = compound.getInt("Transmit"); - } - - @Override - public void tick() { - super.tick(); - - if (isTransmitterBlock() != transmitter) { - transmitter = isTransmitterBlock(); - LinkBehaviour prevlink = link; - removeBehaviour(LinkBehaviour.TYPE); - createLink(); - link.copyItemsFrom(prevlink); - attachBehaviourLate(link); - } - - if (transmitter) - return; - if (level.isClientSide) - return; - - BlockState blockState = getBlockState(); - if (!AllBlocks.REDSTONE_LINK.has(blockState)) - return; - - if ((getReceivedSignal() > 0) != blockState.getValue(RedstoneLinkBlock.POWERED)) { - receivedSignalChanged = true; - level.setBlockAndUpdate(worldPosition, blockState.cycle(RedstoneLinkBlock.POWERED)); - } - - if (receivedSignalChanged) { - Direction attachedFace = blockState.getValue(RedstoneLinkBlock.FACING) - .getOpposite(); - BlockPos attachedPos = worldPosition.relative(attachedFace); - level.blockUpdated(worldPosition, level.getBlockState(worldPosition) - .getBlock()); - level.blockUpdated(attachedPos, level.getBlockState(attachedPos) - .getBlock()); - receivedSignalChanged = false; - } - } - - protected Boolean isTransmitterBlock() { - return !getBlockState().getValue(RedstoneLinkBlock.RECEIVER); - } - - public int getReceivedSignal() { - return receivedSignal; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java deleted file mode 100644 index 7e7250a118..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchBlock.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.Random; - -import com.simibubi.create.AllItems; -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; - -import net.createmod.catnip.gui.ScreenOpener; -import net.createmod.catnip.utility.Iterate; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; - -public class StockpileSwitchBlock extends HorizontalDirectionalBlock - implements ITE, IWrenchable { - - public static final IntegerProperty INDICATOR = IntegerProperty.create("indicator", 0, 6); - - public StockpileSwitchBlock(Properties p_i48377_1_) { - super(p_i48377_1_); - } - - @Override - public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { - updateObservedInventory(state, worldIn, pos); - } - - @Override - public void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbor) { -// if (world.isClientSide()) -// return; -// if (!isObserving(state, pos, neighbor)) -// return; -// updateObservedInventory(state, world, pos); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, - CollisionContext p_220053_4_) { - return AllShapes.STOCKPILE_SWITCH.get(state.getValue(FACING)); - } - - private void updateObservedInventory(BlockState state, LevelReader world, BlockPos pos) { - withTileEntityDo(world, pos, StockpileSwitchTileEntity::updateCurrentLevel); - } - - @Override - public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { - return side != null && side.getOpposite() != state.getValue(FACING); - } - - @Override - public boolean isSignalSource(BlockState state) { - return true; - } - - @Override - public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { - if (side == blockState.getValue(FACING) - .getOpposite()) - return 0; - return getTileEntityOptional(blockAccess, pos).filter(StockpileSwitchTileEntity::isPowered) - .map($ -> 15) - .orElse(0); - } - - @Override - public void tick(BlockState blockState, ServerLevel world, BlockPos pos, Random random) { - getTileEntityOptional(world, pos).ifPresent(StockpileSwitchTileEntity::updatePowerAfterDelay); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(FACING, INDICATOR); - super.createBlockStateDefinition(builder); - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - if (player != null && AllItems.WRENCH.isIn(player.getItemInHand(handIn))) - return InteractionResult.PASS; - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> withTileEntityDo(worldIn, pos, te -> this.displayScreen(te, player))); - return InteractionResult.SUCCESS; - } - - @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(StockpileSwitchTileEntity te, Player player) { - if (player instanceof LocalPlayer) - ScreenOpener.open(new StockpileSwitchScreen(te)); - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext context) { - BlockState state = defaultBlockState(); - Capability itemCap = CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; - Capability fluidCap = CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; - - Direction preferredFacing = null; - for (Direction face : Iterate.horizontalDirections) { - BlockEntity te = context.getLevel() - .getBlockEntity(context.getClickedPos() - .relative(face)); - if (te != null && (te.getCapability(itemCap) - .isPresent() - || te.getCapability(fluidCap) - .isPresent())) - if (preferredFacing == null) - preferredFacing = face; - else { - preferredFacing = null; - break; - } - } - - if (preferredFacing != null) - return state.setValue(FACING, preferredFacing); - - Direction facing = context.getClickedFace() - .getAxis() - .isHorizontal() ? context.getClickedFace() - : context.getHorizontalDirection() - .getOpposite(); - return state.setValue(FACING, context.getPlayer() != null && context.getPlayer() - .isSteppingCarefully() ? facing.getOpposite() : facing); - } - - @Override - public Class getTileEntityClass() { - return StockpileSwitchTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.STOCKPILE_SWITCH.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchObservable.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchObservable.java deleted file mode 100644 index 1c4eff748e..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchObservable.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -public interface StockpileSwitchObservable { - - public float getPercent(); - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java deleted file mode 100644 index 67f6bc9858..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.gui.widget.ScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.gui.AbstractSimiScreen; -import net.createmod.catnip.gui.element.GuiGameElement; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.ItemStack; - -public class StockpileSwitchScreen extends AbstractSimiScreen { - - private ScrollInput offBelow; - private ScrollInput onAbove; - private IconButton confirmButton; - private IconButton flipSignals; - - private final Component invertSignal = CreateLang.translateDirect("gui.stockpile_switch.invert_signal"); - private final ItemStack renderedItem = new ItemStack(AllBlocks.STOCKPILE_SWITCH.get()); - - private AllGuiTextures background; - private StockpileSwitchTileEntity te; - private int lastModification; - - private LerpedFloat cursor; - private LerpedFloat cursorLane; - - public StockpileSwitchScreen(StockpileSwitchTileEntity te) { - super(CreateLang.translateDirect("gui.stockpile_switch.title")); - background = AllGuiTextures.STOCKSWITCH; - this.te = te; - lastModification = -1; - } - - @Override - protected void init() { - setWindowSize(background.getWidth(), background.getHeight()); - setWindowOffset(-20, 0); - super.init(); - - int x = guiLeft; - int y = guiTop; - - cursor = LerpedFloat.linear() - .startWithValue(te.getLevelForDisplay()); - cursorLane = LerpedFloat.linear() - .startWithValue(te.getState() ? 1 : 0); - - offBelow = new ScrollInput(x + 36, y + 40, 102, 18).withRange(0, 100) - .titled(Components.empty()) - .calling(state -> { - lastModification = 0; - offBelow.titled(CreateLang.translateDirect("gui.stockpile_switch.move_to_upper_at", state)); - if (onAbove.getState() <= state) { - onAbove.setState(state + 1); - onAbove.onChanged(); - } - }) - .setState((int) (te.offWhenBelow * 100)); - - onAbove = new ScrollInput(x + 36, y + 18, 102, 18).withRange(1, 101) - .titled(Components.empty()) - .calling(state -> { - lastModification = 0; - onAbove.titled(CreateLang.translateDirect("gui.stockpile_switch.move_to_lower_at", state)); - if (offBelow.getState() >= state) { - offBelow.setState(state - 1); - offBelow.onChanged(); - } - }) - .setState((int) (te.onWhenAbove * 100)); - - onAbove.onChanged(); - offBelow.onChanged(); - - addRenderableWidget(onAbove); - addRenderableWidget(offBelow); - - confirmButton = - new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); - confirmButton.withCallback(() -> { - onClose(); - }); - addRenderableWidget(confirmButton); - - flipSignals = new IconButton(x + 14, y + 40, AllIcons.I_FLIP); - flipSignals.withCallback(() -> { - send(!te.isInverted()); - }); - flipSignals.setToolTip(invertSignal); - addRenderableWidget(flipSignals); - } - - @Override - protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { - int x = guiLeft; - int y = guiTop; - - background.render(ms, x, y, this); - - AllGuiTextures.STOCKSWITCH_POWERED_LANE.render(ms, x + 36, y + (te.isInverted() ? 18 : 40), this); - AllGuiTextures.STOCKSWITCH_UNPOWERED_LANE.render(ms, x + 36, y + (te.isInverted() ? 40 : 18), this); - drawCenteredString(ms, font, title, x + (background.getWidth() - 8) / 2, y + 3, 0xFFFFFF); - - AllGuiTextures sprite = AllGuiTextures.STOCKSWITCH_INTERVAL; - float lowerBound = offBelow.getState(); - float upperBound = onAbove.getState(); - - sprite.bind(); - blit(ms, (int) (x + upperBound) + 37, y + 18, (int) (sprite.getStartX() + upperBound), sprite.getStartY(), - (int) (sprite.getWidth() - upperBound), sprite.getHeight()); - blit(ms, x + 37, y + 40, sprite.getStartX(), sprite.getStartY(), (int) (lowerBound), sprite.getHeight()); - - AllGuiTextures.STOCKSWITCH_ARROW_UP.render(ms, (int) (x + lowerBound + 36) - 2, y + 35, this); - AllGuiTextures.STOCKSWITCH_ARROW_DOWN.render(ms, (int) (x + upperBound + 36) - 3, y + 17, this); - - if (te.currentLevel != -1) { - AllGuiTextures cursor = AllGuiTextures.STOCKSWITCH_CURSOR; - ms.pushPose(); - ms.translate(Math.min(99, this.cursor.getValue(partialTicks) * sprite.getWidth()), - cursorLane.getValue(partialTicks) * 22, 0); - cursor.render(ms, x + 34, y + 19, this); - ms.popPose(); - } - - GuiGameElement.of(renderedItem) - .at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200) - .scale(5) - .render(ms); - } - - @Override - public void tick() { - super.tick(); - - cursor.chase(te.getLevelForDisplay(), 1 / 4f, Chaser.EXP); - cursor.tickChaser(); - cursorLane.chase(te.getState() ? 1 : 0, 1 / 4f, Chaser.EXP); - cursorLane.tickChaser(); - - if (lastModification >= 0) - lastModification++; - - if (lastModification >= 20) { - lastModification = -1; - send(te.isInverted()); - } - } - - @Override - public void removed() { - send(te.isInverted()); - } - - protected void send(boolean invert) { - AllPackets.channel.sendToServer(new ConfigureStockswitchPacket(te.getBlockPos(), offBelow.getState() / 100f, - onAbove.getState() / 100f, invert)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java deleted file mode 100644 index 6a467744d8..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java +++ /dev/null @@ -1,231 +0,0 @@ -package com.simibubi.create.content.logistics.block.redstone; - -import java.util.List; - -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.TankManipulationBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.ticks.TickPriority; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.items.IItemHandler; - -public class StockpileSwitchTileEntity extends SmartTileEntity { - - public float onWhenAbove; - public float offWhenBelow; - public float currentLevel; - private boolean redstoneState; - private boolean inverted; - private boolean poweredAfterDelay; - - private FilteringBehaviour filtering; - private InvManipulationBehaviour observedInventory; - private TankManipulationBehaviour observedTank; - - public StockpileSwitchTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - onWhenAbove = .75f; - offWhenBelow = .25f; - currentLevel = -1; - redstoneState = false; - inverted = false; - poweredAfterDelay = false; - setLazyTickRate(10); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - onWhenAbove = compound.getFloat("OnAbove"); - offWhenBelow = compound.getFloat("OffBelow"); - currentLevel = compound.getFloat("Current"); - redstoneState = compound.getBoolean("Powered"); - inverted = compound.getBoolean("Inverted"); - poweredAfterDelay = compound.getBoolean("PoweredAfterDelay"); - super.read(compound, clientPacket); - } - - protected void writeCommon(CompoundTag compound) { - compound.putFloat("OnAbove", onWhenAbove); - compound.putFloat("OffBelow", offWhenBelow); - compound.putBoolean("Inverted", inverted); - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - writeCommon(compound); - compound.putFloat("Current", currentLevel); - compound.putBoolean("Powered", redstoneState); - compound.putBoolean("PoweredAfterDelay", poweredAfterDelay); - super.write(compound, clientPacket); - } - - @Override - public void writeSafe(CompoundTag compound) { - writeCommon(compound); - super.writeSafe(compound); - } - - public float getStockLevel() { - return currentLevel; - } - - public void updateCurrentLevel() { - boolean changed = false; - float occupied = 0; - float totalSpace = 0; - float prevLevel = currentLevel; - - observedInventory.findNewCapability(); - observedTank.findNewCapability(); - - BlockPos target = worldPosition.relative(getBlockState().getOptionalValue(StockpileSwitchBlock.FACING) - .orElse(Direction.NORTH)); - - if (level.getBlockEntity(target) instanceof StockpileSwitchObservable observable) { - currentLevel = observable.getPercent() / 100f; - - } else if (observedInventory.hasInventory() || observedTank.hasInventory()) { - if (observedInventory.hasInventory()) { - // Item inventory - IItemHandler inv = observedInventory.getInventory(); - for (int slot = 0; slot < inv.getSlots(); slot++) { - ItemStack stackInSlot = inv.getStackInSlot(slot); - int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot)); - int count = stackInSlot.getCount(); - if (space == 0) - continue; - - totalSpace += 1; - if (filtering.test(stackInSlot)) - occupied += count * (1f / space); - } - } - - if (observedTank.hasInventory()) { - // Fluid inventory - IFluidHandler tank = observedTank.getInventory(); - for (int slot = 0; slot < tank.getTanks(); slot++) { - FluidStack stackInSlot = tank.getFluidInTank(slot); - int space = tank.getTankCapacity(slot); - int count = stackInSlot.getAmount(); - if (space == 0) - continue; - - totalSpace += 1; - if (filtering.test(stackInSlot)) - occupied += count * (1f / space); - } - } - - currentLevel = occupied / totalSpace; - - } else { - // No compatible inventories found - if (currentLevel == -1) - return; - level.setBlock(worldPosition, getBlockState().setValue(StockpileSwitchBlock.INDICATOR, 0), 3); - currentLevel = -1; - redstoneState = false; - sendData(); - scheduleBlockTick(); - return; - } - - currentLevel = Mth.clamp(currentLevel, 0, 1); - changed = currentLevel != prevLevel; - - boolean previouslyPowered = redstoneState; - if (redstoneState && currentLevel <= offWhenBelow) - redstoneState = false; - else if (!redstoneState && currentLevel >= onWhenAbove) - redstoneState = true; - boolean update = previouslyPowered != redstoneState; - - int displayLevel = 0; - if (currentLevel > 0) - displayLevel = (int) (currentLevel * 6); - level.setBlock(worldPosition, getBlockState().setValue(StockpileSwitchBlock.INDICATOR, displayLevel), - update ? 3 : 2); - - if (update) - scheduleBlockTick(); - - if (changed || update) { - DisplayLinkBlock.notifyGatherers(level, worldPosition); - notifyUpdate(); - } - } - - protected void scheduleBlockTick() { - Block block = getBlockState().getBlock(); - if (!level.getBlockTicks() - .willTickThisTick(worldPosition, block)) - level.scheduleTick(worldPosition, block, 2, TickPriority.NORMAL); - } - - @Override - public void lazyTick() { - super.lazyTick(); - if (level.isClientSide) - return; - updateCurrentLevel(); - } - - @Override - public void addBehaviours(List behaviours) { - filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot()).moveText(new Vec3(0, 5, 0)) - .withCallback($ -> updateCurrentLevel()); - behaviours.add(filtering); - - InterfaceProvider towardBlockFacing = InterfaceProvider.towardBlockFacing(); - behaviours.add(observedInventory = new InvManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); - behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); - } - - public float getLevelForDisplay() { - return currentLevel == -1 ? 0 : currentLevel; - } - - public boolean getState() { - return redstoneState; - } - - public boolean shouldBePowered() { - return inverted != redstoneState; - } - - public void updatePowerAfterDelay() { - poweredAfterDelay = shouldBePowered(); - level.blockUpdated(worldPosition, getBlockState().getBlock()); - } - - public boolean isPowered() { - return poweredAfterDelay; - } - - public boolean isInverted() { - return inverted; - } - - public void setInverted(boolean inverted) { - if (inverted == this.inverted) - return; - this.inverted = inverted; - updatePowerAfterDelay(); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultTileEntity.java deleted file mode 100644 index 681bf28e80..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultTileEntity.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.simibubi.create.content.logistics.block.vault; - -import java.util.List; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.api.connectivity.ConnectivityHandler; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.IMultiTileContainer; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.CombinedInvWrapper; - -public class ItemVaultTileEntity extends SmartTileEntity implements IMultiTileContainer.Inventory { - - protected LazyOptional itemCapability; - - protected ItemStackHandler inventory; - protected BlockPos controller; - protected BlockPos lastKnownPos; - protected boolean updateConnectivity; - protected int radius; - protected int length; - protected Axis axis; - - public ItemVaultTileEntity(BlockEntityType tileEntityTypeIn, BlockPos pos, BlockState state) { - super(tileEntityTypeIn, pos, state); - - inventory = new ItemStackHandler(AllConfigs.SERVER.logistics.vaultCapacity.get()) { - @Override - protected void onContentsChanged(int slot) { - super.onContentsChanged(slot); - updateComparators(); - } - }; - - itemCapability = LazyOptional.empty(); - radius = 1; - length = 1; - } - - @Override - public void addBehaviours(List behaviours) {} - - protected void updateConnectivity() { - updateConnectivity = false; - if (level.isClientSide()) - return; - if (!isController()) - return; - ConnectivityHandler.formMulti(this); - } - - protected void updateComparators() { - ItemVaultTileEntity controllerTE = getControllerTE(); - if (controllerTE == null) - return; - - BlockPos pos = controllerTE.getBlockPos(); - for (int y = 0; y < controllerTE.radius; y++) { - for (int z = 0; z < (controllerTE.axis == Axis.X ? controllerTE.radius : controllerTE.length); z++) { - for (int x = 0; x < (controllerTE.axis == Axis.Z ? controllerTE.radius : controllerTE.length); x++) { - level.updateNeighbourForOutputSignal(pos.offset(x, y, z), getBlockState().getBlock()); - } - } - } - } - - @Override - public void tick() { - super.tick(); - - if (lastKnownPos == null) - lastKnownPos = getBlockPos(); - else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) { - onPositionChanged(); - return; - } - - if (updateConnectivity) - updateConnectivity(); - } - - @Override - public BlockPos getLastKnownPos() { - return lastKnownPos; - } - - @Override - public boolean isController() { - return controller == null || worldPosition.getX() == controller.getX() - && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); - } - - private void onPositionChanged() { - removeController(true); - lastKnownPos = worldPosition; - } - - @SuppressWarnings("unchecked") - @Override - public ItemVaultTileEntity getControllerTE() { - if (isController()) - return this; - BlockEntity tileEntity = level.getBlockEntity(controller); - if (tileEntity instanceof ItemVaultTileEntity) - return (ItemVaultTileEntity) tileEntity; - return null; - } - - public void removeController(boolean keepContents) { - if (level.isClientSide()) - return; - updateConnectivity = true; - controller = null; - radius = 1; - length = 1; - - BlockState state = getBlockState(); - if (ItemVaultBlock.isVault(state)) { - state = state.setValue(ItemVaultBlock.LARGE, false); - getLevel().setBlock(worldPosition, state, 22); - } - - itemCapability.invalidate(); - setChanged(); - sendData(); - } - - @Override - public void setController(BlockPos controller) { - if (level.isClientSide && !isVirtual()) - return; - if (controller.equals(this.controller)) - return; - this.controller = controller; - itemCapability.invalidate(); - setChanged(); - sendData(); - } - - @Override - public BlockPos getController() { - return isController() ? worldPosition : controller; - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - - BlockPos controllerBefore = controller; - int prevSize = radius; - int prevLength = length; - - updateConnectivity = compound.contains("Uninitialized"); - controller = null; - lastKnownPos = null; - - if (compound.contains("LastKnownPos")) - lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos")); - if (compound.contains("Controller")) - controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); - - if (isController()) { - radius = compound.getInt("Size"); - length = compound.getInt("Length"); - } - - if (!clientPacket) { - inventory.deserializeNBT(compound.getCompound("Inventory")); - return; - } - - boolean changeOfController = - controllerBefore == null ? controller != null : !controllerBefore.equals(controller); - if (hasLevel() && (changeOfController || prevSize != radius || prevLength != length)) - level.setBlocksDirty(getBlockPos(), Blocks.AIR.defaultBlockState(), getBlockState()); - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - if (updateConnectivity) - compound.putBoolean("Uninitialized", true); - if (lastKnownPos != null) - compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos)); - if (!isController()) - compound.put("Controller", NbtUtils.writeBlockPos(controller)); - if (isController()) { - compound.putInt("Size", radius); - compound.putInt("Length", length); - } - - super.write(compound, clientPacket); - - if (!clientPacket) { - compound.putString("StorageType", "CombinedInv"); - compound.put("Inventory", inventory.serializeNBT()); - } - } - - public ItemStackHandler getInventoryOfBlock() { - return inventory; - } - - public void applyInventoryToBlock(ItemStackHandler handler) { - for (int i = 0; i < inventory.getSlots(); i++) - inventory.setStackInSlot(i, i < handler.getSlots() ? handler.getStackInSlot(i) : ItemStack.EMPTY); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) { - initCapability(); - return itemCapability.cast(); - } - return super.getCapability(cap, side); - } - - private void initCapability() { - if (itemCapability.isPresent()) - return; - if (!isController()) { - ItemVaultTileEntity controllerTE = getControllerTE(); - if (controllerTE == null) - return; - controllerTE.initCapability(); - itemCapability = controllerTE.itemCapability; - return; - } - - boolean alongZ = ItemVaultBlock.getVaultBlockAxis(getBlockState()) == Axis.Z; - IItemHandlerModifiable[] invs = new IItemHandlerModifiable[length * radius * radius]; - for (int yOffset = 0; yOffset < length; yOffset++) { - for (int xOffset = 0; xOffset < radius; xOffset++) { - for (int zOffset = 0; zOffset < radius; zOffset++) { - BlockPos vaultPos = alongZ ? worldPosition.offset(xOffset, zOffset, yOffset) - : worldPosition.offset(yOffset, xOffset, zOffset); - ItemVaultTileEntity vaultAt = - ConnectivityHandler.partAt(AllTileEntities.ITEM_VAULT.get(), level, vaultPos); - invs[yOffset * radius * radius + xOffset * radius + zOffset] = - vaultAt != null ? vaultAt.inventory : new ItemStackHandler(); - } - } - } - - CombinedInvWrapper combinedInvWrapper = new CombinedInvWrapper(invs); - itemCapability = LazyOptional.of(() -> combinedInvWrapper); - } - - public static int getMaxLength(int radius) { - return radius * 3; - } - - @Override - public void preventConnectivityUpdate() { updateConnectivity = false; } - - @Override - public void notifyMultiUpdated() { - BlockState state = this.getBlockState(); - if (ItemVaultBlock.isVault(state)) { // safety - level.setBlock(getBlockPos(), state.setValue(ItemVaultBlock.LARGE, radius > 2), 6); - } - itemCapability.invalidate(); - setChanged(); - } - - @Override - public Direction.Axis getMainConnectionAxis() { return getMainAxisOf(this); } - - @Override - public int getMaxLength(Direction.Axis longAxis, int width) { - if (longAxis == Direction.Axis.Y) return getMaxWidth(); - return getMaxLength(width); - } - - @Override - public int getMaxWidth() { - return 3; - } - - @Override - public int getHeight() { return length; } - - @Override - public int getWidth() { return radius; } - - @Override - public void setHeight(int height) { this.length = height; } - - @Override - public void setWidth(int width) { this.radius = width; } - - @Override - public boolean hasInventory() { return true; } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/AbstractChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/chute/AbstractChuteBlock.java new file mode 100644 index 0000000000..dd6b5b2157 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/AbstractChuteBlock.java @@ -0,0 +1,216 @@ +package com.simibubi.create.content.logistics.chute; + +import java.util.Random; +import java.util.function.Consumer; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.IBlockRenderProperties; +import net.minecraftforge.common.util.LazyOptional; + +public abstract class AbstractChuteBlock extends Block implements IWrenchable, IBE { + + public AbstractChuteBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + } + + @OnlyIn(Dist.CLIENT) + public void initializeClient(Consumer consumer) { + consumer.accept(new ReducedDestroyEffects()); + } + + public static boolean isChute(BlockState state) { + return state.getBlock() instanceof AbstractChuteBlock; + } + + public static boolean isOpenChute(BlockState state) { + return isChute(state) && ((AbstractChuteBlock) state.getBlock()).isOpen(state); + } + + public static boolean isTransparentChute(BlockState state) { + return isChute(state) && ((AbstractChuteBlock) state.getBlock()).isTransparent(state); + } + + @Nullable + public static Direction getChuteFacing(BlockState state) { + return !isChute(state) ? null : ((AbstractChuteBlock) state.getBlock()).getFacing(state); + } + + public Direction getFacing(BlockState state) { + return Direction.DOWN; + } + + public boolean isOpen(BlockState state) { + return true; + } + + public boolean isTransparent(BlockState state) { + return false; + } + + @Override + public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { + super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); + AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + if (!(entityIn instanceof ItemEntity)) + return; + if (entityIn.level.isClientSide) + return; + if (!entityIn.isAlive()) + return; + DirectBeltInputBehaviour input = BlockEntityBehaviour.get(entityIn.level, new BlockPos(entityIn.position() + .add(0, 0.5f, 0)).below(), DirectBeltInputBehaviour.TYPE); + if (input == null) + return; + if (!input.canInsertFromSide(Direction.UP)) + return; + + ItemEntity itemEntity = (ItemEntity) entityIn; + ItemStack toInsert = itemEntity.getItem(); + ItemStack remainder = input.handleInsertion(toInsert, Direction.UP, false); + + if (remainder.isEmpty()) + itemEntity.discard(); + if (remainder.getCount() < toInsert.getCount()) + itemEntity.setItem(remainder); + } + + @Override + public void onPlace(BlockState state, Level world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { + withBlockEntityDo(world, pos, ChuteBlockEntity::onAdded); + updateDiagonalNeighbour(state, world, pos); + } + + protected void updateDiagonalNeighbour(BlockState state, Level world, BlockPos pos) { + if (!isChute(state)) + return; + AbstractChuteBlock block = (AbstractChuteBlock) state.getBlock(); + Direction facing = block.getFacing(state); + BlockPos toUpdate = pos.below(); + if (facing.getAxis() + .isHorizontal()) + toUpdate = toUpdate.relative(facing.getOpposite()); + + BlockState stateToUpdate = world.getBlockState(toUpdate); + if (isChute(stateToUpdate) && !world.getBlockTicks() + .hasScheduledTick(toUpdate, stateToUpdate.getBlock())) + world.scheduleTick(toUpdate, stateToUpdate.getBlock(), 1); + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, world, pos, newState); + + if (state.is(newState.getBlock())) + return; + + updateDiagonalNeighbour(state, world, pos); + + for (Direction direction : Iterate.horizontalDirections) { + BlockPos toUpdate = pos.above() + .relative(direction); + BlockState stateToUpdate = world.getBlockState(toUpdate); + if (isChute(stateToUpdate) && !world.getBlockTicks() + .hasScheduledTick(toUpdate, stateToUpdate.getBlock())) + world.scheduleTick(toUpdate, stateToUpdate.getBlock(), 1); + } + } + + @Override + public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRandom) { + BlockState updated = updateChuteState(pState, pLevel.getBlockState(pPos.above()), pLevel, pPos); + if (pState != updated) + pLevel.setBlockAndUpdate(pPos, updated); + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState above, LevelAccessor world, + BlockPos pos, BlockPos p_196271_6_) { + if (direction != Direction.UP) + return state; + return updateChuteState(state, above, world, pos); + } + + @Override + public void neighborChanged(BlockState p_220069_1_, Level world, BlockPos pos, Block p_220069_4_, + BlockPos neighbourPos, boolean p_220069_6_) { + if (pos.below() + .equals(neighbourPos)) + withBlockEntityDo(world, pos, ChuteBlockEntity::blockBelowChanged); + else if (pos.above() + .equals(neighbourPos)) + withBlockEntityDo(world, pos, chute -> chute.capAbove = LazyOptional.empty()); + } + + public abstract BlockState updateChuteState(BlockState state, BlockState above, BlockGetter world, BlockPos pos); + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return ChuteShapes.getShape(p_220053_1_); + } + + @Override + public VoxelShape getCollisionShape(BlockState p_220071_1_, BlockGetter p_220071_2_, BlockPos p_220071_3_, + CollisionContext p_220071_4_) { + return ChuteShapes.getCollisionShape(p_220071_1_); + } + + @Override + public Class getBlockEntityClass() { + return ChuteBlockEntity.class; + } + + @Override + public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult p_225533_6_) { + if (!player.getItemInHand(hand) + .isEmpty()) + return InteractionResult.PASS; + if (world.isClientSide) + return InteractionResult.SUCCESS; + + return onBlockEntityUse(world, pos, be -> { + if (be.item.isEmpty()) + return InteractionResult.PASS; + player.getInventory() + .placeItemBackInInventory(be.item); + be.setItem(ItemStack.EMPTY); + return InteractionResult.SUCCESS; + }); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlock.java new file mode 100644 index 0000000000..75f5b17776 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlock.java @@ -0,0 +1,216 @@ +package com.simibubi.create.content.logistics.chute; + +import java.util.HashMap; +import java.util.Map; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; + +public class ChuteBlock extends AbstractChuteBlock implements ProperWaterloggedBlock { + + public static final Property SHAPE = EnumProperty.create("shape", Shape.class); + public static final DirectionProperty FACING = BlockStateProperties.FACING_HOPPER; + + public ChuteBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + registerDefaultState(defaultBlockState().setValue(SHAPE, Shape.NORMAL) + .setValue(FACING, Direction.DOWN) + .setValue(WATERLOGGED, false)); + } + + public enum Shape implements StringRepresentable { + INTERSECTION, WINDOW, NORMAL, ENCASED; + + @Override + public String getSerializedName() { + return Lang.asId(name()); + } + } + + @Override + public Direction getFacing(BlockState state) { + return state.getValue(FACING); + } + + @Override + public boolean isOpen(BlockState state) { + return state.getValue(FACING) == Direction.DOWN || state.getValue(SHAPE) == Shape.INTERSECTION; + } + + @Override + public boolean isTransparent(BlockState state) { + return state.getValue(SHAPE) == Shape.WINDOW; + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + Shape shape = state.getValue(SHAPE); + boolean down = state.getValue(FACING) == Direction.DOWN; + if (shape == Shape.INTERSECTION) + return InteractionResult.PASS; + Level level = context.getLevel(); + if (level.isClientSide) + return InteractionResult.SUCCESS; + if (shape == Shape.ENCASED) { + level.setBlockAndUpdate(context.getClickedPos(), state.setValue(SHAPE, Shape.NORMAL)); + level.levelEvent(2001, context.getClickedPos(), + Block.getId(AllBlocks.INDUSTRIAL_IRON_BLOCK.getDefaultState())); + return InteractionResult.SUCCESS; + } + if (down) + level.setBlockAndUpdate(context.getClickedPos(), + state.setValue(SHAPE, shape != Shape.NORMAL ? Shape.NORMAL : Shape.WINDOW)); + return InteractionResult.SUCCESS; + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hitResult) { + Shape shape = state.getValue(SHAPE); + if (!AllBlocks.INDUSTRIAL_IRON_BLOCK.isIn(player.getItemInHand(hand))) + return super.use(state, level, pos, player, hand, hitResult); + if (shape == Shape.INTERSECTION || shape == Shape.ENCASED) + return super.use(state, level, pos, player, hand, hitResult); + if (player == null || level.isClientSide) + return InteractionResult.SUCCESS; + + level.setBlockAndUpdate(pos, state.setValue(SHAPE, Shape.ENCASED)); + level.playSound(null, pos, SoundEvents.NETHERITE_BLOCK_HIT, SoundSource.BLOCKS, 0.5f, 1.05f); + return InteractionResult.SUCCESS; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { + BlockState state = withWater(super.getStateForPlacement(ctx), ctx); + Direction face = ctx.getClickedFace(); + if (face.getAxis() + .isHorizontal() && !ctx.isSecondaryUseActive()) { + Level world = ctx.getLevel(); + BlockPos pos = ctx.getClickedPos(); + return updateChuteState(state.setValue(FACING, face), world.getBlockState(pos.above()), world, pos); + } + return state; + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState above, LevelAccessor world, + BlockPos pos, BlockPos p_196271_6_) { + updateWater(world, state, pos); + return super.updateShape(state, direction, above, world, pos, p_196271_6_); + } + + @Override + protected void createBlockStateDefinition(Builder p_206840_1_) { + super.createBlockStateDefinition(p_206840_1_.add(SHAPE, FACING, WATERLOGGED)); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + BlockState above = world.getBlockState(pos.above()); + return !isChute(above) || getChuteFacing(above) == Direction.DOWN; + } + + @Override + public BlockState updateChuteState(BlockState state, BlockState above, BlockGetter world, BlockPos pos) { + if (!(state.getBlock() instanceof ChuteBlock)) + return state; + + Map connections = new HashMap<>(); + int amtConnections = 0; + Direction facing = state.getValue(FACING); + boolean vertical = facing == Direction.DOWN; + + if (!vertical) { + BlockState target = world.getBlockState(pos.below() + .relative(facing.getOpposite())); + if (!isChute(target)) + return state.setValue(FACING, Direction.DOWN) + .setValue(SHAPE, Shape.NORMAL); + } + + for (Direction direction : Iterate.horizontalDirections) { + BlockState diagonalInputChute = world.getBlockState(pos.above() + .relative(direction)); + boolean value = + diagonalInputChute.getBlock() instanceof ChuteBlock && diagonalInputChute.getValue(FACING) == direction; + connections.put(direction, value); + if (value) + amtConnections++; + } + + boolean noConnections = amtConnections == 0; + if (vertical) + return state.setValue(SHAPE, + noConnections ? state.getValue(SHAPE) == Shape.INTERSECTION ? Shape.NORMAL : state.getValue(SHAPE) + : Shape.INTERSECTION); + if (noConnections) + return state.setValue(SHAPE, Shape.INTERSECTION); + if (connections.get(Direction.NORTH) && connections.get(Direction.SOUTH)) + return state.setValue(SHAPE, Shape.INTERSECTION); + if (connections.get(Direction.EAST) && connections.get(Direction.WEST)) + return state.setValue(SHAPE, Shape.INTERSECTION); + if (amtConnections == 1 && connections.get(facing) && !(getChuteFacing(above) == Direction.DOWN) + && !(above.getBlock() instanceof FunnelBlock && FunnelBlock.getFunnelFacing(above) == Direction.DOWN)) + return state.setValue(SHAPE, state.getValue(SHAPE) == Shape.ENCASED ? Shape.ENCASED : Shape.NORMAL); + return state.setValue(SHAPE, Shape.INTERSECTION); + } + + @Override + public BlockState rotate(BlockState pState, Rotation pRot) { + return pState.setValue(FACING, pRot.rotate(pState.getValue(FACING))); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState mirror(BlockState pState, Mirror pMirror) { + return pState.rotate(pMirror.getRotation(pState.getValue(FACING))); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CHUTE.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java new file mode 100644 index 0000000000..b123c156b2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteBlockEntity.java @@ -0,0 +1,790 @@ +package com.simibubi.create.content.logistics.chute; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Predicate; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.fan.AirCurrent; +import com.simibubi.create.content.kinetics.fan.EncasedFanBlock; +import com.simibubi.create.content.kinetics.fan.EncasedFanBlockEntity; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; +import com.simibubi.create.foundation.particle.AirParticleData; +import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.Containers; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +/* + * Commented Code: Chutes create air streams and act similarly to encased fans + * (Unfinished) + */ +public class ChuteBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { // , IAirCurrentSource { + + // public AirCurrent airCurrent; + + float pull; + float push; + + ItemStack item; + LerpedFloat itemPosition; + ChuteItemHandler itemHandler; + LazyOptional lazyHandler; + boolean canPickUpItems; + + float bottomPullDistance; + float beltBelowOffset; + TransportedItemStackHandlerBehaviour beltBelow; + boolean updateAirFlow; + int airCurrentUpdateCooldown; + int entitySearchCooldown; + + LazyOptional capAbove; + LazyOptional capBelow; + + public ChuteBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + item = ItemStack.EMPTY; + itemPosition = LerpedFloat.linear(); + itemHandler = new ChuteItemHandler(this); + lazyHandler = LazyOptional.of(() -> itemHandler); + canPickUpItems = false; + capAbove = LazyOptional.empty(); + capBelow = LazyOptional.empty(); + bottomPullDistance = 0; + // airCurrent = new AirCurrent(this); + updateAirFlow = true; + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen((d) -> canDirectlyInsertCached())); + registerAwardables(behaviours, AllAdvancements.CHUTE); + } + + // Cached per-tick, useful when a lot of items are waiting on top of it + public boolean canDirectlyInsertCached() { + return canPickUpItems; + } + + private boolean canDirectlyInsert() { + BlockState blockState = getBlockState(); + BlockState blockStateAbove = level.getBlockState(worldPosition.above()); + if (!AbstractChuteBlock.isChute(blockState)) + return false; + if (AbstractChuteBlock.getChuteFacing(blockStateAbove) == Direction.DOWN) + return false; + if (getItemMotion() > 0 && getInputChutes().isEmpty()) + return false; + return AbstractChuteBlock.isOpenChute(blockState); + } + + @Override + public void initialize() { + super.initialize(); + onAdded(); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition).expandTowards(0, -3, 0); + } + + @Override + public void tick() { + super.tick(); + + if (!level.isClientSide) + canPickUpItems = canDirectlyInsert(); + + boolean clientSide = level != null && level.isClientSide && !isVirtual(); + float itemMotion = getItemMotion(); + if (itemMotion != 0 && level != null && level.isClientSide) + spawnParticles(itemMotion); + tickAirStreams(itemMotion); + + if (item.isEmpty() && !clientSide) { + if (itemMotion < 0) + handleInputFromAbove(); + if (itemMotion > 0) + handleInputFromBelow(); + return; + } + + float nextOffset = itemPosition.getValue() + itemMotion; + + if (itemMotion < 0) { + if (nextOffset < .5f) { + if (!handleDownwardOutput(true)) + nextOffset = .5f; + else if (nextOffset < 0) { + handleDownwardOutput(clientSide); + nextOffset = itemPosition.getValue(); + } + } + } else if (itemMotion > 0) { + if (nextOffset > .5f) { + if (!handleUpwardOutput(true)) + nextOffset = .5f; + else if (nextOffset > 1) { + handleUpwardOutput(clientSide); + nextOffset = itemPosition.getValue(); + } + } + } + + itemPosition.setValue(nextOffset); + } + + private void updateAirFlow(float itemSpeed) { + updateAirFlow = false; + // airCurrent.rebuild(); + if (itemSpeed > 0 && level != null && !level.isClientSide) { + float speed = pull - push; + beltBelow = null; + + float maxPullDistance; + if (speed >= 128) + maxPullDistance = 3; + else if (speed >= 64) + maxPullDistance = 2; + else if (speed >= 32) + maxPullDistance = 1; + else + maxPullDistance = Mth.lerp(speed / 32, 0, 1); + + if (AbstractChuteBlock.isChute(level.getBlockState(worldPosition.below()))) + maxPullDistance = 0; + float flowLimit = maxPullDistance; + if (flowLimit > 0) + flowLimit = AirCurrent.getFlowLimit(level, worldPosition, maxPullDistance, Direction.DOWN); + + for (int i = 1; i <= flowLimit + 1; i++) { + TransportedItemStackHandlerBehaviour behaviour = + BlockEntityBehaviour.get(level, worldPosition.below(i), TransportedItemStackHandlerBehaviour.TYPE); + if (behaviour == null) + continue; + beltBelow = behaviour; + beltBelowOffset = i - 1; + break; + } + this.bottomPullDistance = Math.max(0, flowLimit); + } + sendData(); + } + + private void findEntities(float itemSpeed) { + // if (getSpeed() != 0) + // airCurrent.findEntities(); + if (bottomPullDistance <= 0 && !getItem().isEmpty() || itemSpeed <= 0 || level == null || level.isClientSide) + return; + if (!canCollectItemsFromBelow()) + return; + Vec3 center = VecHelper.getCenterOf(worldPosition); + AABB searchArea = new AABB(center.add(0, -bottomPullDistance - 0.5, 0), center.add(0, -0.5, 0)).inflate(.45f); + for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, searchArea)) { + if (!itemEntity.isAlive()) + continue; + ItemStack entityItem = itemEntity.getItem(); + if (!canAcceptItem(entityItem)) + continue; + setItem(entityItem.copy(), (float) (itemEntity.getBoundingBox() + .getCenter().y - worldPosition.getY())); + itemEntity.discard(); + break; + } + } + + private void extractFromBelt(float itemSpeed) { + if (itemSpeed <= 0 || level == null || level.isClientSide) + return; + if (getItem().isEmpty() && beltBelow != null) { + beltBelow.handleCenteredProcessingOnAllItems(.5f, ts -> { + if (canAcceptItem(ts.stack)) { + setItem(ts.stack.copy(), -beltBelowOffset); + return TransportedResult.removeItem(); + } + return TransportedResult.doNothing(); + }); + } + } + + private void tickAirStreams(float itemSpeed) { + if (!level.isClientSide && airCurrentUpdateCooldown-- <= 0) { + airCurrentUpdateCooldown = AllConfigs.server().kinetics.fanBlockCheckRate.get(); + updateAirFlow = true; + } + + if (updateAirFlow) { + updateAirFlow(itemSpeed); + } + + if (entitySearchCooldown-- <= 0 && item.isEmpty()) { + entitySearchCooldown = 5; + findEntities(itemSpeed); + } + + extractFromBelt(itemSpeed); + // if (getSpeed() != 0) + // airCurrent.tick(); + } + + public void blockBelowChanged() { + updateAirFlow = true; + capBelow = LazyOptional.empty(); + } + + private void spawnParticles(float itemMotion) { + // todo: reduce the amount of particles + if (level == null) + return; + BlockState blockState = getBlockState(); + boolean up = itemMotion > 0; + float absMotion = up ? itemMotion : -itemMotion; + if (blockState == null || !AbstractChuteBlock.isChute(blockState)) + return; + if (push == 0 && pull == 0) + return; + + if (up && AbstractChuteBlock.isOpenChute(blockState) + && BlockHelper.noCollisionInSpace(level, worldPosition.above())) + spawnAirFlow(1, 2, absMotion, .5f); + + if (AbstractChuteBlock.getChuteFacing(blockState) != Direction.DOWN) + return; + + if (AbstractChuteBlock.isTransparentChute(blockState)) + spawnAirFlow(up ? 0 : 1, up ? 1 : 0, absMotion, 1); + + if (!up && BlockHelper.noCollisionInSpace(level, worldPosition.below())) + spawnAirFlow(0, -1, absMotion, .5f); + + if (up && canCollectItemsFromBelow() && bottomPullDistance > 0) { + spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); + spawnAirFlow(-bottomPullDistance, 0, absMotion, 2); + } + } + + private void spawnAirFlow(float verticalStart, float verticalEnd, float motion, float drag) { + if (level == null) + return; + AirParticleData airParticleData = new AirParticleData(drag, motion); + Vec3 origin = Vec3.atLowerCornerOf(worldPosition); + float xOff = Create.RANDOM.nextFloat() * .5f + .25f; + float zOff = Create.RANDOM.nextFloat() * .5f + .25f; + Vec3 v = origin.add(xOff, verticalStart, zOff); + Vec3 d = origin.add(xOff, verticalEnd, zOff) + .subtract(v); + if (Create.RANDOM.nextFloat() < 2 * motion) + level.addAlwaysVisibleParticle(airParticleData, v.x, v.y, v.z, d.x, d.y, d.z); + } + + private void handleInputFromAbove() { + if (!capAbove.isPresent()) + capAbove = grabCapability(Direction.UP); + handleInput(capAbove.orElse(null), 1); + } + + private void handleInputFromBelow() { + if (!capBelow.isPresent()) + capBelow = grabCapability(Direction.DOWN); + handleInput(capBelow.orElse(null), 0); + } + + private void handleInput(IItemHandler inv, float startLocation) { + if (inv == null) + return; + Predicate canAccept = this::canAcceptItem; + int count = getExtractionAmount(); + ExtractionCountMode mode = getExtractionMode(); + if (mode == ExtractionCountMode.UPTO || !ItemHelper.extract(inv, canAccept, mode, count, true) + .isEmpty()) { + ItemStack extracted = ItemHelper.extract(inv, canAccept, mode, count, false); + if (!extracted.isEmpty()) + setItem(extracted, startLocation); + } + } + + private boolean handleDownwardOutput(boolean simulate) { + BlockState blockState = getBlockState(); + ChuteBlockEntity targetChute = getTargetChute(blockState); + Direction direction = AbstractChuteBlock.getChuteFacing(blockState); + + if (level == null || direction == null || !this.canOutputItems()) + return false; + if (!capBelow.isPresent()) + capBelow = grabCapability(Direction.DOWN); + if (capBelow.isPresent()) { + if (level.isClientSide && !isVirtual()) + return false; + ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate); + ItemStack held = getItem(); + if (!simulate) + setItem(remainder, itemPosition.getValue(0)); + if (remainder.getCount() != held.getCount()) + return true; + if (direction == Direction.DOWN) + return false; + } + + if (targetChute != null) { + boolean canInsert = targetChute.canAcceptItem(item); + if (!simulate && canInsert) { + targetChute.setItem(item, direction == Direction.DOWN ? 1 : .51f); + setItem(ItemStack.EMPTY); + } + return canInsert; + } + + // Diagonal chutes cannot drop items + if (direction.getAxis() + .isHorizontal()) + return false; + + if (FunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.below())) == Direction.DOWN) + return false; + if (Block.canSupportRigidBlock(level, worldPosition.below())) + return false; + + if (!simulate) { + Vec3 dropVec = VecHelper.getCenterOf(worldPosition) + .add(0, -12 / 16f, 0); + ItemEntity dropped = new ItemEntity(level, dropVec.x, dropVec.y, dropVec.z, item.copy()); + dropped.setDefaultPickUpDelay(); + dropped.setDeltaMovement(0, -.25f, 0); + level.addFreshEntity(dropped); + setItem(ItemStack.EMPTY); + } + + return true; + } + + private boolean handleUpwardOutput(boolean simulate) { + BlockState stateAbove = level.getBlockState(worldPosition.above()); + + if (level == null || !this.canOutputItems()) + return false; + + if (AbstractChuteBlock.isOpenChute(getBlockState())) { + if (!capAbove.isPresent()) + capAbove = grabCapability(Direction.UP); + if (capAbove.isPresent()) { + if (level.isClientSide && !isVirtual() && !ChuteBlock.isChute(stateAbove)) + return false; + int countBefore = item.getCount(); + ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate); + if (!simulate) + item = remainder; + return countBefore != remainder.getCount(); + } + } + + ChuteBlockEntity bestOutput = null; + List inputChutes = getInputChutes(); + for (ChuteBlockEntity targetChute : inputChutes) { + if (!targetChute.canAcceptItem(item)) + continue; + float itemMotion = targetChute.getItemMotion(); + if (itemMotion < 0) + continue; + if (bestOutput == null || bestOutput.getItemMotion() < itemMotion) { + bestOutput = targetChute; + } + } + + if (bestOutput != null) { + if (!simulate) { + bestOutput.setItem(item, 0); + setItem(ItemStack.EMPTY); + } + return true; + } + + if (FunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == Direction.UP) + return false; + if (BlockHelper.hasBlockSolidSide(stateAbove, level, worldPosition.above(), Direction.DOWN)) + return false; + if (!inputChutes.isEmpty()) + return false; + + if (!simulate) { + Vec3 dropVec = VecHelper.getCenterOf(worldPosition) + .add(0, 8 / 16f, 0); + ItemEntity dropped = new ItemEntity(level, dropVec.x, dropVec.y, dropVec.z, item.copy()); + dropped.setDefaultPickUpDelay(); + dropped.setDeltaMovement(0, getItemMotion() * 2, 0); + level.addFreshEntity(dropped); + setItem(ItemStack.EMPTY); + } + return true; + } + + protected boolean canAcceptItem(ItemStack stack) { + return item.isEmpty(); + } + + protected int getExtractionAmount() { + return 16; + } + + protected ExtractionCountMode getExtractionMode() { + return ExtractionCountMode.UPTO; + } + + protected boolean canCollectItemsFromBelow() { + return true; + } + + protected boolean canOutputItems() { + return true; + } + + private LazyOptional grabCapability(Direction side) { + BlockPos pos = this.worldPosition.relative(side); + if (level == null) + return LazyOptional.empty(); + BlockEntity be = level.getBlockEntity(pos); + if (be == null) + return LazyOptional.empty(); + if (be instanceof ChuteBlockEntity) { + if (side != Direction.DOWN || !(be instanceof SmartChuteBlockEntity) || getItemMotion() > 0) + return LazyOptional.empty(); + } + return be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side.getOpposite()); + } + + public void setItem(ItemStack stack) { + setItem(stack, getItemMotion() < 0 ? 1 : 0); + } + + public void setItem(ItemStack stack, float insertionPos) { + item = stack; + itemPosition.startWithValue(insertionPos); + if (!level.isClientSide) { + notifyUpdate(); + award(AllAdvancements.CHUTE); + } + } + + @Override + public void invalidate() { + if (lazyHandler != null) + lazyHandler.invalidate(); + super.invalidate(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.put("Item", item.serializeNBT()); + compound.putFloat("ItemPosition", itemPosition.getValue()); + compound.putFloat("Pull", pull); + compound.putFloat("Push", push); + compound.putFloat("BottomAirFlowDistance", bottomPullDistance); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + ItemStack previousItem = item; + item = ItemStack.of(compound.getCompound("Item")); + itemPosition.startWithValue(compound.getFloat("ItemPosition")); + pull = compound.getFloat("Pull"); + push = compound.getFloat("Push"); + bottomPullDistance = compound.getFloat("BottomAirFlowDistance"); + super.read(compound, clientPacket); +// if (clientPacket) +// airCurrent.rebuild(); + + if (hasLevel() && level != null && level.isClientSide && !previousItem.equals(item, false) && !item.isEmpty()) { + if (level.random.nextInt(3) != 0) + return; + Vec3 p = VecHelper.getCenterOf(worldPosition); + p = VecHelper.offsetRandomly(p, level.random, .5f); + Vec3 m = Vec3.ZERO; + level.addParticle(new ItemParticleOption(ParticleTypes.ITEM, item), p.x, p.y, p.z, m.x, m.y, m.z); + } + } + + public float getItemMotion() { + // Chutes per second + final float fanSpeedModifier = 1 / 64f; + final float maxItemSpeed = 20f; + final float gravity = 4f; + + float motion = (push + pull) * fanSpeedModifier; + return (Mth.clamp(motion, -maxItemSpeed, maxItemSpeed) + (motion <= 0 ? -gravity : 0)) / 20f; + } + + @Override + public void destroy() { + super.destroy(); + ChuteBlockEntity targetChute = getTargetChute(getBlockState()); + List inputChutes = getInputChutes(); + if (!item.isEmpty() && level != null) + Containers.dropItemStack(level, worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), item); + setRemoved(); + if (targetChute != null) { + targetChute.updatePull(); + targetChute.propagatePush(); + } + inputChutes.forEach(c -> c.updatePush(inputChutes.size())); + } + + public void onAdded() { + refreshBlockState(); + updatePull(); + ChuteBlockEntity targetChute = getTargetChute(getBlockState()); + if (targetChute != null) + targetChute.propagatePush(); + else + updatePush(1); + } + + public void updatePull() { + float totalPull = calculatePull(); + if (pull == totalPull) + return; + pull = totalPull; + updateAirFlow = true; + sendData(); + ChuteBlockEntity targetChute = getTargetChute(getBlockState()); + if (targetChute != null) + targetChute.updatePull(); + } + + public void updatePush(int branchCount) { + float totalPush = calculatePush(branchCount); + if (push == totalPush) + return; + updateAirFlow = true; + push = totalPush; + sendData(); + propagatePush(); + } + + public void propagatePush() { + List inputs = getInputChutes(); + inputs.forEach(c -> c.updatePush(inputs.size())); + } + + protected float calculatePull() { + BlockState blockStateAbove = level.getBlockState(worldPosition.above()); + if (AllBlocks.ENCASED_FAN.has(blockStateAbove) + && blockStateAbove.getValue(EncasedFanBlock.FACING) == Direction.DOWN) { + BlockEntity be = level.getBlockEntity(worldPosition.above()); + if (be instanceof EncasedFanBlockEntity && !be.isRemoved()) { + EncasedFanBlockEntity fan = (EncasedFanBlockEntity) be; + return fan.getSpeed(); + } + } + + float totalPull = 0; + for (Direction d : Iterate.directions) { + ChuteBlockEntity inputChute = getInputChute(d); + if (inputChute == null) + continue; + totalPull += inputChute.pull; + } + return totalPull; + } + + protected float calculatePush(int branchCount) { + if (level == null) + return 0; + BlockState blockStateBelow = level.getBlockState(worldPosition.below()); + if (AllBlocks.ENCASED_FAN.has(blockStateBelow) + && blockStateBelow.getValue(EncasedFanBlock.FACING) == Direction.UP) { + BlockEntity be = level.getBlockEntity(worldPosition.below()); + if (be instanceof EncasedFanBlockEntity && !be.isRemoved()) { + EncasedFanBlockEntity fan = (EncasedFanBlockEntity) be; + return fan.getSpeed(); + } + } + + ChuteBlockEntity targetChute = getTargetChute(getBlockState()); + if (targetChute == null) + return 0; + return targetChute.push / branchCount; + } + + @Nullable + private ChuteBlockEntity getTargetChute(BlockState state) { + if (level == null) + return null; + Direction targetDirection = AbstractChuteBlock.getChuteFacing(state); + if (targetDirection == null) + return null; + BlockPos chutePos = worldPosition.below(); + if (targetDirection.getAxis() + .isHorizontal()) + chutePos = chutePos.relative(targetDirection.getOpposite()); + BlockState chuteState = level.getBlockState(chutePos); + if (!AbstractChuteBlock.isChute(chuteState)) + return null; + BlockEntity be = level.getBlockEntity(chutePos); + if (be instanceof ChuteBlockEntity) + return (ChuteBlockEntity) be; + return null; + } + + private List getInputChutes() { + List inputs = new LinkedList<>(); + for (Direction d : Iterate.directions) { + ChuteBlockEntity inputChute = getInputChute(d); + if (inputChute == null) + continue; + inputs.add(inputChute); + } + return inputs; + } + + @Nullable + private ChuteBlockEntity getInputChute(Direction direction) { + if (level == null || direction == Direction.DOWN) + return null; + direction = direction.getOpposite(); + BlockPos chutePos = worldPosition.above(); + if (direction.getAxis() + .isHorizontal()) + chutePos = chutePos.relative(direction); + BlockState chuteState = level.getBlockState(chutePos); + Direction chuteFacing = AbstractChuteBlock.getChuteFacing(chuteState); + if (chuteFacing != direction) + return null; + BlockEntity be = level.getBlockEntity(chutePos); + if (be instanceof ChuteBlockEntity && !be.isRemoved()) + return (ChuteBlockEntity) be; + return null; + } + + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + boolean downward = getItemMotion() < 0; + CreateLang.translate("tooltip.chute.header") + .forGoggles(tooltip); + + if (pull == 0 && push == 0) + CreateLang.translate("tooltip.chute.no_fans_attached") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + if (pull != 0) + CreateLang.translate("tooltip.chute.fans_" + (pull > 0 ? "pull_up" : "push_down")) + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + if (push != 0) + CreateLang.translate("tooltip.chute.fans_" + (push > 0 ? "push_up" : "pull_down")) + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + CreateLang.text("-> ") + .add(CreateLang.translate("tooltip.chute.items_move_" + (downward ? "down" : "up"))) + .style(ChatFormatting.YELLOW) + .forGoggles(tooltip); + if (!item.isEmpty()) + CreateLang.translate("tooltip.chute.contains", Components.translatable(item.getDescriptionId()) + .getString(), item.getCount()) + .style(ChatFormatting.GREEN) + .forGoggles(tooltip); + + return true; + } + + @Override + public LazyOptional getCapability(Capability cap, @Nullable Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return lazyHandler.cast(); + return super.getCapability(cap, side); + } + + public ItemStack getItem() { + return item; + } + + // @Override + // @Nullable + // public AirCurrent getAirCurrent() { + // return airCurrent; + // } + // + // @Nullable + // @Override + // public World getAirCurrentWorld() { + // return world; + // } + // + // @Override + // public BlockPos getAirCurrentPos() { + // return pos; + // } + // + // @Override + // public float getSpeed() { + // if (getBlockState().get(ChuteBlock.SHAPE) == Shape.NORMAL && + // getBlockState().get(ChuteBlock.FACING) != Direction.DOWN) + // return 0; + // return pull + push; + // } + // + // @Override + // @Nullable + // public Direction getAirFlowDirection() { + // float speed = getSpeed(); + // if (speed == 0) + // return null; + // return speed > 0 ? Direction.UP : Direction.DOWN; + // } + // + // @Override + // public boolean isSourceRemoved() { + // return removed; + // } + // + // @Override + // public Direction getAirflowOriginSide() { + // return world != null && !(world.getBlockEntity(pos.down()) instanceof + // IAirCurrentSource) + // && getBlockState().get(ChuteBlock.FACING) == Direction.DOWN ? Direction.DOWN + // : Direction.UP; + // } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteGenerator.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteGenerator.java similarity index 75% rename from src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteGenerator.java rename to src/main/java/com/simibubi/create/content/logistics/chute/ChuteGenerator.java index a7e637f1e0..6c7098f237 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteGenerator.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteGenerator.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.chute; +package com.simibubi.create.content.logistics.chute; -import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape; +import com.simibubi.create.content.logistics.chute.ChuteBlock.Shape; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; @@ -31,10 +31,12 @@ public class ChuteGenerator extends SpecialBlockStateGen { if (!horizontal) return shape == Shape.NORMAL ? AssetLookup.partialBaseModel(ctx, prov) - : shape == Shape.INTERSECTION ? AssetLookup.partialBaseModel(ctx, prov, "intersection") + : shape == Shape.INTERSECTION || shape == Shape.ENCASED + ? AssetLookup.partialBaseModel(ctx, prov, "intersection") : AssetLookup.partialBaseModel(ctx, prov, "windowed"); return shape == Shape.INTERSECTION ? AssetLookup.partialBaseModel(ctx, prov, "diagonal", "intersection") - : AssetLookup.partialBaseModel(ctx, prov, "diagonal"); + : shape == Shape.ENCASED ? AssetLookup.partialBaseModel(ctx, prov, "diagonal", "encased") + : AssetLookup.partialBaseModel(ctx, prov, "diagonal"); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItem.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteItem.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItem.java rename to src/main/java/com/simibubi/create/content/logistics/chute/ChuteItem.java index 926e4b1472..0ece9042e4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteItem.java @@ -1,4 +1,6 @@ -package com.simibubi.create.content.logistics.block.chute; +package com.simibubi.create.content.logistics.chute; + +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -41,8 +43,11 @@ public class ChuteItem extends BlockItem { return InteractionResult.FAIL; AbstractChuteBlock block = (AbstractChuteBlock) blockState.getBlock(); if (block.getFacing(blockState) == Direction.DOWN) { - world.setBlockAndUpdate(correctPos, block.updateChuteState(blockState.setValue(ChuteBlock.FACING, face), - world.getBlockState(correctPos.above()), world, correctPos)); + world.setBlockAndUpdate(correctPos, + ProperWaterloggedBlock.withWater(world, + block.updateChuteState(blockState.setValue(ChuteBlock.FACING, face), + world.getBlockState(correctPos.above()), world, correctPos), + correctPos)); return InteractionResult.SUCCESS; } return InteractionResult.FAIL; diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteItemHandler.java new file mode 100644 index 0000000000..72a77ff019 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteItemHandler.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.logistics.chute; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +public class ChuteItemHandler implements IItemHandler { + + private ChuteBlockEntity blockEntity; + + public ChuteItemHandler(ChuteBlockEntity be) { + this.blockEntity = be; + } + + @Override + public int getSlots() { + return 1; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return blockEntity.item; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (!blockEntity.canAcceptItem(stack)) + return stack; + if (!simulate) + blockEntity.setItem(stack); + return ItemStack.EMPTY; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + ItemStack remainder = blockEntity.item.copy(); + ItemStack split = remainder.split(amount); + if (!simulate) + blockEntity.setItem(remainder); + return split; + } + + @Override + public int getSlotLimit(int slot) { + return Math.min(64, getStackInSlot(slot).getMaxStackSize()); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/ChuteRenderer.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteRenderer.java new file mode 100644 index 0000000000..c04a44e1c9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteRenderer.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.logistics.chute; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.logistics.chute.ChuteBlock.Shape; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; + +public class ChuteRenderer extends SafeBlockEntityRenderer { + + public ChuteRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(ChuteBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + if (be.item.isEmpty()) + return; + BlockState blockState = be.getBlockState(); + if (blockState.getValue(ChuteBlock.FACING) != Direction.DOWN) + return; + if (blockState.getValue(ChuteBlock.SHAPE) != Shape.WINDOW + && (be.bottomPullDistance == 0 || be.itemPosition.getValue(partialTicks) > .5f)) + return; + + renderItem(be, partialTicks, ms, buffer, light, overlay); + } + + public static void renderItem(ChuteBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + TransformStack msr = TransformStack.cast(ms); + ms.pushPose(); + msr.centre(); + float itemScale = .5f; + float itemPosition = be.itemPosition.getValue(partialTicks); + ms.translate(0, -.5 + itemPosition, 0); + ms.scale(itemScale, itemScale, itemScale); + msr.rotateX(itemPosition * 180); + msr.rotateY(itemPosition * 180); + itemRenderer.renderStatic(be.item, TransformType.FIXED, light, overlay, ms, buffer, 0); + ms.popPose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteShapes.java b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteShapes.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteShapes.java rename to src/main/java/com/simibubi/create/content/logistics/chute/ChuteShapes.java index 9a34c9018a..6d6735a41f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteShapes.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/ChuteShapes.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.block.chute; +package com.simibubi.create.content.logistics.chute; import java.util.HashMap; import java.util.Map; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape; +import com.simibubi.create.content.logistics.chute.ChuteBlock.Shape; import net.minecraft.core.Direction; import net.minecraft.world.level.block.Block; @@ -24,12 +24,12 @@ public class ChuteShapes { public static VoxelShape createShape(BlockState state) { if (AllBlocks.SMART_CHUTE.has(state)) - return AllShapes.SMART_CHUTE; + return Shapes.block(); Direction direction = state.getValue(ChuteBlock.FACING); Shape shape = state.getValue(ChuteBlock.SHAPE); - boolean intersection = shape == Shape.INTERSECTION; + boolean intersection = shape == Shape.INTERSECTION || shape == Shape.ENCASED; if (direction == Direction.DOWN) return intersection ? Shapes.block() : AllShapes.CHUTE; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteBlock.java b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlock.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteBlock.java rename to src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlock.java index 92f23a34cb..6fc6fc7a50 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlock.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.chute; +package com.simibubi.create.content.logistics.chute; import java.util.Random; -import com.simibubi.create.AllTileEntities; +import com.simibubi.create.AllBlockEntityTypes; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; @@ -56,8 +56,8 @@ public class SmartChuteBlock extends AbstractChuteBlock { } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SMART_CHUTE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SMART_CHUTE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java new file mode 100644 index 0000000000..0ac591938c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteBlockEntity.java @@ -0,0 +1,66 @@ +package com.simibubi.create.content.logistics.chute; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class SmartChuteBlockEntity extends ChuteBlockEntity { + + FilteringBehaviour filtering; + + public SmartChuteBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected boolean canAcceptItem(ItemStack stack) { + return super.canAcceptItem(stack) && canCollectItemsFromBelow() && filtering.test(stack); + } + + @Override + protected int getExtractionAmount() { + return filtering.isCountVisible() && !filtering.anyAmount() ? filtering.getAmount() : 64; + } + + @Override + protected ExtractionCountMode getExtractionMode() { + return filtering.isCountVisible() && !filtering.anyAmount() && !filtering.upTo ? ExtractionCountMode.EXACTLY + : ExtractionCountMode.UPTO; + } + + @Override + protected boolean canCollectItemsFromBelow() { + BlockState blockState = getBlockState(); + return blockState.hasProperty(SmartChuteBlock.POWERED) && !blockState.getValue(SmartChuteBlock.POWERED); + } + + @Override + protected boolean canOutputItems() { + BlockState blockState = getBlockState(); + return blockState.hasProperty(SmartChuteBlock.POWERED) && !blockState.getValue(SmartChuteBlock.POWERED); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = + new FilteringBehaviour(this, new SmartChuteFilterSlotPositioning()).showCountWhen(this::isExtracting)); + super.addBehaviours(behaviours); + } + + private boolean isExtracting() { + boolean up = getItemMotion() < 0; + BlockPos chutePos = worldPosition.relative(up ? Direction.UP : Direction.DOWN); + BlockState blockState = level.getBlockState(chutePos); + return !AbstractChuteBlock.isChute(blockState) && !blockState.getMaterial() + .isReplaceable(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteFilterSlotPositioning.java b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteFilterSlotPositioning.java similarity index 75% rename from src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteFilterSlotPositioning.java rename to src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteFilterSlotPositioning.java index 6d8682a2cf..0828021158 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/SmartChuteFilterSlotPositioning.java +++ b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteFilterSlotPositioning.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.chute; +package com.simibubi.create.content.logistics.chute; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; @@ -12,10 +12,10 @@ import net.minecraft.world.phys.Vec3; public class SmartChuteFilterSlotPositioning extends ValueBoxTransform.Sided { @Override - protected Vec3 getLocalOffset(BlockState state) { + public Vec3 getLocalOffset(BlockState state) { Direction side = getSide(); float horizontalAngle = AngleHelper.horizontalAngle(side); - Vec3 southLocation = VecHelper.voxelSpace(8, 12, 15.5f); + Vec3 southLocation = VecHelper.voxelSpace(8, 11, 15.5f); return VecHelper.rotateCentered(southLocation, horizontalAngle, Axis.Y); } diff --git a/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteRenderer.java b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteRenderer.java new file mode 100644 index 0000000000..f34bcecbd2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/chute/SmartChuteRenderer.java @@ -0,0 +1,26 @@ +package com.simibubi.create.content.logistics.chute; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; + +public class SmartChuteRenderer extends SmartBlockEntityRenderer { + + public SmartChuteRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(SmartChuteBlockEntity blockEntity, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + super.renderSafe(blockEntity, partialTicks, ms, buffer, light, overlay); + if (blockEntity.item.isEmpty()) + return; + if (blockEntity.itemPosition.getValue(partialTicks) > 0) + return; + ChuteRenderer.renderItem(blockEntity, partialTicks, ms, buffer, light, overlay); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/BottomlessItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/crate/BottomlessItemHandler.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/inventories/BottomlessItemHandler.java rename to src/main/java/com/simibubi/create/content/logistics/crate/BottomlessItemHandler.java index 1df0af6a2e..6a2adf1db3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/BottomlessItemHandler.java +++ b/src/main/java/com/simibubi/create/content/logistics/crate/BottomlessItemHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.inventories; +package com.simibubi.create.content.logistics.crate; import java.util.function.Supplier; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateBlock.java b/src/main/java/com/simibubi/create/content/logistics/crate/CrateBlock.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateBlock.java rename to src/main/java/com/simibubi/create/content/logistics/crate/CrateBlock.java index 6550f3bc6b..ce54c2f77c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/CrateBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/crate/CrateBlock.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.logistics.block.inventories; +package com.simibubi.create.content.logistics.crate; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/logistics/crate/CrateBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/crate/CrateBlockEntity.java new file mode 100644 index 0000000000..9a7e2ccea9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/crate/CrateBlockEntity.java @@ -0,0 +1,21 @@ +package com.simibubi.create.content.logistics.crate; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class CrateBlockEntity extends SmartBlockEntity { + + public CrateBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) {} + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlock.java b/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlock.java new file mode 100644 index 0000000000..a436839ecd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlock.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.logistics.crate; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.world.level.block.entity.BlockEntityType; + +public class CreativeCrateBlock extends CrateBlock implements IBE { + + public CreativeCrateBlock(Properties p_i48415_1_) { + super(p_i48415_1_); + } + + @Override + public Class getBlockEntityClass() { + return CreativeCrateBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.CREATIVE_CRATE.get(); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlockEntity.java new file mode 100644 index 0000000000..3ee12fc5d3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/crate/CreativeCrateBlockEntity.java @@ -0,0 +1,75 @@ +package com.simibubi.create.content.logistics.crate; + +import java.util.List; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class CreativeCrateBlockEntity extends CrateBlockEntity { + + public CreativeCrateBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inv = new BottomlessItemHandler(filtering::getFilter); + itemHandler = LazyOptional.of(() -> inv); + } + + FilteringBehaviour filtering; + LazyOptional itemHandler; + private BottomlessItemHandler inv; + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = createFilter()); + filtering.setLabel(CreateLang.translateDirect("logistics.creative_crate.supply")); + } + + @Override + public void invalidate() { + super.invalidate(); + if (itemHandler != null) + itemHandler.invalidate(); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return itemHandler.cast(); + return super.getCapability(cap, side); + } + + public FilteringBehaviour createFilter() { + return new FilteringBehaviour(this, new ValueBoxTransform() { + + @Override + public void rotate(BlockState state, PoseStack ms) { + TransformStack.cast(ms) + .rotateX(90); + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + return new Vec3(0.5, 13.5 / 16d, 0.5); + } + + public float getScale() { + return super.getScale(); + }; + + }); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java similarity index 80% rename from src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBehaviour.java rename to src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java index 7f0e65d7e5..3cb77f6d23 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.depot; +package com.simibubi.create.content.logistics.depot; import java.util.ArrayList; import java.util.Iterator; @@ -9,18 +9,18 @@ import java.util.function.Predicate; import java.util.function.Supplier; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.content.logistics.block.funnel.AbstractFunnelBlock; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour.ProcessingResult; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.funnel.AbstractFunnelBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour.ProcessingResult; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; @@ -32,6 +32,7 @@ import net.minecraft.nbt.Tag; import net.minecraft.world.Containers; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.capabilities.Capability; @@ -39,7 +40,7 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemStackHandler; -public class DepotBehaviour extends TileEntityBehaviour { +public class DepotBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); @@ -56,8 +57,8 @@ public class DepotBehaviour extends TileEntityBehaviour { Predicate acceptedItems; boolean allowMerge; - public DepotBehaviour(SmartTileEntity te) { - super(te); + public DepotBehaviour(SmartBlockEntity be) { + super(be); maxStackSize = () -> 64; canAcceptItems = () -> true; canFunnelsPullFrom = $ -> true; @@ -69,7 +70,7 @@ public class DepotBehaviour extends TileEntityBehaviour { lazyItemHandler = LazyOptional.of(() -> itemHandler); processingOutputBuffer = new ItemStackHandler(8) { protected void onContentsChanged(int slot) { - te.notifyUpdate(); + be.notifyUpdate(); }; }; } @@ -92,26 +93,26 @@ public class DepotBehaviour extends TileEntityBehaviour { public void tick() { super.tick(); - Level world = tileEntity.getLevel(); + Level world = blockEntity.getLevel(); for (Iterator iterator = incoming.iterator(); iterator.hasNext();) { TransportedItemStack ts = iterator.next(); if (!tick(ts)) continue; - if (world.isClientSide && !tileEntity.isVirtual()) + if (world.isClientSide && !blockEntity.isVirtual()) continue; if (heldItem == null) { heldItem = ts; } else { if (!ItemHelper.canItemStackAmountsStack(heldItem.stack, ts.stack)) { - Vec3 vec = VecHelper.getCenterOf(tileEntity.getBlockPos()); - Containers.dropItemStack(tileEntity.getLevel(), vec.x, vec.y + .5f, vec.z, ts.stack); + Vec3 vec = VecHelper.getCenterOf(blockEntity.getBlockPos()); + Containers.dropItemStack(blockEntity.getLevel(), vec.x, vec.y + .5f, vec.z, ts.stack); } else { heldItem.stack.grow(ts.stack.getCount()); } } iterator.remove(); - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); } if (heldItem == null) @@ -119,7 +120,7 @@ public class DepotBehaviour extends TileEntityBehaviour { if (!tick(heldItem)) return; - BlockPos pos = tileEntity.getBlockPos(); + BlockPos pos = blockEntity.getBlockPos(); if (world.isClientSide) return; @@ -127,7 +128,7 @@ public class DepotBehaviour extends TileEntityBehaviour { return; BeltProcessingBehaviour processingBehaviour = - TileEntityBehaviour.get(world, pos.above(2), BeltProcessingBehaviour.TYPE); + BlockEntityBehaviour.get(world, pos.above(2), BeltProcessingBehaviour.TYPE); if (processingBehaviour == null) return; if (!heldItem.locked && BeltProcessingBehaviour.isBlocked(world, pos)) @@ -139,13 +140,13 @@ public class DepotBehaviour extends TileEntityBehaviour { : processingBehaviour.handleReceivedItem(heldItem, transportedHandler); if (result == ProcessingResult.REMOVE) { heldItem = null; - tileEntity.sendData(); + blockEntity.sendData(); return; } heldItem.locked = result == ProcessingResult.HOLD; if (heldItem.locked != wasLocked || !previousItem.equals(heldItem.stack, false)) - tileEntity.sendData(); + blockEntity.sendData(); } protected boolean tick(TransportedItemStack heldItem) { @@ -170,19 +171,19 @@ public class DepotBehaviour extends TileEntityBehaviour { ItemStack previousItem = processingOutputBuffer.getStackInSlot(slot); if (previousItem.isEmpty()) continue; - ItemStack afterInsert = tileEntity.getBehaviour(DirectBeltInputBehaviour.TYPE) + ItemStack afterInsert = blockEntity.getBehaviour(DirectBeltInputBehaviour.TYPE) .tryExportingToBeltFunnel(previousItem, null, false); if (afterInsert == null) return false; if (previousItem.getCount() != afterInsert.getCount()) { processingOutputBuffer.setStackInSlot(slot, afterInsert); - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); return true; } } ItemStack previousItem = heldItem.stack; - ItemStack afterInsert = tileEntity.getBehaviour(DirectBeltInputBehaviour.TYPE) + ItemStack afterInsert = blockEntity.getBehaviour(DirectBeltInputBehaviour.TYPE) .tryExportingToBeltFunnel(previousItem, null, false); if (afterInsert == null) return false; @@ -191,7 +192,7 @@ public class DepotBehaviour extends TileEntityBehaviour { heldItem = null; else heldItem.stack = afterInsert; - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); return true; } @@ -199,7 +200,19 @@ public class DepotBehaviour extends TileEntityBehaviour { } @Override - public void remove() { + public void destroy() { + super.destroy(); + Level level = getWorld(); + BlockPos pos = getPos(); + ItemHelper.dropContents(level, pos, processingOutputBuffer); + for (TransportedItemStack transportedItemStack : incoming) + Block.popResource(level, pos, transportedItemStack.stack); + if (!getHeldItemStack().isEmpty()) + Block.popResource(level, pos, getHeldItemStack()); + } + + @Override + public void unload() { if (lazyItemHandler != null) lazyItemHandler.invalidate(); } @@ -225,10 +238,10 @@ public class DepotBehaviour extends TileEntityBehaviour { } } - public void addSubBehaviours(List behaviours) { - behaviours.add(new DirectBeltInputBehaviour(tileEntity).allowingBeltFunnels() + public void addSubBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(blockEntity).allowingBeltFunnels() .setInsertionHandler(this::tryInsertingFromSide)); - transportedHandler = new TransportedItemStackHandlerBehaviour(tileEntity, this::applyToAllItems) + transportedHandler = new TransportedItemStackHandlerBehaviour(blockEntity, this::applyToAllItems) .withStackPlacement(this::getWorldPositionOf); behaviours.add(transportedHandler); } @@ -345,7 +358,7 @@ public class DepotBehaviour extends TileEntityBehaviour { transportedStack.prevBeltPosition = transportedStack.beltPosition; ItemStack remainder = insert(transportedStack, simulate); if (remainder.getCount() != size) - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); return remainder; } @@ -375,12 +388,12 @@ public class DepotBehaviour extends TileEntityBehaviour { continue; } ItemStack remainder = ItemHandlerHelper.insertItemStacked(processingOutputBuffer, added.stack, false); - Vec3 vec = VecHelper.getCenterOf(tileEntity.getBlockPos()); - Containers.dropItemStack(tileEntity.getLevel(), vec.x, vec.y + .5f, vec.z, remainder); + Vec3 vec = VecHelper.getCenterOf(blockEntity.getBlockPos()); + Containers.dropItemStack(blockEntity.getLevel(), vec.x, vec.y + .5f, vec.z, remainder); } if (dirty) - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); } public boolean isEmpty() { @@ -396,7 +409,7 @@ public class DepotBehaviour extends TileEntityBehaviour { } private Vec3 getWorldPositionOf(TransportedItemStack transported) { - return VecHelper.getCenterOf(tileEntity.getBlockPos()); + return VecHelper.getCenterOf(blockEntity.getBlockPos()); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlock.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlock.java new file mode 100644 index 0000000000..e664309dc3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlock.java @@ -0,0 +1,111 @@ +package com.simibubi.create.content.logistics.depot; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class DepotBlock extends Block implements IBE, IWrenchable, ProperWaterloggedBlock { + + public DepotBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(WATERLOGGED)); + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + return withWater(super.getStateForPlacement(pContext), pContext); + } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.CASING_13PX.get(Direction.UP); + } + + @Override + public Class getBlockEntityClass() { + return DepotBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.DEPOT.get(); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + return SharedDepotBlockMethods.onUse(state, world, pos, player, hand, ray); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, worldIn, pos, newState); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + SharedDepotBlockMethods.onLanded(worldIn, entityIn); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { + return SharedDepotBlockMethods.getComparatorInputOverride(blockState, worldIn, pos); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java new file mode 100644 index 0000000000..af3356704a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotBlockEntity.java @@ -0,0 +1,41 @@ +package com.simibubi.create.content.logistics.depot; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; + +public class DepotBlockEntity extends SmartBlockEntity { + + DepotBehaviour depotBehaviour; + + public DepotBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(depotBehaviour = new DepotBehaviour(this)); + depotBehaviour.addSubBehaviours(behaviours); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return depotBehaviour.getItemCapability(cap, side); + return super.getCapability(cap, side); + } + + public ItemStack getHeldItem() { + return depotBehaviour.getHeldItemStack(); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/DepotItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotItemHandler.java new file mode 100644 index 0000000000..c4873ec2cd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotItemHandler.java @@ -0,0 +1,72 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +public class DepotItemHandler implements IItemHandler { + + private static final int MAIN_SLOT = 0; + private DepotBehaviour behaviour; + + public DepotItemHandler(DepotBehaviour behaviour) { + this.behaviour = behaviour; + } + + @Override + public int getSlots() { + return 9; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return slot == MAIN_SLOT ? behaviour.getHeldItemStack() : behaviour.processingOutputBuffer.getStackInSlot(slot - 1); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (slot != MAIN_SLOT) + return stack; + if (!behaviour.getHeldItemStack() + .isEmpty() && !behaviour.canMergeItems()) + return stack; + if (!behaviour.isOutputEmpty() && !behaviour.canMergeItems()) + return stack; + + ItemStack remainder = behaviour.insert(new TransportedItemStack(stack), simulate); + if (!simulate && remainder != stack) + behaviour.blockEntity.notifyUpdate(); + return remainder; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + if (slot != MAIN_SLOT) + return behaviour.processingOutputBuffer.extractItem(slot - 1, amount, simulate); + + TransportedItemStack held = behaviour.heldItem; + if (held == null) + return ItemStack.EMPTY; + ItemStack stack = held.stack.copy(); + ItemStack extracted = stack.split(amount); + if (!simulate) { + behaviour.heldItem.stack = stack; + if (stack.isEmpty()) + behaviour.heldItem = null; + behaviour.blockEntity.notifyUpdate(); + } + return extracted; + } + + @Override + public int getSlotLimit(int slot) { + return slot == MAIN_SLOT ? behaviour.maxStackSize.get() : 64; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return slot == MAIN_SLOT && behaviour.isItemValid(stack); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java b/src/main/java/com/simibubi/create/content/logistics/depot/DepotRenderer.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java rename to src/main/java/com/simibubi/create/content/logistics/depot/DepotRenderer.java index 1646ee2e47..1861fb24d3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/DepotRenderer.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.logistics.block.depot; +package com.simibubi.create.content.logistics.depot; import java.util.Random; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; -import com.simibubi.create.content.contraptions.relays.belt.BeltHelper; -import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; import net.createmod.catnip.utility.VecHelper; import net.minecraft.client.Minecraft; @@ -22,23 +22,23 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; -public class DepotRenderer extends SafeTileEntityRenderer { +public class DepotRenderer extends SafeBlockEntityRenderer { public DepotRenderer(BlockEntityRendererProvider.Context context) { } @Override - protected void renderSafe(DepotTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(DepotBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - renderItemsOf(te, partialTicks, ms, buffer, light, overlay, te.depotBehaviour); + renderItemsOf(be, partialTicks, ms, buffer, light, overlay, be.depotBehaviour); } - public static void renderItemsOf(SmartTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + public static void renderItemsOf(SmartBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay, DepotBehaviour depotBehaviour) { TransportedItemStack transported = depotBehaviour.heldItem; TransformStack msr = TransformStack.cast(ms); - Vec3 itemPosition = VecHelper.getCenterOf(te.getBlockPos()); + Vec3 itemPosition = VecHelper.getCenterOf(be.getBlockPos()); ms.pushPose(); ms.translate(.5f, 15 / 16f, .5f); diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorAwardPacket.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorAwardPacket.java new file mode 100644 index 0000000000..ecc786c0d7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorAwardPacket.java @@ -0,0 +1,34 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; + +public class EjectorAwardPacket extends BlockEntityConfigurationPacket { + + public EjectorAwardPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + public EjectorAwardPacket(BlockPos pos) { + super(pos); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) {} + + @Override + protected void readSettings(FriendlyByteBuf buffer) {} + + @Override + protected void applySettings(ServerPlayer player, EjectorBlockEntity be) { + AllAdvancements.EJECTOR_MAXED.awardTo(player); + } + + @Override + protected void applySettings(EjectorBlockEntity be) {} + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlock.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlock.java new file mode 100644 index 0000000000..0e779f454f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlock.java @@ -0,0 +1,193 @@ +package com.simibubi.create.content.logistics.depot; + +import java.util.Optional; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllShapes; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.logistics.depot.EjectorBlockEntity.State; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class EjectorBlock extends HorizontalKineticBlock implements IBE, ProperWaterloggedBlock { + + public EjectorBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(WATERLOGGED)); + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + return withWater(super.getStateForPlacement(pContext), pContext); + } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, BlockGetter p_220053_2_, BlockPos p_220053_3_, + CollisionContext p_220053_4_) { + return AllShapes.CASING_13PX.get(Direction.UP); + } + + @Override + public float getFriction(BlockState state, LevelReader world, BlockPos pos, Entity entity) { + return getBlockEntityOptional(world, pos).filter(ete -> ete.state == State.LAUNCHING) + .map($ -> 1f) + .orElse(super.getFriction(state, world, pos, entity)); + } + + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, + boolean p_220069_6_) { + withBlockEntityDo(world, pos, EjectorBlockEntity::updateSignal); + } + + @Override + public void fallOn(Level p_180658_1_, BlockState p_152427_, BlockPos p_180658_2_, Entity p_180658_3_, + float p_180658_4_) { + Optional blockEntityOptional = getBlockEntityOptional(p_180658_1_, p_180658_2_); + if (blockEntityOptional.isPresent() && !p_180658_3_.isSuppressingBounce()) { + p_180658_3_.causeFallDamage(p_180658_4_, 1.0F, DamageSource.FALL); + return; + } + super.fallOn(p_180658_1_, p_152427_, p_180658_2_, p_180658_3_, p_180658_4_); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + BlockPos position = entityIn.blockPosition(); + if (!AllBlocks.WEIGHTED_EJECTOR.has(worldIn.getBlockState(position))) + return; + if (!entityIn.isAlive()) + return; + if (entityIn.isSuppressingBounce()) + return; + if (entityIn instanceof ItemEntity) { + SharedDepotBlockMethods.onLanded(worldIn, entityIn); + return; + } + + Optional teProvider = getBlockEntityOptional(worldIn, position); + if (!teProvider.isPresent()) + return; + + EjectorBlockEntity ejectorBlockEntity = teProvider.get(); + if (ejectorBlockEntity.getState() == State.RETRACTING) + return; + if (ejectorBlockEntity.powered) + return; + if (ejectorBlockEntity.launcher.getHorizontalDistance() == 0) + return; + + if (entityIn.isOnGround()) { + entityIn.setOnGround(false); + Vec3 center = VecHelper.getCenterOf(position) + .add(0, 7 / 16f, 0); + Vec3 positionVec = entityIn.position(); + double diff = center.distanceTo(positionVec); + entityIn.setDeltaMovement(0, -0.125, 0); + Vec3 vec = center.add(positionVec) + .scale(.5f); + if (diff > 4 / 16f) { + entityIn.setPos(vec.x, vec.y, vec.z); + return; + } + } + + ejectorBlockEntity.activate(); + ejectorBlockEntity.notifyUpdate(); + if (entityIn.level.isClientSide) + AllPackets.getChannel().sendToServer(new EjectorTriggerPacket(ejectorBlockEntity.getBlockPos())); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult ray) { + if (AllItems.WRENCH.isIn(player.getItemInHand(hand))) + return InteractionResult.PASS; + return SharedDepotBlockMethods.onUse(state, world, pos, player, hand, ray); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.getValue(HORIZONTAL_FACING) + .getClockWise() + .getAxis(); + } + + @Override + public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { + return getRotationAxis(state) == face.getAxis(); + } + + @Override + public Class getBlockEntityClass() { + return EjectorBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.WEIGHTED_EJECTOR.get(); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { + return SharedDepotBlockMethods.getComparatorInputOverride(blockState, worldIn, pos); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlockEntity.java new file mode 100644 index 0000000000..bb2e419915 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorBlockEntity.java @@ -0,0 +1,659 @@ +package com.simibubi.create.content.logistics.depot; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.funnel.AbstractFunnelBlock; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.IntAttached; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ElytraItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.ClipContext.Block; +import net.minecraft.world.level.ClipContext.Fluid; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.ObserverBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.PushReaction; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult.Type; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.ItemStackHandler; + +public class EjectorBlockEntity extends KineticBlockEntity { + + List> launchedItems; + ScrollValueBehaviour maxStackSize; + DepotBehaviour depotBehaviour; + EntityLauncher launcher; + LerpedFloat lidProgress; + boolean powered; + boolean launch; + State state; + + // item collision + @Nullable + Pair earlyTarget; + float earlyTargetTime; + // runtime stuff + int scanCooldown; + ItemStack trackedItem; + + public enum State { + CHARGED, LAUNCHING, RETRACTING; + } + + public EjectorBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + launcher = new EntityLauncher(1, 0); + lidProgress = LerpedFloat.linear() + .startWithValue(1); + this.state = State.RETRACTING; + launchedItems = new ArrayList<>(); + powered = false; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(depotBehaviour = new DepotBehaviour(this)); + + maxStackSize = + new ScrollValueBehaviour(CreateLang.translateDirect("weighted_ejector.stack_size"), this, new EjectorSlot()) + .between(0, 64) + .withFormatter(i -> i == 0 ? "*" : String.valueOf(i)); + behaviours.add(maxStackSize); + + depotBehaviour.maxStackSize = () -> maxStackSize.getValue(); + depotBehaviour.canAcceptItems = () -> state == State.CHARGED; + depotBehaviour.canFunnelsPullFrom = side -> side != getFacing(); + depotBehaviour.enableMerging(); + depotBehaviour.addSubBehaviours(behaviours); + } + + @Override + public void initialize() { + super.initialize(); + updateSignal(); + } + + public void activate() { + launch = true; + nudgeEntities(); + } + + protected boolean cannotLaunch() { + return state != State.CHARGED && !(level.isClientSide && state == State.LAUNCHING); + } + + public void activateDeferred() { + if (cannotLaunch()) + return; + Direction facing = getFacing(); + List entities = + level.getEntitiesOfClass(Entity.class, new AABB(worldPosition).inflate(-1 / 16f, 0, -1 / 16f)); + + // Launch Items + boolean doLogic = !level.isClientSide || isVirtual(); + if (doLogic) + launchItems(); + + // Launch Entities + for (Entity entity : entities) { + boolean isPlayerEntity = entity instanceof Player; + if (!entity.isAlive()) + continue; + if (entity instanceof ItemEntity) + continue; + if (entity.getPistonPushReaction() == PushReaction.IGNORE) + continue; + + entity.setOnGround(false); + + if (isPlayerEntity != level.isClientSide) + continue; + + entity.setPos(worldPosition.getX() + .5f, worldPosition.getY() + 1, worldPosition.getZ() + .5f); + launcher.applyMotion(entity, facing); + + if (!isPlayerEntity) + continue; + + Player playerEntity = (Player) entity; + + if (launcher.getHorizontalDistance() * launcher.getHorizontalDistance() + + launcher.getVerticalDistance() * launcher.getVerticalDistance() >= 25 * 25) + AllPackets.getChannel() + .sendToServer(new EjectorAwardPacket(worldPosition)); + + if (!(playerEntity.getItemBySlot(EquipmentSlot.CHEST) + .getItem() instanceof ElytraItem)) + continue; + + playerEntity.setXRot(-35); + playerEntity.setYRot(facing.toYRot()); + playerEntity.setDeltaMovement(playerEntity.getDeltaMovement() + .scale(.75f)); + deployElytra(playerEntity); + AllPackets.getChannel() + .sendToServer(new EjectorElytraPacket(worldPosition)); + } + + if (doLogic) { + lidProgress.chase(1, .8f, Chaser.EXP); + state = State.LAUNCHING; + if (!level.isClientSide) { + level.playSound(null, worldPosition, SoundEvents.WOODEN_TRAPDOOR_CLOSE, SoundSource.BLOCKS, .35f, 1f); + level.playSound(null, worldPosition, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, .1f, 1.4f); + } + } + } + + public void deployElytra(Player playerEntity) { + EntityHack.setElytraFlying(playerEntity); + } + + protected void launchItems() { + ItemStack heldItemStack = depotBehaviour.getHeldItemStack(); + Direction funnelFacing = getFacing().getOpposite(); + + if (AbstractFunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == funnelFacing) { + DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE); + + if (depotBehaviour.heldItem != null) { + ItemStack remainder = directOutput.tryExportingToBeltFunnel(heldItemStack, funnelFacing, false); + if (remainder == null) + ; + else if (remainder.isEmpty()) + depotBehaviour.removeHeldItem(); + else if (remainder.getCount() != heldItemStack.getCount()) + depotBehaviour.heldItem.stack = remainder; + } + + for (Iterator iterator = depotBehaviour.incoming.iterator(); iterator.hasNext();) { + TransportedItemStack transportedItemStack = iterator.next(); + ItemStack stack = transportedItemStack.stack; + ItemStack remainder = directOutput.tryExportingToBeltFunnel(stack, funnelFacing, false); + if (remainder == null) + ; + else if (remainder.isEmpty()) + iterator.remove(); + else if (!remainder.sameItem(stack)) + transportedItemStack.stack = remainder; + } + + ItemStackHandler outputs = depotBehaviour.processingOutputBuffer; + for (int i = 0; i < outputs.getSlots(); i++) { + ItemStack remainder = + directOutput.tryExportingToBeltFunnel(outputs.getStackInSlot(i), funnelFacing, false); + if (remainder != null) + outputs.setStackInSlot(i, remainder); + } + return; + } + + if (!level.isClientSide) + for (Direction d : Iterate.directions) { + BlockState blockState = level.getBlockState(worldPosition.relative(d)); + if (!(blockState.getBlock() instanceof ObserverBlock)) + continue; + if (blockState.getValue(ObserverBlock.FACING) != d.getOpposite()) + continue; + blockState.updateShape(d.getOpposite(), blockState, level, worldPosition.relative(d), worldPosition); + } + + if (depotBehaviour.heldItem != null) { + addToLaunchedItems(heldItemStack); + depotBehaviour.removeHeldItem(); + } + + for (TransportedItemStack transportedItemStack : depotBehaviour.incoming) + addToLaunchedItems(transportedItemStack.stack); + depotBehaviour.incoming.clear(); + + ItemStackHandler outputs = depotBehaviour.processingOutputBuffer; + for (int i = 0; i < outputs.getSlots(); i++) { + ItemStack extractItem = outputs.extractItem(i, 64, false); + if (!extractItem.isEmpty()) + addToLaunchedItems(extractItem); + } + } + + protected boolean addToLaunchedItems(ItemStack stack) { + if ((!level.isClientSide || isVirtual()) && trackedItem == null && scanCooldown == 0) { + scanCooldown = AllConfigs.server().kinetics.ejectorScanInterval.get(); + trackedItem = stack; + } + return launchedItems.add(IntAttached.withZero(stack)); + } + + protected Direction getFacing() { + BlockState blockState = getBlockState(); + if (!AllBlocks.WEIGHTED_EJECTOR.has(blockState)) + return Direction.UP; + Direction facing = blockState.getValue(EjectorBlock.HORIZONTAL_FACING); + return facing; + } + + @Override + public void tick() { + super.tick(); + + boolean doLogic = !level.isClientSide || isVirtual(); + State prevState = state; + float totalTime = Math.max(3, (float) launcher.getTotalFlyingTicks()); + + if (scanCooldown > 0) + scanCooldown--; + + if (launch) { + launch = false; + activateDeferred(); + } + + for (Iterator> iterator = launchedItems.iterator(); iterator.hasNext();) { + IntAttached intAttached = iterator.next(); + boolean hit = false; + if (intAttached.getSecond() == trackedItem) + hit = scanTrajectoryForObstacles(intAttached.getFirst()); + float maxTime = earlyTarget != null ? Math.min(earlyTargetTime, totalTime) : totalTime; + if (hit || intAttached.exceeds((int) maxTime)) { + placeItemAtTarget(doLogic, maxTime, intAttached); + iterator.remove(); + } + intAttached.increment(); + } + + if (state == State.LAUNCHING) { + lidProgress.chase(1, .8f, Chaser.EXP); + lidProgress.tickChaser(); + if (lidProgress.getValue() > 1 - 1 / 16f && doLogic) { + state = State.RETRACTING; + lidProgress.setValue(1); + } + } + + if (state == State.CHARGED) { + lidProgress.setValue(0); + lidProgress.updateChaseSpeed(0); + if (doLogic) + ejectIfTriggered(); + } + + if (state == State.RETRACTING) { + if (lidProgress.getChaseTarget() == 1 && !lidProgress.settled()) { + lidProgress.tickChaser(); + } else { + lidProgress.updateChaseTarget(0); + lidProgress.updateChaseSpeed(0); + if (lidProgress.getValue() == 0 && doLogic) { + state = State.CHARGED; + lidProgress.setValue(0); + sendData(); + } + + float value = Mth.clamp(lidProgress.getValue() - getWindUpSpeed(), 0, 1); + lidProgress.setValue(value); + + int soundRate = (int) (1 / (getWindUpSpeed() * 5)) + 1; + float volume = .125f; + float pitch = 1.5f - lidProgress.getValue(); + if (((int) level.getGameTime()) % soundRate == 0 && doLogic) + level.playSound(null, worldPosition, SoundEvents.WOODEN_BUTTON_CLICK_OFF, SoundSource.BLOCKS, + volume, pitch); + } + } + + if (state != prevState) + notifyUpdate(); + } + + private boolean scanTrajectoryForObstacles(int time) { + if (time <= 2) + return false; + + Vec3 source = getLaunchedItemLocation(time); + Vec3 target = getLaunchedItemLocation(time + 1); + + BlockHitResult rayTraceBlocks = level.clip(new ClipContext(source, target, Block.COLLIDER, Fluid.NONE, null)); + boolean miss = rayTraceBlocks.getType() == Type.MISS; + + if (!miss && rayTraceBlocks.getType() == Type.BLOCK) { + BlockState blockState = level.getBlockState(rayTraceBlocks.getBlockPos()); + if (FunnelBlock.isFunnel(blockState) && blockState.hasProperty(FunnelBlock.EXTRACTING) + && blockState.getValue(FunnelBlock.EXTRACTING)) + miss = true; + } + + if (miss) { + if (earlyTarget != null && earlyTargetTime < time + 1) { + earlyTarget = null; + earlyTargetTime = 0; + } + return false; + } + + Vec3 vec = rayTraceBlocks.getLocation(); + earlyTarget = Pair.of(vec.add(Vec3.atLowerCornerOf(rayTraceBlocks.getDirection() + .getNormal()) + .scale(.25f)), rayTraceBlocks.getBlockPos()); + earlyTargetTime = (float) (time + (source.distanceTo(vec) / source.distanceTo(target))); + sendData(); + return true; + } + + protected void nudgeEntities() { + for (Entity entity : level.getEntitiesOfClass(Entity.class, + new AABB(worldPosition).inflate(-1 / 16f, 0, -1 / 16f))) { + if (!entity.isAlive()) + continue; + if (entity.getPistonPushReaction() == PushReaction.IGNORE) + continue; + if (!(entity instanceof Player)) + entity.setPos(entity.getX(), entity.getY() + .125f, entity.getZ()); + } + } + + protected void ejectIfTriggered() { + if (powered) + return; + int presentStackSize = depotBehaviour.getPresentStackSize(); + if (presentStackSize == 0) + return; + if (presentStackSize < maxStackSize.getValue()) + return; + if (depotBehaviour.heldItem != null && depotBehaviour.heldItem.beltPosition < .49f) + return; + + Direction funnelFacing = getFacing().getOpposite(); + ItemStack held = depotBehaviour.getHeldItemStack(); + if (AbstractFunnelBlock.getFunnelFacing(level.getBlockState(worldPosition.above())) == funnelFacing) { + DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE); + if (depotBehaviour.heldItem != null) { + ItemStack tryFunnel = directOutput.tryExportingToBeltFunnel(held, funnelFacing, true); + if (tryFunnel == null || !tryFunnel.isEmpty()) + return; + } + } + + DirectBeltInputBehaviour targetOpenInv = getTargetOpenInv(); + + // Do not eject if target cannot accept held item + if (targetOpenInv != null && depotBehaviour.heldItem != null + && targetOpenInv.handleInsertion(held, Direction.UP, true) + .getCount() == held.getCount()) + return; + + activate(); + notifyUpdate(); + } + + protected void placeItemAtTarget(boolean doLogic, float maxTime, IntAttached intAttached) { + if (!doLogic) + return; + if (intAttached.getSecond() == trackedItem) + trackedItem = null; + + DirectBeltInputBehaviour targetOpenInv = getTargetOpenInv(); + if (targetOpenInv != null) { + ItemStack remainder = targetOpenInv.handleInsertion(intAttached.getValue(), Direction.UP, false); + intAttached.setSecond(remainder); + } + + if (intAttached.getValue() + .isEmpty()) + return; + + Vec3 ejectVec = earlyTarget != null ? earlyTarget.getFirst() : getLaunchedItemLocation(maxTime); + Vec3 ejectMotionVec = getLaunchedItemMotion(maxTime); + ItemEntity item = new ItemEntity(level, ejectVec.x, ejectVec.y, ejectVec.z, intAttached.getValue()); + item.setDeltaMovement(ejectMotionVec); + item.setDefaultPickUpDelay(); + level.addFreshEntity(item); + } + + public DirectBeltInputBehaviour getTargetOpenInv() { + BlockPos targetPos = earlyTarget != null ? earlyTarget.getSecond() + : worldPosition.above(launcher.getVerticalDistance()) + .relative(getFacing(), Math.max(1, launcher.getHorizontalDistance())); + return BlockEntityBehaviour.get(level, targetPos, DirectBeltInputBehaviour.TYPE); + } + + public Vec3 getLaunchedItemLocation(float time) { + return launcher.getGlobalPos(time, getFacing().getOpposite(), worldPosition); + } + + public Vec3 getLaunchedItemMotion(float time) { + return launcher.getGlobalVelocity(time, getFacing().getOpposite(), worldPosition) + .scale(.5f); + } + + @Override + public void destroy() { + super.destroy(); + dropFlyingItems(); + } + + public void dropFlyingItems() { + for (IntAttached intAttached : launchedItems) { + Vec3 ejectVec = getLaunchedItemLocation(intAttached.getFirst()); + Vec3 ejectMotionVec = getLaunchedItemMotion(intAttached.getFirst()); + ItemEntity item = new ItemEntity(level, 0, 0, 0, intAttached.getValue()); + item.setPosRaw(ejectVec.x, ejectVec.y, ejectVec.z); + item.setDeltaMovement(ejectMotionVec); + item.setDefaultPickUpDelay(); + level.addFreshEntity(item); + } + launchedItems.clear(); + } + + public float getWindUpSpeed() { + int hd = launcher.getHorizontalDistance(); + int vd = launcher.getVerticalDistance(); + + float speedFactor = Math.abs(getSpeed()) / 256f; + float distanceFactor; + if (hd == 0 && vd == 0) + distanceFactor = 1; + else + distanceFactor = 1 * Mth.sqrt(hd * hd + vd * vd); + return speedFactor / distanceFactor; + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("HorizontalDistance", launcher.getHorizontalDistance()); + compound.putInt("VerticalDistance", launcher.getVerticalDistance()); + compound.putBoolean("Powered", powered); + NBTHelper.writeEnum(compound, "State", state); + compound.put("Lid", lidProgress.writeNBT()); + compound.put("LaunchedItems", + NBTHelper.writeCompoundList(launchedItems, ia -> ia.serializeNBT(ItemStack::serializeNBT))); + + if (earlyTarget != null) { + compound.put("EarlyTarget", VecHelper.writeNBT(earlyTarget.getFirst())); + compound.put("EarlyTargetPos", NbtUtils.writeBlockPos(earlyTarget.getSecond())); + compound.putFloat("EarlyTargetTime", earlyTargetTime); + } + } + + @Override + public void writeSafe(CompoundTag compound) { + super.writeSafe(compound); + compound.putInt("HorizontalDistance", launcher.getHorizontalDistance()); + compound.putInt("VerticalDistance", launcher.getVerticalDistance()); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + int horizontalDistance = compound.getInt("HorizontalDistance"); + int verticalDistance = compound.getInt("VerticalDistance"); + + if (launcher.getHorizontalDistance() != horizontalDistance + || launcher.getVerticalDistance() != verticalDistance) { + launcher.set(horizontalDistance, verticalDistance); + launcher.clamp(AllConfigs.server().kinetics.maxEjectorDistance.get()); + } + + powered = compound.getBoolean("Powered"); + state = NBTHelper.readEnum(compound, "State", State.class); + lidProgress.readNBT(compound.getCompound("Lid"), false); + launchedItems = NBTHelper.readCompoundList(compound.getList("LaunchedItems", Tag.TAG_COMPOUND), + nbt -> IntAttached.read(nbt, ItemStack::of)); + + earlyTarget = null; + earlyTargetTime = 0; + if (compound.contains("EarlyTarget")) { + earlyTarget = Pair.of(VecHelper.readNBT(compound.getList("EarlyTarget", Tag.TAG_DOUBLE)), + NbtUtils.readBlockPos(compound.getCompound("EarlyTargetPos"))); + earlyTargetTime = compound.getFloat("EarlyTargetTime"); + } + + if (compound.contains("ForceAngle")) + lidProgress.startWithValue(compound.getFloat("ForceAngle")); + } + + public void updateSignal() { + boolean shoudPower = level.hasNeighborSignal(worldPosition); + if (shoudPower == powered) + return; + powered = shoudPower; + sendData(); + } + + public void setTarget(int horizontalDistance, int verticalDistance) { + launcher.set(Math.max(1, horizontalDistance), verticalDistance); + sendData(); + } + + public BlockPos getTargetPosition() { + BlockState blockState = getBlockState(); + if (!AllBlocks.WEIGHTED_EJECTOR.has(blockState)) + return worldPosition; + Direction facing = blockState.getValue(EjectorBlock.HORIZONTAL_FACING); + return worldPosition.relative(facing, launcher.getHorizontalDistance()) + .above(launcher.getVerticalDistance()); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return depotBehaviour.getItemCapability(cap, side); + return super.getCapability(cap, side); + } + + public float getLidProgress(float pt) { + return lidProgress.getValue(pt); + } + + public State getState() { + return state; + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getRenderBoundingBox() { + return INFINITE_EXTENT_AABB; + } + + private static abstract class EntityHack extends Entity { + + public EntityHack(EntityType p_i48580_1_, Level p_i48580_2_) { + super(p_i48580_1_, p_i48580_2_); + } + + public static void setElytraFlying(Entity e) { + SynchedEntityData data = e.getEntityData(); + data.set(DATA_SHARED_FLAGS_ID, (byte) (data.get(DATA_SHARED_FLAGS_ID) | 1 << 7)); + } + + } + + private class EjectorSlot extends ValueBoxTransform.Sided { + + @Override + public Vec3 getLocalOffset(BlockState state) { + if (direction != Direction.UP) + return super.getLocalOffset(state); + return new Vec3(.5, 10.5 / 16f, .5).add(VecHelper.rotate(VecHelper.voxelSpace(0, 0, -5), angle(state), Axis.Y)); + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + if (direction != Direction.UP) { + super.rotate(state, ms); + return; + } + TransformStack.cast(ms) + .rotateY(angle(state)) + .rotateX(90); + } + + protected float angle(BlockState state) { + float horizontalAngle = AllBlocks.WEIGHTED_EJECTOR.has(state) + ? AngleHelper.horizontalAngle(state.getValue(EjectorBlock.HORIZONTAL_FACING)) + : 0; + return horizontalAngle; + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + return direction.getAxis() == state.getValue(EjectorBlock.HORIZONTAL_FACING) + .getAxis() + || direction == Direction.UP && EjectorBlockEntity.this.state != EjectorBlockEntity.State.CHARGED; + } + + @Override + protected Vec3 getSouthLocation() { + return direction == Direction.UP ? Vec3.ZERO : VecHelper.voxelSpace(8, 6, 15.5); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorElytraPacket.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorElytraPacket.java new file mode 100644 index 0000000000..c625f91c9a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorElytraPacket.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.network.NetworkEvent.Context; + +public class EjectorElytraPacket extends SimplePacketBase { + + private BlockPos pos; + + public EjectorElytraPacket(BlockPos pos) { + this.pos = pos; + } + + public EjectorElytraPacket(FriendlyByteBuf buffer) { + pos = buffer.readBlockPos(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBlockPos(pos); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + Level world = player.level; + if (world == null || !world.isLoaded(pos)) + return; + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof EjectorBlockEntity) + ((EjectorBlockEntity) blockEntity).deployElytra(player); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorInstance.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorInstance.java new file mode 100644 index 0000000000..84b03a10e1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorInstance.java @@ -0,0 +1,61 @@ +package com.simibubi.create.content.logistics.depot; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.ShaftInstance; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.util.Mth; + +public class EjectorInstance extends ShaftInstance implements DynamicInstance { + + protected final ModelData plate; + + private float lastProgress = Float.NaN; + + public EjectorInstance(MaterialManager dispatcher, EjectorBlockEntity blockEntity) { + super(dispatcher, blockEntity); + + plate = getTransformMaterial().getModel(AllPartialModels.EJECTOR_TOP, blockState).createInstance(); + + pivotPlate(); + } + + @Override + public void beginFrame() { + float lidProgress = getLidProgress(); + + if (Mth.equal(lidProgress, lastProgress)) return; + + pivotPlate(lidProgress); + lastProgress = lidProgress; + } + + @Override + public void updateLight() { + super.updateLight(); + relight(pos, plate); + } + + @Override + public void remove() { + super.remove(); + plate.delete(); + } + + private void pivotPlate() { + pivotPlate(getLidProgress()); + } + + private float getLidProgress() { + return blockEntity.getLidProgress(AnimationTickHolder.getPartialTicks()); + } + + private void pivotPlate(float lidProgress) { + float angle = lidProgress * 70; + + //EjectorRenderer.applyLidAngle(blockEntity, angle, plate.loadIdentity().translate(getInstancePosition()));//TODO flw + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorItem.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorItem.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorItem.java rename to src/main/java/com/simibubi/create/content/logistics/depot/EjectorItem.java index 18a2706a3a..7dd4ce7ddd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.depot; +package com.simibubi.create.content.logistics.depot; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionResult; diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorPlacementPacket.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorPlacementPacket.java new file mode 100644 index 0000000000..4345144445 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorPlacementPacket.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.network.NetworkEvent.Context; + +public class EjectorPlacementPacket extends SimplePacketBase { + + private int h, v; + private BlockPos pos; + private Direction facing; + + public EjectorPlacementPacket(int h, int v, BlockPos pos, Direction facing) { + this.h = h; + this.v = v; + this.pos = pos; + this.facing = facing; + } + + public EjectorPlacementPacket(FriendlyByteBuf buffer) { + h = buffer.readInt(); + v = buffer.readInt(); + pos = buffer.readBlockPos(); + facing = Direction.from3DDataValue(buffer.readVarInt()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(h); + buffer.writeInt(v); + buffer.writeBlockPos(pos); + buffer.writeVarInt(facing.get3DDataValue()); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + Level world = player.level; + if (world == null || !world.isLoaded(pos)) + return; + BlockEntity blockEntity = world.getBlockEntity(pos); + BlockState state = world.getBlockState(pos); + if (blockEntity instanceof EjectorBlockEntity) + ((EjectorBlockEntity) blockEntity).setTarget(h, v); + if (AllBlocks.WEIGHTED_EJECTOR.has(state)) + world.setBlockAndUpdate(pos, state.setValue(EjectorBlock.HORIZONTAL_FACING, facing)); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorRenderer.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorRenderer.java new file mode 100644 index 0000000000..5c708ca042 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorRenderer.java @@ -0,0 +1,106 @@ +package com.simibubi.create.content.logistics.depot; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.base.ShaftRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.IntAttached; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.flw.Rotate; +import net.createmod.catnip.utility.flw.Translate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; + +public class EjectorRenderer extends ShaftRenderer { + + static final Vec3 pivot = VecHelper.voxelSpace(0, 11.25, 0.75); + + public EjectorRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + public boolean shouldRenderOffScreen(EjectorBlockEntity p_188185_1_) { + return true; + } + + @Override + protected void renderSafe(EjectorBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + VertexConsumer vertexBuilder = buffer.getBuffer(RenderType.solid()); + float lidProgress = be.getLidProgress(partialTicks); + float angle = lidProgress * 70; + + if (!Backend.canUseInstancing(be.getLevel())) { + SuperByteBuffer model = CachedPartialBuffers.partial(AllPartialModels.EJECTOR_TOP, be.getBlockState()); + applyLidAngle(be, angle, model); + model.light(light) + .renderInto(ms, vertexBuilder); + } + + TransformStack msr = TransformStack.cast(ms); + + float maxTime = + (float) (be.earlyTarget != null ? be.earlyTargetTime : be.launcher.getTotalFlyingTicks()); + for (IntAttached intAttached : be.launchedItems) { + float time = intAttached.getFirst() + partialTicks; + if (time > maxTime) + continue; + + ms.pushPose(); + Vec3 launchedItemLocation = be.getLaunchedItemLocation(time); + msr.translate(launchedItemLocation.subtract(Vec3.atLowerCornerOf(be.getBlockPos()))); + Vec3 itemRotOffset = VecHelper.voxelSpace(0, 3, 0); + msr.translate(itemRotOffset); + msr.rotateY(AngleHelper.horizontalAngle(be.getFacing())); + msr.rotateX(time * 40); + msr.translateBack(itemRotOffset); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(intAttached.getValue(), TransformType.GROUND, light, overlay, ms, buffer, 0); + ms.popPose(); + } + + DepotBehaviour behaviour = be.getBehaviour(DepotBehaviour.TYPE); + if (behaviour == null || behaviour.isEmpty()) + return; + + ms.pushPose(); + //applyLidAngle(be, angle, msr);//TODO flw + msr.centre() + .rotateY(-180 - AngleHelper.horizontalAngle(be.getBlockState() + .getValue(EjectorBlock.HORIZONTAL_FACING))) + .unCentre(); + DepotRenderer.renderItemsOf(be, partialTicks, ms, buffer, light, overlay, behaviour); + ms.popPose(); + } + + static & Rotate> void applyLidAngle(KineticBlockEntity be, float angle, T tr) { + applyLidAngle(be, pivot, angle, tr); + } + + static & Rotate> void applyLidAngle(KineticBlockEntity be, Vec3 rotationOffset, float angle, T tr) { + tr.centre() + .rotateY(180 + AngleHelper.horizontalAngle(be.getBlockState() + .getValue(EjectorBlock.HORIZONTAL_FACING))) + .unCentre() + .translate(rotationOffset) + .rotateX(-angle) + .translateBack(rotationOffset); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTargetHandler.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorTargetHandler.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTargetHandler.java rename to src/main/java/com/simibubi/create/content/logistics/depot/EjectorTargetHandler.java index a3c2075bef..be48249bbf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EjectorTargetHandler.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorTargetHandler.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.block.depot; +package com.simibubi.create.content.logistics.depot; import com.mojang.math.Vector3f; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.CatnipClient; import net.createmod.catnip.utility.AnimationTickHolder; @@ -120,7 +120,7 @@ public class EjectorTargetHandler { h = Math.abs(diff.getX() + diff.getZ()); v = -diff.getY(); - AllPackets.channel.sendToServer(new EjectorPlacementPacket(h, v, pos, validTargetDirection)); + AllPackets.getChannel().sendToServer(new EjectorPlacementPacket(h, v, pos, validTargetDirection)); currentSelection = null; currentItem = null; @@ -134,7 +134,7 @@ public class EjectorTargetHandler { int xDiff = currentSelection.getX() - pos.getX(); int zDiff = currentSelection.getZ() - pos.getZ(); - int max = AllConfigs.SERVER.kinetics.maxEjectorDistance.get(); + int max = AllConfigs.server().kinetics.maxEjectorDistance.get(); if (Math.abs(xDiff) > max || Math.abs(zDiff) > max) return null; @@ -234,15 +234,15 @@ public class EjectorTargetHandler { BlockHitResult result = (BlockHitResult) objectMouseOver; BlockPos pos = result.getBlockPos(); - BlockEntity te = Minecraft.getInstance().level.getBlockEntity(pos); - if (!(te instanceof EjectorTileEntity)) { + BlockEntity be = Minecraft.getInstance().level.getBlockEntity(pos); + if (!(be instanceof EjectorBlockEntity)) { lastHoveredBlockPos = -1; currentSelection = null; return; } if (lastHoveredBlockPos == -1 || lastHoveredBlockPos != pos.asLong()) { - EjectorTileEntity ejector = (EjectorTileEntity) te; + EjectorBlockEntity ejector = (EjectorBlockEntity) be; if (!ejector.getTargetPosition() .equals(ejector.getBlockPos())) currentSelection = ejector.getTargetPosition(); diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/EjectorTriggerPacket.java b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorTriggerPacket.java new file mode 100644 index 0000000000..94e359149d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EjectorTriggerPacket.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class EjectorTriggerPacket extends BlockEntityConfigurationPacket { + + public EjectorTriggerPacket(BlockPos pos) { + super(pos); + } + + public EjectorTriggerPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) {} + + @Override + protected void readSettings(FriendlyByteBuf buffer) {} + + @Override + protected void applySettings(EjectorBlockEntity be) { + be.activate(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/EntityLauncher.java b/src/main/java/com/simibubi/create/content/logistics/depot/EntityLauncher.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/block/depot/EntityLauncher.java rename to src/main/java/com/simibubi/create/content/logistics/depot/EntityLauncher.java index 87619fabf4..f6a98136ee 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/EntityLauncher.java +++ b/src/main/java/com/simibubi/create/content/logistics/depot/EntityLauncher.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.depot; +package com.simibubi.create.content.logistics.depot; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; diff --git a/src/main/java/com/simibubi/create/content/logistics/depot/SharedDepotBlockMethods.java b/src/main/java/com/simibubi/create/content/logistics/depot/SharedDepotBlockMethods.java new file mode 100644 index 0000000000..9fea807494 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/depot/SharedDepotBlockMethods.java @@ -0,0 +1,106 @@ +package com.simibubi.create.content.logistics.depot; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.Create; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.items.ItemStackHandler; + +public class SharedDepotBlockMethods { + + protected static DepotBehaviour get(BlockGetter worldIn, BlockPos pos) { + return BlockEntityBehaviour.get(worldIn, pos, DepotBehaviour.TYPE); + } + + public static InteractionResult onUse(BlockState state, Level world, BlockPos pos, Player player, + InteractionHand hand, BlockHitResult ray) { + if (ray.getDirection() != Direction.UP) + return InteractionResult.PASS; + if (world.isClientSide) + return InteractionResult.SUCCESS; + + DepotBehaviour behaviour = get(world, pos); + if (behaviour == null) + return InteractionResult.PASS; + if (!behaviour.canAcceptItems.get()) + return InteractionResult.SUCCESS; + + ItemStack heldItem = player.getItemInHand(hand); + boolean wasEmptyHanded = heldItem.isEmpty(); + boolean shouldntPlaceItem = AllBlocks.MECHANICAL_ARM.isIn(heldItem); + + ItemStack mainItemStack = behaviour.getHeldItemStack(); + if (!mainItemStack.isEmpty()) { + player.getInventory() + .placeItemBackInInventory(mainItemStack); + behaviour.removeHeldItem(); + world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, + 1f + Create.RANDOM.nextFloat()); + } + ItemStackHandler outputs = behaviour.processingOutputBuffer; + for (int i = 0; i < outputs.getSlots(); i++) + player.getInventory() + .placeItemBackInInventory(outputs.extractItem(i, 64, false)); + + if (!wasEmptyHanded && !shouldntPlaceItem) { + TransportedItemStack transported = new TransportedItemStack(heldItem); + transported.insertedFrom = player.getDirection(); + transported.prevBeltPosition = .25f; + transported.beltPosition = .25f; + behaviour.setHeldItem(transported); + player.setItemInHand(hand, ItemStack.EMPTY); + AllSoundEvents.DEPOT_SLIDE.playOnServer(world, pos); + } + + behaviour.blockEntity.notifyUpdate(); + return InteractionResult.SUCCESS; + } + + public static void onLanded(BlockGetter worldIn, Entity entityIn) { + if (!(entityIn instanceof ItemEntity)) + return; + if (!entityIn.isAlive()) + return; + if (entityIn.level.isClientSide) + return; + + ItemEntity itemEntity = (ItemEntity) entityIn; + DirectBeltInputBehaviour inputBehaviour = + BlockEntityBehaviour.get(worldIn, entityIn.blockPosition(), DirectBeltInputBehaviour.TYPE); + if (inputBehaviour == null) + return; + ItemStack remainder = inputBehaviour.handleInsertion(itemEntity.getItem(), Direction.DOWN, false); + itemEntity.setItem(remainder); + if (remainder.isEmpty()) + itemEntity.discard(); + } + + public static int getComparatorInputOverride(BlockState blockState, Level worldIn, BlockPos pos) { + DepotBehaviour depotBehaviour = get(worldIn, pos); + if (depotBehaviour == null) + return 0; + float f = depotBehaviour.getPresentStackSize(); + Integer max = depotBehaviour.maxStackSize.get(); + f = f / (max == 0 ? 64 : max); + return Mth.clamp(Mth.floor(f * 14.0F) + (f > 0 ? 1 : 0), 0, 15); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterMenu.java b/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterMenu.java new file mode 100644 index 0000000000..4a3d586250 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterMenu.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.logistics.filter; + +import com.simibubi.create.foundation.gui.menu.GhostItemMenu; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class AbstractFilterMenu extends GhostItemMenu { + + protected AbstractFilterMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + protected AbstractFilterMenu(MenuType type, int id, Inventory inv, ItemStack contentHolder) { + super(type, id, inv, contentHolder); + } + + @Override + public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { + if (slotId == playerInventory.selected && clickTypeIn != ClickType.THROW) + return; + super.clicked(slotId, dragType, clickTypeIn, player); + } + + @Override + protected boolean allowRepeats() { + return false; + } + + @Override + @OnlyIn(Dist.CLIENT) + protected ItemStack createOnClient(FriendlyByteBuf extraData) { + return extraData.readItem(); + } + + protected abstract int getPlayerInventoryXOffset(); + + protected abstract int getPlayerInventoryYOffset(); + + protected abstract void addFilterSlots(); + + @Override + protected void addSlots() { + addPlayerSlots(getPlayerInventoryXOffset(), getPlayerInventoryYOffset()); + addFilterSlots(); + } + + @Override + protected void saveData(ItemStack contentHolder) { + contentHolder.getOrCreateTag() + .put("Items", ghostInventory.serializeNBT()); + } + + @Override + public boolean stillValid(Player player) { + return playerInventory.getSelected() == contentHolder; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterScreen.java new file mode 100644 index 0000000000..0886408a33 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/AbstractFilterScreen.java @@ -0,0 +1,160 @@ +package com.simibubi.create.content.logistics.filter; + +import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; + +import java.util.Collections; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.logistics.filter.FilterScreenPacket.Option; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.Indicator; +import com.simibubi.create.foundation.gui.widget.Indicator.State; +import com.simibubi.create.foundation.item.TooltipHelper; + +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.FontHelper.Palette; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Inventory; + +public abstract class AbstractFilterScreen extends AbstractSimiContainerScreen { + + protected AllGuiTextures background; + private List extraAreas = Collections.emptyList(); + + private IconButton resetButton; + private IconButton confirmButton; + + protected AbstractFilterScreen(F menu, Inventory inv, Component title, AllGuiTextures background) { + super(menu, inv, title); + this.background = background; + } + + @Override + protected void init() { + setWindowSize(Math.max(background.getWidth(), PLAYER_INVENTORY.getWidth()), + background.getHeight() + 4 + PLAYER_INVENTORY.getHeight()); + super.init(); + + int x = leftPos; + int y = topPos; + + resetButton = new IconButton(x + background.getWidth() - 62, y + background.getHeight() - 24, AllIcons.I_TRASH); + resetButton.withCallback(() -> { + menu.clearContents(); + contentsCleared(); + menu.sendClearPacket(); + }); + confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(() -> { + minecraft.player.closeContainer(); + }); + + addRenderableWidget(resetButton); + addRenderableWidget(confirmButton); + + extraAreas = ImmutableList.of(new Rect2i(x + background.getWidth(), y + background.getHeight() - 40, 80, 48)); + } + + @Override + protected void renderBg(PoseStack ms, float partialTicks, int mouseX, int mouseY) { + int invX = getLeftOfCentered(PLAYER_INVENTORY.getWidth()); + int invY = topPos + background.getHeight() + 4; + renderPlayerInventory(ms, invX, invY); + + int x = leftPos; + int y = topPos; + + background.render(ms, x, y, this); + font.draw(ms, title, x + (background.getWidth() - 8) / 2 - font.width(title) / 2, y + 4, + AllItems.FILTER.isIn(menu.contentHolder) ? 0x303030 : 0x592424); + + GuiGameElement.of(menu.contentHolder) + .scale(4) + .at(x + background.getWidth() + 8, y + background.getHeight() - 52, -200) + .render(ms); + } + + @Override + protected void containerTick() { + if (!menu.player.getMainHandItem() + .equals(menu.contentHolder, false)) + menu.player.closeContainer(); + + super.containerTick(); + + handleTooltips(); + handleIndicators(); + } + + protected void handleTooltips() { + List tooltipButtons = getTooltipButtons(); + + for (IconButton button : tooltipButtons) { + if (!button.getToolTip() + .isEmpty()) { + button.setToolTip(button.getToolTip() + .get(0)); + button.getToolTip() + .add(TooltipHelper.holdShift(Palette.YELLOW, hasShiftDown())); + } + } + + if (hasShiftDown()) { + List tooltipDescriptions = getTooltipDescriptions(); + for (int i = 0; i < tooltipButtons.size(); i++) + fillToolTip(tooltipButtons.get(i), tooltipDescriptions.get(i)); + } + } + + public void handleIndicators() { + for (IconButton button : getTooltipButtons()) + button.active = isButtonEnabled(button); + for (Indicator indicator : getIndicators()) + indicator.state = isIndicatorOn(indicator) ? State.ON : State.OFF; + } + + protected abstract boolean isButtonEnabled(IconButton button); + + protected abstract boolean isIndicatorOn(Indicator indicator); + + protected List getTooltipButtons() { + return Collections.emptyList(); + } + + protected List getTooltipDescriptions() { + return Collections.emptyList(); + } + + protected List getIndicators() { + return Collections.emptyList(); + } + + private void fillToolTip(IconButton button, Component tooltip) { + if (!button.isHoveredOrFocused()) + return; + List tip = button.getToolTip(); + tip.addAll(TooltipHelper.cutTextComponent(tooltip, Palette.ALL_GRAY)); + } + + protected void contentsCleared() {} + + protected void sendOptionUpdate(Option option) { + AllPackets.getChannel() + .sendToServer(new FilterScreenPacket(option)); + } + + @Override + public List getExtraAreas() { + return extraAreas; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterMenu.java b/src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterMenu.java new file mode 100644 index 0000000000..12a3fbc625 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterMenu.java @@ -0,0 +1,163 @@ +package com.simibubi.create.content.logistics.filter; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.AllMenuTypes; + +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class AttributeFilterMenu extends AbstractFilterMenu { + + public enum WhitelistMode { + WHITELIST_DISJ, WHITELIST_CONJ, BLACKLIST; + } + + WhitelistMode whitelistMode; + List> selectedAttributes; + + public AttributeFilterMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public AttributeFilterMenu(MenuType type, int id, Inventory inv, ItemStack stack) { + super(type, id, inv, stack); + } + + public static AttributeFilterMenu create(int id, Inventory inv, ItemStack stack) { + return new AttributeFilterMenu(AllMenuTypes.ATTRIBUTE_FILTER.get(), id, inv, stack); + } + + public void appendSelectedAttribute(ItemAttribute itemAttribute, boolean inverted) { + selectedAttributes.add(Pair.of(itemAttribute, inverted)); + } + + @Override + protected void init(Inventory inv, ItemStack contentHolder) { + super.init(inv, contentHolder); + ItemStack stack = new ItemStack(Items.NAME_TAG); + stack.setHoverName( + Components.literal("Selected Tags").withStyle(ChatFormatting.RESET, ChatFormatting.BLUE)); + ghostInventory.setStackInSlot(1, stack); + } + + @Override + protected int getPlayerInventoryXOffset() { + return 51; + } + + @Override + protected int getPlayerInventoryYOffset() { + return 107; + } + + @Override + protected void addFilterSlots() { + this.addSlot(new SlotItemHandler(ghostInventory, 0, 16, 24)); + this.addSlot(new SlotItemHandler(ghostInventory, 1, 22, 59) { + @Override + public boolean mayPickup(Player playerIn) { + return false; + } + }); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return new ItemStackHandler(2); + } + + @Override + public void clearContents() { + selectedAttributes.clear(); + } + + @Override + public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { + if (slotId == 37) + return; + super.clicked(slotId, dragType, clickTypeIn, player); + } + + @Override + public boolean canDragTo(Slot slotIn) { + if (slotIn.index == 37) + return false; + return super.canDragTo(slotIn); + } + + @Override + public boolean canTakeItemForPickAll(ItemStack stack, Slot slotIn) { + if (slotIn.index == 37) + return false; + return super.canTakeItemForPickAll(stack, slotIn); + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + if (index == 37) + return ItemStack.EMPTY; + if (index == 36) { + ghostInventory.setStackInSlot(37, ItemStack.EMPTY); + return ItemStack.EMPTY; + } + if (index < 36) { + ItemStack stackToInsert = playerInventory.getItem(index); + ItemStack copy = stackToInsert.copy(); + copy.setCount(1); + ghostInventory.setStackInSlot(0, copy); + } + return ItemStack.EMPTY; + } + + @Override + protected void initAndReadInventory(ItemStack filterItem) { + super.initAndReadInventory(filterItem); + selectedAttributes = new ArrayList<>(); + whitelistMode = WhitelistMode.values()[filterItem.getOrCreateTag() + .getInt("WhitelistMode")]; + ListTag attributes = filterItem.getOrCreateTag() + .getList("MatchedAttributes", Tag.TAG_COMPOUND); + attributes.forEach(inbt -> { + CompoundTag compound = (CompoundTag) inbt; + selectedAttributes.add(Pair.of(ItemAttribute.fromNBT(compound), compound.getBoolean("Inverted"))); + }); + } + + @Override + protected void saveData(ItemStack filterItem) { + filterItem.getOrCreateTag() + .putInt("WhitelistMode", whitelistMode.ordinal()); + ListTag attributes = new ListTag(); + selectedAttributes.forEach(at -> { + if (at == null) + return; + CompoundTag compoundNBT = new CompoundTag(); + at.getFirst() + .serializeNBT(compoundNBT); + compoundNBT.putBoolean("Inverted", at.getSecond()); + attributes.add(compoundNBT); + }); + filterItem.getOrCreateTag() + .put("MatchedAttributes", attributes); + + if (attributes.isEmpty() && whitelistMode == WhitelistMode.WHITELIST_DISJ) + filterItem.setTag(null); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterScreen.java similarity index 79% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java rename to src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterScreen.java index f7f7c33834..4fd178ad6d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/AttributeFilterScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item.filter; +package com.simibubi.create.content.logistics.filter; import java.util.ArrayList; import java.util.Arrays; @@ -6,15 +6,15 @@ import java.util.List; import java.util.stream.Collectors; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; +import com.simibubi.create.content.logistics.filter.FilterScreenPacket.Option; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Indicator; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; @@ -26,23 +26,23 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class AttributeFilterScreen extends AbstractFilterScreen { +public class AttributeFilterScreen extends AbstractFilterScreen { private static final String PREFIX = "gui.attribute_filter."; - private final Component addDESC = CreateLang.translateDirect(PREFIX + "add_attribute"); - private final Component addInvertedDESC = CreateLang.translateDirect(PREFIX + "add_inverted_attribute"); + private Component addDESC = CreateLang.translateDirect(PREFIX + "add_attribute"); + private Component addInvertedDESC = CreateLang.translateDirect(PREFIX + "add_inverted_attribute"); - private final Component allowDisN = CreateLang.translateDirect(PREFIX + "allow_list_disjunctive"); - private final Component allowDisDESC = CreateLang.translateDirect(PREFIX + "allow_list_disjunctive.description"); - private final Component allowConN = CreateLang.translateDirect(PREFIX + "allow_list_conjunctive"); - private final Component allowConDESC = CreateLang.translateDirect(PREFIX + "allow_list_conjunctive.description"); - private final Component denyN = CreateLang.translateDirect(PREFIX + "deny_list"); - private final Component denyDESC = CreateLang.translateDirect(PREFIX + "deny_list.description"); + private Component allowDisN = CreateLang.translateDirect(PREFIX + "allow_list_disjunctive"); + private Component allowDisDESC = CreateLang.translateDirect(PREFIX + "allow_list_disjunctive.description"); + private Component allowConN = CreateLang.translateDirect(PREFIX + "allow_list_conjunctive"); + private Component allowConDESC = CreateLang.translateDirect(PREFIX + "allow_list_conjunctive.description"); + private Component denyN = CreateLang.translateDirect(PREFIX + "deny_list"); + private Component denyDESC = CreateLang.translateDirect(PREFIX + "deny_list.description"); - private final Component referenceH = CreateLang.translateDirect(PREFIX + "add_reference_item"); - private final Component noSelectedT = CreateLang.translateDirect(PREFIX + "no_selected_attributes"); - private final Component selectedT = CreateLang.translateDirect(PREFIX + "selected_attributes"); + private Component referenceH = CreateLang.translateDirect(PREFIX + "add_reference_item"); + private Component noSelectedT = CreateLang.translateDirect(PREFIX + "no_selected_attributes"); + private Component selectedT = CreateLang.translateDirect(PREFIX + "selected_attributes"); private IconButton whitelistDis, whitelistCon, blacklist; private Indicator whitelistDisIndicator, whitelistConIndicator, blacklistIndicator; @@ -55,8 +55,8 @@ public class AttributeFilterScreen extends AbstractFilterScreen { menu.whitelistMode = WhitelistMode.WHITELIST_DISJ; sendOptionUpdate(Option.WHITELIST); }); whitelistDis.setToolTip(allowDisN); - whitelistCon = new IconButton(x + 65, y + 59, AllIcons.I_WHITELIST_AND); + whitelistCon = new IconButton(x + 65, y + 61, AllIcons.I_WHITELIST_AND); whitelistCon.withCallback(() -> { menu.whitelistMode = WhitelistMode.WHITELIST_CONJ; sendOptionUpdate(Option.WHITELIST2); }); whitelistCon.setToolTip(allowConN); - blacklist = new IconButton(x + 83, y + 59, AllIcons.I_WHITELIST_NOT); + blacklist = new IconButton(x + 83, y + 61, AllIcons.I_WHITELIST_NOT); blacklist.withCallback(() -> { menu.whitelistMode = WhitelistMode.BLACKLIST; sendOptionUpdate(Option.BLACKLIST); }); blacklist.setToolTip(denyN); - whitelistDisIndicator = new Indicator(x + 47, y + 53, Components.immutableEmpty()); - whitelistConIndicator = new Indicator(x + 65, y + 53, Components.immutableEmpty()); - blacklistIndicator = new Indicator(x + 83, y + 53, Components.immutableEmpty()); + whitelistDisIndicator = new Indicator(x + 47, y + 55, Components.immutableEmpty()); + whitelistConIndicator = new Indicator(x + 65, y + 55, Components.immutableEmpty()); + blacklistIndicator = new Indicator(x + 83, y + 55, Components.immutableEmpty()); addRenderableWidgets(blacklist, whitelistCon, whitelistDis, blacklistIndicator, whitelistConIndicator, whitelistDisIndicator); - addRenderableWidget(add = new IconButton(x + 182, y + 21, AllIcons.I_ADD)); - addRenderableWidget(addInverted = new IconButton(x + 200, y + 21, AllIcons.I_ADD_INVERTED_ATTRIBUTE)); + addRenderableWidget(add = new IconButton(x + 182, y + 23, AllIcons.I_ADD)); + addRenderableWidget(addInverted = new IconButton(x + 200, y + 23, AllIcons.I_ADD_INVERTED_ATTRIBUTE)); add.withCallback(() -> { handleAddedAttibute(false); }); @@ -106,9 +106,9 @@ public class AttributeFilterScreen extends AbstractFilterScreen makeSummary = makeSummary(stack); if (makeSummary.isEmpty()) return; - ItemDescription.add(tooltip, Components.literal(" ")); - ItemDescription.add(tooltip, makeSummary); + tooltip.add(Components.literal(" ")); + tooltip.addAll(makeSummary); } } private List makeSummary(ItemStack filter) { List list = new ArrayList<>(); + if (!filter.hasTag()) + return list; if (type == FilterType.REGULAR) { ItemStackHandler filterItems = getFilterItems(filter); boolean blacklist = filter.getOrCreateTag() .getBoolean("Blacklist"); - list.add((blacklist ? CreateLang.translateDirect("gui.filter.deny_list") : CreateLang.translateDirect("gui.filter.allow_list")).withStyle(ChatFormatting.GOLD)); + list.add((blacklist ? CreateLang.translateDirect("gui.filter.deny_list") + : CreateLang.translateDirect("gui.filter.allow_list")).withStyle(ChatFormatting.GOLD)); int count = 0; for (int i = 0; i < filterItems.getSlots(); i++) { if (count > 3) { - list.add(Components.literal("- ...").withStyle(ChatFormatting.DARK_GRAY)); + list.add(Components.literal("- ...") + .withStyle(ChatFormatting.DARK_GRAY)); break; } ItemStack filterStack = filterItems.getStackInSlot(i); if (filterStack.isEmpty()) continue; - list.add(Components.literal("- ").append(filterStack.getHoverName()).withStyle(ChatFormatting.GRAY)); + list.add(Components.literal("- ") + .append(filterStack.getHoverName()) + .withStyle(ChatFormatting.GRAY)); count++; } @@ -122,12 +127,16 @@ public class FilterItem extends Item implements MenuProvider { for (Tag inbt : attributes) { CompoundTag compound = (CompoundTag) inbt; ItemAttribute attribute = ItemAttribute.fromNBT(compound); + if (attribute == null) + continue; boolean inverted = compound.getBoolean("Inverted"); if (count > 3) { - list.add(Components.literal("- ...").withStyle(ChatFormatting.DARK_GRAY)); + list.add(Components.literal("- ...") + .withStyle(ChatFormatting.DARK_GRAY)); break; } - list.add(Components.literal("- ").append(attribute.format(inverted))); + list.add(Components.literal("- ") + .append(attribute.format(inverted))); count++; } @@ -156,9 +165,9 @@ public class FilterItem extends Item implements MenuProvider { public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { ItemStack heldItem = player.getMainHandItem(); if (type == FilterType.REGULAR) - return FilterContainer.create(id, inv, heldItem); + return FilterMenu.create(id, inv, heldItem); if (type == FilterType.ATTRIBUTE) - return AttributeFilterContainer.create(id, inv, heldItem); + return AttributeFilterMenu.create(id, inv, heldItem); return null; } @@ -171,6 +180,8 @@ public class FilterItem extends Item implements MenuProvider { ItemStackHandler newInv = new ItemStackHandler(18); if (AllItems.FILTER.get() != stack.getItem()) throw new IllegalArgumentException("Cannot get filter items from non-filter: " + stack); + if (!stack.hasTag()) + return newInv; CompoundTag invNBT = stack.getOrCreateTagElement("Items"); if (!invNBT.isEmpty()) newInv.deserializeNBT(invNBT); @@ -185,36 +196,53 @@ public class FilterItem extends Item implements MenuProvider { return test(world, stack, filter, true); } - private static boolean test(Level world, ItemStack stack, ItemStack filter, boolean matchNBT) { + public static boolean test(Level world, ItemStack stack, ItemStack filter, boolean matchNBT) { if (filter.isEmpty()) return true; if (!(filter.getItem() instanceof FilterItem)) - return (matchNBT ? ItemHandlerHelper.canItemStacksStack(filter, stack) - : ItemStack.isSame(filter, stack)); + return testDirect(filter, stack, matchNBT); + + boolean defaults = !filter.hasTag(); + + if (defaults) { + return testDirect(filter, stack, matchNBT); + } if (AllItems.FILTER.get() == filter.getItem()) { ItemStackHandler filterItems = getFilterItems(filter); - boolean respectNBT = filter.getOrCreateTag() - .getBoolean("RespectNBT"); - boolean blacklist = filter.getOrCreateTag() - .getBoolean("Blacklist"); + boolean respectNBT = defaults ? false + : filter.getTag() + .getBoolean("RespectNBT"); + boolean blacklist = defaults ? false + : filter.getTag() + .getBoolean("Blacklist"); + boolean isEmpty = true; for (int slot = 0; slot < filterItems.getSlots(); slot++) { ItemStack stackInSlot = filterItems.getStackInSlot(slot); if (stackInSlot.isEmpty()) continue; + isEmpty = false; boolean matches = test(world, stack, stackInSlot, respectNBT); if (matches) return !blacklist; } + if (isEmpty) { + return testDirect(filter, stack, matchNBT); + } return blacklist; } if (AllItems.ATTRIBUTE_FILTER.get() == filter.getItem()) { - WhitelistMode whitelistMode = WhitelistMode.values()[filter.getOrCreateTag() - .getInt("WhitelistMode")]; - ListTag attributes = filter.getOrCreateTag() - .getList("MatchedAttributes", Tag.TAG_COMPOUND); + ListTag attributes = defaults ? new ListTag() + : filter.getTag() + .getList("MatchedAttributes", Tag.TAG_COMPOUND); + if (attributes.isEmpty()) { + return testDirect(filter, stack, matchNBT); + } + WhitelistMode whitelistMode = WhitelistMode.values()[defaults ? 0 + : filter.getTag() + .getInt("WhitelistMode")]; for (Tag inbt : attributes) { CompoundTag compound = (CompoundTag) inbt; ItemAttribute attribute = ItemAttribute.fromNBT(compound); @@ -256,16 +284,16 @@ public class FilterItem extends Item implements MenuProvider { return false; } - private static boolean test(Level world, FluidStack stack, ItemStack filter, boolean matchNBT) { + public static boolean test(Level world, FluidStack stack, ItemStack filter, boolean matchNBT) { if (filter.isEmpty()) return true; if (stack.isEmpty()) return false; if (!(filter.getItem() instanceof FilterItem)) { - if (!EmptyingByBasin.canItemBeEmptied(world, filter)) + if (!GenericItemEmptying.canItemBeEmptied(world, filter)) return false; - FluidStack fluidInFilter = EmptyingByBasin.emptyItem(world, filter, true) + FluidStack fluidInFilter = GenericItemEmptying.emptyItem(world, filter, true) .getFirst(); if (fluidInFilter == null) return false; @@ -276,12 +304,16 @@ public class FilterItem extends Item implements MenuProvider { return fluidEqual; } + boolean defaults = !filter.hasTag(); + if (AllItems.FILTER.get() == filter.getItem()) { ItemStackHandler filterItems = getFilterItems(filter); - boolean respectNBT = filter.getOrCreateTag() - .getBoolean("RespectNBT"); - boolean blacklist = filter.getOrCreateTag() - .getBoolean("Blacklist"); + boolean respectNBT = defaults ? false + : filter.getTag() + .getBoolean("RespectNBT"); + boolean blacklist = defaults ? false + : filter.getTag() + .getBoolean("Blacklist"); for (int slot = 0; slot < filterItems.getSlots(); slot++) { ItemStack stackInSlot = filterItems.getStackInSlot(slot); if (stackInSlot.isEmpty()) @@ -295,4 +327,12 @@ public class FilterItem extends Item implements MenuProvider { return false; } + private static boolean testDirect(ItemStack filter, ItemStack stack, boolean matchNBT) { + if (matchNBT) { + return ItemHandlerHelper.canItemStacksStack(filter, stack); + } else { + return ItemStack.isSame(filter, stack); + } + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterMenu.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterMenu.java new file mode 100644 index 0000000000..29864709fd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterMenu.java @@ -0,0 +1,78 @@ +package com.simibubi.create.content.logistics.filter; + +import com.simibubi.create.AllMenuTypes; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class FilterMenu extends AbstractFilterMenu { + + boolean respectNBT; + boolean blacklist; + + public FilterMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public FilterMenu(MenuType type, int id, Inventory inv, ItemStack stack) { + super(type, id, inv, stack); + } + + public static FilterMenu create(int id, Inventory inv, ItemStack stack) { + return new FilterMenu(AllMenuTypes.FILTER.get(), id, inv, stack); + } + + @Override + protected int getPlayerInventoryXOffset() { + return 38; + } + + @Override + protected int getPlayerInventoryYOffset() { + return 121; + } + + @Override + protected void addFilterSlots() { + int x = 23; + int y = 22; + for (int row = 0; row < 2; ++row) + for (int col = 0; col < 9; ++col) + this.addSlot(new SlotItemHandler(ghostInventory, col + row * 9, x + col * 18, y + row * 18)); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return FilterItem.getFilterItems(contentHolder); + } + + @Override + protected void initAndReadInventory(ItemStack filterItem) { + super.initAndReadInventory(filterItem); + CompoundTag tag = filterItem.getOrCreateTag(); + respectNBT = tag.getBoolean("RespectNBT"); + blacklist = tag.getBoolean("Blacklist"); + } + + @Override + protected void saveData(ItemStack filterItem) { + super.saveData(filterItem); + CompoundTag tag = filterItem.getOrCreateTag(); + tag.putBoolean("RespectNBT", respectNBT); + tag.putBoolean("Blacklist", blacklist); + + if (respectNBT || blacklist) + return; + for (int i = 0; i < ghostInventory.getSlots(); i++) + if (!ghostInventory.getStackInSlot(i) + .isEmpty()) + return; + filterItem.setTag(null); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreen.java new file mode 100644 index 0000000000..179a2184eb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreen.java @@ -0,0 +1,125 @@ +package com.simibubi.create.content.logistics.filter; + +import java.util.Arrays; +import java.util.List; + +import com.simibubi.create.content.logistics.filter.FilterScreenPacket.Option; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.Indicator; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Inventory; + +public class FilterScreen extends AbstractFilterScreen { + + private static final String PREFIX = "gui.filter."; + + private Component allowN = CreateLang.translateDirect(PREFIX + "allow_list"); + private Component allowDESC = CreateLang.translateDirect(PREFIX + "allow_list.description"); + private Component denyN = CreateLang.translateDirect(PREFIX + "deny_list"); + private Component denyDESC = CreateLang.translateDirect(PREFIX + "deny_list.description"); + + private Component respectDataN = CreateLang.translateDirect(PREFIX + "respect_data"); + private Component respectDataDESC = CreateLang.translateDirect(PREFIX + "respect_data.description"); + private Component ignoreDataN = CreateLang.translateDirect(PREFIX + "ignore_data"); + private Component ignoreDataDESC = CreateLang.translateDirect(PREFIX + "ignore_data.description"); + + private IconButton whitelist, blacklist; + private IconButton respectNBT, ignoreNBT; + private Indicator whitelistIndicator, blacklistIndicator; + private Indicator respectNBTIndicator, ignoreNBTIndicator; + + public FilterScreen(FilterMenu menu, Inventory inv, Component title) { + super(menu, inv, title, AllGuiTextures.FILTER); + } + + @Override + protected void init() { + setWindowOffset(-11, 5); + super.init(); + + int x = leftPos; + int y = topPos; + + blacklist = new IconButton(x + 18, y + 75, AllIcons.I_BLACKLIST); + blacklist.withCallback(() -> { + menu.blacklist = true; + sendOptionUpdate(Option.BLACKLIST); + }); + blacklist.setToolTip(denyN); + whitelist = new IconButton(x + 36, y + 75, AllIcons.I_WHITELIST); + whitelist.withCallback(() -> { + menu.blacklist = false; + sendOptionUpdate(Option.WHITELIST); + }); + whitelist.setToolTip(allowN); + blacklistIndicator = new Indicator(x + 18, y + 69, Components.immutableEmpty()); + whitelistIndicator = new Indicator(x + 36, y + 69, Components.immutableEmpty()); + addRenderableWidgets(blacklist, whitelist, blacklistIndicator, whitelistIndicator); + + respectNBT = new IconButton(x + 60, y + 75, AllIcons.I_RESPECT_NBT); + respectNBT.withCallback(() -> { + menu.respectNBT = true; + sendOptionUpdate(Option.RESPECT_DATA); + }); + respectNBT.setToolTip(respectDataN); + ignoreNBT = new IconButton(x + 78, y + 75, AllIcons.I_IGNORE_NBT); + ignoreNBT.withCallback(() -> { + menu.respectNBT = false; + sendOptionUpdate(Option.IGNORE_DATA); + }); + ignoreNBT.setToolTip(ignoreDataN); + respectNBTIndicator = new Indicator(x + 60, y + 69, Components.immutableEmpty()); + ignoreNBTIndicator = new Indicator(x + 78, y + 69, Components.immutableEmpty()); + addRenderableWidgets(respectNBT, ignoreNBT, respectNBTIndicator, ignoreNBTIndicator); + + handleIndicators(); + } + + @Override + protected List getTooltipButtons() { + return Arrays.asList(blacklist, whitelist, respectNBT, ignoreNBT); + } + + @Override + protected List getTooltipDescriptions() { + return Arrays.asList(denyDESC.plainCopy(), allowDESC.plainCopy(), respectDataDESC.plainCopy(), ignoreDataDESC.plainCopy()); + } + + @Override + protected List getIndicators() { + return Arrays.asList(blacklistIndicator, whitelistIndicator, respectNBTIndicator, ignoreNBTIndicator); + } + + @Override + protected boolean isButtonEnabled(IconButton button) { + if (button == blacklist) + return !menu.blacklist; + if (button == whitelist) + return menu.blacklist; + if (button == respectNBT) + return !menu.respectNBT; + if (button == ignoreNBT) + return menu.respectNBT; + return true; + } + + @Override + protected boolean isIndicatorOn(Indicator indicator) { + if (indicator == blacklistIndicator) + return menu.blacklist; + if (indicator == whitelistIndicator) + return !menu.blacklist; + if (indicator == respectNBTIndicator) + return menu.respectNBT; + if (indicator == ignoreNBTIndicator) + return !menu.respectNBT; + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java similarity index 75% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java rename to src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java index 8b1b5440c1..2896d8abc9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreenPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java @@ -1,8 +1,6 @@ -package com.simibubi.create.content.logistics.item.filter; +package com.simibubi.create.content.logistics.filter; -import java.util.function.Supplier; - -import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; +import com.simibubi.create.content.logistics.filter.AttributeFilterMenu.WhitelistMode; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.nbt.CompoundTag; @@ -40,14 +38,14 @@ public class FilterScreenPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) return; - if (player.containerMenu instanceof FilterContainer) { - FilterContainer c = (FilterContainer) player.containerMenu; + if (player.containerMenu instanceof FilterMenu) { + FilterMenu c = (FilterMenu) player.containerMenu; if (option == Option.WHITELIST) c.blacklist = false; if (option == Option.BLACKLIST) @@ -62,8 +60,8 @@ public class FilterScreenPacket extends SimplePacketBase { net.minecraft.world.item.ItemStack.of(data.getCompound("Item"))); } - if (player.containerMenu instanceof AttributeFilterContainer) { - AttributeFilterContainer c = (AttributeFilterContainer) player.containerMenu; + if (player.containerMenu instanceof AttributeFilterMenu) { + AttributeFilterMenu c = (AttributeFilterMenu) player.containerMenu; if (option == Option.WHITELIST) c.whitelistMode = WhitelistMode.WHITELIST_DISJ; if (option == Option.WHITELIST2) @@ -77,7 +75,7 @@ public class FilterScreenPacket extends SimplePacketBase { } }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/ItemAttribute.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/ItemAttribute.java index 8d00977d68..a3c5aa50ef 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/ItemAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/ItemAttribute.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item.filter; +package com.simibubi.create.content.logistics.filter; import java.util.ArrayList; import java.util.Arrays; @@ -10,20 +10,21 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.InWorldProcessing; -import com.simibubi.create.content.logistics.item.filter.attribute.BookAuthorAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.BookCopyAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.ColorAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.EnchantAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.FluidContentsAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.ItemNameAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.ShulkerFillLevelAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery.AstralSorceryAmuletAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery.AstralSorceryAttunementAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery.AstralSorceryCrystalAttribute; -import com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery.AstralSorceryPerkGemAttribute; +import com.simibubi.create.content.kinetics.fan.FanProcessing; +import com.simibubi.create.content.logistics.filter.attribute.BookAuthorAttribute; +import com.simibubi.create.content.logistics.filter.attribute.BookCopyAttribute; +import com.simibubi.create.content.logistics.filter.attribute.ColorAttribute; +import com.simibubi.create.content.logistics.filter.attribute.EnchantAttribute; +import com.simibubi.create.content.logistics.filter.attribute.FluidContentsAttribute; +import com.simibubi.create.content.logistics.filter.attribute.ItemNameAttribute; +import com.simibubi.create.content.logistics.filter.attribute.ShulkerFillLevelAttribute; +import com.simibubi.create.content.logistics.filter.attribute.astralsorcery.AstralSorceryAmuletAttribute; +import com.simibubi.create.content.logistics.filter.attribute.astralsorcery.AstralSorceryAttunementAttribute; +import com.simibubi.create.content.logistics.filter.attribute.astralsorcery.AstralSorceryCrystalAttribute; +import com.simibubi.create.content.logistics.filter.attribute.astralsorcery.AstralSorceryPerkGemAttribute; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.lang.Lang; @@ -79,6 +80,7 @@ public interface ItemAttribute { return attributeType; } + @Nullable static ItemAttribute fromNBT(CompoundTag nbt) { for (ItemAttribute itemAttribute : types) if (itemAttribute.canRead(nbt)) @@ -139,13 +141,13 @@ public interface ItemAttribute { MAX_ENCHANTED(StandardTraits::maxEnchanted), RENAMED(ItemStack::hasCustomHoverName), DAMAGED(ItemStack::isDamaged), - BADLY_DAMAGED(s -> s.isDamaged() && s.getDamageValue() / s.getMaxDamage() > 3 / 4f), + BADLY_DAMAGED(s -> s.isDamaged() && (float) s.getDamageValue() / s.getMaxDamage() > 3 / 4f), NOT_STACKABLE(((Predicate) ItemStack::isStackable).negate()), EQUIPABLE(s -> LivingEntity.getEquipmentSlotForItem(s) .getType() != EquipmentSlot.Type.HAND), FURNACE_FUEL(AbstractFurnaceBlockEntity::isFuel), - WASHABLE(InWorldProcessing::isWashable), - HAUNTABLE(InWorldProcessing::isHauntable), + WASHABLE(FanProcessing::isWashable), + HAUNTABLE(FanProcessing::isHauntable), CRUSHABLE((s, w) -> testRecipe(s, w, AllRecipeTypes.CRUSHING.getType()) || testRecipe(s, w, AllRecipeTypes.MILLING.getType())), SMELTABLE((s, w) -> testRecipe(s, w, RecipeType.SMELTING)), diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookAuthorAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookAuthorAttribute.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookAuthorAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookAuthorAttribute.java index 9e7d8c026e..c0eaf419f5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookAuthorAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookAuthorAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookCopyAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookCopyAttribute.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookCopyAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookCopyAttribute.java index 88a3c7c87c..04a60b8b31 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/BookCopyAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/BookCopyAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ColorAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ColorAttribute.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ColorAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/ColorAttribute.java index cd524d4324..ec03bbae00 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ColorAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ColorAttribute.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.Arrays; import java.util.Collection; @@ -8,7 +8,7 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.client.resources.language.I18n; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/EnchantAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/EnchantAttribute.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/EnchantAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/EnchantAttribute.java index 0420742ad8..15c52704ef 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/EnchantAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/EnchantAttribute.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.List; import java.util.stream.Collectors; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/FluidContentsAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/FluidContentsAttribute.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/FluidContentsAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/FluidContentsAttribute.java index 8bcac6099d..ce2758d877 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/FluidContentsAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/FluidContentsAttribute.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.ArrayList; import java.util.List; @@ -6,7 +6,7 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ItemNameAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ItemNameAttribute.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ItemNameAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/ItemNameAttribute.java index ab3ff572b8..83bab8d968 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ItemNameAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ItemNameAttribute.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.ArrayList; import java.util.List; import com.google.gson.JsonParseException; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ShulkerFillLevelAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ShulkerFillLevelAttribute.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ShulkerFillLevelAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/ShulkerFillLevelAttribute.java index acc594a16f..a128597c7b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/ShulkerFillLevelAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/ShulkerFillLevelAttribute.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item.filter.attribute; +package com.simibubi.create.content.logistics.filter.attribute; import java.util.Arrays; import java.util.List; @@ -7,7 +7,7 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.core.NonNullList; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java index bcfa6414e2..68f132c840 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAmuletAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery; +package com.simibubi.create.content.logistics.filter.attribute.astralsorcery; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java index 88d3630ee8..bbcbe65191 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryAttunementAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery; +package com.simibubi.create.content.logistics.filter.attribute.astralsorcery; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java index 19c5f5a478..8ec6b1d1c1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryCrystalAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery; +package com.simibubi.create.content.logistics.filter.attribute.astralsorcery; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java rename to src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java index 1609dcb95f..beacd4e8a9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/attribute/astralsorcery/AstralSorceryPerkGemAttribute.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.item.filter.attribute.astralsorcery; +package com.simibubi.create.content.logistics.filter.attribute.astralsorcery; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.filter.ItemAttribute; import net.createmod.catnip.utility.lang.Components; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/flap/FlapData.java b/src/main/java/com/simibubi/create/content/logistics/flwdata/FlapData.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/block/flap/FlapData.java rename to src/main/java/com/simibubi/create/content/logistics/flwdata/FlapData.java index 591f0160cb..6c616eefba 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/flap/FlapData.java +++ b/src/main/java/com/simibubi/create/content/logistics/flwdata/FlapData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.flap; +package com.simibubi.create.content.logistics.flwdata; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.core.materials.FlatLit; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/flap/FlapType.java b/src/main/java/com/simibubi/create/content/logistics/flwdata/FlapType.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/flap/FlapType.java rename to src/main/java/com/simibubi/create/content/logistics/flwdata/FlapType.java index 1745d78db4..42adae76ed 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/flap/FlapType.java +++ b/src/main/java/com/simibubi/create/content/logistics/flwdata/FlapType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.flap; +package com.simibubi.create.content.logistics.flwdata; import com.jozufozu.flywheel.api.struct.Batched; import com.jozufozu.flywheel.api.struct.Instanced; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/flap/UnsafeFlapWriter.java b/src/main/java/com/simibubi/create/content/logistics/flwdata/UnsafeFlapWriter.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/flap/UnsafeFlapWriter.java rename to src/main/java/com/simibubi/create/content/logistics/flwdata/UnsafeFlapWriter.java index 345fde063b..4ca7961d5d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/flap/UnsafeFlapWriter.java +++ b/src/main/java/com/simibubi/create/content/logistics/flwdata/UnsafeFlapWriter.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.flap; +package com.simibubi.create.content.logistics.flwdata; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/simibubi/create/content/logistics/flwdata/package-info.java b/src/main/java/com/simibubi/create/content/logistics/flwdata/package-info.java new file mode 100644 index 0000000000..5f4c5ce95a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/flwdata/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.simibubi.create.content.logistics.flwdata; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractDirectionalFunnelBlock.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/AbstractDirectionalFunnelBlock.java index 9fabd9a115..2d7627ed89 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractDirectionalFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractDirectionalFunnelBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import net.minecraft.core.Direction; import net.minecraft.world.level.block.Block; diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractFunnelBlock.java new file mode 100644 index 0000000000..a93e017c94 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractFunnelBlock.java @@ -0,0 +1,162 @@ +package com.simibubi.create.content.logistics.funnel; + +import java.util.Random; +import java.util.function.Consumer; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.IBlockRenderProperties; + +public abstract class AbstractFunnelBlock extends Block + implements IBE, IWrenchable, ProperWaterloggedBlock { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + protected AbstractFunnelBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + registerDefaultState(defaultBlockState().setValue(POWERED, false) + .setValue(WATERLOGGED, false)); + } + + @OnlyIn(Dist.CLIENT) + public void initializeClient(Consumer consumer) { + consumer.accept(new ReducedDestroyEffects()); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return withWater(defaultBlockState().setValue(POWERED, context.getLevel() + .hasNeighborSignal(context.getClickedPos())), context); + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(POWERED, WATERLOGGED)); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + if (worldIn.isClientSide) + return; + InvManipulationBehaviour behaviour = BlockEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + if (behaviour != null) + behaviour.onNeighborChanged(fromPos); + if (!worldIn.getBlockTicks() + .willTickThisTick(pos, this)) + worldIn.scheduleTick(pos, this, 0); + } + + @Override + public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random r) { + boolean previouslyPowered = state.getValue(POWERED); + if (previouslyPowered != worldIn.hasNeighborSignal(pos)) + worldIn.setBlock(pos, state.cycle(POWERED), 2); + } + + public static ItemStack tryInsert(Level worldIn, BlockPos pos, ItemStack toInsert, boolean simulate) { + FilteringBehaviour filter = BlockEntityBehaviour.get(worldIn, pos, FilteringBehaviour.TYPE); + InvManipulationBehaviour inserter = BlockEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + if (inserter == null) + return toInsert; + if (filter != null && !filter.test(toInsert)) + return toInsert; + if (simulate) + inserter.simulate(); + ItemStack insert = inserter.insert(toInsert); + + if (!simulate && insert.getCount() != toInsert.getCount()) { + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (blockEntity instanceof FunnelBlockEntity) { + FunnelBlockEntity funnelBlockEntity = (FunnelBlockEntity) blockEntity; + funnelBlockEntity.onTransfer(toInsert); + if (funnelBlockEntity.hasFlap()) + funnelBlockEntity.flap(true); + } + } + return insert; + } + + @Override + public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + Block block = world.getBlockState(pos.relative(getFunnelFacing(state).getOpposite())) + .getBlock(); + return !(block instanceof AbstractFunnelBlock); + } + + @Nullable + public static boolean isFunnel(BlockState state) { + return state.getBlock() instanceof AbstractFunnelBlock; + } + + @Nullable + public static Direction getFunnelFacing(BlockState state) { + if (!(state.getBlock() instanceof AbstractFunnelBlock)) + return null; + return ((AbstractFunnelBlock) state.getBlock()).getFacing(state); + } + + protected abstract Direction getFacing(BlockState state); + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + if (state.getBlock() != newState.getBlock() && !isFunnel(newState) || !newState.hasBlockEntity()) + IBE.onRemove(state, world, pos, newState); + } + + @Override + public Class getBlockEntityClass() { + return FunnelBlockEntity.class; + } + + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.FUNNEL.get(); + }; + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractHorizontalFunnelBlock.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/AbstractHorizontalFunnelBlock.java index 7e1b030739..368d6dfd4d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AbstractHorizontalFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/AbstractHorizontalFunnelBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import net.minecraft.core.Direction; import net.minecraft.world.level.block.Block; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/AndesiteFunnelBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/AndesiteFunnelBlock.java index 26792cf23e..239fe3cad1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/AndesiteFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/AndesiteFunnelBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import com.simibubi.create.AllBlocks; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelBlock.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelBlock.java index bf1def8548..538cb80808 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BeltFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelBlock.java @@ -1,14 +1,15 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.tterrag.registrate.util.entry.BlockEntry; import net.createmod.catnip.utility.VoxelShaper; @@ -71,6 +72,17 @@ public class BeltFunnelBlock extends AbstractHorizontalFunnelBlock implements IS super.createBlockStateDefinition(p_206840_1_.add(SHAPE)); } + public boolean isOfSameType(FunnelBlock otherFunnel) { + return parent.get() == otherFunnel; + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + if (newState.getBlock() instanceof FunnelBlock fb && isOfSameType(fb)) + return; + super.onRemove(state, world, pos, newState, isMoving); + } + @Override public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_, CollisionContext p_220053_4_) { @@ -121,8 +133,9 @@ public class BeltFunnelBlock extends AbstractHorizontalFunnelBlock implements IS @Override public BlockState updateShape(BlockState state, Direction direction, BlockState neighbour, LevelAccessor world, BlockPos pos, BlockPos p_196271_6_) { + updateWater(world, state, pos); if (!isOnValidBelt(state, world, pos)) { - BlockState parentState = parent.getDefaultState(); + BlockState parentState = ProperWaterloggedBlock.withWater(world, parent.getDefaultState(), pos); if (state.getOptionalValue(POWERED) .orElse(false)) parentState = parentState.setValue(POWERED, true); @@ -150,7 +163,7 @@ public class BeltFunnelBlock extends AbstractHorizontalFunnelBlock implements IS if ((stateBelow.getBlock() instanceof BeltBlock)) return BeltBlock.canTransportObjects(stateBelow); DirectBeltInputBehaviour directBeltInputBehaviour = - TileEntityBehaviour.get(world, pos.below(), DirectBeltInputBehaviour.TYPE); + BlockEntityBehaviour.get(world, pos.below(), DirectBeltInputBehaviour.TYPE); if (directBeltInputBehaviour == null) return false; return directBeltInputBehaviour.canSupportBeltFunnels(); @@ -196,8 +209,8 @@ public class BeltFunnelBlock extends AbstractHorizontalFunnelBlock implements IS } @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return ItemRequirement.of(parent.getDefaultState(), te); + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + return ItemRequirement.of(parent.getDefaultState(), be); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelGenerator.java b/src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelGenerator.java new file mode 100644 index 0000000000..3f3468d530 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/BeltFunnelGenerator.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.logistics.funnel; + +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraftforge.client.model.generators.ModelFile; + +public class BeltFunnelGenerator extends SpecialBlockStateGen { + + private String type; + private ResourceLocation materialBlockTexture; + + public BeltFunnelGenerator(String type) { + this.type = type; + this.materialBlockTexture = Create.asResource("block/" + type + "_block"); + } + + @Override + protected int getXRotation(BlockState state) { + return 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.getValue(BeltFunnelBlock.HORIZONTAL_FACING)) + 180; + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + String prefix = "block/funnel/"; + Shape shape = state.getValue(BeltFunnelBlock.SHAPE); + String shapeName = shape.getSerializedName(); + boolean powered = state.getOptionalValue(BlockStateProperties.POWERED) + .orElse(false); + String poweredSuffix = powered ? "_powered" : "_unpowered"; + String shapeSuffix = shape == Shape.PULLING ? "_pull" : shape == Shape.PUSHING ? "_push" : "_neutral"; + String name = ctx.getName() + "_" + shapeName + poweredSuffix; + + return prov.models() + .withExistingParent(name, prov.modLoc("block/belt_funnel/block_" + shapeName)) + .texture("particle", materialBlockTexture) + .texture("block", materialBlockTexture) + .texture("direction", prov.modLoc(prefix + type + "_funnel" + shapeSuffix)) + .texture("redstone", prov.modLoc(prefix + type + "_funnel" + poweredSuffix)) + .texture("base", prov.modLoc(prefix + type + "_funnel")); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/BrassFunnelBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/BrassFunnelBlock.java index 18a5fa81af..a9e273fbdd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/BrassFunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/BrassFunnelBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import com.simibubi.create.AllBlocks; @@ -12,7 +12,7 @@ public class BrassFunnelBlock extends FunnelBlock { public BrassFunnelBlock(Properties p_i48415_1_) { super(p_i48415_1_); } - + @Override public BlockState getEquivalentBeltFunnel(BlockGetter world, BlockPos pos, BlockState state) { Direction facing = getFacing(state); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlock.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlock.java index f20236d408..3c5eb5d781 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlock.java @@ -1,9 +1,10 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -64,6 +65,13 @@ public abstract class FunnelBlock extends AbstractDirectionalFunnelBlock { super.createBlockStateDefinition(builder.add(EXTRACTING)); } + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + if (newState.getBlock() instanceof BeltFunnelBlock bfb && bfb.isOfSameType(this)) + return; + super.onRemove(state, world, pos, newState, isMoving); + } + @Override public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); @@ -82,7 +90,7 @@ public abstract class FunnelBlock extends AbstractDirectionalFunnelBlock { if (hit.getDirection() == getFunnelFacing(state) && !shouldntInsertItem) { if (!worldIn.isClientSide) - withTileEntityDo(worldIn, pos, te -> { + withBlockEntityDo(worldIn, pos, be -> { ItemStack toInsert = heldItem.copy(); ItemStack remainder = tryInsert(worldIn, pos, toInsert, false); if (!ItemStack.matches(remainder, toInsert)) @@ -156,10 +164,12 @@ public abstract class FunnelBlock extends AbstractDirectionalFunnelBlock { @Override public BlockState updateShape(BlockState state, Direction direction, BlockState p_196271_3_, LevelAccessor world, BlockPos pos, BlockPos p_196271_6_) { + updateWater(world, state, pos); if (getFacing(state).getAxis() .isVertical() || direction != Direction.DOWN) return state; - BlockState equivalentFunnel = getEquivalentBeltFunnel(null, null, state); + BlockState equivalentFunnel = + ProperWaterloggedBlock.withWater(world, getEquivalentBeltFunnel(null, null, state), pos); if (BeltFunnelBlock.isOnValidBelt(equivalentFunnel, world, pos)) return equivalentFunnel.setValue(BeltFunnelBlock.SHAPE, BeltFunnelBlock.getShapeForPosition(world, pos, getFacing(state), state.getValue(EXTRACTING))); diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java new file mode 100644 index 0000000000..a2ad3eeb73 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelBlockEntity.java @@ -0,0 +1,356 @@ +package com.simibubi.create.content.logistics.funnel; + +import java.lang.ref.WeakReference; +import java.util.List; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.equipment.goggles.IHaveHoveringInformation; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.BlockFace; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class FunnelBlockEntity extends SmartBlockEntity implements IHaveHoveringInformation { + + private FilteringBehaviour filtering; + private InvManipulationBehaviour invManipulation; + private int extractionCooldown; + + private WeakReference lastObserved; // In-world Extractors only + + LerpedFloat flap; + + static enum Mode { + INVALID, PAUSED, COLLECT, PUSHING_TO_BELT, TAKING_FROM_BELT, EXTRACT + } + + public FunnelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + extractionCooldown = 0; + flap = createChasingFlap(); + } + + public Mode determineCurrentMode() { + BlockState state = getBlockState(); + if (!FunnelBlock.isFunnel(state)) + return Mode.INVALID; + if (state.getOptionalValue(BlockStateProperties.POWERED) + .orElse(false)) + return Mode.PAUSED; + if (state.getBlock() instanceof BeltFunnelBlock) { + Shape shape = state.getValue(BeltFunnelBlock.SHAPE); + if (shape == Shape.PULLING) + return Mode.TAKING_FROM_BELT; + if (shape == Shape.PUSHING) + return Mode.PUSHING_TO_BELT; + + BeltBlockEntity belt = BeltHelper.getSegmentBE(level, worldPosition.below()); + if (belt != null) + return belt.getMovementFacing() == state.getValue(BeltFunnelBlock.HORIZONTAL_FACING) + ? Mode.PUSHING_TO_BELT + : Mode.TAKING_FROM_BELT; + return Mode.INVALID; + } + if (state.getBlock() instanceof FunnelBlock) + return state.getValue(FunnelBlock.EXTRACTING) ? Mode.EXTRACT : Mode.COLLECT; + + return Mode.INVALID; + } + + @Override + public void tick() { + super.tick(); + flap.tickChaser(); + Mode mode = determineCurrentMode(); + if (level.isClientSide) + return; + + // Redstone resets the extraction cooldown + if (mode == Mode.PAUSED) + extractionCooldown = 0; + if (mode == Mode.TAKING_FROM_BELT) + return; + + if (extractionCooldown > 0) { + extractionCooldown--; + return; + } + + if (mode == Mode.PUSHING_TO_BELT) + activateExtractingBeltFunnel(); + if (mode == Mode.EXTRACT) + activateExtractor(); + } + + private void activateExtractor() { + BlockState blockState = getBlockState(); + Direction facing = AbstractFunnelBlock.getFunnelFacing(blockState); + + if (facing == null) + return; + + boolean trackingEntityPresent = true; + AABB area = getEntityOverflowScanningArea(); + + // Check if last item is still blocking the extractor + if (lastObserved == null) { + trackingEntityPresent = false; + } else { + ItemEntity lastEntity = lastObserved.get(); + if (lastEntity == null || !lastEntity.isAlive() || !lastEntity.getBoundingBox() + .intersects(area)) { + trackingEntityPresent = false; + lastObserved = null; + } + } + + if (trackingEntityPresent) + return; + + // Find other entities blocking the extract (only if necessary) + int amountToExtract = getAmountToExtract(); + ExtractionCountMode mode = getModeToExtract(); + ItemStack stack = invManipulation.simulate() + .extract(mode, amountToExtract); + if (stack.isEmpty()) + return; + for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, area)) { + lastObserved = new WeakReference<>(itemEntity); + return; + } + + // Extract + stack = invManipulation.extract(mode, amountToExtract); + if (stack.isEmpty()) + return; + + flap(false); + onTransfer(stack); + + Vec3 outputPos = VecHelper.getCenterOf(worldPosition); + boolean vertical = facing.getAxis() + .isVertical(); + boolean up = facing == Direction.UP; + + outputPos = outputPos.add(Vec3.atLowerCornerOf(facing.getNormal()) + .scale(vertical ? up ? .15f : .5f : .25f)); + if (!vertical) + outputPos = outputPos.subtract(0, .45f, 0); + + Vec3 motion = Vec3.ZERO; + if (up) + motion = new Vec3(0, 4 / 16f, 0); + + ItemEntity item = new ItemEntity(level, outputPos.x, outputPos.y, outputPos.z, stack.copy()); + item.setDefaultPickUpDelay(); + item.setDeltaMovement(motion); + level.addFreshEntity(item); + lastObserved = new WeakReference<>(item); + + startCooldown(); + } + + static final AABB coreBB = new AABB(VecHelper.CENTER_OF_ORIGIN, VecHelper.CENTER_OF_ORIGIN).inflate(.75f); + + private AABB getEntityOverflowScanningArea() { + Direction facing = AbstractFunnelBlock.getFunnelFacing(getBlockState()); + AABB bb = coreBB.move(worldPosition); + if (facing == null || facing == Direction.UP) + return bb; + return bb.expandTowards(0, -1, 0); + } + + private void activateExtractingBeltFunnel() { + BlockState blockState = getBlockState(); + Direction facing = blockState.getValue(BeltFunnelBlock.HORIZONTAL_FACING); + DirectBeltInputBehaviour inputBehaviour = + BlockEntityBehaviour.get(level, worldPosition.below(), DirectBeltInputBehaviour.TYPE); + + if (inputBehaviour == null) + return; + if (!inputBehaviour.canInsertFromSide(facing)) + return; + + int amountToExtract = getAmountToExtract(); + ExtractionCountMode mode = getModeToExtract(); + ItemStack stack = + invManipulation.extract(mode, amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true) + .isEmpty()); + if (stack.isEmpty()) + return; + flap(false); + onTransfer(stack); + inputBehaviour.handleInsertion(stack, facing, false); + startCooldown(); + } + + public int getAmountToExtract() { + if (!supportsAmountOnFilter()) + return 64; + int amountToExtract = invManipulation.getAmountFromFilter(); + if (!filtering.isActive()) + amountToExtract = 1; + return amountToExtract; + } + + public ExtractionCountMode getModeToExtract() { + if (!supportsAmountOnFilter() || !filtering.isActive()) + return ExtractionCountMode.UPTO; + return invManipulation.getModeFromFilter(); + } + + private int startCooldown() { + return extractionCooldown = AllConfigs.server().logistics.defaultExtractionTimer.get(); + } + + @Override + public void addBehaviours(List behaviours) { + invManipulation = + new InvManipulationBehaviour(this, (w, p, s) -> new BlockFace(p, AbstractFunnelBlock.getFunnelFacing(s) + .getOpposite())); + behaviours.add(invManipulation); + + filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()); + filtering.showCountWhen(this::supportsAmountOnFilter); + filtering.onlyActiveWhen(this::supportsFiltering); + behaviours.add(filtering); + + behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput) + .setInsertionHandler(this::handleDirectBeltInput)); + registerAwardables(behaviours, AllAdvancements.FUNNEL); + } + + private boolean supportsAmountOnFilter() { + BlockState blockState = getBlockState(); + boolean beltFunnelsupportsAmount = false; + if (blockState.getBlock() instanceof BeltFunnelBlock) { + Shape shape = blockState.getValue(BeltFunnelBlock.SHAPE); + if (shape == Shape.PUSHING) + beltFunnelsupportsAmount = true; + else + beltFunnelsupportsAmount = BeltHelper.getSegmentBE(level, worldPosition.below()) != null; + } + boolean extractor = blockState.getBlock() instanceof FunnelBlock && blockState.getValue(FunnelBlock.EXTRACTING); + return beltFunnelsupportsAmount || extractor; + } + + private boolean supportsDirectBeltInput(Direction side) { + BlockState blockState = getBlockState(); + if (blockState == null) + return false; + if (!(blockState.getBlock() instanceof FunnelBlock)) + return false; + if (blockState.getValue(FunnelBlock.EXTRACTING)) + return false; + return FunnelBlock.getFunnelFacing(blockState) == Direction.UP; + } + + private boolean supportsFiltering() { + BlockState blockState = getBlockState(); + return AllBlocks.BRASS_BELT_FUNNEL.has(blockState) || AllBlocks.BRASS_FUNNEL.has(blockState); + } + + private ItemStack handleDirectBeltInput(TransportedItemStack stack, Direction side, boolean simulate) { + ItemStack inserted = stack.stack; + if (!filtering.test(inserted)) + return inserted; + if (determineCurrentMode() == Mode.PAUSED) + return inserted; + if (simulate) + invManipulation.simulate(); + if (!simulate) + onTransfer(inserted); + return invManipulation.insert(inserted); + } + + public void flap(boolean inward) { + if (!level.isClientSide) { + AllPackets.getChannel() + .send(packetTarget(), new FunnelFlapPacket(this, inward)); + } else { + flap.setValue(inward ? 1 : -1); + AllSoundEvents.FUNNEL_FLAP.playAt(level, worldPosition, 1, 1, true); + } + } + + public boolean hasFlap() { + BlockState blockState = getBlockState(); + if (!AbstractFunnelBlock.getFunnelFacing(blockState) + .getAxis() + .isHorizontal()) + return false; + return true; + } + + public float getFlapOffset() { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BeltFunnelBlock)) + return -1 / 16f; + switch (blockState.getValue(BeltFunnelBlock.SHAPE)) { + default: + case RETRACTED: + return 0; + case EXTENDED: + return 8 / 16f; + case PULLING: + case PUSHING: + return -2 / 16f; + } + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.putInt("TransferCooldown", extractionCooldown); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + extractionCooldown = compound.getInt("TransferCooldown"); + + if (clientPacket) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + } + + public void onTransfer(ItemStack stack) { + AllBlocks.SMART_OBSERVER.get() + .onFunnelTransfer(level, worldPosition, stack); + award(AllAdvancements.FUNNEL); + } + + private LerpedFloat createChasingFlap() { + return LerpedFloat.linear() + .startWithValue(.25f) + .chase(0, .05f, Chaser.EXP); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFilterSlotPositioning.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFilterSlotPositioning.java index 109230fa9a..e55b57f777 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelFilterSlotPositioning.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFilterSlotPositioning.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; @@ -15,7 +15,7 @@ import net.minecraft.world.phys.Vec3; public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { @Override - protected Vec3 getLocalOffset(BlockState state) { + public Vec3 getLocalOffset(BlockState state) { Direction side = getSide(); float horizontalAngle = AngleHelper.horizontalAngle(side); Direction funnelFacing = FunnelBlock.getFunnelFacing(state); @@ -28,7 +28,7 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 15.5f, 13), stateAngle, Axis.Y); case PULLING: case PUSHING: - return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y); + return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.0f, 8.675f), horizontalAngle, Axis.Y); default: case RETRACTED: return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 13, 7.5f), horizontalAngle, Axis.Y); @@ -41,11 +41,11 @@ public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided { return VecHelper.rotateCentered(southLocation, horizontalAngle, Axis.Y); } - return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.1, 8.7f), horizontalAngle, Axis.Y); + return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 12.2, 8.55f), horizontalAngle, Axis.Y); } @Override - protected void rotate(BlockState state, PoseStack ms) { + public void rotate(BlockState state, PoseStack ms) { Direction facing = FunnelBlock.getFunnelFacing(state); if (facing.getAxis() diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFlapPacket.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFlapPacket.java new file mode 100644 index 0000000000..b403a527d0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelFlapPacket.java @@ -0,0 +1,31 @@ +package com.simibubi.create.content.logistics.funnel; + +import com.simibubi.create.foundation.networking.BlockEntityDataPacket; + +import net.minecraft.network.FriendlyByteBuf; + +public class FunnelFlapPacket extends BlockEntityDataPacket { + + private final boolean inwards; + + public FunnelFlapPacket(FriendlyByteBuf buffer) { + super(buffer); + + inwards = buffer.readBoolean(); + } + + public FunnelFlapPacket(FunnelBlockEntity blockEntity, boolean inwards) { + super(blockEntity.getBlockPos()); + this.inwards = inwards; + } + + @Override + protected void writeData(FriendlyByteBuf buffer) { + buffer.writeBoolean(inwards); + } + + @Override + protected void handlePacket(FunnelBlockEntity blockEntity) { + blockEntity.flap(inwards); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelGenerator.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelGenerator.java new file mode 100644 index 0000000000..67d130ff6c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelGenerator.java @@ -0,0 +1,81 @@ +package com.simibubi.create.content.logistics.funnel; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; +import com.tterrag.registrate.providers.RegistrateItemModelProvider; +import com.tterrag.registrate.util.nullness.NonNullBiConsumer; + +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.generators.BlockModelBuilder; +import net.minecraftforge.client.model.generators.ModelFile; + +public class FunnelGenerator extends SpecialBlockStateGen { + + private String type; + private ResourceLocation blockTexture; + private boolean hasFilter; + + public FunnelGenerator(String type, boolean hasFilter) { + this.type = type; + this.hasFilter = hasFilter; + this.blockTexture = Create.asResource("block/" + type + "_block"); + } + + @Override + protected int getXRotation(BlockState state) { + return state.getValue(FunnelBlock.FACING) == Direction.DOWN ? 180 : 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.getValue(FunnelBlock.FACING)) + 180; + } + + @Override + public ModelFile getModel(DataGenContext c, RegistrateBlockstateProvider p, + BlockState s) { + String prefix = "block/funnel/"; + String powered = s.getValue(FunnelBlock.POWERED) ? "_powered" : "_unpowered"; + String closed = s.getValue(FunnelBlock.POWERED) ? "_closed" : "_open"; + String extracting = s.getValue(FunnelBlock.EXTRACTING) ? "_push" : "_pull"; + Direction facing = s.getValue(FunnelBlock.FACING); + boolean horizontal = facing.getAxis() + .isHorizontal(); + String parent = horizontal ? "horizontal" : hasFilter ? "vertical" : "vertical_filterless"; + + BlockModelBuilder model = p.models() + .withExistingParent("block/" + type + "_funnel_" + parent + extracting + powered, + p.modLoc(prefix + "block_" + parent)) + .texture("particle", blockTexture) + .texture("base", p.modLoc(prefix + type + "_funnel")) + .texture("redstone", p.modLoc(prefix + type + "_funnel" + powered)) + .texture("direction", p.modLoc(prefix + type + "_funnel" + extracting)); + + if (horizontal) + return model.texture("block", blockTexture); + + return model.texture("frame", p.modLoc(prefix + type + "_funnel_frame")) + .texture("open", p.modLoc(prefix + "funnel" + closed)); + } + + public static NonNullBiConsumer, RegistrateItemModelProvider> itemModel( + String type) { + String prefix = "block/funnel/"; + ResourceLocation blockTexture = Create.asResource("block/" + type + "_block"); + return (c, p) -> { + p.withExistingParent("item/" + type + "_funnel", p.modLoc("block/funnel/item")) + .texture("particle", blockTexture) + .texture("block", blockTexture) + .texture("base", p.modLoc(prefix + type + "_funnel")) + .texture("direction", p.modLoc(prefix + type + "_funnel_neutral")) + .texture("redstone", p.modLoc(prefix + type + "_funnel_unpowered")); + }; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelInstance.java new file mode 100644 index 0000000000..7a1a6283f0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelInstance.java @@ -0,0 +1,87 @@ +package com.simibubi.create.content.logistics.funnel; + +import java.util.ArrayList; + +import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.api.Instancer; +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.logistics.flwdata.FlapData; +import com.simibubi.create.foundation.render.AllMaterialSpecs; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.minecraft.core.Direction; +import net.minecraft.world.level.LightLayer; + +public class FunnelInstance extends BlockEntityInstance implements DynamicInstance { + + private final ArrayList flaps; + + public FunnelInstance(MaterialManager materialManager, FunnelBlockEntity blockEntity) { + super(materialManager, blockEntity); + + flaps = new ArrayList<>(4); + + if (!blockEntity.hasFlap()) return; + + PartialModel flapPartial = (blockState.getBlock() instanceof FunnelBlock ? AllPartialModels.FUNNEL_FLAP + : AllPartialModels.BELT_FUNNEL_FLAP); + Instancer model = materialManager.defaultSolid() + .material(AllMaterialSpecs.FLAPS) + .getModel(flapPartial, blockState); + + int blockLight = world.getBrightness(LightLayer.BLOCK, pos); + int skyLight = world.getBrightness(LightLayer.SKY, pos); + + Direction direction = FunnelBlock.getFunnelFacing(blockState); + + float flapness = blockEntity.flap.getValue(AnimationTickHolder.getPartialTicks()); + float horizontalAngle = direction.getOpposite().toYRot(); + + for (int segment = 0; segment <= 3; segment++) { + float intensity = segment == 3 ? 1.5f : segment + 1; + float segmentOffset = -3.05f / 16f * segment + 0.075f / 16f; + + FlapData key = model.createInstance(); + + key.setPosition(getInstancePosition()) + .setSegmentOffset(segmentOffset, 0, -blockEntity.getFlapOffset()) + .setBlockLight(blockLight) + .setSkyLight(skyLight) + .setHorizontalAngle(horizontalAngle) + .setFlapness(flapness) + .setFlapScale(-1) + .setPivotVoxelSpace(0, 10, 9.5f) + .setIntensity(intensity); + + flaps.add(key); + } + } + + @Override + public void beginFrame() { + if (flaps == null) return; + + float flapness = blockEntity.flap.getValue(AnimationTickHolder.getPartialTicks()); + + for (FlapData flap : flaps) { + flap.setFlapness(flapness); + } + } + + @Override + public void updateLight() { + if (flaps != null) + relight(pos, flaps.stream()); + } + + @Override + public void remove() { + if (flaps == null) return; + + flaps.forEach(InstanceData::delete); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelItem.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/FunnelItem.java index 7376cff5d0..1e5eecbe39 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java similarity index 80% rename from src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java index 5928c04039..9178f36848 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelMovementBehaviour.java @@ -1,11 +1,10 @@ -package com.simibubi.create.content.logistics.block.funnel; +package com.simibubi.create.content.logistics.funnel; import java.util.List; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.logistics.filter.FilterItem; import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.core.BlockPos; @@ -73,12 +72,14 @@ public class FunnelMovementBehaviour implements MovementBehaviour { return; ItemStack filter = getFilter(context); - int filterAmount = context.tileData.getInt("FilterAmount"); + int filterAmount = context.blockEntityData.getInt("FilterAmount"); + boolean upTo = context.blockEntityData.getBoolean("UpTo"); if (filterAmount <= 0) - filterAmount = hasFilter ? AllConfigs.SERVER.logistics.defaultExtractionLimit.get() : 1; + filterAmount = hasFilter ? 64 : 1; ItemStack extract = ItemHelper.extract(context.contraption.getSharedInventory(), - s -> FilterItem.test(world, s, filter), ItemHelper.ExtractionCountMode.UPTO, filterAmount, false); + s -> FilterItem.test(world, s, filter), + upTo ? ItemHelper.ExtractionCountMode.UPTO : ItemHelper.ExtractionCountMode.EXACTLY, filterAmount, false); if (extract.isEmpty()) return; @@ -119,12 +120,12 @@ public class FunnelMovementBehaviour implements MovementBehaviour { } @Override - public boolean renderAsNormalTileEntity() { + public boolean renderAsNormalBlockEntity() { return true; } private ItemStack getFilter(MovementContext context) { - return hasFilter ? ItemStack.of(context.tileData.getCompound("Filter")) : ItemStack.EMPTY; + return hasFilter ? ItemStack.of(context.blockEntityData.getCompound("Filter")) : ItemStack.EMPTY; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelRenderer.java b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelRenderer.java new file mode 100644 index 0000000000..27179aa22d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/funnel/FunnelRenderer.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.logistics.funnel; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class FunnelRenderer extends SmartBlockEntityRenderer { + + public FunnelRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(FunnelBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (!be.hasFlap() || Backend.canUseInstancing(be.getLevel())) + return; + + BlockState blockState = be.getBlockState(); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + PartialModel partialModel = (blockState.getBlock() instanceof FunnelBlock ? AllPartialModels.FUNNEL_FLAP + : AllPartialModels.BELT_FUNNEL_FLAP); + SuperByteBuffer flapBuffer = CachedPartialBuffers.partial(partialModel, blockState); + Vec3 pivot = VecHelper.voxelSpace(0, 10, 9.5f); + TransformStack msr = TransformStack.cast(ms); + + float horizontalAngle = AngleHelper.horizontalAngle(FunnelBlock.getFunnelFacing(blockState) + .getOpposite()); + float f = be.flap.getValue(partialTicks); + + ms.pushPose(); + msr.centre() + .rotateY(horizontalAngle) + .unCentre(); + ms.translate(0.075f / 16f, 0, -be.getFlapOffset()); + + for (int segment = 0; segment <= 3; segment++) { + ms.pushPose(); + + float intensity = segment == 3 ? 1.5f : segment + 1; + float abs = Math.abs(f); + float flapAngle = Mth.sin((float) ((1 - abs) * Math.PI * intensity)) * 30 * -f; + if (f > 0) + flapAngle *= .5f; + + msr.translate(pivot) + .rotateX(flapAngle) + .translateBack(pivot); + + flapBuffer.light(light) + .renderInto(ms, vb); + + ms.popPose(); + ms.translate(-3.05f / 16f, 0, 0); + } + ms.popPose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerBlock.java b/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerBlock.java deleted file mode 100644 index 7df57cf9da..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerBlock.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.simibubi.create.content.logistics.item; - -import java.util.ArrayList; - -import com.simibubi.create.AllItems; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.block.ITE; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LecternBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; - -public class LecternControllerBlock extends LecternBlock - implements ITE, ISpecialBlockItemRequirement { - - public LecternControllerBlock(Properties properties) { - super(properties); - registerDefaultState(defaultBlockState().setValue(HAS_BOOK, true)); - } - - @Override - public Class getTileEntityClass() { - return LecternControllerTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.LECTERN_CONTROLLER.get(); - } - - @Override - public BlockEntity newBlockEntity(BlockPos p_153573_, BlockState p_153574_) { - return ITE.super.newBlockEntity(p_153573_, p_153574_); - } - - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, - BlockHitResult hit) { - if (!player.isShiftKeyDown() && LecternControllerTileEntity.playerInRange(player, world, pos)) { - if (!world.isClientSide) - withTileEntityDo(world, pos, te -> te.tryStartUsing(player)); - return InteractionResult.SUCCESS; - } - - if (player.isShiftKeyDown()) { - if (!world.isClientSide) - replaceWithLectern(state, world, pos); - return InteractionResult.SUCCESS; - } - - return InteractionResult.PASS; - } - - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - if (!state.is(newState.getBlock())) { - if (!world.isClientSide) - withTileEntityDo(world, pos, te -> te.dropController(state)); - - super.onRemove(state, world, pos, newState, isMoving); - } - } - - @Override - public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { - return 15; - } - - public void replaceLectern(BlockState lecternState, Level world, BlockPos pos, ItemStack controller) { - world.setBlockAndUpdate(pos, defaultBlockState().setValue(FACING, lecternState.getValue(FACING)) - .setValue(POWERED, lecternState.getValue(POWERED))); - withTileEntityDo(world, pos, te -> te.setController(controller)); - } - - public void replaceWithLectern(BlockState state, Level world, BlockPos pos) { - AllSoundEvents.CONTROLLER_TAKE.playOnServer(world, pos); - world.setBlockAndUpdate(pos, Blocks.LECTERN.defaultBlockState() - .setValue(FACING, state.getValue(FACING)) - .setValue(POWERED, state.getValue(POWERED))); - } - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { - return Blocks.LECTERN.getCloneItemStack(state, target, world, pos, player); - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - ArrayList requiredItems = new ArrayList<>(); - requiredItems.add(new ItemStack(Blocks.LECTERN)); - requiredItems.add(new ItemStack(AllItems.LINKED_CONTROLLER.get())); - return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, requiredItems); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerRenderer.java b/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerRenderer.java deleted file mode 100644 index b9841c9cdc..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerRenderer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.simibubi.create.content.logistics.item; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.Direction; -import net.minecraft.world.item.ItemStack; - -public class LecternControllerRenderer extends SafeTileEntityRenderer { - - public LecternControllerRenderer(BlockEntityRendererProvider.Context context) { - } - - @Override - protected void renderSafe(LecternControllerTileEntity te, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - - ItemStack stack = AllItems.LINKED_CONTROLLER.asStack(); - TransformType transformType = TransformType.NONE; - LinkedControllerModel mainModel = (LinkedControllerModel) Minecraft.getInstance() - .getItemRenderer() - .getModel(stack, te.getLevel(), null, 0); - PartialItemModelRenderer renderer = PartialItemModelRenderer.of(stack, transformType, ms, buffer, overlay); - boolean active = te.hasUser(); - boolean renderDepression = te.isUsedBy(Minecraft.getInstance().player); - - Direction facing = te.getBlockState().getValue(LecternControllerBlock.FACING); - TransformStack msr = TransformStack.cast(ms); - - ms.pushPose(); - msr.translate(0.5, 1.45, 0.5); - msr.rotateY(AngleHelper.horizontalAngle(facing) - 90); - msr.translate(0.28, 0, 0); - msr.rotateZ(-22.0); - LinkedControllerItemRenderer.renderInLectern(stack, mainModel, renderer, transformType, ms, light, active, renderDepression); - ms.popPose(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerTileEntity.java deleted file mode 100644 index d67868a236..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/LecternControllerTileEntity.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.simibubi.create.content.logistics.item; - -import java.util.List; -import java.util.UUID; - -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.fml.DistExecutor; - -public class LecternControllerTileEntity extends SmartTileEntity { - - private ItemStack controller; - private UUID user; - private UUID prevUser; // used only on client - private boolean deactivatedThisTick; // used only on server - - public LecternControllerTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - super.write(compound, clientPacket); - compound.put("Controller", controller.save(new CompoundTag())); - if (user != null) - compound.putUUID("User", user); - } - - @Override - public void writeSafe(CompoundTag compound) { - super.writeSafe(compound); - compound.put("Controller", controller.save(new CompoundTag())); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); - controller = ItemStack.of(compound.getCompound("Controller")); - user = compound.hasUUID("User") ? compound.getUUID("User") : null; - } - - public ItemStack getController() { - return controller; - } - - public boolean hasUser() { return user != null; } - - public boolean isUsedBy(Player player) { - return hasUser() && user.equals(player.getUUID()); - } - - public void tryStartUsing(Player player) { - if (!deactivatedThisTick && !hasUser() && !playerIsUsingLectern(player) && playerInRange(player, level, worldPosition)) - startUsing(player); - } - - public void tryStopUsing(Player player) { - if (isUsedBy(player)) - stopUsing(player); - } - - private void startUsing(Player player) { - user = player.getUUID(); - player.getPersistentData().putBoolean("IsUsingLecternController", true); - sendData(); - } - - private void stopUsing(Player player) { - user = null; - if (player != null) - player.getPersistentData().remove("IsUsingLecternController"); - deactivatedThisTick = true; - sendData(); - } - - public static boolean playerIsUsingLectern(Player player) { - return player.getPersistentData().contains("IsUsingLecternController"); - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::tryToggleActive); - prevUser = user; - } - - if (!level.isClientSide) { - deactivatedThisTick = false; - - if (!(level instanceof ServerLevel)) - return; - if (user == null) - return; - - Entity entity = ((ServerLevel) level).getEntity(user); - if (!(entity instanceof Player)) { - stopUsing(null); - return; - } - - Player player = (Player) entity; - if (!playerInRange(player, level, worldPosition) || !playerIsUsingLectern(player)) - stopUsing(player); - } - } - - @OnlyIn(Dist.CLIENT) - private void tryToggleActive() { - if (user == null && Minecraft.getInstance().player.getUUID().equals(prevUser)) { - LinkedControllerClientHandler.deactivateInLectern(); - } else if (prevUser == null && Minecraft.getInstance().player.getUUID().equals(user)) { - LinkedControllerClientHandler.activateInLectern(worldPosition); - } - } - - public void setController(ItemStack newController) { - controller = newController; - if (newController != null) { - AllSoundEvents.CONTROLLER_PUT.playOnServer(level, worldPosition); - } - } - - public void swapControllers(ItemStack stack, Player player, InteractionHand hand, BlockState state) { - ItemStack newController = stack.copy(); - stack.setCount(0); - if (player.getItemInHand(hand).isEmpty()) { - player.setItemInHand(hand, controller); - } else { - dropController(state); - } - setController(newController); - } - - public void dropController(BlockState state) { - Entity playerEntity = ((ServerLevel) level).getEntity(user); - if (playerEntity instanceof Player) - stopUsing((Player) playerEntity); - - Direction dir = state.getValue(LecternControllerBlock.FACING); - double x = worldPosition.getX() + 0.5 + 0.25*dir.getStepX(); - double y = worldPosition.getY() + 1; - double z = worldPosition.getZ() + 0.5 + 0.25*dir.getStepZ(); - ItemEntity itementity = new ItemEntity(level, x, y, z, controller.copy()); - itementity.setDefaultPickUpDelay(); - level.addFreshEntity(itementity); - controller = null; - } - - public static boolean playerInRange(Player player, Level world, BlockPos pos) { - //double modifier = world.isRemote ? 0 : 1.0; - double reach = 0.4*player.getAttributeValue(ForgeMod.REACH_DISTANCE.get());// + modifier; - return player.distanceToSqr(Vec3.atCenterOf(pos)) < reach*reach; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerContainer.java deleted file mode 100644 index ab08fd0a60..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerContainer.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.simibubi.create.content.logistics.item; - -import com.simibubi.create.AllContainerTypes; -import com.simibubi.create.foundation.gui.container.GhostItemContainer; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class LinkedControllerContainer extends GhostItemContainer { - - public LinkedControllerContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public LinkedControllerContainer(MenuType type, int id, Inventory inv, ItemStack filterItem) { - super(type, id, inv, filterItem); - } - - public static LinkedControllerContainer create(int id, Inventory inv, ItemStack filterItem) { - return new LinkedControllerContainer(AllContainerTypes.LINKED_CONTROLLER.get(), id, inv, filterItem); - } - - @Override - protected ItemStack createOnClient(FriendlyByteBuf extraData) { - return extraData.readItem(); - } - - @Override - protected ItemStackHandler createGhostInventory() { - return LinkedControllerItem.getFrequencyItems(contentHolder); - } - - @Override - protected void addSlots() { - addPlayerSlots(8, 131); - - int x = 12; - int y = 34; - int slot = 0; - - for (int column = 0; column < 6; column++) { - for (int row = 0; row < 2; ++row) - addSlot(new SlotItemHandler(ghostInventory, slot++, x, y + row * 18)); - x += 24; - if (column == 3) - x += 11; - } - } - - @Override - protected void saveData(ItemStack contentHolder) { - contentHolder.getOrCreateTag() - .put("Items", ghostInventory.serializeNBT()); - } - - @Override - protected boolean allowRepeats() { - return true; - } - - @Override - public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { - if (slotId == playerInventory.selected && clickTypeIn != ClickType.THROW) - return; - super.clicked(slotId, dragType, clickTypeIn, player); - } - - @Override - public boolean stillValid(Player playerIn) { - return playerInventory.getSelected() == contentHolder; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerModel.java b/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerModel.java deleted file mode 100644 index 7b3784d6ed..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerModel.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.simibubi.create.content.logistics.item; - -import com.simibubi.create.foundation.item.render.CreateCustomRenderedItemModel; - -import net.minecraft.client.resources.model.BakedModel; - -public class LinkedControllerModel extends CreateCustomRenderedItemModel { - - public LinkedControllerModel(BakedModel template) { - super(template, "linked_controller"); - addPartials("powered", "button"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java deleted file mode 100644 index 614e61d8bf..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterContainer.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.simibubi.create.content.logistics.item.filter; - -import com.simibubi.create.foundation.gui.container.GhostItemContainer; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public abstract class AbstractFilterContainer extends GhostItemContainer { - - protected AbstractFilterContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - protected AbstractFilterContainer(MenuType type, int id, Inventory inv, ItemStack contentHolder) { - super(type, id, inv, contentHolder); - } - - @Override - public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { - if (slotId == playerInventory.selected && clickTypeIn != ClickType.THROW) - return; - super.clicked(slotId, dragType, clickTypeIn, player); - } - - @Override - protected boolean allowRepeats() { - return false; - } - - @Override - @OnlyIn(Dist.CLIENT) - protected ItemStack createOnClient(FriendlyByteBuf extraData) { - return extraData.readItem(); - } - - protected abstract int getPlayerInventoryXOffset(); - - protected abstract int getPlayerInventoryYOffset(); - - protected abstract void addFilterSlots(); - - @Override - protected void addSlots() { - addPlayerSlots(getPlayerInventoryXOffset(), getPlayerInventoryYOffset()); - addFilterSlots(); - } - - @Override - protected void saveData(ItemStack contentHolder) { - contentHolder.getOrCreateTag() - .put("Items", ghostInventory.serializeNBT()); - } - - @Override - public boolean stillValid(Player player) { - return playerInventory.getSelected() == contentHolder; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java deleted file mode 100644 index a145db03f2..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.simibubi.create.content.logistics.item.filter; - -import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; -import static net.minecraft.ChatFormatting.GRAY; - -import java.util.Collections; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; -import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.gui.widget.Indicator; -import com.simibubi.create.foundation.gui.widget.Indicator.State; -import com.simibubi.create.foundation.item.ItemDescription.Palette; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.networking.AllPackets; - -import net.createmod.catnip.gui.element.GuiGameElement; -import net.createmod.catnip.utility.FontHelper; -import net.minecraft.client.renderer.Rect2i; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.entity.player.Inventory; - -public abstract class AbstractFilterScreen extends AbstractSimiContainerScreen { - - protected AllGuiTextures background; - private List extraAreas = Collections.emptyList(); - - private IconButton resetButton; - private IconButton confirmButton; - - protected AbstractFilterScreen(F container, Inventory inv, Component title, AllGuiTextures background) { - super(container, inv, title); - this.background = background; - } - - @Override - protected void init() { - setWindowSize(Math.max(background.getWidth(), PLAYER_INVENTORY.getWidth()), background.getHeight() + 4 + PLAYER_INVENTORY.getHeight()); - super.init(); - - int x = leftPos; - int y = topPos; - - resetButton = new IconButton(x + background.getWidth() - 62, y + background.getHeight() - 24, AllIcons.I_TRASH); - resetButton.withCallback(() -> { - menu.clearContents(); - contentsCleared(); - menu.sendClearPacket(); - }); - confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); - confirmButton.withCallback(() -> { - minecraft.player.closeContainer(); - }); - - addRenderableWidget(resetButton); - addRenderableWidget(confirmButton); - - extraAreas = ImmutableList.of( - new Rect2i(x + background.getWidth(), y + background.getHeight() - 40, 80, 48) - ); - } - - @Override - protected void renderBg(PoseStack ms, float partialTicks, int mouseX, int mouseY) { - int invX = getLeftOfCentered(PLAYER_INVENTORY.getWidth()); - int invY = topPos + background.getHeight() + 4; - renderPlayerInventory(ms, invX, invY); - - int x = leftPos; - int y = topPos; - - background.render(ms, x, y, this); - drawCenteredString(ms, font, title, x + (background.getWidth() - 8) / 2, y + 3, 0xFFFFFF); - - GuiGameElement.of(menu.contentHolder) - .at(x + background.getWidth(), y + background.getHeight() - 56, -200) - .scale(5) - .render(ms); - } - - @Override - protected void containerTick() { - if (!menu.player.getMainHandItem() - .equals(menu.contentHolder, false)) - menu.player.closeContainer(); - - super.containerTick(); - - handleTooltips(); - handleIndicators(); - } - - protected void handleTooltips() { - List tooltipButtons = getTooltipButtons(); - - for (IconButton button : tooltipButtons) { - if (!button.getToolTip() - .isEmpty()) { - button.setToolTip(button.getToolTip() - .get(0)); - button.getToolTip() - .add(TooltipHelper.holdShift(Palette.Yellow, hasShiftDown())); - } - } - - if (hasShiftDown()) { - List tooltipDescriptions = getTooltipDescriptions(); - for (int i = 0; i < tooltipButtons.size(); i++) - fillToolTip(tooltipButtons.get(i), tooltipDescriptions.get(i)); - } - } - - public void handleIndicators() { - for (IconButton button : getTooltipButtons()) - button.active = isButtonEnabled(button); - for (Indicator indicator : getIndicators()) - indicator.state = isIndicatorOn(indicator) ? State.ON : State.OFF; - } - - protected abstract boolean isButtonEnabled(IconButton button); - - protected abstract boolean isIndicatorOn(Indicator indicator); - - protected List getTooltipButtons() { - return Collections.emptyList(); - } - - protected List getTooltipDescriptions() { - return Collections.emptyList(); - } - - protected List getIndicators() { - return Collections.emptyList(); - } - - private void fillToolTip(IconButton button, Component tooltip) { - if (!button.isHoveredOrFocused()) - return; - List tip = button.getToolTip(); - tip.addAll(FontHelper.cutTextComponent(tooltip, GRAY, GRAY)); - } - - protected void contentsCleared() {} - - protected void sendOptionUpdate(Option option) { - AllPackets.channel.sendToServer(new FilterScreenPacket(option)); - } - - @Override - public List getExtraAreas() { - return extraAreas; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java deleted file mode 100644 index 7bd0cfd847..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AttributeFilterContainer.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.simibubi.create.content.logistics.item.filter; - -import java.util.ArrayList; -import java.util.List; - -import com.simibubi.create.AllContainerTypes; - -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class AttributeFilterContainer extends AbstractFilterContainer { - - public enum WhitelistMode { - WHITELIST_DISJ, WHITELIST_CONJ, BLACKLIST; - } - - WhitelistMode whitelistMode; - List> selectedAttributes; - - public AttributeFilterContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public AttributeFilterContainer(MenuType type, int id, Inventory inv, ItemStack stack) { - super(type, id, inv, stack); - } - - public static AttributeFilterContainer create(int id, Inventory inv, ItemStack stack) { - return new AttributeFilterContainer(AllContainerTypes.ATTRIBUTE_FILTER.get(), id, inv, stack); - } - - public void appendSelectedAttribute(ItemAttribute itemAttribute, boolean inverted) { - selectedAttributes.add(Pair.of(itemAttribute, inverted)); - } - - @Override - protected void init(Inventory inv, ItemStack contentHolder) { - super.init(inv, contentHolder); - ItemStack stack = new ItemStack(Items.NAME_TAG); - stack.setHoverName( - Components.literal("Selected Tags").withStyle(ChatFormatting.RESET, ChatFormatting.BLUE)); - ghostInventory.setStackInSlot(1, stack); - } - - @Override - protected int getPlayerInventoryXOffset() { - return 51; - } - - @Override - protected int getPlayerInventoryYOffset() { - return 105; - } - - @Override - protected void addFilterSlots() { - this.addSlot(new SlotItemHandler(ghostInventory, 0, 16, 22)); - this.addSlot(new SlotItemHandler(ghostInventory, 1, 22, 57) { - @Override - public boolean mayPickup(Player playerIn) { - return false; - } - }); - } - - @Override - protected ItemStackHandler createGhostInventory() { - return new ItemStackHandler(2); - } - - @Override - public void clearContents() { - selectedAttributes.clear(); - } - - @Override - public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { - if (slotId == 37) - return; - super.clicked(slotId, dragType, clickTypeIn, player); - } - - @Override - public boolean canDragTo(Slot slotIn) { - if (slotIn.index == 37) - return false; - return super.canDragTo(slotIn); - } - - @Override - public boolean canTakeItemForPickAll(ItemStack stack, Slot slotIn) { - if (slotIn.index == 37) - return false; - return super.canTakeItemForPickAll(stack, slotIn); - } - - @Override - public ItemStack quickMoveStack(Player playerIn, int index) { - if (index == 37) - return ItemStack.EMPTY; - if (index == 36) { - ghostInventory.setStackInSlot(37, ItemStack.EMPTY); - return ItemStack.EMPTY; - } - if (index < 36) { - ItemStack stackToInsert = playerInventory.getItem(index); - ItemStack copy = stackToInsert.copy(); - copy.setCount(1); - ghostInventory.setStackInSlot(0, copy); - } - return ItemStack.EMPTY; - } - - @Override - protected void initAndReadInventory(ItemStack filterItem) { - super.initAndReadInventory(filterItem); - selectedAttributes = new ArrayList<>(); - whitelistMode = WhitelistMode.values()[filterItem.getOrCreateTag() - .getInt("WhitelistMode")]; - ListTag attributes = filterItem.getOrCreateTag() - .getList("MatchedAttributes", Tag.TAG_COMPOUND); - attributes.forEach(inbt -> { - CompoundTag compound = (CompoundTag) inbt; - selectedAttributes.add(Pair.of(ItemAttribute.fromNBT(compound), compound.getBoolean("Inverted"))); - }); - } - - @Override - protected void saveData(ItemStack filterItem) { - super.saveData(filterItem); - filterItem.getOrCreateTag() - .putInt("WhitelistMode", whitelistMode.ordinal()); - ListTag attributes = new ListTag(); - selectedAttributes.forEach(at -> { - if (at == null) - return; - CompoundTag compoundNBT = new CompoundTag(); - at.getFirst() - .serializeNBT(compoundNBT); - compoundNBT.putBoolean("Inverted", at.getSecond()); - attributes.add(compoundNBT); - }); - filterItem.getOrCreateTag() - .put("MatchedAttributes", attributes); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java deleted file mode 100644 index 10b66edd26..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterContainer.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.simibubi.create.content.logistics.item.filter; - -import com.simibubi.create.AllContainerTypes; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class FilterContainer extends AbstractFilterContainer { - - boolean respectNBT; - boolean blacklist; - - public FilterContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public FilterContainer(MenuType type, int id, Inventory inv, ItemStack stack) { - super(type, id, inv, stack); - } - - public static FilterContainer create(int id, Inventory inv, ItemStack stack) { - return new FilterContainer(AllContainerTypes.FILTER.get(), id, inv, stack); - } - - @Override - protected int getPlayerInventoryXOffset() { - return 38; - } - - @Override - protected int getPlayerInventoryYOffset() { - return 119; - } - - @Override - protected void addFilterSlots() { - int x = 23; - int y = 20; - for (int row = 0; row < 2; ++row) - for (int col = 0; col < 9; ++col) - this.addSlot(new SlotItemHandler(ghostInventory, col + row * 9, x + col * 18, y + row * 18)); - } - - @Override - protected ItemStackHandler createGhostInventory() { - return FilterItem.getFilterItems(contentHolder); - } - - @Override - protected void initAndReadInventory(ItemStack filterItem) { - super.initAndReadInventory(filterItem); - CompoundTag tag = filterItem.getOrCreateTag(); - respectNBT = tag.getBoolean("RespectNBT"); - blacklist = tag.getBoolean("Blacklist"); - } - - @Override - protected void saveData(ItemStack filterItem) { - super.saveData(filterItem); - CompoundTag tag = filterItem.getOrCreateTag(); - tag.putBoolean("RespectNBT", respectNBT); - tag.putBoolean("Blacklist", blacklist); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java deleted file mode 100644 index 9d19f4c41d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/FilterScreen.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.simibubi.create.content.logistics.item.filter; - -import java.util.Arrays; -import java.util.List; - -import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.gui.widget.Indicator; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.entity.player.Inventory; - -public class FilterScreen extends AbstractFilterScreen { - - private static final String PREFIX = "gui.filter."; - - private final Component allowN = CreateLang.translateDirect(PREFIX + "allow_list"); - private final Component allowDESC = CreateLang.translateDirect(PREFIX + "allow_list.description"); - private final Component denyN = CreateLang.translateDirect(PREFIX + "deny_list"); - private final Component denyDESC = CreateLang.translateDirect(PREFIX + "deny_list.description"); - - private final Component respectDataN = CreateLang.translateDirect(PREFIX + "respect_data"); - private final Component respectDataDESC = CreateLang.translateDirect(PREFIX + "respect_data.description"); - private final Component ignoreDataN = CreateLang.translateDirect(PREFIX + "ignore_data"); - private final Component ignoreDataDESC = CreateLang.translateDirect(PREFIX + "ignore_data.description"); - - private IconButton whitelist, blacklist; - private IconButton respectNBT, ignoreNBT; - private Indicator whitelistIndicator, blacklistIndicator; - private Indicator respectNBTIndicator, ignoreNBTIndicator; - - public FilterScreen(FilterContainer container, Inventory inv, Component title) { - super(container, inv, title, AllGuiTextures.FILTER); - } - - @Override - protected void init() { - setWindowOffset(-11, 5); - super.init(); - - int x = leftPos; - int y = topPos; - - blacklist = new IconButton(x + 18, y + 73, AllIcons.I_BLACKLIST); - blacklist.withCallback(() -> { - menu.blacklist = true; - sendOptionUpdate(Option.BLACKLIST); - }); - blacklist.setToolTip(denyN); - whitelist = new IconButton(x + 36, y + 73, AllIcons.I_WHITELIST); - whitelist.withCallback(() -> { - menu.blacklist = false; - sendOptionUpdate(Option.WHITELIST); - }); - whitelist.setToolTip(allowN); - blacklistIndicator = new Indicator(x + 18, y + 67, Components.immutableEmpty()); - whitelistIndicator = new Indicator(x + 36, y + 67, Components.immutableEmpty()); - addRenderableWidgets(blacklist, whitelist, blacklistIndicator, whitelistIndicator); - - respectNBT = new IconButton(x + 60, y + 73, AllIcons.I_RESPECT_NBT); - respectNBT.withCallback(() -> { - menu.respectNBT = true; - sendOptionUpdate(Option.RESPECT_DATA); - }); - respectNBT.setToolTip(respectDataN); - ignoreNBT = new IconButton(x + 78, y + 73, AllIcons.I_IGNORE_NBT); - ignoreNBT.withCallback(() -> { - menu.respectNBT = false; - sendOptionUpdate(Option.IGNORE_DATA); - }); - ignoreNBT.setToolTip(ignoreDataN); - respectNBTIndicator = new Indicator(x + 60, y + 67, Components.immutableEmpty()); - ignoreNBTIndicator = new Indicator(x + 78, y + 67, Components.immutableEmpty()); - addRenderableWidgets(respectNBT, ignoreNBT, respectNBTIndicator, ignoreNBTIndicator); - - handleIndicators(); - } - - @Override - protected List getTooltipButtons() { - return Arrays.asList(blacklist, whitelist, respectNBT, ignoreNBT); - } - - @Override - protected List getTooltipDescriptions() { - return Arrays.asList(denyDESC.plainCopy(), allowDESC.plainCopy(), respectDataDESC.plainCopy(), ignoreDataDESC.plainCopy()); - } - - @Override - protected List getIndicators() { - return Arrays.asList(blacklistIndicator, whitelistIndicator, respectNBTIndicator, ignoreNBTIndicator); - } - - @Override - protected boolean isButtonEnabled(IconButton button) { - if (button == blacklist) - return !menu.blacklist; - if (button == whitelist) - return menu.blacklist; - if (button == respectNBT) - return !menu.respectNBT; - if (button == ignoreNBT) - return menu.respectNBT; - return true; - } - - @Override - protected boolean isIndicatorOn(Indicator indicator) { - if (indicator == blacklistIndicator) - return menu.blacklist; - if (indicator == whitelistIndicator) - return !menu.blacklist; - if (indicator == respectNBTIndicator) - return menu.respectNBT; - if (indicator == ignoreNBTIndicator) - return !menu.respectNBT; - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java b/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java deleted file mode 100644 index 39f4474f24..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/packet/ConfigureStockswitchPacket.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.simibubi.create.content.logistics.packet; - -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; - -public class ConfigureStockswitchPacket extends TileEntityConfigurationPacket { - - private float offBelow; - private float onAbove; - private boolean invert; - - public ConfigureStockswitchPacket(BlockPos pos, float offBelow, float onAbove, boolean invert) { - super(pos); - this.offBelow = offBelow; - this.onAbove = onAbove; - this.invert = invert; - } - - public ConfigureStockswitchPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void readSettings(FriendlyByteBuf buffer) { - offBelow = buffer.readFloat(); - onAbove = buffer.readFloat(); - invert = buffer.readBoolean(); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) { - buffer.writeFloat(offBelow); - buffer.writeFloat(onAbove); - buffer.writeBoolean(invert); - } - - @Override - protected void applySettings(StockpileSwitchTileEntity te) { - te.offWhenBelow = offBelow; - te.onWhenAbove = onAbove; - te.setInverted(invert); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/packet/FunnelFlapPacket.java b/src/main/java/com/simibubi/create/content/logistics/packet/FunnelFlapPacket.java deleted file mode 100644 index a7eaf3bdc1..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/packet/FunnelFlapPacket.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.simibubi.create.content.logistics.packet; - -import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity; -import com.simibubi.create.foundation.networking.TileEntityDataPacket; - -import net.minecraft.network.FriendlyByteBuf; - -public class FunnelFlapPacket extends TileEntityDataPacket { - - private final boolean inwards; - - public FunnelFlapPacket(FriendlyByteBuf buffer) { - super(buffer); - - inwards = buffer.readBoolean(); - } - - public FunnelFlapPacket(FunnelTileEntity tile, boolean inwards) { - super(tile.getBlockPos()); - this.inwards = inwards; - } - - @Override - protected void writeData(FriendlyByteBuf buffer) { - buffer.writeBoolean(inwards); - } - - @Override - protected void handlePacket(FunnelTileEntity tile) { - tile.flap(inwards); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java b/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java deleted file mode 100644 index ffbf776a02..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/packet/TunnelFlapPacket.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.simibubi.create.content.logistics.packet; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelTileEntity; -import com.simibubi.create.foundation.networking.TileEntityDataPacket; - -import net.minecraft.core.Direction; -import net.minecraft.network.FriendlyByteBuf; - -public class TunnelFlapPacket extends TileEntityDataPacket { - - private List> flaps; - - public TunnelFlapPacket(FriendlyByteBuf buffer) { - super(buffer); - - byte size = buffer.readByte(); - - this.flaps = new ArrayList<>(size); - - for (int i = 0; i < size; i++) { - Direction direction = Direction.from3DDataValue(buffer.readByte()); - boolean inwards = buffer.readBoolean(); - - flaps.add(Pair.of(direction, inwards)); - } - } - - public TunnelFlapPacket(BeltTunnelTileEntity tile, List> flaps) { - super(tile.getBlockPos()); - - this.flaps = new ArrayList<>(flaps); - } - - @Override - protected void writeData(FriendlyByteBuf buffer) { - buffer.writeByte(flaps.size()); - - for (Pair flap : flaps) { - buffer.writeByte(flap.getLeft().get3DDataValue()); - buffer.writeBoolean(flap.getRight()); - } - } - - @Override - protected void handlePacket(BeltTunnelTileEntity tile) { - for (Pair flap : flaps) { - tile.flap(flap.getLeft(), flap.getRight()); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java deleted file mode 100644 index 94a08b1457..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -public class BogeyTileEntityRenderer extends SafeTileEntityRenderer { - - public BogeyTileEntityRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, - int overlay) { - BlockState blockState = te.getBlockState(); - float angle = 0; - if (te instanceof StandardBogeyTileEntity sbte) - angle = sbte.getVirtualAngle(partialTicks); - if (blockState.getBlock()instanceof IBogeyBlock bogey) - bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/CameraDistanceModifier.java b/src/main/java/com/simibubi/create/content/logistics/trains/CameraDistanceModifier.java deleted file mode 100644 index dc289fc8be..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/CameraDistanceModifier.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import com.simibubi.create.foundation.config.AllConfigs; - -import net.createmod.catnip.utility.animation.LerpedFloat; - -public class CameraDistanceModifier { - - private static final LerpedFloat multiplier = LerpedFloat.linear().startWithValue(1); - - public static float getMultiplier(float partialTicks) { - return multiplier.getValue(partialTicks); - } - - public static void tick() { - multiplier.tickChaser(); - } - - public static void reset() { - multiplier.chase(1, 0.1, LerpedFloat.Chaser.EXP); - } - - public static void zoomOut() { - zoomOut(AllConfigs.CLIENT.mountedZoomMultiplier.getF()); - } - - public static void zoomOut(float targetMultiplier) { - multiplier.chase(targetMultiplier, 0.075, LerpedFloat.Chaser.EXP); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GraphLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/GraphLocation.java deleted file mode 100644 index 6dc5519c7b..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GraphLocation.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import net.createmod.catnip.utility.Couple; - -public class GraphLocation { - - public TrackGraph graph; - public Couple edge; - public double position; - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java deleted file mode 100644 index 643d21a0bb..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/IBogeyBlock.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; - -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; - -public interface IBogeyBlock extends IWrenchable { - - static final List BOGEYS = new ArrayList<>(); - - public static void register(ResourceLocation block) { - BOGEYS.add(block); - } - - public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state); - - public double getWheelPointSpacing(); - - public double getWheelRadius(); - - public boolean allowsSingleBogeyCarriage(); - - public Vec3 getConnectorAnchorOffset(); - - @OnlyIn(Dist.CLIENT) - public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks, - MultiBufferSource buffers, int light, int overlay); - - @OnlyIn(Dist.CLIENT) - public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey); - - public default Direction getBogeyUpDirection() { - return Direction.UP; - } - - public boolean isTrackAxisAlongFirstCoordinate(BlockState state); - - @Nullable - public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst); - - @Override - default BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { - Block block = state.getBlock(); - int indexOf = BOGEYS.indexOf(CatnipServices.REGISTRIES.getKeyOrThrow(block)); - if (indexOf == -1) - return state; - - int index = (indexOf + 1) % BOGEYS.size(); - Direction bogeyUpDirection = getBogeyUpDirection(); - boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state); - - while (index != indexOf) { - ResourceLocation id = BOGEYS.get(index); - Block newBlock = ForgeRegistries.BLOCKS.getValue(id); - if (newBlock instanceof IBogeyBlock bogey) { - BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate); - if (matchingBogey != null) - return matchingBogey.hasProperty(WATERLOGGED) - ? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED)) - : matchingBogey; - } - index = (index + 1) % BOGEYS.size(); - } - - return state; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java deleted file mode 100644 index e3e0b46809..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Function; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackShape; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.Pair; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public interface ITrackBlock { - - public Vec3 getUpNormal(BlockGetter world, BlockPos pos, BlockState state); - - public List getTrackAxes(BlockGetter world, BlockPos pos, BlockState state); - - public Vec3 getCurveStart(BlockGetter world, BlockPos pos, BlockState state, Vec3 axis); - - public BlockState getBogeyAnchor(BlockGetter world, BlockPos pos, BlockState state); // should be on bogey side - - public boolean trackEquals(BlockState state1, BlockState state2); - - public default BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) { - return existing; - } - - public default double getElevationAtCenter(BlockGetter world, BlockPos pos, BlockState state) { - return isSlope(world, pos, state) ? .5 : 0; - } - - public static Collection walkConnectedTracks(BlockGetter worldIn, TrackNodeLocation location, - boolean linear) { - BlockGetter world = location != null && worldIn instanceof ServerLevel sl ? sl.getServer() - .getLevel(location.dimension) : worldIn; - List list = new ArrayList<>(); - for (BlockPos blockPos : location.allAdjacent()) { - BlockState blockState = world.getBlockState(blockPos); - if (blockState.getBlock()instanceof ITrackBlock track) - list.addAll(track.getConnected(world, blockPos, blockState, linear, location)); - } - return list; - } - - public default Collection getConnected(BlockGetter worldIn, BlockPos pos, BlockState state, - boolean linear, @Nullable TrackNodeLocation connectedTo) { - BlockGetter world = connectedTo != null && worldIn instanceof ServerLevel sl ? sl.getServer() - .getLevel(connectedTo.dimension) : worldIn; - Vec3 center = Vec3.atBottomCenterOf(pos) - .add(0, getElevationAtCenter(world, pos, state), 0); - List list = new ArrayList<>(); - TrackShape shape = state.getValue(TrackBlock.SHAPE); - getTrackAxes(world, pos, state).forEach(axis -> { - addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) - .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, - axis, null); - }); - - return list; - } - - public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection list, - BiFunction offsetFactory, Function normalFactory, - Function> dimensionFactory, Vec3 axis, BezierConnection viaTurn) { - - DiscoveredLocation firstLocation = - new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) - .withNormal(normalFactory.apply(true)) - .withDirection(axis); - DiscoveredLocation secondLocation = - new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) - .withNormal(normalFactory.apply(false)) - .withDirection(axis); - - if (!firstLocation.dimension.equals(secondLocation.dimension)) { - firstLocation.forceNode(); - secondLocation.forceNode(); - } - - boolean skipFirst = false; - boolean skipSecond = false; - - if (fromEnd != null) { - boolean equalsFirst = firstLocation.equals(fromEnd); - boolean equalsSecond = secondLocation.equals(fromEnd); - - // not reachable from this end - if (!equalsFirst && !equalsSecond) - return; - - if (equalsFirst) - skipFirst = true; - if (equalsSecond) - skipSecond = true; - } - - if (!skipFirst) - list.add(firstLocation); - if (!skipSecond) - list.add(secondLocation); - } - - @OnlyIn(Dist.CLIENT) - public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state, - BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack transform, - RenderedTrackOverlayType type); - - @OnlyIn(Dist.CLIENT) - public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction, - PoseStack ms); - - public default boolean isSlope(BlockGetter world, BlockPos pos, BlockState state) { - return getTrackAxes(world, pos, state).get(0).y != 0; - } - - public default Pair getNearestTrackAxis(BlockGetter world, BlockPos pos, BlockState state, - Vec3 lookVec) { - Vec3 best = null; - double bestDiff = Double.MAX_VALUE; - for (Vec3 vec3 : getTrackAxes(world, pos, state)) { - for (int opposite : Iterate.positiveAndNegative) { - double distanceTo = vec3.normalize() - .distanceTo(lookVec.scale(opposite)); - if (distanceTo > bestDiff) - continue; - bestDiff = distanceTo; - best = vec3; - } - } - return Pair.of(best, lookVec.dot(best.multiply(1, 0, 1) - .normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java deleted file mode 100644 index 61078a2995..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - -import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class TrackEdge { - - public TrackNode node1; - public TrackNode node2; - BezierConnection turn; - EdgeData edgeData; - boolean interDimensional; - - public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) { - this.interDimensional = !node1.location.dimension.equals(node2.location.dimension); - this.edgeData = new EdgeData(this); - this.node1 = node1; - this.node2 = node2; - this.turn = turn; - } - - public boolean isTurn() { - return turn != null; - } - - public boolean isInterDimensional() { - return interDimensional; - } - - public EdgeData getEdgeData() { - return edgeData; - } - - public BezierConnection getTurn() { - return turn; - } - - public Vec3 getDirection(boolean fromFirst) { - return getPosition(fromFirst ? 0.25f : 1).subtract(getPosition(fromFirst ? 0 : 0.75f)) - .normalize(); - } - - public Vec3 getDirectionAt(double t) { - double length = getLength(); - double step = .5f / length; - t /= length; - Vec3 ahead = getPosition(Math.min(1, t + step)); - Vec3 behind = getPosition(Math.max(0, t - step)); - return ahead.subtract(behind) - .normalize(); - } - - public boolean canTravelTo(TrackEdge other) { - if (isInterDimensional() || other.isInterDimensional()) - return true; - Vec3 newDirection = other.getDirection(true); - return getDirection(false).dot(newDirection) > 7 / 8f; - } - - public double getLength() { - return isInterDimensional() ? 0 - : isTurn() ? turn.getLength() - : node1.location.getLocation() - .distanceTo(node2.location.getLocation()); - } - - public double incrementT(double currentT, double distance) { - boolean tooFar = Math.abs(distance) > 5; - double length = getLength(); - distance = distance / (length == 0 ? 1 : length); - return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance; - } - - public Vec3 getPosition(double t) { - return isTurn() ? turn.getPosition(Mth.clamp(t, 0, 1)) - : VecHelper.lerp((float) t, node1.location.getLocation(), node2.location.getLocation()); - } - - public Collection getIntersection(TrackNode node1, TrackNode node2, TrackEdge other, TrackNode other1, - TrackNode other2) { - Vec3 v1 = node1.location.getLocation(); - Vec3 v2 = node2.location.getLocation(); - Vec3 w1 = other1.location.getLocation(); - Vec3 w2 = other2.location.getLocation(); - - if (isInterDimensional() || other.isInterDimensional()) - return Collections.emptyList(); - if (v1.y != v2.y || v1.y != w1.y || v1.y != w2.y) - return Collections.emptyList(); - - if (!isTurn()) { - if (!other.isTurn()) - return ImmutableList.of(VecHelper.intersectRanged(v1, w1, v2, w2, Axis.Y)); - return other.getIntersection(other1, other2, this, node1, node2) - .stream() - .map(a -> new double[] { a[1], a[0] }) - .toList(); - } - - AABB bb = turn.getBounds(); - - if (!other.isTurn()) { - if (!bb.intersects(w1, w2)) - return Collections.emptyList(); - - Vec3 seg1 = v1; - Vec3 seg2 = null; - double t = 0; - - Collection intersections = new ArrayList<>(); - for (int i = 0; i < turn.getSegmentCount(); i++) { - double tOffset = t; - t += .5; - seg2 = getPosition(t / getLength()); - double[] intersection = VecHelper.intersectRanged(seg1, w1, seg2, w2, Axis.Y); - seg1 = seg2; - if (intersection == null) - continue; - intersection[0] += tOffset; - intersections.add(intersection); - } - - return intersections; - } - - if (!bb.intersects(other.turn.getBounds())) - return Collections.emptyList(); - - Vec3 seg1 = v1; - Vec3 seg2 = null; - double t = 0; - - Collection intersections = new ArrayList<>(); - for (int i = 0; i < turn.getSegmentCount(); i++) { - double tOffset = t; - t += .5; - seg2 = getPosition(t / getLength()); - - Vec3 otherSeg1 = w1; - Vec3 otherSeg2 = null; - double u = 0; - - for (int j = 0; j < other.turn.getSegmentCount(); j++) { - double uOffset = u; - u += .5; - otherSeg2 = other.getPosition(u / other.getLength()); - - double[] intersection = VecHelper.intersectRanged(seg1, otherSeg1, seg2, otherSeg2, Axis.Y); - otherSeg1 = otherSeg2; - - if (intersection == null) - continue; - - intersection[0] += tOffset; - intersection[1] += uOffset; - intersections.add(intersection); - } - - seg1 = seg2; - } - - return intersections; - } - - public Vec3 getNormal(TrackNode node1, TrackNode node2, double t) { - return isTurn() ? turn.getNormal(Mth.clamp(t, 0, 1)) : node1.getNormal(); - } - - public CompoundTag write(DimensionPalette dimensions) { - CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); - baseCompound.put("Signals", edgeData.write(dimensions)); - return baseCompound; - } - - public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, - DimensionPalette dimensions) { - TrackEdge trackEdge = - new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null); - trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions); - return trackEdge; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java deleted file mode 100644 index b49ef2e78a..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; - -import javax.annotation.Nullable; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; - -import net.createmod.catnip.utility.Couple; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class TrackGraphHelper { - - @Nullable - public static GraphLocation getGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection, - Vec3 targetAxis) { - BlockState trackBlockState = level.getBlockState(pos); - if (!(trackBlockState.getBlock()instanceof ITrackBlock track)) - return null; - - Vec3 axis = targetAxis.scale(targetDirection.getStep()); - double length = axis.length(); - TrackGraph graph = null; - - // Case 1: Centre of block lies on a node - - TrackNodeLocation location = new TrackNodeLocation(Vec3.atBottomCenterOf(pos) - .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0)).in(level); - graph = Create.RAILWAYS.sided(level) - .getGraph(level, location); - if (graph != null) { - TrackNode node = graph.locateNode(location); - if (node != null) { - Map connectionsFrom = graph.getConnectionsFrom(node); - for (Entry entry : connectionsFrom.entrySet()) { - TrackNode backNode = entry.getKey(); - Vec3 direction = entry.getValue() - .getDirection(true); - if (direction.scale(length) - .distanceToSqr(axis.scale(-1)) > 1 / 4096f) - continue; - - GraphLocation graphLocation = new GraphLocation(); - graphLocation.edge = Couple.create(node.getLocation(), backNode.getLocation()); - graphLocation.position = 0; - graphLocation.graph = graph; - return graphLocation; - } - } - } - - // Case 2: Center of block is between two nodes - - Collection ends = track.getConnected(level, pos, trackBlockState, true, null); - Vec3 start = Vec3.atBottomCenterOf(pos) - .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0); - - TrackNode frontNode = null; - TrackNode backNode = null; - double position = 0; - - for (DiscoveredLocation current : ends) { - Vec3 offset = current.getLocation() - .subtract(start) - .normalize() - .scale(length); - - boolean forward = offset.distanceToSqr(axis.scale(-1)) < 1 / 4096f; - boolean backwards = offset.distanceToSqr(axis) < 1 / 4096f; - - if (!forward && !backwards) - continue; - - DiscoveredLocation previous = null; - double distance = 0; - for (int i = 0; i < 100 && distance < 32; i++) { - DiscoveredLocation loc = current; - if (graph == null) - graph = Create.RAILWAYS.sided(level) - .getGraph(level, loc); - - if (graph == null || graph.locateNode(loc) == null) { - Collection list = ITrackBlock.walkConnectedTracks(level, loc, true); - for (DiscoveredLocation discoveredLocation : list) { - if (discoveredLocation == previous) - continue; - Vec3 diff = discoveredLocation.getLocation() - .subtract(loc.getLocation()); - if ((forward ? axis.scale(-1) : axis).distanceToSqr(diff.normalize() - .scale(length)) > 1 / 4096f) - continue; - - previous = current; - current = discoveredLocation; - distance += diff.length(); - break; - } - continue; - } - - TrackNode node = graph.locateNode(loc); - if (forward) - frontNode = node; - if (backwards) { - backNode = node; - position = distance + axis.length() / 2; - } - break; - } - } - - if (frontNode == null || backNode == null) - return null; - - GraphLocation graphLocation = new GraphLocation(); - graphLocation.edge = Couple.create(backNode.getLocation(), frontNode.getLocation()); - graphLocation.position = position; - graphLocation.graph = graph; - return graphLocation; - } - - @Nullable - public static GraphLocation getBezierGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection, - BezierTrackPointLocation targetBezier) { - BlockState state = level.getBlockState(pos); - - if (!(state.getBlock()instanceof ITrackBlock track)) - return null; - if (!(level.getBlockEntity(pos)instanceof TrackTileEntity trackTE)) - return null; - BezierConnection bc = trackTE.getConnections() - .get(targetBezier.curveTarget()); - if (bc == null || !bc.isPrimary()) - return null; - - TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond()).in(level); - for (DiscoveredLocation location : track.getConnected(level, pos, state, true, null)) { - TrackGraph graph = Create.RAILWAYS.sided(level) - .getGraph(level, location); - if (graph == null) - continue; - TrackNode targetNode = graph.locateNode(targetLoc); - if (targetNode == null) - continue; - TrackNode node = graph.locateNode(location); - TrackEdge edge = graph.getConnectionsFrom(node) - .get(targetNode); - if (edge == null) - continue; - - GraphLocation graphLocation = new GraphLocation(); - graphLocation.graph = graph; - graphLocation.edge = Couple.create(location, targetLoc); - graphLocation.position = (targetBezier.segment() + 1) / 2f; - if (targetDirection == AxisDirection.POSITIVE) { - graphLocation.edge = graphLocation.edge.swap(); - graphLocation.position = edge.getLength() - graphLocation.position; - } - - return graphLocation; - } - - return null; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphPacket.java deleted file mode 100644 index 8884744053..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphPacket.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraftforge.network.NetworkEvent.Context; - -public abstract class TrackGraphPacket extends SimplePacketBase { - - public UUID graphId; - public int netId; - public boolean packetDeletesGraph; - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> handle(CreateClient.RAILWAYS, CreateClient.RAILWAYS.getOrCreateGraph(graphId, netId))); - context.get() - .setPacketHandled(true); - } - - protected abstract void handle(GlobalRailwayManager manager, TrackGraph graph); - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRequestPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRequestPacket.java deleted file mode 100644 index eb179ba413..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRequestPacket.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent.Context; - -public class TrackGraphRequestPacket extends SimplePacketBase { - - private int netId; - - public TrackGraphRequestPacket(int netId) { - this.netId = netId; - } - - public TrackGraphRequestPacket(FriendlyByteBuf buffer) { - netId = buffer.readInt(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeInt(netId); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { - if (trackGraph.netId == netId) { - Create.RAILWAYS.sync.sendFullGraphTo(trackGraph, context.get() - .getSender()); - break; - } - } - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRollCallPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRollCallPacket.java deleted file mode 100644 index fe4f3b0f8a..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphRollCallPacket.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent.Context; - -public class TrackGraphRollCallPacket extends SimplePacketBase { - - int[] ints; - - public TrackGraphRollCallPacket() { - GlobalRailwayManager manager = Create.RAILWAYS; - ints = new int[manager.trackNetworks.size() * 2]; - int i = 0; - for (TrackGraph trackGraph : manager.trackNetworks.values()) { - ints[i] = trackGraph.netId; - ints[i + 1] = trackGraph.getChecksum(); - i += 2; - } - } - - public TrackGraphRollCallPacket(FriendlyByteBuf buffer) { - ints = new int[buffer.readVarInt()]; - for (int i = 0; i < ints.length; i++) - ints[i] = buffer.readInt(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeVarInt(ints.length); - for (int i : ints) - buffer.writeInt(i); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - - GlobalRailwayManager manager = Create.RAILWAYS.sided(null); - Set unusedIds = new HashSet<>(manager.trackNetworks.keySet()); - List failedIds = new ArrayList<>(); - Map idByNetId = new HashMap<>(); - manager.trackNetworks.forEach((uuid, g) -> idByNetId.put(g.netId, uuid)); - - for (int i = 0; i < ints.length; i += 2) { - UUID uuid = idByNetId.get(ints[i]); - if (uuid == null) { - failedIds.add(ints[i]); - continue; - } - unusedIds.remove(uuid); - TrackGraph trackGraph = manager.trackNetworks.get(uuid); - if (trackGraph.getChecksum() == ints[i + 1]) - continue; - Create.LOGGER.warn("Track network: " + uuid.toString() - .substring(0, 6) + " failed its checksum; Requesting refresh"); - failedIds.add(ints[i]); - } - - for (Integer failed : failedIds) - AllPackets.channel.sendToServer(new TrackGraphRequestPacket(failed)); - for (UUID unused : unusedIds) - manager.trackNetworks.remove(unused); - - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java deleted file mode 100644 index 944bd87ff6..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.simibubi.create.content.logistics.trains; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; - -public class TrackNodeLocation extends Vec3i { - - public ResourceKey dimension; - - public TrackNodeLocation(Vec3 vec) { - this(vec.x, vec.y, vec.z); - } - - public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) { - super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2)); - } - - public TrackNodeLocation in(Level level) { - return in(level.dimension()); - } - - public TrackNodeLocation in(ResourceKey dimension) { - this.dimension = dimension; - return this; - } - - private static TrackNodeLocation fromPackedPos(BlockPos bufferPos) { - return new TrackNodeLocation(bufferPos); - } - - private TrackNodeLocation(BlockPos readBlockPos) { - super(readBlockPos.getX(), readBlockPos.getY(), readBlockPos.getZ()); - } - - public Vec3 getLocation() { - return new Vec3(getX() / 2f, getY() / 2f, getZ() / 2f); - } - - public ResourceKey getDimension() { - return dimension; - } - - @Override - public boolean equals(Object pOther) { - return equalsIgnoreDim(pOther) && pOther instanceof TrackNodeLocation tnl - && Objects.equals(tnl.dimension, dimension); - } - - public boolean equalsIgnoreDim(Object pOther) { - return super.equals(pOther); - } - - @Override - public int hashCode() { - return (this.getY() + (this.getZ() * 31 + dimension.hashCode()) * 31) * 31 + this.getX(); - } - - public CompoundTag write(DimensionPalette dimensions) { - CompoundTag c = NbtUtils.writeBlockPos(new BlockPos(this)); - if (dimensions != null) - c.putInt("D", dimensions.encode(dimension)); - return c; - } - - public static TrackNodeLocation read(CompoundTag tag, DimensionPalette dimensions) { - TrackNodeLocation location = fromPackedPos(NbtUtils.readBlockPos(tag)); - if (dimensions != null) - location.dimension = dimensions.decode(tag.getInt("D")); - return location; - } - - public void send(FriendlyByteBuf buffer, DimensionPalette dimensions) { - buffer.writeBlockPos(new BlockPos(this)); - buffer.writeVarInt(dimensions.encode(dimension)); - } - - public static TrackNodeLocation receive(FriendlyByteBuf buffer, DimensionPalette dimensions) { - TrackNodeLocation location = fromPackedPos(buffer.readBlockPos()); - location.dimension = dimensions.decode(buffer.readVarInt()); - return location; - } - - public Collection allAdjacent() { - Set set = new HashSet<>(); - Vec3 vec3 = getLocation(); - double step = 1 / 8f; - for (int x : Iterate.positiveAndNegative) - for (int y : Iterate.positiveAndNegative) - for (int z : Iterate.positiveAndNegative) - set.add(new BlockPos(vec3.add(x * step, y * step, z * step))); - return set; - } - - public static class DiscoveredLocation extends TrackNodeLocation { - - BezierConnection turn = null; - boolean forceNode = false; - Vec3 direction; - Vec3 normal; - - public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) { - super(p_121865_, p_121866_, p_121867_); - in(level); - } - - public DiscoveredLocation(ResourceKey dimension, Vec3 vec) { - super(vec); - in(dimension); - } - - public DiscoveredLocation(Level level, Vec3 vec) { - this(level.dimension(), vec); - } - - public DiscoveredLocation viaTurn(BezierConnection turn) { - this.turn = turn; - if (turn != null) - forceNode(); - return this; - } - - public DiscoveredLocation forceNode() { - forceNode = true; - return this; - } - - public DiscoveredLocation withNormal(Vec3 normal) { - this.normal = normal; - return this; - } - - public DiscoveredLocation withDirection(Vec3 direction) { - this.direction = direction == null ? null : direction.normalize(); - return this; - } - - public boolean connectedViaTurn() { - return turn != null; - } - - public BezierConnection getTurn() { - return turn; - } - - public boolean shouldForceNode() { - return forceNode; - } - - public boolean notInLineWith(Vec3 direction) { - return this.direction != null - && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java deleted file mode 100644 index 3a1df60072..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyInstance.java +++ /dev/null @@ -1,235 +0,0 @@ -package com.simibubi.create.content.logistics.trains.entity; - -import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.materials.model.ModelData; -import com.jozufozu.flywheel.util.AnimationTickHolder; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.phys.Vec3; - -public sealed class BogeyInstance { - - public final CarriageBogey bogey; - private final ModelData[] shafts; - - protected BogeyInstance(CarriageBogey bogey, MaterialManager materialManager) { - this.bogey = bogey; - - shafts = new ModelData[2]; - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Direction.Axis.Z)) - .createInstances(shafts); - - } - - public void remove() { - for (ModelData shaft : shafts) - shaft.delete(); - } - - public void hiddenFrame() { - beginFrame(0, null); - } - - public void beginFrame(float wheelAngle, PoseStack ms) { - if (ms == null) { - for (int i : Iterate.zeroAndOne) - shafts[i].setEmptyTransform(); - return; - } - - for (int i : Iterate.zeroAndOne) - shafts[i].setTransform(ms) - .translate(-.5f, .25f, i * -1) - .centre() - .rotateZ(wheelAngle) - .unCentre(); - } - - public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { - var lightPos = new BlockPos(getLightPos(entity)); - - updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), world.getBrightness(LightLayer.SKY, lightPos)); - } - - private Vec3 getLightPos(CarriageContraptionEntity entity) { - if (bogey.getAnchorPosition() != null) { - return bogey.getAnchorPosition(); - } else { - return entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); - } - } - - public void updateLight(int blockLight, int skyLight) { - for (ModelData shaft : shafts) { - shaft.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - } - - public static final class Frame extends BogeyInstance { - - private final ModelData frame; - private final ModelData[] wheels; - - public Frame(CarriageBogey bogey, MaterialManager materialManager) { - super(bogey, materialManager); - - frame = materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.BOGEY_FRAME) - .createInstance(); - - wheels = new ModelData[2]; - - materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(AllBlockPartials.SMALL_BOGEY_WHEELS) - .createInstances(wheels); - } - - @Override - public void beginFrame(float wheelAngle, PoseStack ms) { - super.beginFrame(wheelAngle, ms); - - if (ms == null) { - frame.setEmptyTransform(); - for (int side : Iterate.positiveAndNegative) - wheels[(side + 1) / 2].setEmptyTransform(); - return; - } - - frame.setTransform(ms); - - for (int side : Iterate.positiveAndNegative) { - wheels[(side + 1) / 2].setTransform(ms) - .translate(0, 12 / 16f, side) - .rotateX(wheelAngle); - } - } - - @Override - public void updateLight(int blockLight, int skyLight) { - super.updateLight(blockLight, skyLight); - frame.setBlockLight(blockLight) - .setSkyLight(skyLight); - for (ModelData wheel : wheels) - wheel.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - - @Override - public void remove() { - super.remove(); - frame.delete(); - for (ModelData wheel : wheels) - wheel.delete(); - } - } - - public static final class Drive extends BogeyInstance { - - private final ModelData[] secondShaft; - private final ModelData drive; - private final ModelData piston; - private final ModelData wheels; - private final ModelData pin; - - public Drive(CarriageBogey bogey, MaterialManager materialManager) { - super(bogey, materialManager); - Material mat = materialManager.defaultSolid() - .material(Materials.TRANSFORMED); - - secondShaft = new ModelData[2]; - - mat.getModel(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Direction.Axis.X)) - .createInstances(secondShaft); - - drive = mat.getModel(AllBlockPartials.BOGEY_DRIVE) - .createInstance(); - piston = mat.getModel(AllBlockPartials.BOGEY_PISTON) - .createInstance(); - wheels = mat.getModel(AllBlockPartials.LARGE_BOGEY_WHEELS) - .createInstance(); - pin = mat.getModel(AllBlockPartials.BOGEY_PIN) - .createInstance(); - } - - @Override - public void beginFrame(float wheelAngle, PoseStack ms) { - super.beginFrame(wheelAngle, ms); - - if (ms == null) { - for (int i : Iterate.zeroAndOne) - secondShaft[i].setEmptyTransform(); - drive.setEmptyTransform(); - piston.setEmptyTransform(); - wheels.setEmptyTransform(); - pin.setEmptyTransform(); - return; - } - - for (int i : Iterate.zeroAndOne) - secondShaft[i].setTransform(ms) - .translate(-.5f, .25f, .5f + i * -2) - .centre() - .rotateX(wheelAngle) - .unCentre(); - - drive.setTransform(ms); - piston.setTransform(ms) - .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))); - - wheels.setTransform(ms) - .translate(0, 1, 0) - .rotateX(wheelAngle); - pin.setTransform(ms) - .translate(0, 1, 0) - .rotateX(wheelAngle) - .translate(0, 1 / 4f, 0) - .rotateX(-wheelAngle); - } - - @Override - public void updateLight(int blockLight, int skyLight) { - super.updateLight(blockLight, skyLight); - for (ModelData shaft : secondShaft) - shaft.setBlockLight(blockLight) - .setSkyLight(skyLight); - drive.setBlockLight(blockLight) - .setSkyLight(skyLight); - piston.setBlockLight(blockLight) - .setSkyLight(skyLight); - wheels.setBlockLight(blockLight) - .setSkyLight(skyLight); - pin.setBlockLight(blockLight) - .setSkyLight(skyLight); - } - - @Override - public void remove() { - super.remove(); - for (ModelData shaft : secondShaft) - shaft.delete(); - drive.delete(); - piston.delete(); - wheels.delete(); - pin.delete(); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java deleted file mode 100644 index 2f532d34ca..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageBogey.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.simibubi.create.content.logistics.trains.entity; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.TrackGraph; - -import net.createmod.catnip.platform.CatnipServices; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.core.Direction.Axis; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.registries.ForgeRegistries; - -public class CarriageBogey { - - public Carriage carriage; - - boolean isLeading; - - IBogeyBlock type; - Couple points; - - LerpedFloat wheelAngle; - LerpedFloat yaw; - LerpedFloat pitch; - - public Couple couplingAnchors; - - int derailAngle; - - public CarriageBogey(IBogeyBlock type, TravellingPoint point, TravellingPoint point2) { - this.type = type; - points = Couple.create(point, point2); - wheelAngle = LerpedFloat.angular(); - yaw = LerpedFloat.angular(); - pitch = LerpedFloat.angular(); - derailAngle = Create.RANDOM.nextInt(60) - 30; - couplingAnchors = Couple.create(null, null); - } - - public ResourceKey getDimension() { - TravellingPoint leading = leading(); - TravellingPoint trailing = trailing(); - if (leading.edge == null || trailing.edge == null) - return null; - if (leading.edge.isInterDimensional() || trailing.edge.isInterDimensional()) - return null; - ResourceKey dimension1 = leading.node1.getLocation().dimension; - ResourceKey dimension2 = trailing.node1.getLocation().dimension; - if (dimension1.equals(dimension2)) - return dimension1; - return null; - } - - public void updateAngles(CarriageContraptionEntity entity, double distanceMoved) { - double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); - - float xRot = 0; - float yRot = 0; - - if (leading().edge == null || carriage.train.derailed) { - yRot = -90 + entity.yaw - derailAngle; - } else if (!entity.level.dimension() - .equals(getDimension())) { - yRot = -90 + entity.yaw; - xRot = 0; - } else { - Vec3 positionVec = leading().getPosition(); - Vec3 coupledVec = trailing().getPosition(); - double diffX = positionVec.x - coupledVec.x; - double diffY = positionVec.y - coupledVec.y; - double diffZ = positionVec.z - coupledVec.z; - yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90; - xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ))); - } - - double newWheelAngle = (wheelAngle.getValue() - angleDiff) % 360; - - for (boolean twice : Iterate.trueAndFalse) { - if (twice && !entity.firstPositionUpdate) - continue; - wheelAngle.setValue(newWheelAngle); - pitch.setValue(xRot); - yaw.setValue(-yRot); - } - } - - public TravellingPoint leading() { - return points.getFirst(); - } - - public TravellingPoint trailing() { - return points.getSecond(); - } - - public double getStress() { - if (getDimension() == null) - return 0; - if (carriage.train.derailed) - return 0; - return type.getWheelPointSpacing() - leading().getPosition() - .distanceTo(trailing().getPosition()); - } - - @Nullable - public Vec3 getAnchorPosition() { - if (leading().edge == null) - return null; - return points.getFirst() - .getPosition() - .add(points.getSecond() - .getPosition()) - .scale(.5); - } - - public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, - float partialTicks, boolean leading) { - Vec3 thisOffset = type.getConnectorAnchorOffset(); - thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1); - - thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X); - thisOffset = VecHelper.rotate(thisOffset, yaw.getValue(partialTicks), Axis.Y); - thisOffset = VecHelper.rotate(thisOffset, -entityYRot - 90, Axis.Y); - thisOffset = VecHelper.rotate(thisOffset, entityXRot, Axis.X); - thisOffset = VecHelper.rotate(thisOffset, -180, Axis.Y); - thisOffset = thisOffset.add(0, 0, leading ? 0 : -bogeySpacing); - thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y); - thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X); - thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y); - - couplingAnchors.set(leading, entityPos.add(thisOffset)); - } - - public CompoundTag write(DimensionPalette dimensions) { - CompoundTag tag = new CompoundTag(); - tag.putString("Type", CatnipServices.REGISTRIES.getKeyOrThrow((Block) type) - .toString()); - tag.put("Points", points.serializeEach(tp -> tp.write(dimensions))); - return tag; - } - - public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { - ResourceLocation location = new ResourceLocation(tag.getString("Type")); - IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); - Couple points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), - c -> TravellingPoint.read(c, graph, dimensions)); - CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond()); - return carriageBogey; - } - - public BogeyInstance createInstance(MaterialManager materialManager) { - return type.createInstance(materialManager, this); - } - - void setLeading() { - isLeading = true; - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java deleted file mode 100644 index 322d0239ab..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.simibubi.create.content.logistics.trains.entity; - -import java.util.Collection; -import java.util.List; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class CarriageCouplingRenderer { - - public static void renderAll(PoseStack ms, MultiBufferSource buffer) { - Collection trains = CreateClient.RAILWAYS.trains.values(); - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - BlockState air = Blocks.AIR.defaultBlockState(); - float partialTicks = AnimationTickHolder.getPartialTicks(); - Entity cameraEntity = Minecraft.getInstance().cameraEntity; - if (cameraEntity == null) - return; - - Vec3 camera = cameraEntity.getPosition(partialTicks); - Level level = cameraEntity.level; - - for (Train train : trains) { - List carriages = train.carriages; - for (int i = 0; i < carriages.size() - 1; i++) { - Carriage carriage = carriages.get(i); - CarriageContraptionEntity entity = carriage.getDimensional(level).entity.get(); - Carriage carriage2 = carriages.get(i + 1); - CarriageContraptionEntity entity2 = carriage.getDimensional(level).entity.get(); - - if (entity == null || entity2 == null) - continue; - - CarriageBogey bogey1 = carriage.trailingBogey(); - CarriageBogey bogey2 = carriage2.leadingBogey(); - Vec3 anchor = bogey1.couplingAnchors.getSecond(); - Vec3 anchor2 = bogey2.couplingAnchors.getFirst(); - - if (anchor == null || anchor2 == null) - continue; - if (!anchor.closerThan(camera, 64)) - continue; - - int lightCoords = getPackedLightCoords(entity, partialTicks); - int lightCoords2 = getPackedLightCoords(entity2, partialTicks); - - double diffX = anchor2.x - anchor.x; - double diffY = anchor2.y - anchor.y; - double diffZ = anchor2.z - anchor.z; - float yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90; - float xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ))); - - Vec3 position = entity.getPosition(partialTicks); - Vec3 position2 = entity2.getPosition(partialTicks); - - ms.pushPose(); - ms.pushPose(); - ms.translate(anchor.x, anchor.y, anchor.z); - CachedPartialBuffers.partial(AllBlockPartials.TRAIN_COUPLING_HEAD, air) - .rotate(Direction.Axis.Y, Mth.DEG_TO_RAD * -yRot) - .rotate(Direction.Axis.X, Mth.DEG_TO_RAD * xRot) - .light(lightCoords) - .renderInto(ms, vb); - - float margin = 3 / 16f; - double couplingDistance = train.carriageSpacing.get(i) - 2 * margin - - bogey1.type.getConnectorAnchorOffset().z - bogey2.type.getConnectorAnchorOffset().z; - int couplingSegments = (int) Math.round(couplingDistance * 4); - double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; - for (int j = 0; j < couplingSegments; j++) { - CachedPartialBuffers.partial(AllBlockPartials.TRAIN_COUPLING_CABLE, air) - .rotate(Direction.Axis.Y, Mth.DEG_TO_RAD * (-yRot + 180)) - .rotate(Direction.Axis.X, Mth.DEG_TO_RAD * -xRot) - .translate(0, 0, margin + 2 / 16f) - .scale(1, 1, (float) stretch) - .translate(0, 0, j / 4f) - .light(lightCoords) - .renderInto(ms, vb); - } - - ms.popPose(); - - ms.pushPose(); - ms.translate(-position.x, -position.y, -position.z); - ms.translate(position2.x, position2.y, position2.z); - ms.translate(anchor2.x, anchor2.y, anchor2.z); - CachedPartialBuffers.partial(AllBlockPartials.TRAIN_COUPLING_HEAD, air) - .rotate(Direction.Axis.Y, Mth.DEG_TO_RAD * (-yRot + 180)) - .rotate(Direction.Axis.X, Mth.DEG_TO_RAD * -xRot) - .light(lightCoords2) - .renderInto(ms, vb); - ms.popPose(); - ms.popPose(); - - } - } - - } - - public static int getPackedLightCoords(Entity pEntity, float pPartialTicks) { - BlockPos blockpos = new BlockPos(pEntity.getLightProbePosition(pPartialTicks)); - return LightTexture.pack(getBlockLightLevel(pEntity, blockpos), getSkyLightLevel(pEntity, blockpos)); - } - - protected static int getSkyLightLevel(Entity pEntity, BlockPos pPos) { - return pEntity.level.getBrightness(LightLayer.SKY, pPos); - } - - protected static int getBlockLightLevel(Entity pEntity, BlockPos pPos) { - return pEntity.isOnFire() ? 15 : pEntity.level.getBrightness(LightLayer.BLOCK, pPos); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java deleted file mode 100644 index d9f4727138..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPacket.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.simibubi.create.content.logistics.trains.entity; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.CreateClient; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.createmod.catnip.platform.CatnipServices; -import net.createmod.catnip.utility.Couple; -import net.createmod.catnip.utility.Iterate; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Block; -import net.minecraftforge.network.NetworkEvent.Context; -import net.minecraftforge.registries.ForgeRegistries; - -public class TrainPacket extends SimplePacketBase { - - UUID trainId; - Train train; - boolean add; - - public TrainPacket(Train train, boolean add) { - this.train = train; - this.add = add; - } - - public TrainPacket(FriendlyByteBuf buffer) { - add = buffer.readBoolean(); - trainId = buffer.readUUID(); - - if (!add) - return; - - UUID owner = buffer.readUUID(); - List carriages = new ArrayList<>(); - List carriageSpacing = new ArrayList<>(); - - int size = buffer.readVarInt(); - for (int i = 0; i < size; i++) { - Couple bogies = Couple.create(null, null); - for (boolean first : Iterate.trueAndFalse) { - if (!first && !buffer.readBoolean()) - continue; - IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); - bogies.set(first, new CarriageBogey(type, new TravellingPoint(), new TravellingPoint())); - } - int spacing = buffer.readVarInt(); - carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); - } - - size = buffer.readVarInt(); - for (int i = 0; i < size; i++) - carriageSpacing.add(buffer.readVarInt()); - - boolean doubleEnded = buffer.readBoolean(); - train = new Train(trainId, owner, null, carriages, carriageSpacing, doubleEnded); - - train.name = Component.Serializer.fromJson(buffer.readUtf()); - train.icon = TrainIconType.byId(buffer.readResourceLocation()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeBoolean(add); - buffer.writeUUID(train.id); - - if (!add) - return; - - buffer.writeUUID(train.owner); - - buffer.writeVarInt(train.carriages.size()); - for (Carriage carriage : train.carriages) { - for (boolean first : Iterate.trueAndFalse) { - if (!first) { - boolean onTwoBogeys = carriage.isOnTwoBogeys(); - buffer.writeBoolean(onTwoBogeys); - if (!onTwoBogeys) - continue; - } - CarriageBogey bogey = carriage.bogeys.get(first); - buffer.writeResourceLocation(CatnipServices.REGISTRIES.getKeyOrThrow((Block) bogey.type)); - } - buffer.writeVarInt(carriage.bogeySpacing); - } - - buffer.writeVarInt(train.carriageSpacing.size()); - train.carriageSpacing.forEach(buffer::writeVarInt); - - buffer.writeBoolean(train.doubleEnded); - buffer.writeUtf(Component.Serializer.toJson(train.name)); - buffer.writeResourceLocation(train.icon.id); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - Map trains = CreateClient.RAILWAYS.trains; - if (add) - trains.put(train.id, train); - else - trains.remove(trainId); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPromptPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPromptPacket.java deleted file mode 100644 index 695a75392c..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainPromptPacket.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.logistics.trains.entity; - -import java.util.function.Supplier; - -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.network.NetworkEvent.Context; - -public class TrainPromptPacket extends SimplePacketBase { - - private Component text; - private boolean shadow; - - public TrainPromptPacket(Component text, boolean shadow) { - this.text = text; - this.shadow = shadow; - } - - public TrainPromptPacket(FriendlyByteBuf buffer) { - text = buffer.readComponent(); - shadow = buffer.readBoolean(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeComponent(text); - buffer.writeBoolean(shadow); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::apply)); - context.get() - .setPacketHandled(true); - } - - @OnlyIn(Dist.CLIENT) - public void apply() { - TrainHUD.currentPrompt = text; - TrainHUD.currentPromptShadow = shadow; - TrainHUD.promptKeepAlive = 30; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayTileEntity.java deleted file mode 100644 index 7586e61bbd..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayTileEntity.java +++ /dev/null @@ -1,329 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.display; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.google.gson.JsonElement; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.DyeHelper; -import com.simibubi.create.foundation.utility.DynamicComponent; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.core.BlockPos; -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class FlapDisplayTileEntity extends KineticTileEntity { - - public List lines; - public boolean isController; - public boolean isRunning; - public int xSize, ySize; - public DyeColor[] colour; - public boolean[] glowingLines; - public boolean[] manualLines; - - public FlapDisplayTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(10); - isController = false; - xSize = 1; - ySize = 1; - colour = new DyeColor[2]; - manualLines = new boolean[2]; - glowingLines = new boolean[2]; - } - - @Override - public void initialize() { - super.initialize(); - } - - @Override - public void lazyTick() { - super.lazyTick(); - updateControllerStatus(); - } - - public void updateControllerStatus() { - if (level.isClientSide) - return; - - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof FlapDisplayBlock)) - return; - - Direction leftDirection = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING) - .getClockWise(); - boolean shouldBeController = !blockState.getValue(FlapDisplayBlock.UP) - && level.getBlockState(worldPosition.relative(leftDirection)) != blockState; - - int newXSize = 1; - int newYSize = 1; - - if (shouldBeController) { - for (int xOffset = 1; xOffset < 32; xOffset++) { - if (level.getBlockState(worldPosition.relative(leftDirection.getOpposite(), xOffset)) != blockState) - break; - newXSize++; - } - for (int yOffset = 0; yOffset < 32; yOffset++) { - if (!level.getBlockState(worldPosition.relative(Direction.DOWN, yOffset)) - .getOptionalValue(FlapDisplayBlock.DOWN) - .orElse(false)) - break; - newYSize++; - } - } - - if (isController == shouldBeController && newXSize == xSize && newYSize == ySize) - return; - - isController = shouldBeController; - xSize = newXSize; - ySize = newYSize; - colour = Arrays.copyOf(colour, ySize * 2); - glowingLines = Arrays.copyOf(glowingLines, ySize * 2); - manualLines = new boolean[ySize * 2]; - lines = null; - sendData(); - } - - @Override - public void tick() { - super.tick(); - isRunning = super.isSpeedRequirementFulfilled(); - if ((!level.isClientSide || !isRunning) && !isVirtual()) - return; - int activeFlaps = 0; - for (FlapDisplayLayout line : lines) - for (FlapDisplaySection section : line.getSections()) - activeFlaps += section.tick(); - if (activeFlaps == 0) - return; - - float volume = Mth.clamp(activeFlaps / 20f, 0.25f, 1.5f); - float bgVolume = Mth.clamp(activeFlaps / 40f, 0.25f, 1f); - BlockPos middle = worldPosition.relative(getDirection().getClockWise(), xSize / 2) - .relative(Direction.DOWN, ySize / 2); - AllSoundEvents.SCROLL_VALUE.playAt(level, middle, volume, 0.56f, false); - level.playLocalSound(middle.getX(), middle.getY(), middle.getZ(), SoundEvents.CALCITE_HIT, SoundSource.BLOCKS, - .35f * bgVolume, 1.95f, false); - } - - @Override - protected boolean isNoisy() { - return false; - } - - @Override - public boolean isSpeedRequirementFulfilled() { - return isRunning; - } - - public void applyTextManually(int lineIndex, String rawComponentText) { - FlapDisplayLayout layout = getLines().get(lineIndex); - if (!layout.isLayout("Default")) - layout.loadDefault(getMaxCharCount()); - List sections = layout.getSections(); - - FlapDisplaySection flapDisplaySection = sections.get(0); - if (rawComponentText == null) { - manualLines[lineIndex] = false; - flapDisplaySection.setText(Components.immutableEmpty()); - notifyUpdate(); - return; - } - - JsonElement json = DynamicComponent.getJsonFromString(rawComponentText); - if (json == null) - return; - - manualLines[lineIndex] = true; - Component text = isVirtual() ? Component.Serializer.fromJson(rawComponentText) - : DynamicComponent.parseCustomText(level, worldPosition, json); - flapDisplaySection.setText(text); - if (isVirtual()) - flapDisplaySection.refresh(true); - else - notifyUpdate(); - } - - public void setColour(int lineIndex, DyeColor color) { - colour[lineIndex] = color == DyeColor.WHITE ? null : color; - notifyUpdate(); - } - - public void setGlowing(int lineIndex) { - glowingLines[lineIndex] = true; - notifyUpdate(); - } - - public List getLines() { - if (lines == null) - initDefaultSections(); - return lines; - } - - public void initDefaultSections() { - lines = new ArrayList<>(); - for (int i = 0; i < ySize * 2; i++) - lines.add(new FlapDisplayLayout(getMaxCharCount())); - } - - public int getMaxCharCount() { - return getMaxCharCount(0); - } - - public int getMaxCharCount(int gaps) { - return (int) ((xSize * 16f - 2f - 4f * gaps) / 3.5f); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - - tag.putBoolean("Controller", isController); - tag.putInt("XSize", xSize); - tag.putInt("YSize", ySize); - - for (int j = 0; j < manualLines.length; j++) - if (manualLines[j]) - NBTHelper.putMarker(tag, "CustomLine" + j); - - for (int j = 0; j < glowingLines.length; j++) - if (glowingLines[j]) - NBTHelper.putMarker(tag, "GlowingLine" + j); - - for (int j = 0; j < colour.length; j++) - if (colour[j] != null) - NBTHelper.writeEnum(tag, "Dye" + j, colour[j]); - - List lines = getLines(); - for (int i = 0; i < lines.size(); i++) - tag.put("Display" + i, lines.get(i) - .write()); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - super.read(tag, clientPacket); - boolean wasActive = isController; - int prevX = xSize; - int prevY = ySize; - - isController = tag.getBoolean("Controller"); - xSize = tag.getInt("XSize"); - ySize = tag.getInt("YSize"); - - manualLines = new boolean[ySize * 2]; - for (int i = 0; i < ySize * 2; i++) - manualLines[i] = tag.contains("CustomLine" + i); - - glowingLines = new boolean[ySize * 2]; - for (int i = 0; i < ySize * 2; i++) - glowingLines[i] = tag.contains("GlowingLine" + i); - - colour = new DyeColor[ySize * 2]; - for (int i = 0; i < ySize * 2; i++) - colour[i] = tag.contains("Dye" + i) ? NBTHelper.readEnum(tag, "Dye" + i, DyeColor.class) : null; - - if (clientPacket && wasActive != isController || prevX != xSize || prevY != ySize) { - invalidateRenderBoundingBox(); - lines = null; - } - - List lines = getLines(); - for (int i = 0; i < lines.size(); i++) - lines.get(i) - .read(tag.getCompound("Display" + i)); - } - - public int getLineIndexAt(double yCoord) { - return (int) Mth.clamp(Math.floor(2 * (worldPosition.getY() - yCoord + 1)), 0, ySize * 2); - } - - public FlapDisplayTileEntity getController() { - if (isController) - return this; - - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof FlapDisplayBlock)) - return null; - - MutableBlockPos pos = getBlockPos().mutable(); - Direction side = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING) - .getClockWise(); - - for (int i = 0; i < 64; i++) { - BlockState other = level.getBlockState(pos); - - if (other.getOptionalValue(FlapDisplayBlock.UP) - .orElse(false)) { - pos.move(Direction.UP); - continue; - } - - if (!level.getBlockState(pos.relative(side)) - .getOptionalValue(FlapDisplayBlock.UP) - .orElse(true)) { - pos.move(side); - continue; - } - - BlockEntity found = level.getBlockEntity(pos); - if (found instanceof FlapDisplayTileEntity flap && flap.isController) - return flap; - - break; - } - - return null; - } - - @Override - protected AABB createRenderBoundingBox() { - AABB aabb = new AABB(worldPosition); - if (!isController) - return aabb; - Vec3i normal = getDirection().getClockWise() - .getNormal(); - return aabb.expandTowards(normal.getX() * xSize, -ySize, normal.getZ() * xSize); - } - - public Direction getDirection() { - return getBlockState().getOptionalValue(FlapDisplayBlock.HORIZONTAL_FACING) - .orElse(Direction.SOUTH) - .getOpposite(); - } - - @Override - public void addBehaviours(List behaviours) {} - - public int getLineColor(int line) { - DyeColor color = colour[line]; - return color == null ? 0xFF_D3C6BA - : DyeHelper.DYE_TABLE.get(color) - .getFirst() | 0xFF_000000; - } - - public boolean isLineGlowing(int line) { - return glowingLines[line]; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointType.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointType.java deleted file mode 100644 index 306ad68ba8..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointType.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserver; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; - -public class EdgePointType { - - public static final Map> TYPES = new HashMap<>(); - private ResourceLocation id; - private Supplier factory; - - public static final EdgePointType SIGNAL = - register(Create.asResource("signal"), SignalBoundary::new); - public static final EdgePointType STATION = - register(Create.asResource("station"), GlobalStation::new); - public static final EdgePointType OBSERVER = - register(Create.asResource("observer"), TrackObserver::new); - - public static EdgePointType register(ResourceLocation id, Supplier factory) { - EdgePointType type = new EdgePointType<>(id, factory); - TYPES.put(id, type); - return type; - } - - public EdgePointType(ResourceLocation id, Supplier factory) { - this.id = id; - this.factory = factory; - } - - public T create() { - T t = factory.get(); - t.setType(this); - return t; - } - - public ResourceLocation getId() { - return id; - } - - public static TrackEdgePoint read(FriendlyByteBuf buffer, DimensionPalette dimensions) { - ResourceLocation type = buffer.readResourceLocation(); - EdgePointType edgePointType = TYPES.get(type); - TrackEdgePoint point = edgePointType.create(); - point.read(buffer, dimensions); - return point; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserver.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserver.java deleted file mode 100644 index 62ad747bb9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserver.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.observer; - -import java.util.UUID; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalPropagator; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; - -public class TrackObserver extends SingleTileEdgePoint { - - private int activated; - private ItemStack filter; - private UUID currentTrain; - - public TrackObserver() { - activated = 0; - filter = ItemStack.EMPTY; - currentTrain = null; - } - - @Override - public void tileAdded(BlockEntity tile, boolean front) { - super.tileAdded(tile, front); - FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get(tile, FilteringBehaviour.TYPE); - if (filteringBehaviour != null) - setFilterAndNotify(tile.getLevel(), filteringBehaviour.getFilter()); - } - - @Override - public void tick(TrackGraph graph, boolean preTrains) { - super.tick(graph, preTrains); - if (isActivated()) - activated--; - if (!isActivated()) - currentTrain = null; - } - - public void setFilterAndNotify(Level level, ItemStack filter) { - this.filter = filter; - notifyTrains(level); - } - - private void notifyTrains(Level level) { - TrackGraph graph = Create.RAILWAYS.sided(level) - .getGraph(level, edgeLocation.getFirst()); - if (graph == null) - return; - TrackEdge edge = graph.getConnection(edgeLocation.map(graph::locateNode)); - if (edge == null) - return; - SignalPropagator.notifyTrains(graph, edge); - } - - public ItemStack getFilter() { - return filter; - } - - public UUID getCurrentTrain() { - return currentTrain; - } - - public boolean isActivated() { - return activated > 0; - } - - public void keepAlive(Train train) { - activated = 8; - currentTrain = train.id; - } - - @Override - public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { - super.read(nbt, migration, dimensions); - activated = nbt.getInt("Activated"); - filter = ItemStack.of(nbt.getCompound("Filter")); - if (nbt.contains("TrainId")) - currentTrain = nbt.getUUID("TrainId"); - } - - @Override - public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) { - super.read(buffer, dimensions); - } - - @Override - public void write(CompoundTag nbt, DimensionPalette dimensions) { - super.write(nbt, dimensions); - nbt.putInt("Activated", activated); - nbt.put("Filter", filter.serializeNBT()); - if (currentTrain != null) - nbt.putUUID("TrainId", currentTrain); - } - - @Override - public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) { - super.write(buffer, dimensions); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverBlock.java deleted file mode 100644 index 59c5c89325..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverBlock.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.observer; - -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; - -public class TrackObserverBlock extends Block implements ITE, IWrenchable { - - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - - public TrackObserverBlock(Properties p_49795_) { - super(p_49795_); - registerDefaultState(defaultBlockState().setValue(POWERED, false)); - } - - @Override - protected void createBlockStateDefinition(Builder pBuilder) { - super.createBlockStateDefinition(pBuilder.add(POWERED)); - } - - @Override - public boolean isSignalSource(BlockState state) { - return true; - } - - @Override - public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { - return blockState.getValue(POWERED) ? 15 : 0; - } - - @Override - public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { - return true; - } - - @Override - public Class getTileEntityClass() { - return TrackObserverTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TRACK_OBSERVER.get(); - } - - @Override - public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { - if (pState.hasBlockEntity() && (!pState.is(pNewState.getBlock()) || !pNewState.hasBlockEntity())) { - TileEntityBehaviour.destroy(pLevel, pPos, FilteringBehaviour.TYPE); - pLevel.removeBlockEntity(pPos); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverRenderer.java deleted file mode 100644 index c9f4655f3a..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverRenderer.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.observer; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class TrackObserverRenderer extends SmartTileEntityRenderer { - - public TrackObserverRenderer(Context context) { - super(context); - } - - @Override - protected void renderSafe(TrackObserverTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); - BlockPos pos = te.getBlockPos(); - - TrackTargetingBehaviour target = te.edgePoint; - BlockPos targetPosition = target.getGlobalPosition(); - Level level = te.getLevel(); - BlockState trackState = level.getBlockState(targetPosition); - Block block = trackState.getBlock(); - - if (!(block instanceof ITrackBlock)) - return; - - ms.pushPose(); - ms.translate(-pos.getX(), -pos.getY(), -pos.getZ()); - RenderedTrackOverlayType type = RenderedTrackOverlayType.OBSERVER; - TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), ms, - buffer, light, overlay, type, 1); - ms.popPose(); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverTileEntity.java deleted file mode 100644 index 7b19574f46..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/observer/TrackObserverTileEntity.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.observer; - -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -public class TrackObserverTileEntity extends SmartTileEntity implements ITransformableTE { - - public TrackTargetingBehaviour edgePoint; - - private FilteringBehaviour filtering; - - public TrackObserverTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.OBSERVER)); - behaviours.add(filtering = createFilter().withCallback(this::onFilterChanged)); - } - - private void onFilterChanged(ItemStack newFilter) { - if (level.isClientSide()) - return; - TrackObserver observer = getObserver(); - if (observer != null) - observer.setFilterAndNotify(level, newFilter); - } - - @Override - public void tick() { - super.tick(); - - if (level.isClientSide()) - return; - - boolean shouldBePowered = false; - TrackObserver observer = getObserver(); - if (observer != null) - shouldBePowered = observer.isActivated(); - if (isBlockPowered() == shouldBePowered) - return; - - BlockState blockState = getBlockState(); - if (blockState.hasProperty(TrackObserverBlock.POWERED)) - level.setBlock(worldPosition, blockState.setValue(TrackObserverBlock.POWERED, shouldBePowered), 3); - DisplayLinkBlock.notifyGatherers(level, worldPosition); - } - - @Nullable - public TrackObserver getObserver() { - return edgePoint.getEdgePoint(); - } - - public ItemStack getFilter() { - return filtering.getFilter(); - } - - public boolean isBlockPowered() { - return getBlockState().getOptionalValue(TrackObserverBlock.POWERED) - .orElse(false); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); - } - - @Override - public void transform(StructureTransform transform) { - edgePoint.transform(transform); - } - - public FilteringBehaviour createFilter() { - return new FilteringBehaviour(this, new ValueBoxTransform() { - - @Override - protected void rotate(BlockState state, PoseStack ms) { - TransformStack.cast(ms) - .rotateX(90); - } - - @Override - protected Vec3 getLocalOffset(BlockState state) { - return new Vec3(0.5, 15 / 16d, 0.5); - } - - protected float getScale() { - return super.getScale() * 1.5f; - }; - - }); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroupPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroupPacket.java deleted file mode 100644 index 8918a6e77d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroupPacket.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Supplier; - -import com.google.common.collect.ImmutableList; -import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent.Context; - -public class SignalEdgeGroupPacket extends SimplePacketBase { - - List ids; - List colors; - boolean add; - - public SignalEdgeGroupPacket(UUID id, EdgeGroupColor color) { - this(ImmutableList.of(id), ImmutableList.of(color), true); - } - - public SignalEdgeGroupPacket(List ids, List colors, boolean add) { - this.ids = ids; - this.colors = colors; - this.add = add; - } - - public SignalEdgeGroupPacket(FriendlyByteBuf buffer) { - ids = new ArrayList<>(); - colors = new ArrayList<>(); - add = buffer.readBoolean(); - int size = buffer.readVarInt(); - for (int i = 0; i < size; i++) - ids.add(buffer.readUUID()); - size = buffer.readVarInt(); - for (int i = 0; i < size; i++) - colors.add(EdgeGroupColor.values()[buffer.readVarInt()]); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeBoolean(add); - buffer.writeVarInt(ids.size()); - ids.forEach(buffer::writeUUID); - buffer.writeVarInt(colors.size()); - colors.forEach(c -> buffer.writeVarInt(c.ordinal())); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - Map signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups; - int i = 0; - for (UUID id : ids) { - if (!add) { - signalEdgeGroups.remove(id); - continue; - } - - SignalEdgeGroup group = new SignalEdgeGroup(id); - signalEdgeGroups.put(id, group); - if (colors.size() > i) - group.color = colors.get(i); - i++; - } - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java deleted file mode 100644 index 1145d93c52..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalRenderer.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.OverlayState; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.ponder.utility.WorldTickHolder; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class SignalRenderer extends SafeTileEntityRenderer { - - public SignalRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(SignalTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - BlockState blockState = te.getBlockState(); - SignalState signalState = te.getState(); - OverlayState overlayState = te.getOverlay(); - - float renderTime = WorldTickHolder.getRenderTime(te.getLevel()); - if (signalState.isRedLight(renderTime)) - CachedPartialBuffers.partial(AllBlockPartials.SIGNAL_ON, blockState) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - else - CachedPartialBuffers.partial(AllBlockPartials.SIGNAL_OFF, blockState) - .light(light) - .renderInto(ms, buffer.getBuffer(RenderType.solid())); - - BlockPos pos = te.getBlockPos(); - TrackTargetingBehaviour target = te.edgePoint; - BlockPos targetPosition = target.getGlobalPosition(); - Level level = te.getLevel(); - BlockState trackState = level.getBlockState(targetPosition); - Block block = trackState.getBlock(); - - if (!(block instanceof ITrackBlock)) - return; - if (overlayState == OverlayState.SKIP) - return; - - ms.pushPose(); - ms.translate(-pos.getX(), -pos.getY(), -pos.getZ()); - RenderedTrackOverlayType type = - overlayState == OverlayState.DUAL ? RenderedTrackOverlayType.DUAL_SIGNAL : RenderedTrackOverlayType.SIGNAL; - TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), ms, - buffer, light, overlay, type, 1); - ms.popPose(); - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java deleted file mode 100644 index 42f9d79256..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; - -import java.util.List; - -import javax.annotation.Nullable; - -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.NBTHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class SignalTileEntity extends SmartTileEntity implements ITransformableTE { - - public static enum OverlayState { - RENDER, SKIP, DUAL - } - - public static enum SignalState { - RED, YELLOW, GREEN, INVALID; - - public boolean isRedLight(float renderTime) { - return this == RED || this == INVALID && renderTime % 40 < 3; - } - - public boolean isYellowLight(float renderTime) { - return this == YELLOW; - } - - public boolean isGreenLight(float renderTime) { - return this == GREEN; - } - } - - public TrackTargetingBehaviour edgePoint; - - private SignalState state; - private OverlayState overlay; - private int switchToRedAfterTrainEntered; - private boolean lastReportedPower; - - public SignalTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - this.state = SignalState.INVALID; - this.overlay = OverlayState.SKIP; - this.lastReportedPower = false; - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - NBTHelper.writeEnum(tag, "State", state); - NBTHelper.writeEnum(tag, "Overlay", overlay); - tag.putBoolean("Power", lastReportedPower); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - super.read(tag, clientPacket); - state = NBTHelper.readEnum(tag, "State", SignalState.class); - overlay = NBTHelper.readEnum(tag, "Overlay", OverlayState.class); - lastReportedPower = tag.getBoolean("Power"); - invalidateRenderBoundingBox(); - } - - @Nullable - public SignalBoundary getSignal() { - return edgePoint.getEdgePoint(); - } - - public boolean isPowered() { - return state == SignalState.RED; - } - - @Override - public void addBehaviours(List behaviours) { - edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.SIGNAL); - behaviours.add(edgePoint); - } - - @Override - public void tick() { - super.tick(); - if (level.isClientSide) - return; - - SignalBoundary boundary = getSignal(); - if (boundary == null) { - enterState(SignalState.INVALID); - setOverlay(OverlayState.RENDER); - return; - } - - BlockState blockState = getBlockState(); - - blockState.getOptionalValue(SignalBlock.POWERED).ifPresent(powered -> { - if (lastReportedPower == powered) - return; - lastReportedPower = powered; - boundary.updateTilePower(this); - notifyUpdate(); - }); - - blockState.getOptionalValue(SignalBlock.TYPE) - .ifPresent(stateType -> { - SignalType targetType = boundary.getTypeFor(worldPosition); - if (stateType != targetType) { - level.setBlock(worldPosition, blockState.setValue(SignalBlock.TYPE, targetType), 3); - refreshBlockState(); - } - }); - - enterState(boundary.getStateFor(worldPosition)); - setOverlay(boundary.getOverlayFor(worldPosition)); - } - - public boolean getReportedPower() { - return lastReportedPower; - } - - public SignalState getState() { - return state; - } - - public OverlayState getOverlay() { - return overlay; - } - - public void setOverlay(OverlayState state) { - if (this.overlay == state) - return; - this.overlay = state; - notifyUpdate(); - } - - public void enterState(SignalState state) { - if (switchToRedAfterTrainEntered > 0) - switchToRedAfterTrainEntered--; - if (this.state == state) - return; - if (state == SignalState.RED && switchToRedAfterTrainEntered > 0) - return; - this.state = state; - switchToRedAfterTrainEntered = state == SignalState.GREEN || state == SignalState.YELLOW ? 15 : 0; - notifyUpdate(); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); - } - - @Override - public void transform(StructureTransform transform) { - edgePoint.transform(transform); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java deleted file mode 100644 index f18b78390b..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; - -import com.simibubi.create.content.logistics.trains.DimensionPalette; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; - -public abstract class SingleTileEdgePoint extends TrackEdgePoint { - - public ResourceKey tileDimension; - public BlockPos tilePos; - - public BlockPos getTilePos() { - return tilePos; - } - - public ResourceKey getTileDimension() { - return tileDimension; - } - - @Override - public void tileAdded(BlockEntity tile, boolean front) { - this.tilePos = tile.getBlockPos(); - this.tileDimension = tile.getLevel() - .dimension(); - } - - @Override - public void tileRemoved(BlockPos tilePos, boolean front) { - removeFromAllGraphs(); - } - - @Override - public void invalidate(LevelAccessor level) { - invalidateAt(level, tilePos); - } - - @Override - public boolean canMerge() { - return false; - } - - @Override - public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { - super.read(nbt, migration, dimensions); - if (migration) - return; - tilePos = NbtUtils.readBlockPos(nbt.getCompound("TilePos")); - tileDimension = dimensions.decode(nbt.contains("TileDimension") ? nbt.getInt("TileDimension") : -1); - } - - @Override - public void write(CompoundTag nbt, DimensionPalette dimensions) { - super.write(nbt, dimensions); - nbt.put("TilePos", NbtUtils.writeBlockPos(tilePos)); - nbt.putInt("TileDimension", dimensions.encode(tileDimension)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java deleted file mode 100644 index 0ec69784e7..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; - -import java.util.UUID; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Couple; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; - -public abstract class TrackEdgePoint { - - public UUID id; - public Couple edgeLocation; - public double position; - private EdgePointType type; - - public void setId(UUID id) { - this.id = id; - } - - public UUID getId() { - return id; - } - - public void setType(EdgePointType type) { - this.type = type; - } - - public EdgePointType getType() { - return type; - } - - public abstract boolean canMerge(); - - public boolean canCoexistWith(EdgePointType otherType, boolean front) { - return false; - } - - public abstract void invalidate(LevelAccessor level); - - protected void invalidateAt(LevelAccessor level, BlockPos tilePos) { - TrackTargetingBehaviour behaviour = TileEntityBehaviour.get(level, tilePos, TrackTargetingBehaviour.TYPE); - if (behaviour == null) - return; - CompoundTag migrationData = new CompoundTag(); - DimensionPalette dimensions = new DimensionPalette(); - write(migrationData, dimensions); - dimensions.write(migrationData); - behaviour.invalidateEdgePoint(migrationData); - } - - public abstract void tileAdded(BlockEntity tile, boolean front); - - public abstract void tileRemoved(BlockPos tilePos, boolean front); - - public void onRemoved(TrackGraph graph) {} - - public void setLocation(Couple nodes, double position) { - this.edgeLocation = nodes; - this.position = position; - } - - public double getLocationOn(TrackEdge edge) { - return isPrimary(edge.node1) ? edge.getLength() - position : position; - } - - public boolean canNavigateVia(TrackNode side) { - return true; - } - - public boolean isPrimary(TrackNode node1) { - return edgeLocation.getSecond() - .equals(node1.getLocation()); - } - - public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { - if (migration) - return; - - id = nbt.getUUID("Id"); - position = nbt.getDouble("Position"); - edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND), - tag -> TrackNodeLocation.read(tag, dimensions)); - } - - public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) { - id = buffer.readUUID(); - edgeLocation = Couple.create(() -> TrackNodeLocation.receive(buffer, dimensions)); - position = buffer.readDouble(); - } - - public void write(CompoundTag nbt, DimensionPalette dimensions) { - nbt.putUUID("Id", id); - nbt.putDouble("Position", position); - nbt.put("Edge", edgeLocation.serializeEach(loc -> loc.write(dimensions))); - } - - public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) { - buffer.writeResourceLocation(type.getId()); - buffer.writeUUID(id); - edgeLocation.forEach(loc -> loc.send(buffer, dimensions)); - buffer.writeDouble(position); - } - - public void tick(TrackGraph graph, boolean preTrains) {} - - protected void removeFromAllGraphs() { - for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) - if (trackGraph.removePoint(getType(), id) != null) - return; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java deleted file mode 100644 index 849e69d3b2..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AbstractStationScreen.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import java.lang.ref.WeakReference; -import java.util.List; - -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.CreateClient; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainIconType; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; -import com.simibubi.create.foundation.gui.widget.IconButton; - -import net.createmod.catnip.gui.AbstractSimiScreen; -import net.createmod.catnip.gui.element.GuiGameElement; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; - -public abstract class AbstractStationScreen extends AbstractSimiScreen { - - protected AllGuiTextures background; - protected StationTileEntity te; - protected GlobalStation station; - - protected WeakReference displayedTrain; - - private IconButton confirmButton; - - public AbstractStationScreen(StationTileEntity te, GlobalStation station) { - super(te.getBlockState() - .getBlock() - .getName()); - this.te = te; - this.station = station; - displayedTrain = new WeakReference<>(null); - } - - @Override - protected void init() { - setWindowSize(background.getWidth(), background.getHeight()); - super.init(); - clearWidgets(); - - int x = guiLeft; - int y = guiTop; - - confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); - confirmButton.withCallback(this::onClose); - addRenderableWidget(confirmButton); - } - - public int getTrainIconWidth(Train train) { - TrainIconType icon = train.icon; - List carriages = train.carriages; - - int w = icon.getIconWidth(TrainIconType.ENGINE); - if (carriages.size() == 1) - return w; - - for (int i = 1; i < carriages.size(); i++) { - if (i == carriages.size() - 1 && train.doubleEnded) { - w += icon.getIconWidth(TrainIconType.FLIPPED_ENGINE) + 1; - break; - } - Carriage carriage = carriages.get(i); - w += icon.getIconWidth(carriage.bogeySpacing) + 1; - } - - return w; - } - - @Override - protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { - int x = guiLeft; - int y = guiTop; - - background.render(ms, x, y, this); - - ms.pushPose(); - TransformStack msr = TransformStack.cast(ms); - msr.pushPose() - .translate(x + background.getWidth() + 4, y + background.getHeight() + 4, 100) - .scale(40) - .rotateX(-22) - .rotateY(63); - GuiGameElement.of(te.getBlockState() - .setValue(BlockStateProperties.WATERLOGGED, false)) - .render(ms); - - if (te.resolveFlagAngle()) { - msr.translate(1 / 16f, -19 / 16f, -12 / 16f); - StationRenderer.transformFlag(msr, te, partialTicks, 180); - PartialModelGuiElement.of(getFlag(partialTicks)) - .render(ms); - } - - ms.popPose(); - } - - protected abstract PartialModel getFlag(float partialTicks); - - protected Train getImminent() { - return te.imminentTrain == null ? null : CreateClient.RAILWAYS.trains.get(te.imminentTrain); - } - - protected boolean trainPresent() { - return te.trainPresent; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java deleted file mode 100644 index a9d71a8d4d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import java.lang.ref.WeakReference; -import java.util.List; - -import com.jozufozu.flywheel.core.PartialModel; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainIconType; -import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.gui.widget.ScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.minecraft.client.gui.components.Widget; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; - -public class AssemblyScreen extends AbstractStationScreen { - - private IconButton quitAssembly; - private IconButton toggleAssemblyButton; - private List iconTypes; - private ScrollInput iconTypeScroll; - - public AssemblyScreen(StationTileEntity te, GlobalStation station) { - super(te, station); - background = AllGuiTextures.STATION_ASSEMBLING; - } - - @Override - protected void init() { - super.init(); - int x = guiLeft; - int y = guiTop; - int by = y + background.getHeight() - 24; - - Widget widget = renderables.get(0); - if (widget instanceof IconButton ib) { - ib.setIcon(AllIcons.I_PRIORITY_VERY_LOW); - ib.setToolTip(CreateLang.translateDirect("station.close")); - } - - iconTypes = TrainIconType.REGISTRY.keySet() - .stream() - .toList(); - iconTypeScroll = new ScrollInput(x + 4, y + 17, 184, 14).titled(CreateLang.translateDirect("station.icon_type")); - iconTypeScroll.withRange(0, iconTypes.size()); - iconTypeScroll.withStepFunction(ctx -> -iconTypeScroll.standardStep() - .apply(ctx)); - iconTypeScroll.calling(s -> { - Train train = displayedTrain.get(); - if (train != null) - train.icon = TrainIconType.byId(iconTypes.get(s)); - }); - iconTypeScroll.active = iconTypeScroll.visible = false; - addRenderableWidget(iconTypeScroll); - - toggleAssemblyButton = new WideIconButton(x + 94, by, AllGuiTextures.I_ASSEMBLE_TRAIN); - toggleAssemblyButton.active = false; - toggleAssemblyButton.setToolTip(CreateLang.translateDirect("station.assemble_train")); - toggleAssemblyButton.withCallback(() -> { - AllPackets.channel.sendToServer(StationEditPacket.tryAssemble(te.getBlockPos())); - }); - - quitAssembly = new IconButton(x + 73, by, AllIcons.I_DISABLE); - quitAssembly.active = true; - quitAssembly.setToolTip(CreateLang.translateDirect("station.cancel")); - quitAssembly.withCallback(() -> { - AllPackets.channel.sendToServer(StationEditPacket.configure(te.getBlockPos(), false, station.name)); - minecraft.setScreen(new StationScreen(te, station)); - }); - - addRenderableWidget(toggleAssemblyButton); - addRenderableWidget(quitAssembly); - - tickTrainDisplay(); - } - - @Override - public void tick() { - super.tick(); - tickTrainDisplay(); - Train train = displayedTrain.get(); - toggleAssemblyButton.active = te.bogeyCount > 0 || train != null; - - if (train != null) { - AllPackets.channel.sendToServer(StationEditPacket.configure(te.getBlockPos(), false, station.name)); - minecraft.setScreen(new StationScreen(te, station)); - for (Carriage carriage : train.carriages) - carriage.updateConductors(); - } - } - - private void tickTrainDisplay() { - if (getImminent() == null) { - displayedTrain = new WeakReference<>(null); - quitAssembly.active = true; - iconTypeScroll.active = iconTypeScroll.visible = false; - toggleAssemblyButton.setToolTip(CreateLang.translateDirect("station.assemble_train")); - toggleAssemblyButton.setIcon(AllGuiTextures.I_ASSEMBLE_TRAIN); - toggleAssemblyButton.withCallback(() -> { - AllPackets.channel.sendToServer(StationEditPacket.tryAssemble(te.getBlockPos())); - }); - } else { - AllPackets.channel.sendToServer(StationEditPacket.configure(te.getBlockPos(), false, station.name)); - minecraft.setScreen(new StationScreen(te, station)); - } - } - - @Override - protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { - super.renderWindow(ms, mouseX, mouseY, partialTicks); - int x = guiLeft; - int y = guiTop; - - MutableComponent header = CreateLang.translateDirect("station.assembly_title"); - font.draw(ms, header, x + background.getWidth() / 2 - font.width(header) / 2, y + 4, 0x0E2233); - - AssemblyException lastAssemblyException = te.lastException; - if (lastAssemblyException != null) { - MutableComponent text = CreateLang.translateDirect("station.failed"); - font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x775B5B); - int offset = 0; - if (te.failedCarriageIndex != -1) { - font.draw(ms, CreateLang.translateDirect("station.carriage_number", te.failedCarriageIndex), x + 30, y + 67, - 0x7A7A7A); - offset += 10; - } - font.drawWordWrap(lastAssemblyException.component, x + 30, y + 67 + offset, 134, 0x775B5B); - offset += font.split(lastAssemblyException.component, 134) - .size() * 9 + 5; - font.drawWordWrap(CreateLang.translateDirect("station.retry"), x + 30, y + 67 + offset, 134, 0x7A7A7A); - return; - } - - int bogeyCount = te.bogeyCount; - - MutableComponent text = CreateLang.translateDirect( - bogeyCount == 0 ? "station.no_bogeys" : bogeyCount == 1 ? "station.one_bogey" : "station.more_bogeys", - bogeyCount); - font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x7A7A7A); - - font.drawWordWrap(CreateLang.translateDirect("station.how_to"), x + 28, y + 62, 134, 0x7A7A7A); - font.drawWordWrap(CreateLang.translateDirect("station.how_to_1"), x + 28, y + 94, 134, 0x7A7A7A); - font.drawWordWrap(CreateLang.translateDirect("station.how_to_2"), x + 28, y + 117, 138, 0x7A7A7A); - } - - @Override - public void removed() { - super.removed(); - Train train = displayedTrain.get(); - if (train != null) { - ResourceLocation iconId = iconTypes.get(iconTypeScroll.getState()); - train.icon = TrainIconType.byId(iconId); - AllPackets.channel.sendToServer(new TrainEditPacket(train.id, "", iconId)); - } - } - - @Override - protected PartialModel getFlag(float partialTicks) { - return AllBlockPartials.STATION_ASSEMBLE; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java deleted file mode 100644 index eeaf9f4857..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class StationEditPacket extends TileEntityConfigurationPacket { - - boolean dropSchedule; - boolean assemblyMode; - Boolean tryAssemble; - String name; - - public static StationEditPacket dropSchedule(BlockPos pos) { - StationEditPacket packet = new StationEditPacket(pos); - packet.dropSchedule = true; - return packet; - } - - public static StationEditPacket tryAssemble(BlockPos pos) { - StationEditPacket packet = new StationEditPacket(pos); - packet.tryAssemble = true; - return packet; - } - - public static StationEditPacket tryDisassemble(BlockPos pos) { - StationEditPacket packet = new StationEditPacket(pos); - packet.tryAssemble = false; - return packet; - } - - public static StationEditPacket configure(BlockPos pos, boolean assemble, String name) { - StationEditPacket packet = new StationEditPacket(pos); - packet.assemblyMode = assemble; - packet.tryAssemble = null; - packet.name = name; - return packet; - } - - public StationEditPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - public StationEditPacket(BlockPos pos) { - super(pos); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) { - buffer.writeBoolean(dropSchedule); - if (dropSchedule) - return; - buffer.writeBoolean(tryAssemble != null); - if (tryAssemble != null) { - buffer.writeBoolean(tryAssemble); - return; - } - buffer.writeBoolean(assemblyMode); - buffer.writeUtf(name); - } - - @Override - protected void readSettings(FriendlyByteBuf buffer) { - if (buffer.readBoolean()) { - dropSchedule = true; - return; - } - name = ""; - if (buffer.readBoolean()) { - tryAssemble = buffer.readBoolean(); - return; - } - assemblyMode = buffer.readBoolean(); - name = buffer.readUtf(256); - } - - @Override - protected void applySettings(ServerPlayer player, StationTileEntity te) { - Level level = te.getLevel(); - BlockPos blockPos = te.getBlockPos(); - BlockState blockState = level.getBlockState(blockPos); - - if (dropSchedule) { - scheduleDropRequested(player, te); - return; - } - - if (!name.isBlank()) { - GlobalStation station = te.getStation(); - GraphLocation graphLocation = te.edgePoint.determineGraphLocation(); - if (station != null && graphLocation != null) { - station.name = name; - Create.RAILWAYS.sync.pointAdded(graphLocation.graph, station); - Create.RAILWAYS.markTracksDirty(); - } - } - - if (!(blockState.getBlock() instanceof StationBlock)) - return; - - Boolean isAssemblyMode = blockState.getValue(StationBlock.ASSEMBLING); - boolean assemblyComplete = false; - - if (tryAssemble != null) { - if (!isAssemblyMode) - return; - if (tryAssemble) { - te.assemble(player.getUUID()); - assemblyComplete = te.getStation() != null && te.getStation() - .getPresentTrain() != null; - } else { - if (disassembleAndEnterMode(player, te)) - te.refreshAssemblyInfo(); - } - if (!assemblyComplete) - return; - } - if (isAssemblyMode == assemblyMode) - return; - - BlockState newState = blockState.cycle(StationBlock.ASSEMBLING); - Boolean nowAssembling = newState.getValue(StationBlock.ASSEMBLING); - - if (nowAssembling) { - if (!disassembleAndEnterMode(player, te)) - return; - } else { - te.cancelAssembly(); - } - - level.setBlock(blockPos, newState, 3); - te.refreshBlockState(); - - if (nowAssembling) - te.refreshAssemblyInfo(); - - GlobalStation station = te.getStation(); - GraphLocation graphLocation = te.edgePoint.determineGraphLocation(); - if (station != null && graphLocation != null) { - station.assembling = nowAssembling; - Create.RAILWAYS.sync.pointAdded(graphLocation.graph, station); - Create.RAILWAYS.markTracksDirty(); - - if (nowAssembling) - for (Train train : Create.RAILWAYS.sided(level).trains.values()) { - if (train.navigation.destination != station) - continue; - GlobalStation preferredDestination = train.runtime.startCurrentInstruction(); - if (preferredDestination != null) - train.navigation.startNavigation(preferredDestination, Double.MAX_VALUE, false); - else - train.navigation.startNavigation(station, Double.MAX_VALUE, false); - } - } - } - - private void scheduleDropRequested(ServerPlayer sender, StationTileEntity te) { - GlobalStation station = te.getStation(); - if (station == null) - return; - Train train = station.getPresentTrain(); - if (train == null) - return; - ItemStack schedule = train.runtime.returnSchedule(); - dropSchedule(sender, te, schedule); - } - - private boolean disassembleAndEnterMode(ServerPlayer sender, StationTileEntity te) { - GlobalStation station = te.getStation(); - if (station != null) { - Train train = station.getPresentTrain(); - BlockPos trackPosition = te.edgePoint.getGlobalPosition(); - ItemStack schedule = train == null ? ItemStack.EMPTY : train.runtime.returnSchedule(); - if (train != null && !train.disassemble(te.getAssemblyDirection(), trackPosition.above())) - return false; - dropSchedule(sender, te, schedule); - } - return te.tryEnterAssemblyMode(); - } - - private void dropSchedule(ServerPlayer sender, StationTileEntity te, ItemStack schedule) { - if (schedule.isEmpty()) - return; - if (sender.getMainHandItem() - .isEmpty()) { - sender.getInventory() - .placeItemBackInInventory(schedule); - return; - } - Vec3 v = VecHelper.getCenterOf(te.getBlockPos()); - ItemEntity itemEntity = new ItemEntity(te.getLevel(), v.x, v.y, v.z, schedule); - itemEntity.setDeltaMovement(Vec3.ZERO); - te.getLevel() - .addFreshEntity(itemEntity); - } - - @Override - protected void applySettings(StationTileEntity te) {} - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMapData.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMapData.java deleted file mode 100644 index a440b81355..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMapData.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.LevelAccessor; - -public interface StationMapData { - - boolean toggleStation(LevelAccessor level, BlockPos pos, StationTileEntity stationTileEntity); - - void addStationMarker(StationMarker marker); - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMarker.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMarker.java deleted file mode 100644 index 3caad3aec7..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationMarker.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import java.util.Objects; -import java.util.Optional; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Matrix4f; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.saveddata.maps.MapDecoration; -import net.minecraft.world.level.saveddata.maps.MapItemSavedData; - -public class StationMarker { - - private final BlockPos source; - private final BlockPos target; - private final Component name; - - public StationMarker(BlockPos source, BlockPos target, Component name) { - this.source = source; - this.target = target; - this.name = name; - } - - public static StationMarker load(CompoundTag tag) { - BlockPos source = NbtUtils.readBlockPos(tag.getCompound("source")); - BlockPos target = NbtUtils.readBlockPos(tag.getCompound("target")); - Component name = Component.Serializer.fromJson(tag.getString("name")); - if (name == null) name = Components.immutableEmpty(); - - return new StationMarker(source, target, name); - } - - public static StationMarker fromWorld(BlockGetter level, BlockPos pos) { - Optional stationOption = AllTileEntities.TRACK_STATION.get(level, pos); - - if (stationOption.isEmpty() || stationOption.get().getStation() == null) - return null; - - String name = stationOption.get() - .getStation().name; - return new StationMarker(pos, TileEntityBehaviour.get(stationOption.get(), TrackTargetingBehaviour.TYPE) - .getPositionForMapMarker(), Components.literal(name)); - } - - public CompoundTag save() { - CompoundTag tag = new CompoundTag(); - tag.put("source", NbtUtils.writeBlockPos(this.source)); - tag.put("target", NbtUtils.writeBlockPos(this.target)); - tag.putString("name", Component.Serializer.toJson(this.name)); - - return tag; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - StationMarker that = (StationMarker) o; - - if (!target.equals(that.target)) return false; - return name.equals(that.name); - } - - @Override - public int hashCode() { - return Objects.hash(this.target, this.name); - } - - public BlockPos getTarget() { - return this.target; - } - - public BlockPos getSource() { - return this.source; - } - - public Component getName() { - return name; - } - - public MapDecoration.Type getType() { - return MapDecoration.Type.MANSION; - } - - public String getId() { - return "create:station-" + this.target.getX() + "," + this.target.getY() + "," + this.target.getZ(); - } - - public static class Decoration extends MapDecoration { - - public Decoration(byte pX, byte pY, Component pName) { - super(Type.MANSION, pX, pY, (byte) 0, pName); - } - - @Override - public boolean renderOnFrame() { - return true; - } - - @Override - public boolean render(int index) { - return true; - } - - public boolean render(PoseStack ms, MultiBufferSource bufferSource, int mapId, MapItemSavedData mapData, boolean active, int packedLight, int index) { - ms.pushPose(); - - ms.translate(getX() / 2D + 64.0, getY() / 2D + 64.0, -0.02D); - - ms.pushPose(); - - ms.translate(0.5f, 0f, 0); - ms.scale(4.5F, 4.5F, 3.0F); - - VertexConsumer buffer = bufferSource.getBuffer(RenderType.text(Create.asResource("textures/gui/station_map_icon.png"))); - - float zOffset = -0.001f; - float alpha = 1f; - - Matrix4f mat = ms.last().pose(); - buffer.vertex(mat, -1, -1, zOffset * index).color(1f, 1f, 1f, alpha).uv(0.0f , 0.0f ).uv2(packedLight).endVertex(); - buffer.vertex(mat, -1, 1, zOffset * index).color(1f, 1f, 1f, alpha).uv(0.0f , 0.0f + 1.0f).uv2(packedLight).endVertex(); - buffer.vertex(mat, 1, 1, zOffset * index).color(1f, 1f, 1f, alpha).uv(0.0f + 1.0f, 0.0f + 1.0f).uv2(packedLight).endVertex(); - buffer.vertex(mat, 1, -1, zOffset * index).color(1f, 1f, 1f, alpha).uv(0.0f + 1.0f, 0.0f ).uv2(packedLight).endVertex(); - - ms.popPose(); - - if (getName() != null) { - Font font = Minecraft.getInstance().font; - Component component = getName(); - float f6 = (float)font.width(component); -// float f7 = Mth.clamp(25.0F / f6, 0.0F, 6.0F / 9.0F); - ms.pushPose(); - //ms.translate((double)(0.0F + (float)getX() / 2.0F + 64.0F / 2.0F), (double)(0.0F + (float)getY() / 2.0F + 64.0F + 4.0F), (double)-0.025F); - ms.translate(0, 6.0D, -0.005F); - - ms.scale(0.8f, 0.8f, 1.0F); - ms.translate(-f6 / 2f + .5f, 0, 0); - //ms.scale(f7, f7, 1.0F); - font.drawInBatch(component, 0.0F, 0.0F, -1, false, ms.last().pose(), bufferSource, false, Integer.MIN_VALUE, 15728880); - ms.popPose(); - } - - ms.popPose(); - - return false; - } - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationRenderer.java deleted file mode 100644 index 46917e19fb..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationRenderer.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.util.transform.Transform; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.block.depot.DepotRenderer; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -public class StationRenderer extends SafeTileEntityRenderer { - - public StationRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(StationTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, - int light, int overlay) { - - BlockPos pos = te.getBlockPos(); - TrackTargetingBehaviour target = te.edgePoint; - BlockPos targetPosition = target.getGlobalPosition(); - Level level = te.getLevel(); - - DepotRenderer.renderItemsOf(te, partialTicks, ms, buffer, light, overlay, te.depotBehaviour); - - BlockState trackState = level.getBlockState(targetPosition); - Block block = trackState.getBlock(); - if (!(block instanceof ITrackBlock)) - return; - - GlobalStation station = te.getStation(); - boolean isAssembling = te.getBlockState() - .getValue(StationBlock.ASSEMBLING); - - if (!isAssembling || (station == null || station.getPresentTrain() != null) && !te.isVirtual()) { - renderFlag( - te.flag.getValue(partialTicks) > 0.75f ? AllBlockPartials.STATION_ON : AllBlockPartials.STATION_OFF, te, - partialTicks, ms, buffer, light, overlay); - ms.pushPose(); - ms.translate(-pos.getX(), -pos.getY(), -pos.getZ()); - TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), - ms, buffer, light, overlay, RenderedTrackOverlayType.STATION, 1); - ms.popPose(); - return; - } - - renderFlag(AllBlockPartials.STATION_ASSEMBLE, te, partialTicks, ms, buffer, light, overlay); - - ITrackBlock track = (ITrackBlock) block; - Direction direction = te.assemblyDirection; - - if (te.isVirtual() && te.bogeyLocations == null) - te.refreshAssemblyInfo(); - - if (direction == null || te.assemblyLength == 0 || te.bogeyLocations == null) - return; - - ms.pushPose(); - BlockPos offset = targetPosition.subtract(pos); - ms.translate(offset.getX(), offset.getY(), offset.getZ()); - - MutableBlockPos currentPos = targetPosition.mutable(); - - PartialModel assemblyOverlay = track.prepareAssemblyOverlay(level, targetPosition, trackState, direction, ms); - int colorWhenValid = 0x96B5FF; - int colorWhenCarriage = 0xCAFF96; - VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - - currentPos.move(direction, 1); - ms.translate(0, 0, 1); - - for (int i = 0; i < te.assemblyLength; i++) { - int valid = te.isValidBogeyOffset(i) ? colorWhenValid : -1; - - for (int j : te.bogeyLocations) - if (i == j) { - valid = colorWhenCarriage; - break; - } - - if (valid != -1) { - int lightColor = LevelRenderer.getLightColor(level, currentPos); - SuperByteBuffer sbb = CachedPartialBuffers.partial(assemblyOverlay, trackState); - sbb.color(valid); - sbb.light(lightColor); - sbb.renderInto(ms, vb); - } - ms.translate(0, 0, 1); - currentPos.move(direction); - } - - ms.popPose(); - } - - public static void renderFlag(PartialModel flag, StationTileEntity te, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - if (!te.resolveFlagAngle()) - return; - SuperByteBuffer flagBB = CachedPartialBuffers.partial(flag, te.getBlockState()); - - float value = te.flag.getValue(partialTicks); - float progress = (float) (Math.pow(Math.min(value * 5, 1), 2)); - if (te.flag.getChaseTarget() > 0 && !te.flag.settled() && progress == 1) { - float wiggleProgress = (value - .2f) / .8f; - progress += (Math.sin(wiggleProgress * (2 * Mth.PI) * 4) / 8f) / Math.max(1, 8f * wiggleProgress); - } - - float nudge = 1 / 512f; - flagBB.centre() // inlined #transformFlag - .rotateY(te.flagYRot) - .translate(nudge, 9.5f / 16f, te.flagFlipped ? 14f / 16f - nudge : 2f / 16f + nudge) - .unCentre() - .rotateX((te.flagFlipped ? 1 : -1) * (progress * 90 + 270)) - .translate(0.5f / 16, 0, 0) - .rotateY(te.flagFlipped ? 0 : 180) - .translate(-0.5f / 16, 0, 0); - - - flagBB.light(light).renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); - } - - public static void transformFlag(Transform flag, StationTileEntity te, float partialTicks, int yRot) { - float value = te.flag.getValue(partialTicks); - float progress = (float) (Math.pow(Math.min(value * 5, 1), 2)); - if (te.flag.getChaseTarget() > 0 && !te.flag.settled() && progress == 1) { - float wiggleProgress = (value - .2f) / .8f; - progress += (Math.sin(wiggleProgress * (2 * Mth.PI) * 4) / 8f) / Math.max(1, 8f * wiggleProgress); - } - - float nudge = 1 / 512f; - flag.centre() - .rotateY(yRot) - .translate(nudge, 9.5f / 16f, 2f / 16f + nudge) - .unCentre() - .rotateX(-1 * (progress * 90 + 270)); - } - - @Override - public boolean shouldRenderOffScreen(StationTileEntity pBlockEntity) { - return true; - } - - @Override - public int getViewDistance() { - return 96 * 2; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java deleted file mode 100644 index cf7adf4a83..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ /dev/null @@ -1,769 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.UUID; - -import javax.annotation.Nullable; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.block.depot.DepotBehaviour; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainPacket; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; -import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; -import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.WorldAttached; -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; -import net.minecraft.core.BlockPos; -import net.minecraft.core.BlockPos.MutableBlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.network.PacketDistributor; - -public class StationTileEntity extends SmartTileEntity implements ITransformableTE { - - public TrackTargetingBehaviour edgePoint; - public LerpedFloat flag; - - protected int failedCarriageIndex; - protected AssemblyException lastException; - protected DepotBehaviour depotBehaviour; - - // for display - UUID imminentTrain; - boolean trainPresent; - boolean trainBackwards; - boolean trainCanDisassemble; - boolean trainHasSchedule; - boolean trainHasAutoSchedule; - - int flagYRot = -1; - boolean flagFlipped; - - public Component lastDisassembledTrainName; - - public StationTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(20); - lastException = null; - failedCarriageIndex = -1; - flag = LerpedFloat.linear() - .startWithValue(0); - } - - @Override - public void addBehaviours(List behaviours) { - behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.STATION)); - behaviours.add(depotBehaviour = new DepotBehaviour(this).onlyAccepts(AllItems.SCHEDULE::isIn) - .withCallback(s -> applyAutoSchedule())); - depotBehaviour.addSubBehaviours(behaviours); - registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS, AllAdvancements.TRAIN, - AllAdvancements.LONG_TRAIN, AllAdvancements.CONDUCTOR); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - lastException = AssemblyException.read(tag); - failedCarriageIndex = tag.getInt("FailedCarriageIndex"); - super.read(tag, clientPacket); - invalidateRenderBoundingBox(); - - if (tag.contains("ForceFlag")) - trainPresent = tag.getBoolean("ForceFlag"); - if (tag.contains("PrevTrainName")) - lastDisassembledTrainName = Component.Serializer.fromJson(tag.getString("PrevTrainName")); - - if (!clientPacket) - return; - if (!tag.contains("ImminentTrain")) { - imminentTrain = null; - trainPresent = false; - trainCanDisassemble = false; - trainBackwards = false; - return; - } - - imminentTrain = tag.getUUID("ImminentTrain"); - trainPresent = tag.contains("TrainPresent"); - trainCanDisassemble = tag.contains("TrainCanDisassemble"); - trainBackwards = tag.contains("TrainBackwards"); - trainHasSchedule = tag.contains("TrainHasSchedule"); - trainHasAutoSchedule = tag.contains("TrainHasAutoSchedule"); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - AssemblyException.write(tag, lastException); - tag.putInt("FailedCarriageIndex", failedCarriageIndex); - - if (lastDisassembledTrainName != null) - tag.putString("PrevTrainName", Component.Serializer.toJson(lastDisassembledTrainName)); - - super.write(tag, clientPacket); - - if (!clientPacket) - return; - if (imminentTrain == null) - return; - - tag.putUUID("ImminentTrain", imminentTrain); - - if (trainPresent) - NBTHelper.putMarker(tag, "TrainPresent"); - if (trainCanDisassemble) - NBTHelper.putMarker(tag, "TrainCanDisassemble"); - if (trainBackwards) - NBTHelper.putMarker(tag, "TrainBackwards"); - if (trainHasSchedule) - NBTHelper.putMarker(tag, "TrainHasSchedule"); - if (trainHasAutoSchedule) - NBTHelper.putMarker(tag, "TrainHasAutoSchedule"); - } - - @Nullable - public GlobalStation getStation() { - return edgePoint.getEdgePoint(); - } - - // Train Assembly - - public static WorldAttached> assemblyAreas = new WorldAttached<>(w -> new HashMap<>()); - - Direction assemblyDirection; - int assemblyLength; - int[] bogeyLocations; - IBogeyBlock[] bogeyTypes; - int bogeyCount; - - @Override - public void lazyTick() { - if (isAssembling() && !level.isClientSide) - refreshAssemblyInfo(); - super.lazyTick(); - } - - @Override - public void tick() { - if (isAssembling() && level.isClientSide) - refreshAssemblyInfo(); - super.tick(); - - if (level.isClientSide) { - float currentTarget = flag.getChaseTarget(); - if (currentTarget == 0 || flag.settled()) { - int target = trainPresent || isAssembling() ? 1 : 0; - if (target != currentTarget) { - flag.chase(target, 0.1f, Chaser.LINEAR); - if (target == 1) - AllSoundEvents.CONTRAPTION_ASSEMBLE.playAt(level, worldPosition, 1, 2, true); - } - } - boolean settled = flag.getValue() > .15f; - flag.tickChaser(); - if (currentTarget == 0 && settled != flag.getValue() > .15f) - AllSoundEvents.CONTRAPTION_DISASSEMBLE.playAt(level, worldPosition, 0.75f, 1.5f, true); - return; - } - - GlobalStation station = getStation(); - if (station == null) - return; - - Train imminentTrain = station.getImminentTrain(); - boolean trainPresent = imminentTrain != null && imminentTrain.getCurrentStation() == station; - boolean canDisassemble = trainPresent && imminentTrain.canDisassemble(); - UUID imminentID = imminentTrain != null ? imminentTrain.id : null; - boolean trainHasSchedule = trainPresent && imminentTrain.runtime.getSchedule() != null; - boolean trainHasAutoSchedule = trainHasSchedule && imminentTrain.runtime.isAutoSchedule; - boolean newlyArrived = this.trainPresent != trainPresent; - - if (trainPresent && imminentTrain.runtime.displayLinkUpdateRequested) { - DisplayLinkBlock.notifyGatherers(level, worldPosition); - imminentTrain.runtime.displayLinkUpdateRequested = false; - } - - if (newlyArrived) - applyAutoSchedule(); - - if (newlyArrived || this.trainCanDisassemble != canDisassemble - || !Objects.equals(imminentID, this.imminentTrain) || this.trainHasSchedule != trainHasSchedule - || this.trainHasAutoSchedule != trainHasAutoSchedule) { - - this.imminentTrain = imminentID; - this.trainPresent = trainPresent; - this.trainCanDisassemble = canDisassemble; - this.trainBackwards = imminentTrain != null && imminentTrain.currentlyBackwards; - this.trainHasSchedule = trainHasSchedule; - this.trainHasAutoSchedule = trainHasAutoSchedule; - - notifyUpdate(); - } - } - - public boolean trackClicked(Player player, InteractionHand hand, ITrackBlock track, BlockState state, - BlockPos pos) { - refreshAssemblyInfo(); - BoundingBox bb = assemblyAreas.get(level) - .get(worldPosition); - if (bb == null || !bb.isInside(pos)) - return false; - - BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); - int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; - if (!isValidBogeyOffset(bogeyOffset)) { - for (int i = -1; i <= 1; i++) { - BlockPos bogeyPos = pos.relative(assemblyDirection, i) - .offset(up); - BlockState blockState = level.getBlockState(bogeyPos); - if (blockState.getBlock() instanceof IBogeyBlock bogey) { - level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3); - bogey.playRotateSound(level, bogeyPos); - return true; - } - } - - return false; - } - - ItemStack handItem = player.getItemInHand(hand); - if (!player.isCreative() && !AllBlocks.RAILWAY_CASING.isIn(handItem)) { - player.displayClientMessage(CreateLang.translateDirect("train_assembly.requires_casing"), true); - return false; - } - - BlockPos targetPos = pos.offset(up); - if (level.getBlockState(targetPos) - .getDestroySpeed(level, targetPos) == -1) { - return false; - } - - level.destroyBlock(targetPos, true); - - BlockState bogeyAnchor = ProperWaterloggedBlock.withWater(level, track.getBogeyAnchor(level, pos, state), pos); - level.setBlock(targetPos, bogeyAnchor, 3); - player.displayClientMessage(CreateLang.translateDirect("train_assembly.bogey_created"), true); - SoundType soundtype = bogeyAnchor.getBlock() - .getSoundType(state, level, pos, player); - level.playSound(null, pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, - soundtype.getPitch() * 0.8F); - - if (!player.isCreative()) { - ItemStack itemInHand = player.getItemInHand(hand); - itemInHand.shrink(1); - if (itemInHand.isEmpty()) - player.setItemInHand(hand, ItemStack.EMPTY); - } - - return true; - } - - public boolean isAssembling() { - BlockState state = getBlockState(); - return state.hasProperty(StationBlock.ASSEMBLING) && state.getValue(StationBlock.ASSEMBLING); - } - - public boolean tryEnterAssemblyMode() { - if (!edgePoint.hasValidTrack()) - return false; - - BlockPos targetPosition = edgePoint.getGlobalPosition(); - BlockState trackState = edgePoint.getTrackBlockState(); - ITrackBlock track = edgePoint.getTrack(); - Vec3 trackAxis = track.getTrackAxes(level, targetPosition, trackState) - .get(0); - - boolean axisFound = false; - for (Axis axis : Iterate.axes) { - if (trackAxis.get(axis) == 0) - continue; - if (axisFound) - return false; - axisFound = true; - } - - return true; - } - - public void refreshAssemblyInfo() { - if (!edgePoint.hasValidTrack()) - return; - - if (!isVirtual()) { - GlobalStation station = getStation(); - if (station == null || station.getPresentTrain() != null) - return; - } - - int prevLength = assemblyLength; - BlockPos targetPosition = edgePoint.getGlobalPosition(); - BlockState trackState = edgePoint.getTrackBlockState(); - ITrackBlock track = edgePoint.getTrack(); - getAssemblyDirection(); - - MutableBlockPos currentPos = targetPosition.mutable(); - currentPos.move(assemblyDirection); - - BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, targetPosition, trackState)); - - int MAX_LENGTH = AllConfigs.SERVER.trains.maxAssemblyLength.get(); - int MAX_BOGEY_COUNT = AllConfigs.SERVER.trains.maxBogeyCount.get(); - - int bogeyIndex = 0; - int maxBogeyCount = MAX_BOGEY_COUNT; - if (bogeyLocations == null) - bogeyLocations = new int[maxBogeyCount]; - if (bogeyTypes == null) - bogeyTypes = new IBogeyBlock[maxBogeyCount]; - Arrays.fill(bogeyLocations, -1); - Arrays.fill(bogeyTypes, null); - - for (int i = 0; i < MAX_LENGTH; i++) { - if (i == MAX_LENGTH - 1) { - assemblyLength = i; - break; - } - if (!track.trackEquals(trackState, level.getBlockState(currentPos))) { - assemblyLength = Math.max(0, i - 1); - break; - } - - BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); - if (potentialBogeyState.getBlock() instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) { - bogeyTypes[bogeyIndex] = bogey; - bogeyLocations[bogeyIndex] = i; - bogeyIndex++; - } - - currentPos.move(assemblyDirection); - } - - bogeyCount = bogeyIndex; - - if (level.isClientSide) - return; - if (prevLength == assemblyLength) - return; - if (isVirtual()) - return; - - Map map = assemblyAreas.get(level); - BlockPos startPosition = targetPosition.relative(assemblyDirection); - BlockPos trackEnd = startPosition.relative(assemblyDirection, assemblyLength - 1); - map.put(worldPosition, BoundingBox.fromCorners(startPosition, trackEnd)); - } - - public boolean isValidBogeyOffset(int i) { - if ((i < 3 || bogeyCount == 0) && i != 0) - return false; - for (int j : bogeyLocations) { - if (j == -1) - break; - if (i >= j - 2 && i <= j + 2) - return false; - } - return true; - } - - public Direction getAssemblyDirection() { - if (assemblyDirection != null) - return assemblyDirection; - if (!edgePoint.hasValidTrack()) - return null; - BlockPos targetPosition = edgePoint.getGlobalPosition(); - BlockState trackState = edgePoint.getTrackBlockState(); - ITrackBlock track = edgePoint.getTrack(); - AxisDirection axisDirection = edgePoint.getTargetDirection(); - Vec3 axis = track.getTrackAxes(level, targetPosition, trackState) - .get(0) - .normalize() - .scale(axisDirection.getStep()); - return assemblyDirection = Direction.getNearest(axis.x, axis.y, axis.z); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - assemblyAreas.get(level) - .remove(worldPosition); - - super.setRemovedNotDueToChunkUnload(); - } - - public void assemble(UUID playerUUID) { - refreshAssemblyInfo(); - - if (bogeyLocations == null) - return; - - if (bogeyLocations[0] != 0) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.frontmost_bogey_at_station")), -1); - return; - } - - if (!edgePoint.hasValidTrack()) - return; - - BlockPos trackPosition = edgePoint.getGlobalPosition(); - BlockState trackState = edgePoint.getTrackBlockState(); - ITrackBlock track = edgePoint.getTrack(); - BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, trackPosition, trackState)); - - TrackNodeLocation location = null; - Vec3 centre = Vec3.atBottomCenterOf(trackPosition) - .add(0, track.getElevationAtCenter(level, trackPosition, trackState), 0); - Collection ends = track.getConnected(level, trackPosition, trackState, true, null); - Vec3 targetOffset = Vec3.atLowerCornerOf(assemblyDirection.getNormal()); - for (DiscoveredLocation end : ends) - if (Mth.equal(0, targetOffset.distanceToSqr(end.getLocation() - .subtract(centre) - .normalize()))) - location = end; - if (location == null) - return; - - List pointOffsets = new ArrayList<>(); - int iPrevious = -100; - for (int i = 0; i < bogeyLocations.length; i++) { - int loc = bogeyLocations[i]; - if (loc == -1) - break; - - if (loc - iPrevious < 3) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.bogeys_too_close", i, i + 1)), -1); - return; - } - - double bogeySize = bogeyTypes[i].getWheelPointSpacing(); - pointOffsets.add(Double.valueOf(loc + .5 - bogeySize / 2)); - pointOffsets.add(Double.valueOf(loc + .5 + bogeySize / 2)); - iPrevious = loc; - } - - List points = new ArrayList<>(); - Vec3 directionVec = Vec3.atLowerCornerOf(assemblyDirection.getNormal()); - TrackGraph graph = null; - TrackNode secondNode = null; - - for (int j = 0; j < assemblyLength * 2 + 40; j++) { - double i = j / 2d; - if (points.size() == pointOffsets.size()) - break; - - TrackNodeLocation currentLocation = location; - location = new TrackNodeLocation(location.getLocation() - .add(directionVec.scale(.5))).in(location.dimension); - - if (graph == null) - graph = Create.RAILWAYS.getGraph(level, currentLocation); - if (graph == null) - continue; - TrackNode node = graph.locateNode(currentLocation); - if (node == null) - continue; - - for (int pointIndex = points.size(); pointIndex < pointOffsets.size(); pointIndex++) { - double offset = pointOffsets.get(pointIndex); - if (offset > i) - break; - double positionOnEdge = i - offset; - - Map connectionsFromNode = graph.getConnectionsFrom(node); - - if (secondNode == null) - for (Entry entry : connectionsFromNode.entrySet()) { - TrackEdge edge = entry.getValue(); - TrackNode otherNode = entry.getKey(); - if (edge.isTurn()) - continue; - Vec3 edgeDirection = edge.getDirection(true); - if (Mth.equal(edgeDirection.normalize() - .dot(directionVec), -1d)) - secondNode = otherNode; - } - - if (secondNode == null) { - Create.LOGGER.warn("Cannot assemble: No valid starting node found"); - return; - } - - TrackEdge edge = connectionsFromNode.get(secondNode); - - if (edge == null) { - Create.LOGGER.warn("Cannot assemble: Missing graph edge"); - return; - } - - points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge)); - } - - secondNode = node; - } - - if (points.size() != pointOffsets.size()) { - Create.LOGGER.warn("Cannot assemble: Not all Points created"); - return; - } - - if (points.size() == 0) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.no_bogeys")), -1); - return; - } - - List contraptions = new ArrayList<>(); - List carriages = new ArrayList<>(); - List spacing = new ArrayList<>(); - boolean atLeastOneForwardControls = false; - - for (int bogeyIndex = 0; bogeyIndex < bogeyCount; bogeyIndex++) { - int pointIndex = bogeyIndex * 2; - if (bogeyIndex > 0) - spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); - CarriageContraption contraption = new CarriageContraption(assemblyDirection); - BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); - - try { - int offset = bogeyLocations[bogeyIndex] + 1; - boolean success = contraption.assemble(level, bogeyPosOffset.relative(assemblyDirection, offset)); - atLeastOneForwardControls |= contraption.hasForwardControls(); - contraption.setSoundQueueOffset(offset); - if (!success) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.nothing_attached", bogeyIndex + 1)), - -1); - return; - } - } catch (AssemblyException e) { - exception(e, contraptions.size() + 1); - return; - } - - IBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; - CarriageBogey firstBogey = - new CarriageBogey(typeOfFirstBogey, points.get(pointIndex), points.get(pointIndex + 1)); - CarriageBogey secondBogey = null; - BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); - int bogeySpacing = 0; - - if (secondBogeyPos != null) { - if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos - .equals(bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.not_connected_in_order")), - contraptions.size() + 1); - return; - } - - bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; - secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], points.get(pointIndex + 2), - points.get(pointIndex + 3)); - bogeyIndex++; - - } else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.single_bogey_carriage")), - contraptions.size() + 1); - return; - } - - contraptions.add(contraption); - carriages.add(new Carriage(firstBogey, secondBogey, bogeySpacing)); - } - - if (!atLeastOneForwardControls) { - exception(new AssemblyException(CreateLang.translateDirect("train_assembly.no_controls")), -1); - return; - } - - for (CarriageContraption contraption : contraptions) { - contraption.removeBlocksFromWorld(level, BlockPos.ZERO); - contraption.expandBoundsAroundAxis(Axis.Y); - } - - Train train = new Train(UUID.randomUUID(), playerUUID, graph, carriages, spacing, contraptions.stream() - .anyMatch(CarriageContraption::hasBackwardControls)); - - if (lastDisassembledTrainName != null) { - train.name = lastDisassembledTrainName; - lastDisassembledTrainName = null; - } - - for (int i = 0; i < contraptions.size(); i++) { - CarriageContraption contraption = contraptions.get(i); - Carriage carriage = carriages.get(i); - carriage.setContraption(level, contraption); - if (contraption.containsBlockBreakers()) - award(AllAdvancements.CONTRAPTION_ACTORS); - } - - GlobalStation station = getStation(); - if (station != null) { - train.setCurrentStation(station); - station.reserveFor(train); - } - - train.collectInitiallyOccupiedSignalBlocks(); - Create.RAILWAYS.addTrain(train); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, true)); - clearException(); - - award(AllAdvancements.TRAIN); - if (contraptions.size() >= 6) - award(AllAdvancements.LONG_TRAIN); - } - - public void cancelAssembly() { - assemblyLength = 0; - assemblyAreas.get(level) - .remove(worldPosition); - clearException(); - } - - private void clearException() { - exception(null, -1); - } - - private void exception(AssemblyException exception, int carriage) { - failedCarriageIndex = carriage; - lastException = exception; - sendData(); - } - - @Override - @OnlyIn(Dist.CLIENT) - public AABB getRenderBoundingBox() { - if (isAssembling()) - return INFINITE_EXTENT_AABB; - return super.getRenderBoundingBox(); - } - - @Override - protected AABB createRenderBoundingBox() { - return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); - } - - public ItemStack getAutoSchedule() { - return depotBehaviour.getHeldItemStack(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) - return depotBehaviour.getItemCapability(cap, side); - return super.getCapability(cap, side); - } - - private void applyAutoSchedule() { - ItemStack stack = getAutoSchedule(); - if (!AllItems.SCHEDULE.isIn(stack)) - return; - Schedule schedule = ScheduleItem.getSchedule(stack); - if (schedule == null || schedule.entries.isEmpty()) - return; - GlobalStation station = getStation(); - if (station == null) - return; - Train imminentTrain = station.getImminentTrain(); - if (imminentTrain == null || imminentTrain.getCurrentStation() != station) - return; - - award(AllAdvancements.CONDUCTOR); - imminentTrain.runtime.setSchedule(schedule, true); - AllSoundEvents.CONFIRM.playOnServer(level, worldPosition, 1, 1); - - if (!(level instanceof ServerLevel server)) - return; - - Vec3 v = Vec3.atBottomCenterOf(worldPosition.above()); - server.sendParticles(ParticleTypes.HAPPY_VILLAGER, v.x, v.y, v.z, 8, 0.35, 0.05, 0.35, 1); - server.sendParticles(ParticleTypes.END_ROD, v.x, v.y + .25f, v.z, 10, 0.05, 1, 0.05, 0.005f); - } - - public boolean resolveFlagAngle() { - if (flagYRot != -1) - return true; - - BlockState target = edgePoint.getTrackBlockState(); - if (!(target.getBlock() instanceof ITrackBlock def)) - return false; - - Vec3 axis = null; - BlockPos trackPos = edgePoint.getGlobalPosition(); - for (Vec3 vec3 : def.getTrackAxes(level, trackPos, target)) - axis = vec3.scale(edgePoint.getTargetDirection() - .getStep()); - if (axis == null) - return false; - - Direction nearest = Direction.getNearest(axis.x, 0, axis.z); - flagYRot = (int) (-nearest.toYRot() - 90); - - Vec3 diff = Vec3.atLowerCornerOf(trackPos.subtract(worldPosition)) - .multiply(1, 0, 1); - if (diff.lengthSqr() == 0) - return true; - - flagFlipped = diff.dot(Vec3.atLowerCornerOf(nearest.getClockWise() - .getNormal())) > 0; - - return true; - } - - @Override - public void transform(StructureTransform transform) { - edgePoint.transform(transform); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/TrainEditPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/TrainEditPacket.java deleted file mode 100644 index ae9514a0eb..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/TrainEditPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; - -import java.util.UUID; -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainIconType; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkEvent.Context; -import net.minecraftforge.network.PacketDistributor; - -public class TrainEditPacket extends SimplePacketBase { - - private String name; - private UUID id; - private ResourceLocation iconType; - - public TrainEditPacket(UUID id, String name, ResourceLocation iconType) { - this.name = name; - this.id = id; - this.iconType = iconType; - } - - public TrainEditPacket(FriendlyByteBuf buffer) { - id = buffer.readUUID(); - name = buffer.readUtf(256); - iconType = buffer.readResourceLocation(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeUUID(id); - buffer.writeUtf(name); - buffer.writeResourceLocation(iconType); - } - - @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer sender = ctx.getSender(); - Level level = sender == null ? null : sender.level; - Train train = Create.RAILWAYS.sided(level).trains.get(id); - if (train == null) - return; - if (!name.isBlank()) - train.name = Components.literal(name); - train.icon = TrainIconType.byId(iconType); - if (sender != null) - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainEditReturnPacket(id, name, iconType)); - }); - ctx.setPacketHandled(true); - } - - public static class TrainEditReturnPacket extends TrainEditPacket { - - public TrainEditReturnPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - public TrainEditReturnPacket(UUID id, String name, ResourceLocation iconType) { - super(id, name, iconType); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/Schedule.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/Schedule.java deleted file mode 100644 index 16e184881d..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/Schedule.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.FluidThresholdCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.IdleCargoCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ItemThresholdCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.PlayerPassengerCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.RedstoneLinkCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduledDelay; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.StationPoweredCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.StationUnloadedCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.TimeOfDayCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ChangeThrottleInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ChangeTitleInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction; - -import net.createmod.catnip.utility.NBTHelper; -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; - -public class Schedule { - - public static List>> INSTRUCTION_TYPES = - new ArrayList<>(); - public static List>> CONDITION_TYPES = - new ArrayList<>(); - - static { - registerInstruction("destination", DestinationInstruction::new); - registerInstruction("rename", ChangeTitleInstruction::new); - registerInstruction("throttle", ChangeThrottleInstruction::new); - registerCondition("delay", ScheduledDelay::new); - registerCondition("time_of_day", TimeOfDayCondition::new); - registerCondition("fluid_threshold", FluidThresholdCondition::new); - registerCondition("item_threshold", ItemThresholdCondition::new); - registerCondition("redstone_link", RedstoneLinkCondition::new); - registerCondition("player_count", PlayerPassengerCondition::new); - registerCondition("idle", IdleCargoCondition::new); - registerCondition("unloaded", StationUnloadedCondition::new); - registerCondition("powered", StationPoweredCondition::new); - } - - private static void registerInstruction(String name, Supplier factory) { - INSTRUCTION_TYPES.add(Pair.of(Create.asResource(name), factory)); - } - - private static void registerCondition(String name, Supplier factory) { - CONDITION_TYPES.add(Pair.of(Create.asResource(name), factory)); - } - - public static List getTypeOptions(List> list) { - String langSection = list.equals(INSTRUCTION_TYPES) ? "instruction." : "condition."; - return list.stream() - .map(Pair::getFirst) - .map(rl -> rl.getNamespace() + ".schedule." + langSection + rl.getPath()) - .map(Components::translatable) - .toList(); - } - - public List entries; - public boolean cyclic; - public int savedProgress; - - public Schedule() { - entries = new ArrayList<>(); - cyclic = true; - savedProgress = 0; - } - - public CompoundTag write() { - CompoundTag tag = new CompoundTag(); - ListTag list = NBTHelper.writeCompoundList(entries, ScheduleEntry::write); - tag.put("Entries", list); - tag.putBoolean("Cyclic", cyclic); - if (savedProgress > 0) - tag.putInt("Progress", savedProgress); - return tag; - } - - public static Schedule fromTag(CompoundTag tag) { - Schedule schedule = new Schedule(); - schedule.entries = NBTHelper.readCompoundList(tag.getList("Entries", Tag.TAG_COMPOUND), ScheduleEntry::fromTag); - schedule.cyclic = tag.getBoolean("Cyclic"); - if (tag.contains("Progress")) - schedule.savedProgress = tag.getInt("Progress"); - return schedule; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleContainer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleContainer.java deleted file mode 100644 index 15f456bbb2..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleContainer.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; - -import com.simibubi.create.foundation.gui.container.GhostItemContainer; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.Container; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.SlotItemHandler; - -public class ScheduleContainer extends GhostItemContainer { - - public boolean slotsActive = true; - public int targetSlotsActive = 1; - - static final int slots = 2; - - public ScheduleContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public ScheduleContainer(MenuType type, int id, Inventory inv, ItemStack contentHolder) { - super(type, id, inv, contentHolder); - } - - @Override - protected ItemStackHandler createGhostInventory() { - return new ItemStackHandler(slots); - } - - @Override - public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { - if (slotId != playerInventory.selected || clickTypeIn == ClickType.THROW) - super.clicked(slotId, dragType, clickTypeIn, player); - } - - @Override - protected boolean allowRepeats() { - return true; - } - - @Override - protected ItemStack createOnClient(FriendlyByteBuf extraData) { - return extraData.readItem(); - } - - @Override - protected void addSlots() { - addPlayerSlots(46, 140); - for (int i = 0; i < slots; i++) - addSlot(new InactiveItemHandlerSlot(ghostInventory, i, i, 54 + 20 * i, 88)); - } - - @Override - protected void addPlayerSlots(int x, int y) { - for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) - this.addSlot(new InactiveSlot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); - for (int row = 0; row < 3; ++row) - for (int col = 0; col < 9; ++col) - this.addSlot(new InactiveSlot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); - } - - @Override - protected void saveData(ItemStack contentHolder) {} - - @Override - public boolean stillValid(Player player) { - return playerInventory.getSelected() == contentHolder; - } - - class InactiveSlot extends Slot { - - public InactiveSlot(Container pContainer, int pIndex, int pX, int pY) { - super(pContainer, pIndex, pX, pY); - } - - @Override - public boolean isActive() { - return slotsActive; - } - - } - - class InactiveItemHandlerSlot extends SlotItemHandler { - - private int targetIndex; - - public InactiveItemHandlerSlot(IItemHandler itemHandler, int targetIndex, int index, int xPosition, - int yPosition) { - super(itemHandler, index, xPosition, yPosition); - this.targetIndex = targetIndex; - } - - @Override - public boolean isActive() { - return slotsActive && targetIndex < targetSlotsActive; - } - - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEditPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEditPacket.java deleted file mode 100644 index c609feeca9..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEditPacket.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; - -import java.util.function.Supplier; - -import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ScheduleEditPacket extends SimplePacketBase { - - private Schedule schedule; - - public ScheduleEditPacket(Schedule schedule) { - this.schedule = schedule; - } - - public ScheduleEditPacket(FriendlyByteBuf buffer) { - schedule = Schedule.fromTag(buffer.readNbt()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeNbt(schedule.write()); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer sender = context.get() - .getSender(); - ItemStack mainHandItem = sender.getMainHandItem(); - if (!AllItems.SCHEDULE.isIn(mainHandItem)) - return; - - CompoundTag tag = mainHandItem.getOrCreateTag(); - if (schedule.entries.isEmpty()) { - tag.remove("Schedule"); - if (tag.isEmpty()) - mainHandItem.setTag(null); - } else - tag.put("Schedule", schedule.write()); - - sender.getCooldowns() - .addCooldown(mainHandItem.getItem(), 5); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java deleted file mode 100644 index 4b94496d44..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduleWaitCondition.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; - -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleDataEntry; - -import net.createmod.catnip.utility.Pair; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.Level; - -public abstract class ScheduleWaitCondition extends ScheduleDataEntry { - - public abstract boolean tickCompletion(Level level, Train train, CompoundTag context); - - protected void requestStatusToUpdate(CompoundTag context) { - context.putInt("StatusVersion", context.getInt("StatusVersion") + 1); - } - - public final CompoundTag write() { - CompoundTag tag = new CompoundTag(); - tag.putString("Id", getId().toString()); - tag.put("Data", data.copy()); - writeAdditional(tag); - return tag; - } - - public static ScheduleWaitCondition fromTag(CompoundTag tag) { - ResourceLocation location = new ResourceLocation(tag.getString("Id")); - Supplier supplier = null; - for (Pair> pair : Schedule.CONDITION_TYPES) - if (pair.getFirst() - .equals(location)) - supplier = pair.getSecond(); - - if (supplier == null) { - Create.LOGGER.warn("Could not parse waiting condition type: " + location); - return null; - } - - ScheduleWaitCondition condition = supplier.get(); - condition.data = tag.getCompound("Data"); - condition.readAdditional(tag); - return condition; - } - - public abstract MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag); - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationUnloadedCondition.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationUnloadedCondition.java deleted file mode 100644 index 211ce9aa9a..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationUnloadedCondition.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.Pair; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -public class StationUnloadedCondition extends ScheduleWaitCondition { - @Override - public Pair getSummary() { - return Pair.of(ItemStack.EMPTY, CreateLang.translateDirect("schedule.condition.unloaded")); - } - - @Override - public boolean tickCompletion(Level level, Train train, CompoundTag context) { - GlobalStation currentStation = train.getCurrentStation(); - if (currentStation == null) - return false; - if (level instanceof ServerLevel serverLevel) - return !serverLevel.isPositionEntityTicking(currentStation.getTilePos()); - return false; - } - - @Override - protected void writeAdditional(CompoundTag tag) {} - - @Override - protected void readAdditional(CompoundTag tag) {} - - @Override - public ResourceLocation getId() { - return Create.asResource("unloaded"); - } - - @Override - public MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag) { - return CreateLang.translateDirect("schedule.condition.unloaded.status"); - } -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java deleted file mode 100644 index d140b78a50..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ScheduleInstruction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.destination; - -import java.util.function.Supplier; - -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleDataEntry; - -import net.createmod.catnip.utility.Pair; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; - -public abstract class ScheduleInstruction extends ScheduleDataEntry { - - public abstract boolean supportsConditions(); - - public final CompoundTag write() { - CompoundTag tag = new CompoundTag(); - tag.putString("Id", getId().toString()); - tag.put("Data", data.copy()); - writeAdditional(tag); - return tag; - } - - public static ScheduleInstruction fromTag(CompoundTag tag) { - ResourceLocation location = new ResourceLocation(tag.getString("Id")); - Supplier supplier = null; - for (Pair> pair : Schedule.INSTRUCTION_TYPES) - if (pair.getFirst() - .equals(location)) - supplier = pair.getSecond(); - - if (supplier == null) { - Create.LOGGER.warn("Could not parse schedule instruction type: " + location); - return new DestinationInstruction(); - } - - ScheduleInstruction scheduleDestination = supplier.get(); - scheduleDestination.data = tag.getCompound("Data"); - scheduleDestination.readAdditional(tag); - return scheduleDestination; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/BezierTrackPointLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/BezierTrackPointLocation.java deleted file mode 100644 index c087ed6a10..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/BezierTrackPointLocation.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import net.minecraft.core.BlockPos; - -public record BezierTrackPointLocation(BlockPos curveTarget, int segment) { -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackDestroyPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackDestroyPacket.java deleted file mode 100644 index ab4b2ddce0..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackDestroyPacket.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.TrackPropagator; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.state.BlockState; - -public class CurvedTrackDestroyPacket extends TileEntityConfigurationPacket { - - private BlockPos targetPos; - private BlockPos soundSource; - private boolean wrench; - - public CurvedTrackDestroyPacket(BlockPos pos, BlockPos targetPos, BlockPos soundSource, boolean wrench) { - super(pos); - this.targetPos = targetPos; - this.soundSource = soundSource; - this.wrench = wrench; - } - - public CurvedTrackDestroyPacket(FriendlyByteBuf buffer) { - super(buffer); - } - - @Override - protected void writeSettings(FriendlyByteBuf buffer) { - buffer.writeBlockPos(targetPos); - buffer.writeBlockPos(soundSource); - buffer.writeBoolean(wrench); - } - - @Override - protected void readSettings(FriendlyByteBuf buffer) { - targetPos = buffer.readBlockPos(); - soundSource = buffer.readBlockPos(); - wrench = buffer.readBoolean(); - } - - @Override - protected void applySettings(ServerPlayer player, TrackTileEntity te) { - if (!te.getBlockPos() - .closerThan(player.blockPosition(), 128)) { - Create.LOGGER.warn(player.getScoreboardName() + " too far away from destroyed Curve track"); - return; - } - - Level level = te.getLevel(); - BezierConnection bezierConnection = te.getConnections() - .get(targetPos); - - te.removeConnection(targetPos); - if (level.getBlockEntity(targetPos)instanceof TrackTileEntity other) - other.removeConnection(pos); - - BlockState blockState = te.getBlockState(); - TrackPropagator.onRailRemoved(level, pos, blockState); - - if (wrench) { - AllSoundEvents.WRENCH_REMOVE.playOnServer(player.level, soundSource, 1, - Create.RANDOM.nextFloat() * .5f + .5f); - if (!player.isCreative() && bezierConnection != null) - bezierConnection.addItemsToPlayer(player); - } else if (!player.isCreative() && bezierConnection != null) - bezierConnection.spawnItems(level); - - bezierConnection.spawnDestroyParticles(level); - SoundType soundtype = blockState.getSoundType(level, pos, player); - if (soundtype == null) - return; - - level.playSound(null, soundSource, soundtype.getBreakSound(), SoundSource.BLOCKS, - (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); - } - - @Override - protected int maxRange() { - return 64; - } - - @Override - protected void applySettings(TrackTileEntity te) {} - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/FakeTrackTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/FakeTrackTileEntity.java deleted file mode 100644 index 8d38b57cfa..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/FakeTrackTileEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public class FakeTrackTileEntity extends SyncedTileEntity { - - int keepAlive; - - public FakeTrackTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - keepAlive(); - } - - public void randomTick() { - keepAlive--; - if (keepAlive > 0) - return; - level.removeBlock(worldPosition, false); - } - - public void keepAlive() { - keepAlive = 3; - } - - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java deleted file mode 100644 index 4d1859325f..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/PlaceExtendedCurvePacket.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import java.util.function.Supplier; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent.Context; - -public class PlaceExtendedCurvePacket extends SimplePacketBase { - - boolean mainHand; - boolean ctrlDown; - - public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) { - this.mainHand = mainHand; - this.ctrlDown = ctrlDown; - } - - public PlaceExtendedCurvePacket(FriendlyByteBuf buffer) { - mainHand = buffer.readBoolean(); - ctrlDown = buffer.readBoolean(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeBoolean(mainHand); - buffer.writeBoolean(ctrlDown); - } - - @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer sender = ctx.getSender(); - ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); - if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) - return; - CompoundTag tag = stack.getTag(); - tag.putBoolean("ExtendCurve", true); - stack.setTag(tag); - }); - ctx.setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java deleted file mode 100644 index 9452a1d670..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java +++ /dev/null @@ -1,240 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import java.util.EnumSet; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.entity.BogeyInstance; -import com.simibubi.create.content.logistics.trains.entity.CarriageBogey; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.render.CachedPartialBuffers; - -import net.createmod.catnip.render.CachedBlockBuffers; -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.StateDefinition.Builder; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class StandardBogeyBlock extends Block - implements IBogeyBlock, ITE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { - - public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; - private final boolean large; - - public StandardBogeyBlock(Properties p_i48440_1_, boolean large) { - super(p_i48440_1_); - this.large = large; - registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); - } - - @Override - protected void createBlockStateDefinition(Builder builder) { - builder.add(AXIS, WATERLOGGED); - super.createBlockStateDefinition(builder); - } - - static final EnumSet STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); - static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); - - @Override - public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) { - return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Axis.X ? STICKY_X : STICKY_Z; - } - - @Override - public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, - LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { - updateWater(pLevel, pState, pCurrentPos); - return pState; - } - - @Override - public FluidState getFluidState(BlockState pState) { - return fluidState(pState); - } - - @Override - public double getWheelPointSpacing() { - return 2; - } - - @Override - public double getWheelRadius() { - return (large ? 12.5 : 6.5) / 16d; - } - - @Override - public Vec3 getConnectorAnchorOffset() { - return new Vec3(0, 7 / 32f, 1); - } - - @Override - public boolean allowsSingleBogeyCarriage() { - return true; - } - - @Override - public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) { - if (upDirection != Direction.UP) - return null; - return defaultBlockState().setValue(AXIS, axisAlongFirst ? Axis.X : Axis.Z); - } - - @Override - public boolean isTrackAxisAlongFirstCoordinate(BlockState state) { - return state.getValue(AXIS) == Axis.X; - } - - @Override - @OnlyIn(Dist.CLIENT) - public void render(BlockState state, float wheelAngle, PoseStack ms, float partialTicks, MultiBufferSource buffers, - int light, int overlay) { - if (state != null) { - ms.translate(.5f, .5f, .5f); - if (state.getValue(AXIS) == Axis.X) - ms.mulPose(Vector3f.YP.rotationDegrees(90)); - } - - ms.translate(0, -1.5 - 1 / 128f, 0); - - VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped()); - BlockState air = Blocks.AIR.defaultBlockState(); - - for (int i : Iterate.zeroAndOne) - CachedBlockBuffers.block(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Axis.Z)) - .translate(-.5f, .25f, i * -1) - .rotateCentered(Axis.Z, Mth.DEG_TO_RAD * wheelAngle) - .light(light) - .renderInto(ms, vb); - - if (large) { - renderLargeBogey(wheelAngle, ms, light, vb, air); - } else { - renderBogey(wheelAngle, ms, light, vb, air); - } - } - - private void renderBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) { - CachedPartialBuffers.partial(AllBlockPartials.BOGEY_FRAME, air) - .scale(1 - 1 / 512f) - .light(light) - .renderInto(ms, vb); - - for (int side : Iterate.positiveAndNegative) { - ms.pushPose(); - CachedPartialBuffers.partial(AllBlockPartials.SMALL_BOGEY_WHEELS, air) - .translate(0, 12 / 16f, side) - .rotate(Axis.X, Mth.DEG_TO_RAD * wheelAngle) - .light(light) - .renderInto(ms, vb); - ms.popPose(); - } - } - - private void renderLargeBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) { - for (int i : Iterate.zeroAndOne) - CachedBlockBuffers.block(AllBlocks.SHAFT.getDefaultState() - .setValue(ShaftBlock.AXIS, Axis.X)) - .translate(-.5f, .25f, .5f + i * -2) - .rotateCentered(Axis.X, Mth.DEG_TO_RAD * wheelAngle) - .light(light) - .renderInto(ms, vb); - - CachedPartialBuffers.partial(AllBlockPartials.BOGEY_DRIVE, air) - .scale(1 - 1 / 512f) - .light(light) - .renderInto(ms, vb); - CachedPartialBuffers.partial(AllBlockPartials.BOGEY_PISTON, air) - .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))) - .light(light) - .renderInto(ms, vb); - - ms.pushPose(); - CachedPartialBuffers.partial(AllBlockPartials.LARGE_BOGEY_WHEELS, air) - .translate(0, 1, 0) - .rotate(Axis.X, Mth.DEG_TO_RAD * wheelAngle) - .light(light) - .renderInto(ms, vb); - CachedPartialBuffers.partial(AllBlockPartials.BOGEY_PIN, air) - .translate(0, 1, 0) - .rotate(Axis.X, Mth.DEG_TO_RAD * wheelAngle) - .translate(0, 1 / 4f, 0) - .rotate(Axis.X, Mth.DEG_TO_RAD * -wheelAngle) - .light(light) - .renderInto(ms, vb); - ms.popPose(); - } - - @Override - public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey) { - if (large) { - return new BogeyInstance.Drive(bogey, materialManager); - } else { - return new BogeyInstance.Frame(bogey, materialManager); - } - } - - @Override - public BlockState rotate(BlockState pState, Rotation pRotation) { - return switch (pRotation) { - case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS); - default -> pState; - }; - } - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, - Player player) { - return AllBlocks.RAILWAY_CASING.asStack(); - } - - @Override - public Class getTileEntityClass() { - return StandardBogeyTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.BOGEY.get(); - } - - @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java deleted file mode 100644 index 6968fc4583..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyTileEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity; - -import net.createmod.catnip.utility.animation.LerpedFloat; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; - -public class StandardBogeyTileEntity extends CachedRenderBBTileEntity { - - public StandardBogeyTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Override - protected AABB createRenderBoundingBox() { - return super.createRenderBoundingBox().inflate(2); - } - - // Ponder - - LerpedFloat virtualAnimation = LerpedFloat.angular(); - - public float getVirtualAngle(float partialTicks) { - return virtualAnimation.getValue(partialTicks); - } - - public void animate(float distanceMoved) { - BlockState blockState = getBlockState(); - if (!(blockState.getBlock() instanceof IBogeyBlock type)) - return; - double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); - double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360; - virtualAnimation.setValue(newWheelAngle); - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java deleted file mode 100644 index 4bfd4c3726..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM; -import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE; -import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP; -import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT; -import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT; -import static com.simibubi.create.AllBlockPartials.TRACK_TIE; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.util.transform.TransformStack; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.PoseStack.Pose; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; -import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.utility.Iterate; -import net.createmod.catnip.utility.VecHelper; -import net.createmod.catnip.utility.math.AngleHelper; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class TrackRenderer extends SafeTileEntityRenderer { - - public TrackRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(TrackTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, - int overlay) { - Level level = te.getLevel(); - if (Backend.canUseInstancing(level)) - return; - VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - te.connections.values() - .forEach(bc -> renderBezierTurn(level, bc, ms, vb)); - } - - public static void renderBezierTurn(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb) { - if (!bc.isPrimary()) - return; - - ms.pushPose(); - BlockPos tePosition = bc.tePositions.getFirst(); - BlockState air = Blocks.AIR.defaultBlockState(); - SegmentAngles[] segments = bc.getBakedSegments(); - - TransformStack.cast(ms) - .nudge((int) tePosition.asLong()); - - renderGirder(level, bc, ms, vb, tePosition); - - for (int i = 1; i < segments.length; i++) { - SegmentAngles segment = segments[i]; - int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); - - CachedPartialBuffers.partial(TRACK_TIE, air) - .mulPose(segment.tieTransform.pose()) - .mulNormal(segment.tieTransform.normal()) - .light(light) - .renderInto(ms, vb); - - for (boolean first : Iterate.trueAndFalse) { - Pose transform = segment.railTransforms.get(first); - CachedPartialBuffers.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air) - .mulPose(transform.pose()) - .mulNormal(transform.normal()) - .light(light) - .renderInto(ms, vb); - } - } - - ms.popPose(); - } - - private static void renderGirder(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb, - BlockPos tePosition) { - if (!bc.hasGirder) - return; - - BlockState air = Blocks.AIR.defaultBlockState(); - GirderAngles[] girders = bc.getBakedGirders(); - - for (int i = 1; i < girders.length; i++) { - GirderAngles segment = girders[i]; - int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); - - for (boolean first : Iterate.trueAndFalse) { - Pose beamTransform = segment.beams.get(first); - CachedPartialBuffers.partial(GIRDER_SEGMENT_MIDDLE, air) - .mulPose(beamTransform.pose()) - .mulNormal(beamTransform.normal()) - .light(light) - .renderInto(ms, vb); - - for (boolean top : Iterate.trueAndFalse) { - Pose beamCapTransform = segment.beamCaps.get(top) - .get(first); - CachedPartialBuffers.partial(top ? GIRDER_SEGMENT_TOP : GIRDER_SEGMENT_BOTTOM, air) - .mulPose(beamCapTransform.pose()) - .mulNormal(beamCapTransform.normal()) - .light(light) - .renderInto(ms, vb); - } - } - } - } - - public static Vec3 getModelAngles(Vec3 normal, Vec3 diff) { - double diffX = diff.x(); - double diffY = diff.y(); - double diffZ = diff.z(); - double len = Mth.sqrt((float) (diffX * diffX + diffZ * diffZ)); - double yaw = Mth.atan2(diffX, diffZ); - double pitch = Mth.atan2(len, diffY) - Math.PI * .5; - - Vec3 yawPitchNormal = VecHelper.rotate(VecHelper.rotate(new Vec3(0, 1, 0), AngleHelper.deg(pitch), Axis.X), - AngleHelper.deg(yaw), Axis.Y); - - double signum = Math.signum(yawPitchNormal.dot(normal)); - if (Math.abs(signum) < 0.5f) - signum = yawPitchNormal.distanceToSqr(normal) < 0.5f ? -1 : 1; - double dot = diff.cross(normal) - .normalize() - .dot(yawPitchNormal); - double roll = Math.acos(Mth.clamp(dot, -1, 1)) * signum; - return new Vec3(pitch, yaw, roll); - } - - @Override - public boolean shouldRenderOffScreen(TrackTileEntity pBlockEntity) { - return true; - } - - @Override - public int getViewDistance() { - return 96 * 2; - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java deleted file mode 100644 index 98ae991137..0000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java +++ /dev/null @@ -1,396 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.IMergeableTE; -import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; - -import net.createmod.catnip.utility.Pair; -import net.createmod.catnip.utility.VecHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Registry; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.nbt.Tag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.DistExecutor; - -public class TrackTileEntity extends SmartTileEntity implements ITransformableTE, IMergeableTE { - - Map connections; - boolean cancelDrops; - - public Pair, BlockPos> boundLocation; - - public TrackTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - connections = new HashMap<>(); - setLazyTickRate(100); - } - - public Map getConnections() { - return connections; - } - - @Override - public void initialize() { - super.initialize(); - if (!level.isClientSide && hasInteractableConnections()) - registerToCurveInteraction(); - } - - @Override - public void lazyTick() { - for (BezierConnection connection : connections.values()) - if (connection.isPrimary()) - manageFakeTracksAlong(connection, false); - } - - public void validateConnections() { - Set invalid = new HashSet<>(); - - for (Entry entry : connections.entrySet()) { - BlockPos key = entry.getKey(); - BezierConnection bc = entry.getValue(); - - if (!key.equals(bc.getKey()) || !worldPosition.equals(bc.tePositions.getFirst())) { - invalid.add(key); - continue; - } - - BlockState blockState = level.getBlockState(key); - if (blockState.getBlock()instanceof ITrackBlock trackBlock && !blockState.getValue(TrackBlock.HAS_TE)) - for (Vec3 v : trackBlock.getTrackAxes(level, key, blockState)) { - Vec3 bcEndAxis = bc.axes.getSecond(); - if (v.distanceTo(bcEndAxis) < 1 / 1024f || v.distanceTo(bcEndAxis.scale(-1)) < 1 / 1024f) - level.setBlock(key, blockState.setValue(TrackBlock.HAS_TE, true), 3); - } - - BlockEntity blockEntity = level.getBlockEntity(key); - if (!(blockEntity instanceof TrackTileEntity trackTE) || blockEntity.isRemoved()) { - invalid.add(key); - continue; - } - - if (!trackTE.connections.containsKey(worldPosition)) - trackTE.addConnection(bc.secondary()); - } - - for (BlockPos blockPos : invalid) - removeConnection(blockPos); - } - - public void addConnection(BezierConnection connection) { - connections.put(connection.getKey(), connection); - level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); - notifyUpdate(); - - if (connection.isPrimary()) - manageFakeTracksAlong(connection, false); - } - - public void removeConnection(BlockPos target) { - BezierConnection removed = connections.remove(target); - notifyUpdate(); - - if (removed != null) - manageFakeTracksAlong(removed, true); - - if (!connections.isEmpty() || getBlockState().getOptionalValue(TrackBlock.SHAPE) - .orElse(TrackShape.NONE) - .isPortal()) - return; - - BlockState blockState = level.getBlockState(worldPosition); - if (blockState.hasProperty(TrackBlock.HAS_TE)) - level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_TE, false)); - AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition)); - } - - public void removeInboundConnections() { - for (BezierConnection bezierConnection : connections.values()) { - BlockEntity blockEntity = level.getBlockEntity(bezierConnection.getKey()); - if (!(blockEntity instanceof TrackTileEntity)) - return; - TrackTileEntity other = (TrackTileEntity) blockEntity; - other.removeConnection(bezierConnection.tePositions.getFirst()); - - if (!cancelDrops) - bezierConnection.spawnItems(level); - bezierConnection.spawnDestroyParticles(level); - } - AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition)); - } - - public void bind(ResourceKey boundDimension, BlockPos boundLocation) { - this.boundLocation = Pair.of(boundDimension, boundLocation); - setChanged(); - } - - @Override - public void writeSafe(CompoundTag tag) { - super.writeSafe(tag); - writeTurns(tag); - } - - @Override - protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); - writeTurns(tag); - if (boundLocation == null) - return; - tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond())); - tag.putString("BoundDimension", boundLocation.getFirst() - .location() - .toString()); - } - - private void writeTurns(CompoundTag tag) { - ListTag listTag = new ListTag(); - for (BezierConnection bezierConnection : connections.values()) - listTag.add(bezierConnection.write(worldPosition)); - tag.put("Connections", listTag); - } - - @Override - protected void read(CompoundTag tag, boolean clientPacket) { - super.read(tag, clientPacket); - connections.clear(); - for (Tag t : tag.getList("Connections", Tag.TAG_COMPOUND)) { - if (!(t instanceof CompoundTag)) - return; - BezierConnection connection = new BezierConnection((CompoundTag) t, worldPosition); - connections.put(connection.getKey(), connection); - } - - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); - - if (hasInteractableConnections()) - registerToCurveInteraction(); - else - removeFromCurveInteraction(); - - if (tag.contains("BoundLocation")) - boundLocation = Pair.of( - ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(tag.getString("BoundDimension"))), - NbtUtils.readBlockPos(tag.getCompound("BoundLocation"))); - } - - @Override - @OnlyIn(Dist.CLIENT) - public AABB getRenderBoundingBox() { - return INFINITE_EXTENT_AABB; - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void accept(BlockEntity other) { - if (other instanceof TrackTileEntity track) - connections.putAll(track.connections); - validateConnections(); - level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); - } - - public boolean hasInteractableConnections() { - for (BezierConnection connection : connections.values()) - if (connection.isPrimary()) - return true; - return false; - } - - @Override - public void transform(StructureTransform transform) { - if (transform.rotationAxis != Axis.Y) - return; - - Map transformedConnections = new HashMap<>(); - for (Entry entry : connections.entrySet()) { - BezierConnection newConnection = entry.getValue(); - newConnection.normals.replace(transform::applyWithoutOffsetUncentered); - newConnection.axes.replace(transform::applyWithoutOffsetUncentered); - - BlockPos diff = newConnection.tePositions.getSecond() - .subtract(newConnection.tePositions.getFirst()); - newConnection.tePositions.setSecond(new BlockPos(Vec3.atCenterOf(newConnection.tePositions.getFirst()) - .add(transform.applyWithoutOffsetUncentered(Vec3.atLowerCornerOf(diff))))); - - Vec3 teVec = Vec3.atLowerCornerOf(worldPosition); - Vec3 teCenterVec = teVec.add(0.5, 0.5, 0.5); - Vec3 start = newConnection.starts.getFirst(); - Vec3 startToTE = start.subtract(teCenterVec); - Vec3 endToStart = newConnection.starts.getSecond() - .subtract(start); - startToTE = transform.applyWithoutOffsetUncentered(startToTE) - .add(teCenterVec); - endToStart = transform.applyWithoutOffsetUncentered(endToStart) - .add(startToTE); - - newConnection.starts.setFirst(new TrackNodeLocation(startToTE).getLocation()); - newConnection.starts.setSecond(new TrackNodeLocation(endToStart).getLocation()); - - BlockPos newTarget = newConnection.getKey(); - transformedConnections.put(newTarget, newConnection); - } - - connections = transformedConnections; - } - - @Override - public void setRemoved() { - super.setRemoved(); - if (level.isClientSide) - removeFromCurveInteraction(); - } - - @Override - protected void setRemovedNotDueToChunkUnload() { - super.setRemovedNotDueToChunkUnload(); - - for (BezierConnection connection : connections.values()) - manageFakeTracksAlong(connection, true); - - if (boundLocation != null && level instanceof ServerLevel) { - ServerLevel otherLevel = level.getServer() - .getLevel(boundLocation.getFirst()); - if (otherLevel == null) - return; - if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond()))) - otherLevel.destroyBlock(boundLocation.getSecond(), false); - } - } - - private void registerToCurveInteraction() { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerToCurveInteractionUnsafe); - } - - private void removeFromCurveInteraction() { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::removeFromCurveInteractionUnsafe); - } - - @OnlyIn(Dist.CLIENT) - private void registerToCurveInteractionUnsafe() { - TrackBlockOutline.TRACKS_WITH_TURNS.get(level) - .put(worldPosition, this); - } - - @OnlyIn(Dist.CLIENT) - private void removeFromCurveInteractionUnsafe() { - TrackBlockOutline.TRACKS_WITH_TURNS.get(level) - .remove(worldPosition); - } - - public void manageFakeTracksAlong(BezierConnection bc, boolean remove) { - Map, Double> yLevels = new HashMap<>(); - BlockPos tePosition = bc.tePositions.getFirst(); - Vec3 end1 = bc.starts.getFirst() - .subtract(Vec3.atLowerCornerOf(tePosition)) - .add(0, 3 / 16f, 0); - Vec3 end2 = bc.starts.getSecond() - .subtract(Vec3.atLowerCornerOf(tePosition)) - .add(0, 3 / 16f, 0); - Vec3 axis1 = bc.axes.getFirst(); - Vec3 axis2 = bc.axes.getSecond(); - - double handleLength = bc.getHandleLength(); - - Vec3 finish1 = axis1.scale(handleLength) - .add(end1); - Vec3 finish2 = axis2.scale(handleLength) - .add(end2); - - Vec3 faceNormal1 = bc.normals.getFirst(); - Vec3 faceNormal2 = bc.normals.getSecond(); - - int segCount = bc.getSegmentCount(); - float[] lut = bc.getStepLUT(); - - for (int i = 0; i < segCount; i++) { - float t = i == segCount ? 1 : i * lut[i] / segCount; - t += 0.5f / segCount; - - Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t); - Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t) - .normalize(); - Vec3 faceNormal = - faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2); - Vec3 normal = faceNormal.cross(derivative) - .normalize(); - Vec3 below = result.add(faceNormal.scale(-.25f)); - Vec3 rail1 = below.add(normal.scale(.05f)); - Vec3 rail2 = below.subtract(normal.scale(.05f)); - Vec3 railMiddle = rail1.add(rail2) - .scale(.5); - - for (Vec3 vec : new Vec3[] { railMiddle }) { - BlockPos pos = new BlockPos(vec); - Pair key = Pair.of(pos.getX(), pos.getZ()); - if (!yLevels.containsKey(key) || yLevels.get(key) > vec.y) - yLevels.put(key, vec.y); - } - } - - for (Entry, Double> entry : yLevels.entrySet()) { - double yValue = entry.getValue(); - int floor = Mth.floor(yValue); - BlockPos targetPos = new BlockPos(entry.getKey() - .getFirst(), floor, - entry.getKey() - .getSecond()); - targetPos = targetPos.offset(tePosition) - .above(1); - - BlockState stateAtPos = level.getBlockState(targetPos); - boolean present = AllBlocks.FAKE_TRACK.has(stateAtPos); - - if (remove) { - if (present) - level.removeBlock(targetPos, false); - continue; - } - - FluidState fluidState = stateAtPos.getFluidState(); - if (!fluidState.isEmpty() && !fluidState.isSourceOfType(Fluids.WATER)) - continue; - - if (!present && stateAtPos.getMaterial() - .isReplaceable()) - level.setBlock(targetPos, - ProperWaterloggedBlock.withWater(level, AllBlocks.FAKE_TRACK.getDefaultState(), targetPos), 3); - FakeTrackBlock.keepAlive(level, targetPos); - } - } - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlock.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java rename to src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlock.java index 616f83a801..5514fb01a7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlock.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; +package com.simibubi.create.content.logistics.tunnel; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.createmod.catnip.utility.lang.Lang; import net.createmod.catnip.utility.worldWrappers.WrappedWorld; @@ -36,7 +36,7 @@ import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class BeltTunnelBlock extends Block implements ITE, IWrenchable { +public class BeltTunnelBlock extends Block implements IBE, IWrenchable { public static final Property SHAPE = EnumProperty.create("shape", Shape.class); public static final Property HORIZONTAL_AXIS = BlockStateProperties.HORIZONTAL_AXIS; @@ -100,7 +100,7 @@ public class BeltTunnelBlock extends Block implements ITE, @Override public void onPlace(BlockState state, Level world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { if (!(world instanceof WrappedWorld) && !world.isClientSide()) - withTileEntityDo(world, pos, BeltTunnelTileEntity::updateTunnelConnections); + withBlockEntityDo(world, pos, BeltTunnelBlockEntity::updateTunnelConnections); } @Override @@ -110,7 +110,7 @@ public class BeltTunnelBlock extends Block implements ITE, .isVertical()) return state; if (!(worldIn instanceof WrappedWorld) && !worldIn.isClientSide()) - withTileEntityDo(worldIn, currentPos, BeltTunnelTileEntity::updateTunnelConnections); + withBlockEntityDo(worldIn, currentPos, BeltTunnelBlockEntity::updateTunnelConnections); BlockState tunnelState = getTunnelState(worldIn, currentPos); if (tunnelState.getValue(HORIZONTAL_AXIS) == state.getValue(HORIZONTAL_AXIS)) { if (hasWindow(tunnelState) == hasWindow(state)) @@ -125,9 +125,9 @@ public class BeltTunnelBlock extends Block implements ITE, BlockState newTunnel = getTunnelState(world, pos); if (tunnel != newTunnel && !world.isClientSide()) { world.setBlock(pos, newTunnel, 3); - BlockEntity te = world.getBlockEntity(pos); - if (te != null && (te instanceof BeltTunnelTileEntity)) - ((BeltTunnelTileEntity) te).updateTunnelConnections(); + BlockEntity be = world.getBlockEntity(pos); + if (be != null && (be instanceof BeltTunnelBlockEntity)) + ((BeltTunnelBlockEntity) be).updateTunnelConnections(); } } @@ -185,7 +185,7 @@ public class BeltTunnelBlock extends Block implements ITE, return blockState.getValue(BeltBlock.HORIZONTAL_FACING) .getAxis() == side.getAxis(); DirectBeltInputBehaviour behaviour = - TileEntityBehaviour.get(world, pos.relative(side), DirectBeltInputBehaviour.TYPE); + BlockEntityBehaviour.get(world, pos.relative(side), DirectBeltInputBehaviour.TYPE); return behaviour != null && behaviour.canInsertFromSide(side); } @@ -232,13 +232,13 @@ public class BeltTunnelBlock extends Block implements ITE, } @Override - public Class getTileEntityClass() { - return BeltTunnelTileEntity.class; + public Class getBlockEntityClass() { + return BeltTunnelBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ANDESITE_TUNNEL.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ANDESITE_TUNNEL.get(); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlockEntity.java new file mode 100644 index 0000000000..4a04cab0e7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelBlockEntity.java @@ -0,0 +1,211 @@ +package com.simibubi.create.content.logistics.tunnel; + +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.tuple.Pair; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock.Shape; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class BeltTunnelBlockEntity extends SmartBlockEntity { + + public Map flaps; + public Set sides; + + protected LazyOptional cap = LazyOptional.empty(); + protected List> flapsToSend; + + public BeltTunnelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + flaps = new EnumMap<>(Direction.class); + sides = new HashSet<>(); + flapsToSend = new LinkedList<>(); + } + + @Override + public void invalidate() { + super.invalidate(); + cap.invalidate(); + } + + protected void writeFlapsAndSides(CompoundTag compound) { + ListTag flapsNBT = new ListTag(); + for (Direction direction : flaps.keySet()) + flapsNBT.add(IntTag.valueOf(direction.get3DDataValue())); + compound.put("Flaps", flapsNBT); + + ListTag sidesNBT = new ListTag(); + for (Direction direction : sides) + sidesNBT.add(IntTag.valueOf(direction.get3DDataValue())); + compound.put("Sides", sidesNBT); + } + + @Override + public void writeSafe(CompoundTag tag) { + writeFlapsAndSides(tag); + super.writeSafe(tag); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + writeFlapsAndSides(compound); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + Set newFlaps = new HashSet<>(6); + ListTag flapsNBT = compound.getList("Flaps", Tag.TAG_INT); + for (Tag inbt : flapsNBT) + if (inbt instanceof IntTag) + newFlaps.add(Direction.from3DDataValue(((IntTag) inbt).getAsInt())); + + sides.clear(); + ListTag sidesNBT = compound.getList("Sides", Tag.TAG_INT); + for (Tag inbt : sidesNBT) + if (inbt instanceof IntTag) + sides.add(Direction.from3DDataValue(((IntTag) inbt).getAsInt())); + + for (Direction d : Iterate.directions) + if (!newFlaps.contains(d)) + flaps.remove(d); + else if (!flaps.containsKey(d)) + flaps.put(d, createChasingFlap()); + + // Backwards compat + if (!compound.contains("Sides") && compound.contains("Flaps")) + sides.addAll(flaps.keySet()); + super.read(compound, clientPacket); + if (clientPacket) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + } + + private LerpedFloat createChasingFlap() { + return LerpedFloat.linear() + .startWithValue(.25f) + .chase(0, .05f, Chaser.EXP); + } + + public void updateTunnelConnections() { + flaps.clear(); + sides.clear(); + BlockState tunnelState = getBlockState(); + for (Direction direction : Iterate.horizontalDirections) { + if (direction.getAxis() != tunnelState.getValue(BlockStateProperties.HORIZONTAL_AXIS)) { + boolean positive = + direction.getAxisDirection() == AxisDirection.POSITIVE ^ direction.getAxis() == Axis.Z; + Shape shape = tunnelState.getValue(BeltTunnelBlock.SHAPE); + if (BeltTunnelBlock.isStraight(tunnelState)) + continue; + if (positive && shape == Shape.T_LEFT) + continue; + if (!positive && shape == Shape.T_RIGHT) + continue; + } + + sides.add(direction); + + // Flap might be occluded + BlockState nextState = level.getBlockState(worldPosition.relative(direction)); + if (nextState.getBlock() instanceof BeltTunnelBlock) + continue; + if (nextState.getBlock() instanceof BeltFunnelBlock) + if (nextState.getValue(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED + && nextState.getValue(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite()) + continue; + + flaps.put(direction, createChasingFlap()); + } + sendData(); + } + + public void flap(Direction side, boolean inward) { + if (level.isClientSide) { + if (flaps.containsKey(side)) + flaps.get(side) + .setValue(inward ^ side.getAxis() == Axis.Z ? -1 : 1); + return; + } + + flapsToSend.add(Pair.of(side, inward)); + } + + @Override + public void initialize() { + super.initialize(); + updateTunnelConnections(); + } + + @Override + public void tick() { + super.tick(); + if (!level.isClientSide) { + if (!flapsToSend.isEmpty()) + sendFlaps(); + return; + } + flaps.forEach((d, value) -> value.tickChaser()); + } + + private void sendFlaps() { + AllPackets.getChannel().send(packetTarget(), new TunnelFlapPacket(this, flapsToSend)); + + flapsToSend.clear(); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public LazyOptional getCapability(Capability capability, Direction side) { + if (capability != CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return super.getCapability(capability, side); + + if (!this.cap.isPresent()) { + if (AllBlocks.BELT.has(level.getBlockState(worldPosition.below()))) { + BlockEntity teBelow = level.getBlockEntity(worldPosition.below()); + if (teBelow != null) { + T capBelow = teBelow.getCapability(capability, Direction.UP) + .orElse(null); + if (capBelow != null) { + cap = LazyOptional.of(() -> capBelow) + .cast(); + } + } + } + } + return this.cap.cast(); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelInstance.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java rename to src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelInstance.java index f5ef5a0edf..b0407b4a1d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; +package com.simibubi.create.content.logistics.tunnel; import java.util.ArrayList; import java.util.Collection; @@ -10,8 +10,8 @@ import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.block.flap.FlapData; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.logistics.flwdata.FlapData; import com.simibubi.create.foundation.render.AllMaterialSpecs; import net.createmod.catnip.utility.AnimationTickHolder; @@ -19,23 +19,23 @@ import net.createmod.catnip.utility.animation.LerpedFloat; import net.minecraft.core.Direction; import net.minecraft.world.level.LightLayer; -public class BeltTunnelInstance extends BlockEntityInstance implements DynamicInstance { +public class BeltTunnelInstance extends BlockEntityInstance implements DynamicInstance { private final Map> tunnelFlaps; - public BeltTunnelInstance(MaterialManager modelManager, BeltTunnelTileEntity tile) { - super(modelManager, tile); + public BeltTunnelInstance(MaterialManager materialManager, BeltTunnelBlockEntity blockEntity) { + super(materialManager, blockEntity); tunnelFlaps = new EnumMap<>(Direction.class); - Instancer model = modelManager.defaultSolid() + Instancer model = materialManager.defaultSolid() .material(AllMaterialSpecs.FLAPS) - .getModel(AllBlockPartials.BELT_TUNNEL_FLAP, blockState); + .getModel(AllPartialModels.BELT_TUNNEL_FLAP, blockState); int blockLight = world.getBrightness(LightLayer.BLOCK, pos); int skyLight = world.getBrightness(LightLayer.SKY, pos); - tile.flaps.forEach((direction, flapValue) -> { + blockEntity.flaps.forEach((direction, flapValue) -> { float flapness = flapValue.getValue(AnimationTickHolder.getPartialTicks()); @@ -47,7 +47,7 @@ public class BeltTunnelInstance extends BlockEntityInstance { + + public BeltTunnelRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected void renderSafe(BeltTunnelBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(be.getLevel())) + return; + + SuperByteBuffer flapBuffer = CachedPartialBuffers.partial(AllPartialModels.BELT_TUNNEL_FLAP, be.getBlockState()); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + Vec3 pivot = VecHelper.voxelSpace(0, 10, 1f); + TransformStack msr = TransformStack.cast(ms); + + for (Direction direction : Iterate.directions) { + if (!be.flaps.containsKey(direction)) + continue; + + float horizontalAngle = AngleHelper.horizontalAngle(direction.getOpposite()); + float f = be.flaps.get(direction) + .getValue(partialTicks); + + ms.pushPose(); + msr.centre() + .rotateY(horizontalAngle) + .unCentre(); + + ms.translate(0.075f / 16f, 0, 0); + + for (int segment = 0; segment <= 3; segment++) { + ms.pushPose(); + float intensity = segment == 3 ? 1.5f : segment + 1; + float abs = Math.abs(f); + float flapAngle = Mth.sin((float) ((1 - abs) * Math.PI * intensity)) * 30 * f + * (direction.getAxis() == Axis.X ? 1 : -1); + if (f > 0) + flapAngle *= .5f; + + msr.translate(pivot) + .rotateX(flapAngle) + .translateBack(pivot); + flapBuffer.light(light) + .renderInto(ms, vb); + + ms.popPose(); + ms.translate(-3.05f / 16f, 0, 0); + } + ms.popPose(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelShapes.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelShapes.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelShapes.java rename to src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelShapes.java index 5bbcedcb2a..9dcf98999c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelShapes.java +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BeltTunnelShapes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.belts.tunnel; +package com.simibubi.create.content.logistics.tunnel; import static net.minecraft.world.level.block.Block.box; diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlock.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlock.java new file mode 100644 index 0000000000..5812add243 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlock.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.logistics.tunnel; + +import java.util.List; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class BrassTunnelBlock extends BeltTunnelBlock { + + public BrassTunnelBlock(BlockBehaviour.Properties properties) { + super(properties); + } + + @Override + public InteractionResult use(BlockState p_225533_1_, Level world, BlockPos pos, Player player, + InteractionHand p_225533_5_, BlockHitResult p_225533_6_) { + return onBlockEntityUse(world, pos, be -> { + if (!(be instanceof BrassTunnelBlockEntity)) + return InteractionResult.PASS; + BrassTunnelBlockEntity bte = (BrassTunnelBlockEntity) be; + List stacksOfGroup = bte.grabAllStacksOfGroup(world.isClientSide); + if (stacksOfGroup.isEmpty()) + return InteractionResult.PASS; + if (world.isClientSide) + return InteractionResult.SUCCESS; + for (ItemStack itemStack : stacksOfGroup) + player.getInventory().placeItemBackInInventory(itemStack.copy()); + world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, + 1f + world.random.nextFloat()); + return InteractionResult.SUCCESS; + }); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BRASS_TUNNEL.get(); + } + + @Override + public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor worldIn, + BlockPos currentPos, BlockPos facingPos) { + return super.updateShape(state, facing, facingState, worldIn, currentPos, facingPos); + } + + @Override + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, level, pos, newState); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlockEntity.java new file mode 100644 index 0000000000..d2b39809f8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelBlockEntity.java @@ -0,0 +1,806 @@ +package com.simibubi.create.content.logistics.tunnel; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltHelper; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock; +import com.simibubi.create.content.logistics.funnel.BeltFunnelBlock.Shape; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.SidedFilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +public class BrassTunnelBlockEntity extends BeltTunnelBlockEntity implements IHaveGoggleInformation { + + SidedFilteringBehaviour filtering; + + boolean connectedLeft; + boolean connectedRight; + + ItemStack stackToDistribute; + Direction stackEnteredFrom; + + float distributionProgress; + int distributionDistanceLeft; + int distributionDistanceRight; + int previousOutputIndex; + + // + Couple>> distributionTargets; + + private boolean syncedOutputActive; + private Set syncSet; + + protected ScrollOptionBehaviour selectionMode; + private LazyOptional beltCapability; + private LazyOptional tunnelCapability; + + public BrassTunnelBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + distributionTargets = Couple.create(ArrayList::new); + syncSet = new HashSet<>(); + stackToDistribute = ItemStack.EMPTY; + stackEnteredFrom = null; + beltCapability = LazyOptional.empty(); + tunnelCapability = LazyOptional.of(() -> new BrassTunnelItemHandler(this)); + previousOutputIndex = 0; + syncedOutputActive = false; + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + behaviours.add(selectionMode = new ScrollOptionBehaviour<>(SelectionMode.class, + CreateLang.translateDirect("logistics.when_multiple_outputs_available"), this, new BrassTunnelModeSlot())); + + selectionMode.onlyActiveWhen(this::hasDistributionBehaviour); + + // Propagate settings across connected tunnels + selectionMode.withCallback(setting -> { + for (boolean side : Iterate.trueAndFalse) { + if (!isConnected(side)) + continue; + BrassTunnelBlockEntity adjacent = getAdjacent(side); + if (adjacent != null) + adjacent.selectionMode.setValue(setting); + } + }); + } + + @Override + public void tick() { + super.tick(); + BeltBlockEntity beltBelow = BeltHelper.getSegmentBE(level, worldPosition.below()); + + if (distributionProgress > 0) + distributionProgress--; + if (beltBelow == null || beltBelow.getSpeed() == 0) + return; + if (stackToDistribute.isEmpty() && !syncedOutputActive) + return; + if (level.isClientSide && !isVirtual()) + return; + + if (distributionProgress == -1) { + distributionTargets.forEach(List::clear); + distributionDistanceLeft = 0; + distributionDistanceRight = 0; + + syncSet.clear(); + List> validOutputs = gatherValidOutputs(); + if (selectionMode.get() == SelectionMode.SYNCHRONIZE) { + boolean allEmpty = true; + boolean allFull = true; + for (BrassTunnelBlockEntity be : syncSet) { + boolean hasStack = !be.stackToDistribute.isEmpty(); + allEmpty &= !hasStack; + allFull &= hasStack; + } + final boolean notifySyncedOut = !allEmpty; + if (allFull || allEmpty) + syncSet.forEach(be -> be.syncedOutputActive = notifySyncedOut); + } + + if (validOutputs == null) + return; + if (stackToDistribute.isEmpty()) + return; + + for (Pair pair : validOutputs) { + BrassTunnelBlockEntity tunnel = pair.getKey(); + Direction output = pair.getValue(); + if (insertIntoTunnel(tunnel, output, stackToDistribute, true) == null) + continue; + distributionTargets.get(!tunnel.flapFilterEmpty(output)) + .add(Pair.of(tunnel.worldPosition, output)); + int distance = tunnel.worldPosition.getX() + tunnel.worldPosition.getZ() - worldPosition.getX() + - worldPosition.getZ(); + if (distance < 0) + distributionDistanceLeft = Math.max(distributionDistanceLeft, -distance); + else + distributionDistanceRight = Math.max(distributionDistanceRight, distance); + } + + if (distributionTargets.getFirst() + .isEmpty() + && distributionTargets.getSecond() + .isEmpty()) + return; + + if (selectionMode.get() != SelectionMode.SYNCHRONIZE || syncedOutputActive) { + distributionProgress = AllConfigs.server().logistics.brassTunnelTimer.get(); + sendData(); + } + return; + } + + if (distributionProgress != 0) + return; + + distributionTargets.forEach(list -> { + if (stackToDistribute.isEmpty()) + return; + List> validTargets = new ArrayList<>(); + for (Pair pair : list) { + BlockPos tunnelPos = pair.getKey(); + Direction output = pair.getValue(); + if (tunnelPos.equals(worldPosition) && output == stackEnteredFrom) + continue; + BlockEntity be = level.getBlockEntity(tunnelPos); + if (!(be instanceof BrassTunnelBlockEntity)) + continue; + validTargets.add(Pair.of((BrassTunnelBlockEntity) be, output)); + } + distribute(validTargets); + distributionProgress = -1; + }); + } + + private static Random rand = new Random(); + private static Map, ItemStack> distributed = new IdentityHashMap<>(); + private static Set> full = new HashSet<>(); + + private void distribute(List> validTargets) { + int amountTargets = validTargets.size(); + if (amountTargets == 0) + return; + + distributed.clear(); + full.clear(); + + int indexStart = previousOutputIndex % amountTargets; + SelectionMode mode = selectionMode.get(); + boolean force = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.FORCED_SPLIT; + boolean split = mode == SelectionMode.FORCED_SPLIT || mode == SelectionMode.SPLIT; + boolean robin = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.ROUND_ROBIN; + + if (mode == SelectionMode.RANDOMIZE) + indexStart = rand.nextInt(amountTargets); + if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE) + indexStart = 0; + + ItemStack toDistribute = stackToDistribute.copy(); + for (boolean distributeAgain : Iterate.trueAndFalse) { + ItemStack toDistributeThisCycle = null; + int remainingOutputs = amountTargets; + int leftovers = 0; + + for (boolean simulate : Iterate.trueAndFalse) { + if (remainingOutputs == 0) + break; + + leftovers = 0; + int index = indexStart; + int stackSize = toDistribute.getCount(); + int splitStackSize = stackSize / remainingOutputs; + int splitRemainder = stackSize % remainingOutputs; + int visited = 0; + + toDistributeThisCycle = toDistribute.copy(); + if (!(force || split) && simulate) + continue; + + while (visited < amountTargets) { + Pair pair = validTargets.get(index); + BrassTunnelBlockEntity tunnel = pair.getKey(); + Direction side = pair.getValue(); + index = (index + 1) % amountTargets; + visited++; + + if (full.contains(pair)) { + if (split && simulate) + remainingOutputs--; + continue; + } + + int count = split ? splitStackSize + (splitRemainder > 0 ? 1 : 0) : stackSize; + ItemStack toOutput = ItemHandlerHelper.copyStackWithSize(toDistributeThisCycle, count); + + // Grow by 1 to determine if target is full even after a successful transfer + boolean testWithIncreasedCount = distributed.containsKey(pair); + int increasedCount = testWithIncreasedCount ? distributed.get(pair) + .getCount() : 0; + if (testWithIncreasedCount) + toOutput.grow(increasedCount); + + ItemStack remainder = insertIntoTunnel(tunnel, side, toOutput, true); + + if (remainder == null || remainder.getCount() == (testWithIncreasedCount ? count + 1 : count)) { + if (force) + return; + if (split && simulate) + remainingOutputs--; + if (!simulate) + full.add(pair); + if (robin) + break; + continue; + } else if (!remainder.isEmpty() && !simulate) { + full.add(pair); + } + + if (!simulate) { + toOutput.shrink(remainder.getCount()); + distributed.put(pair, toOutput); + } + + leftovers += remainder.getCount(); + toDistributeThisCycle.shrink(count); + if (toDistributeThisCycle.isEmpty()) + break; + splitRemainder--; + if (!split) + break; + } + } + + toDistribute.setCount(toDistributeThisCycle.getCount() + leftovers); + if (leftovers == 0 && distributeAgain) + break; + if (!split) + break; + } + + int failedTransferrals = 0; + for (Entry, ItemStack> entry : distributed.entrySet()) { + Pair pair = entry.getKey(); + failedTransferrals += insertIntoTunnel(pair.getKey(), pair.getValue(), entry.getValue(), false).getCount(); + } + + toDistribute.grow(failedTransferrals); + stackToDistribute = ItemHandlerHelper.copyStackWithSize(stackToDistribute, toDistribute.getCount()); + if (stackToDistribute.isEmpty()) + stackEnteredFrom = null; + previousOutputIndex++; + previousOutputIndex %= amountTargets; + notifyUpdate(); + } + + public void setStackToDistribute(ItemStack stack, @Nullable Direction enteredFrom) { + stackToDistribute = stack; + stackEnteredFrom = enteredFrom; + distributionProgress = -1; + sendData(); + setChanged(); + } + + public ItemStack getStackToDistribute() { + return stackToDistribute; + } + + public List grabAllStacksOfGroup(boolean simulate) { + List list = new ArrayList<>(); + + ItemStack own = getStackToDistribute(); + if (!own.isEmpty()) { + list.add(own); + if (!simulate) + setStackToDistribute(ItemStack.EMPTY, null); + } + + for (boolean left : Iterate.trueAndFalse) { + BrassTunnelBlockEntity adjacent = this; + while (adjacent != null) { + if (!level.isLoaded(adjacent.getBlockPos())) + return null; + adjacent = adjacent.getAdjacent(left); + if (adjacent == null) + continue; + ItemStack other = adjacent.getStackToDistribute(); + if (other.isEmpty()) + continue; + list.add(other); + if (!simulate) + adjacent.setStackToDistribute(ItemStack.EMPTY, null); + } + } + + return list; + } + + @Nullable + protected ItemStack insertIntoTunnel(BrassTunnelBlockEntity tunnel, Direction side, ItemStack stack, + boolean simulate) { + if (stack.isEmpty()) + return stack; + if (!tunnel.testFlapFilter(side, stack)) + return null; + + BeltBlockEntity below = BeltHelper.getSegmentBE(level, tunnel.worldPosition.below()); + if (below == null) + return null; + BlockPos offset = tunnel.getBlockPos() + .below() + .relative(side); + DirectBeltInputBehaviour sideOutput = BlockEntityBehaviour.get(level, offset, DirectBeltInputBehaviour.TYPE); + if (sideOutput != null) { + if (!sideOutput.canInsertFromSide(side)) + return null; + ItemStack result = sideOutput.handleInsertion(stack, side, simulate); + if (result.isEmpty() && !simulate) + tunnel.flap(side, false); + return result; + } + + Direction movementFacing = below.getMovementFacing(); + if (side == movementFacing) + if (!BlockHelper.hasBlockSolidSide(level.getBlockState(offset), level, offset, side.getOpposite())) { + BeltBlockEntity controllerBE = below.getControllerBE(); + if (controllerBE == null) + return null; + + if (!simulate) { + tunnel.flap(side, true); + ItemStack ejected = stack; + float beltMovementSpeed = below.getDirectionAwareBeltMovementSpeed(); + float movementSpeed = Math.max(Math.abs(beltMovementSpeed), 1 / 8f); + int additionalOffset = beltMovementSpeed > 0 ? 1 : 0; + Vec3 outPos = BeltHelper.getVectorForOffset(controllerBE, below.index + additionalOffset); + Vec3 outMotion = Vec3.atLowerCornerOf(side.getNormal()) + .scale(movementSpeed) + .add(0, 1 / 8f, 0); + outPos.add(outMotion.normalize()); + ItemEntity entity = new ItemEntity(level, outPos.x, outPos.y + 6 / 16f, outPos.z, ejected); + entity.setDeltaMovement(outMotion); + entity.setDefaultPickUpDelay(); + entity.hurtMarked = true; + level.addFreshEntity(entity); + } + + return ItemStack.EMPTY; + } + + return null; + } + + public boolean testFlapFilter(Direction side, ItemStack stack) { + if (filtering == null) + return false; + if (filtering.get(side) == null) { + FilteringBehaviour adjacentFilter = + BlockEntityBehaviour.get(level, worldPosition.relative(side), FilteringBehaviour.TYPE); + if (adjacentFilter == null) + return true; + return adjacentFilter.test(stack); + } + return filtering.test(side, stack); + } + + public boolean flapFilterEmpty(Direction side) { + if (filtering == null) + return false; + if (filtering.get(side) == null) { + FilteringBehaviour adjacentFilter = + BlockEntityBehaviour.get(level, worldPosition.relative(side), FilteringBehaviour.TYPE); + if (adjacentFilter == null) + return true; + return adjacentFilter.getFilter() + .isEmpty(); + } + return filtering.getFilter(side) + .isEmpty(); + } + + @Override + public void initialize() { + if (filtering == null) { + filtering = createSidedFilter(); + attachBehaviourLate(filtering); + } + super.initialize(); + } + + public boolean canInsert(Direction side, ItemStack stack) { + if (filtering != null && !filtering.test(side, stack)) + return false; + if (!hasDistributionBehaviour()) + return true; + if (!stackToDistribute.isEmpty()) + return false; + return true; + } + + public boolean hasDistributionBehaviour() { + if (flaps.isEmpty()) + return false; + if (connectedLeft || connectedRight) + return true; + BlockState blockState = getBlockState(); + if (!AllBlocks.BRASS_TUNNEL.has(blockState)) + return false; + Axis axis = blockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS); + for (Direction direction : flaps.keySet()) + if (direction.getAxis() != axis) + return true; + return false; + } + + private List> gatherValidOutputs() { + List> validOutputs = new ArrayList<>(); + boolean synchronize = selectionMode.get() == SelectionMode.SYNCHRONIZE; + addValidOutputsOf(this, validOutputs); + + for (boolean left : Iterate.trueAndFalse) { + BrassTunnelBlockEntity adjacent = this; + while (adjacent != null) { + if (!level.isLoaded(adjacent.getBlockPos())) + return null; + adjacent = adjacent.getAdjacent(left); + if (adjacent == null) + continue; + addValidOutputsOf(adjacent, validOutputs); + } + } + + if (!syncedOutputActive && synchronize) + return null; + return validOutputs; + } + + private void addValidOutputsOf(BrassTunnelBlockEntity tunnelBE, + List> validOutputs) { + syncSet.add(tunnelBE); + BeltBlockEntity below = BeltHelper.getSegmentBE(level, tunnelBE.worldPosition.below()); + if (below == null) + return; + Direction movementFacing = below.getMovementFacing(); + BlockState blockState = getBlockState(); + if (!AllBlocks.BRASS_TUNNEL.has(blockState)) + return; + + boolean prioritizeSides = tunnelBE == this; + + for (boolean sidePass : Iterate.trueAndFalse) { + if (!prioritizeSides && sidePass) + continue; + for (Direction direction : Iterate.horizontalDirections) { + if (direction == movementFacing && below.getSpeed() == 0) + continue; + if (prioritizeSides && sidePass == (direction.getAxis() == movementFacing.getAxis())) + continue; + if (direction == movementFacing.getOpposite()) + continue; + if (!tunnelBE.sides.contains(direction)) + continue; + + BlockPos offset = tunnelBE.worldPosition.below() + .relative(direction); + + BlockState potentialFunnel = level.getBlockState(offset.above()); + if (potentialFunnel.getBlock() instanceof BeltFunnelBlock + && potentialFunnel.getValue(BeltFunnelBlock.SHAPE) == Shape.PULLING + && FunnelBlock.getFunnelFacing(potentialFunnel) == direction) + continue; + + DirectBeltInputBehaviour inputBehaviour = + BlockEntityBehaviour.get(level, offset, DirectBeltInputBehaviour.TYPE); + if (inputBehaviour == null) { + if (direction == movementFacing) + if (!BlockHelper.hasBlockSolidSide(level.getBlockState(offset), level, offset, + direction.getOpposite())) + validOutputs.add(Pair.of(tunnelBE, direction)); + continue; + } + if (inputBehaviour.canInsertFromSide(direction)) + validOutputs.add(Pair.of(tunnelBE, direction)); + continue; + } + } + } + + @Override + public void addBehavioursDeferred(List behaviours) { + super.addBehavioursDeferred(behaviours); + filtering = createSidedFilter(); + behaviours.add(filtering); + } + + protected SidedFilteringBehaviour createSidedFilter() { + return new SidedFilteringBehaviour(this, new BrassTunnelFilterSlot(), this::makeFilter, + this::isValidFaceForFilter); + } + + private FilteringBehaviour makeFilter(Direction side, FilteringBehaviour filter) { + return filter; + } + + private boolean isValidFaceForFilter(Direction side) { + return sides.contains(side); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("SyncedOutput", syncedOutputActive); + compound.putBoolean("ConnectedLeft", connectedLeft); + compound.putBoolean("ConnectedRight", connectedRight); + + compound.put("StackToDistribute", stackToDistribute.serializeNBT()); + if (stackEnteredFrom != null) + NBTHelper.writeEnum(compound, "StackEnteredFrom", stackEnteredFrom); + + compound.putFloat("DistributionProgress", distributionProgress); + compound.putInt("PreviousIndex", previousOutputIndex); + compound.putInt("DistanceLeft", distributionDistanceLeft); + compound.putInt("DistanceRight", distributionDistanceRight); + + for (boolean filtered : Iterate.trueAndFalse) { + compound.put(filtered ? "FilteredTargets" : "Targets", + NBTHelper.writeCompoundList(distributionTargets.get(filtered), pair -> { + CompoundTag nbt = new CompoundTag(); + nbt.put("Pos", NbtUtils.writeBlockPos(pair.getKey())); + nbt.putInt("Face", pair.getValue() + .get3DDataValue()); + return nbt; + })); + } + + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + boolean wasConnectedLeft = connectedLeft; + boolean wasConnectedRight = connectedRight; + + syncedOutputActive = compound.getBoolean("SyncedOutput"); + connectedLeft = compound.getBoolean("ConnectedLeft"); + connectedRight = compound.getBoolean("ConnectedRight"); + + stackToDistribute = ItemStack.of(compound.getCompound("StackToDistribute")); + stackEnteredFrom = + compound.contains("StackEnteredFrom") ? NBTHelper.readEnum(compound, "StackEnteredFrom", Direction.class) + : null; + + distributionProgress = compound.getFloat("DistributionProgress"); + previousOutputIndex = compound.getInt("PreviousIndex"); + distributionDistanceLeft = compound.getInt("DistanceLeft"); + distributionDistanceRight = compound.getInt("DistanceRight"); + + for (boolean filtered : Iterate.trueAndFalse) { + distributionTargets.set(filtered, NBTHelper + .readCompoundList(compound.getList(filtered ? "FilteredTargets" : "Targets", Tag.TAG_COMPOUND), nbt -> { + BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")); + Direction face = Direction.from3DDataValue(nbt.getInt("Face")); + return Pair.of(pos, face); + })); + } + + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (wasConnectedLeft != connectedLeft || wasConnectedRight != connectedRight) { + requestModelDataUpdate(); + if (hasLevel()) + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16); + } + filtering.updateFilterPresence(); + } + + public boolean isConnected(boolean leftSide) { + return leftSide ? connectedLeft : connectedRight; + } + + @Override + public void updateTunnelConnections() { + super.updateTunnelConnections(); + boolean connectivityChanged = false; + boolean nowConnectedLeft = determineIfConnected(true); + boolean nowConnectedRight = determineIfConnected(false); + + if (connectedLeft != nowConnectedLeft) { + connectedLeft = nowConnectedLeft; + connectivityChanged = true; + BrassTunnelBlockEntity adjacent = getAdjacent(true); + if (adjacent != null && !level.isClientSide) { + adjacent.updateTunnelConnections(); + adjacent.selectionMode.setValue(selectionMode.getValue()); + } + } + + if (connectedRight != nowConnectedRight) { + connectedRight = nowConnectedRight; + connectivityChanged = true; + BrassTunnelBlockEntity adjacent = getAdjacent(false); + if (adjacent != null && !level.isClientSide) { + adjacent.updateTunnelConnections(); + adjacent.selectionMode.setValue(selectionMode.getValue()); + } + } + + if (filtering != null) + filtering.updateFilterPresence(); + if (connectivityChanged) + sendData(); + } + + protected boolean determineIfConnected(boolean leftSide) { + if (flaps.isEmpty()) + return false; + BrassTunnelBlockEntity adjacentTunnelBE = getAdjacent(leftSide); + return adjacentTunnelBE != null && !adjacentTunnelBE.flaps.isEmpty(); + } + + @Nullable + protected BrassTunnelBlockEntity getAdjacent(boolean leftSide) { + if (!hasLevel()) + return null; + + BlockState blockState = getBlockState(); + if (!AllBlocks.BRASS_TUNNEL.has(blockState)) + return null; + + Axis axis = blockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS); + Direction baseDirection = Direction.get(AxisDirection.POSITIVE, axis); + Direction direction = leftSide ? baseDirection.getCounterClockWise() : baseDirection.getClockWise(); + BlockPos adjacentPos = worldPosition.relative(direction); + BlockState adjacentBlockState = level.getBlockState(adjacentPos); + + if (!AllBlocks.BRASS_TUNNEL.has(adjacentBlockState)) + return null; + if (adjacentBlockState.getValue(BrassTunnelBlock.HORIZONTAL_AXIS) != axis) + return null; + BlockEntity adjacentBE = level.getBlockEntity(adjacentPos); + if (adjacentBE.isRemoved()) + return null; + if (!(adjacentBE instanceof BrassTunnelBlockEntity)) + return null; + return (BrassTunnelBlockEntity) adjacentBE; + } + + @Override + public void invalidate() { + super.invalidate(); + tunnelCapability.invalidate(); + } + + @Override + public void destroy() { + super.destroy(); + Block.popResource(level, worldPosition, stackToDistribute); + stackEnteredFrom = null; + } + + @Override + public LazyOptional getCapability(Capability capability, Direction side) { + if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return tunnelCapability.cast(); + return super.getCapability(capability, side); + } + + public LazyOptional getBeltCapability() { + if (!beltCapability.isPresent()) { + BlockEntity blockEntity = level.getBlockEntity(worldPosition.below()); + if (blockEntity != null) + beltCapability = blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + } + return beltCapability; + } + + public enum SelectionMode implements INamedIconOptions { + SPLIT(AllIcons.I_TUNNEL_SPLIT), + FORCED_SPLIT(AllIcons.I_TUNNEL_FORCED_SPLIT), + ROUND_ROBIN(AllIcons.I_TUNNEL_ROUND_ROBIN), + FORCED_ROUND_ROBIN(AllIcons.I_TUNNEL_FORCED_ROUND_ROBIN), + PREFER_NEAREST(AllIcons.I_TUNNEL_PREFER_NEAREST), + RANDOMIZE(AllIcons.I_TUNNEL_RANDOMIZE), + SYNCHRONIZE(AllIcons.I_TUNNEL_SYNCHRONIZE), + + ; + + private final String translationKey; + private final AllIcons icon; + + SelectionMode(AllIcons icon) { + this.icon = icon; + this.translationKey = "tunnel.selection_mode." + Lang.asId(name()); + } + + @Override + public AllIcons getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + } + + public boolean canTakeItems() { + return stackToDistribute.isEmpty() && !syncedOutputActive; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + List allStacks = grabAllStacksOfGroup(true); + if (allStacks.isEmpty()) + return false; + + tooltip.add(componentSpacing.plainCopy() + .append(CreateLang.translateDirect("tooltip.brass_tunnel.contains")) + .withStyle(ChatFormatting.WHITE)); + for (ItemStack item : allStacks) { + tooltip.add(componentSpacing.plainCopy() + .append(CreateLang.translateDirect("tooltip.brass_tunnel.contains_entry", + Components.translatable(item.getDescriptionId()) + .getString(), + item.getCount())) + .withStyle(ChatFormatting.GRAY)); + } + tooltip.add(componentSpacing.plainCopy() + .append(CreateLang.translateDirect("tooltip.brass_tunnel.retrieve")) + .withStyle(ChatFormatting.DARK_GRAY)); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelCTBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelCTBehaviour.java new file mode 100644 index 0000000000..7004a7c862 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelCTBehaviour.java @@ -0,0 +1,50 @@ +package com.simibubi.create.content.logistics.tunnel; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllSpriteShifts; +import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; +import com.simibubi.create.foundation.block.connected.CTType; +import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class BrassTunnelCTBehaviour extends ConnectedTextureBehaviour.Base { + + @Override + public @Nullable CTType getDataType(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction direction) { + if (!(world.getBlockEntity(pos) instanceof BrassTunnelBlockEntity tunnelBE) + || !tunnelBE.hasDistributionBehaviour()) + return null; + return super.getDataType(world, pos, state, direction); + } + + @Override + public CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite) { + return direction == Direction.UP ? AllSpriteShifts.BRASS_TUNNEL_TOP : null; + } + + @Override + protected boolean reverseUVs(BlockState state, Direction face) { + return true; + } + + @Override + public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, + BlockPos otherPos, Direction face) { + int yDiff = otherPos.getY() - pos.getY(); + int zDiff = otherPos.getZ() - pos.getZ(); + if (yDiff != 0) + return false; + + if (!(reader.getBlockEntity(pos) instanceof BrassTunnelBlockEntity tunnelBE)) + return false; + boolean leftSide = zDiff > 0; + return tunnelBE.isConnected(leftSide); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelFilterSlot.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelFilterSlot.java new file mode 100644 index 0000000000..d06b5a0086 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelFilterSlot.java @@ -0,0 +1,15 @@ +package com.simibubi.create.content.logistics.tunnel; + +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.world.phys.Vec3; + +public class BrassTunnelFilterSlot extends ValueBoxTransform.Sided { + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 13, 15.5f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelItemHandler.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelItemHandler.java new file mode 100644 index 0000000000..430755c504 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelItemHandler.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.logistics.tunnel; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; + +public class BrassTunnelItemHandler implements IItemHandler { + + private BrassTunnelBlockEntity blockEntity; + + public BrassTunnelItemHandler(BrassTunnelBlockEntity be) { + this.blockEntity = be; + } + + @Override + public int getSlots() { + return 1; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return blockEntity.stackToDistribute; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + if (!blockEntity.hasDistributionBehaviour()) { + LazyOptional beltCapability = blockEntity.getBeltCapability(); + if (!beltCapability.isPresent()) + return stack; + return beltCapability.orElse(null).insertItem(slot, stack, simulate); + } + + if (!blockEntity.canTakeItems()) + return stack; + if (!simulate) + blockEntity.setStackToDistribute(stack, null); + return ItemStack.EMPTY; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + LazyOptional beltCapability = blockEntity.getBeltCapability(); + if (!beltCapability.isPresent()) + return ItemStack.EMPTY; + return beltCapability.orElse(null).extractItem(slot, amount, simulate); + } + + @Override + public int getSlotLimit(int slot) { + return blockEntity.stackToDistribute.isEmpty() ? 64 : blockEntity.stackToDistribute.getMaxStackSize(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelModeSlot.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelModeSlot.java new file mode 100644 index 0000000000..0b07a36c50 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/BrassTunnelModeSlot.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.logistics.tunnel; + +import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; + +import net.minecraft.core.Direction; + +public class BrassTunnelModeSlot extends CenteredSideValueBoxTransform { + + public BrassTunnelModeSlot() { + super((state, d) -> d == Direction.UP); + } + + @Override + public int getOverrideColor() { + return 0x592424; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/tunnel/TunnelFlapPacket.java b/src/main/java/com/simibubi/create/content/logistics/tunnel/TunnelFlapPacket.java new file mode 100644 index 0000000000..1cfe8db709 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/tunnel/TunnelFlapPacket.java @@ -0,0 +1,54 @@ +package com.simibubi.create.content.logistics.tunnel; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.foundation.networking.BlockEntityDataPacket; + +import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; + +public class TunnelFlapPacket extends BlockEntityDataPacket { + + private List> flaps; + + public TunnelFlapPacket(FriendlyByteBuf buffer) { + super(buffer); + + byte size = buffer.readByte(); + + this.flaps = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + Direction direction = Direction.from3DDataValue(buffer.readByte()); + boolean inwards = buffer.readBoolean(); + + flaps.add(Pair.of(direction, inwards)); + } + } + + public TunnelFlapPacket(BeltTunnelBlockEntity blockEntity, List> flaps) { + super(blockEntity.getBlockPos()); + + this.flaps = new ArrayList<>(flaps); + } + + @Override + protected void writeData(FriendlyByteBuf buffer) { + buffer.writeByte(flaps.size()); + + for (Pair flap : flaps) { + buffer.writeByte(flap.getLeft().get3DDataValue()); + buffer.writeBoolean(flap.getRight()); + } + } + + @Override + protected void handlePacket(BeltTunnelBlockEntity blockEntity) { + for (Pair flap : flaps) { + blockEntity.flap(flap.getLeft(), flap.getRight()); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultBlock.java b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultBlock.java rename to src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlock.java index f7cdb74eae..134d6f0e0e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.logistics.block.vault; +package com.simibubi.create.content.logistics.vault; import javax.annotation.Nullable; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllTileEntities; import com.simibubi.create.api.connectivity.ConnectivityHandler; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.core.BlockPos; @@ -34,7 +34,7 @@ import net.minecraft.world.level.block.state.properties.Property; import net.minecraftforge.common.util.ForgeSoundType; import net.minecraftforge.items.CapabilityItemHandler; -public class ItemVaultBlock extends Block implements IWrenchable, ITE { +public class ItemVaultBlock extends Block implements IWrenchable, IBE { public static final Property HORIZONTAL_AXIS = BlockStateProperties.HORIZONTAL_AXIS; public static final BooleanProperty LARGE = BooleanProperty.create("large"); @@ -74,7 +74,7 @@ public class ItemVaultBlock extends Block implements IWrenchable, ITE vte.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)) .map(lo -> lo.map(ItemHelper::calcRedstoneFromInventory) .orElse(0)) @@ -167,12 +167,12 @@ public class ItemVaultBlock extends Block implements IWrenchable, ITE getTileEntityType() { - return AllTileEntities.ITEM_VAULT.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ITEM_VAULT.get(); } @Override - public Class getTileEntityClass() { - return ItemVaultTileEntity.class; + public Class getBlockEntityClass() { + return ItemVaultBlockEntity.class; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java new file mode 100644 index 0000000000..9127bc91d8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultBlockEntity.java @@ -0,0 +1,312 @@ +package com.simibubi.create.content.logistics.vault; + +import java.util.List; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.api.connectivity.ConnectivityHandler; +import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.CombinedInvWrapper; + +public class ItemVaultBlockEntity extends SmartBlockEntity implements IMultiBlockEntityContainer.Inventory { + + protected LazyOptional itemCapability; + + protected ItemStackHandler inventory; + protected BlockPos controller; + protected BlockPos lastKnownPos; + protected boolean updateConnectivity; + protected int radius; + protected int length; + protected Axis axis; + + public ItemVaultBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + + inventory = new ItemStackHandler(AllConfigs.server().logistics.vaultCapacity.get()) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + updateComparators(); + } + }; + + itemCapability = LazyOptional.empty(); + radius = 1; + length = 1; + } + + @Override + public void addBehaviours(List behaviours) {} + + protected void updateConnectivity() { + updateConnectivity = false; + if (level.isClientSide()) + return; + if (!isController()) + return; + ConnectivityHandler.formMulti(this); + } + + protected void updateComparators() { + ItemVaultBlockEntity controllerBE = getControllerBE(); + if (controllerBE == null) + return; + + level.blockEntityChanged(controllerBE.worldPosition); + + BlockPos pos = controllerBE.getBlockPos(); + for (int y = 0; y < controllerBE.radius; y++) { + for (int z = 0; z < (controllerBE.axis == Axis.X ? controllerBE.radius : controllerBE.length); z++) { + for (int x = 0; x < (controllerBE.axis == Axis.Z ? controllerBE.radius : controllerBE.length); x++) { + level.updateNeighbourForOutputSignal(pos.offset(x, y, z), getBlockState().getBlock()); + } + } + } + } + + @Override + public void tick() { + super.tick(); + + if (lastKnownPos == null) + lastKnownPos = getBlockPos(); + else if (!lastKnownPos.equals(worldPosition) && worldPosition != null) { + onPositionChanged(); + return; + } + + if (updateConnectivity) + updateConnectivity(); + } + + @Override + public BlockPos getLastKnownPos() { + return lastKnownPos; + } + + @Override + public boolean isController() { + return controller == null || worldPosition.getX() == controller.getX() + && worldPosition.getY() == controller.getY() && worldPosition.getZ() == controller.getZ(); + } + + private void onPositionChanged() { + removeController(true); + lastKnownPos = worldPosition; + } + + @SuppressWarnings("unchecked") + @Override + public ItemVaultBlockEntity getControllerBE() { + if (isController()) + return this; + BlockEntity blockEntity = level.getBlockEntity(controller); + if (blockEntity instanceof ItemVaultBlockEntity) + return (ItemVaultBlockEntity) blockEntity; + return null; + } + + public void removeController(boolean keepContents) { + if (level.isClientSide()) + return; + updateConnectivity = true; + controller = null; + radius = 1; + length = 1; + + BlockState state = getBlockState(); + if (ItemVaultBlock.isVault(state)) { + state = state.setValue(ItemVaultBlock.LARGE, false); + getLevel().setBlock(worldPosition, state, 22); + } + + itemCapability.invalidate(); + setChanged(); + sendData(); + } + + @Override + public void setController(BlockPos controller) { + if (level.isClientSide && !isVirtual()) + return; + if (controller.equals(this.controller)) + return; + this.controller = controller; + itemCapability.invalidate(); + setChanged(); + sendData(); + } + + @Override + public BlockPos getController() { + return isController() ? worldPosition : controller; + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + + BlockPos controllerBefore = controller; + int prevSize = radius; + int prevLength = length; + + updateConnectivity = compound.contains("Uninitialized"); + controller = null; + lastKnownPos = null; + + if (compound.contains("LastKnownPos")) + lastKnownPos = NbtUtils.readBlockPos(compound.getCompound("LastKnownPos")); + if (compound.contains("Controller")) + controller = NbtUtils.readBlockPos(compound.getCompound("Controller")); + + if (isController()) { + radius = compound.getInt("Size"); + length = compound.getInt("Length"); + } + + if (!clientPacket) { + inventory.deserializeNBT(compound.getCompound("Inventory")); + return; + } + + boolean changeOfController = + controllerBefore == null ? controller != null : !controllerBefore.equals(controller); + if (hasLevel() && (changeOfController || prevSize != radius || prevLength != length)) + level.setBlocksDirty(getBlockPos(), Blocks.AIR.defaultBlockState(), getBlockState()); + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + if (updateConnectivity) + compound.putBoolean("Uninitialized", true); + if (lastKnownPos != null) + compound.put("LastKnownPos", NbtUtils.writeBlockPos(lastKnownPos)); + if (!isController()) + compound.put("Controller", NbtUtils.writeBlockPos(controller)); + if (isController()) { + compound.putInt("Size", radius); + compound.putInt("Length", length); + } + + super.write(compound, clientPacket); + + if (!clientPacket) { + compound.putString("StorageType", "CombinedInv"); + compound.put("Inventory", inventory.serializeNBT()); + } + } + + public ItemStackHandler getInventoryOfBlock() { + return inventory; + } + + public void applyInventoryToBlock(ItemStackHandler handler) { + for (int i = 0; i < inventory.getSlots(); i++) + inventory.setStackInSlot(i, i < handler.getSlots() ? handler.getStackInSlot(i) : ItemStack.EMPTY); + } + + @Override + public LazyOptional getCapability(Capability cap, Direction side) { + if (isItemHandlerCap(cap)) { + initCapability(); + return itemCapability.cast(); + } + return super.getCapability(cap, side); + } + + private void initCapability() { + if (itemCapability.isPresent()) + return; + if (!isController()) { + ItemVaultBlockEntity controllerBE = getControllerBE(); + if (controllerBE == null) + return; + controllerBE.initCapability(); + itemCapability = controllerBE.itemCapability; + return; + } + + boolean alongZ = ItemVaultBlock.getVaultBlockAxis(getBlockState()) == Axis.Z; + IItemHandlerModifiable[] invs = new IItemHandlerModifiable[length * radius * radius]; + for (int yOffset = 0; yOffset < length; yOffset++) { + for (int xOffset = 0; xOffset < radius; xOffset++) { + for (int zOffset = 0; zOffset < radius; zOffset++) { + BlockPos vaultPos = alongZ ? worldPosition.offset(xOffset, zOffset, yOffset) + : worldPosition.offset(yOffset, xOffset, zOffset); + ItemVaultBlockEntity vaultAt = + ConnectivityHandler.partAt(AllBlockEntityTypes.ITEM_VAULT.get(), level, vaultPos); + invs[yOffset * radius * radius + xOffset * radius + zOffset] = + vaultAt != null ? vaultAt.inventory : new ItemStackHandler(); + } + } + } + + CombinedInvWrapper combinedInvWrapper = new CombinedInvWrapper(invs); + itemCapability = LazyOptional.of(() -> combinedInvWrapper); + } + + public static int getMaxLength(int radius) { + return radius * 3; + } + + @Override + public void preventConnectivityUpdate() { updateConnectivity = false; } + + @Override + public void notifyMultiUpdated() { + BlockState state = this.getBlockState(); + if (ItemVaultBlock.isVault(state)) { // safety + level.setBlock(getBlockPos(), state.setValue(ItemVaultBlock.LARGE, radius > 2), 6); + } + itemCapability.invalidate(); + setChanged(); + } + + @Override + public Direction.Axis getMainConnectionAxis() { return getMainAxisOf(this); } + + @Override + public int getMaxLength(Direction.Axis longAxis, int width) { + if (longAxis == Direction.Axis.Y) return getMaxWidth(); + return getMaxLength(width); + } + + @Override + public int getMaxWidth() { + return 3; + } + + @Override + public int getHeight() { return length; } + + @Override + public int getWidth() { return radius; } + + @Override + public void setHeight(int height) { this.length = height; } + + @Override + public void setWidth(int width) { this.radius = width; } + + @Override + public boolean hasInventory() { return true; } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultCTBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultCTBehaviour.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultCTBehaviour.java rename to src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultCTBehaviour.java index 8088762775..d46b266167 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultCTBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultCTBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.vault; +package com.simibubi.create.content.logistics.vault; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultItem.java b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultItem.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultItem.java rename to src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultItem.java index cdb33430dd..7a863529fb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/vault/ItemVaultItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/vault/ItemVaultItem.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.vault; +package com.simibubi.create.content.logistics.vault; -import com.simibubi.create.AllTileEntities; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.api.connectivity.ConnectivityHandler; import net.createmod.catnip.utility.VecHelper; @@ -65,14 +65,14 @@ public class ItemVaultItem extends BlockItem { if (!ItemVaultBlock.isVault(placedOnState)) return; - ItemVaultTileEntity tankAt = ConnectivityHandler.partAt(AllTileEntities.ITEM_VAULT.get(), world, placedOnPos); + ItemVaultBlockEntity tankAt = ConnectivityHandler.partAt(AllBlockEntityTypes.ITEM_VAULT.get(), world, placedOnPos); if (tankAt == null) return; - ItemVaultTileEntity controllerTE = tankAt.getControllerTE(); - if (controllerTE == null) + ItemVaultBlockEntity controllerBE = tankAt.getControllerBE(); + if (controllerBE == null) return; - int width = controllerTE.radius; + int width = controllerBE.radius; if (width == 1) return; @@ -84,10 +84,10 @@ public class ItemVaultItem extends BlockItem { return; Direction vaultFacing = Direction.fromAxisAndDirection(vaultBlockAxis, AxisDirection.POSITIVE); - BlockPos startPos = face == vaultFacing.getOpposite() ? controllerTE.getBlockPos() + BlockPos startPos = face == vaultFacing.getOpposite() ? controllerBE.getBlockPos() .relative(vaultFacing.getOpposite()) - : controllerTE.getBlockPos() - .relative(vaultFacing, controllerTE.length); + : controllerBE.getBlockPos() + .relative(vaultFacing, controllerBE.length); if (VecHelper.getCoordinate(startPos, vaultBlockAxis) != VecHelper.getCoordinate(pos, vaultBlockAxis)) return; diff --git a/src/main/java/com/simibubi/create/content/materials/ExperienceBlock.java b/src/main/java/com/simibubi/create/content/materials/ExperienceBlock.java new file mode 100644 index 0000000000..4f57a20e56 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/materials/ExperienceBlock.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.materials; + +import java.util.Random; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class ExperienceBlock extends Block { + + public ExperienceBlock(Properties pProperties) { + super(pProperties); + } + + @Override + public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, Random pRand) { + if (pRand.nextInt(5) != 0) + return; + Vec3 vec3 = VecHelper.clampComponentWise(VecHelper.offsetRandomly(Vec3.ZERO, pRand, .75f), .55f) + .add(VecHelper.getCenterOf(pPos)); + pLevel.addParticle(ParticleTypes.END_ROD, vec3.x, vec3.y, vec3.z, pRand.nextGaussian() * 0.005D, + pRand.nextGaussian() * 0.005D, pRand.nextGaussian() * 0.005D); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/ExperienceNuggetItem.java b/src/main/java/com/simibubi/create/content/materials/ExperienceNuggetItem.java similarity index 86% rename from src/main/java/com/simibubi/create/content/curiosities/ExperienceNuggetItem.java rename to src/main/java/com/simibubi/create/content/materials/ExperienceNuggetItem.java index 9c981a587c..c29944eed9 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/ExperienceNuggetItem.java +++ b/src/main/java/com/simibubi/create/content/materials/ExperienceNuggetItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.content.materials; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.Direction.Axis; @@ -34,8 +34,9 @@ public class ExperienceNuggetItem extends Item { return InteractionResultHolder.consume(itemInHand); } - int total = Mth.ceil(3f * itemInHand.getCount()); - int maxOrbs = 5; + int amountUsed = pPlayer.isSteppingCarefully() ? 1 : itemInHand.getCount(); + int total = Mth.ceil(3f * amountUsed); + int maxOrbs = amountUsed == 1 ? 1 : 5; int valuePer = Math.max(1, 1 + total / maxOrbs); for (int i = 0; i < maxOrbs; i++) { @@ -60,6 +61,10 @@ public class ExperienceNuggetItem extends Item { pLevel.addFreshEntity(xp); } + itemInHand.shrink(amountUsed); + if (!itemInHand.isEmpty()) + return InteractionResultHolder.success(itemInHand); + pPlayer.setItemInHand(pUsedHand, ItemStack.EMPTY); return InteractionResultHolder.consume(itemInHand); } diff --git a/src/main/java/com/simibubi/create/content/palettes/PalettesItemGroup.java b/src/main/java/com/simibubi/create/content/palettes/PalettesItemGroup.java deleted file mode 100644 index 980ca176d3..0000000000 --- a/src/main/java/com/simibubi/create/content/palettes/PalettesItemGroup.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.simibubi.create.content.palettes; - -import java.util.EnumSet; - -import com.simibubi.create.content.AllSections; -import com.simibubi.create.foundation.item.CreateItemGroupBase; - -import net.minecraft.core.NonNullList; -import net.minecraft.world.item.ItemStack; - -public class PalettesItemGroup extends CreateItemGroupBase { - - public PalettesItemGroup() { - super("palettes"); - } - - @Override - protected EnumSet getSections() { - return EnumSet.of(AllSections.PALETTES); - } - - @Override - public void addItems(NonNullList items, boolean specialItems) {} - - @Override - public ItemStack makeIcon() { - return new ItemStack(AllPaletteBlocks.ORNATE_IRON_WINDOW.get()); - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorBlockItem.java b/src/main/java/com/simibubi/create/content/processing/AssemblyOperatorBlockItem.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorBlockItem.java rename to src/main/java/com/simibubi/create/content/processing/AssemblyOperatorBlockItem.java index c7e4d65db8..0538cb5f63 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorBlockItem.java +++ b/src/main/java/com/simibubi/create/content/processing/AssemblyOperatorBlockItem.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.components; +package com.simibubi.create.content.processing; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltSlope; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorUseContext.java b/src/main/java/com/simibubi/create/content/processing/AssemblyOperatorUseContext.java similarity index 91% rename from src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorUseContext.java rename to src/main/java/com/simibubi/create/content/processing/AssemblyOperatorUseContext.java index 38a66bb7bd..6115a92749 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/AssemblyOperatorUseContext.java +++ b/src/main/java/com/simibubi/create/content/processing/AssemblyOperatorUseContext.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components; +package com.simibubi.create.content.processing; import javax.annotation.Nullable; diff --git a/src/main/java/com/simibubi/create/content/processing/basin/BasinBlock.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinBlock.java new file mode 100644 index 0000000000..941cd5a991 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinBlock.java @@ -0,0 +1,229 @@ +package com.simibubi.create.content.processing.basin; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllShapes; +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.fluids.transfer.GenericItemFilling; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.logistics.funnel.FunnelBlock; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.foundation.item.ItemHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.EntityCollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; + +public class BasinBlock extends Block implements IBE, IWrenchable { + + public static final DirectionProperty FACING = BlockStateProperties.FACING_HOPPER; + + public BasinBlock(Properties p_i48440_1_) { + super(p_i48440_1_); + registerDefaultState(defaultBlockState().setValue(FACING, Direction.DOWN)); + } + + @Override + protected void createBlockStateDefinition(Builder p_206840_1_) { + super.createBlockStateDefinition(p_206840_1_.add(FACING)); + } + + @Override + public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { + BlockEntity blockEntity = world.getBlockEntity(pos.above()); + if (blockEntity instanceof BasinOperatingBlockEntity) + return false; + return true; + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + if (!context.getLevel().isClientSide) + withBlockEntityDo(context.getLevel(), context.getClickedPos(), + bte -> bte.onWrenched(context.getClickedFace())); + return InteractionResult.SUCCESS; + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + ItemStack heldItem = player.getItemInHand(handIn); + + return onBlockEntityUse(worldIn, pos, be -> { + if (!heldItem.isEmpty()) { + if (FluidHelper.tryEmptyItemIntoBE(worldIn, player, handIn, heldItem, be)) + return InteractionResult.SUCCESS; + if (FluidHelper.tryFillItemFromBE(worldIn, player, handIn, heldItem, be)) + return InteractionResult.SUCCESS; + + if (GenericItemEmptying.canItemBeEmptied(worldIn, heldItem) + || GenericItemFilling.canItemBeFilled(worldIn, heldItem)) + return InteractionResult.SUCCESS; + if (heldItem.getItem() + .equals(Items.SPONGE) + && !be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + .map(iFluidHandler -> iFluidHandler.drain(Integer.MAX_VALUE, IFluidHandler.FluidAction.EXECUTE)) + .orElse(FluidStack.EMPTY) + .isEmpty()) { + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + IItemHandlerModifiable inv = be.itemCapability.orElse(new ItemStackHandler(1)); + boolean success = false; + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + if (stackInSlot.isEmpty()) + continue; + player.getInventory() + .placeItemBackInInventory(stackInSlot); + inv.setStackInSlot(slot, ItemStack.EMPTY); + success = true; + } + if (success) + worldIn.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, .2f, + 1f + Create.RANDOM.nextFloat()); + be.onEmptied(); + return InteractionResult.SUCCESS; + }); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter worldIn, Entity entityIn) { + super.updateEntityAfterFallOn(worldIn, entityIn); + if (!AllBlocks.BASIN.has(worldIn.getBlockState(entityIn.blockPosition()))) + return; + if (!(entityIn instanceof ItemEntity)) + return; + if (!entityIn.isAlive()) + return; + ItemEntity itemEntity = (ItemEntity) entityIn; + withBlockEntityDo(worldIn, entityIn.blockPosition(), be -> { + + // Tossed items bypass the quarter-stack limit + be.inputInventory.withMaxStackSize(64); + ItemStack insertItem = ItemHandlerHelper.insertItem(be.inputInventory, itemEntity.getItem() + .copy(), false); + be.inputInventory.withMaxStackSize(16); + + if (insertItem.isEmpty()) { + itemEntity.discard(); + return; + } + + itemEntity.setItem(insertItem); + }); + } + + @Override + public VoxelShape getInteractionShape(BlockState p_199600_1_, BlockGetter p_199600_2_, BlockPos p_199600_3_) { + return AllShapes.BASIN_RAYTRACE_SHAPE; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.BASIN_BLOCK_SHAPE; + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter reader, BlockPos pos, CollisionContext ctx) { + if (ctx instanceof EntityCollisionContext && ((EntityCollisionContext) ctx).getEntity() instanceof ItemEntity) + return AllShapes.BASIN_COLLISION_SHAPE; + return getShape(state, reader, pos, ctx); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, worldIn, pos, newState); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) { + return getBlockEntityOptional(worldIn, pos).map(BasinBlockEntity::getInputInventory) + .map(ItemHelper::calcRedstoneFromInventory) + .orElse(0); + } + + @Override + public Class getBlockEntityClass() { + return BasinBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BASIN.get(); + } + + public static boolean canOutputTo(BlockGetter world, BlockPos basinPos, Direction direction) { + BlockPos neighbour = basinPos.relative(direction); + BlockPos output = neighbour.below(); + BlockState blockState = world.getBlockState(neighbour); + + if (FunnelBlock.isFunnel(blockState)) { + if (FunnelBlock.getFunnelFacing(blockState) == direction) + return false; + } else if (!blockState.getCollisionShape(world, neighbour) + .isEmpty()) { + return false; + } else { + BlockEntity blockEntity = world.getBlockEntity(output); + if (blockEntity instanceof BeltBlockEntity) { + BeltBlockEntity belt = (BeltBlockEntity) blockEntity; + return belt.getSpeed() == 0 || belt.getMovementFacing() != direction.getOpposite(); + } + } + + DirectBeltInputBehaviour directBeltInputBehaviour = + BlockEntityBehaviour.get(world, output, DirectBeltInputBehaviour.TYPE); + if (directBeltInputBehaviour != null) + return directBeltInputBehaviour.canInsertFromSide(direction); + return false; + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/processing/basin/BasinBlockEntity.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinBlockEntity.java new file mode 100644 index 0000000000..149b7aed6e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinBlockEntity.java @@ -0,0 +1,789 @@ +package com.simibubi.create.content.processing.basin; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.Random; + +import javax.annotation.Nonnull; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllParticleTypes; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.content.fluids.FluidFX; +import com.simibubi.create.content.fluids.particle.FluidParticleData; +import com.simibubi.create.content.kinetics.belt.behaviour.DirectBeltInputBehaviour; +import com.simibubi.create.content.kinetics.mixer.MechanicalMixerBlockEntity; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.fluid.CombinedTankWrapper; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.IntAttached; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.lang.LangBuilder; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.wrapper.CombinedInvWrapper; + +public class BasinBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + private boolean areFluidsMoving; + LerpedFloat ingredientRotationSpeed; + LerpedFloat ingredientRotation; + + public BasinInventory inputInventory; + public SmartFluidTankBehaviour inputTank; + protected SmartInventory outputInventory; + protected SmartFluidTankBehaviour outputTank; + private FilteringBehaviour filtering; + private boolean contentsChanged; + + private Couple invs; + private Couple tanks; + + protected LazyOptional itemCapability; + protected LazyOptional fluidCapability; + + List disabledSpoutputs; + Direction preferredSpoutput; + protected List spoutputBuffer; + protected List spoutputFluidBuffer; + int recipeBackupCheck; + + public static final int OUTPUT_ANIMATION_TIME = 10; + List> visualizedOutputItems; + List> visualizedOutputFluids; + + public BasinBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inputInventory = new BasinInventory(9, this); + inputInventory.whenContentsChanged($ -> contentsChanged = true); + outputInventory = new BasinInventory(9, this).forbidInsertion() + .withMaxStackSize(64); + areFluidsMoving = false; + itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory)); + contentsChanged = true; + ingredientRotation = LerpedFloat.angular() + .startWithValue(0); + ingredientRotationSpeed = LerpedFloat.linear() + .startWithValue(0); + + invs = Couple.create(inputInventory, outputInventory); + tanks = Couple.create(inputTank, outputTank); + visualizedOutputItems = Collections.synchronizedList(new ArrayList<>()); + visualizedOutputFluids = Collections.synchronizedList(new ArrayList<>()); + disabledSpoutputs = new ArrayList<>(); + preferredSpoutput = null; + spoutputBuffer = new ArrayList<>(); + spoutputFluidBuffer = new ArrayList<>(); + recipeBackupCheck = 20; + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(new DirectBeltInputBehaviour(this)); + filtering = new FilteringBehaviour(this, new BasinValueBox()).withCallback(newFilter -> contentsChanged = true) + .forRecipes(); + behaviours.add(filtering); + + inputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.INPUT, this, 2, 1000, true) + .whenFluidUpdates(() -> contentsChanged = true); + outputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.OUTPUT, this, 2, 1000, true) + .whenFluidUpdates(() -> contentsChanged = true) + .forbidInsertion(); + behaviours.add(inputTank); + behaviours.add(outputTank); + + fluidCapability = LazyOptional.of(() -> { + LazyOptional inputCap = inputTank.getCapability(); + LazyOptional outputCap = outputTank.getCapability(); + return new CombinedTankWrapper(outputCap.orElse(null), inputCap.orElse(null)); + }); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + inputInventory.deserializeNBT(compound.getCompound("InputItems")); + outputInventory.deserializeNBT(compound.getCompound("OutputItems")); + + preferredSpoutput = null; + if (compound.contains("PreferredSpoutput")) + preferredSpoutput = NBTHelper.readEnum(compound, "PreferredSpoutput", Direction.class); + disabledSpoutputs.clear(); + ListTag disabledList = compound.getList("DisabledSpoutput", Tag.TAG_STRING); + disabledList.forEach(d -> disabledSpoutputs.add(Direction.valueOf(((StringTag) d).getAsString()))); + spoutputBuffer = NBTHelper.readItemList(compound.getList("Overflow", Tag.TAG_COMPOUND)); + spoutputFluidBuffer = NBTHelper.readCompoundList(compound.getList("FluidOverflow", Tag.TAG_COMPOUND), + FluidStack::loadFluidStackFromNBT); + + if (!clientPacket) + return; + + NBTHelper.iterateCompoundList(compound.getList("VisualizedItems", Tag.TAG_COMPOUND), + c -> visualizedOutputItems.add(IntAttached.with(OUTPUT_ANIMATION_TIME, ItemStack.of(c)))); + NBTHelper.iterateCompoundList(compound.getList("VisualizedFluids", Tag.TAG_COMPOUND), + c -> visualizedOutputFluids + .add(IntAttached.with(OUTPUT_ANIMATION_TIME, FluidStack.loadFluidStackFromNBT(c)))); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.put("InputItems", inputInventory.serializeNBT()); + compound.put("OutputItems", outputInventory.serializeNBT()); + + if (preferredSpoutput != null) + NBTHelper.writeEnum(compound, "PreferredSpoutput", preferredSpoutput); + ListTag disabledList = new ListTag(); + disabledSpoutputs.forEach(d -> disabledList.add(StringTag.valueOf(d.name()))); + compound.put("DisabledSpoutput", disabledList); + compound.put("Overflow", NBTHelper.writeItemList(spoutputBuffer)); + compound.put("FluidOverflow", + NBTHelper.writeCompoundList(spoutputFluidBuffer, fs -> fs.writeToNBT(new CompoundTag()))); + + if (!clientPacket) + return; + + compound.put("VisualizedItems", NBTHelper.writeCompoundList(visualizedOutputItems, ia -> ia.getValue() + .serializeNBT())); + compound.put("VisualizedFluids", NBTHelper.writeCompoundList(visualizedOutputFluids, ia -> ia.getValue() + .writeToNBT(new CompoundTag()))); + visualizedOutputItems.clear(); + visualizedOutputFluids.clear(); + } + + @Override + public void destroy() { + super.destroy(); + ItemHelper.dropContents(level, worldPosition, inputInventory); + ItemHelper.dropContents(level, worldPosition, outputInventory); + spoutputBuffer.forEach(is -> Block.popResource(level, worldPosition, is)); + } + + @Override + public void remove() { + super.remove(); + onEmptied(); + } + + public void onEmptied() { + getOperator().ifPresent(be -> be.basinRemoved = true); + } + + @Override + public void invalidate() { + super.invalidate(); + itemCapability.invalidate(); + fluidCapability.invalidate(); + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, Direction side) { + if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + return itemCapability.cast(); + if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + return fluidCapability.cast(); + return super.getCapability(cap, side); + } + + @Override + public void notifyUpdate() { + super.notifyUpdate(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + + if (!level.isClientSide) { + updateSpoutput(); + if (recipeBackupCheck-- > 0) + return; + recipeBackupCheck = 20; + if (isEmpty()) + return; + notifyChangeOfContents(); + return; + } + + BlockEntity blockEntity = level.getBlockEntity(worldPosition.above(2)); + if (!(blockEntity instanceof MechanicalMixerBlockEntity)) { + setAreFluidsMoving(false); + return; + } + + MechanicalMixerBlockEntity mixer = (MechanicalMixerBlockEntity) blockEntity; + setAreFluidsMoving(mixer.running && mixer.runningTicks <= 20); + } + + public boolean isEmpty() { + return inputInventory.isEmpty() && outputInventory.isEmpty() && inputTank.isEmpty() && outputTank.isEmpty(); + } + + public void onWrenched(Direction face) { + BlockState blockState = getBlockState(); + Direction currentFacing = blockState.getValue(BasinBlock.FACING); + + disabledSpoutputs.remove(face); + if (currentFacing == face) { + if (preferredSpoutput == face) + preferredSpoutput = null; + disabledSpoutputs.add(face); + } else + preferredSpoutput = face; + + updateSpoutput(); + } + + private void updateSpoutput() { + BlockState blockState = getBlockState(); + Direction currentFacing = blockState.getValue(BasinBlock.FACING); + Direction newFacing = Direction.DOWN; + for (Direction test : Iterate.horizontalDirections) { + boolean canOutputTo = BasinBlock.canOutputTo(level, worldPosition, test); + if (canOutputTo && !disabledSpoutputs.contains(test)) + newFacing = test; + } + + if (preferredSpoutput != null && BasinBlock.canOutputTo(level, worldPosition, preferredSpoutput) + && preferredSpoutput != Direction.UP) + newFacing = preferredSpoutput; + + if (newFacing == currentFacing) + return; + + level.setBlockAndUpdate(worldPosition, blockState.setValue(BasinBlock.FACING, newFacing)); + + if (newFacing.getAxis() + .isVertical()) + return; + + for (int slot = 0; slot < outputInventory.getSlots(); slot++) { + ItemStack extractItem = outputInventory.extractItem(slot, 64, true); + if (extractItem.isEmpty()) + continue; + if (acceptOutputs(ImmutableList.of(extractItem), Collections.emptyList(), true)) + acceptOutputs(ImmutableList.of(outputInventory.extractItem(slot, 64, false)), Collections.emptyList(), + false); + } + + IFluidHandler handler = outputTank.getCapability() + .orElse(null); + for (int slot = 0; slot < handler.getTanks(); slot++) { + FluidStack fs = handler.getFluidInTank(slot) + .copy(); + if (fs.isEmpty()) + continue; + if (acceptOutputs(Collections.emptyList(), ImmutableList.of(fs), true)) { + handler.drain(fs, FluidAction.EXECUTE); + acceptOutputs(Collections.emptyList(), ImmutableList.of(fs), false); + } + } + + notifyChangeOfContents(); + notifyUpdate(); + } + + @Override + public void tick() { + super.tick(); + if (level.isClientSide) { + createFluidParticles(); + tickVisualizedOutputs(); + ingredientRotationSpeed.tickChaser(); + ingredientRotation.setValue(ingredientRotation.getValue() + ingredientRotationSpeed.getValue()); + } + + if ((!spoutputBuffer.isEmpty() || !spoutputFluidBuffer.isEmpty()) && !level.isClientSide) + tryClearingSpoutputOverflow(); + if (!contentsChanged) + return; + + contentsChanged = false; + getOperator().ifPresent(be -> be.basinChecker.scheduleUpdate()); + + for (Direction offset : Iterate.horizontalDirections) { + BlockPos toUpdate = worldPosition.above() + .relative(offset); + BlockState stateToUpdate = level.getBlockState(toUpdate); + if (stateToUpdate.getBlock() instanceof BasinBlock + && stateToUpdate.getValue(BasinBlock.FACING) == offset.getOpposite()) { + BlockEntity be = level.getBlockEntity(toUpdate); + if (be instanceof BasinBlockEntity) + ((BasinBlockEntity) be).contentsChanged = true; + } + } + } + + private void tryClearingSpoutputOverflow() { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return; + Direction direction = blockState.getValue(BasinBlock.FACING); + BlockEntity be = level.getBlockEntity(worldPosition.below() + .relative(direction)); + + FilteringBehaviour filter = null; + InvManipulationBehaviour inserter = null; + if (be != null) { + filter = BlockEntityBehaviour.get(level, be.getBlockPos(), FilteringBehaviour.TYPE); + inserter = BlockEntityBehaviour.get(level, be.getBlockPos(), InvManipulationBehaviour.TYPE); + } + + IItemHandler targetInv = be == null ? null + : be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, direction.getOpposite()) + .orElse(inserter == null ? null : inserter.getInventory()); + + IFluidHandler targetTank = be == null ? null + : be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite()) + .orElse(null); + + boolean update = false; + + for (Iterator iterator = spoutputBuffer.iterator(); iterator.hasNext();) { + ItemStack itemStack = iterator.next(); + + if (direction == Direction.DOWN) { + Block.popResource(level, worldPosition, itemStack); + iterator.remove(); + update = true; + continue; + } + + if (targetInv == null) + break; + if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack, true) + .isEmpty()) + continue; + if (filter != null && !filter.test(itemStack)) + continue; + + update = true; + ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), false); + iterator.remove(); + visualizedOutputItems.add(IntAttached.withZero(itemStack)); + } + + for (Iterator iterator = spoutputFluidBuffer.iterator(); iterator.hasNext();) { + FluidStack fluidStack = iterator.next(); + + if (direction == Direction.DOWN) { + iterator.remove(); + update = true; + continue; + } + + if (targetTank == null) + break; + + for (boolean simulate : Iterate.trueAndFalse) { + FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; + int fill = targetTank instanceof SmartFluidTankBehaviour.InternalFluidHandler + ? ((SmartFluidTankBehaviour.InternalFluidHandler) targetTank).forceFill(fluidStack.copy(), action) + : targetTank.fill(fluidStack.copy(), action); + if (fill != fluidStack.getAmount()) + break; + if (simulate) + continue; + + update = true; + iterator.remove(); + visualizedOutputFluids.add(IntAttached.withZero(fluidStack)); + } + } + + if (update) { + notifyChangeOfContents(); + sendData(); + } + } + + public float getTotalFluidUnits(float partialTicks) { + int renderedFluids = 0; + float totalUnits = 0; + + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.getRenderedFluid() + .isEmpty()) + continue; + float units = tankSegment.getTotalUnits(partialTicks); + if (units < 1) + continue; + totalUnits += units; + renderedFluids++; + } + } + + if (renderedFluids == 0) + return 0; + if (totalUnits < 1) + return 0; + return totalUnits; + } + + private Optional getOperator() { + if (level == null) + return Optional.empty(); + BlockEntity be = level.getBlockEntity(worldPosition.above(2)); + if (be instanceof BasinOperatingBlockEntity) + return Optional.of((BasinOperatingBlockEntity) be); + return Optional.empty(); + } + + public FilteringBehaviour getFilter() { + return filtering; + } + + public void notifyChangeOfContents() { + contentsChanged = true; + } + + public SmartInventory getInputInventory() { + return inputInventory; + } + + public SmartInventory getOutputInventory() { + return outputInventory; + } + + public boolean canContinueProcessing() { + return spoutputBuffer.isEmpty() && spoutputFluidBuffer.isEmpty(); + } + + public boolean acceptOutputs(List outputItems, List outputFluids, boolean simulate) { + outputInventory.allowInsertion(); + outputTank.allowInsertion(); + boolean acceptOutputsInner = acceptOutputsInner(outputItems, outputFluids, simulate); + outputInventory.forbidInsertion(); + outputTank.forbidInsertion(); + return acceptOutputsInner; + } + + private boolean acceptOutputsInner(List outputItems, List outputFluids, boolean simulate) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return false; + + Direction direction = blockState.getValue(BasinBlock.FACING); + if (direction != Direction.DOWN) { + + BlockEntity be = level.getBlockEntity(worldPosition.below() + .relative(direction)); + + InvManipulationBehaviour inserter = + be == null ? null : BlockEntityBehaviour.get(level, be.getBlockPos(), InvManipulationBehaviour.TYPE); + IItemHandler targetInv = be == null ? null + : be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, direction.getOpposite()) + .orElse(inserter == null ? null : inserter.getInventory()); + IFluidHandler targetTank = be == null ? null + : be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction.getOpposite()) + .orElse(null); + boolean externalTankNotPresent = targetTank == null; + + if (!outputItems.isEmpty() && targetInv == null) + return false; + if (!outputFluids.isEmpty() && externalTankNotPresent) { + // Special case - fluid outputs but output only accepts items + targetTank = outputTank.getCapability() + .orElse(null); + if (targetTank == null) + return false; + if (!acceptFluidOutputsIntoBasin(outputFluids, simulate, targetTank)) + return false; + } + + if (simulate) + return true; + for (ItemStack itemStack : outputItems) { + spoutputBuffer.add(itemStack.copy()); + } + if (!externalTankNotPresent) + for (FluidStack fluidStack : outputFluids) + spoutputFluidBuffer.add(fluidStack.copy()); + return true; + } + + IItemHandler targetInv = outputInventory; + IFluidHandler targetTank = outputTank.getCapability() + .orElse(null); + + if (targetInv == null && !outputItems.isEmpty()) + return false; + if (!acceptItemOutputsIntoBasin(outputItems, simulate, targetInv)) + return false; + if (outputFluids.isEmpty()) + return true; + if (targetTank == null) + return false; + if (!acceptFluidOutputsIntoBasin(outputFluids, simulate, targetTank)) + return false; + + return true; + } + + private boolean acceptFluidOutputsIntoBasin(List outputFluids, boolean simulate, + IFluidHandler targetTank) { + for (FluidStack fluidStack : outputFluids) { + FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; + int fill = targetTank instanceof SmartFluidTankBehaviour.InternalFluidHandler + ? ((SmartFluidTankBehaviour.InternalFluidHandler) targetTank).forceFill(fluidStack.copy(), action) + : targetTank.fill(fluidStack.copy(), action); + if (fill != fluidStack.getAmount()) + return false; + } + return true; + } + + private boolean acceptItemOutputsIntoBasin(List outputItems, boolean simulate, IItemHandler targetInv) { + for (ItemStack itemStack : outputItems) { + if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate) + .isEmpty()) + return false; + } + return true; + } + + public void readOnlyItems(CompoundTag compound) { + inputInventory.deserializeNBT(compound.getCompound("InputItems")); + outputInventory.deserializeNBT(compound.getCompound("OutputItems")); + } + + public static HeatLevel getHeatLevelOf(BlockState state) { + if (state.hasProperty(BlazeBurnerBlock.HEAT_LEVEL)) + return state.getValue(BlazeBurnerBlock.HEAT_LEVEL); + return AllTags.AllBlockTags.PASSIVE_BOILER_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; + } + + public Couple getTanks() { + return tanks; + } + + public Couple getInvs() { + return invs; + } + + // client things + + private void tickVisualizedOutputs() { + visualizedOutputFluids.forEach(IntAttached::decrement); + visualizedOutputItems.forEach(IntAttached::decrement); + visualizedOutputFluids.removeIf(IntAttached::isOrBelowZero); + visualizedOutputItems.removeIf(IntAttached::isOrBelowZero); + } + + private void createFluidParticles() { + Random r = level.random; + + if (!visualizedOutputFluids.isEmpty()) + createOutputFluidParticles(r); + + if (!areFluidsMoving && r.nextFloat() > 1 / 8f) + return; + + int segments = 0; + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) + if (!tankSegment.isEmpty(0)) + segments++; + } + if (segments < 2) + return; + + float totalUnits = getTotalFluidUnits(0); + if (totalUnits == 0) + return; + float fluidLevel = Mth.clamp(totalUnits / 2000, 0, 1); + float rim = 2 / 16f; + float space = 12 / 16f; + float surface = worldPosition.getY() + rim + space * fluidLevel + 1 / 32f; + + if (areFluidsMoving) { + createMovingFluidParticles(surface, segments); + return; + } + + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + float x = worldPosition.getX() + rim + space * r.nextFloat(); + float z = worldPosition.getZ() + rim + space * r.nextFloat(); + level.addAlwaysVisibleParticle( + new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), x, + surface, z, 0, 0, 0); + } + } + } + + private void createOutputFluidParticles(Random r) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return; + Direction direction = blockState.getValue(BasinBlock.FACING); + if (direction == Direction.DOWN) + return; + Vec3 directionVec = Vec3.atLowerCornerOf(direction.getNormal()); + Vec3 outVec = VecHelper.getCenterOf(worldPosition) + .add(directionVec.scale(.65) + .subtract(0, 1 / 4f, 0)); + Vec3 outMotion = directionVec.scale(1 / 16f) + .add(0, -1 / 16f, 0); + + for (int i = 0; i < 2; i++) { + visualizedOutputFluids.forEach(ia -> { + FluidStack fluidStack = ia.getValue(); + ParticleOptions fluidParticle = FluidFX.getFluidParticle(fluidStack); + Vec3 m = VecHelper.offsetRandomly(outMotion, r, 1 / 16f); + level.addAlwaysVisibleParticle(fluidParticle, outVec.x, outVec.y, outVec.z, m.x, m.y, m.z); + }); + } + } + + private void createMovingFluidParticles(float surface, int segments) { + Vec3 pointer = new Vec3(1, 0, 0).scale(1 / 16f); + float interval = 360f / segments; + Vec3 centerOf = VecHelper.getCenterOf(worldPosition); + float intervalOffset = (AnimationTickHolder.getTicks() * 18) % 360; + + int currentSegment = 0; + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + float angle = interval * (1 + currentSegment) + intervalOffset; + Vec3 vec = centerOf.add(VecHelper.rotate(pointer, angle, Axis.Y)); + level.addAlwaysVisibleParticle( + new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), vec.x(), + surface, vec.z(), 1, 0, 0); + currentSegment++; + } + } + } + + public boolean areFluidsMoving() { + return areFluidsMoving; + } + + public boolean setAreFluidsMoving(boolean areFluidsMoving) { + this.areFluidsMoving = areFluidsMoving; + ingredientRotationSpeed.chase(areFluidsMoving ? 20 : 0, .1f, Chaser.EXP); + return areFluidsMoving; + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + CreateLang.translate("gui.goggles.basin_contents") + .forGoggles(tooltip); + + IItemHandlerModifiable items = itemCapability.orElse(new ItemStackHandler()); + IFluidHandler fluids = fluidCapability.orElse(new FluidTank(0)); + boolean isEmpty = true; + + for (int i = 0; i < items.getSlots(); i++) { + ItemStack stackInSlot = items.getStackInSlot(i); + if (stackInSlot.isEmpty()) + continue; + CreateLang.text("") + .add(Components.translatable(stackInSlot.getDescriptionId()) + .withStyle(ChatFormatting.GRAY)) + .add(CreateLang.text(" x" + stackInSlot.getCount()) + .style(ChatFormatting.GREEN)) + .forGoggles(tooltip, 1); + isEmpty = false; + } + + LangBuilder mb = CreateLang.translate("generic.unit.millibuckets"); + for (int i = 0; i < fluids.getTanks(); i++) { + FluidStack fluidStack = fluids.getFluidInTank(i); + if (fluidStack.isEmpty()) + continue; + CreateLang.text("") + .add(CreateLang.fluidName(fluidStack) + .add(CreateLang.text(" ")) + .style(ChatFormatting.GRAY) + .add(CreateLang.number(fluidStack.getAmount()) + .add(mb) + .style(ChatFormatting.BLUE))) + .forGoggles(tooltip, 1); + isEmpty = false; + } + + if (isEmpty) + tooltip.remove(0); + + return true; + } + + class BasinValueBox extends ValueBoxTransform.Sided { + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8, 12, 16.05); + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + return direction.getAxis() + .isHorizontal(); + } + + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinGenerator.java similarity index 94% rename from src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java rename to src/main/java/com/simibubi/create/content/processing/basin/BasinGenerator.java index 84704801e5..1683a5ebad 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinGenerator.java +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.processing.basin; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinInventory.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java rename to src/main/java/com/simibubi/create/content/processing/basin/BasinInventory.java index c0e3bed776..0c88d4d0d1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinInventory.java +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinInventory.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.processing.basin; import com.simibubi.create.foundation.item.SmartInventory; @@ -7,11 +7,11 @@ import net.minecraftforge.items.ItemHandlerHelper; public class BasinInventory extends SmartInventory { - private BasinTileEntity te; + private BasinBlockEntity blockEntity; - public BasinInventory(int slots, BasinTileEntity te) { - super(slots, te, 16, true); - this.te = te; + public BasinInventory(int slots, BasinBlockEntity be) { + super(slots, be, 16, true); + this.blockEntity = be; } @Override @@ -27,7 +27,7 @@ public class BasinInventory extends SmartInventory { public ItemStack extractItem(int slot, int amount, boolean simulate) { ItemStack extractItem = super.extractItem(slot, amount, simulate); if (!simulate && !extractItem.isEmpty()) - te.notifyChangeOfContents(); + blockEntity.notifyChangeOfContents(); return extractItem; } diff --git a/src/main/java/com/simibubi/create/content/processing/basin/BasinMovementBehaviour.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinMovementBehaviour.java new file mode 100644 index 0000000000..646c3783d0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinMovementBehaviour.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.processing.basin; + +import java.util.HashMap; +import java.util.Map; + +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; + +import net.minecraft.core.Direction; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.items.ItemStackHandler; + +public class BasinMovementBehaviour implements MovementBehaviour { + public Map getOrReadInventory(MovementContext context) { + Map map = new HashMap<>(); + map.put("InputItems", new ItemStackHandler(9)); + map.put("OutputItems", new ItemStackHandler(8)); + map.forEach((s, h) -> h.deserializeNBT(context.blockEntityData.getCompound(s))); + return map; + } + + @Override + public boolean renderAsNormalBlockEntity() { + return true; + } + + @Override + public void tick(MovementContext context) { + MovementBehaviour.super.tick(context); + if (context.temporaryData == null || (boolean) context.temporaryData) { + Vec3 facingVec = context.rotation.apply(Vec3.atLowerCornerOf(Direction.UP.getNormal())); + facingVec.normalize(); + if (Direction.getNearest(facingVec.x, facingVec.y, facingVec.z) == Direction.DOWN) + dump(context, facingVec); + } + } + + private void dump(MovementContext context, Vec3 facingVec) { + getOrReadInventory(context).forEach((key, itemStackHandler) -> { + for (int i = 0; i < itemStackHandler.getSlots(); i++) { + if (itemStackHandler.getStackInSlot(i) + .isEmpty()) + continue; + ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y, + context.position.z, itemStackHandler.getStackInSlot(i)); + itemEntity.setDeltaMovement(facingVec.scale(.05)); + context.world.addFreshEntity(itemEntity); + itemStackHandler.setStackInSlot(i, ItemStack.EMPTY); + } + context.blockEntityData.put(key, itemStackHandler.serializeNBT()); + }); + BlockEntity blockEntity = context.contraption.presentBlockEntities.get(context.localPos); + if (blockEntity instanceof BasinBlockEntity) + ((BasinBlockEntity) blockEntity).readOnlyItems(context.blockEntityData); + context.temporaryData = false; // did already dump, so can't any more + } +} diff --git a/src/main/java/com/simibubi/create/content/processing/basin/BasinOperatingBlockEntity.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinOperatingBlockEntity.java new file mode 100644 index 0000000000..d179938516 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinOperatingBlockEntity.java @@ -0,0 +1,155 @@ +package com.simibubi.create.content.processing.basin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.advancement.CreateAdvancement; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.simple.DeferralBehaviour; +import com.simibubi.create.foundation.recipe.RecipeFinder; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.Container; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class BasinOperatingBlockEntity extends KineticBlockEntity { + + public DeferralBehaviour basinChecker; + public boolean basinRemoved; + protected Recipe currentRecipe; + + public BasinOperatingBlockEntity(BlockEntityType typeIn, BlockPos pos, BlockState state) { + super(typeIn, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + super.addBehaviours(behaviours); + basinChecker = new DeferralBehaviour(this, this::updateBasin); + behaviours.add(basinChecker); + } + + @Override + public void onSpeedChanged(float prevSpeed) { + super.onSpeedChanged(prevSpeed); + if (getSpeed() == 0) + basinRemoved = true; + basinRemoved = false; + basinChecker.scheduleUpdate(); + } + + @Override + public void tick() { + if (basinRemoved) { + basinRemoved = false; + onBasinRemoved(); + sendData(); + return; + } + + super.tick(); + } + + protected boolean updateBasin() { + if (!isSpeedRequirementFulfilled()) + return true; + if (getSpeed() == 0) + return true; + if (isRunning()) + return true; + if (level == null || level.isClientSide) + return true; + Optional basin = getBasin(); + if (!basin.filter(BasinBlockEntity::canContinueProcessing) + .isPresent()) + return true; + + List> recipes = getMatchingRecipes(); + if (recipes.isEmpty()) + return true; + currentRecipe = recipes.get(0); + startProcessingBasin(); + sendData(); + return true; + } + + protected abstract boolean isRunning(); + + public void startProcessingBasin() {} + + public boolean continueWithPreviousRecipe() { + return true; + } + + protected boolean matchBasinRecipe(Recipe recipe) { + if (recipe == null) + return false; + Optional basin = getBasin(); + if (!basin.isPresent()) + return false; + return BasinRecipe.match(basin.get(), recipe); + } + + protected void applyBasinRecipe() { + if (currentRecipe == null) + return; + + Optional optionalBasin = getBasin(); + if (!optionalBasin.isPresent()) + return; + BasinBlockEntity basin = optionalBasin.get(); + boolean wasEmpty = basin.canContinueProcessing(); + if (!BasinRecipe.apply(basin, currentRecipe)) + return; + getProcessedRecipeTrigger().ifPresent(this::award); + basin.inputTank.sendDataImmediately(); + + // Continue mixing + if (wasEmpty && matchBasinRecipe(currentRecipe)) { + continueWithPreviousRecipe(); + sendData(); + } + + basin.notifyChangeOfContents(); + } + + protected List> getMatchingRecipes() { + if (getBasin().map(BasinBlockEntity::isEmpty) + .orElse(true)) + return new ArrayList<>(); + + List> list = RecipeFinder.get(getRecipeCacheKey(), level, this::matchStaticFilters); + return list.stream() + .filter(this::matchBasinRecipe) + .sorted((r1, r2) -> r2.getIngredients() + .size() + - r1.getIngredients() + .size()) + .collect(Collectors.toList()); + } + + protected abstract void onBasinRemoved(); + + protected Optional getBasin() { + if (level == null) + return Optional.empty(); + BlockEntity basinBE = level.getBlockEntity(worldPosition.below(2)); + if (!(basinBE instanceof BasinBlockEntity)) + return Optional.empty(); + return Optional.of((BasinBlockEntity) basinBE); + } + + protected Optional getProcessedRecipeTrigger() { + return Optional.empty(); + } + + protected abstract boolean matchStaticFilters(Recipe recipe); + + protected abstract Object getRecipeCacheKey(); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinRecipe.java similarity index 83% rename from src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java rename to src/main/java/com/simibubi/create/content/processing/basin/BasinRecipe.java index df78b93e1b..dfb4142e5b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRecipe.java +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinRecipe.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.processing.basin; import java.util.ArrayList; import java.util.Collections; @@ -8,15 +8,17 @@ import java.util.List; import javax.annotation.Nonnull; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeParams; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.item.SmartInventory; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.utility.recipe.DummyCraftingContainer; -import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo; +import com.simibubi.create.foundation.recipe.DummyCraftingContainer; +import com.simibubi.create.foundation.recipe.IRecipeTypeInfo; import net.createmod.catnip.utility.Iterate; import net.minecraft.world.item.ItemStack; @@ -32,7 +34,7 @@ import net.minecraftforge.items.IItemHandler; public class BasinRecipe extends ProcessingRecipe { - public static boolean match(BasinTileEntity basin, Recipe recipe) { + public static boolean match(BasinBlockEntity basin, Recipe recipe) { FilteringBehaviour filter = basin.getFilter(); if (filter == null) return false; @@ -54,11 +56,11 @@ public class BasinRecipe extends ProcessingRecipe { return apply(basin, recipe, true); } - public static boolean apply(BasinTileEntity basin, Recipe recipe) { + public static boolean apply(BasinBlockEntity basin, Recipe recipe) { return apply(basin, recipe, false); } - private static boolean apply(BasinTileEntity basin, Recipe recipe, boolean test) { + private static boolean apply(BasinBlockEntity basin, Recipe recipe, boolean test) { boolean isBasinRecipe = recipe instanceof BasinRecipe; IItemHandler availableItems = basin.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) .orElse(null); @@ -68,7 +70,7 @@ public class BasinRecipe extends ProcessingRecipe { if (availableItems == null || availableFluids == null) return false; - HeatLevel heat = BasinTileEntity.getHeatLevelOf(basin.getLevel() + HeatLevel heat = BasinBlockEntity.getHeatLevelOf(basin.getLevel() .getBlockState(basin.getBlockPos() .below(1))); if (isBasinRecipe && !((BasinRecipe) recipe).getRequiredHeat() @@ -100,10 +102,6 @@ public class BasinRecipe extends ProcessingRecipe { ItemStack extracted = availableItems.extractItem(slot, 1, true); if (!ingredient.test(extracted)) continue; - // Catalyst items are never consumed - if (extracted.hasContainerItem() && extracted.getContainerItem() - .sameItem(extracted)) - continue Ingredients; if (!simulate) availableItems.extractItem(slot, 1, false); extractedItemsFromSlot[slot]++; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java b/src/main/java/com/simibubi/create/content/processing/basin/BasinRenderer.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java rename to src/main/java/com/simibubi/create/content/processing/basin/BasinRenderer.java index e7e1ea1d1c..6bd0d7a34e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java +++ b/src/main/java/com/simibubi/create/content/processing/basin/BasinRenderer.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.contraptions.processing; +package com.simibubi.create.content.processing.basin; import java.util.Random; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; import com.simibubi.create.foundation.fluid.FluidRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; -import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import net.createmod.catnip.utility.IntAttached; import net.createmod.catnip.utility.VecHelper; @@ -28,14 +28,14 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; -public class BasinRenderer extends SmartTileEntityRenderer { +public class BasinRenderer extends SmartBlockEntityRenderer { public BasinRenderer(BlockEntityRendererProvider.Context context) { super(context); } @Override - protected void renderSafe(BasinTileEntity basin, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(BasinBlockEntity basin, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { super.renderSafe(basin, partialTicks, ms, buffer, light, overlay); @@ -116,7 +116,7 @@ public class BasinRenderer extends SmartTileEntityRenderer { .getBlock() instanceof BasinBlock; for (IntAttached intAttached : basin.visualizedOutputItems) { - float progress = 1 - (intAttached.getFirst() - partialTicks) / BasinTileEntity.OUTPUT_ANIMATION_TIME; + float progress = 1 - (intAttached.getFirst() - partialTicks) / BasinBlockEntity.OUTPUT_ANIMATION_TIME; if (!outToBasin && progress > .35f) continue; @@ -139,7 +139,7 @@ public class BasinRenderer extends SmartTileEntityRenderer { .renderStatic(stack, TransformType.GROUND, light, overlay, ms, buffer, 0); } - protected float renderFluids(BasinTileEntity basin, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected float renderFluids(BasinBlockEntity basin, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { SmartFluidTankBehaviour inputFluids = basin.getBehaviour(SmartFluidTankBehaviour.INPUT); SmartFluidTankBehaviour outputFluids = basin.getBehaviour(SmartFluidTankBehaviour.OUTPUT); @@ -172,7 +172,8 @@ public class BasinRenderer extends SmartTileEntityRenderer { float partial = Mth.clamp(units / totalUnits, 0, 1); xMax += partial * 12 / 16f; - FluidRenderer.renderFluidBox(renderedFluid.getFluid(), renderedFluid.getAmount(), xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false); + FluidRenderer.renderFluidBox(renderedFluid.getFluid(), renderedFluid.getAmount(), xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, + false); xMin = xMax; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlock.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlock.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlock.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlock.java index 859b48d6ee..11548d5324 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlock.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlock.java @@ -1,17 +1,17 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import java.util.Random; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.processing.BasinTileEntity; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.processing.basin.BasinBlockEntity; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.MethodsReturnNonnullByDefault; @@ -20,7 +20,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; import net.minecraft.util.StringRepresentable; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -58,7 +57,7 @@ import net.minecraftforge.common.util.FakePlayer; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE, IWrenchable { +public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements IBE, IWrenchable { public static final EnumProperty HEAT_LEVEL = EnumProperty.create("blaze", HeatLevel.class); @@ -77,10 +76,10 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< public void onPlace(BlockState state, Level world, BlockPos pos, BlockState p_220082_4_, boolean p_220082_5_) { if (world.isClientSide) return; - BlockEntity tileEntity = world.getBlockEntity(pos.above()); - if (!(tileEntity instanceof BasinTileEntity)) + BlockEntity blockEntity = world.getBlockEntity(pos.above()); + if (!(blockEntity instanceof BasinBlockEntity)) return; - BasinTileEntity basin = (BasinTileEntity) tileEntity; + BasinBlockEntity basin = (BasinBlockEntity) blockEntity; basin.notifyChangeOfContents(); } @@ -91,13 +90,13 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< } @Override - public Class getTileEntityClass() { - return BlazeBurnerTileEntity.class; + public Class getBlockEntityClass() { + return BlazeBurnerBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.HEATER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.HEATER.get(); } @Nullable @@ -105,7 +104,7 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { if (state.getValue(HEAT_LEVEL) == HeatLevel.NONE) return null; - return ITE.super.newBlockEntity(pos, state); + return IBE.super.newBlockEntity(pos, state); } @Override @@ -115,7 +114,7 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< HeatLevel heat = state.getValue(HEAT_LEVEL); if (AllItems.GOGGLES.isIn(heldItem) && heat != HeatLevel.NONE) - return onTileEntityUse(world, pos, bbte -> { + return onBlockEntityUse(world, pos, bbte -> { if (bbte.goggles) return InteractionResult.PASS; bbte.goggles = true; @@ -124,7 +123,7 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< }); if (heldItem.isEmpty() && heat != HeatLevel.NONE) - return onTileEntityUse(world, pos, bbte -> { + return onBlockEntityUse(world, pos, bbte -> { if (!bbte.goggles) return InteractionResult.PASS; bbte.goggles = false; @@ -168,17 +167,17 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< if (!state.hasBlockEntity()) return InteractionResultHolder.fail(ItemStack.EMPTY); - BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof BlazeBurnerTileEntity)) + BlockEntity be = world.getBlockEntity(pos); + if (!(be instanceof BlazeBurnerBlockEntity)) return InteractionResultHolder.fail(ItemStack.EMPTY); - BlazeBurnerTileEntity burnerTE = (BlazeBurnerTileEntity) te; + BlazeBurnerBlockEntity burnerBE = (BlazeBurnerBlockEntity) be; - if (burnerTE.isCreativeFuel(stack)) { + if (burnerBE.isCreativeFuel(stack)) { if (!simulate) - burnerTE.applyCreativeFuel(); + burnerBE.applyCreativeFuel(); return InteractionResultHolder.success(ItemStack.EMPTY); } - if (!burnerTE.tryUpdateFuel(stack, forceOverflow, simulate)) + if (!burnerBE.tryUpdateFuel(stack, forceOverflow, simulate)) return InteractionResultHolder.fail(ItemStack.EMPTY); if (!doNotConsume) { @@ -252,8 +251,12 @@ public class BlazeBurnerBlock extends HorizontalDirectionalBlock implements ITE< } public static int getLight(BlockState state) { - return Mth.clamp(state.getValue(HEAT_LEVEL) - .ordinal() * 4 - 1, 0, 15); + HeatLevel level = state.getValue(HEAT_LEVEL); + return switch (level) { + case NONE -> 0; + case SMOULDERING -> 8; + default -> 15; + }; } public static LootTable.Builder buildLootTable() { diff --git a/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockEntity.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockEntity.java new file mode 100644 index 0000000000..b54fe47b6a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockEntity.java @@ -0,0 +1,354 @@ +package com.simibubi.create.content.processing.burner; + +import java.util.List; +import java.util.Random; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllTags.AllItemTags; +import com.simibubi.create.content.fluids.tank.FluidTankBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.ForgeHooks; + +public class BlazeBurnerBlockEntity extends SmartBlockEntity { + + public static final int MAX_HEAT_CAPACITY = 10000; + public static final int INSERTION_THRESHOLD = 500; + + protected FuelType activeFuel; + protected int remainingBurnTime; + protected LerpedFloat headAnimation; + protected LerpedFloat headAngle; + protected boolean isCreative; + protected boolean goggles; + protected boolean hat; + + public BlazeBurnerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + activeFuel = FuelType.NONE; + remainingBurnTime = 0; + headAnimation = LerpedFloat.linear(); + headAngle = LerpedFloat.angular(); + isCreative = false; + goggles = false; + + headAngle.startWithValue((AngleHelper.horizontalAngle(state.getOptionalValue(BlazeBurnerBlock.FACING) + .orElse(Direction.SOUTH)) + 180) % 360); + } + + public FuelType getActiveFuel() { + return activeFuel; + } + + public int getRemainingBurnTime() { + return remainingBurnTime; + } + + public boolean isCreative() { + return isCreative; + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) { + tickAnimation(); + if (!isVirtual()) + spawnParticles(getHeatLevelFromBlock(), 1); + return; + } + + if (isCreative) + return; + + if (remainingBurnTime > 0) + remainingBurnTime--; + + if (activeFuel == FuelType.NORMAL) + updateBlockState(); + if (remainingBurnTime > 0) + return; + + if (activeFuel == FuelType.SPECIAL) { + activeFuel = FuelType.NORMAL; + remainingBurnTime = MAX_HEAT_CAPACITY / 2; + } else + activeFuel = FuelType.NONE; + + updateBlockState(); + } + + @OnlyIn(Dist.CLIENT) + private void tickAnimation() { + boolean active = getHeatLevelFromBlock().isAtLeast(HeatLevel.FADING) && isValidBlockAbove(); + + if (!active) { + float target = 0; + LocalPlayer player = Minecraft.getInstance().player; + if (player != null && !player.isInvisible()) { + double x; + double z; + if (isVirtual()) { + x = -4; + z = -10; + } else { + x = player.getX(); + z = player.getZ(); + } + double dx = x - (getBlockPos().getX() + 0.5); + double dz = z - (getBlockPos().getZ() + 0.5); + target = AngleHelper.deg(-Mth.atan2(dz, dx)) - 90; + } + target = headAngle.getValue() + AngleHelper.getShortestAngleDiff(headAngle.getValue(), target); + headAngle.chase(target, .25f, Chaser.exp(5)); + headAngle.tickChaser(); + } else { + headAngle.chase((AngleHelper.horizontalAngle(getBlockState().getOptionalValue(BlazeBurnerBlock.FACING) + .orElse(Direction.SOUTH)) + 180) % 360, .125f, Chaser.EXP); + headAngle.tickChaser(); + } + + headAnimation.chase(active ? 1 : 0, .25f, Chaser.exp(.25f)); + headAnimation.tickChaser(); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (!isCreative) { + compound.putInt("fuelLevel", activeFuel.ordinal()); + compound.putInt("burnTimeRemaining", remainingBurnTime); + } else + compound.putBoolean("isCreative", true); + if (goggles) + compound.putBoolean("Goggles", true); + if (hat) + compound.putBoolean("TrainHat", true); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + activeFuel = FuelType.values()[compound.getInt("fuelLevel")]; + remainingBurnTime = compound.getInt("burnTimeRemaining"); + isCreative = compound.getBoolean("isCreative"); + goggles = compound.contains("Goggles"); + hat = compound.contains("TrainHat"); + super.read(compound, clientPacket); + } + + public BlazeBurnerBlock.HeatLevel getHeatLevelFromBlock() { + return BlazeBurnerBlock.getHeatLevelOf(getBlockState()); + } + + public void updateBlockState() { + setBlockHeat(getHeatLevel()); + } + + protected void setBlockHeat(HeatLevel heat) { + HeatLevel inBlockState = getHeatLevelFromBlock(); + if (inBlockState == heat) + return; + level.setBlockAndUpdate(worldPosition, getBlockState().setValue(BlazeBurnerBlock.HEAT_LEVEL, heat)); + notifyUpdate(); + } + + /** + * @return true if the heater updated its burn time and an item should be + * consumed + */ + protected boolean tryUpdateFuel(ItemStack itemStack, boolean forceOverflow, boolean simulate) { + if (isCreative) + return false; + + FuelType newFuel = FuelType.NONE; + int newBurnTime; + + if (AllItemTags.BLAZE_BURNER_FUEL_SPECIAL.matches(itemStack)) { + newBurnTime = 3200; + newFuel = FuelType.SPECIAL; + } else { + newBurnTime = ForgeHooks.getBurnTime(itemStack, null); + if (newBurnTime > 0) { + newFuel = FuelType.NORMAL; + } else if (AllItemTags.BLAZE_BURNER_FUEL_REGULAR.matches(itemStack)) { + newBurnTime = 1600; // Same as coal + newFuel = FuelType.NORMAL; + } + } + + if (newFuel == FuelType.NONE) + return false; + if (newFuel.ordinal() < activeFuel.ordinal()) + return false; + + if (newFuel == activeFuel) { + if (remainingBurnTime <= INSERTION_THRESHOLD) { + newBurnTime += remainingBurnTime; + } else if (forceOverflow && newFuel == FuelType.NORMAL) { + if (remainingBurnTime < MAX_HEAT_CAPACITY) { + newBurnTime = Math.min(remainingBurnTime + newBurnTime, MAX_HEAT_CAPACITY); + } else { + newBurnTime = remainingBurnTime; + } + } else { + return false; + } + } + + if (simulate) + return true; + + activeFuel = newFuel; + remainingBurnTime = newBurnTime; + + if (level.isClientSide) { + spawnParticleBurst(activeFuel == FuelType.SPECIAL); + return true; + } + + HeatLevel prev = getHeatLevelFromBlock(); + playSound(); + updateBlockState(); + + if (prev != getHeatLevelFromBlock()) + level.playSound(null, worldPosition, SoundEvents.BLAZE_AMBIENT, SoundSource.BLOCKS, + .125f + level.random.nextFloat() * .125f, 1.15f - level.random.nextFloat() * .25f); + + return true; + } + + protected void applyCreativeFuel() { + activeFuel = FuelType.NONE; + remainingBurnTime = 0; + isCreative = true; + + HeatLevel next = getHeatLevelFromBlock().nextActiveLevel(); + + if (level.isClientSide) { + spawnParticleBurst(next.isAtLeast(HeatLevel.SEETHING)); + return; + } + + playSound(); + if (next == HeatLevel.FADING) + next = next.nextActiveLevel(); + setBlockHeat(next); + } + + public boolean isCreativeFuel(ItemStack stack) { + return AllItems.CREATIVE_BLAZE_CAKE.isIn(stack); + } + + public boolean isValidBlockAbove() { + if (isVirtual()) + return false; + BlockState blockState = level.getBlockState(worldPosition.above()); + return AllBlocks.BASIN.has(blockState) || blockState.getBlock() instanceof FluidTankBlock; + } + + protected void playSound() { + level.playSound(null, worldPosition, SoundEvents.BLAZE_SHOOT, SoundSource.BLOCKS, + .125f + level.random.nextFloat() * .125f, .75f - level.random.nextFloat() * .25f); + } + + protected HeatLevel getHeatLevel() { + HeatLevel level = HeatLevel.SMOULDERING; + switch (activeFuel) { + case SPECIAL: + level = HeatLevel.SEETHING; + break; + case NORMAL: + boolean lowPercent = (double) remainingBurnTime / MAX_HEAT_CAPACITY < 0.0125; + level = lowPercent ? HeatLevel.FADING : HeatLevel.KINDLED; + break; + default: + case NONE: + break; + } + return level; + } + + protected void spawnParticles(HeatLevel heatLevel, double burstMult) { + if (level == null) + return; + if (heatLevel == BlazeBurnerBlock.HeatLevel.NONE) + return; + + Random r = level.getRandom(); + + Vec3 c = VecHelper.getCenterOf(worldPosition); + Vec3 v = c.add(VecHelper.offsetRandomly(Vec3.ZERO, r, .125f) + .multiply(1, 0, 1)); + + if (r.nextInt(4) != 0) + return; + + boolean empty = level.getBlockState(worldPosition.above()) + .getCollisionShape(level, worldPosition.above()) + .isEmpty(); + + if (empty || r.nextInt(8) == 0) + level.addParticle(ParticleTypes.LARGE_SMOKE, v.x, v.y, v.z, 0, 0, 0); + + double yMotion = empty ? .0625f : r.nextDouble() * .0125f; + Vec3 v2 = c.add(VecHelper.offsetRandomly(Vec3.ZERO, r, .5f) + .multiply(1, .25f, 1) + .normalize() + .scale((empty ? .25f : .5) + r.nextDouble() * .125f)) + .add(0, .5, 0); + + if (heatLevel.isAtLeast(HeatLevel.SEETHING)) { + level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v2.x, v2.y, v2.z, 0, yMotion, 0); + } else if (heatLevel.isAtLeast(HeatLevel.FADING)) { + level.addParticle(ParticleTypes.FLAME, v2.x, v2.y, v2.z, 0, yMotion, 0); + } + return; + } + + public void spawnParticleBurst(boolean soulFlame) { + Vec3 c = VecHelper.getCenterOf(worldPosition); + Random r = level.random; + for (int i = 0; i < 20; i++) { + Vec3 offset = VecHelper.offsetRandomly(Vec3.ZERO, r, .5f) + .multiply(1, .25f, 1) + .normalize(); + Vec3 v = c.add(offset.scale(.5 + r.nextDouble() * .125f)) + .add(0, .125, 0); + Vec3 m = offset.scale(1 / 32f); + + level.addParticle(soulFlame ? ParticleTypes.SOUL_FIRE_FLAME : ParticleTypes.FLAME, v.x, v.y, v.z, m.x, m.y, + m.z); + } + } + + public enum FuelType { + NONE, NORMAL, SPECIAL + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlockItem.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockItem.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlockItem.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockItem.java index 0843fe2864..1115905586 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerBlockItem.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerBlockItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import java.util.ArrayList; import java.util.List; @@ -82,13 +82,13 @@ public class BlazeBurnerBlockItem extends BlockItem { Level world = context.getLevel(); BlockPos pos = context.getClickedPos(); - BlockEntity te = world.getBlockEntity(pos); + BlockEntity be = world.getBlockEntity(pos); Player player = context.getPlayer(); - if (!(te instanceof SpawnerBlockEntity)) + if (!(be instanceof SpawnerBlockEntity)) return super.useOn(context); - BaseSpawner spawner = ((SpawnerBlockEntity) te).getSpawner(); + BaseSpawner spawner = ((SpawnerBlockEntity) be).getSpawner(); List possibleSpawns = spawner.spawnPotentials.unwrap() .stream() diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerHandler.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerHandler.java similarity index 88% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerHandler.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerHandler.java index cae8d2cc58..6d63f2890e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerHandler.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerHandler.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerTileEntity.FuelType; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlockEntity.FuelType; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -44,9 +44,9 @@ public class BlazeBurnerHandler { .getType() != HitResult.Type.BLOCK) return; - BlockEntity tile = projectile.level.getBlockEntity(new BlockPos(event.getRayTraceResult() + BlockEntity blockEntity = projectile.level.getBlockEntity(new BlockPos(event.getRayTraceResult() .getLocation())); - if (!(tile instanceof BlazeBurnerTileEntity)) { + if (!(blockEntity instanceof BlazeBurnerBlockEntity)) { return; } @@ -58,12 +58,12 @@ public class BlazeBurnerHandler { if (world.isClientSide) return; - BlazeBurnerTileEntity heater = (BlazeBurnerTileEntity) tile; + BlazeBurnerBlockEntity heater = (BlazeBurnerBlockEntity) blockEntity; if (!heater.isCreative()) { if (heater.activeFuel != FuelType.SPECIAL) { heater.activeFuel = FuelType.NORMAL; heater.remainingBurnTime = - Mth.clamp(heater.remainingBurnTime + 80, 0, BlazeBurnerTileEntity.MAX_HEAT_CAPACITY); + Mth.clamp(heater.remainingBurnTime + 80, 0, BlazeBurnerBlockEntity.MAX_HEAT_CAPACITY); heater.updateBlockState(); heater.notifyUpdate(); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerInteractionBehaviour.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerInteractionBehaviour.java index d6874906b8..31695b900b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerInteractionBehaviour.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.schedule.ScheduleItem; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerMovementBehaviour.java similarity index 84% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerMovementBehaviour.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerMovementBehaviour.java index 2f62d8a09b..e387628b80 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerMovementBehaviour.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import java.util.Random; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; @@ -24,6 +24,7 @@ import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -31,10 +32,15 @@ import net.minecraftforge.api.distmarker.OnlyIn; public class BlazeBurnerMovementBehaviour implements MovementBehaviour { @Override - public boolean renderAsNormalTileEntity() { + public boolean renderAsNormalBlockEntity() { return false; } + @Override + public ItemStack canBeDisabledVia(MovementContext context) { + return null; + } + @Override public void tick(MovementContext context) { if (!context.world.isClientSide()) diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerRenderer.java similarity index 76% rename from src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java rename to src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerRenderer.java index 3c31d46cff..31ac943959 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerRenderer.java +++ b/src/main/java/com/simibubi/create/content/processing/burner/BlazeBurnerRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.processing.burner; +package com.simibubi.create.content.processing.burner; import javax.annotation.Nullable; @@ -6,13 +6,13 @@ import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.AllSpriteShifts; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.render.ContraptionMatrices; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import net.createmod.catnip.render.SpriteShiftEntry; import net.createmod.catnip.render.SuperByteBuffer; @@ -28,25 +28,25 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; -public class BlazeBurnerRenderer extends SafeTileEntityRenderer { +public class BlazeBurnerRenderer extends SafeBlockEntityRenderer { public BlazeBurnerRenderer(BlockEntityRendererProvider.Context context) {} @Override - protected void renderSafe(BlazeBurnerTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource bufferSource, + protected void renderSafe(BlazeBurnerBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource bufferSource, int light, int overlay) { - HeatLevel heatLevel = te.getHeatLevelFromBlock(); + HeatLevel heatLevel = be.getHeatLevelFromBlock(); if (heatLevel == HeatLevel.NONE) return; - Level level = te.getLevel(); - BlockState blockState = te.getBlockState(); - float animation = te.headAnimation.getValue(partialTicks) * .175f; - float horizontalAngle = AngleHelper.rad(te.headAngle.getValue(partialTicks)); + Level level = be.getLevel(); + BlockState blockState = be.getBlockState(); + float animation = be.headAnimation.getValue(partialTicks) * .175f; + float horizontalAngle = AngleHelper.rad(be.headAngle.getValue(partialTicks)); boolean canDrawFlame = heatLevel.isAtLeast(HeatLevel.FADING); - boolean drawGoggles = te.goggles; - boolean drawHat = te.hat; - int hashCode = te.hashCode(); + boolean drawGoggles = be.goggles; + boolean drawHat = be.hat; + int hashCode = be.hashCode(); renderShared(ms, null, bufferSource, level, blockState, heatLevel, animation, horizontalAngle, @@ -66,8 +66,8 @@ public class BlazeBurnerRenderer extends SafeTileEntityRenderer { protected List> sequence; protected int loops; protected ProcessingOutput transitionalItem; - protected List resultPool; + + public final List resultPool; public SequencedAssemblyRecipe(ResourceLocation recipeId, SequencedAssemblyRecipeSerializer serializer) { this.id = recipeId; @@ -55,9 +58,13 @@ public class SequencedAssemblyRecipe implements Recipe { public static > Optional getRecipe(Level world, C inv, RecipeType type, Class recipeClass) { - //return getRecipe(world, inv.getStackInSlot(0), type, recipeClass).filter(r -> r.matches(inv, world)); - return getRecipes(world, inv.getItem(0), type, recipeClass).filter(r -> r.matches(inv, world)) - .findFirst(); + return getRecipe(world, inv, type, recipeClass, r -> r.matches(inv, world)); + } + + public static > Optional getRecipe(Level world, C inv, + RecipeType type, Class recipeClass, Predicate recipeFilter) { + return getRecipes(world, inv.getItem(0), type, recipeClass).filter(recipeFilter) + .findFirst(); } public static > Optional getRecipe(Level world, ItemStack item, @@ -220,29 +227,31 @@ public class SequencedAssemblyRecipe implements Recipe { } @OnlyIn(Dist.CLIENT) - public static void addToTooltip(List toolTip, ItemStack stack) { + public static void addToTooltip(ItemTooltipEvent event) { + ItemStack stack = event.getItemStack(); if (!stack.hasTag() || !stack.getTag() .contains("SequencedAssembly")) return; CompoundTag compound = stack.getTag() .getCompound("SequencedAssembly"); ResourceLocation resourceLocation = new ResourceLocation(compound.getString("id")); - Optional> recipe = Minecraft.getInstance().level.getRecipeManager() + Optional> optionalRecipe = Minecraft.getInstance().level.getRecipeManager() .byKey(resourceLocation); - if (!recipe.isPresent()) + if (!optionalRecipe.isPresent()) return; - Recipe iRecipe = recipe.get(); - if (!(iRecipe instanceof SequencedAssemblyRecipe)) + Recipe recipe = optionalRecipe.get(); + if (!(recipe instanceof SequencedAssemblyRecipe)) return; - SequencedAssemblyRecipe sequencedAssemblyRecipe = (SequencedAssemblyRecipe) iRecipe; + SequencedAssemblyRecipe sequencedAssemblyRecipe = (SequencedAssemblyRecipe) recipe; int length = sequencedAssemblyRecipe.sequence.size(); int step = sequencedAssemblyRecipe.getStep(stack); int total = length * sequencedAssemblyRecipe.loops; - toolTip.add(Components.immutableEmpty()); - toolTip.add(CreateLang.translateDirect("recipe.sequenced_assembly") + List tooltip = event.getToolTip(); + tooltip.add(Components.immutableEmpty()); + tooltip.add(CreateLang.translateDirect("recipe.sequenced_assembly") .withStyle(ChatFormatting.GRAY)); - toolTip.add(CreateLang.translateDirect("recipe.assembly.progress", step, total) + tooltip.add(CreateLang.translateDirect("recipe.assembly.progress", step, total) .withStyle(ChatFormatting.DARK_GRAY)); int remaining = total - step; @@ -253,10 +262,10 @@ public class SequencedAssemblyRecipe implements Recipe { Component textComponent = sequencedRecipe.getAsAssemblyRecipe() .getDescriptionForAssembly(); if (i == 0) - toolTip.add(CreateLang.translateDirect("recipe.assembly.next", textComponent) + tooltip.add(CreateLang.translateDirect("recipe.assembly.next", textComponent) .withStyle(ChatFormatting.AQUA)); else - toolTip.add(Components.literal("-> ").append(textComponent) + tooltip.add(Components.literal("-> ").append(textComponent) .withStyle(ChatFormatting.DARK_AQUA)); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeBuilder.java b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeBuilder.java similarity index 90% rename from src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeBuilder.java rename to src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeBuilder.java index 18924d88a2..6e9745de56 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeBuilder.java +++ b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeBuilder.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.itemAssembly; +package com.simibubi.create.content.processing.sequenced; import java.util.ArrayList; import java.util.List; @@ -8,10 +8,10 @@ import java.util.function.UnaryOperator; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder.ProcessingRecipeFactory; import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeSerializer.java b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeSerializer.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeSerializer.java rename to src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeSerializer.java index 1733661666..69e83f0515 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedAssemblyRecipeSerializer.java +++ b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedAssemblyRecipeSerializer.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.contraptions.itemAssembly; +package com.simibubi.create.content.processing.sequenced; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.simibubi.create.content.contraptions.processing.ProcessingOutput; +import com.simibubi.create.content.processing.recipe.ProcessingOutput; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedRecipe.java b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedRecipe.java similarity index 93% rename from src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedRecipe.java rename to src/main/java/com/simibubi/create/content/processing/sequenced/SequencedRecipe.java index d433b80610..3105e477f8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/itemAssembly/SequencedRecipe.java +++ b/src/main/java/com/simibubi/create/content/processing/sequenced/SequencedRecipe.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.itemAssembly; +package com.simibubi.create.content.processing.sequenced; import com.google.common.collect.ImmutableList; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeSerializer; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/com/simibubi/create/content/redstone/DirectedDirectionalBlock.java b/src/main/java/com/simibubi/create/content/redstone/DirectedDirectionalBlock.java new file mode 100644 index 0000000000..5fb2d1c057 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/DirectedDirectionalBlock.java @@ -0,0 +1,98 @@ +package com.simibubi.create.content.redstone; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.contraptions.ITransformableBlock; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.equipment.wrench.IWrenchable; + +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.level.block.state.properties.EnumProperty; + +public class DirectedDirectionalBlock extends HorizontalDirectionalBlock implements IWrenchable, ITransformableBlock { + + public static final EnumProperty TARGET = EnumProperty.create("target", AttachFace.class); + + public DirectedDirectionalBlock(Properties pProperties) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(TARGET, AttachFace.WALL)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(TARGET, FACING)); + } + + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext pContext) { + for (Direction direction : pContext.getNearestLookingDirections()) { + BlockState blockstate; + if (direction.getAxis() == Direction.Axis.Y) { + blockstate = this.defaultBlockState() + .setValue(TARGET, direction == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR) + .setValue(FACING, pContext.getHorizontalDirection()); + } else { + blockstate = this.defaultBlockState() + .setValue(TARGET, AttachFace.WALL) + .setValue(FACING, direction.getOpposite()); + } + + return blockstate; + } + + return null; + } + + public static Direction getTargetDirection(BlockState pState) { + switch ((AttachFace) pState.getValue(TARGET)) { + case CEILING: + return Direction.UP; + case FLOOR: + return Direction.DOWN; + default: + return pState.getValue(FACING); + } + } + + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + if (targetedFace.getAxis() == Axis.Y) + return IWrenchable.super.getRotatedBlockState(originalState, targetedFace); + + Direction targetDirection = getTargetDirection(originalState); + Direction newFacing = targetDirection.getClockWise(targetedFace.getAxis()); + if (targetedFace.getAxisDirection() == AxisDirection.NEGATIVE) + newFacing = newFacing.getOpposite(); + + if (newFacing.getAxis() == Axis.Y) + return originalState.setValue(TARGET, newFacing == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR); + return originalState.setValue(TARGET, AttachFace.WALL) + .setValue(FACING, newFacing); + } + + @Override + @SuppressWarnings("deprecation") + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) + state = mirror(state, transform.mirror); + if (transform.rotationAxis == Direction.Axis.Y) + return rotate(state, transform.rotation); + + Direction targetDirection = getTargetDirection(state); + Direction newFacing = transform.rotateFacing(targetDirection); + + if (newFacing.getAxis() == Axis.Y) + return state.setValue(TARGET, newFacing == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR); + return state.setValue(TARGET, AttachFace.WALL) + .setValue(FACING, newFacing); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/FilteredDetectorFilterSlot.java b/src/main/java/com/simibubi/create/content/redstone/FilteredDetectorFilterSlot.java new file mode 100644 index 0000000000..0f03de6e97 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/FilteredDetectorFilterSlot.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.redstone; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class FilteredDetectorFilterSlot extends ValueBoxTransform.Sided { + + private boolean hasSlotAtBottom; + + public FilteredDetectorFilterSlot(boolean hasSlotAtBottom) { + this.hasSlotAtBottom = hasSlotAtBottom; + } + + @Override + protected boolean isSideActive(BlockState state, Direction direction) { + Direction targetDirection = DirectedDirectionalBlock.getTargetDirection(state); + if (direction == targetDirection) + return false; + if (targetDirection.getOpposite() == direction) + return true; + + if (targetDirection.getAxis() != Axis.Y) + return direction == Direction.UP || direction == Direction.DOWN && hasSlotAtBottom; + if (targetDirection == Direction.UP) + direction = direction.getOpposite(); + if (!hasSlotAtBottom) + return direction == state.getValue(DirectedDirectionalBlock.FACING); + + return direction.getAxis() == state.getValue(DirectedDirectionalBlock.FACING) + .getClockWise() + .getAxis(); + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + super.rotate(state, ms); + Direction facing = state.getValue(DirectedDirectionalBlock.FACING); + if (facing.getAxis() == Axis.Y) + return; + if (getSide() != Direction.UP) + return; + TransformStack.cast(ms) + .rotateZ(-AngleHelper.horizontalAngle(facing) + 180); + } + + @Override + protected Vec3 getSouthLocation() { + return VecHelper.voxelSpace(8f, 8f, 15.5f); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RoseQuartzLampBlock.java b/src/main/java/com/simibubi/create/content/redstone/RoseQuartzLampBlock.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/RoseQuartzLampBlock.java rename to src/main/java/com/simibubi/create/content/redstone/RoseQuartzLampBlock.java index 340c9c363d..4b2f819222 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RoseQuartzLampBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/RoseQuartzLampBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone; import java.util.HashSet; import java.util.LinkedList; @@ -7,8 +7,8 @@ import java.util.Random; import java.util.Set; import java.util.function.BiConsumer; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.redstone.diodes.BrassDiodeBlock; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverBlock.java b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlock.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverBlock.java rename to src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlock.java index ca7641fff3..7bbe3bd64f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.analogLever; import java.util.Random; import com.mojang.math.Vector3f; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -30,7 +30,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock implements ITE { +public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock implements IBE { public AnalogLeverBlock(Properties p_i48402_1_) { super(p_i48402_1_); @@ -44,10 +44,10 @@ public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock imp return InteractionResult.SUCCESS; } - return onTileEntityUse(worldIn, pos, te -> { + return onBlockEntityUse(worldIn, pos, be -> { boolean sneak = player.isShiftKeyDown(); - te.changeState(sneak); - float f = .25f + ((te.state + 5) / 15f) * .5f; + be.changeState(sneak); + float f = .25f + ((be.state + 5) / 15f) * .5f; worldIn.playSound(null, pos, SoundEvents.LEVER_CLICK, SoundSource.BLOCKS, 0.2F, f); return InteractionResult.SUCCESS; }); @@ -55,7 +55,7 @@ public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock imp @Override public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { - return getTileEntityOptional(blockAccess, pos).map(al -> al.state) + return getBlockEntityOptional(blockAccess, pos).map(al -> al.state) .orElse(0); } @@ -72,8 +72,8 @@ public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock imp @Override @OnlyIn(Dist.CLIENT) public void animateTick(BlockState stateIn, Level worldIn, BlockPos pos, Random rand) { - withTileEntityDo(worldIn, pos, te -> { - if (te.state != 0 && rand.nextFloat() < 0.25F) + withBlockEntityDo(worldIn, pos, be -> { + if (be.state != 0 && rand.nextFloat() < 0.25F) addParticles(stateIn, worldIn, pos, 0.5F); }); } @@ -82,8 +82,8 @@ public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock imp public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (isMoving || state.getBlock() == newState.getBlock()) return; - withTileEntityDo(worldIn, pos, te -> { - if (te.state != 0) + withBlockEntityDo(worldIn, pos, be -> { + if (be.state != 0) updateNeighbors(state, worldIn, pos); worldIn.removeBlockEntity(pos); }); @@ -120,13 +120,13 @@ public class AnalogLeverBlock extends FaceAttachedHorizontalDirectionalBlock imp } @Override - public Class getTileEntityClass() { - return AnalogLeverTileEntity.class; + public Class getBlockEntityClass() { + return AnalogLeverBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.ANALOG_LEVER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.ANALOG_LEVER.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlockEntity.java new file mode 100644 index 0000000000..2374ce0b59 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverBlockEntity.java @@ -0,0 +1,90 @@ +package com.simibubi.create.content.redstone.analogLever; + +import java.util.List; + +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class AnalogLeverBlockEntity extends SmartBlockEntity implements IHaveGoggleInformation { + + int state = 0; + int lastChange; + LerpedFloat clientState; + + public AnalogLeverBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + clientState = LerpedFloat.linear(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("State", state); + compound.putInt("ChangeTimer", lastChange); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + state = compound.getInt("State"); + lastChange = compound.getInt("ChangeTimer"); + clientState.chase(state, 0.2f, Chaser.EXP); + super.read(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + if (lastChange > 0) { + lastChange--; + if (lastChange == 0) + updateOutput(); + } + if (level.isClientSide) + clientState.tickChaser(); + } + + @Override + public void initialize() { + super.initialize(); + + } + + private void updateOutput() { + AnalogLeverBlock.updateNeighbors(getBlockState(), level, worldPosition); + } + + @Override + public void addBehaviours(List behaviours) { + } + + public void changeState(boolean back) { + int prevState = state; + state += back ? -1 : 1; + state = Mth.clamp(state, 0, 15); + if (prevState != state) + lastChange = 15; + sendData(); + } + + @Override + public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) { + tooltip.add(componentSpacing.plainCopy().append(CreateLang.translateDirect("tooltip.analogStrength", this.state))); + + return true; + } + + public int getState() { + return state; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverInstance.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java rename to src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverInstance.java index 3f629a0436..4d0c24907a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverInstance.java +++ b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.analogLever; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; @@ -7,7 +7,7 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.util.transform.Rotate; import com.jozufozu.flywheel.util.transform.Translate; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.math.AngleHelper; @@ -15,7 +15,7 @@ import net.createmod.catnip.utility.theme.Color; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.properties.AttachFace; -public class AnalogLeverInstance extends BlockEntityInstance implements DynamicInstance { +public class AnalogLeverInstance extends BlockEntityInstance implements DynamicInstance { protected final ModelData handle; protected final ModelData indicator; @@ -23,14 +23,14 @@ public class AnalogLeverInstance extends BlockEntityInstance mat = getTransformMaterial(); - handle = mat.getModel(AllBlockPartials.ANALOG_LEVER_HANDLE, blockState) + handle = mat.getModel(AllPartialModels.ANALOG_LEVER_HANDLE, blockState) .createInstance(); - indicator = mat.getModel(AllBlockPartials.ANALOG_LEVER_INDICATOR, blockState) + indicator = mat.getModel(AllPartialModels.ANALOG_LEVER_INDICATOR, blockState) .createInstance(); transform(indicator); diff --git a/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverRenderer.java b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverRenderer.java new file mode 100644 index 0000000000..9f6f0b4fc4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/analogLever/AnalogLeverRenderer.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.redstone.analogLever; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.AttachFace; + +public class AnalogLeverRenderer extends SafeBlockEntityRenderer { + + public AnalogLeverRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(AnalogLeverBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + BlockState leverState = be.getBlockState(); + float state = be.clientState.getValue(partialTicks); + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + // Handle + SuperByteBuffer handle = CachedPartialBuffers.partial(AllPartialModels.ANALOG_LEVER_HANDLE, leverState); + float angle = (float) ((state / 15) * 90 / 180 * Math.PI); + transform(handle, leverState).translate(1 / 2f, 1 / 16f, 1 / 2f) + .rotate(Direction.EAST, angle) + .translate(-1 / 2f, -1 / 16f, -1 / 2f); + handle.light(light) + .renderInto(ms, vb); + + // Indicator + int color = Color.mixColors(0x2C0300, 0xCD0000, state / 15f); + SuperByteBuffer indicator = transform(CachedPartialBuffers.partial(AllPartialModels.ANALOG_LEVER_INDICATOR, leverState), leverState); + indicator.light(light) + .color(color) + .renderInto(ms, vb); + } + + private SuperByteBuffer transform(SuperByteBuffer buffer, BlockState leverState) { + AttachFace face = leverState.getValue(AnalogLeverBlock.FACE); + float rX = face == AttachFace.FLOOR ? 0 : face == AttachFace.WALL ? 90 : 180; + float rY = AngleHelper.horizontalAngle(leverState.getValue(AnalogLeverBlock.FACING)); + buffer.rotateCentered(Direction.UP, (float) (rY / 180 * Math.PI)); + buffer.rotateCentered(Direction.EAST, (float) (rX / 180 * Math.PI)); + return buffer; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/contact/ContactMovementBehaviour.java b/src/main/java/com/simibubi/create/content/redstone/contact/ContactMovementBehaviour.java new file mode 100644 index 0000000000..e4f4bef7b5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/contact/ContactMovementBehaviour.java @@ -0,0 +1,80 @@ +package com.simibubi.create.content.redstone.contact; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.ticks.TickPriority; + +public class ContactMovementBehaviour implements MovementBehaviour { + + @Override + public Vec3 getActiveAreaOffset(MovementContext context) { + return Vec3.atLowerCornerOf(context.state.getValue(RedstoneContactBlock.FACING) + .getNormal()) + .scale(.65f); + } + + @Override + public void visitNewPosition(MovementContext context, BlockPos pos) { + BlockState block = context.state; + Level world = context.world; + + if (world.isClientSide) + return; + if (context.firstMovement) + return; + + deactivateLastVisitedContact(context); + BlockState visitedState = world.getBlockState(pos); + if (!AllBlocks.REDSTONE_CONTACT.has(visitedState) && !AllBlocks.ELEVATOR_CONTACT.has(visitedState)) + return; + + Vec3 contact = Vec3.atLowerCornerOf(block.getValue(RedstoneContactBlock.FACING) + .getNormal()); + contact = context.rotation.apply(contact); + Direction direction = Direction.getNearest(contact.x, contact.y, contact.z); + + if (visitedState.getValue(RedstoneContactBlock.FACING) != direction.getOpposite()) + return; + + if (AllBlocks.REDSTONE_CONTACT.has(visitedState)) + world.setBlockAndUpdate(pos, visitedState.setValue(RedstoneContactBlock.POWERED, true)); + if (AllBlocks.ELEVATOR_CONTACT.has(visitedState) && context.contraption instanceof ElevatorContraption ec) + ec.broadcastFloorData(world, pos); + + context.data.put("lastContact", NbtUtils.writeBlockPos(pos)); + return; + } + + @Override + public void stopMoving(MovementContext context) { + deactivateLastVisitedContact(context); + } + + @Override + public void cancelStall(MovementContext context) { + MovementBehaviour.super.cancelStall(context); + deactivateLastVisitedContact(context); + } + + public void deactivateLastVisitedContact(MovementContext context) { + if (!context.data.contains("lastContact")) + return; + + BlockPos last = NbtUtils.readBlockPos(context.data.getCompound("lastContact")); + context.data.remove("lastContact"); + BlockState blockState = context.world.getBlockState(last); + + if (AllBlocks.REDSTONE_CONTACT.has(blockState)) + context.world.scheduleTick(last, AllBlocks.REDSTONE_CONTACT.get(), 1, TickPriority.NORMAL); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactBlock.java b/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactBlock.java new file mode 100644 index 0000000000..7e81bb8c65 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactBlock.java @@ -0,0 +1,143 @@ +package com.simibubi.create.content.redstone.contact; + +import java.util.Random; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class RedstoneContactBlock extends WrenchableDirectionalBlock { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + public RedstoneContactBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(POWERED, false) + .setValue(FACING, Direction.UP)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + builder.add(POWERED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState state = defaultBlockState().setValue(FACING, context.getNearestLookingDirection() + .getOpposite()); + Direction placeDirection = context.getClickedFace() + .getOpposite(); + + if ((context.getPlayer() != null && context.getPlayer() + .isShiftKeyDown()) || hasValidContact(context.getLevel(), context.getClickedPos(), placeDirection)) + state = state.setValue(FACING, placeDirection); + if (hasValidContact(context.getLevel(), context.getClickedPos(), state.getValue(FACING))) + state = state.setValue(POWERED, true); + + return state; + } + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + InteractionResult onWrenched = super.onWrenched(state, context); + if (onWrenched != InteractionResult.SUCCESS) + return onWrenched; + + Level level = context.getLevel(); + if (level.isClientSide()) + return onWrenched; + + BlockPos pos = context.getClickedPos(); + state = level.getBlockState(pos); + Direction facing = state.getValue(RedstoneContactBlock.FACING); + if (facing.getAxis() == Axis.Y) + return onWrenched; + if (ElevatorColumn.get(level, new ColumnCoords(pos.getX(), pos.getZ(), facing)) == null) + return onWrenched; + + level.setBlockAndUpdate(pos, BlockHelper.copyProperties(state, AllBlocks.ELEVATOR_CONTACT.getDefaultState())); + + return onWrenched; + } + + @Override + public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn, + BlockPos currentPos, BlockPos facingPos) { + if (facing != stateIn.getValue(FACING)) + return stateIn; + boolean hasValidContact = hasValidContact(worldIn, currentPos, facing); + if (stateIn.getValue(POWERED) != hasValidContact) + return stateIn.setValue(POWERED, hasValidContact); + return stateIn; + } + + @SuppressWarnings("deprecation") + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (state.getBlock() == this && newState.getBlock() == this) + if (state == newState.cycle(POWERED)) + worldIn.updateNeighborsAt(pos, this); + super.onRemove(state, worldIn, pos, newState, isMoving); + } + + @Override + public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { + boolean hasValidContact = hasValidContact(worldIn, pos, state.getValue(FACING)); + if (state.getValue(POWERED) != hasValidContact) + worldIn.setBlockAndUpdate(pos, state.setValue(POWERED, hasValidContact)); + } + + public static boolean hasValidContact(LevelAccessor world, BlockPos pos, Direction direction) { + BlockState blockState = world.getBlockState(pos.relative(direction)); + return (AllBlocks.REDSTONE_CONTACT.has(blockState) || AllBlocks.ELEVATOR_CONTACT.has(blockState)) + && blockState.getValue(FACING) == direction.getOpposite(); + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, LevelReader level, BlockPos pos, Direction side) { + return false; + } + + @Override + public boolean isSignalSource(BlockState state) { + return state.getValue(POWERED); + } + + @Override + public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { + return side != null && state.getValue(FACING) != side.getOpposite(); + } + + @Override + public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) { + return state.getValue(POWERED) && side != state.getValue(FACING) + .getOpposite() ? 15 : 0; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactItem.java b/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactItem.java new file mode 100644 index 0000000000..7969b39950 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/contact/RedstoneContactItem.java @@ -0,0 +1,43 @@ +package com.simibubi.create.content.redstone.contact; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn; +import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class RedstoneContactItem extends BlockItem { + + public RedstoneContactItem(Block pBlock, Properties pProperties) { + super(pBlock, pProperties); + } + + @Override + protected BlockState getPlacementState(BlockPlaceContext ctx) { + Level world = ctx.getLevel(); + BlockPos pos = ctx.getClickedPos(); + BlockState state = super.getPlacementState(ctx); + + if (state == null) + return state; + if (!(state.getBlock() instanceof RedstoneContactBlock)) + return state; + Direction facing = state.getValue(RedstoneContactBlock.FACING); + if (facing.getAxis() == Axis.Y) + return state; + + if (ElevatorColumn.get(world, new ColumnCoords(pos.getX(), pos.getZ(), facing)) == null) + return state; + + return BlockHelper.copyProperties(state, AllBlocks.ELEVATOR_CONTACT.getDefaultState()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeBlock.java b/src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeBlock.java new file mode 100644 index 0000000000..2c16bb1d9e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeBlock.java @@ -0,0 +1,18 @@ +package com.simibubi.create.content.redstone.diodes; + +import com.simibubi.create.content.equipment.wrench.IWrenchable; + +import net.minecraft.world.level.block.DiodeBlock; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class AbstractDiodeBlock extends DiodeBlock implements IWrenchable { + + public AbstractDiodeBlock(Properties builder) { + super(builder); + } + + @Override + public boolean isSignalSource(BlockState state) { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeGenerator.java b/src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeGenerator.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeGenerator.java index 89a74d08fc..e5abcfb3cb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AbstractDiodeGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/AbstractDiodeGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Vector; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeBlock.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeBlock.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlock.java index be5b927d81..c80c6a4a97 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlock.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -21,7 +21,7 @@ import net.minecraft.world.level.block.state.StateDefinition.Builder; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.phys.BlockHitResult; -public class BrassDiodeBlock extends AbstractDiodeBlock implements ITE { +public class BrassDiodeBlock extends AbstractDiodeBlock implements IBE { public static final BooleanProperty POWERING = BooleanProperty.create("powering"); public static final BooleanProperty INVERTED = BooleanProperty.create("inverted"); @@ -36,6 +36,11 @@ public class BrassDiodeBlock extends AbstractDiodeBlock implements ITE getTileEntityClass() { - return BrassDiodeTileEntity.class; + public Class getBlockEntityClass() { + return BrassDiodeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllBlocks.PULSE_EXTENDER.is(this) ? AllTileEntities.PULSE_EXTENDER.get() - : AllTileEntities.PULSE_REPEATER.get(); + public BlockEntityType getBlockEntityType() { + return AllBlocks.PULSE_EXTENDER.is(this) ? AllBlockEntityTypes.PULSE_EXTENDER.get() + : AllBlockEntityTypes.PULSE_REPEATER.get(); } } diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlockEntity.java new file mode 100644 index 0000000000..e3e09625b0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeBlockEntity.java @@ -0,0 +1,111 @@ +package com.simibubi.create.content.redstone.diodes; + +import static com.simibubi.create.content.redstone.diodes.BrassDiodeBlock.POWERING; + +import java.util.List; + +import com.simibubi.create.content.equipment.clipboard.ClipboardCloneable; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.DiodeBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class BrassDiodeBlockEntity extends SmartBlockEntity implements ClipboardCloneable { + + protected int state; + ScrollValueBehaviour maxState; + + public BrassDiodeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + maxState = new BrassDiodeScrollValueBehaviour(CreateLang.translateDirect("logistics.redstone_interval"), this, + new BrassDiodeScrollSlot()).between(2, 60 * 20 * 60); + maxState.withFormatter(this::format); + maxState.withCallback(this::onMaxDelayChanged); + maxState.setValue(2); + behaviours.add(maxState); + } + + public float getProgress() { + int max = Math.max(2, maxState.getValue()); + return Mth.clamp(state, 0, max) / (float) max; + } + + public boolean isIdle() { + return state == 0; + } + + @Override + public void tick() { + super.tick(); + boolean powered = getBlockState().getValue(DiodeBlock.POWERED); + boolean powering = getBlockState().getValue(POWERING); + boolean atMax = state >= maxState.getValue(); + boolean atMin = state <= 0; + updateState(powered, powering, atMax, atMin); + } + + protected abstract void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin); + + private void onMaxDelayChanged(int newMax) { + state = Mth.clamp(state, 0, newMax); + sendData(); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + state = compound.getInt("State"); + super.read(compound, clientPacket); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("State", state); + super.write(compound, clientPacket); + } + + private String format(int value) { + if (value < 60) + return value + "t"; + if (value < 20 * 60) + return (value / 20) + "s"; + return (value / 20 / 60) + "m"; + } + + @Override + public String getClipboardKey() { + return "Block"; + } + + @Override + public boolean readFromClipboard(CompoundTag tag, Player player, Direction side, boolean simulate) { + if (!tag.contains("Inverted")) + return false; + if (simulate) + return true; + BlockState blockState = getBlockState(); + if (blockState.getValue(BrassDiodeBlock.INVERTED) != tag.getBoolean("Inverted")) + level.setBlockAndUpdate(worldPosition, blockState.cycle(BrassDiodeBlock.INVERTED)); + return true; + } + + @Override + public boolean writeToClipboard(CompoundTag tag, Direction side) { + tag.putBoolean("Inverted", getBlockState().getOptionalValue(BrassDiodeBlock.INVERTED) + .orElse(false)); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeGenerator.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeGenerator.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeGenerator.java index a1ee768594..dc3055f4cf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/BrassDiodeGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Vector; diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeInstance.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeInstance.java new file mode 100644 index 0000000000..59715ec968 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeInstance.java @@ -0,0 +1,54 @@ +package com.simibubi.create.content.redstone.diodes; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.TickableInstance; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.simibubi.create.AllPartialModels; + +import net.createmod.catnip.utility.theme.Color; + +public class BrassDiodeInstance extends BlockEntityInstance implements TickableInstance { + + protected final ModelData indicator; + + protected int previousState; + + public BrassDiodeInstance(MaterialManager materialManager, BrassDiodeBlockEntity blockEntity) { + super(materialManager, blockEntity); + + indicator = materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(AllPartialModels.FLEXPEATER_INDICATOR, blockState).createInstance(); + + indicator.loadIdentity() + .translate(getInstancePosition()) + .setColor(getColor()); + + previousState = blockEntity.state; + } + + @Override + public void tick() { + if (previousState == blockEntity.state) return; + + indicator.setColor(getColor()); + + previousState = blockEntity.state; + } + + @Override + public void updateLight() { + relight(pos, indicator); + } + + @Override + public void remove() { + indicator.delete(); + } + + protected int getColor() { + return Color.mixColors(0x2c0300, 0xcd0000, blockEntity.getProgress()); + } +} diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeRenderer.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeRenderer.java new file mode 100644 index 0000000000..d9356c0593 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeRenderer.java @@ -0,0 +1,27 @@ +package com.simibubi.create.content.redstone.diodes; + +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.ColoredOverlayBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; + +public class BrassDiodeRenderer extends ColoredOverlayBlockEntityRenderer { + + public BrassDiodeRenderer(BlockEntityRendererProvider.Context context) { + super(context); + } + + @Override + protected int getColor(BrassDiodeBlockEntity be, float partialTicks) { + return Color.mixColors(0x2C0300, 0xCD0000, be.getProgress()); + } + + @Override + protected SuperByteBuffer getOverlayBuffer(BrassDiodeBlockEntity be) { + return CachedPartialBuffers.partial(AllPartialModels.FLEXPEATER_INDICATOR, be.getBlockState()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollSlot.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollSlot.java new file mode 100644 index 0000000000..b3d0ae0ebd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollSlot.java @@ -0,0 +1,33 @@ +package com.simibubi.create.content.redstone.diodes; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.phys.Vec3; + +public class BrassDiodeScrollSlot extends ValueBoxTransform { + + @Override + public Vec3 getLocalOffset(BlockState state) { + return VecHelper.voxelSpace(8, 2.6f, 8); + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + float yRot = AngleHelper.horizontalAngle(state.getValue(BlockStateProperties.HORIZONTAL_FACING)) + 180; + TransformStack.cast(ms) + .rotateY(yRot) + .rotateX(90); + } + + @Override + public int getOverrideColor() { + return 0x592424; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollValueBehaviour.java b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollValueBehaviour.java new file mode 100644 index 0000000000..c48921e333 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/BrassDiodeScrollValueBehaviour.java @@ -0,0 +1,82 @@ +package com.simibubi.create.content.redstone.diodes; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public class BrassDiodeScrollValueBehaviour extends ScrollValueBehaviour { + + public BrassDiodeScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot) { + super(label, be, slot); + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + return new ValueSettingsBoard(label, 60, 10, + CreateLang.translatedOptions("generic.unit", "ticks", "seconds", "minutes"), + new ValueSettingsFormatter(this::formatSettings)); + } + + @Override + public void onShortInteract(Player player, InteractionHand hand, Direction side) { + BlockState blockState = blockEntity.getBlockState(); + if (blockState.getBlock()instanceof BrassDiodeBlock bdb) + bdb.toggle(getWorld(), getPos(), blockState, player, hand); + } + + @Override + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlHeld) { + int value = valueSetting.value(); + int multiplier = switch (valueSetting.row()) { + case 0 -> 1; + case 1 -> 20; + default -> 60 * 20; + }; + if (!valueSetting.equals(getValueSettings())) + playFeedbackSound(this); + setValue(Math.max(2, Math.max(1, value) * multiplier)); + } + + @Override + public ValueSettings getValueSettings() { + int row = 0; + int value = this.value; + + if (value > 60 * 20) { + value = value / (60 * 20); + row = 2; + } else if (value > 60) { + value = value / 20; + row = 1; + } + + return new ValueSettings(row, value); + } + + public MutableComponent formatSettings(ValueSettings settings) { + int value = Math.max(1, settings.value()); + return Components.literal(switch (settings.row()) { + case 0 -> Math.max(2, value) + "t"; + case 1 -> "0:" + (value < 10 ? "0" : "") + value; + default -> value + ":00"; + }); + } + + @Override + public String getClipboardKey() { + return "Timings"; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchBlock.java b/src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchBlock.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchBlock.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchBlock.java index 60119b98ab..f235412fe7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Random; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchGenerator.java b/src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchGenerator.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchGenerator.java index 290df75171..5928f3649c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/PoweredLatchGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/PoweredLatchGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Vector; diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/PulseExtenderBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/diodes/PulseExtenderBlockEntity.java new file mode 100644 index 0000000000..23dc3cf74c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/PulseExtenderBlockEntity.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.redstone.diodes; + +import static com.simibubi.create.content.redstone.diodes.BrassDiodeBlock.POWERING; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class PulseExtenderBlockEntity extends BrassDiodeBlockEntity { + + public PulseExtenderBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin) { + if (atMin && !powered) + return; + if (atMin || powered) { + level.setBlockAndUpdate(worldPosition, getBlockState().setValue(POWERING, true)); + state = maxState.getValue(); + return; + } + + if (state == 1) { + if (powering && !level.isClientSide) + level.setBlockAndUpdate(worldPosition, getBlockState().setValue(POWERING, false)); + if (!powered) + state = 0; + return; + } + + if (!powered) + state--; + } +} diff --git a/src/main/java/com/simibubi/create/content/redstone/diodes/PulseRepeaterBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/diodes/PulseRepeaterBlockEntity.java new file mode 100644 index 0000000000..76e9dc0040 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/PulseRepeaterBlockEntity.java @@ -0,0 +1,35 @@ +package com.simibubi.create.content.redstone.diodes; + +import static com.simibubi.create.content.redstone.diodes.BrassDiodeBlock.POWERING; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class PulseRepeaterBlockEntity extends BrassDiodeBlockEntity { + + public PulseRepeaterBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + protected void updateState(boolean powered, boolean powering, boolean atMax, boolean atMin) { + if (atMin && !powered) + return; + if (state > maxState.getValue() + 1) { + if (!powered && !powering) + state = 0; + return; + } + + state++; + if (level.isClientSide) + return; + + if (state == maxState.getValue() - 1 && !powering) + level.setBlockAndUpdate(worldPosition, getBlockState().cycle(POWERING)); + if (state == maxState.getValue() + 1 && powering) + level.setBlockAndUpdate(worldPosition, getBlockState().cycle(POWERING)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchBlock.java b/src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchBlock.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchBlock.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchBlock.java index 4dc408e765..9eedc9e434 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Random; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchGenerator.java b/src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchGenerator.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchGenerator.java index 9e09e32fd1..c98d3a51a7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/ToggleLatchGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/diodes/ToggleLatchGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.diodes; +package com.simibubi.create.content.redstone.diodes; import java.util.Vector; diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/AllDisplayBehaviours.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/AllDisplayBehaviours.java new file mode 100644 index 0000000000..86e4f502d6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/AllDisplayBehaviours.java @@ -0,0 +1,246 @@ +package com.simibubi.create.content.redstone.displayLink; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.simibubi.create.Create; +import com.simibubi.create.compat.Mods; +import com.simibubi.create.content.redstone.displayLink.source.ComputerDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.DeathCounterDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.EnchantPowerDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.RedstonePowerDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.ScoreboardDisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; +import com.simibubi.create.content.redstone.displayLink.target.LecternDisplayTarget; +import com.simibubi.create.content.redstone.displayLink.target.SignDisplayTarget; +import com.simibubi.create.foundation.utility.AttachedRegistry; +import com.tterrag.registrate.util.nullness.NonNullConsumer; + +import net.createmod.catnip.platform.CatnipServices; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.registries.ForgeRegistries; + +public class AllDisplayBehaviours { + public static final Map GATHERER_BEHAVIOURS = new HashMap<>(); + + private static final AttachedRegistry> SOURCES_BY_BLOCK = new AttachedRegistry<>(ForgeRegistries.BLOCKS); + private static final AttachedRegistry, List> SOURCES_BY_BLOCK_ENTITY = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITIES); + + private static final AttachedRegistry TARGETS_BY_BLOCK = new AttachedRegistry<>(ForgeRegistries.BLOCKS); + private static final AttachedRegistry, DisplayTarget> TARGETS_BY_BLOCK_ENTITY = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITIES); + + public static DisplayBehaviour register(ResourceLocation id, DisplayBehaviour behaviour) { + behaviour.id = id; + GATHERER_BEHAVIOURS.put(id, behaviour); + return behaviour; + } + + public static void assignBlock(DisplayBehaviour behaviour, ResourceLocation block) { + if (behaviour instanceof DisplaySource source) { + List sources = SOURCES_BY_BLOCK.get(block); + if (sources == null) { + sources = new ArrayList<>(); + SOURCES_BY_BLOCK.register(block, sources); + } + sources.add(source); + } + if (behaviour instanceof DisplayTarget target) { + TARGETS_BY_BLOCK.register(block, target); + } + } + + public static void assignBlockEntity(DisplayBehaviour behaviour, ResourceLocation beType) { + if (behaviour instanceof DisplaySource source) { + List sources = SOURCES_BY_BLOCK_ENTITY.get(beType); + if (sources == null) { + sources = new ArrayList<>(); + SOURCES_BY_BLOCK_ENTITY.register(beType, sources); + } + sources.add(source); + } + if (behaviour instanceof DisplayTarget target) { + TARGETS_BY_BLOCK_ENTITY.register(beType, target); + } + } + + public static void assignBlock(DisplayBehaviour behaviour, Block block) { + if (behaviour instanceof DisplaySource source) { + List sources = SOURCES_BY_BLOCK.get(block); + if (sources == null) { + sources = new ArrayList<>(); + SOURCES_BY_BLOCK.register(block, sources); + } + sources.add(source); + } + if (behaviour instanceof DisplayTarget target) { + TARGETS_BY_BLOCK.register(block, target); + } + } + + public static void assignBlockEntity(DisplayBehaviour behaviour, BlockEntityType beType) { + if (behaviour instanceof DisplaySource source) { + List sources = SOURCES_BY_BLOCK_ENTITY.get(beType); + if (sources == null) { + sources = new ArrayList<>(); + SOURCES_BY_BLOCK_ENTITY.register(beType, sources); + } + sources.add(source); + } + if (behaviour instanceof DisplayTarget target) { + TARGETS_BY_BLOCK_ENTITY.register(beType, target); + } + } + + public static NonNullConsumer assignDataBehaviour(DisplayBehaviour behaviour, + String... suffix) { + return b -> { + ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(b); + String idSuffix = behaviour instanceof DisplaySource ? "_source" : "_target"; + if (suffix.length > 0) + idSuffix += "_" + suffix[0]; + assignBlock(register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), + behaviour), registryName); + }; + } + + public static > NonNullConsumer assignDataBehaviourBE( + DisplayBehaviour behaviour, String... suffix) { + return b -> { + ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(b); + String idSuffix = behaviour instanceof DisplaySource ? "_source" : "_target"; + if (suffix.length > 0) + idSuffix += "_" + suffix[0]; + assignBlockEntity( + register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), + behaviour), + registryName); + }; + } + + // + + @Nullable + public static DisplaySource getSource(ResourceLocation resourceLocation) { + DisplayBehaviour available = GATHERER_BEHAVIOURS.getOrDefault(resourceLocation, null); + if (available instanceof DisplaySource source) + return source; + return null; + } + + @Nullable + public static DisplayTarget getTarget(ResourceLocation resourceLocation) { + DisplayBehaviour available = GATHERER_BEHAVIOURS.getOrDefault(resourceLocation, null); + if (available instanceof DisplayTarget target) + return target; + return null; + } + + // + + public static List sourcesOf(Block block) { + List sources = SOURCES_BY_BLOCK.get(block); + if (sources == null) { + return Collections.emptyList(); + } + return sources; + } + + public static List sourcesOf(BlockState state) { + return sourcesOf(state.getBlock()); + } + + public static List sourcesOf(BlockEntityType blockEntityType) { + List sources = SOURCES_BY_BLOCK_ENTITY.get(blockEntityType); + if (sources == null) { + return Collections.emptyList(); + } + return sources; + } + + public static List sourcesOf(BlockEntity blockEntity) { + return sourcesOf(blockEntity.getType()); + } + + @Nullable + public static DisplayTarget targetOf(Block block) { + return TARGETS_BY_BLOCK.get(block); + } + + @Nullable + public static DisplayTarget targetOf(BlockState state) { + return targetOf(state.getBlock()); + } + + @Nullable + public static DisplayTarget targetOf(BlockEntityType blockEntityType) { + return TARGETS_BY_BLOCK_ENTITY.get(blockEntityType); + } + + @Nullable + public static DisplayTarget targetOf(BlockEntity blockEntity) { + return targetOf(blockEntity.getType()); + } + + public static List sourcesOf(LevelAccessor level, BlockPos pos) { + BlockState blockState = level.getBlockState(pos); + BlockEntity blockEntity = level.getBlockEntity(pos); + + List sourcesOfBlock = sourcesOf(blockState); + List sourcesOfBlockEntity = blockEntity == null ? Collections.emptyList() : sourcesOf(blockEntity); + + if (sourcesOfBlockEntity.isEmpty()) + return sourcesOfBlock; + return sourcesOfBlockEntity; + } + + @Nullable + public static DisplayTarget targetOf(LevelAccessor level, BlockPos pos) { + BlockState blockState = level.getBlockState(pos); + BlockEntity blockEntity = level.getBlockEntity(pos); + + DisplayTarget targetOfBlock = targetOf(blockState); + DisplayTarget targetOfBlockEntity = blockEntity == null ? null : targetOf(blockEntity); + + // Commonly added by mods, but with a non-vanilla blockentitytype + if (targetOfBlockEntity == null && blockEntity instanceof SignBlockEntity) + targetOfBlockEntity = targetOf(BlockEntityType.SIGN); + + if (targetOfBlockEntity == null) + return targetOfBlock; + return targetOfBlockEntity; + } + + // + + public static void registerDefaults() { + assignBlockEntity(register(Create.asResource("sign_display_target"), new SignDisplayTarget()), BlockEntityType.SIGN); + assignBlockEntity(register(Create.asResource("lectern_display_target"), new LecternDisplayTarget()), BlockEntityType.LECTERN); + assignBlock(register(Create.asResource("death_count_display_source"), new DeathCounterDisplaySource()), Blocks.RESPAWN_ANCHOR); + assignBlockEntity(register(Create.asResource("scoreboard_display_source"), new ScoreboardDisplaySource()), BlockEntityType.COMMAND_BLOCK); + assignBlockEntity(register(Create.asResource("enchant_power_display_source"), new EnchantPowerDisplaySource()), BlockEntityType.ENCHANTING_TABLE); + assignBlock(register(Create.asResource("redstone_power_display_source"), new RedstonePowerDisplaySource()), Blocks.TARGET); + + Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { + DisplayBehaviour computerDisplaySource = register(Create.asResource("computer_display_source"), new ComputerDisplaySource()); + + assignBlockEntity(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "wired_modem_full")); + assignBlockEntity(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_normal")); + assignBlockEntity(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_advanced")); + assignBlockEntity(computerDisplaySource, new ResourceLocation(Mods.COMPUTERCRAFT.asId(), "computer_command")); + }); + } +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayBehaviour.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayBehaviour.java new file mode 100644 index 0000000000..7c067394d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayBehaviour.java @@ -0,0 +1,9 @@ +package com.simibubi.create.content.redstone.displayLink; + +import net.minecraft.resources.ResourceLocation; + +public abstract class DisplayBehaviour { + + public ResourceLocation id; + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlock.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlock.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlock.java index 78323e27f5..b43e4ce4b7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlock.java @@ -1,15 +1,15 @@ -package com.simibubi.create.content.logistics.block.display; +package com.simibubi.create.content.redstone.displayLink; import java.util.function.BiConsumer; import java.util.function.Consumer; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.content.logistics.block.display.source.RedstonePowerDisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.RedstonePowerDisplaySource; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import com.simibubi.create.foundation.utility.CreateLang; @@ -42,7 +42,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE { +public class DisplayLinkBlock extends WrenchableDirectionalBlock implements IBE { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -65,12 +65,12 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< } public static void notifyGatherers(LevelAccessor level, BlockPos pos) { - forEachAttachedGatherer(level, pos, DisplayLinkTileEntity::updateGatheredData); + forEachAttachedGatherer(level, pos, DisplayLinkBlockEntity::updateGatheredData); } @SuppressWarnings("unchecked") public static void sendToGatherers(LevelAccessor level, BlockPos pos, - BiConsumer callback, Class type) { + BiConsumer callback, Class type) { forEachAttachedGatherer(level, pos, dgte -> { if (type.isInstance(dgte.activeSource)) callback.accept(dgte, (T) dgte.activeSource); @@ -78,7 +78,7 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< } private static void forEachAttachedGatherer(LevelAccessor level, BlockPos pos, - Consumer callback) { + Consumer callback) { for (Direction d : Iterate.directions) { BlockPos offsetPos = pos.relative(d); BlockState blockState = level.getBlockState(offsetPos); @@ -86,14 +86,14 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< continue; BlockEntity blockEntity = level.getBlockEntity(offsetPos); - if (!(blockEntity instanceof DisplayLinkTileEntity dgte)) + if (!(blockEntity instanceof DisplayLinkBlockEntity dlbe)) continue; - if (dgte.activeSource == null) + if (dlbe.activeSource == null) continue; - if (dgte.getDirection() != d.getOpposite()) + if (dlbe.getDirection() != d.getOpposite()) continue; - callback.accept(dgte); + callback.accept(dlbe); } } @@ -112,7 +112,7 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< if (previouslyPowered != powered) { worldIn.setBlock(pos, state.cycle(POWERED), 2); if (!powered) - withTileEntityDo(worldIn, pos, DisplayLinkTileEntity::onNoLongerPowered); + withBlockEntityDo(worldIn, pos, DisplayLinkBlockEntity::onNoLongerPowered); } } @@ -142,19 +142,19 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< if (pPlayer.isSteppingCarefully()) return InteractionResult.PASS; DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> withTileEntityDo(pLevel, pPos, te -> this.displayScreen(te, pPlayer))); + () -> () -> withBlockEntityDo(pLevel, pPos, be -> this.displayScreen(be, pPlayer))); return InteractionResult.SUCCESS; } @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(DisplayLinkTileEntity te, Player player) { + protected void displayScreen(DisplayLinkBlockEntity be, Player player) { if (!(player instanceof LocalPlayer)) return; - if (te.targetOffset.equals(BlockPos.ZERO)) { + if (be.targetOffset.equals(BlockPos.ZERO)) { player.displayClientMessage(CreateLang.translateDirect("display_link.invalid"), true); return; } - ScreenOpener.open(new DisplayLinkScreen(te)); + ScreenOpener.open(new DisplayLinkScreen(be)); } @Override @@ -168,13 +168,13 @@ public class DisplayLinkBlock extends WrenchableDirectionalBlock implements ITE< } @Override - public Class getTileEntityClass() { - return DisplayLinkTileEntity.class; + public Class getBlockEntityClass() { + return DisplayLinkBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.DISPLAY_LINK.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.DISPLAY_LINK.get(); } } diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockEntity.java new file mode 100644 index 0000000000..e8c6e1cf03 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockEntity.java @@ -0,0 +1,226 @@ +package com.simibubi.create.content.redstone.displayLink; + +import java.util.List; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public class DisplayLinkBlockEntity extends SmartBlockEntity { + + protected BlockPos targetOffset; + + public DisplaySource activeSource; + private CompoundTag sourceConfig; + + public DisplayTarget activeTarget; + public int targetLine; + + public LerpedFloat glow; + private boolean sendPulse; + + public int refreshTicks; + public AbstractComputerBehaviour computerBehaviour; + + public DisplayLinkBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + targetOffset = BlockPos.ZERO; + sourceConfig = new CompoundTag(); + targetLine = 0; + glow = LerpedFloat.linear() + .startWithValue(0); + glow.chase(0, 0.5f, Chaser.EXP); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + registerAwardables(behaviours, AllAdvancements.DISPLAY_LINK, AllAdvancements.DISPLAY_BOARD); + } + + @Override + public void tick() { + super.tick(); + + if (isVirtual()) { + glow.tickChaser(); + return; + } + + if (activeSource == null) + return; + if (level.isClientSide) { + glow.tickChaser(); + return; + } + + refreshTicks++; + if (refreshTicks < activeSource.getPassiveRefreshTicks() || !activeSource.shouldPassiveReset()) + return; + tickSource(); + } + + public void tickSource() { + refreshTicks = 0; + if (getBlockState().getOptionalValue(DisplayLinkBlock.POWERED) + .orElse(true)) + return; + if (!level.isClientSide) + updateGatheredData(); + } + + public void onNoLongerPowered() { + if (activeSource == null) + return; + refreshTicks = 0; + activeSource.onSignalReset(new DisplayLinkContext(level, this)); + updateGatheredData(); + } + + public void updateGatheredData() { + BlockPos sourcePosition = getSourcePosition(); + BlockPos targetPosition = getTargetPosition(); + + if (!level.isLoaded(targetPosition) || !level.isLoaded(sourcePosition)) + return; + + DisplayTarget target = AllDisplayBehaviours.targetOf(level, targetPosition); + List sources = AllDisplayBehaviours.sourcesOf(level, sourcePosition); + boolean notify = false; + + if (activeTarget != target) { + activeTarget = target; + notify = true; + } + + if (activeSource != null && !sources.contains(activeSource)) { + activeSource = null; + sourceConfig = new CompoundTag(); + notify = true; + } + + if (notify) + notifyUpdate(); + if (activeSource == null || activeTarget == null) + return; + + DisplayLinkContext context = new DisplayLinkContext(level, this); + activeSource.transferData(context, activeTarget, targetLine); + sendPulse = true; + sendData(); + + award(AllAdvancements.DISPLAY_LINK); + } + + @Override + public void writeSafe(CompoundTag tag) { + super.writeSafe(tag); + writeGatheredData(tag); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + writeGatheredData(tag); + if (clientPacket && activeTarget != null) + tag.putString("TargetType", activeTarget.id.toString()); + if (clientPacket && sendPulse) { + sendPulse = false; + NBTHelper.putMarker(tag, "Pulse"); + } + } + + private void writeGatheredData(CompoundTag tag) { + tag.put("TargetOffset", NbtUtils.writeBlockPos(targetOffset)); + tag.putInt("TargetLine", targetLine); + + if (activeSource != null) { + CompoundTag data = sourceConfig.copy(); + data.putString("Id", activeSource.id.toString()); + tag.put("Source", data); + } + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + targetOffset = NbtUtils.readBlockPos(tag.getCompound("TargetOffset")); + targetLine = tag.getInt("TargetLine"); + + if (clientPacket && tag.contains("TargetType")) + activeTarget = AllDisplayBehaviours.getTarget(new ResourceLocation(tag.getString("TargetType"))); + if (clientPacket && tag.contains("Pulse")) + glow.setValue(2); + + if (!tag.contains("Source")) + return; + + CompoundTag data = tag.getCompound("Source"); + activeSource = AllDisplayBehaviours.getSource(new ResourceLocation(data.getString("Id"))); + sourceConfig = new CompoundTag(); + if (activeSource != null) + sourceConfig = data.copy(); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + + public void target(BlockPos targetPosition) { + this.targetOffset = targetPosition.subtract(worldPosition); + } + + public BlockPos getSourcePosition() { + return worldPosition.relative(getDirection()); + } + + public CompoundTag getSourceConfig() { + return sourceConfig; + } + + public void setSourceConfig(CompoundTag sourceConfig) { + this.sourceConfig = sourceConfig; + } + + public Direction getDirection() { + return getBlockState().getOptionalValue(DisplayLinkBlock.FACING) + .orElse(Direction.UP) + .getOpposite(); + } + + public BlockPos getTargetPosition() { + return worldPosition.offset(targetOffset); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlockItem.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlockItem.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockItem.java index 134bc941b6..5592d48fae 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkBlockItem.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkBlockItem.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.display; +package com.simibubi.create.content.redstone.displayLink; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.CatnipClient; import net.minecraft.ChatFormatting; @@ -82,7 +82,7 @@ public class DisplayLinkBlockItem extends BlockItem { BlockPos placedPos = pos.relative(pContext.getClickedFace(), state.getMaterial() .isReplaceable() ? 0 : 1); - if (!selectedPos.closerThan(placedPos, AllConfigs.SERVER.logistics.displayLinkRange.get())) { + if (!selectedPos.closerThan(placedPos, AllConfigs.server().logistics.displayLinkRange.get())) { player.displayClientMessage(CreateLang.translateDirect("display_link.too_far") .withStyle(ChatFormatting.RED), true); return InteractionResult.FAIL; diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkConfigurationPacket.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkConfigurationPacket.java new file mode 100644 index 0000000000..70fbba6a63 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkConfigurationPacket.java @@ -0,0 +1,66 @@ +package com.simibubi.create.content.redstone.displayLink; + +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; + +public class DisplayLinkConfigurationPacket extends BlockEntityConfigurationPacket { + + private CompoundTag configData; + private int targetLine; + + public DisplayLinkConfigurationPacket(BlockPos pos, CompoundTag configData, int targetLine) { + super(pos); + this.configData = configData; + this.targetLine = targetLine; + } + + public DisplayLinkConfigurationPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeNbt(configData); + buffer.writeInt(targetLine); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + configData = buffer.readNbt(); + targetLine = buffer.readInt(); + } + + @Override + protected void applySettings(DisplayLinkBlockEntity be) { + be.targetLine = targetLine; + + if (!configData.contains("Id")) { + be.notifyUpdate(); + return; + } + + ResourceLocation id = new ResourceLocation(configData.getString("Id")); + DisplaySource source = AllDisplayBehaviours.getSource(id); + if (source == null) { + be.notifyUpdate(); + return; + } + + if (be.activeSource == null || be.activeSource != source) { + be.activeSource = source; + be.setSourceConfig(configData.copy()); + } else { + be.getSourceConfig() + .merge(configData); + } + + be.updateGatheredData(); + be.notifyUpdate(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkContext.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkContext.java new file mode 100644 index 0000000000..0bbebc50da --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkContext.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.redstone.displayLink; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class DisplayLinkContext { + + private Level level; + private DisplayLinkBlockEntity blockEntity; + + public Object flapDisplayContext; + + public DisplayLinkContext(Level level, DisplayLinkBlockEntity blockEntity) { + this.level = level; + this.blockEntity = blockEntity; + } + + public Level level() { + return level; + } + + public DisplayLinkBlockEntity blockEntity() { + return blockEntity; + } + + public BlockEntity getSourceBlockEntity() { + return level.getBlockEntity(getSourcePos()); + } + + public BlockPos getSourcePos() { + return blockEntity.getSourcePosition(); + } + + public BlockEntity getTargetBlockEntity() { + return level.getBlockEntity(getTargetPos()); + } + + public BlockPos getTargetPos() { + return blockEntity.getTargetPosition(); + } + + public CompoundTag sourceConfig() { + return blockEntity.getSourceConfig(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkRenderer.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkRenderer.java new file mode 100644 index 0000000000..41b23a6b5d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkRenderer.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.redstone.displayLink; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; +import com.simibubi.create.foundation.render.RenderTypes; + +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; + +public class DisplayLinkRenderer extends SafeBlockEntityRenderer { + + public DisplayLinkRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(DisplayLinkBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + float glow = be.glow.getValue(partialTicks); + if (glow < .125f) + return; + + glow = (float) (1 - (2 * Math.pow(glow - .75f, 2))); + glow = Mth.clamp(glow, -1, 1); + + int color = (int) (200 * glow); + + BlockState blockState = be.getBlockState(); + TransformStack msr = TransformStack.cast(ms); + + Direction face = blockState.getOptionalValue(DisplayLinkBlock.FACING) + .orElse(Direction.UP); + + if (face.getAxis() + .isHorizontal()) + face = face.getOpposite(); + + ms.pushPose(); + + msr.centre() + .rotateY(AngleHelper.horizontalAngle(face)) + .rotateX(-AngleHelper.verticalAngle(face) - 90) + .unCentre(); + + CachedPartialBuffers.partial(AllPartialModels.DISPLAY_LINK_TUBE, blockState) + .light(LightTexture.FULL_BRIGHT) + .renderInto(ms, buffer.getBuffer(RenderType.translucent())); + + CachedPartialBuffers.partial(AllPartialModels.DISPLAY_LINK_GLOW, blockState) + .light(LightTexture.FULL_BRIGHT) + .color(color, color, color, 255) + .disableDiffuse() + .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); + + ms.popPose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkScreen.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkScreen.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkScreen.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkScreen.java index a05ecf2ce7..8fd8af775e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/DisplayLinkScreen.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/DisplayLinkScreen.java @@ -1,14 +1,15 @@ -package com.simibubi.create.content.logistics.block.display; +package com.simibubi.create.content.redstone.displayLink; import java.util.Collections; import java.util.List; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.block.display.source.DisplaySource; -import com.simibubi.create.content.logistics.block.display.source.SingleLineDisplaySource; -import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.SingleLineDisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.ModularGuiLine; @@ -17,9 +18,8 @@ import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.ScrollInput; import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.ponder.CreatePonderTag; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.ponder.AllPonderTags; import net.createmod.catnip.gui.AbstractSimiScreen; import net.createmod.catnip.gui.ScreenOpener; @@ -47,7 +47,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { private static final ItemStack FALLBACK = new ItemStack(Items.BARRIER); private AllGuiTextures background; - private DisplayLinkTileEntity te; + private DisplayLinkBlockEntity blockEntity; private IconButton confirmButton; BlockState sourceState; @@ -64,9 +64,9 @@ public class DisplayLinkScreen extends AbstractSimiScreen { Couple configWidgets; - public DisplayLinkScreen(DisplayLinkTileEntity te) { + public DisplayLinkScreen(DisplayLinkBlockEntity be) { this.background = AllGuiTextures.DATA_GATHERER; - this.te = te; + this.blockEntity = be; sources = Collections.emptyList(); configWidgets = Couple.create(ModularGuiLine::new); target = null; @@ -92,9 +92,9 @@ public class DisplayLinkScreen extends AbstractSimiScreen { @Override public void tick() { super.tick(); - if (sourceState != null && sourceState.getBlock() != minecraft.level.getBlockState(te.getSourcePosition()) + if (sourceState != null && sourceState.getBlock() != minecraft.level.getBlockState(blockEntity.getSourcePosition()) .getBlock() - || targetState != null && targetState.getBlock() != minecraft.level.getBlockState(te.getTargetPosition()) + || targetState != null && targetState.getBlock() != minecraft.level.getBlockState(blockEntity.getTargetPosition()) .getBlock()) initGathererOptions(); } @@ -102,8 +102,8 @@ public class DisplayLinkScreen extends AbstractSimiScreen { @SuppressWarnings("deprecation") private void initGathererOptions() { ClientLevel level = minecraft.level; - sourceState = level.getBlockState(te.getSourcePosition()); - targetState = level.getBlockState(te.getTargetPosition()); + sourceState = level.getBlockState(blockEntity.getSourcePosition()); + targetState = level.getBlockState(blockEntity.getTargetPosition()); ItemStack asItem; int x = guiLeft; @@ -112,13 +112,13 @@ public class DisplayLinkScreen extends AbstractSimiScreen { Block sourceBlock = sourceState.getBlock(); Block targetBlock = targetState.getBlock(); - asItem = sourceBlock.getCloneItemStack(level, te.getSourcePosition(), sourceState); + asItem = sourceBlock.getCloneItemStack(level, blockEntity.getSourcePosition(), sourceState); ItemStack sourceIcon = asItem == null || asItem.isEmpty() ? FALLBACK : asItem; - asItem = targetBlock.getCloneItemStack(level, te.getTargetPosition(), targetState); + asItem = targetBlock.getCloneItemStack(level, blockEntity.getTargetPosition(), targetState); ItemStack targetIcon = asItem == null || asItem.isEmpty() ? FALLBACK : asItem; - sources = AllDisplayBehaviours.sourcesOf(level, te.getSourcePosition()); - target = AllDisplayBehaviours.targetOf(level, te.getTargetPosition()); + sources = AllDisplayBehaviours.sourcesOf(level, blockEntity.getSourcePosition()); + target = AllDisplayBehaviours.targetOf(level, blockEntity.getTargetPosition()); removeWidget(targetLineSelector); removeWidget(targetLineLabel); @@ -133,9 +133,9 @@ public class DisplayLinkScreen extends AbstractSimiScreen { sourceTypeSelector = null; if (target != null) { - DisplayTargetStats stats = target.provideStats(new DisplayLinkContext(level, te)); + DisplayTargetStats stats = target.provideStats(new DisplayLinkContext(level, blockEntity)); int rows = stats.maxRows(); - int startIndex = Math.min(te.targetLine, rows); + int startIndex = Math.min(blockEntity.targetLine, rows); targetLineLabel = new Label(x + 65, y + 109, Components.immutableEmpty()).withShadow(); targetLineLabel.text = target.getLineOptionText(startIndex); @@ -155,7 +155,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { sourceWidget = new ElementWidget(x + 37, y + 26) .showingElement(GuiGameElement.of(sourceIcon)) .withCallback((mX, mY) -> { - ScreenOpener.open(new PonderTagScreen(CreatePonderTag.DISPLAY_SOURCES)); + ScreenOpener.open(new PonderTagScreen(AllPonderTags.DISPLAY_SOURCES)); }); sourceWidget.getToolTip().addAll(List.of( @@ -172,7 +172,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { targetWidget = new ElementWidget(x + 37, y + 105) .showingElement(GuiGameElement.of(targetIcon)) .withCallback((mX, mY) -> { - ScreenOpener.open(new PonderTagScreen(CreatePonderTag.DISPLAY_TARGETS)); + ScreenOpener.open(new PonderTagScreen(AllPonderTags.DISPLAY_TARGETS)); }); targetWidget.getToolTip().addAll(List.of( @@ -187,7 +187,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { addRenderableWidget(targetWidget); if (!sources.isEmpty()) { - int startIndex = Math.max(sources.indexOf(te.activeSource), 0); + int startIndex = Math.max(sources.indexOf(blockEntity.activeSource), 0); sourceTypeLabel = new Label(x + 65, y + 30, Components.immutableEmpty()).withShadow(); sourceTypeLabel.text = sources.get(startIndex) @@ -214,7 +214,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { private void initGathererSourceSubOptions(int i) { DisplaySource source = sources.get(i); - source.populateData(new DisplayLinkContext(te.getLevel(), te)); + source.populateData(new DisplayLinkContext(blockEntity.getLevel(), blockEntity)); if (targetLineSelector != null) targetLineSelector @@ -226,11 +226,11 @@ public class DisplayLinkScreen extends AbstractSimiScreen { s.clear(); }); - DisplayLinkContext context = new DisplayLinkContext(minecraft.level, te); + DisplayLinkContext context = new DisplayLinkContext(minecraft.level, blockEntity); configWidgets.forEachWithContext((s, first) -> source.initConfigurationWidgets(context, new ModularGuiLineBuilder(font, s, guiLeft + 60, guiTop + (first ? 51 : 72)), first)); configWidgets - .forEach(s -> s.loadValues(te.getSourceConfig(), this::addRenderableWidget, this::addRenderableOnly)); + .forEach(s -> s.loadValues(blockEntity.getSourceConfig(), this::addRenderableWidget, this::addRenderableOnly)); } @Override @@ -244,7 +244,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { configWidgets.forEach(s -> s.saveValues(sourceData)); } - AllPackets.channel.sendToServer(new DisplayLinkConfigurationPacket(te.getBlockPos(), sourceData, + AllPackets.getChannel().sendToServer(new DisplayLinkConfigurationPacket(blockEntity.getBlockPos(), sourceData, targetLineSelector == null ? 0 : targetLineSelector.getState())); } @@ -255,7 +255,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { background.render(ms, x, y, this); MutableComponent header = CreateLang.translateDirect("display_link.title"); - font.draw(ms, header, x + background.getWidth() / 2 - font.width(header) / 2, y + 4, 0x442000); + font.draw(ms, header, x + background.getWidth() / 2 - font.width(header) / 2, y + 4, 0x592424); if (sources.isEmpty()) font.drawShadow(ms, CreateLang.translateDirect("display_link.no_source"), x + 65, y + 30, 0xD3D3D3); @@ -278,7 +278,7 @@ public class DisplayLinkScreen extends AbstractSimiScreen { .scale(40) .rotateX(-22) .rotateY(63); - GuiGameElement.of(te.getBlockState() + GuiGameElement.of(blockEntity.getBlockState() .setValue(DisplayLinkBlock.FACING, Direction.UP)) .render(ms); ms.popPose(); diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/AccumulatedItemCountDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/AccumulatedItemCountDisplaySource.java new file mode 100644 index 0000000000..a2d249cd25 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/AccumulatedItemCountDisplaySource.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.MutableComponent; + +public class AccumulatedItemCountDisplaySource extends NumericSingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + return Components.literal(String.valueOf(context.sourceConfig() + .getInt("Collected"))); + } + + public void itemReceived(DisplayLinkBlockEntity be, int amount) { + if (be.getBlockState() + .getOptionalValue(DisplayLinkBlock.POWERED) + .orElse(true)) + return; + + int collected = be.getSourceConfig() + .getInt("Collected"); + be.getSourceConfig() + .putInt("Collected", collected + amount); + be.updateGatheredData(); + } + + @Override + protected String getTranslationKey() { + return "accumulate_items"; + } + + @Override + public int getPassiveRefreshTicks() { + return 200; + } + + @Override + public void onSignalReset(DisplayLinkContext context) { + context.sourceConfig() + .remove("Collected"); + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/BoilerDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/BoilerDisplaySource.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/BoilerDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/BoilerDisplaySource.java index 9de89b1cb0..376675203f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/BoilerDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/BoilerDisplaySource.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.List; import java.util.Optional; import java.util.stream.Stream; -import com.simibubi.create.content.contraptions.fluids.tank.BoilerData; -import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.fluids.tank.BoilerData; +import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; +import com.simibubi.create.content.trains.display.FlapDisplaySection; import com.simibubi.create.foundation.utility.CreateLang; import joptsimple.internal.Strings; @@ -41,7 +41,7 @@ public class BoilerDisplaySource extends DisplaySource { else if (stats.maxRows() < 4) return notEnoughSpaceDouble; - boolean isBook = context.getTargetTE() instanceof LecternBlockEntity; + boolean isBook = context.getTargetBlockEntity() instanceof LecternBlockEntity; if (isBook) { Stream componentList = getComponents(context, false).map(components -> { @@ -84,7 +84,7 @@ public class BoilerDisplaySource extends DisplaySource { } @Override - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout, int lineIndex) { if (lineIndex == 0 || context.flapDisplayContext instanceof Boolean b && !b) { if (layout.isLayout("Default")) @@ -107,17 +107,17 @@ public class BoilerDisplaySource extends DisplaySource { } private Stream> getComponents(DisplayLinkContext context, boolean forFlapDisplay) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof FluidTankTileEntity tankTile)) + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof FluidTankBlockEntity tankBlockEntity)) return Stream.of(EMPTY); - tankTile = tankTile.getControllerTE(); - if (tankTile == null) + tankBlockEntity = tankBlockEntity.getControllerBE(); + if (tankBlockEntity == null) return Stream.of(EMPTY); - BoilerData boiler = tankTile.boiler; + BoilerData boiler = tankBlockEntity.boiler; - int totalTankSize = tankTile.getTotalTankSize(); + int totalTankSize = tankBlockEntity.getTotalTankSize(); boiler.calcMinMaxForSize(totalTankSize); @@ -134,9 +134,9 @@ public class BoilerDisplaySource extends DisplaySource { } return Stream.of(List.of(CreateLang.translateDirect(label, boiler.getHeatLevelTextComponent())), - List.of(size, boiler.getSizeComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.BLACK)), - List.of(water, boiler.getWaterComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.BLACK)), - List.of(heat, boiler.getHeatComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.BLACK))); + List.of(size, boiler.getSizeComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.RESET)), + List.of(water, boiler.getWaterComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.RESET)), + List.of(heat, boiler.getHeatComponent(!forFlapDisplay, forFlapDisplay, ChatFormatting.RESET))); } private int labelWidth() { diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ComputerDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ComputerDisplaySource.java new file mode 100644 index 0000000000..61d2b962b4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ComputerDisplaySource.java @@ -0,0 +1,33 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.MutableComponent; + +public class ComputerDisplaySource extends DisplaySource { + + @Override + public List provideText(DisplayLinkContext context, DisplayTargetStats stats) { + List components = new ArrayList<>(); + ListTag tag = context.sourceConfig().getList("ComputerSourceList", Tag.TAG_STRING); + + for (int i = 0; i < tag.size(); i++) { + components.add(Components.literal(tag.getString(i))); + } + + return components; + } + + @Override + public boolean shouldPassiveReset() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/CurrentFloorDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/CurrentFloorDisplaySource.java new file mode 100644 index 0000000000..e63a6e1891 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/CurrentFloorDisplaySource.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.contraptions.elevator.ElevatorContactBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.MutableComponent; + +public class CurrentFloorDisplaySource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + if (!(context.getSourceBlockEntity() instanceof ElevatorContactBlockEntity ecbe)) + return EMPTY_LINE; + return Components.literal(ecbe.lastReportedCurrentFloor); + } + + @Override + protected String getTranslationKey() { + return "current_floor"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DeathCounterDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/DeathCounterDisplaySource.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/DeathCounterDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/DeathCounterDisplaySource.java index 467735291d..e8e4668e81 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DeathCounterDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/DeathCounterDisplaySource.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/DisplaySource.java similarity index 75% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/DisplaySource.java index 641e1325bf..435c779f17 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/DisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/DisplaySource.java @@ -1,16 +1,16 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.Arrays; import java.util.List; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.block.display.DisplayBehaviour; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayBoardTarget; -import com.simibubi.create.content.logistics.block.display.target.DisplayTarget; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayBehaviour; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import net.createmod.catnip.utility.lang.Components; @@ -49,6 +49,10 @@ public abstract class DisplaySource extends DisplayBehaviour { return 100; }; + public boolean shouldPassiveReset() { + return true; + } + protected String getTranslationKey() { return id.getPath(); } @@ -57,11 +61,11 @@ public abstract class DisplaySource extends DisplayBehaviour { return Components.translatable(id.getNamespace() + ".display_source." + getTranslationKey()); } - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, FlapDisplayLayout layout, int lineIndex) { + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout, int lineIndex) { loadFlapDisplayLayout(context, flapDisplay, layout); } - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout) { if (!layout.isLayout("Default")) layout.loadDefault(flapDisplay.getMaxCharCount()); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/EnchantPowerDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/EnchantPowerDisplaySource.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/EnchantPowerDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/EnchantPowerDisplaySource.java index 00c23ba0f4..950e466a84 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/EnchantPowerDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/EnchantPowerDisplaySource.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.Random; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; import net.createmod.catnip.utility.lang.Components; import net.minecraft.core.BlockPos; @@ -22,7 +22,7 @@ public class EnchantPowerDisplaySource extends NumericSingleLineDisplaySource { @Override protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - if (!(context.getSourceTE() instanceof EnchantmentTableBlockEntity enchantmentTile)) + if (!(context.getSourceBlockEntity() instanceof EnchantmentTableBlockEntity)) return ZERO.copy(); BlockPos pos = context.getSourcePos(); diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/EntityNameDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/EntityNameDisplaySource.java new file mode 100644 index 0000000000..8dd981462f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/EntityNameDisplaySource.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import java.util.List; + +import com.simibubi.create.content.contraptions.actors.seat.SeatEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; + +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.AABB; + +public class EntityNameDisplaySource extends SingleLineDisplaySource { + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + List seats = context.level().getEntitiesOfClass(SeatEntity.class, new AABB(context.getSourcePos())); + + if (seats.isEmpty()) + return EMPTY_LINE; + + SeatEntity seatEntity = seats.get(0); + List passengers = seatEntity.getPassengers(); + + if (passengers.isEmpty()) + return EMPTY_LINE; + + return passengers.get(0).getDisplayName().copy(); + } + + @Override + protected String getTranslationKey() { + return "entity_name"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FillLevelDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FillLevelDisplaySource.java similarity index 77% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/FillLevelDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/FillLevelDisplaySource.java index 417872df07..96b8777de0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FillLevelDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FillLevelDisplaySource.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlockEntity; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -13,10 +13,10 @@ public class FillLevelDisplaySource extends PercentOrProgressBarDisplaySource { @Override protected Float getProgress(DisplayLinkContext context) { - BlockEntity te = context.getSourceTE(); - if (!(te instanceof StockpileSwitchTileEntity sste)) + BlockEntity be = context.getSourceBlockEntity(); + if (!(be instanceof ThresholdSwitchBlockEntity tsbe)) return null; - return sste.currentLevel; + return tsbe.currentLevel; } @Override diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidAmountDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidAmountDisplaySource.java new file mode 100644 index 0000000000..0c37909fad --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidAmountDisplaySource.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; +import com.simibubi.create.foundation.utility.FluidFormatter; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public class FluidAmountDisplaySource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof SmartObserverBlockEntity cobe)) + return EMPTY_LINE; + + TankManipulationBehaviour tankManipulationBehaviour = cobe.getBehaviour(TankManipulationBehaviour.OBSERVE); + FilteringBehaviour filteringBehaviour = cobe.getBehaviour(FilteringBehaviour.TYPE); + IFluidHandler handler = tankManipulationBehaviour.getInventory(); + + if (handler == null) + return EMPTY_LINE; + + long collected = 0; + for (int i = 0; i < handler.getTanks(); i++) { + FluidStack stack = handler.getFluidInTank(i); + if (stack.isEmpty()) + continue; + if (!filteringBehaviour.test(stack)) + continue; + collected += stack.getAmount(); + } + + return Components.literal(FluidFormatter.asString(collected, false)); + } + + @Override + protected String getTranslationKey() { + return "fluid_amount"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidListDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidListDisplaySource.java similarity index 77% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidListDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidListDisplaySource.java index 2f0cabc376..c9bfd5f3e9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/FluidListDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/FluidListDisplaySource.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.Comparator; import java.util.HashMap; @@ -8,13 +8,13 @@ import java.util.stream.Stream; import org.apache.commons.lang3.mutable.MutableInt; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.redstone.ContentObserverTileEntity; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.inventory.TankManipulationBehaviour; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; +import com.simibubi.create.content.trains.display.FlapDisplaySection; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; import com.simibubi.create.foundation.utility.FluidFormatter; import net.createmod.catnip.utility.Couple; @@ -31,12 +31,12 @@ public class FluidListDisplaySource extends ValueListDisplaySource { @Override protected Stream> provideEntries(DisplayLinkContext context, int maxRows) { - BlockEntity sourceTE = context.getSourceTE(); - if (!(sourceTE instanceof ContentObserverTileEntity cote)) + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof SmartObserverBlockEntity cobe)) return Stream.empty(); - TankManipulationBehaviour tankManipulationBehaviour = cote.getBehaviour(TankManipulationBehaviour.OBSERVE); - FilteringBehaviour filteringBehaviour = cote.getBehaviour(FilteringBehaviour.TYPE); + TankManipulationBehaviour tankManipulationBehaviour = cobe.getBehaviour(TankManipulationBehaviour.OBSERVE); + FilteringBehaviour filteringBehaviour = cobe.getBehaviour(FilteringBehaviour.TYPE); IFluidHandler handler = tankManipulationBehaviour.getInventory(); if (handler == null) @@ -78,7 +78,7 @@ public class FluidListDisplaySource extends ValueListDisplaySource { } @Override - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, FlapDisplayLayout layout) { + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout) { Integer max = ((MutableInt) context.flapDisplayContext).getValue(); boolean shorten = shortenNumbers(context); int length = FluidFormatter.asString(max, shorten).length(); diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemCountDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemCountDisplaySource.java new file mode 100644 index 0000000000..2d1b42e96f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemCountDisplaySource.java @@ -0,0 +1,53 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.IItemHandler; + +public class ItemCountDisplaySource extends NumericSingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof SmartObserverBlockEntity cobe)) + return ZERO.copy(); + + InvManipulationBehaviour invManipulationBehaviour = cobe.getBehaviour(InvManipulationBehaviour.TYPE); + FilteringBehaviour filteringBehaviour = cobe.getBehaviour(FilteringBehaviour.TYPE); + IItemHandler handler = invManipulationBehaviour.getInventory(); + + if (handler == null) + return ZERO.copy(); + + int collected = 0; + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack stack = handler.extractItem(i, handler.getSlotLimit(i), true); + if (stack.isEmpty()) + continue; + if (!filteringBehaviour.test(stack)) + continue; + collected += stack.getCount(); + } + + return Components.literal(String.valueOf(collected)); + } + + @Override + protected String getTranslationKey() { + return "count_items"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemListDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemListDisplaySource.java new file mode 100644 index 0000000000..733b86f218 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemListDisplaySource.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import java.util.stream.Stream; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.smartObserver.SmartObserverBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.item.CountedItemStackList; + +import net.createmod.catnip.utility.IntAttached; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.IItemHandler; + +public class ItemListDisplaySource extends ValueListDisplaySource { + + @Override + protected Stream> provideEntries(DisplayLinkContext context, int maxRows) { + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof SmartObserverBlockEntity cobe)) + return Stream.empty(); + + InvManipulationBehaviour invManipulationBehaviour = cobe.getBehaviour(InvManipulationBehaviour.TYPE); + FilteringBehaviour filteringBehaviour = cobe.getBehaviour(FilteringBehaviour.TYPE); + IItemHandler handler = invManipulationBehaviour.getInventory(); + + if (handler == null) + return Stream.empty(); + + return new CountedItemStackList(handler, filteringBehaviour).getTopNames(maxRows); + } + + @Override + protected String getTranslationKey() { + return "list_items"; + } + + @Override + protected boolean valueFirst() { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemNameDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemNameDisplaySource.java new file mode 100644 index 0000000000..5c7aef3c84 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemNameDisplaySource.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import org.apache.commons.lang3.mutable.MutableObject; + +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; + +public class ItemNameDisplaySource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + DisplayLinkBlockEntity gatherer = context.blockEntity(); + Direction direction = gatherer.getDirection(); + MutableBlockPos pos = gatherer.getSourcePosition() + .mutable(); + + MutableComponent combined = EMPTY_LINE.copy(); + + for (int i = 0; i < 32; i++) { + TransportedItemStackHandlerBehaviour behaviour = + BlockEntityBehaviour.get(context.level(), pos, TransportedItemStackHandlerBehaviour.TYPE); + pos.move(direction); + + if (behaviour == null) + break; + + MutableObject stackHolder = new MutableObject<>(); + behaviour.handleCenteredProcessingOnAllItems(.25f, tis -> { + stackHolder.setValue(tis.stack); + return TransportedResult.doNothing(); + }); + + ItemStack stack = stackHolder.getValue(); + if (stack != null && !stack.isEmpty()) + combined = combined.append(stack.getHoverName()); + } + + return combined; + } + + @Override + protected String getTranslationKey() { + return "combine_item_names"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } + + @Override + protected String getFlapDisplayLayoutName(DisplayLinkContext context) { + return "Number"; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemThroughputDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemThroughputDisplaySource.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemThroughputDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemThroughputDisplaySource.java index 133a53755b..f62d2e1ca9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ItemThroughputDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ItemThroughputDisplaySource.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.DisplayLinkTileEntity; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -30,7 +30,7 @@ public class ItemThroughputDisplaySource extends AccumulatedItemCountDisplaySour if (rate > 0) { long previousTime = conf.getLong("LastReceived"); - long gameTime = context.te() + long gameTime = context.blockEntity() .getLevel() .getGameTime(); int diff = (int) (gameTime - previousTime); @@ -47,14 +47,14 @@ public class ItemThroughputDisplaySource extends AccumulatedItemCountDisplaySour .component(); } - public void itemReceived(DisplayLinkTileEntity te, int amount) { - if (te.getBlockState() + public void itemReceived(DisplayLinkBlockEntity be, int amount) { + if (be.getBlockState() .getOptionalValue(DisplayLinkBlock.POWERED) .orElse(true)) return; - CompoundTag conf = te.getSourceConfig(); - long gameTime = te.getLevel() + CompoundTag conf = be.getSourceConfig(); + long gameTime = be.getLevel() .getGameTime(); if (!conf.contains("LastReceived")) { @@ -95,7 +95,7 @@ public class ItemThroughputDisplaySource extends AccumulatedItemCountDisplaySour conf.putLong("LastReceived", gameTime); conf.putInt("Index", poolIndex + 1); conf.put("PrevRates", rates); - te.updateGatheredData(); + be.updateGatheredData(); } @Override diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticSpeedDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticSpeedDisplaySource.java new file mode 100644 index 0000000000..34124ff890 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticSpeedDisplaySource.java @@ -0,0 +1,52 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.network.chat.MutableComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class KineticSpeedDisplaySource extends NumericSingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + if (!(context.getSourceBlockEntity() instanceof SpeedGaugeBlockEntity speedGauge)) + return ZERO.copy(); + + boolean absoluteValue = context.sourceConfig() + .getInt("Directional") == 0; + float speed = absoluteValue ? Math.abs(speedGauge.getSpeed()) : speedGauge.getSpeed(); + return CreateLang.number(speed) + .space() + .translate("generic.unit.rpm") + .component(); + } + + @Override + protected String getTranslationKey() { + return "kinetic_speed"; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, + boolean isFirstLine) { + super.initConfigurationWidgets(context, builder, isFirstLine); + if (isFirstLine) + return; + + builder.addSelectionScrollInput(0, 95, (selectionScrollInput, label) -> { + selectionScrollInput + .forOptions(CreateLang.translatedOptions("display_source.kinetic_speed", "absolute", "directional")); + }, "Directional"); + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticStressDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticStressDisplaySource.java similarity index 78% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticStressDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticStressDisplaySource.java index e7ee30ca6b..e0ac677b23 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/KineticStressDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/KineticStressDisplaySource.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -19,7 +19,7 @@ public class KineticStressDisplaySource extends PercentOrProgressBarDisplaySourc if (mode == 1) return super.formatNumeric(context, currentLevel); LangBuilder builder = CreateLang.number(currentLevel); - if (context.getTargetTE() instanceof FlapDisplayTileEntity) + if (context.getTargetBlockEntity() instanceof FlapDisplayBlockEntity) builder.space(); return builder.translate("generic.unit.stress") .component(); @@ -32,11 +32,11 @@ public class KineticStressDisplaySource extends PercentOrProgressBarDisplaySourc @Override protected Float getProgress(DisplayLinkContext context) { - if (!(context.getSourceTE()instanceof StressGaugeTileEntity gaugeTile)) + if (!(context.getSourceBlockEntity()instanceof StressGaugeBlockEntity stressGauge)) return null; - float capacity = gaugeTile.getNetworkCapacity(); - float stress = gaugeTile.getNetworkStress(); + float capacity = stressGauge.getNetworkCapacity(); + float stress = stressGauge.getNetworkStress(); if (capacity == 0) return 0f; diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NixieTubeDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NixieTubeDisplaySource.java new file mode 100644 index 0000000000..3d08cd1f9d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NixieTubeDisplaySource.java @@ -0,0 +1,60 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.redstone.displayLink.target.NixieTubeDisplayTarget; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplaySection; + +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class NixieTubeDisplaySource extends SingleLineDisplaySource { + + @Override + protected String getTranslationKey() { + return "nixie_tube"; + } + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + BlockEntity sourceBE = context.getSourceBlockEntity(); + if (!(sourceBE instanceof NixieTubeBlockEntity nbe)) + return EMPTY_LINE; + + MutableComponent text = nbe.getFullText(); + + try { + String line = text.getString(); + Integer.valueOf(line); + context.flapDisplayContext = Boolean.TRUE; + } catch (NumberFormatException e) { + } + + return text; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return !(context.blockEntity().activeTarget instanceof NixieTubeDisplayTarget); + } + + @Override + protected String getFlapDisplayLayoutName(DisplayLinkContext context) { + if (isNumeric(context)) + return "Number"; + return super.getFlapDisplayLayoutName(context); + } + + @Override + protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { + if (isNumeric(context)) + return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "numeric", false, false); + return super.createSectionForValue(context, size); + } + + protected boolean isNumeric(DisplayLinkContext context) { + return context.flapDisplayContext == Boolean.TRUE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NumericSingleLineDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NumericSingleLineDisplaySource.java new file mode 100644 index 0000000000..d644d48c83 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/NumericSingleLineDisplaySource.java @@ -0,0 +1,23 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.trains.display.FlapDisplaySection; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.Component; + +public abstract class NumericSingleLineDisplaySource extends SingleLineDisplaySource { + + protected static final Component ZERO = Components.literal("0"); + + @Override + protected String getFlapDisplayLayoutName(DisplayLinkContext context) { + return "Number"; + } + + @Override + protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { + return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "numeric", false, false); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ObservedTrainNameSource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ObservedTrainNameSource.java new file mode 100644 index 0000000000..2503d00d65 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ObservedTrainNameSource.java @@ -0,0 +1,47 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import java.util.UUID; + +import com.simibubi.create.Create; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.observer.TrackObserver; +import com.simibubi.create.content.trains.observer.TrackObserverBlockEntity; + +import net.minecraft.network.chat.MutableComponent; + +public class ObservedTrainNameSource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + if (!(context.getSourceBlockEntity() instanceof TrackObserverBlockEntity observerBE)) + return EMPTY_LINE; + TrackObserver observer = observerBE.getObserver(); + if (observer == null) + return EMPTY_LINE; + UUID currentTrain = observer.getCurrentTrain(); + if (currentTrain == null) + return EMPTY_LINE; + Train train = Create.RAILWAYS.trains.get(currentTrain); + if (train == null) + return EMPTY_LINE; + return train.name.copy(); + } + + @Override + public int getPassiveRefreshTicks() { + return 400; + } + + @Override + protected String getTranslationKey() { + return "observed_train_name"; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/PercentOrProgressBarDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/PercentOrProgressBarDisplaySource.java similarity index 76% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/PercentOrProgressBarDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/PercentOrProgressBarDisplaySource.java index 61dcc3a38e..72a680ed38 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/PercentOrProgressBarDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/PercentOrProgressBarDisplaySource.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import static com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection.WIDE_MONOSPACE; +import static com.simibubi.create.content.trains.display.FlapDisplaySection.WIDE_MONOSPACE; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplaySection; import net.createmod.catnip.utility.lang.Components; import net.minecraft.network.chat.MutableComponent; @@ -30,9 +30,9 @@ public abstract class PercentOrProgressBarDisplaySource extends NumericSingleLin int labelSize = label.isEmpty() ? 0 : label.length() + 1; int length = Math.min(stats.maxColumns() - labelSize, 128); - if (context.getTargetTE() instanceof SignBlockEntity) + if (context.getTargetBlockEntity() instanceof SignBlockEntity) length = (int) (length * 6f / 9f); - if (context.getTargetTE() instanceof FlapDisplayTileEntity) + if (context.getTargetBlockEntity() instanceof FlapDisplayBlockEntity) length = sizeForWideChars(length); int filledLength = (int) (currentLevel * length); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/RedstonePowerDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/RedstonePowerDisplaySource.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/RedstonePowerDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/RedstonePowerDisplaySource.java index 90a7b96ef1..3f4d155e95 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/RedstonePowerDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/RedstonePowerDisplaySource.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ScoreboardDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ScoreboardDisplaySource.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/ScoreboardDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/ScoreboardDisplaySource.java index 10160fcba7..111d03d50e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ScoreboardDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ScoreboardDisplaySource.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.stream.Stream; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -19,7 +19,7 @@ public class ScoreboardDisplaySource extends ValueListDisplaySource { @Override protected Stream> provideEntries(DisplayLinkContext context, int maxRows) { - Level level = context.te() + Level level = context.blockEntity() .getLevel(); if (!(level instanceof ServerLevel sLevel)) return Stream.empty(); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/SingleLineDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/SingleLineDisplaySource.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/SingleLineDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/SingleLineDisplaySource.java index 1e1a7a2bc9..10adde9ad2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/SingleLineDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/SingleLineDisplaySource.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.List; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; +import com.simibubi.create.content.trains.display.FlapDisplaySection; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -71,7 +71,7 @@ public abstract class SingleLineDisplaySource extends DisplaySource { } @Override - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout) { String layoutKey = getFlapDisplayLayoutName(context); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StatTrackingDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StatTrackingDisplaySource.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/StatTrackingDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/StatTrackingDisplaySource.java index 59e05d215e..7e5d700189 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StatTrackingDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StatTrackingDisplaySource.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import java.util.stream.Stream; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import net.createmod.catnip.utility.IntAttached; @@ -22,7 +22,7 @@ public abstract class StatTrackingDisplaySource extends ScoreboardDisplaySource @Override protected Stream> provideEntries(DisplayLinkContext context, int maxRows) { - Level level = context.te() + Level level = context.blockEntity() .getLevel(); if (!(level instanceof ServerLevel sLevel)) return Stream.empty(); @@ -33,7 +33,7 @@ public abstract class StatTrackingDisplaySource extends ScoreboardDisplaySource scoreboard.addObjective(name, ObjectiveCriteria.DUMMY, getObjectiveDisplayName(), RenderType.INTEGER); Objective objective = scoreboard.getObjective(name); - sLevel.players() + sLevel.getServer().getPlayerList().getPlayers() .forEach(s -> scoreboard.getOrCreatePlayerScore(s.getScoreboardName(), objective) .setScore(updatedScoreOf(s))); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StationSummaryDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StationSummaryDisplaySource.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/StationSummaryDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/StationSummaryDisplaySource.java index 1471e6c708..a1a28ee760 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/StationSummaryDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StationSummaryDisplaySource.java @@ -1,19 +1,19 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import static com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection.MONOSPACE; +import static com.simibubi.create.content.trains.display.FlapDisplaySection.MONOSPACE; import java.util.ArrayList; import java.util.List; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; -import com.simibubi.create.content.logistics.trains.management.display.GlobalTrainDisplayData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; +import com.simibubi.create.content.trains.display.FlapDisplaySection; +import com.simibubi.create.content.trains.display.GlobalTrainDisplayData; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.StationBlockEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -91,7 +91,7 @@ public class StationSummaryDisplaySource extends DisplaySource { }); if (list.size() > 0) - context.te() + context.blockEntity() .award(AllAdvancements.DISPLAY_BOARD); int toPad = stats.maxRows() - list.size(); @@ -102,7 +102,7 @@ public class StationSummaryDisplaySource extends DisplaySource { } @Override - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout) { CompoundTag conf = context.sourceConfig(); int columnWidth = conf.getInt("NameColumn"); @@ -172,9 +172,9 @@ public class StationSummaryDisplaySource extends DisplaySource { if (conf.contains("Filter")) return; - if (!(context.getSourceTE() instanceof StationTileEntity stationTe)) + if (!(context.getSourceBlockEntity() instanceof StationBlockEntity stationBe)) return; - GlobalStation station = stationTe.getStation(); + GlobalStation station = stationBe.getStation(); if (station == null) return; conf.putString("Filter", station.name); diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StopWatchDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StopWatchDisplaySource.java new file mode 100644 index 0000000000..a86d271f0c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/StopWatchDisplaySource.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.kinetics.clock.CuckooClockBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplaySection; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.MutableComponent; + +public class StopWatchDisplaySource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + if (!(context.getSourceBlockEntity() instanceof CuckooClockBlockEntity ccbe)) + return TimeOfDayDisplaySource.EMPTY_TIME; + if (ccbe.getSpeed() == 0) + return TimeOfDayDisplaySource.EMPTY_TIME; + + if (!context.sourceConfig() + .contains("StartTime")) + onSignalReset(context); + + long started = context.sourceConfig() + .getLong("StartTime"); + long current = context.blockEntity() + .getLevel() + .getGameTime(); + + int diff = (int) (current - started); + int hours = (diff / 60 / 60 / 20); + int minutes = (diff / 60 / 20) % 60; + int seconds = (diff / 20) % 60; + + MutableComponent component = Components.literal((hours == 0 ? "" : (hours < 10 ? " " : "") + hours + ":") + + (minutes < 10 ? hours == 0 ? " " : "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds); + + return component; + } + + @Override + public void onSignalReset(DisplayLinkContext context) { + context.sourceConfig() + .putLong("StartTime", context.blockEntity() + .getLevel() + .getGameTime()); + } + + @Override + public int getPassiveRefreshTicks() { + return 20; + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return true; + } + + @Override + protected String getFlapDisplayLayoutName(DisplayLinkContext context) { + return "Instant"; + } + + @Override + protected FlapDisplaySection createSectionForValue(DisplayLinkContext context, int size) { + return new FlapDisplaySection(size * FlapDisplaySection.MONOSPACE, "instant", false, false); + } + + @Override + protected String getTranslationKey() { + return "stop_watch"; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/TimeOfDayDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/TimeOfDayDisplaySource.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/TimeOfDayDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/TimeOfDayDisplaySource.java index 7fac300103..59fac741df 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/TimeOfDayDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/TimeOfDayDisplaySource.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; +import com.simibubi.create.content.kinetics.clock.CuckooClockBlockEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplaySection; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -22,9 +22,9 @@ public class TimeOfDayDisplaySource extends SingleLineDisplaySource { protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { if (!(context.level()instanceof ServerLevel sLevel)) return EMPTY_TIME; - if (!(context.getSourceTE() instanceof CuckooClockTileEntity ccte)) + if (!(context.getSourceBlockEntity() instanceof CuckooClockBlockEntity ccbe)) return EMPTY_TIME; - if (ccte.getSpeed() == 0) + if (ccbe.getSpeed() == 0) return EMPTY_TIME; boolean c12 = context.sourceConfig() diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/source/TrainStatusDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/TrainStatusDisplaySource.java new file mode 100644 index 0000000000..b2656a1252 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/TrainStatusDisplaySource.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.StationBlockEntity; + +import net.minecraft.network.chat.MutableComponent; + +public class TrainStatusDisplaySource extends SingleLineDisplaySource { + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + if (!(context.getSourceBlockEntity() instanceof StationBlockEntity observerBE)) + return EMPTY_LINE; + GlobalStation observer = observerBE.getStation(); + if (observer == null) + return EMPTY_LINE; + Train currentTrain = observer.getPresentTrain(); + if (currentTrain == null) + return EMPTY_LINE; + + ScheduleRuntime runtime = currentTrain.runtime; + Schedule schedule = runtime.getSchedule(); + if (schedule == null) + return EMPTY_LINE; + if (runtime.paused) + return EMPTY_LINE; + if (runtime.state != State.POST_TRANSIT) + return EMPTY_LINE; + if (runtime.currentEntry == schedule.entries.size() - 1 && !schedule.cyclic) + return EMPTY_LINE; + + return runtime.getWaitingStatus(context.level()); + } + + @Override + protected boolean allowsLabeling(DisplayLinkContext context) { + return false; + } + + @Override + protected String getTranslationKey() { + return "train_status"; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ValueListDisplaySource.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ValueListDisplaySource.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/block/display/source/ValueListDisplaySource.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/source/ValueListDisplaySource.java index eaa9b5e1fb..863874c71d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/source/ValueListDisplaySource.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/source/ValueListDisplaySource.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.display.source; +package com.simibubi.create.content.redstone.displayLink.source; -import static com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection.MONOSPACE; +import static com.simibubi.create.content.trains.display.FlapDisplaySection.MONOSPACE; import java.util.ArrayList; import java.util.Arrays; @@ -9,11 +9,11 @@ import java.util.stream.Stream; import org.apache.commons.lang3.mutable.MutableInt; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayLayout; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplaySection; -import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; +import com.simibubi.create.content.trains.display.FlapDisplaySection; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -33,7 +33,7 @@ public abstract class ValueListDisplaySource extends DisplaySource { @Override public List provideText(DisplayLinkContext context, DisplayTargetStats stats) { - boolean isBook = context.getTargetTE() instanceof LecternBlockEntity; + boolean isBook = context.getTargetBlockEntity() instanceof LecternBlockEntity; List list = provideEntries(context, stats.maxRows() * (isBook ? ENTRIES_PER_PAGE : 1)) .map(e -> createComponentsFromEntry(context, e)) @@ -104,7 +104,7 @@ public abstract class ValueListDisplaySource extends DisplaySource { } @Override - public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayTileEntity flapDisplay, + public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout) { boolean valueFirst = valueFirst(); diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayBoardTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayBoardTarget.java new file mode 100644 index 0000000000..ba2ae4053f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayBoardTarget.java @@ -0,0 +1,109 @@ +package com.simibubi.create.content.redstone.displayLink.target; + +import java.util.List; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.source.DisplaySource; +import com.simibubi.create.content.redstone.displayLink.source.SingleLineDisplaySource; +import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity; +import com.simibubi.create.content.trains.display.FlapDisplayLayout; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class DisplayBoardTarget extends DisplayTarget { + + @Override + public void acceptText(int line, List text, DisplayLinkContext context) {} + + public void acceptFlapText(int line, List> text, DisplayLinkContext context) { + FlapDisplayBlockEntity controller = getController(context); + if (controller == null) + return; + if (!controller.isSpeedRequirementFulfilled()) + return; + + DisplaySource source = context.blockEntity().activeSource; + List lines = controller.getLines(); + for (int i = 0; i + line < lines.size(); i++) { + + if (i == 0) + reserve(i + line, controller, context); + if (i > 0 && isReserved(i + line, controller, context)) + break; + + FlapDisplayLayout layout = lines.get(i + line); + + if (i >= text.size()) { + if (source instanceof SingleLineDisplaySource) + break; + controller.applyTextManually(i + line, null); + continue; + } + + source.loadFlapDisplayLayout(context, controller, layout, i); + + for (int sectionIndex = 0; sectionIndex < layout.getSections() + .size(); sectionIndex++) { + List textLine = text.get(i); + if (textLine.size() <= sectionIndex) + break; + layout.getSections() + .get(sectionIndex) + .setText(textLine.get(sectionIndex)); + } + } + + controller.sendData(); + } + + @Override + public boolean isReserved(int line, BlockEntity target, DisplayLinkContext context) { + return super.isReserved(line, target, context) + || target instanceof FlapDisplayBlockEntity fdte && fdte.manualLines.length > line && fdte.manualLines[line]; + } + + @Override + public DisplayTargetStats provideStats(DisplayLinkContext context) { + FlapDisplayBlockEntity controller = getController(context); + if (controller == null) + return new DisplayTargetStats(1, 1, this); + return new DisplayTargetStats(controller.ySize * 2, controller.getMaxCharCount(), this); + } + + private FlapDisplayBlockEntity getController(DisplayLinkContext context) { + BlockEntity teIn = context.getTargetBlockEntity(); + if (!(teIn instanceof FlapDisplayBlockEntity be)) + return null; + return be.getController(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getMultiblockBounds(LevelAccessor level, BlockPos pos) { + AABB baseShape = super.getMultiblockBounds(level, pos); + BlockEntity be = level.getBlockEntity(pos); + + if (!(be instanceof FlapDisplayBlockEntity fdbe)) + return baseShape; + + FlapDisplayBlockEntity controller = fdbe.getController(); + if (controller == null) + return baseShape; + + Vec3i normal = controller.getDirection() + .getClockWise() + .getNormal(); + return baseShape.move(controller.getBlockPos() + .subtract(pos)) + .expandTowards(normal.getX() * (controller.xSize - 1), 1 - controller.ySize, + normal.getZ() * (controller.xSize - 1)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTarget.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTarget.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTarget.java index b4542bd802..48415497ec 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/DisplayTarget.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTarget.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.block.display.target; +package com.simibubi.create.content.redstone.displayLink.target; import java.util.List; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.logistics.block.display.DisplayBehaviour; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayBehaviour; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.core.BlockPos; @@ -41,7 +41,7 @@ public abstract class DisplayTarget extends DisplayBehaviour { CompoundTag tag = target.getTileData(); CompoundTag compound = tag.getCompound("DisplayLink"); - compound.putLong("Line" + line, context.te() + compound.putLong("Line" + line, context.blockEntity() .getBlockPos() .asLong()); tag.put("DisplayLink", compound); @@ -57,7 +57,7 @@ public abstract class DisplayTarget extends DisplayBehaviour { long l = compound.getLong("Line" + line); BlockPos reserved = BlockPos.of(l); - if (!reserved.equals(context.te() + if (!reserved.equals(context.blockEntity() .getBlockPos()) && AllBlocks.DISPLAY_LINK.has(target.getLevel() .getBlockState(reserved))) return true; diff --git a/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTargetStats.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTargetStats.java new file mode 100644 index 0000000000..13dff95505 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/DisplayTargetStats.java @@ -0,0 +1,5 @@ +package com.simibubi.create.content.redstone.displayLink.target; + +public record DisplayTargetStats(int maxRows, int maxColumns, DisplayTarget type) { + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/LecternDisplayTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/LecternDisplayTarget.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/block/display/target/LecternDisplayTarget.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/target/LecternDisplayTarget.java index da2a3dec03..00000884f0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/LecternDisplayTarget.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/LecternDisplayTarget.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.display.target; +package com.simibubi.create.content.redstone.displayLink.target; import java.util.List; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.nbt.CompoundTag; @@ -20,8 +20,8 @@ public class LecternDisplayTarget extends DisplayTarget { @Override public void acceptText(int line, List text, DisplayLinkContext context) { - BlockEntity te = context.getTargetTE(); - if (!(te instanceof LecternBlockEntity lectern)) + BlockEntity be = context.getTargetBlockEntity(); + if (!(be instanceof LecternBlockEntity lectern)) return; ItemStack book = lectern.getBook(); if (book.isEmpty()) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/NixieTubeDisplayTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/NixieTubeDisplayTarget.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/block/display/target/NixieTubeDisplayTarget.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/target/NixieTubeDisplayTarget.java index 2a08576829..13415b9bed 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/NixieTubeDisplayTarget.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/NixieTubeDisplayTarget.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.block.display.target; +package com.simibubi.create.content.redstone.displayLink.target; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlock; -import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlock; +import com.simibubi.create.content.redstone.nixieTube.NixieTubeBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -25,7 +25,7 @@ public class NixieTubeDisplayTarget extends SingleLineDisplayTarget { NixieTubeBlock.walkNixies(context.level(), context.getTargetPos(), (currentPos, rowPosition) -> { BlockEntity blockEntity = context.level() .getBlockEntity(currentPos); - if (blockEntity instanceof NixieTubeTileEntity nixie) + if (blockEntity instanceof NixieTubeBlockEntity nixie) nixie.displayCustomText(tagElement, rowPosition); }); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/SignDisplayTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/SignDisplayTarget.java similarity index 79% rename from src/main/java/com/simibubi/create/content/logistics/block/display/target/SignDisplayTarget.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/target/SignDisplayTarget.java index 031f4fe0f2..77efd54364 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/SignDisplayTarget.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/SignDisplayTarget.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.display.target; +package com.simibubi.create.content.redstone.displayLink.target; import java.util.List; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.level.block.entity.BlockEntity; @@ -12,8 +12,8 @@ public class SignDisplayTarget extends DisplayTarget { @Override public void acceptText(int line, List text, DisplayLinkContext context) { - BlockEntity te = context.getTargetTE(); - if (!(te instanceof SignBlockEntity sign)) + BlockEntity be = context.getTargetBlockEntity(); + if (!(be instanceof SignBlockEntity sign)) return; boolean changed = false; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/display/target/SingleLineDisplayTarget.java b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/SingleLineDisplayTarget.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/display/target/SingleLineDisplayTarget.java rename to src/main/java/com/simibubi/create/content/redstone/displayLink/target/SingleLineDisplayTarget.java index aa327dc870..265ec9e79d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/display/target/SingleLineDisplayTarget.java +++ b/src/main/java/com/simibubi/create/content/redstone/displayLink/target/SingleLineDisplayTarget.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.display.target; +package com.simibubi.create.content.redstone.displayLink.target; import java.util.List; -import com.simibubi.create.content.logistics.block.display.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/simibubi/create/content/redstone/link/IRedstoneLinkable.java b/src/main/java/com/simibubi/create/content/redstone/link/IRedstoneLinkable.java new file mode 100644 index 0000000000..59ab830eb7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/IRedstoneLinkable.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.redstone.link; + +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler.Frequency; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; + +public interface IRedstoneLinkable { + + public int getTransmittedStrength(); + + public void setReceivedStrength(int power); + + public boolean isListening(); + + public boolean isAlive(); + + public Couple getNetworkKey(); + + public BlockPos getLocation(); + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/link/LinkBehaviour.java b/src/main/java/com/simibubi/create/content/redstone/link/LinkBehaviour.java new file mode 100644 index 0000000000..24b7944c03 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/LinkBehaviour.java @@ -0,0 +1,253 @@ +package com.simibubi.create.content.redstone.link; + +import java.util.function.Function; +import java.util.function.IntConsumer; +import java.util.function.IntSupplier; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.Create; +import com.simibubi.create.content.equipment.clipboard.ClipboardCloneable; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler.Frequency; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class LinkBehaviour extends BlockEntityBehaviour implements IRedstoneLinkable, ClipboardCloneable { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + enum Mode { + TRANSMIT, RECEIVE + } + + Frequency frequencyFirst; + Frequency frequencyLast; + ValueBoxTransform firstSlot; + ValueBoxTransform secondSlot; + Vec3 textShift; + + public boolean newPosition; + private Mode mode; + private IntSupplier transmission; + private IntConsumer signalCallback; + + protected LinkBehaviour(SmartBlockEntity be, Pair slots) { + super(be); + frequencyFirst = Frequency.EMPTY; + frequencyLast = Frequency.EMPTY; + firstSlot = slots.getLeft(); + secondSlot = slots.getRight(); + textShift = Vec3.ZERO; + newPosition = true; + } + + public static LinkBehaviour receiver(SmartBlockEntity be, Pair slots, + IntConsumer signalCallback) { + LinkBehaviour behaviour = new LinkBehaviour(be, slots); + behaviour.signalCallback = signalCallback; + behaviour.mode = Mode.RECEIVE; + return behaviour; + } + + public static LinkBehaviour transmitter(SmartBlockEntity be, Pair slots, + IntSupplier transmission) { + LinkBehaviour behaviour = new LinkBehaviour(be, slots); + behaviour.transmission = transmission; + behaviour.mode = Mode.TRANSMIT; + return behaviour; + } + + public LinkBehaviour moveText(Vec3 shift) { + textShift = shift; + return this; + } + + public void copyItemsFrom(LinkBehaviour behaviour) { + if (behaviour == null) + return; + frequencyFirst = behaviour.frequencyFirst; + frequencyLast = behaviour.frequencyLast; + } + + @Override + public boolean isListening() { + return mode == Mode.RECEIVE; + } + + @Override + public int getTransmittedStrength() { + return mode == Mode.TRANSMIT ? transmission.getAsInt() : 0; + } + + @Override + public void setReceivedStrength(int networkPower) { + if (!newPosition) + return; + signalCallback.accept(networkPower); + } + + public void notifySignalChange() { + Create.REDSTONE_LINK_NETWORK_HANDLER.updateNetworkOf(getWorld(), this); + } + + @Override + public void initialize() { + super.initialize(); + if (getWorld().isClientSide) + return; + getHandler().addToNetwork(getWorld(), this); + newPosition = true; + } + + @Override + public Couple getNetworkKey() { + return Couple.create(frequencyFirst, frequencyLast); + } + + @Override + public void unload() { + super.unload(); + if (getWorld().isClientSide) + return; + getHandler().removeFromNetwork(getWorld(), this); + } + + @Override + public boolean isSafeNBT() { + return true; + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + super.write(nbt, clientPacket); + nbt.put("FrequencyFirst", frequencyFirst.getStack() + .save(new CompoundTag())); + nbt.put("FrequencyLast", frequencyLast.getStack() + .save(new CompoundTag())); + nbt.putLong("LastKnownPosition", blockEntity.getBlockPos() + .asLong()); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + long positionInTag = blockEntity.getBlockPos() + .asLong(); + long positionKey = nbt.getLong("LastKnownPosition"); + newPosition = positionInTag != positionKey; + + super.read(nbt, clientPacket); + frequencyFirst = Frequency.of(ItemStack.of(nbt.getCompound("FrequencyFirst"))); + frequencyLast = Frequency.of(ItemStack.of(nbt.getCompound("FrequencyLast"))); + } + + public void setFrequency(boolean first, ItemStack stack) { + stack = stack.copy(); + stack.setCount(1); + ItemStack toCompare = first ? frequencyFirst.getStack() : frequencyLast.getStack(); + boolean changed = !ItemStack.isSame(stack, toCompare) || !ItemStack.tagMatches(stack, toCompare); + + if (changed) + getHandler().removeFromNetwork(getWorld(), this); + + if (first) + frequencyFirst = Frequency.of(stack); + else + frequencyLast = Frequency.of(stack); + + if (!changed) + return; + + blockEntity.sendData(); + getHandler().addToNetwork(getWorld(), this); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + private RedstoneLinkNetworkHandler getHandler() { + return Create.REDSTONE_LINK_NETWORK_HANDLER; + } + + public static class SlotPositioning { + Function> offsets; + Function rotation; + float scale; + + public SlotPositioning(Function> offsetsForState, + Function rotationForState) { + offsets = offsetsForState; + rotation = rotationForState; + scale = 1; + } + + public SlotPositioning scale(float scale) { + this.scale = scale; + return this; + } + + } + + public boolean testHit(Boolean first, Vec3 hit) { + BlockState state = blockEntity.getBlockState(); + Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos())); + return (first ? firstSlot : secondSlot).testHit(state, localHit); + } + + @Override + public boolean isAlive() { + Level level = getWorld(); + BlockPos pos = getPos(); + if (blockEntity.isChunkUnloaded()) + return false; + if (blockEntity.isRemoved()) + return false; + if (!level.isLoaded(pos)) + return false; + return level.getBlockEntity(pos) == blockEntity; + } + + @Override + public BlockPos getLocation() { + return getPos(); + } + + @Override + public String getClipboardKey() { + return "Frequencies"; + } + + @Override + public boolean writeToClipboard(CompoundTag tag, Direction side) { + tag.put("First", frequencyFirst.getStack() + .save(new CompoundTag())); + tag.put("Last", frequencyLast.getStack() + .save(new CompoundTag())); + return true; + } + + @Override + public boolean readFromClipboard(CompoundTag tag, Player player, Direction side, boolean simulate) { + if (!tag.contains("First") || !tag.contains("Last")) + return false; + if (simulate) + return true; + setFrequency(true, ItemStack.of(tag.getCompound("First"))); + setFrequency(false, ItemStack.of(tag.getCompound("Last"))); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/link/LinkHandler.java b/src/main/java/com/simibubi/create/content/redstone/link/LinkHandler.java new file mode 100644 index 0000000000..ebf115239a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/LinkHandler.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.redstone.link; + +import java.util.Arrays; + +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.RaycastHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class LinkHandler { + + @SubscribeEvent + public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) { + Level world = event.getWorld(); + BlockPos pos = event.getPos(); + Player player = event.getPlayer(); + InteractionHand hand = event.getHand(); + + if (player.isShiftKeyDown() || player.isSpectator()) + return; + + LinkBehaviour behaviour = BlockEntityBehaviour.get(world, pos, LinkBehaviour.TYPE); + if (behaviour == null) + return; + + ItemStack heldItem = player.getItemInHand(hand); + BlockHitResult ray = RaycastHelper.rayTraceRange(world, player, 10); + if (ray == null) + return; + if (AllItems.LINKED_CONTROLLER.isIn(heldItem)) + return; + if (AllItems.WRENCH.isIn(heldItem)) + return; + + boolean fakePlayer = player instanceof FakePlayer; + boolean fakePlayerChoice = false; + + if (fakePlayer) { + BlockState blockState = world.getBlockState(pos); + Vec3 localHit = ray.getLocation() + .subtract(Vec3.atLowerCornerOf(pos)) + .add(Vec3.atLowerCornerOf(ray.getDirection() + .getNormal()) + .scale(.25f)); + fakePlayerChoice = localHit.distanceToSqr(behaviour.firstSlot.getLocalOffset(blockState)) > localHit + .distanceToSqr(behaviour.secondSlot.getLocalOffset(blockState)); + } + + for (boolean first : Arrays.asList(false, true)) { + if (behaviour.testHit(first, ray.getLocation()) || fakePlayer && fakePlayerChoice == first) { + if (event.getSide() != LogicalSide.CLIENT) + behaviour.setFrequency(first, heldItem); + event.setCanceled(true); + event.setCancellationResult(InteractionResult.SUCCESS); + world.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/link/LinkRenderer.java b/src/main/java/com/simibubi/create/content/redstone/link/LinkRenderer.java new file mode 100644 index 0000000000..9a2d335fdd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/LinkRenderer.java @@ -0,0 +1,109 @@ +package com.simibubi.create.content.redstone.link; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.datafixers.util.Pair; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxRenderer; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class LinkRenderer { + + public static void tick() { + Minecraft mc = Minecraft.getInstance(); + HitResult target = mc.hitResult; + if (target == null || !(target instanceof BlockHitResult)) + return; + + BlockHitResult result = (BlockHitResult) target; + ClientLevel world = mc.level; + BlockPos pos = result.getBlockPos(); + + LinkBehaviour behaviour = BlockEntityBehaviour.get(world, pos, LinkBehaviour.TYPE); + if (behaviour == null) + return; + + Component freq1 = CreateLang.translateDirect("logistics.firstFrequency"); + Component freq2 = CreateLang.translateDirect("logistics.secondFrequency"); + + for (boolean first : Iterate.trueAndFalse) { + AABB bb = new AABB(Vec3.ZERO, Vec3.ZERO).inflate(.25f); + Component label = first ? freq1 : freq2; + boolean hit = behaviour.testHit(first, target.getLocation()); + ValueBoxTransform transform = first ? behaviour.firstSlot : behaviour.secondSlot; + + ValueBox box = new ValueBox(label, bb, pos).passive(!hit); + boolean empty = behaviour.getNetworkKey() + .get(first) + .getStack() + .isEmpty(); + + if (!empty) + box.wideOutline(); + + CatnipClient.OUTLINER.showOutline(Pair.of(Boolean.valueOf(first), pos), box.transform(transform)) + .highlightFace(result.getDirection()); + + if (!hit) + continue; + + List tip = new ArrayList<>(); + tip.add(label.copy()); + tip.add( + CreateLang.translateDirect(empty ? "logistics.filter.click_to_set" : "logistics.filter.click_to_replace")); + CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip); + } + } + + public static void renderOnBlockEntity(SmartBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + if (be == null || be.isRemoved()) + return; + + Entity cameraEntity = Minecraft.getInstance().cameraEntity; + float max = AllConfigs.client().filterItemRenderDistance.getF(); + if (!be.isVirtual() && cameraEntity != null && cameraEntity.position() + .distanceToSqr(VecHelper.getCenterOf(be.getBlockPos())) > (max * max)) + return; + + LinkBehaviour behaviour = be.getBehaviour(LinkBehaviour.TYPE); + if (behaviour == null) + return; + + for (boolean first : Iterate.trueAndFalse) { + ValueBoxTransform transform = first ? behaviour.firstSlot : behaviour.secondSlot; + ItemStack stack = first ? behaviour.frequencyFirst.getStack() : behaviour.frequencyLast.getStack(); + + ms.pushPose(); + transform.transform(be.getBlockState(), ms); + ValueBoxRenderer.renderItemIntoValueBox(stack, ms, buffer, light, overlay); + ms.popPose(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkBlock.java b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlock.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkBlock.java rename to src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlock.java index 79a325e90d..c86033661f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.link; import java.util.Random; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.WrenchableDirectionalBlock; import net.createmod.catnip.utility.Iterate; @@ -30,7 +30,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements ITE { +public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements IBE { public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public static final BooleanProperty RECEIVER = BooleanProperty.create("receiver"); @@ -85,7 +85,7 @@ public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements ITE worldIn.setBlock(pos, state.cycle(POWERED), 2); int transmit = power; - withTileEntityDo(worldIn, pos, te -> te.transmit(transmit)); + withBlockEntityDo(worldIn, pos, be -> be.transmit(transmit)); } private int getPower(Level worldIn, BlockPos pos) { @@ -113,7 +113,7 @@ public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements ITE public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) { if (!state.getValue(RECEIVER)) return 0; - return getTileEntityOptional(blockAccess, pos).map(RedstoneLinkTileEntity::getReceivedSignal) + return getBlockEntityOptional(blockAccess, pos).map(RedstoneLinkBlockEntity::getReceivedSignal) .orElse(0); } @@ -135,12 +135,12 @@ public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements ITE if (worldIn.isClientSide) return InteractionResult.SUCCESS; - return onTileEntityUse(worldIn, pos, te -> { + return onBlockEntityUse(worldIn, pos, be -> { Boolean wasReceiver = state.getValue(RECEIVER); boolean blockPowered = worldIn.hasNeighborSignal(pos); worldIn.setBlock(pos, state.cycle(RECEIVER) .setValue(POWERED, blockPowered), 3); - te.transmit(wasReceiver ? 0 : getPower(worldIn, pos)); + be.transmit(wasReceiver ? 0 : getPower(worldIn, pos)); return InteractionResult.SUCCESS; }); } @@ -189,13 +189,13 @@ public class RedstoneLinkBlock extends WrenchableDirectionalBlock implements ITE } @Override - public Class getTileEntityClass() { - return RedstoneLinkTileEntity.class; + public Class getBlockEntityClass() { + return RedstoneLinkBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.REDSTONE_LINK.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.REDSTONE_LINK.get(); } } diff --git a/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlockEntity.java new file mode 100644 index 0000000000..7b5b706d22 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkBlockEntity.java @@ -0,0 +1,129 @@ +package com.simibubi.create.content.redstone.link; + +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class RedstoneLinkBlockEntity extends SmartBlockEntity { + + private boolean receivedSignalChanged; + private int receivedSignal; + private int transmittedSignal; + private LinkBehaviour link; + private boolean transmitter; + + public RedstoneLinkBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void addBehavioursDeferred(List behaviours) { + createLink(); + behaviours.add(link); + } + + protected void createLink() { + Pair slots = + ValueBoxTransform.Dual.makeSlots(RedstoneLinkFrequencySlot::new); + link = transmitter ? LinkBehaviour.transmitter(this, slots, this::getSignal) + : LinkBehaviour.receiver(this, slots, this::setSignal); + } + + public int getSignal() { + return transmittedSignal; + } + + public void setSignal(int power) { + if (receivedSignal != power) + receivedSignalChanged = true; + receivedSignal = power; + } + + public void transmit(int strength) { + transmittedSignal = strength; + if (link != null) + link.notifySignalChange(); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putBoolean("Transmitter", transmitter); + compound.putInt("Receive", getReceivedSignal()); + compound.putBoolean("ReceivedChanged", receivedSignalChanged); + compound.putInt("Transmit", transmittedSignal); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + transmitter = compound.getBoolean("Transmitter"); + super.read(compound, clientPacket); + + receivedSignal = compound.getInt("Receive"); + receivedSignalChanged = compound.getBoolean("ReceivedChanged"); + if (level == null || level.isClientSide || !link.newPosition) + transmittedSignal = compound.getInt("Transmit"); + } + + @Override + public void tick() { + super.tick(); + + if (isTransmitterBlock() != transmitter) { + transmitter = isTransmitterBlock(); + LinkBehaviour prevlink = link; + removeBehaviour(LinkBehaviour.TYPE); + createLink(); + link.copyItemsFrom(prevlink); + attachBehaviourLate(link); + } + + if (transmitter) + return; + if (level.isClientSide) + return; + + BlockState blockState = getBlockState(); + if (!AllBlocks.REDSTONE_LINK.has(blockState)) + return; + + if ((getReceivedSignal() > 0) != blockState.getValue(RedstoneLinkBlock.POWERED)) { + receivedSignalChanged = true; + level.setBlockAndUpdate(worldPosition, blockState.cycle(RedstoneLinkBlock.POWERED)); + } + + if (receivedSignalChanged) { + Direction attachedFace = blockState.getValue(RedstoneLinkBlock.FACING) + .getOpposite(); + BlockPos attachedPos = worldPosition.relative(attachedFace); + level.blockUpdated(worldPosition, level.getBlockState(worldPosition) + .getBlock()); + level.blockUpdated(attachedPos, level.getBlockState(attachedPos) + .getBlock()); + receivedSignalChanged = false; + } + } + + protected Boolean isTransmitterBlock() { + return !getBlockState().getValue(RedstoneLinkBlock.RECEIVER); + } + + public int getReceivedSignal() { + return receivedSignal; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkFrequencySlot.java b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkFrequencySlot.java similarity index 78% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkFrequencySlot.java rename to src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkFrequencySlot.java index df07b1df0a..47d90514c6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkFrequencySlot.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkFrequencySlot.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.link; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.math.AngleHelper; @@ -21,13 +21,13 @@ public class RedstoneLinkFrequencySlot extends ValueBoxTransform.Dual { Vec3 vertical = VecHelper.voxelSpace(10f, 2.5f, 5.5f); @Override - protected Vec3 getLocalOffset(BlockState state) { + public Vec3 getLocalOffset(BlockState state) { Direction facing = state.getValue(RedstoneLinkBlock.FACING); - Vec3 location = vertical; + Vec3 location = VecHelper.voxelSpace(8f, 3.01f, 5.5f); if (facing.getAxis() .isHorizontal()) { - location = horizontal; + location = VecHelper.voxelSpace(8f, 5.5f, 3.01f); if (isFirst()) location = location.add(0, 5 / 16f, 0); return rotateHorizontally(state, location); @@ -40,7 +40,7 @@ public class RedstoneLinkFrequencySlot extends ValueBoxTransform.Dual { } @Override - protected void rotate(BlockState state, PoseStack ms) { + public void rotate(BlockState state, PoseStack ms) { Direction facing = state.getValue(RedstoneLinkBlock.FACING); float yRot = facing.getAxis() .isVertical() ? 0 : AngleHelper.horizontalAngle(facing) + 180; @@ -51,8 +51,8 @@ public class RedstoneLinkFrequencySlot extends ValueBoxTransform.Dual { } @Override - protected float getScale() { - return .5f; + public float getScale() { + return .4975f; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkGenerator.java b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkGenerator.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkGenerator.java index 769138d437..24ca6ae8f8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.link; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; diff --git a/src/main/java/com/simibubi/create/content/logistics/RedstoneLinkNetworkHandler.java b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkNetworkHandler.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/RedstoneLinkNetworkHandler.java rename to src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkNetworkHandler.java index f553bfd2f5..560e33c5ac 100644 --- a/src/main/java/com/simibubi/create/content/logistics/RedstoneLinkNetworkHandler.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/RedstoneLinkNetworkHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics; +package com.simibubi.create.content.redstone.link; import java.util.HashMap; import java.util.IdentityHashMap; @@ -9,15 +9,13 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import com.simibubi.create.Create; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.WorldHelper; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; public class RedstoneLinkNetworkHandler { @@ -112,10 +110,7 @@ public class RedstoneLinkNetworkHandler { iterator.remove(); continue; } - if (!(world instanceof Level level) || !level.isLoaded(other.getLocation())) { - iterator.remove(); - continue; - } + if (!withinRange(actor, other)) continue; @@ -142,7 +137,7 @@ public class RedstoneLinkNetworkHandler { if (from == to) return true; return from.getLocation() - .closerThan(to.getLocation(), AllConfigs.SERVER.logistics.linkRange.get()); + .closerThan(to.getLocation(), AllConfigs.server().logistics.linkRange.get()); } public Map, Set> networksIn(LevelAccessor world) { diff --git a/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlock.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlock.java new file mode 100644 index 0000000000..a2b793a585 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlock.java @@ -0,0 +1,108 @@ +package com.simibubi.create.content.redstone.link.controller; + +import java.util.ArrayList; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LecternBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +public class LecternControllerBlock extends LecternBlock + implements IBE, ISpecialBlockItemRequirement { + + public LecternControllerBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(HAS_BOOK, true)); + } + + @Override + public Class getBlockEntityClass() { + return LecternControllerBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.LECTERN_CONTROLLER.get(); + } + + @Override + public BlockEntity newBlockEntity(BlockPos p_153573_, BlockState p_153574_) { + return IBE.super.newBlockEntity(p_153573_, p_153574_); + } + + @Override + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + if (!player.isShiftKeyDown() && LecternControllerBlockEntity.playerInRange(player, world, pos)) { + if (!world.isClientSide) + withBlockEntityDo(world, pos, be -> be.tryStartUsing(player)); + return InteractionResult.SUCCESS; + } + + if (player.isShiftKeyDown()) { + if (!world.isClientSide) + replaceWithLectern(state, world, pos); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { + if (!state.is(newState.getBlock())) { + if (!world.isClientSide) + withBlockEntityDo(world, pos, be -> be.dropController(state)); + + super.onRemove(state, world, pos, newState, isMoving); + } + } + + @Override + public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { + return 15; + } + + public void replaceLectern(BlockState lecternState, Level world, BlockPos pos, ItemStack controller) { + world.setBlockAndUpdate(pos, defaultBlockState().setValue(FACING, lecternState.getValue(FACING)) + .setValue(POWERED, lecternState.getValue(POWERED))); + withBlockEntityDo(world, pos, be -> be.setController(controller)); + } + + public void replaceWithLectern(BlockState state, Level world, BlockPos pos) { + AllSoundEvents.CONTROLLER_TAKE.playOnServer(world, pos); + world.setBlockAndUpdate(pos, Blocks.LECTERN.defaultBlockState() + .setValue(FACING, state.getValue(FACING)) + .setValue(POWERED, state.getValue(POWERED))); + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) { + return Blocks.LECTERN.getCloneItemStack(state, target, world, pos, player); + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + ArrayList requiredItems = new ArrayList<>(); + requiredItems.add(new ItemStack(Blocks.LECTERN)); + requiredItems.add(new ItemStack(AllItems.LINKED_CONTROLLER.get())); + return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, requiredItems); + } +} diff --git a/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlockEntity.java new file mode 100644 index 0000000000..1c0cd29ba7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerBlockEntity.java @@ -0,0 +1,179 @@ +package com.simibubi.create.content.redstone.link.controller; + +import java.util.List; +import java.util.UUID; + +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.fml.DistExecutor; + +public class LecternControllerBlockEntity extends SmartBlockEntity { + + private ItemStack controller; + private UUID user; + private UUID prevUser; // used only on client + private boolean deactivatedThisTick; // used only on server + + public LecternControllerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + super.write(compound, clientPacket); + compound.put("Controller", controller.save(new CompoundTag())); + if (user != null) + compound.putUUID("User", user); + } + + @Override + public void writeSafe(CompoundTag compound) { + super.writeSafe(compound); + compound.put("Controller", controller.save(new CompoundTag())); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + controller = ItemStack.of(compound.getCompound("Controller")); + user = compound.hasUUID("User") ? compound.getUUID("User") : null; + } + + public ItemStack getController() { + return controller; + } + + public boolean hasUser() { return user != null; } + + public boolean isUsedBy(Player player) { + return hasUser() && user.equals(player.getUUID()); + } + + public void tryStartUsing(Player player) { + if (!deactivatedThisTick && !hasUser() && !playerIsUsingLectern(player) && playerInRange(player, level, worldPosition)) + startUsing(player); + } + + public void tryStopUsing(Player player) { + if (isUsedBy(player)) + stopUsing(player); + } + + private void startUsing(Player player) { + user = player.getUUID(); + player.getPersistentData().putBoolean("IsUsingLecternController", true); + sendData(); + } + + private void stopUsing(Player player) { + user = null; + if (player != null) + player.getPersistentData().remove("IsUsingLecternController"); + deactivatedThisTick = true; + sendData(); + } + + public static boolean playerIsUsingLectern(Player player) { + return player.getPersistentData().contains("IsUsingLecternController"); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::tryToggleActive); + prevUser = user; + } + + if (!level.isClientSide) { + deactivatedThisTick = false; + + if (!(level instanceof ServerLevel)) + return; + if (user == null) + return; + + Entity entity = ((ServerLevel) level).getEntity(user); + if (!(entity instanceof Player)) { + stopUsing(null); + return; + } + + Player player = (Player) entity; + if (!playerInRange(player, level, worldPosition) || !playerIsUsingLectern(player)) + stopUsing(player); + } + } + + @OnlyIn(Dist.CLIENT) + private void tryToggleActive() { + if (user == null && Minecraft.getInstance().player.getUUID().equals(prevUser)) { + LinkedControllerClientHandler.deactivateInLectern(); + } else if (prevUser == null && Minecraft.getInstance().player.getUUID().equals(user)) { + LinkedControllerClientHandler.activateInLectern(worldPosition); + } + } + + public void setController(ItemStack newController) { + controller = newController; + if (newController != null) { + AllSoundEvents.CONTROLLER_PUT.playOnServer(level, worldPosition); + } + } + + public void swapControllers(ItemStack stack, Player player, InteractionHand hand, BlockState state) { + ItemStack newController = stack.copy(); + stack.setCount(0); + if (player.getItemInHand(hand).isEmpty()) { + player.setItemInHand(hand, controller); + } else { + dropController(state); + } + setController(newController); + } + + public void dropController(BlockState state) { + Entity playerEntity = ((ServerLevel) level).getEntity(user); + if (playerEntity instanceof Player) + stopUsing((Player) playerEntity); + + Direction dir = state.getValue(LecternControllerBlock.FACING); + double x = worldPosition.getX() + 0.5 + 0.25*dir.getStepX(); + double y = worldPosition.getY() + 1; + double z = worldPosition.getZ() + 0.5 + 0.25*dir.getStepZ(); + ItemEntity itementity = new ItemEntity(level, x, y, z, controller.copy()); + itementity.setDefaultPickUpDelay(); + level.addFreshEntity(itementity); + controller = null; + } + + public static boolean playerInRange(Player player, Level world, BlockPos pos) { + //double modifier = world.isRemote ? 0 : 1.0; + double reach = 0.4*player.getAttributeValue(ForgeMod.REACH_DISTANCE.get());// + modifier; + return player.distanceToSqr(Vec3.atCenterOf(pos)) < reach*reach; + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerRenderer.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerRenderer.java new file mode 100644 index 0000000000..20f42d619a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LecternControllerRenderer.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.redstone.link.controller; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; +import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; + +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; + +public class LecternControllerRenderer extends SafeBlockEntityRenderer { + + public LecternControllerRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(LecternControllerBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + ItemStack stack = AllItems.LINKED_CONTROLLER.asStack(); + TransformType transformType = TransformType.NONE; + CustomRenderedItemModel mainModel = (CustomRenderedItemModel) Minecraft.getInstance() + .getItemRenderer() + .getModel(stack, be.getLevel(), null, 0); + PartialItemModelRenderer renderer = PartialItemModelRenderer.of(stack, transformType, ms, buffer, overlay); + boolean active = be.hasUser(); + boolean renderDepression = be.isUsedBy(Minecraft.getInstance().player); + + Direction facing = be.getBlockState().getValue(LecternControllerBlock.FACING); + TransformStack msr = TransformStack.cast(ms); + + ms.pushPose(); + msr.translate(0.5, 1.45, 0.5); + msr.rotateY(AngleHelper.horizontalAngle(facing) - 90); + msr.translate(0.28, 0, 0); + msr.rotateZ(-22.0); + LinkedControllerItemRenderer.renderInLectern(stack, mainModel, renderer, transformType, ms, light, active, renderDepression); + ms.popPose(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerBindPacket.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerBindPacket.java similarity index 80% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerBindPacket.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerBindPacket.java index 2af7d85552..5c9e790ff9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerBindPacket.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerBindPacket.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; +import com.simibubi.create.content.redstone.link.LinkBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; @@ -39,7 +39,7 @@ public class LinkedControllerBindPacket extends LinkedControllerPacketBase { return; ItemStackHandler frequencyItems = LinkedControllerItem.getFrequencyItems(heldItem); - LinkBehaviour linkBehaviour = TileEntityBehaviour.get(player.level, linkLocation, LinkBehaviour.TYPE); + LinkBehaviour linkBehaviour = BlockEntityBehaviour.get(player.level, linkLocation, LinkBehaviour.TYPE); if (linkBehaviour == null) return; @@ -52,6 +52,6 @@ public class LinkedControllerBindPacket extends LinkedControllerPacketBase { } @Override - protected void handleLectern(ServerPlayer player, LecternControllerTileEntity lectern) {} + protected void handleLectern(ServerPlayer player, LecternControllerBlockEntity lectern) {} } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerClientHandler.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerClientHandler.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerClientHandler.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerClientHandler.java index 696e0a219b..6629198243 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerClientHandler.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerClientHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import java.util.ArrayList; import java.util.Collection; @@ -12,15 +12,16 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; +import com.simibubi.create.content.redstone.link.LinkBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.utility.ControlsUtil; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.CatnipClient; -import net.createmod.catnip.utility.FontHelper; +import net.createmod.catnip.utility.FontHelper.Palette; import net.createmod.catnip.utility.lang.Components; import net.minecraft.ChatFormatting; import net.minecraft.client.KeyMapping; @@ -90,11 +91,11 @@ public class LinkedControllerClientHandler { selectedLocation = BlockPos.ZERO; if (inLectern()) - AllPackets.channel.sendToServer(new LinkedControllerStopLecternPacket(lecternPos)); + AllPackets.getChannel().sendToServer(new LinkedControllerStopLecternPacket(lecternPos)); lecternPos = null; if (!currentlyPressed.isEmpty()) - AllPackets.channel.sendToServer(new LinkedControllerInputPacket(currentlyPressed, false)); + AllPackets.getChannel().sendToServer(new LinkedControllerInputPacket(currentlyPressed, false)); currentlyPressed.clear(); LinkedControllerItemRenderer.resetButtons(); @@ -128,8 +129,8 @@ public class LinkedControllerClientHandler { } if (inLectern() && AllBlocks.LECTERN_CONTROLLER.get() - .getTileEntityOptional(mc.level, lecternPos) - .map(te -> !te.isUsedBy(mc.player)) + .getBlockEntityOptional(mc.level, lecternPos) + .map(be -> !be.isUsedBy(mc.player)) .orElse(true)) { deactivateInLectern(); return; @@ -163,13 +164,13 @@ public class LinkedControllerClientHandler { if (MODE == Mode.ACTIVE) { // Released Keys if (!releasedKeys.isEmpty()) { - AllPackets.channel.sendToServer(new LinkedControllerInputPacket(releasedKeys, false, lecternPos)); + AllPackets.getChannel().sendToServer(new LinkedControllerInputPacket(releasedKeys, false, lecternPos)); AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .5f, true); } // Newly Pressed Keys if (!newKeys.isEmpty()) { - AllPackets.channel.sendToServer(new LinkedControllerInputPacket(newKeys, true, lecternPos)); + AllPackets.getChannel().sendToServer(new LinkedControllerInputPacket(newKeys, true, lecternPos)); packetCooldown = PACKET_RATE; AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .75f, true); } @@ -177,7 +178,7 @@ public class LinkedControllerClientHandler { // Keepalive Pressed Keys if (packetCooldown == 0) { if (!pressedKeys.isEmpty()) { - AllPackets.channel.sendToServer(new LinkedControllerInputPacket(pressedKeys, true, lecternPos)); + AllPackets.getChannel().sendToServer(new LinkedControllerInputPacket(pressedKeys, true, lecternPos)); packetCooldown = PACKET_RATE; } } @@ -193,9 +194,9 @@ public class LinkedControllerClientHandler { .lineWidth(1 / 16f); for (Integer integer : newKeys) { - LinkBehaviour linkBehaviour = TileEntityBehaviour.get(mc.level, selectedLocation, LinkBehaviour.TYPE); + LinkBehaviour linkBehaviour = BlockEntityBehaviour.get(mc.level, selectedLocation, LinkBehaviour.TYPE); if (linkBehaviour != null) { - AllPackets.channel.sendToServer(new LinkedControllerBindPacket(integer, selectedLocation)); + AllPackets.getChannel().sendToServer(new LinkedControllerBindPacket(integer, selectedLocation)); CreateLang.translate("linked_controller.key_bound", controls.get(integer) .getTranslatedKeyMessage() .getString()) @@ -235,8 +236,8 @@ public class LinkedControllerClientHandler { List list = new ArrayList<>(); list.add(CreateLang.translateDirect("linked_controller.bind_mode") .withStyle(ChatFormatting.GOLD)); - list.addAll(FontHelper.cutTextComponent(CreateLang.translateDirect("linked_controller.press_keybind", keys), - ChatFormatting.GRAY, ChatFormatting.GRAY)); + list.addAll(TooltipHelper.cutTextComponent(CreateLang.translateDirect("linked_controller.press_keybind", keys), + Palette.ALL_GRAY)); int width = 0; int height = list.size() * mc.font.lineHeight; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerInputPacket.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerInputPacket.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerInputPacket.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerInputPacket.java index 48d8f886df..0eabc73a43 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerInputPacket.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerInputPacket.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import java.util.ArrayList; import java.util.Collection; @@ -44,7 +44,7 @@ public class LinkedControllerInputPacket extends LinkedControllerPacketBase { } @Override - protected void handleLectern(ServerPlayer player, LecternControllerTileEntity lectern) { + protected void handleLectern(ServerPlayer player, LecternControllerBlockEntity lectern) { if (lectern.isUsedBy(player)) handleItem(player, lectern.getController()); } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItem.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItem.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItem.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItem.java index 6a6d65910d..bf4bda9f8b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItem.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItem.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import java.util.function.Consumer; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler; -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler.Frequency; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler.Frequency; import com.simibubi.create.foundation.item.render.SimpleCustomRenderer; import net.createmod.catnip.utility.Couple; @@ -53,8 +53,8 @@ public class LinkedControllerItem extends Item implements MenuProvider { if (player.isShiftKeyDown()) { if (AllBlocks.LECTERN_CONTROLLER.has(hitState)) { if (!world.isClientSide) - AllBlocks.LECTERN_CONTROLLER.get().withTileEntityDo(world, pos, te -> - te.swapControllers(stack, player, ctx.getHand(), hitState)); + AllBlocks.LECTERN_CONTROLLER.get().withBlockEntityDo(world, pos, be -> + be.swapControllers(stack, player, ctx.getHand(), hitState)); return InteractionResult.SUCCESS; } } else { @@ -133,7 +133,7 @@ public class LinkedControllerItem extends Item implements MenuProvider { @Override public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { ItemStack heldItem = player.getMainHandItem(); - return LinkedControllerContainer.create(id, inv, heldItem); + return LinkedControllerMenu.create(id, inv, heldItem); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItemRenderer.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItemRenderer.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItemRenderer.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItemRenderer.java index 8746f7b685..232b23bd17 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerItemRenderer.java @@ -1,11 +1,14 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import java.util.Vector; +import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler.Mode; +import com.simibubi.create.Create; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerClientHandler.Mode; +import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; @@ -21,7 +24,10 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.item.ItemStack; -public class LinkedControllerItemRenderer extends CustomRenderedItemModelRenderer { +public class LinkedControllerItemRenderer extends CustomRenderedItemModelRenderer { + + protected static final PartialModel POWERED = new PartialModel(Create.asResource("item/linked_controller/powered")); + protected static final PartialModel BUTTON = new PartialModel(Create.asResource("item/linked_controller/button")); static LerpedFloat equipProgress; static Vector buttons; @@ -61,25 +67,25 @@ public class LinkedControllerItemRenderer extends CustomRenderedItemModelRendere } @Override - protected void render(ItemStack stack, LinkedControllerModel model, PartialItemModelRenderer renderer, + protected void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { renderNormal(stack, model, renderer, transformType, ms, light); } - protected static void renderNormal(ItemStack stack, LinkedControllerModel model, + protected static void renderNormal(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, PoseStack ms, int light) { render(stack, model, renderer, transformType, ms, light, RenderType.NORMAL, false, false); } - public static void renderInLectern(ItemStack stack, LinkedControllerModel model, + public static void renderInLectern(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, PoseStack ms, int light, boolean active, boolean renderDepression) { render(stack, model, renderer, transformType, ms, light, RenderType.LECTERN, active, renderDepression); } - protected static void render(ItemStack stack, LinkedControllerModel model, + protected static void render(ItemStack stack, CustomRenderedItemModel model, PartialItemModelRenderer renderer, ItemTransforms.TransformType transformType, PoseStack ms, int light, RenderType renderType, boolean active, boolean renderDepression) { float pt = AnimationTickHolder.getPartialTicks(); @@ -119,14 +125,14 @@ public class LinkedControllerItemRenderer extends CustomRenderedItemModelRendere renderDepression = true; } - renderer.render(active ? model.getPartial("powered") : model.getOriginalModel(), light); + renderer.render(active ? POWERED.get() : model.getOriginalModel(), light); if (!active) { ms.popPose(); return; } - BakedModel button = model.getPartial("button"); + BakedModel button = BUTTON.get(); float s = 1 / 16f; float b = s * -.75f; int index = 0; @@ -168,11 +174,6 @@ public class LinkedControllerItemRenderer extends CustomRenderedItemModelRendere ms.popPose(); } - @Override - public LinkedControllerModel createModel(BakedModel originalModel) { - return new LinkedControllerModel(originalModel); - } - protected enum RenderType { NORMAL, LECTERN; } diff --git a/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerMenu.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerMenu.java new file mode 100644 index 0000000000..51bb6f9053 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerMenu.java @@ -0,0 +1,79 @@ +package com.simibubi.create.content.redstone.link.controller; + +import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.foundation.gui.menu.GhostItemMenu; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class LinkedControllerMenu extends GhostItemMenu { + + public LinkedControllerMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public LinkedControllerMenu(MenuType type, int id, Inventory inv, ItemStack filterItem) { + super(type, id, inv, filterItem); + } + + public static LinkedControllerMenu create(int id, Inventory inv, ItemStack filterItem) { + return new LinkedControllerMenu(AllMenuTypes.LINKED_CONTROLLER.get(), id, inv, filterItem); + } + + @Override + protected ItemStack createOnClient(FriendlyByteBuf extraData) { + return extraData.readItem(); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return LinkedControllerItem.getFrequencyItems(contentHolder); + } + + @Override + protected void addSlots() { + addPlayerSlots(8, 131); + + int x = 12; + int y = 34; + int slot = 0; + + for (int column = 0; column < 6; column++) { + for (int row = 0; row < 2; ++row) + addSlot(new SlotItemHandler(ghostInventory, slot++, x, y + row * 18)); + x += 24; + if (column == 3) + x += 11; + } + } + + @Override + protected void saveData(ItemStack contentHolder) { + contentHolder.getOrCreateTag() + .put("Items", ghostInventory.serializeNBT()); + } + + @Override + protected boolean allowRepeats() { + return true; + } + + @Override + public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { + if (slotId == playerInventory.selected && clickTypeIn != ClickType.THROW) + return; + super.clicked(slotId, dragType, clickTypeIn, player); + } + + @Override + public boolean stillValid(Player playerIn) { + return playerInventory.getSelected() == contentHolder; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerPacketBase.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerPacketBase.java similarity index 77% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerPacketBase.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerPacketBase.java index 2f1cb8d94b..0b07397774 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerPacketBase.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerPacketBase.java @@ -1,6 +1,4 @@ -package com.simibubi.create.content.logistics.item; - -import java.util.function.Supplier; +package com.simibubi.create.content.redstone.link.controller; import com.simibubi.create.AllItems; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -41,17 +39,17 @@ public abstract class LinkedControllerPacketBase extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) return; if (inLectern()) { - BlockEntity te = player.level.getBlockEntity(lecternPos); - if (!(te instanceof LecternControllerTileEntity)) + BlockEntity be = player.level.getBlockEntity(lecternPos); + if (!(be instanceof LecternControllerBlockEntity)) return; - handleLectern(player, (LecternControllerTileEntity) te); + handleLectern(player, (LecternControllerBlockEntity) be); } else { ItemStack controller = player.getMainHandItem(); if (!AllItems.LINKED_CONTROLLER.isIn(controller)) { @@ -62,11 +60,10 @@ public abstract class LinkedControllerPacketBase extends SimplePacketBase { handleItem(player, controller); } }); - - context.get().setPacketHandled(true); + return true; } protected abstract void handleItem(ServerPlayer player, ItemStack heldItem); - protected abstract void handleLectern(ServerPlayer player, LecternControllerTileEntity lectern); + protected abstract void handleLectern(ServerPlayer player, LecternControllerBlockEntity lectern); } diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerScreen.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerScreen.java index 97aaabf2ec..08e7db7cdb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerScreen.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; @@ -10,7 +10,7 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.utility.ControlsUtil; import com.simibubi.create.foundation.utility.CreateLang; @@ -22,7 +22,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class LinkedControllerScreen extends AbstractSimiContainerScreen { +public class LinkedControllerScreen extends AbstractSimiContainerScreen { protected AllGuiTextures background; private List extraAreas = Collections.emptyList(); @@ -30,8 +30,8 @@ public class LinkedControllerScreen extends AbstractSimiContainerScreenat(x + background.getWidth() - 4, y + background.getHeight() - 56, -200) diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerServerHandler.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerServerHandler.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerServerHandler.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerServerHandler.java index 3c4fdba4c0..9d01047742 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerServerHandler.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerServerHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import java.util.ArrayList; import java.util.Collection; @@ -10,10 +10,10 @@ import java.util.Map.Entry; import java.util.UUID; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.IRedstoneLinkable; -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler.Frequency; +import com.simibubi.create.content.redstone.link.IRedstoneLinkable; +import com.simibubi.create.content.redstone.link.LinkBehaviour; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler.Frequency; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.IntAttached; diff --git a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerStopLecternPacket.java b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerStopLecternPacket.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerStopLecternPacket.java rename to src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerStopLecternPacket.java index 03cbe95329..1281e0e496 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/LinkedControllerStopLecternPacket.java +++ b/src/main/java/com/simibubi/create/content/redstone/link/controller/LinkedControllerStopLecternPacket.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.item; +package com.simibubi.create.content.redstone.link.controller; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; @@ -16,7 +16,7 @@ public class LinkedControllerStopLecternPacket extends LinkedControllerPacketBas } @Override - protected void handleLectern(ServerPlayer player, LecternControllerTileEntity lectern) { + protected void handleLectern(ServerPlayer player, LecternControllerBlockEntity lectern) { lectern.tryStopUsing(player); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/DoubleFaceAttachedBlock.java b/src/main/java/com/simibubi/create/content/redstone/nixieTube/DoubleFaceAttachedBlock.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/DoubleFaceAttachedBlock.java rename to src/main/java/com/simibubi/create/content/redstone/nixieTube/DoubleFaceAttachedBlock.java index 0d7625ff73..adeca87f02 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/DoubleFaceAttachedBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/nixieTube/DoubleFaceAttachedBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.nixieTube; import javax.annotation.Nullable; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlock.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java rename to src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlock.java index 783083f953..7e76d8fd6c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlock.java @@ -1,24 +1,27 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.nixieTube; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; +import java.util.List; import java.util.Random; import java.util.function.BiConsumer; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.clipboard.ClipboardEntry; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -45,7 +48,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; public class NixieTubeBlock extends DoubleFaceAttachedBlock - implements ITE, IWrenchable, SimpleWaterloggedBlock, ISpecialBlockItemRequirement { + implements IBE, IWrenchable, SimpleWaterloggedBlock, ISpecialBlockItemRequirement { protected final DyeColor color; @@ -64,7 +67,7 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock return InteractionResult.PASS; ItemStack heldItem = player.getItemInHand(hand); - NixieTubeTileEntity nixie = getTileEntity(world, pos); + NixieTubeBlockEntity nixie = getBlockEntity(world, pos); if (nixie == null) return InteractionResult.PASS; @@ -76,20 +79,31 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock return InteractionResult.SUCCESS; } - boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName(); + boolean display = + heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllBlocks.CLIPBOARD.isIn(heldItem); DyeColor dye = DyeColor.getColor(heldItem); if (!display && dye == null) return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; CompoundTag tag = heldItem.getTagElement("display"); String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null; + if (AllBlocks.CLIPBOARD.isIn(heldItem)) { + List entries = ClipboardEntry.getLastViewedEntries(heldItem); + for (int i = 0; i < entries.size();) { + tagElement = Component.Serializer.toJson(entries.get(i).text); + break; + } + } + + if (world.isClientSide) + return InteractionResult.SUCCESS; + + String tagUsed = tagElement; walkNixies(world, pos, (currentPos, rowPosition) -> { if (display) - withTileEntityDo(world, currentPos, te -> te.displayCustomText(tagElement, rowPosition)); + withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagUsed, rowPosition)); if (dye != null) world.setBlockAndUpdate(currentPos, withColor(state, dye)); }); @@ -151,7 +165,7 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock } @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.ORANGE_NIXIE_TUBE.get() .asItem()); } @@ -231,9 +245,9 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock private void updateDisplayedRedstoneValue(BlockState state, Level worldIn, BlockPos pos) { if (worldIn.isClientSide) return; - withTileEntityDo(worldIn, pos, te -> { - if (te.reactsToRedstone()) - te.updateRedstoneStrength(getPower(worldIn, pos)); + withBlockEntityDo(worldIn, pos, be -> { + if (be.reactsToRedstone()) + be.updateRedstoneStrength(getPower(worldIn, pos)); }); } @@ -263,13 +277,13 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock } @Override - public Class getTileEntityClass() { - return NixieTubeTileEntity.class; + public Class getBlockEntityClass() { + return NixieTubeBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.NIXIE_TUBE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.NIXIE_TUBE.get(); } public DyeColor getColor() { diff --git a/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlockEntity.java new file mode 100644 index 0000000000..ee29b04ed6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeBlockEntity.java @@ -0,0 +1,174 @@ +package com.simibubi.create.content.redstone.nixieTube; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.Optional; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.trains.signal.SignalBlockEntity; +import com.simibubi.create.content.trains.signal.SignalBlockEntity.SignalState; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.DynamicComponent; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class NixieTubeBlockEntity extends SmartBlockEntity { + + private static final Couple EMPTY = Couple.create("", ""); + + private int redstoneStrength; + private Optional customText; + private int nixieIndex; + private Couple displayedStrings; + + private WeakReference cachedSignalTE; + public SignalState signalState; + + public NixieTubeBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + customText = Optional.empty(); + redstoneStrength = 0; + cachedSignalTE = new WeakReference<>(null); + } + + @Override + public void tick() { + super.tick(); + if (!level.isClientSide) + return; + + signalState = null; + SignalBlockEntity signalBlockEntity = cachedSignalTE.get(); + + if (signalBlockEntity == null || signalBlockEntity.isRemoved()) { + Direction facing = NixieTubeBlock.getFacing(getBlockState()); + BlockEntity blockEntity = level.getBlockEntity(worldPosition.relative(facing.getOpposite())); + if (blockEntity instanceof SignalBlockEntity signal) { + signalState = signal.getState(); + cachedSignalTE = new WeakReference<>(signal); + } + return; + } + + signalState = signalBlockEntity.getState(); + } + + @Override + public void initialize() { + if (level.isClientSide) + updateDisplayedStrings(); + } + + // + + public boolean reactsToRedstone() { + return customText.isEmpty(); + } + + public Couple getDisplayedStrings() { + if (displayedStrings == null) + return EMPTY; + return displayedStrings; + } + + public MutableComponent getFullText() { + return customText.map(DynamicComponent::get) + .orElse(Components.literal("" + redstoneStrength)); + } + + public void updateRedstoneStrength(int signalStrength) { + clearCustomText(); + redstoneStrength = signalStrength; + DisplayLinkBlock.notifyGatherers(level, worldPosition); + notifyUpdate(); + } + + public void displayCustomText(String tagElement, int nixiePositionInRow) { + if (tagElement == null) + return; + if (customText.filter(d -> d.sameAs(tagElement)) + .isPresent()) + return; + + DynamicComponent component = customText.orElseGet(DynamicComponent::new); + component.displayCustomText(level, worldPosition, tagElement); + customText = Optional.of(component); + nixieIndex = nixiePositionInRow; + DisplayLinkBlock.notifyGatherers(level, worldPosition); + notifyUpdate(); + } + + public void updateDisplayedStrings() { + if (signalState != null) + return; + customText.map(DynamicComponent::resolve) + .ifPresentOrElse( + fullText -> displayedStrings = + Couple.create(charOrEmpty(fullText, nixieIndex * 2), charOrEmpty(fullText, nixieIndex * 2 + 1)), + () -> displayedStrings = + Couple.create(redstoneStrength < 10 ? "0" : "1", String.valueOf(redstoneStrength % 10))); + } + + public void clearCustomText() { + nixieIndex = 0; + customText = Optional.empty(); + } + + public int getRedstoneStrength() { + return redstoneStrength; + } + + // + + @Override + protected void read(CompoundTag nbt, boolean clientPacket) { + super.read(nbt, clientPacket); + + if (nbt.contains("CustomText")) { + DynamicComponent component = customText.orElseGet(DynamicComponent::new); + component.read(level, worldPosition, nbt); + + if (component.isValid()) { + customText = Optional.of(component); + nixieIndex = nbt.getInt("CustomTextIndex"); + } else { + customText = Optional.empty(); + nixieIndex = 0; + } + } + + if (customText.isEmpty()) + redstoneStrength = nbt.getInt("RedstoneStrength"); + if (clientPacket) + updateDisplayedStrings(); + } + + @Override + protected void write(CompoundTag nbt, boolean clientPacket) { + super.write(nbt, clientPacket); + + if (customText.isPresent()) { + nbt.putInt("CustomTextIndex", nixieIndex); + customText.get() + .write(nbt); + } else + nbt.putInt("RedstoneStrength", redstoneStrength); + } + + private String charOrEmpty(String string, int index) { + return string.length() <= index ? " " : string.substring(index, index + 1); + } + + @Override + public void addBehaviours(List behaviours) {} + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeGenerator.java b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeGenerator.java similarity index 86% rename from src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeGenerator.java index c39fde187d..63e0277d06 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeGenerator.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.block.redstone; +package com.simibubi.create.content.redstone.nixieTube; -import com.simibubi.create.content.logistics.block.redstone.DoubleFaceAttachedBlock.DoubleAttachFace; +import com.simibubi.create.content.redstone.nixieTube.DoubleFaceAttachedBlock.DoubleAttachFace; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; diff --git a/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeRenderer.java b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeRenderer.java new file mode 100644 index 0000000000..bceefe2d9f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/nixieTube/NixieTubeRenderer.java @@ -0,0 +1,205 @@ +package com.simibubi.create.content.redstone.nixieTube; + +import java.util.Random; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.redstone.nixieTube.DoubleFaceAttachedBlock.DoubleAttachFace; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; +import com.simibubi.create.foundation.render.RenderTypes; +import com.simibubi.create.foundation.utility.DyeHelper; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.createmod.catnip.utility.theme.Color; +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.font.glyphs.BakedGlyph; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.MultiBufferSource.BufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Style; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class NixieTubeRenderer extends SafeBlockEntityRenderer { + + private static Random r = new Random(); + + public NixieTubeRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(NixieTubeBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + ms.pushPose(); + BlockState blockState = be.getBlockState(); + DoubleAttachFace face = blockState.getValue(NixieTubeBlock.FACE); + float yRot = AngleHelper.horizontalAngle(blockState.getValue(NixieTubeBlock.FACING)) - 90 + + (face == DoubleAttachFace.WALL_REVERSED ? 180 : 0); + float xRot = face == DoubleAttachFace.WALL ? -90 : face == DoubleAttachFace.WALL_REVERSED ? 90 : 0; + + TransformStack msr = TransformStack.cast(ms); + msr.centre() + .rotateY(yRot) + .rotateZ(xRot) + .unCentre(); + + if (be.signalState != null) { + renderAsSignal(be, partialTicks, ms, buffer, light, overlay); + ms.popPose(); + return; + } + + msr.centre(); + + float height = face == DoubleAttachFace.CEILING ? 5 : 3; + float scale = 1 / 20f; + + Couple s = be.getDisplayedStrings(); + DyeColor color = NixieTubeBlock.colorOf(be.getBlockState()); + + ms.pushPose(); + ms.translate(-4 / 16f, 0, 0); + ms.scale(scale, -scale, scale); + drawTube(ms, buffer, s.getFirst(), height, color); + ms.popPose(); + + ms.pushPose(); + ms.translate(4 / 16f, 0, 0); + ms.scale(scale, -scale, scale); + drawTube(ms, buffer, s.getSecond(), height, color); + ms.popPose(); + + ms.popPose(); + } + + public static void drawTube(PoseStack ms, MultiBufferSource buffer, String c, float height, DyeColor color) { + Font fontRenderer = Minecraft.getInstance().font; + float charWidth = fontRenderer.width(c); + float shadowOffset = .5f; + float flicker = r.nextFloat(); + Couple couple = DyeHelper.DYE_TABLE.get(color); + int brightColor = couple.getFirst(); + int darkColor = couple.getSecond(); + int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4); + + ms.pushPose(); + ms.translate((charWidth - shadowOffset) / -2f, -height, 0); + drawInWorldString(ms, buffer, c, flickeringBrightColor); + ms.pushPose(); + ms.translate(shadowOffset, shadowOffset, -1 / 16f); + drawInWorldString(ms, buffer, c, darkColor); + ms.popPose(); + ms.popPose(); + + ms.pushPose(); + ms.scale(-1, 1, 1); + ms.translate((charWidth - shadowOffset) / -2f, -height, 0); + drawInWorldString(ms, buffer, c, darkColor); + ms.pushPose(); + ms.translate(-shadowOffset, shadowOffset, -1 / 16f); + drawInWorldString(ms, buffer, c, Color.mixColors(darkColor, 0, .35f)); + ms.popPose(); + ms.popPose(); + } + + public static void drawInWorldString(PoseStack ms, MultiBufferSource buffer, String c, int color) { + Font fontRenderer = Minecraft.getInstance().font; + fontRenderer.drawInBatch(c, 0, 0, color, false, ms.last() + .pose(), buffer, false, 0, LightTexture.FULL_BRIGHT); + if (buffer instanceof BufferSource) { + BakedGlyph texturedglyph = fontRenderer.getFontSet(Style.DEFAULT_FONT) + .whiteGlyph(); + ((BufferSource) buffer).endBatch(texturedglyph.renderType(Font.DisplayMode.NORMAL)); + } + } + + private void renderAsSignal(NixieTubeBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + Direction facing = NixieTubeBlock.getFacing(blockState); + Vec3 observerVec = Minecraft.getInstance().cameraEntity.getEyePosition(partialTicks); + TransformStack msr = TransformStack.cast(ms); + + if (facing == Direction.DOWN) + msr.centre() + .rotateZ(180) + .unCentre(); + + boolean invertTubes = + facing == Direction.DOWN || blockState.getValue(NixieTubeBlock.FACE) == DoubleAttachFace.WALL_REVERSED; + + CachedPartialBuffers.partial(AllPartialModels.SIGNAL_PANEL, blockState) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + + ms.pushPose(); + ms.translate(1 / 2f, 7.5f / 16f, 1 / 2f); + float renderTime = WorldTickHolder.getRenderTime(be.getLevel()); + + for (boolean first : Iterate.trueAndFalse) { + Vec3 lampVec = Vec3.atCenterOf(be.getBlockPos()); + Vec3 diff = lampVec.subtract(observerVec); + + if (first && !be.signalState.isRedLight(renderTime)) + continue; + if (!first && !be.signalState.isGreenLight(renderTime) && !be.signalState.isYellowLight(renderTime)) + continue; + + boolean flip = first == invertTubes; + boolean yellow = be.signalState.isYellowLight(renderTime); + + ms.pushPose(); + ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0); + + if (diff.lengthSqr() < 96 * 96) { + boolean vert = first ^ facing.getAxis() + .isHorizontal(); + float longSide = yellow ? 1 : 4; + float longSideGlow = yellow ? 2 : 5.125f; + + CachedPartialBuffers.partial(AllPartialModels.SIGNAL_WHITE_CUBE, blockState) + .light(0xf000f0) + .disableDiffuse() + .scale(vert ? longSide : 1, vert ? 1 : longSide, 1) + .renderInto(ms, buffer.getBuffer(RenderType.translucent())); + + CachedPartialBuffers + .partial( + first ? AllPartialModels.SIGNAL_RED_GLOW + : yellow ? AllPartialModels.SIGNAL_YELLOW_GLOW : AllPartialModels.SIGNAL_WHITE_GLOW, + blockState) + .light(0xf000f0) + .disableDiffuse() + .scale(vert ? longSideGlow : 2, vert ? 2 : longSideGlow, 2) + .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); + } + + CachedPartialBuffers + .partial(first ? AllPartialModels.SIGNAL_RED + : yellow ? AllPartialModels.SIGNAL_YELLOW : AllPartialModels.SIGNAL_WHITE, blockState) + .light(0xF000F0) + .disableDiffuse() + .scale(1 + 1 / 16f) + .renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive())); + + ms.popPose(); + } + ms.popPose(); + + } + + @Override + public int getViewDistance() { + return 128; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailBlock.java b/src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailBlock.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailBlock.java rename to src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailBlock.java index 726f0e90c6..2126988683 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailBlock.java +++ b/src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailBlock.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.contraptions.components.tracks; +package com.simibubi.create.content.redstone.rail; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailGenerator.java b/src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailGenerator.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailGenerator.java rename to src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailGenerator.java index d8510c7bb4..a363005447 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/tracks/ControllerRailGenerator.java +++ b/src/main/java/com/simibubi/create/content/redstone/rail/ControllerRailGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.components.tracks; +package com.simibubi.create.content.redstone.rail; import com.simibubi.create.foundation.data.AssetLookup; import com.simibubi.create.foundation.data.SpecialBlockStateGen; diff --git a/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlock.java b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlock.java new file mode 100644 index 0000000000..b896eac5a1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlock.java @@ -0,0 +1,164 @@ +package com.simibubi.create.content.redstone.smartObserver; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.logistics.funnel.FunnelBlockEntity; +import com.simibubi.create.content.redstone.DirectedDirectionalBlock; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class SmartObserverBlock extends DirectedDirectionalBlock implements IBE { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + public SmartObserverBlock(Properties properties) { + super(properties); + registerDefaultState(defaultBlockState().setValue(POWERED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(POWERED)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState state = defaultBlockState(); + Capability itemCap = CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + Capability fluidCap = CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; + + Direction preferredFacing = null; + for (Direction face : context.getNearestLookingDirections()) { + BlockPos offsetPos = context.getClickedPos() + .relative(face); + Level world = context.getLevel(); + boolean canDetect = false; + BlockEntity blockEntity = world.getBlockEntity(offsetPos); + + if (BlockEntityBehaviour.get(blockEntity, TransportedItemStackHandlerBehaviour.TYPE) != null) + canDetect = true; + else if (BlockEntityBehaviour.get(blockEntity, FluidTransportBehaviour.TYPE) != null) + canDetect = true; + else if (blockEntity != null && (blockEntity.getCapability(itemCap) + .isPresent() + || blockEntity.getCapability(fluidCap) + .isPresent())) + canDetect = true; + else if (blockEntity instanceof FunnelBlockEntity) + canDetect = true; + + if (canDetect) { + preferredFacing = face; + break; + } + } + + if (preferredFacing == null) { + Direction facing = context.getNearestLookingDirection(); + preferredFacing = context.getPlayer() != null && context.getPlayer() + .isSteppingCarefully() ? facing : facing.getOpposite(); + } + + if (preferredFacing.getAxis() == Axis.Y) { + state = state.setValue(TARGET, preferredFacing == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR); + preferredFacing = context.getHorizontalDirection(); + } + + return state.setValue(FACING, preferredFacing); + } + + @Override + public boolean isSignalSource(BlockState state) { + return state.getValue(POWERED); + } + + @Override + public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { + return isSignalSource(blockState) && (side == null || side != blockState.getValue(FACING) + .getOpposite()) ? 15 : 0; + } + + @Override + public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random random) { + worldIn.setBlock(pos, state.setValue(POWERED, false), 2); + worldIn.updateNeighborsAt(pos, this); + } + + @Override + public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { + return side != state.getValue(FACING) + .getOpposite(); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, worldIn, pos, newState); + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + InvManipulationBehaviour behaviour = BlockEntityBehaviour.get(worldIn, pos, InvManipulationBehaviour.TYPE); + if (behaviour != null) + behaviour.onNeighborChanged(fromPos); + } + + public void onFunnelTransfer(Level world, BlockPos funnelPos, ItemStack transferred) { + for (Direction direction : Iterate.directions) { + BlockPos detectorPos = funnelPos.relative(direction); + BlockState detectorState = world.getBlockState(detectorPos); + if (!AllBlocks.SMART_OBSERVER.has(detectorState)) + continue; + if (SmartObserverBlock.getTargetDirection(detectorState) != direction.getOpposite()) + continue; + withBlockEntityDo(world, detectorPos, be -> { + FilteringBehaviour filteringBehaviour = BlockEntityBehaviour.get(be, FilteringBehaviour.TYPE); + if (filteringBehaviour == null) + return; + if (!filteringBehaviour.test(transferred)) + return; + be.activate(4); + }); + } + } + + @Override + public Class getBlockEntityClass() { + return SmartObserverBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SMART_OBSERVER.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java new file mode 100644 index 0000000000..e4d5eb6788 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverBlockEntity.java @@ -0,0 +1,152 @@ +package com.simibubi.create.content.redstone.smartObserver; + +import java.util.List; + +import com.simibubi.create.content.fluids.FluidTransportBehaviour; +import com.simibubi.create.content.fluids.PipeConnection.Flow; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour; +import com.simibubi.create.content.kinetics.belt.behaviour.TransportedItemStackHandlerBehaviour.TransportedResult; +import com.simibubi.create.content.redstone.DirectedDirectionalBlock; +import com.simibubi.create.content.redstone.FilteredDetectorFilterSlot; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; + +import net.createmod.catnip.utility.BlockFace; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class SmartObserverBlockEntity extends SmartBlockEntity { + + private static final int DEFAULT_DELAY = 6; + private FilteringBehaviour filtering; + private InvManipulationBehaviour observedInventory; + private TankManipulationBehaviour observedTank; + public int turnOffTicks = 0; + + public SmartObserverBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(20); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(false))); + + InterfaceProvider towardBlockFacing = + (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); + + behaviours.add(observedInventory = new InvManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); + behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide()) + return; + + BlockState state = getBlockState(); + if (turnOffTicks > 0) { + turnOffTicks--; + if (turnOffTicks == 0) + level.scheduleTick(worldPosition, state.getBlock(), 1); + } + + if (!isActive()) + return; + + BlockPos targetPos = worldPosition.relative(SmartObserverBlock.getTargetDirection(state)); + Block block = level.getBlockState(targetPos) + .getBlock(); + + if (!filtering.getFilter() + .isEmpty() && block.asItem() != null && filtering.test(new ItemStack(block))) { + activate(3); + return; + } + + // Detect items on belt + TransportedItemStackHandlerBehaviour behaviour = + BlockEntityBehaviour.get(level, targetPos, TransportedItemStackHandlerBehaviour.TYPE); + if (behaviour != null) { + behaviour.handleCenteredProcessingOnAllItems(.45f, stack -> { + if (!filtering.test(stack.stack) || turnOffTicks == 6) + return TransportedResult.doNothing(); + activate(); + return TransportedResult.doNothing(); + }); + return; + } + + // Detect fluids in pipe + FluidTransportBehaviour fluidBehaviour = + BlockEntityBehaviour.get(level, targetPos, FluidTransportBehaviour.TYPE); + if (fluidBehaviour != null) { + for (Direction side : Iterate.directions) { + Flow flow = fluidBehaviour.getFlow(side); + if (flow == null || !flow.inbound || !flow.complete) + continue; + if (!filtering.test(flow.fluid)) + continue; + activate(); + return; + } + return; + } + + if (!observedInventory.simulate() + .extract() + .isEmpty()) { + activate(); + return; + } + + if (!observedTank.simulate() + .extractAny() + .isEmpty()) { + activate(); + return; + } + } + + public void activate() { + activate(DEFAULT_DELAY); + } + + public void activate(int ticks) { + BlockState state = getBlockState(); + turnOffTicks = ticks; + if (state.getValue(SmartObserverBlock.POWERED)) + return; + level.setBlockAndUpdate(worldPosition, state.setValue(SmartObserverBlock.POWERED, true)); + level.updateNeighborsAt(worldPosition, state.getBlock()); + } + + private boolean isActive() { + return true; + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + compound.putInt("TurnOff", turnOffTicks); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + super.read(compound, clientPacket); + turnOffTicks = compound.getInt("TurnOff"); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverGenerator.java b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverGenerator.java new file mode 100644 index 0000000000..9f7f73289c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/smartObserver/SmartObserverGenerator.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.redstone.smartObserver; + +import com.simibubi.create.content.redstone.thresholdSwitch.ThresholdSwitchBlock; +import com.simibubi.create.foundation.data.AssetLookup; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.generators.ModelFile; + +public class SmartObserverGenerator extends SpecialBlockStateGen { + + @Override + protected int getXRotation(BlockState state) { + return switch (state.getValue(SmartObserverBlock.TARGET)) { + case CEILING -> -90; + case WALL -> 0; + case FLOOR -> 90; + }; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.getValue(ThresholdSwitchBlock.FACING)) + 180; + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + return AssetLookup.forPowered(ctx, prov) + .apply(state); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ConfigureThresholdSwitchPacket.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ConfigureThresholdSwitchPacket.java new file mode 100644 index 0000000000..235023c7d9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ConfigureThresholdSwitchPacket.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigureThresholdSwitchPacket extends BlockEntityConfigurationPacket { + + private float offBelow; + private float onAbove; + private boolean invert; + + public ConfigureThresholdSwitchPacket(BlockPos pos, float offBelow, float onAbove, boolean invert) { + super(pos); + this.offBelow = offBelow; + this.onAbove = onAbove; + this.invert = invert; + } + + public ConfigureThresholdSwitchPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + offBelow = buffer.readFloat(); + onAbove = buffer.readFloat(); + invert = buffer.readBoolean(); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeFloat(offBelow); + buffer.writeFloat(onAbove); + buffer.writeBoolean(invert); + } + + @Override + protected void applySettings(ThresholdSwitchBlockEntity be) { + be.offWhenBelow = offBelow; + be.onWhenAbove = onAbove; + be.setInverted(invert); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlock.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlock.java new file mode 100644 index 0000000000..206fed0463 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlock.java @@ -0,0 +1,147 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +import java.util.Random; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.redstone.DirectedDirectionalBlock; +import com.simibubi.create.foundation.block.IBE; + +import net.createmod.catnip.gui.ScreenOpener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public class ThresholdSwitchBlock extends DirectedDirectionalBlock implements IBE { + + public static final IntegerProperty LEVEL = IntegerProperty.create("level", 0, 5); + + public ThresholdSwitchBlock(Properties p_i48377_1_) { + super(p_i48377_1_); + } + + @Override + public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + updateObservedInventory(state, worldIn, pos); + } + + private void updateObservedInventory(BlockState state, LevelReader world, BlockPos pos) { + withBlockEntityDo(world, pos, ThresholdSwitchBlockEntity::updateCurrentLevel); + } + + @Override + public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { + return side != null && side.getOpposite() != state.getValue(FACING); + } + + @Override + public boolean isSignalSource(BlockState state) { + return true; + } + + @Override + public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { + if (side == blockState.getValue(FACING) + .getOpposite()) + return 0; + return getBlockEntityOptional(blockAccess, pos).filter(ThresholdSwitchBlockEntity::isPowered) + .map($ -> 15) + .orElse(0); + } + + @Override + public void tick(BlockState blockState, ServerLevel world, BlockPos pos, Random random) { + getBlockEntityOptional(world, pos).ifPresent(ThresholdSwitchBlockEntity::updatePowerAfterDelay); + } + + @Override + protected void createBlockStateDefinition(Builder builder) { + super.createBlockStateDefinition(builder.add(LEVEL)); + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (player != null && AllItems.WRENCH.isIn(player.getItemInHand(handIn))) + return InteractionResult.PASS; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> withBlockEntityDo(worldIn, pos, be -> this.displayScreen(be, player))); + return InteractionResult.SUCCESS; + } + + @OnlyIn(value = Dist.CLIENT) + protected void displayScreen(ThresholdSwitchBlockEntity be, Player player) { + if (player instanceof LocalPlayer) + ScreenOpener.open(new ThresholdSwitchScreen(be)); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockState state = defaultBlockState(); + Capability itemCap = CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + Capability fluidCap = CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; + + Direction preferredFacing = null; + for (Direction face : context.getNearestLookingDirections()) { + BlockEntity be = context.getLevel() + .getBlockEntity(context.getClickedPos() + .relative(face)); + if (be != null && (be.getCapability(itemCap) + .isPresent() + || be.getCapability(fluidCap) + .isPresent())) { + preferredFacing = face; + break; + } + } + + if (preferredFacing == null) { + Direction facing = context.getNearestLookingDirection(); + preferredFacing = context.getPlayer() != null && context.getPlayer() + .isSteppingCarefully() ? facing : facing.getOpposite(); + } + + if (preferredFacing.getAxis() == Axis.Y) { + state = state.setValue(TARGET, preferredFacing == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR); + preferredFacing = context.getHorizontalDirection(); + } + + return state.setValue(FACING, preferredFacing); + } + + @Override + public Class getBlockEntityClass() { + return ThresholdSwitchBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.THRESHOLD_SWITCH.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java new file mode 100644 index 0000000000..66f773a377 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchBlockEntity.java @@ -0,0 +1,238 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +import java.util.List; + +import com.simibubi.create.compat.storageDrawers.StorageDrawers; +import com.simibubi.create.content.redstone.DirectedDirectionalBlock; +import com.simibubi.create.content.redstone.FilteredDetectorFilterSlot; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.CapManipulationBehaviourBase.InterfaceProvider; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.InvManipulationBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.inventory.TankManipulationBehaviour; + +import net.createmod.catnip.utility.BlockFace; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.TickPriority; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; + +public class ThresholdSwitchBlockEntity extends SmartBlockEntity { + + public float onWhenAbove; + public float offWhenBelow; + public float currentLevel; + private boolean redstoneState; + private boolean inverted; + private boolean poweredAfterDelay; + + private FilteringBehaviour filtering; + private InvManipulationBehaviour observedInventory; + private TankManipulationBehaviour observedTank; + + public ThresholdSwitchBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + onWhenAbove = .75f; + offWhenBelow = .25f; + currentLevel = -1; + redstoneState = false; + inverted = false; + poweredAfterDelay = false; + setLazyTickRate(10); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + onWhenAbove = compound.getFloat("OnAbove"); + offWhenBelow = compound.getFloat("OffBelow"); + currentLevel = compound.getFloat("Current"); + redstoneState = compound.getBoolean("Powered"); + inverted = compound.getBoolean("Inverted"); + poweredAfterDelay = compound.getBoolean("PoweredAfterDelay"); + super.read(compound, clientPacket); + } + + protected void writeCommon(CompoundTag compound) { + compound.putFloat("OnAbove", onWhenAbove); + compound.putFloat("OffBelow", offWhenBelow); + compound.putBoolean("Inverted", inverted); + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + writeCommon(compound); + compound.putFloat("Current", currentLevel); + compound.putBoolean("Powered", redstoneState); + compound.putBoolean("PoweredAfterDelay", poweredAfterDelay); + super.write(compound, clientPacket); + } + + @Override + public void writeSafe(CompoundTag compound) { + writeCommon(compound); + super.writeSafe(compound); + } + + public float getStockLevel() { + return currentLevel; + } + + public void updateCurrentLevel() { + boolean changed = false; + float occupied = 0; + float totalSpace = 0; + float prevLevel = currentLevel; + + observedInventory.findNewCapability(); + observedTank.findNewCapability(); + + BlockPos target = worldPosition.relative(ThresholdSwitchBlock.getTargetDirection(getBlockState())); + BlockEntity targetBlockEntity = level.getBlockEntity(target); + + if (targetBlockEntity instanceof ThresholdSwitchObservable observable) { + currentLevel = observable.getPercent() / 100f; + + } else if (StorageDrawers.isDrawer(targetBlockEntity) && observedInventory.hasInventory()) { + currentLevel = StorageDrawers.getTrueFillLevel(observedInventory.getInventory(), filtering); + + } else if (observedInventory.hasInventory() || observedTank.hasInventory()) { + if (observedInventory.hasInventory()) { + // Item inventory + IItemHandler inv = observedInventory.getInventory(); + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + int space = Math.min(stackInSlot.getMaxStackSize(), inv.getSlotLimit(slot)); + int count = stackInSlot.getCount(); + if (space == 0) + continue; + + totalSpace += 1; + if (filtering.test(stackInSlot)) + occupied += count * (1f / space); + } + } + + if (observedTank.hasInventory()) { + // Fluid inventory + IFluidHandler tank = observedTank.getInventory(); + for (int slot = 0; slot < tank.getTanks(); slot++) { + FluidStack stackInSlot = tank.getFluidInTank(slot); + int space = tank.getTankCapacity(slot); + int count = stackInSlot.getAmount(); + if (space == 0) + continue; + + totalSpace += 1; + if (filtering.test(stackInSlot)) + occupied += count * (1f / space); + } + } + + currentLevel = occupied / totalSpace; + + } else { + // No compatible inventories found + if (currentLevel == -1) + return; + level.setBlock(worldPosition, getBlockState().setValue(ThresholdSwitchBlock.LEVEL, 0), 3); + currentLevel = -1; + redstoneState = false; + sendData(); + scheduleBlockTick(); + return; + } + + currentLevel = Mth.clamp(currentLevel, 0, 1); + changed = currentLevel != prevLevel; + + boolean previouslyPowered = redstoneState; + if (redstoneState && currentLevel <= offWhenBelow) + redstoneState = false; + else if (!redstoneState && currentLevel >= onWhenAbove) + redstoneState = true; + boolean update = previouslyPowered != redstoneState; + + int displayLevel = 0; + if (currentLevel > 0) + displayLevel = (int) (1 + currentLevel * 4); + level.setBlock(worldPosition, getBlockState().setValue(ThresholdSwitchBlock.LEVEL, displayLevel), + update ? 3 : 2); + + if (update) + scheduleBlockTick(); + + if (changed || update) { + DisplayLinkBlock.notifyGatherers(level, worldPosition); + notifyUpdate(); + } + } + + protected void scheduleBlockTick() { + Block block = getBlockState().getBlock(); + if (!level.getBlockTicks() + .willTickThisTick(worldPosition, block)) + level.scheduleTick(worldPosition, block, 2, TickPriority.NORMAL); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (level.isClientSide) + return; + updateCurrentLevel(); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(filtering = new FilteringBehaviour(this, new FilteredDetectorFilterSlot(true)) + .withCallback($ -> this.updateCurrentLevel())); + + InterfaceProvider towardBlockFacing = + (w, p, s) -> new BlockFace(p, DirectedDirectionalBlock.getTargetDirection(s)); + + behaviours.add(observedInventory = new InvManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); + behaviours.add(observedTank = new TankManipulationBehaviour(this, towardBlockFacing).bypassSidedness()); + } + + public float getLevelForDisplay() { + return currentLevel == -1 ? 0 : currentLevel; + } + + public boolean getState() { + return redstoneState; + } + + public boolean shouldBePowered() { + return inverted != redstoneState; + } + + public void updatePowerAfterDelay() { + poweredAfterDelay = shouldBePowered(); + level.blockUpdated(worldPosition, getBlockState().getBlock()); + } + + public boolean isPowered() { + return poweredAfterDelay; + } + + public boolean isInverted() { + return inverted; + } + + public void setInverted(boolean inverted) { + if (inverted == this.inverted) + return; + this.inverted = inverted; + updatePowerAfterDelay(); + } +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchGenerator.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchGenerator.java new file mode 100644 index 0000000000..d372f8cf59 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchGenerator.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.data.SpecialBlockStateGen; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; + +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.client.model.generators.ModelFile; + +public class ThresholdSwitchGenerator extends SpecialBlockStateGen { + + @Override + protected int getXRotation(BlockState state) { + return 0; + } + + @Override + protected int getYRotation(BlockState state) { + return horizontalAngle(state.getValue(ThresholdSwitchBlock.FACING)) + 180; + } + + @Override + public ModelFile getModel(DataGenContext ctx, RegistrateBlockstateProvider prov, + BlockState state) { + int level = state.getValue(ThresholdSwitchBlock.LEVEL); + String path = "threshold_switch/block_" + Lang.asId(state.getValue(ThresholdSwitchBlock.TARGET) + .name()); + return prov.models() + .withExistingParent(path + "_" + level, Create.asResource("block/" + path)) + .texture("level", Create.asResource("block/threshold_switch/level_" + level)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchObservable.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchObservable.java new file mode 100644 index 0000000000..039945c2a6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchObservable.java @@ -0,0 +1,7 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +public interface ThresholdSwitchObservable { + + public float getPercent(); + +} diff --git a/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchScreen.java b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchScreen.java new file mode 100644 index 0000000000..0db31f992a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/redstone/thresholdSwitch/ThresholdSwitchScreen.java @@ -0,0 +1,169 @@ +package com.simibubi.create.content.redstone.thresholdSwitch; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; + +public class ThresholdSwitchScreen extends AbstractSimiScreen { + + private ScrollInput offBelow; + private ScrollInput onAbove; + private IconButton confirmButton; + private IconButton flipSignals; + + private final Component invertSignal = CreateLang.translateDirect("gui.threshold_switch.invert_signal"); + private final ItemStack renderedItem = new ItemStack(AllBlocks.THRESHOLD_SWITCH.get()); + + private AllGuiTextures background; + private ThresholdSwitchBlockEntity blockEntity; + private int lastModification; + + private LerpedFloat cursor; + private LerpedFloat cursorLane; + + public ThresholdSwitchScreen(ThresholdSwitchBlockEntity be) { + super(CreateLang.translateDirect("gui.threshold_switch.title")); + background = AllGuiTextures.STOCKSWITCH; + this.blockEntity = be; + lastModification = -1; + } + + @Override + protected void init() { + setWindowSize(background.getWidth(), background.getHeight()); + setWindowOffset(-20, 0); + super.init(); + + int x = guiLeft; + int y = guiTop; + + cursor = LerpedFloat.linear() + .startWithValue(blockEntity.getLevelForDisplay()); + cursorLane = LerpedFloat.linear() + .startWithValue(blockEntity.getState() ? 1 : 0); + + offBelow = new ScrollInput(x + 36, y + 42, 102, 18).withRange(0, 100) + .titled(Components.empty()) + .calling(state -> { + lastModification = 0; + offBelow.titled(CreateLang.translateDirect("gui.threshold_switch.move_to_upper_at", state)); + if (onAbove.getState() <= state) { + onAbove.setState(state + 1); + onAbove.onChanged(); + } + }) + .setState((int) (blockEntity.offWhenBelow * 100)); + + onAbove = new ScrollInput(x + 36, y + 20, 102, 18).withRange(1, 101) + .titled(Components.empty()) + .calling(state -> { + lastModification = 0; + onAbove.titled(CreateLang.translateDirect("gui.threshold_switch.move_to_lower_at", state)); + if (offBelow.getState() >= state) { + offBelow.setState(state - 1); + offBelow.onChanged(); + } + }) + .setState((int) (blockEntity.onWhenAbove * 100)); + + onAbove.onChanged(); + offBelow.onChanged(); + + addRenderableWidget(onAbove); + addRenderableWidget(offBelow); + + confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(() -> { + onClose(); + }); + addRenderableWidget(confirmButton); + + flipSignals = new IconButton(x + background.getWidth() - 62, y + background.getHeight() - 24, AllIcons.I_FLIP); + flipSignals.withCallback(() -> { + send(!blockEntity.isInverted()); + }); + flipSignals.setToolTip(invertSignal); + addRenderableWidget(flipSignals); + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + + AllGuiTextures.STOCKSWITCH_POWERED_LANE.render(ms, x + 37, y + (blockEntity.isInverted() ? 20 : 42), this); + AllGuiTextures.STOCKSWITCH_UNPOWERED_LANE.render(ms, x + 37, y + (blockEntity.isInverted() ? 42 : 20), this); + font.draw(ms, title, x + (background.getWidth() - 8) / 2 - font.width(title) / 2, y + 4, 0x592424); + + AllGuiTextures sprite = AllGuiTextures.STOCKSWITCH_INTERVAL; + float lowerBound = offBelow.getState(); + float upperBound = onAbove.getState(); + + sprite.bind(); + blit(ms, (int) (x + upperBound) + 37, y + 20, (int) (sprite.getStartX() + upperBound), sprite.getStartY(), + (int) (sprite.getWidth() - upperBound), sprite.getHeight()); + blit(ms, x + 37, y + 42, sprite.getStartX(), sprite.getStartY(), (int) (lowerBound), sprite.getHeight()); + + AllGuiTextures.STOCKSWITCH_ARROW_UP.render(ms, (int) (x + lowerBound + 36) - 2, y + 37, this); + AllGuiTextures.STOCKSWITCH_ARROW_DOWN.render(ms, (int) (x + upperBound + 36) - 3, y + 19, this); + + if (blockEntity.currentLevel != -1) { + AllGuiTextures cursor = AllGuiTextures.STOCKSWITCH_CURSOR; + ms.pushPose(); + ms.translate(Math.min(99, this.cursor.getValue(partialTicks) * sprite.getWidth()), + cursorLane.getValue(partialTicks) * 22, 0); + cursor.render(ms, x + 34, y + 21, this); + ms.popPose(); + } + + GuiGameElement.of(renderedItem).at(x + background.getWidth() + 6, y + background.getHeight() - 56, -200) + .scale(5) + .render(ms); + } + + @Override + public void tick() { + super.tick(); + + cursor.chase(blockEntity.getLevelForDisplay(), 1 / 4f, Chaser.EXP); + cursor.tickChaser(); + cursorLane.chase(blockEntity.getState() ? 1 : 0, 1 / 4f, Chaser.EXP); + cursorLane.tickChaser(); + + if (lastModification >= 0) + lastModification++; + + if (lastModification >= 20) { + lastModification = -1; + send(blockEntity.isInverted()); + } + } + + @Override + public void removed() { + send(blockEntity.isInverted()); + } + + protected void send(boolean invert) { + AllPackets.getChannel() + .sendToServer(new ConfigureThresholdSwitchPacket(blockEntity.getBlockPos(), offBelow.getState() / 100f, + onAbove.getState() / 100f, invert)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockEntityItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockEntityItemRequirement.java deleted file mode 100644 index bfcb9ef69e..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockEntityItemRequirement.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.simibubi.create.content.schematics; - -import net.minecraft.world.level.block.state.BlockState; - -public interface ISpecialBlockEntityItemRequirement { - - public ItemRequirement getRequiredItems(BlockState state); - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockItemRequirement.java deleted file mode 100644 index 26729dc498..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/ISpecialBlockItemRequirement.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.simibubi.create.content.schematics; - -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; - -public interface ISpecialBlockItemRequirement { - - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te); - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/ISpecialEntityItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/ISpecialEntityItemRequirement.java deleted file mode 100644 index 7cdf23c5e7..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/ISpecialEntityItemRequirement.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.simibubi.create.content.schematics; - -public interface ISpecialEntityItemRequirement { - - public ItemRequirement getRequiredItems(); - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java deleted file mode 100644 index 32f4c15636..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/ItemRequirement.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.simibubi.create.content.schematics; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.decoration.ItemFrame; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.AbstractBannerBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.DirtPathBlock; -import net.minecraft.world.level.block.FarmBlock; -import net.minecraft.world.level.block.SeaPickleBlock; -import net.minecraft.world.level.block.SnowLayerBlock; -import net.minecraft.world.level.block.TurtleEggBlock; -import net.minecraft.world.level.block.entity.BannerBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.SlabType; - -public class ItemRequirement { - public static final ItemRequirement NONE = new ItemRequirement(Collections.emptyList()); - public static final ItemRequirement INVALID = new ItemRequirement(Collections.emptyList()); - - protected List requiredItems; - - public ItemRequirement(List requiredItems) { - this.requiredItems = requiredItems; - } - - public ItemRequirement(StackRequirement stackRequirement) { - this(List.of(stackRequirement)); - } - - public ItemRequirement(ItemUseType usage, ItemStack stack) { - this(new StackRequirement(stack, usage)); - } - - public ItemRequirement(ItemUseType usage, Item item) { - this(usage, new ItemStack(item)); - } - - public ItemRequirement(ItemUseType usage, List requiredItems) { - this(requiredItems.stream().map(req -> new StackRequirement(req, usage)).collect(Collectors.toList())); - } - - public static ItemRequirement of(BlockState state, BlockEntity te) { - Block block = state.getBlock(); - - ItemRequirement requirement; - if (block instanceof ISpecialBlockItemRequirement specialBlock) { - requirement = specialBlock.getRequiredItems(state, te); - } else { - requirement = defaultOf(state, te); - } - - if (te instanceof ISpecialBlockEntityItemRequirement specialBE) - requirement = requirement.union(specialBE.getRequiredItems(state)); - - return requirement; - } - - private static ItemRequirement defaultOf(BlockState state, BlockEntity te) { - Block block = state.getBlock(); - if (block == Blocks.AIR) - return NONE; - - Item item = block.asItem(); - if (item == Items.AIR) - return INVALID; - - // double slab needs two items - if (state.hasProperty(BlockStateProperties.SLAB_TYPE) && state.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, 2)); - if (block instanceof TurtleEggBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(TurtleEggBlock.EGGS).intValue())); - if (block instanceof SeaPickleBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SeaPickleBlock.PICKLES).intValue())); - if (block instanceof SnowLayerBlock) - return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SnowLayerBlock.LAYERS).intValue())); - if (block instanceof FarmBlock || block instanceof DirtPathBlock) - return new ItemRequirement(ItemUseType.CONSUME, Items.DIRT); - if (block instanceof AbstractBannerBlock && te instanceof BannerBlockEntity bannerBE) - return new ItemRequirement(new StrictNbtStackRequirement(bannerBE.getItem(), ItemUseType.CONSUME)); - - return new ItemRequirement(ItemUseType.CONSUME, item); - } - - public static ItemRequirement of(Entity entity) { - if (entity instanceof ISpecialEntityItemRequirement specialEntity) - return specialEntity.getRequiredItems(); - - if (entity instanceof ItemFrame itemFrame) { - ItemStack frame = new ItemStack(Items.ITEM_FRAME); - ItemStack displayedItem = itemFrame.getItem(); - if (displayedItem.isEmpty()) - return new ItemRequirement(ItemUseType.CONSUME, Items.ITEM_FRAME); - return new ItemRequirement(ItemUseType.CONSUME, Arrays.asList(frame, displayedItem)); - } - - if (entity instanceof ArmorStand armorStand) { - List requirements = new ArrayList<>(); - requirements.add(new ItemStack(Items.ARMOR_STAND)); - armorStand.getAllSlots().forEach(requirements::add); - return new ItemRequirement(ItemUseType.CONSUME, requirements); - } - - ItemStack pickedStack = entity.getPickResult(); - if (pickedStack != null) { - return new ItemRequirement(ItemUseType.CONSUME, pickedStack); - } - - return INVALID; - } - - public boolean isEmpty() { - return NONE == this; - } - - public boolean isInvalid() { - return INVALID == this; - } - - public List getRequiredItems() { - return requiredItems; - } - - public ItemRequirement union(ItemRequirement other) { - if (this.isInvalid() || other.isInvalid()) - return INVALID; - if (this.isEmpty()) - return other; - if (other.isEmpty()) - return this; - - return new ItemRequirement( - Stream.concat(requiredItems.stream(), other.requiredItems.stream()).collect(Collectors.toList()) - ); - } - - public enum ItemUseType { - CONSUME, DAMAGE - } - - public static class StackRequirement { - public final ItemStack stack; - public final ItemUseType usage; - - public StackRequirement(ItemStack stack, ItemUseType usage) { - this.stack = stack; - this.usage = usage; - } - - public boolean matches(ItemStack other) { - return stack.sameItem(other); - } - } - - public static class StrictNbtStackRequirement extends StackRequirement { - public StrictNbtStackRequirement(ItemStack stack, ItemUseType usage) { - super(stack, usage); - } - - @Override - public boolean matches(ItemStack other) { - return ItemStack.isSameItemSameTags(stack, other); - } - } -} diff --git a/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java b/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java deleted file mode 100644 index 9009051d62..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.simibubi.create.content.schematics; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import com.google.common.collect.Sets; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.utility.CreateLang; - -import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.ChatFormatting; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.StringTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.HoverEvent; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.Style; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; - -public class MaterialChecklist { - - public static final int MAX_ENTRIES_PER_PAGE = 5; - - public Object2IntMap gathered = new Object2IntArrayMap<>(); - public Object2IntMap required = new Object2IntArrayMap<>(); - public Object2IntMap damageRequired = new Object2IntArrayMap<>(); - public boolean blocksNotLoaded; - - public void warnBlockNotLoaded() { - blocksNotLoaded = true; - } - - public void require(ItemRequirement requirement) { - if (requirement.isEmpty()) - return; - if (requirement.isInvalid()) - return; - - for (ItemRequirement.StackRequirement stack : requirement.requiredItems) { - if (stack.usage == ItemUseType.DAMAGE) - putOrIncrement(damageRequired, stack.stack); - if (stack.usage == ItemUseType.CONSUME) - putOrIncrement(required, stack.stack); - } - } - - private void putOrIncrement(Object2IntMap map, ItemStack stack) { - Item item = stack.getItem(); - if (item == Items.AIR) - return; - if (map.containsKey(item)) - map.put(item, map.getInt(item) + stack.getCount()); - else - map.put(item, stack.getCount()); - } - - public void collect(ItemStack stack) { - Item item = stack.getItem(); - if (required.containsKey(item) || damageRequired.containsKey(item)) - if (gathered.containsKey(item)) - gathered.put(item, gathered.getInt(item) + stack.getCount()); - else - gathered.put(item, stack.getCount()); - } - - public ItemStack createItem() { - ItemStack book = new ItemStack(Items.WRITTEN_BOOK); - - CompoundTag tag = book.getOrCreateTag(); - ListTag pages = new ListTag(); - - int itemsWritten = 0; - MutableComponent textComponent; - - if (blocksNotLoaded) { - textComponent = Components.literal("\n" + ChatFormatting.RED); - textComponent = textComponent.append(CreateLang.translateDirect("materialChecklist.blocksNotLoaded")); - pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); - } - - List keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet())); - Collections.sort(keys, (item1, item2) -> { - Locale locale = Locale.ENGLISH; - String name1 = item1.getDescription().getString() - .toLowerCase(locale); - String name2 = item2.getDescription().getString() - .toLowerCase(locale); - return name1.compareTo(name2); - }); - - textComponent = Components.empty(); - List completed = new ArrayList<>(); - for (Item item : keys) { - int amount = getRequiredAmount(item); - if (gathered.containsKey(item)) - amount -= gathered.getInt(item); - - if (amount <= 0) { - completed.add(item); - continue; - } - - if (itemsWritten == MAX_ENTRIES_PER_PAGE) { - itemsWritten = 0; - textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.BLUE)); - pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); - textComponent = Components.empty(); - } - - itemsWritten++; - textComponent.append(entry(new ItemStack(item), amount, true)); - } - - for (Item item : completed) { - if (itemsWritten == MAX_ENTRIES_PER_PAGE) { - itemsWritten = 0; - textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.DARK_GREEN)); - pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); - textComponent = Components.empty(); - } - - itemsWritten++; - textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false)); - } - - pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); - - tag.put("pages", pages); - tag.putString("author", "Schematicannon"); - tag.putString("title", ChatFormatting.BLUE + "Material Checklist"); - textComponent = CreateLang.translateDirect("materialChecklist") - .setStyle(Style.EMPTY.withColor(ChatFormatting.BLUE) - .withItalic(Boolean.FALSE)); - book.getOrCreateTagElement("display") - .putString("Name", Component.Serializer.toJson(textComponent)); - book.setTag(tag); - - return book; - } - - public int getRequiredAmount(Item item) { - int amount = required.getOrDefault(item, 0); - if (damageRequired.containsKey(item)) - amount += Math.ceil(damageRequired.getInt(item) / (float) new ItemStack(item).getMaxDamage()); - return amount; - } - - private Component entry(ItemStack item, int amount, boolean unfinished) { - int stacks = amount / 64; - int remainder = amount % 64; - MutableComponent tc = Components.empty(); - tc.append(Components.translatable(item.getDescriptionId()) - .setStyle(Style.EMPTY - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(item))))); - - if (!unfinished) - tc.append(" \u2714"); - tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN); - return tc.append(Components.literal("\n" + " x" + amount).withStyle(ChatFormatting.BLACK)) - .append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + "\n").withStyle(ChatFormatting.GRAY)); - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/item/SchematicAndQuillItem.java b/src/main/java/com/simibubi/create/content/schematics/SchematicAndQuillItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/schematics/item/SchematicAndQuillItem.java rename to src/main/java/com/simibubi/create/content/schematics/SchematicAndQuillItem.java index f820b0b2a0..3214012900 100644 --- a/src/main/java/com/simibubi/create/content/schematics/item/SchematicAndQuillItem.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicAndQuillItem.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.schematics.item; +package com.simibubi.create.content.schematics; import java.util.Iterator; import com.simibubi.create.AllEntityTypes; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.utility.NBTHelper; diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java b/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java new file mode 100644 index 0000000000..7069fee813 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicExport.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.schematics; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +import javax.annotation.Nullable; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.FilesHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.fml.loading.FMLPaths; + +public class SchematicExport { + public static final Path SCHEMATICS = FMLPaths.GAMEDIR.get().resolve("schematics"); + + /** + * Save a schematic to a file from a world. + * @param dir the directory the schematic will be created in + * @param fileName the ideal name of the schematic, may not be the name of the created file + * @param overwrite whether overwriting an existing schematic is allowed + * @param level the level where the schematic structure is placed + * @param first the first corner of the schematic area + * @param second the second corner of the schematic area + * @return a SchematicExportResult, or null if an error occurred. + */ + @Nullable + public static SchematicExportResult saveSchematic(Path dir, String fileName, boolean overwrite, Level level, BlockPos first, BlockPos second) { + BoundingBox bb = BoundingBox.fromCorners(first, second); + BlockPos origin = new BlockPos(bb.minX(), bb.minY(), bb.minZ()); + BlockPos bounds = new BlockPos(bb.getXSpan(), bb.getYSpan(), bb.getZSpan()); + + StructureTemplate structure = new StructureTemplate(); + structure.fillFromWorld(level, origin, bounds, true, Blocks.AIR); + CompoundTag data = structure.save(new CompoundTag()); + SchematicAndQuillItem.replaceStructureVoidWithAir(data); + SchematicAndQuillItem.clampGlueBoxes(level, new AABB(origin, origin.offset(bounds)), data); + + if (fileName.isEmpty()) + fileName = CreateLang.translateDirect("schematicAndQuill.fallbackName").getString(); + if (!overwrite) + fileName = FilesHelper.findFirstValidFilename(fileName, dir, "nbt"); + if (!fileName.endsWith(".nbt")) + fileName += ".nbt"; + Path file = dir.resolve(fileName).toAbsolutePath(); + + try { + Files.createDirectories(dir); + boolean overwritten = Files.deleteIfExists(file); + try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.CREATE)) { + NbtIo.writeCompressed(data, out); + } + return new SchematicExportResult(file, dir, fileName, overwritten, origin, bounds); + } catch (IOException e) { + Create.LOGGER.error("An error occurred while saving schematic [" + fileName + "]", e); + return null; + } + } + + public record SchematicExportResult(Path file, Path dir, String fileName, boolean overwritten, BlockPos origin, BlockPos bounds) { + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/filtering/SchematicInstances.java b/src/main/java/com/simibubi/create/content/schematics/SchematicInstances.java similarity index 82% rename from src/main/java/com/simibubi/create/content/schematics/filtering/SchematicInstances.java rename to src/main/java/com/simibubi/create/content/schematics/SchematicInstances.java index 1e6bebd253..581e73e44a 100644 --- a/src/main/java/com/simibubi/create/content/schematics/filtering/SchematicInstances.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicInstances.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.schematics.filtering; +package com.simibubi.create.content.schematics; import java.util.concurrent.TimeUnit; @@ -6,23 +6,25 @@ import javax.annotation.Nullable; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.simibubi.create.content.schematics.item.SchematicItem; +import com.simibubi.create.content.contraptions.StructureTransform; import net.createmod.catnip.utility.WorldAttached; import net.createmod.catnip.utility.worldWrappers.SchematicWorld; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; public class SchematicInstances { - public static WorldAttached> loadedSchematics; + public static final WorldAttached> loadedSchematics; static { loadedSchematics = new WorldAttached<>($ -> CacheBuilder.newBuilder() @@ -65,6 +67,11 @@ public class SchematicInstances { StructurePlaceSettings settings = SchematicItem.getSettings(schematic); activeTemplate.placeInWorld(world, anchor, anchor, settings, wrapped.getRandom(), Block.UPDATE_CLIENTS); + StructureTransform transform = new StructureTransform(settings.getRotationPivot(), Direction.Axis.Y, + settings.getRotation(), settings.getMirror()); + for (BlockEntity be : world.getBlockEntities()) + transform.apply(be); + return world; } diff --git a/src/main/java/com/simibubi/create/content/schematics/item/SchematicItem.java b/src/main/java/com/simibubi/create/content/schematics/SchematicItem.java similarity index 94% rename from src/main/java/com/simibubi/create/content/schematics/item/SchematicItem.java rename to src/main/java/com/simibubi/create/content/schematics/SchematicItem.java index 2ddbb96b46..ac3fd9ae31 100644 --- a/src/main/java/com/simibubi/create/content/schematics/item/SchematicItem.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.schematics.item; +package com.simibubi.create.content.schematics; import java.io.BufferedInputStream; import java.io.DataInputStream; @@ -12,13 +12,11 @@ import java.util.zip.GZIPInputStream; import javax.annotation.Nonnull; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import com.mojang.logging.LogUtils; import com.simibubi.create.AllItems; -import com.simibubi.create.content.schematics.SchematicProcessor; import com.simibubi.create.content.schematics.client.SchematicEditScreen; -import com.simibubi.create.content.schematics.filtering.SchematicInstances; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.ScreenOpener; @@ -53,7 +51,7 @@ import net.minecraftforge.fml.util.thread.SidedThreadGroups; public class SchematicItem extends Item { - private static final Logger LOGGER = LogManager.getLogger(); + private static final Logger LOGGER = LogUtils.getLogger(); public SchematicItem(Properties properties) { super(properties); diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java b/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java index c21a34657a..4a5f411f7d 100644 --- a/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java @@ -5,10 +5,12 @@ import java.util.List; import java.util.stream.Collectors; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.schematics.item.SchematicItem; -import com.simibubi.create.foundation.tileEntity.IMergeableTE; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.BlockMovementChecks; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.schematics.cannon.MaterialChecklist; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.IMergeableBE; import com.simibubi.create.foundation.utility.BlockHelper; import net.createmod.catnip.utility.BBHelper; @@ -38,6 +40,7 @@ public class SchematicPrinter { } private boolean schematicLoaded; + private boolean isErrored; private SchematicWorld blockReader; private BlockPos schematicAnchor; @@ -94,7 +97,16 @@ public class SchematicPrinter { schematicAnchor = NbtUtils.readBlockPos(blueprint.getTag() .getCompound("Anchor")); blockReader = new SchematicWorld(schematicAnchor, originalWorld); - activeTemplate.placeInWorld(blockReader, schematicAnchor, schematicAnchor, settings, blockReader.getRandom(), Block.UPDATE_CLIENTS); + + try { + activeTemplate.placeInWorld(blockReader, schematicAnchor, schematicAnchor, settings, + blockReader.getRandom(), Block.UPDATE_CLIENTS); + } catch (Exception e) { + Create.LOGGER.error("Failed to load Schematic for Printing", e); + schematicLoaded = true; + isErrored = true; + return; + } BlockPos extraBounds = StructureTemplate.calculateRelativePosition(settings, new BlockPos(activeTemplate.getSize()) .offset(-1, -1, -1)); @@ -102,8 +114,8 @@ public class SchematicPrinter { StructureTransform transform = new StructureTransform(settings.getRotationPivot(), Direction.Axis.Y, settings.getRotation(), settings.getMirror()); - for (BlockEntity te : blockReader.getTileEntities().values()) - transform.apply(te); + for (BlockEntity be : blockReader.getBlockEntities()) + transform.apply(be); printingEntityIndex = -1; printStage = PrintStage.BLOCKS; @@ -116,6 +128,7 @@ public class SchematicPrinter { public void resetSchematic() { schematicLoaded = false; schematicAnchor = null; + isErrored = false; currentPos = null; blockReader = null; printingEntityIndex = -1; @@ -127,8 +140,12 @@ public class SchematicPrinter { return schematicLoaded; } + public boolean isErrored() { + return isErrored; + } + public BlockPos getCurrentTarget() { - if (!isLoaded()) + if (!isLoaded() || isErrored()) return null; return schematicAnchor.offset(currentPos); } @@ -148,7 +165,7 @@ public class SchematicPrinter { @FunctionalInterface public interface BlockTargetHandler { - void handle(BlockPos target, BlockState blockState, BlockEntity tileEntity); + void handle(BlockPos target, BlockState blockState, BlockEntity blockEntity); } @FunctionalInterface public interface EntityTargetHandler { @@ -165,14 +182,14 @@ public class SchematicPrinter { entityHandler.handle(target, entity); } else { BlockState blockState = BlockHelper.setZeroAge(blockReader.getBlockState(target)); - BlockEntity tileEntity = blockReader.getBlockEntity(target); - blockHandler.handle(target, blockState, tileEntity); + BlockEntity blockEntity = blockReader.getBlockEntity(target); + blockHandler.handle(target, blockState, blockEntity); } } @FunctionalInterface public interface PlacementPredicate { - boolean shouldPlace(BlockPos target, BlockState blockState, BlockEntity tileEntity, + boolean shouldPlace(BlockPos target, BlockState blockState, BlockEntity blockEntity, BlockState toReplace, BlockState toReplaceOther, boolean isNormalCube); } @@ -190,10 +207,10 @@ public class SchematicPrinter { public boolean shouldPlaceBlock(Level world, PlacementPredicate predicate, BlockPos pos) { BlockState state = BlockHelper.setZeroAge(blockReader.getBlockState(pos)); - BlockEntity tileEntity = blockReader.getBlockEntity(pos); + BlockEntity blockEntity = blockReader.getBlockEntity(pos); BlockState toReplace = world.getBlockState(pos); - BlockEntity toReplaceTE = world.getBlockEntity(pos); + BlockEntity toReplaceBE = world.getBlockEntity(pos); BlockState toReplaceOther = null; if (state.hasProperty(BlockStateProperties.BED_PART) && state.hasProperty(BlockStateProperties.HORIZONTAL_FACING) @@ -203,8 +220,8 @@ public class SchematicPrinter { && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER) toReplaceOther = world.getBlockState(pos.above()); - boolean mergeTEs = tileEntity != null && toReplaceTE instanceof IMergeableTE mergeTE && toReplaceTE.getType() - .equals(tileEntity.getType()); + boolean mergeTEs = blockEntity != null && toReplaceBE instanceof IMergeableBE mergeBE && toReplaceBE.getType() + .equals(blockEntity.getType()); if (!world.isLoaded(pos)) return false; @@ -217,7 +234,7 @@ public class SchematicPrinter { return false; boolean isNormalCube = state.isRedstoneConductor(blockReader, currentPos); - return predicate.shouldPlace(pos, state, tileEntity, toReplace, toReplaceOther, isNormalCube); + return predicate.shouldPlace(pos, state, blockEntity, toReplace, toReplaceOther, isNormalCube); } public ItemRequirement getCurrentRequirement() { @@ -228,8 +245,8 @@ public class SchematicPrinter { BlockPos target = getCurrentTarget(); BlockState blockState = BlockHelper.setZeroAge(blockReader.getBlockState(target)); - BlockEntity tileEntity = blockReader.getBlockEntity(target); - return ItemRequirement.of(blockState, tileEntity); + BlockEntity blockEntity = blockReader.getBlockEntity(target); + return ItemRequirement.of(blockState, blockEntity); } public int markAllBlockRequirements(MaterialChecklist checklist, Level world, PlacementPredicate predicate) { @@ -237,7 +254,7 @@ public class SchematicPrinter { for (BlockPos pos : blockReader.getAllPositions()) { BlockPos relPos = pos.offset(schematicAnchor); BlockState required = blockReader.getBlockState(relPos); - BlockEntity requiredTE = blockReader.getBlockEntity(relPos); + BlockEntity requiredBE = blockReader.getBlockEntity(relPos); if (!world.isLoaded(pos.offset(schematicAnchor))) { checklist.warnBlockNotLoaded(); @@ -245,7 +262,7 @@ public class SchematicPrinter { } if (!shouldPlaceBlock(world, predicate, relPos)) continue; - ItemRequirement requirement = ItemRequirement.of(required, requiredTE); + ItemRequirement requirement = ItemRequirement.of(required, requiredBE); if (requirement.isEmpty()) continue; if (requirement.isInvalid()) diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java b/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java index e5507d8e74..d8a5c6eae0 100644 --- a/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java @@ -6,8 +6,8 @@ import javax.annotation.Nullable; import com.mojang.serialization.Codec; import com.simibubi.create.AllStructureProcessorTypes; -import com.simibubi.create.foundation.utility.NBTProcessors; +import net.createmod.catnip.utility.NBTProcessors; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.Entity; @@ -33,9 +33,9 @@ public class SchematicProcessor extends StructureProcessor { public StructureTemplate.StructureBlockInfo process(LevelReader world, BlockPos pos, BlockPos anotherPos, StructureTemplate.StructureBlockInfo rawInfo, StructureTemplate.StructureBlockInfo info, StructurePlaceSettings settings, @Nullable StructureTemplate template) { if (info.nbt != null && info.state.hasBlockEntity()) { - BlockEntity te = ((EntityBlock) info.state.getBlock()).newBlockEntity(info.pos, info.state); - if (te != null) { - CompoundTag nbt = NBTProcessors.process(te, info.nbt, false); + BlockEntity be = ((EntityBlock) info.state.getBlock()).newBlockEntity(info.pos, info.state); + if (be != null) { + CompoundTag nbt = NBTProcessors.process(be, info.nbt, false); if (nbt != info.nbt) return new StructureTemplate.StructureBlockInfo(info.pos, info.state, nbt); } diff --git a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java index 297ce924a4..af21568f05 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java @@ -8,6 +8,7 @@ import java.nio.file.Paths; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -16,27 +17,22 @@ import java.util.stream.Stream; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.Create; -import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; -import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; -import com.simibubi.create.content.schematics.item.SchematicItem; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CSchematics; +import com.simibubi.create.content.schematics.SchematicExport.SchematicExportResult; +import com.simibubi.create.content.schematics.table.SchematicTableBlockEntity; import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.FilesHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CSchematics; import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraft.world.phys.AABB; public class ServerSchematicLoader { @@ -92,9 +88,9 @@ public class ServerSchematicLoader { public void handleNewUpload(ServerPlayer player, String schematic, long size, BlockPos pos) { String playerPath = getSchematicPath() + "/" + player.getGameProfile() - .getName(); + .getName(); String playerSchematicId = player.getGameProfile() - .getName() + "/" + schematic; + .getName() + "/" + schematic; FilesHelper.createFolderIfMissing(playerPath); // Unsupported Format @@ -104,11 +100,11 @@ public class ServerSchematicLoader { } Path playerSchematicsPath = Paths.get(getSchematicPath(), player.getGameProfile() - .getName()) - .toAbsolutePath(); + .getName()) + .toAbsolutePath(); Path uploadPath = playerSchematicsPath.resolve(schematic) - .normalize(); + .normalize(); if (!uploadPath.startsWith(playerSchematicsPath)) { Create.LOGGER.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId); return; @@ -124,7 +120,7 @@ public class ServerSchematicLoader { try { // Validate Referenced Block - SchematicTableTileEntity table = getTable(player.getCommandSenderWorld(), pos); + SchematicTableBlockEntity table = getTable(player.getCommandSenderWorld(), pos); if (table == null) return; @@ -140,8 +136,8 @@ public class ServerSchematicLoader { if (count >= getConfig().maxSchematics.get()) { Stream list2 = Files.list(Paths.get(playerPath)); Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) - .min(Comparator.comparingLong(f -> f.toFile() - .lastModified())); + .min(Comparator.comparingLong(f -> f.toFile() + .lastModified())); list2.close(); if (lastFilePath.isPresent()) { Files.deleteIfExists(lastFilePath.get()); @@ -152,7 +148,7 @@ public class ServerSchematicLoader { OutputStream writer = Files.newOutputStream(uploadPath); activeUploads.put(playerSchematicId, new SchematicUploadEntry(writer, size, player.getLevel(), pos)); - // Notify Tile Entity + // Notify Block Entity table.startUpload(schematic); } catch (IOException e) { @@ -166,21 +162,21 @@ public class ServerSchematicLoader { if (size > maxFileSize * 1000) { player.sendMessage(CreateLang.translateDirect("schematics.uploadTooLarge") - .append(Components.literal(" (" + size / 1000 + " KB).")), Util.NIL_UUID); + .append(Components.literal(" (" + size / 1000 + " KB).")), Util.NIL_UUID); player.sendMessage(CreateLang.translateDirect("schematics.maxAllowedSize") - .append(Components.literal(" " + maxFileSize + " KB")), Util.NIL_UUID); + .append(Components.literal(" " + maxFileSize + " KB")), Util.NIL_UUID); return false; } return true; } public CSchematics getConfig() { - return AllConfigs.SERVER.schematics; + return AllConfigs.server().schematics; } public void handleWriteRequest(ServerPlayer player, String schematic, byte[] data) { String playerSchematicId = player.getGameProfile() - .getName() + "/" + schematic; + .getName() + "/" + schematic; if (activeUploads.containsKey(playerSchematicId)) { SchematicUploadEntry entry = activeUploads.get(playerSchematicId); @@ -203,7 +199,7 @@ public class ServerSchematicLoader { entry.stream.write(data); entry.idleTime = 0; - SchematicTableTileEntity table = getTable(entry.world, entry.tablePos); + SchematicTableBlockEntity table = getTable(entry.world, entry.tablePos); if (table == null) return; table.uploadingProgress = (float) ((double) entry.bytesUploaded / entry.totalBytes); @@ -236,22 +232,22 @@ public class ServerSchematicLoader { if (pos == null) return; - SchematicTableTileEntity table = getTable(entry.world, pos); + SchematicTableBlockEntity table = getTable(entry.world, pos); if (table != null) table.finishUpload(); } - public SchematicTableTileEntity getTable(Level world, BlockPos pos) { - BlockEntity te = world.getBlockEntity(pos); - if (!(te instanceof SchematicTableTileEntity)) + public SchematicTableBlockEntity getTable(Level world, BlockPos pos) { + BlockEntity be = world.getBlockEntity(pos); + if (!(be instanceof SchematicTableBlockEntity)) return null; - SchematicTableTileEntity table = (SchematicTableTileEntity) te; + SchematicTableBlockEntity table = (SchematicTableBlockEntity) be; return table; } public void handleFinishedUpload(ServerPlayer player, String schematic) { String playerSchematicId = player.getGameProfile() - .getName() + "/" + schematic; + .getName() + "/" + schematic; if (activeUploads.containsKey(playerSchematicId)) { try { @@ -268,12 +264,12 @@ public class ServerSchematicLoader { if (AllBlocks.SCHEMATIC_TABLE.get() != blockState.getBlock()) return; - SchematicTableTileEntity table = getTable(world, pos); + SchematicTableBlockEntity table = getTable(world, pos); if (table == null) return; table.finishUpload(); table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getGameProfile() - .getName())); + .getName())); } catch (IOException e) { Create.LOGGER.error("Exception Thrown when finishing Upload: " + playerSchematicId); @@ -283,11 +279,10 @@ public class ServerSchematicLoader { } public void handleInstantSchematic(ServerPlayer player, String schematic, Level world, BlockPos pos, - BlockPos bounds) { - String playerPath = getSchematicPath() + "/" + player.getGameProfile() - .getName(); - String playerSchematicId = player.getGameProfile() - .getName() + "/" + schematic; + BlockPos bounds) { + String playerName = player.getGameProfile().getName(); + String playerPath = getSchematicPath() + "/" + playerName; + String playerSchematicId = playerName + "/" + schematic; FilesHelper.createFolderIfMissing(playerPath); // Unsupported Format @@ -297,10 +292,10 @@ public class ServerSchematicLoader { } Path schematicPath = Paths.get(getSchematicPath()) - .toAbsolutePath(); + .toAbsolutePath(); Path path = schematicPath.resolve(playerSchematicId) - .normalize(); + .normalize(); if (!path.startsWith(schematicPath)) { Create.LOGGER.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId); return; @@ -310,43 +305,43 @@ public class ServerSchematicLoader { if (!AllItems.SCHEMATIC_AND_QUILL.isIn(player.getMainHandItem())) return; + // if there's too many schematics, delete oldest + Path playerSchematics = Paths.get(playerPath); + + if (!tryDeleteOldestSchematic(playerSchematics)) + return; + + SchematicExportResult result = SchematicExport.saveSchematic( + playerSchematics, schematic, true, + world, pos, pos.offset(bounds).offset(-1, -1, -1) + ); + if (result != null) + player.setItemInHand(InteractionHand.MAIN_HAND, SchematicItem.create(schematic, playerName)); + else CreateLang.translate("schematicAndQuill.instant_failed") + .style(ChatFormatting.RED) + .sendStatus(player); + } + + private boolean tryDeleteOldestSchematic(Path dir) { + try (Stream stream = Files.list(dir)) { + List files = stream.toList(); + if (files.size() < getConfig().maxSchematics.get()) + return true; + Optional oldest = files.stream().min(Comparator.comparingLong(this::getLastModifiedTime)); + Files.delete(oldest.orElseThrow()); + return true; + } catch (IOException | IllegalStateException e) { + Create.LOGGER.error("Error deleting oldest schematic", e); + return false; + } + } + + private long getLastModifiedTime(Path file) { try { - // Delete schematic with same name - Files.deleteIfExists(path); - - // Too many Schematics - long count; - try (Stream list = Files.list(Paths.get(playerPath))) { - count = list.count(); - } - - if (count >= getConfig().maxSchematics.get()) { - Stream list2 = Files.list(Paths.get(playerPath)); - Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) - .min(Comparator.comparingLong(f -> f.toFile() - .lastModified())); - list2.close(); - if (lastFilePath.isPresent()) - Files.deleteIfExists(lastFilePath.get()); - } - - StructureTemplate t = new StructureTemplate(); - t.fillFromWorld(world, pos, bounds, true, Blocks.AIR); - - try (OutputStream outputStream = Files.newOutputStream(path)) { - CompoundTag nbttagcompound = t.save(new CompoundTag()); - SchematicAndQuillItem.replaceStructureVoidWithAir(nbttagcompound); - SchematicAndQuillItem.clampGlueBoxes(world, new AABB(pos, pos.offset(bounds)), nbttagcompound); - NbtIo.writeCompressed(nbttagcompound, outputStream); - player.setItemInHand(InteractionHand.MAIN_HAND, SchematicItem.create(schematic, player.getGameProfile() - .getName())); - - } catch (IOException e) { - e.printStackTrace(); - } + return Files.getLastModifiedTime(file).toMillis(); } catch (IOException e) { - Create.LOGGER.error("Exception Thrown in direct Schematic Upload: " + playerSchematicId); - e.printStackTrace(); + Create.LOGGER.error("Error getting modification time of file " + file.getFileName(), e); + throw new IllegalStateException(e); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java deleted file mode 100644 index 36d9eb85b3..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableContainer.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import com.simibubi.create.AllContainerTypes; -import com.simibubi.create.AllItems; -import com.simibubi.create.foundation.gui.container.ContainerBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.items.SlotItemHandler; - -public class SchematicTableContainer extends ContainerBase { - - private Slot inputSlot; - private Slot outputSlot; - - public SchematicTableContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - public SchematicTableContainer(MenuType type, int id, Inventory inv, SchematicTableTileEntity te) { - super(type, id, inv, te); - } - - public static SchematicTableContainer create(int id, Inventory inv, SchematicTableTileEntity te) { - return new SchematicTableContainer(AllContainerTypes.SCHEMATIC_TABLE.get(), id, inv, te); - } - - public boolean canWrite() { - return inputSlot.hasItem() && !outputSlot.hasItem(); - } - - @Override - public ItemStack quickMoveStack(Player playerIn, int index) { - Slot clickedSlot = getSlot(index); - if (!clickedSlot.hasItem()) - return ItemStack.EMPTY; - - ItemStack stack = clickedSlot.getItem(); - if (index < 2) - moveItemStackTo(stack, 2, slots.size(), false); - else - moveItemStackTo(stack, 0, 1, false); - - return ItemStack.EMPTY; - } - - @Override - protected SchematicTableTileEntity createOnClient(FriendlyByteBuf extraData) { - ClientLevel world = Minecraft.getInstance().level; - BlockEntity tileEntity = world.getBlockEntity(extraData.readBlockPos()); - if (tileEntity instanceof SchematicTableTileEntity schematicTable) { - schematicTable.readClient(extraData.readNbt()); - return schematicTable; - } - return null; - } - - @Override - protected void initAndReadInventory(SchematicTableTileEntity contentHolder) { - } - - @Override - protected void addSlots() { - inputSlot = new SlotItemHandler(contentHolder.inventory, 0, 21, 57) { - @Override - public boolean mayPlace(ItemStack stack) { - return AllItems.EMPTY_SCHEMATIC.isIn(stack) || AllItems.SCHEMATIC_AND_QUILL.isIn(stack) - || AllItems.SCHEMATIC.isIn(stack); - } - }; - - outputSlot = new SlotItemHandler(contentHolder.inventory, 1, 166, 57) { - @Override - public boolean mayPlace(ItemStack stack) { - return false; - } - }; - - addSlot(inputSlot); - addSlot(outputSlot); - - // player Slots - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 9; ++col) { - this.addSlot(new Slot(player.getInventory(), col + row * 9 + 9, 38 + col * 18, 105 + row * 18)); - } - } - - for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) { - this.addSlot(new Slot(player.getInventory(), hotbarSlot, 38 + hotbarSlot * 18, 163)); - } - } - - @Override - protected void saveData(SchematicTableTileEntity contentHolder) { - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableTileEntity.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableTileEntity.java deleted file mode 100644 index 6efa518ff1..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableTileEntity.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import java.util.List; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.IInteractionChecker; - -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.items.ItemStackHandler; - -public class SchematicTableTileEntity extends SmartTileEntity implements MenuProvider, IInteractionChecker { - - public SchematicTableInventory inventory; - public boolean isUploading; - public String uploadingSchematic; - public float uploadingProgress; - public boolean sendUpdate; - - public class SchematicTableInventory extends ItemStackHandler { - public SchematicTableInventory() { - super(2); - } - - @Override - protected void onContentsChanged(int slot) { - super.onContentsChanged(slot); - setChanged(); - } - } - - public SchematicTableTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - inventory = new SchematicTableInventory(); - uploadingSchematic = null; - uploadingProgress = 0; - } - - public void sendToContainer(FriendlyByteBuf buffer) { - buffer.writeBlockPos(getBlockPos()); - buffer.writeNbt(getUpdateTag()); - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - inventory.deserializeNBT(compound.getCompound("Inventory")); - super.read(compound, clientPacket); - - if (!clientPacket) - return; - if (compound.contains("Uploading")) { - isUploading = true; - uploadingSchematic = compound.getString("Schematic"); - uploadingProgress = compound.getFloat("Progress"); - } else { - isUploading = false; - uploadingSchematic = null; - uploadingProgress = 0; - } - } - - @Override - protected void write(CompoundTag compound, boolean clientPacket) { - compound.put("Inventory", inventory.serializeNBT()); - super.write(compound, clientPacket); - - if (clientPacket && isUploading) { - compound.putBoolean("Uploading", true); - compound.putString("Schematic", uploadingSchematic); - compound.putFloat("Progress", uploadingProgress); - } - } - - @Override - public void tick() { - // Update Client Tile - if (sendUpdate) { - sendUpdate = false; - level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 6); - } - } - - public void startUpload(String schematic) { - isUploading = true; - uploadingProgress = 0; - uploadingSchematic = schematic; - sendUpdate = true; - inventory.setStackInSlot(0, ItemStack.EMPTY); - } - - public void finishUpload() { - isUploading = false; - uploadingProgress = 0; - uploadingSchematic = null; - sendUpdate = true; - } - - @Override - public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { - return SchematicTableContainer.create(id, inv, this); - } - - @Override - public Component getDisplayName() { - return CreateLang.translateDirect("gui.schematicTable.title"); - } - - @Override - public boolean canPlayerUse(Player player) { - if (level == null || level.getBlockEntity(worldPosition) != this) { - return false; - } - return player.distanceToSqr(worldPosition.getX() + 0.5D, worldPosition.getY() + 0.5D, - worldPosition.getZ() + 0.5D) <= 64.0D; - } - - @Override - public void addBehaviours(List behaviours) {} - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java deleted file mode 100644 index d85de10012..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlock.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import javax.annotation.Nullable; - -import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; -import com.simibubi.create.foundation.item.ItemHelper; - -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.network.NetworkHooks; - -public class SchematicannonBlock extends Block implements ITE { - - public SchematicannonBlock(Properties properties) { - super(properties); - } - - @Override - public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return AllShapes.SCHEMATICANNON_SHAPE; - } - - @Override - public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) { - if (entity != null) { - withTileEntityDo(level, pos, be -> { - be.defaultYaw = (-Mth.floor((entity.getYRot() + (entity.isShiftKeyDown() ? 180.0F : 0.0F)) * 16.0F / 360.0F + 0.5F) & 15) * 360.0F / 16.0F; - }); - } - } - - @Override - public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, - BlockHitResult hit) { - if (worldIn.isClientSide) - return InteractionResult.SUCCESS; - withTileEntityDo(worldIn, pos, - te -> NetworkHooks.openGui((ServerPlayer) player, te, te::sendToContainer)); - return InteractionResult.SUCCESS; - } - - @Override - public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, - boolean isMoving) { - withTileEntityDo(worldIn, pos, te -> te.neighbourCheckCooldown = 0); - } - - @Override - public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) - return; - - withTileEntityDo(worldIn, pos, te -> ItemHelper.dropContents(worldIn, pos, te.inventory)); - worldIn.removeBlockEntity(pos); - } - - @Override - public Class getTileEntityClass() { - return SchematicannonTileEntity.class; - } - - @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SCHEMATICANNON.get(); - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonContainer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonContainer.java deleted file mode 100644 index 6d83bb0201..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonContainer.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import com.simibubi.create.AllContainerTypes; -import com.simibubi.create.foundation.gui.container.ContainerBase; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.items.SlotItemHandler; - -public class SchematicannonContainer extends ContainerBase { - - public SchematicannonContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf buffer) { - super(type, id, inv, buffer); - } - - public SchematicannonContainer(MenuType type, int id, Inventory inv, SchematicannonTileEntity te) { - super(type, id, inv, te); - } - - public static SchematicannonContainer create(int id, Inventory inv, SchematicannonTileEntity te) { - return new SchematicannonContainer(AllContainerTypes.SCHEMATICANNON.get(), id, inv, te); - } - - @Override - protected SchematicannonTileEntity createOnClient(FriendlyByteBuf extraData) { - ClientLevel world = Minecraft.getInstance().level; - BlockEntity tileEntity = world.getBlockEntity(extraData.readBlockPos()); - if (tileEntity instanceof SchematicannonTileEntity schematicannon) { - schematicannon.readClient(extraData.readNbt()); - return schematicannon; - } - return null; - } - - @Override - protected void initAndReadInventory(SchematicannonTileEntity contentHolder) { - } - - @Override - protected void addSlots() { - int x = 0; - int y = 0; - - addSlot(new SlotItemHandler(contentHolder.inventory, 0, x + 15, y + 65)); - addSlot(new SlotItemHandler(contentHolder.inventory, 1, x + 171, y + 65)); - addSlot(new SlotItemHandler(contentHolder.inventory, 2, x + 134, y + 19)); - addSlot(new SlotItemHandler(contentHolder.inventory, 3, x + 174, y + 19)); - addSlot(new SlotItemHandler(contentHolder.inventory, 4, x + 15, y + 19)); - - addPlayerSlots(37, 161); - } - - @Override - protected void saveData(SchematicannonTileEntity contentHolder) { - } - - @Override - public ItemStack quickMoveStack(Player playerIn, int index) { - Slot clickedSlot = getSlot(index); - if (!clickedSlot.hasItem()) - return ItemStack.EMPTY; - ItemStack stack = clickedSlot.getItem(); - - if (index < 5) { - moveItemStackTo(stack, 5, slots.size(), false); - } else { - if (moveItemStackTo(stack, 0, 1, false) || moveItemStackTo(stack, 2, 3, false) - || moveItemStackTo(stack, 4, 5, false)) - ; - } - - return ItemStack.EMPTY; - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java deleted file mode 100644 index e7252dd8f0..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import com.simibubi.create.AllItems; - -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraftforge.items.ItemStackHandler; - -public class SchematicannonInventory extends ItemStackHandler { - /** - * - */ - private final SchematicannonTileEntity te; - - public SchematicannonInventory(SchematicannonTileEntity schematicannonTileEntity) { - super(5); - te = schematicannonTileEntity; - } - - @Override - protected void onContentsChanged(int slot) { - super.onContentsChanged(slot); - te.setChanged(); - } - - @Override - public boolean isItemValid(int slot, ItemStack stack) { - switch (slot) { - case 0: // Blueprint Slot - return AllItems.SCHEMATIC.isIn(stack); - case 1: // Blueprint output - return false; - case 2: // Book input - return stack.sameItem(new ItemStack(Items.BOOK)) || stack.sameItem(new ItemStack(Items.WRITTEN_BOOK)); - case 3: // Material List output - return false; - case 4: // Gunpowder - return stack.sameItem(new ItemStack(Items.GUNPOWDER)); - default: - return super.isItemValid(slot, stack); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java deleted file mode 100644 index ae7bf5bd4e..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonRenderer.java +++ /dev/null @@ -1,226 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import java.util.Random; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Vector3f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.schematics.block.LaunchedItem.ForBelt; -import com.simibubi.create.content.schematics.block.LaunchedItem.ForBlockState; -import com.simibubi.create.content.schematics.block.LaunchedItem.ForEntity; -import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; - -import net.createmod.catnip.render.SuperByteBuffer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.util.Mth; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -public class SchematicannonRenderer extends SafeTileEntityRenderer { - - public SchematicannonRenderer(BlockEntityRendererProvider.Context context) {} - - @Override - protected void renderSafe(SchematicannonTileEntity tileEntity, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - - boolean blocksLaunching = !tileEntity.flyingBlocks.isEmpty(); - if (blocksLaunching) - renderLaunchedBlocks(tileEntity, partialTicks, ms, buffer, light, overlay); - - if (Backend.canUseInstancing(tileEntity.getLevel())) - return; - - BlockPos pos = tileEntity.getBlockPos(); - BlockState state = tileEntity.getBlockState(); - - double[] cannonAngles = getCannonAngles(tileEntity, pos, partialTicks); - - double yaw = cannonAngles[0]; - double pitch = cannonAngles[1]; - - double recoil = getRecoil(tileEntity, partialTicks); - - ms.pushPose(); - - VertexConsumer vb = buffer.getBuffer(RenderType.solid()); - - SuperByteBuffer connector = CachedPartialBuffers.partial(AllBlockPartials.SCHEMATICANNON_CONNECTOR, state); - connector.translate(.5f, 0, .5f); - connector.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); - connector.translate(-.5f, 0, -.5f); - connector.light(light) - .renderInto(ms, vb); - - SuperByteBuffer pipe = CachedPartialBuffers.partial(AllBlockPartials.SCHEMATICANNON_PIPE, state); - pipe.translate(.5f, 15 / 16f, .5f); - pipe.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); - pipe.rotate(Direction.SOUTH, (float) (pitch / 180 * Math.PI)); - pipe.translate(-.5f, -15 / 16f, -.5f); - pipe.translate(0, -recoil / 100, 0); - pipe.light(light) - .renderInto(ms, vb); - - ms.popPose(); - } - - public static double[] getCannonAngles(SchematicannonTileEntity tile, BlockPos pos, float partialTicks) { - double yaw; - double pitch; - - BlockPos target = tile.printer.getCurrentTarget(); - if (target != null) { - - // Calculate Angle of Cannon - Vec3 diff = Vec3.atLowerCornerOf(target.subtract(pos)); - if (tile.previousTarget != null) { - diff = (Vec3.atLowerCornerOf(tile.previousTarget) - .add(Vec3.atLowerCornerOf(target.subtract(tile.previousTarget)) - .scale(partialTicks))).subtract(Vec3.atLowerCornerOf(pos)); - } - - double diffX = diff.x(); - double diffZ = diff.z(); - yaw = Mth.atan2(diffX, diffZ); - yaw = yaw / Math.PI * 180; - - float distance = Mth.sqrt((float) (diffX * diffX + diffZ * diffZ)); - double yOffset = 0 + distance * 2f; - pitch = Mth.atan2(distance, diff.y() * 3 + yOffset); - pitch = pitch / Math.PI * 180 + 10; - - } else { - yaw = tile.defaultYaw; - pitch = 40; - } - - return new double[] { yaw, pitch }; - } - - public static double getRecoil(SchematicannonTileEntity tileEntityIn, float partialTicks) { - double recoil = 0; - - for (LaunchedItem launched : tileEntityIn.flyingBlocks) { - - if (launched.ticksRemaining == 0) - continue; - - // Apply Recoil if block was just launched - if ((launched.ticksRemaining + 1 - partialTicks) > launched.totalTicks - 10) - recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); - } - - return recoil; - } - - private static void renderLaunchedBlocks(SchematicannonTileEntity tileEntityIn, float partialTicks, PoseStack ms, - MultiBufferSource buffer, int light, int overlay) { - for (LaunchedItem launched : tileEntityIn.flyingBlocks) { - - if (launched.ticksRemaining == 0) - continue; - - // Calculate position of flying block - Vec3 start = Vec3.atLowerCornerOf(tileEntityIn.getBlockPos() - .offset(.5f, 1, .5f)); - Vec3 target = Vec3.atLowerCornerOf(launched.target) - .add(-.5, 0, 1); - Vec3 distance = target.subtract(start); - - double targetY = target.y - start.y; - double throwHeight = Math.sqrt(distance.lengthSqr()) * .6f + targetY; - Vec3 cannonOffset = distance.add(0, throwHeight, 0) - .normalize() - .scale(2); - start = start.add(cannonOffset); - - float progress = - ((float) launched.totalTicks - (launched.ticksRemaining + 1 - partialTicks)) / launched.totalTicks; - Vec3 blockLocationXZ = new Vec3(.5, .5, .5).add(target.subtract(start) - .scale(progress) - .multiply(1, 0, 1)); - - // Height is determined through a bezier curve - float t = progress; - double yOffset = 2 * (1 - t) * t * throwHeight + t * t * targetY; - Vec3 blockLocation = blockLocationXZ.add(0, yOffset + 1, 0) - .add(cannonOffset); - - // Offset to position - ms.pushPose(); - ms.translate(blockLocation.x, blockLocation.y, blockLocation.z); - - ms.translate(.125f, .125f, .125f); - ms.mulPose(new Vector3f(0, 1, 0).rotationDegrees(360 * t)); - ms.mulPose(new Vector3f(1, 0, 0).rotationDegrees(360 * t)); - ms.translate(-.125f, -.125f, -.125f); - - if (launched instanceof ForBlockState) { - // Render the Block - BlockState state; - if (launched instanceof ForBelt) { - // Render a shaft instead of the belt - state = AllBlocks.SHAFT.getDefaultState(); - } else { - state = ((ForBlockState) launched).state; - } - float scale = .3f; - ms.scale(scale, scale, scale); - Minecraft.getInstance() - .getBlockRenderer() - .renderSingleBlock(state, ms, buffer, light, overlay, - VirtualEmptyModelData.INSTANCE); - } else if (launched instanceof ForEntity) { - // Render the item - float scale = 1.2f; - ms.scale(scale, scale, scale); - Minecraft.getInstance() - .getItemRenderer() - .renderStatic(launched.stack, TransformType.GROUND, light, overlay, ms, buffer, 0); - } - - ms.popPose(); - - // Render particles for launch - if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) { - tileEntityIn.firstRenderTick = false; - for (int i = 0; i < 10; i++) { - Random r = tileEntityIn.getLevel() - .getRandom(); - double sX = cannonOffset.x * .01f; - double sY = (cannonOffset.y + 1) * .01f; - double sZ = cannonOffset.z * .01f; - double rX = r.nextFloat() - sX * 40; - double rY = r.nextFloat() - sY * 40; - double rZ = r.nextFloat() - sZ * 40; - tileEntityIn.getLevel() - .addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, start.z + rZ, sX, sY, sZ); - } - } - - } - } - - @Override - public boolean shouldRenderOffScreen(SchematicannonTileEntity tileEntity) { - return true; - } - - @Override - public int getViewDistance() { - return 128; - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java deleted file mode 100644 index e638797b1e..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java +++ /dev/null @@ -1,834 +0,0 @@ -package com.simibubi.create.content.schematics.block; - -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; - -import javax.annotation.Nullable; - -import com.simibubi.create.AllBlocks; -import com.simibubi.create.AllItems; -import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTags.AllBlockTags; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltPart; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.AbstractSimpleShaftBlock; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.content.schematics.MaterialChecklist; -import com.simibubi.create.content.schematics.SchematicPrinter; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CSchematics; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.IPartialSafeNBT; -import com.simibubi.create.foundation.utility.NBTProcessors; - -import net.createmod.catnip.utility.Iterate; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Direction.AxisDirection; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.piston.PistonHeadBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BedPart; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; -import net.minecraft.world.phys.AABB; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.wrapper.EmptyHandler; - -public class SchematicannonTileEntity extends SmartTileEntity implements MenuProvider { - - public static final int NEIGHBOUR_CHECKING = 100; - public static final int MAX_ANCHOR_DISTANCE = 256; - - // Inventory - public SchematicannonInventory inventory; - - public boolean sendUpdate; - // Sync - public boolean dontUpdateChecklist; - public int neighbourCheckCooldown; - - // Printer - public SchematicPrinter printer; - public ItemStack missingItem; - public boolean positionNotLoaded; - public boolean hasCreativeCrate; - private int printerCooldown; - private int skipsLeft; - private boolean blockSkipped; - - public BlockPos previousTarget; - public LinkedHashSet> attachedInventories; - public List flyingBlocks; - public MaterialChecklist checklist; - - // Gui information - public float fuelLevel; - public float bookPrintingProgress; - public float schematicProgress; - public String statusMsg; - public State state; - public int blocksPlaced; - public int blocksToPlace; - - // Settings - public int replaceMode; - public boolean skipMissing; - public boolean replaceTileEntities; - - // Render - public boolean firstRenderTick; - public float defaultYaw; - - public SchematicannonTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - setLazyTickRate(30); - attachedInventories = new LinkedHashSet<>(); - flyingBlocks = new LinkedList<>(); - inventory = new SchematicannonInventory(this); - statusMsg = "idle"; - this.state = State.STOPPED; - replaceMode = 2; - checklist = new MaterialChecklist(); - printer = new SchematicPrinter(); - } - - public void findInventories() { - hasCreativeCrate = false; - attachedInventories.clear(); - for (Direction facing : Iterate.directions) { - - if (!level.isLoaded(worldPosition.relative(facing))) - continue; - - if (AllBlocks.CREATIVE_CRATE.has(level.getBlockState(worldPosition.relative(facing)))) - hasCreativeCrate = true; - - BlockEntity tileEntity = level.getBlockEntity(worldPosition.relative(facing)); - if (tileEntity != null) { - LazyOptional capability = - tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); - if (capability.isPresent()) { - attachedInventories.add(capability); - } - } - } - } - - @Override - protected void read(CompoundTag compound, boolean clientPacket) { - if (!clientPacket) { - inventory.deserializeNBT(compound.getCompound("Inventory")); - } - - // Gui information - statusMsg = compound.getString("Status"); - schematicProgress = compound.getFloat("Progress"); - bookPrintingProgress = compound.getFloat("PaperProgress"); - fuelLevel = compound.getFloat("Fuel"); - state = State.valueOf(compound.getString("State")); - blocksPlaced = compound.getInt("AmountPlaced"); - blocksToPlace = compound.getInt("AmountToPlace"); - - missingItem = null; - if (compound.contains("MissingItem")) - missingItem = ItemStack.of(compound.getCompound("MissingItem")); - - // Settings - CompoundTag options = compound.getCompound("Options"); - replaceMode = options.getInt("ReplaceMode"); - skipMissing = options.getBoolean("SkipMissing"); - replaceTileEntities = options.getBoolean("ReplaceTileEntities"); - - // Printer & Flying Blocks - if (compound.contains("Printer")) - printer.fromTag(compound.getCompound("Printer"), clientPacket); - if (compound.contains("FlyingBlocks")) - readFlyingBlocks(compound); - - defaultYaw = compound.getFloat("DefaultYaw"); - - super.read(compound, clientPacket); - } - - protected void readFlyingBlocks(CompoundTag compound) { - ListTag tagBlocks = compound.getList("FlyingBlocks", 10); - if (tagBlocks.isEmpty()) - flyingBlocks.clear(); - - boolean pastDead = false; - - for (int i = 0; i < tagBlocks.size(); i++) { - CompoundTag c = tagBlocks.getCompound(i); - LaunchedItem launched = LaunchedItem.fromNBT(c); - BlockPos readBlockPos = launched.target; - - // Always write to Server tile - if (level == null || !level.isClientSide) { - flyingBlocks.add(launched); - continue; - } - - // Delete all Client side blocks that are now missing on the server - while (!pastDead && !flyingBlocks.isEmpty() && !flyingBlocks.get(0).target.equals(readBlockPos)) { - flyingBlocks.remove(0); - } - - pastDead = true; - - // Add new server side blocks - if (i >= flyingBlocks.size()) { - flyingBlocks.add(launched); - continue; - } - - // Don't do anything with existing - } - } - - @Override - public void write(CompoundTag compound, boolean clientPacket) { - if (!clientPacket) { - compound.put("Inventory", inventory.serializeNBT()); - if (state == State.RUNNING) { - compound.putBoolean("Running", true); - } - } - - // Gui information - compound.putFloat("Progress", schematicProgress); - compound.putFloat("PaperProgress", bookPrintingProgress); - compound.putFloat("Fuel", fuelLevel); - compound.putString("Status", statusMsg); - compound.putString("State", state.name()); - compound.putInt("AmountPlaced", blocksPlaced); - compound.putInt("AmountToPlace", blocksToPlace); - - if (missingItem != null) - compound.put("MissingItem", missingItem.serializeNBT()); - - // Settings - CompoundTag options = new CompoundTag(); - options.putInt("ReplaceMode", replaceMode); - options.putBoolean("SkipMissing", skipMissing); - options.putBoolean("ReplaceTileEntities", replaceTileEntities); - compound.put("Options", options); - - // Printer & Flying Blocks - CompoundTag printerData = new CompoundTag(); - printer.write(printerData); - compound.put("Printer", printerData); - - ListTag tagFlyingBlocks = new ListTag(); - for (LaunchedItem b : flyingBlocks) - tagFlyingBlocks.add(b.serializeNBT()); - compound.put("FlyingBlocks", tagFlyingBlocks); - - compound.putFloat("DefaultYaw", defaultYaw); - - super.write(compound, clientPacket); - } - - @Override - public void tick() { - super.tick(); - - if (state != State.STOPPED && neighbourCheckCooldown-- <= 0) { - neighbourCheckCooldown = NEIGHBOUR_CHECKING; - findInventories(); - } - - firstRenderTick = true; - previousTarget = printer.getCurrentTarget(); - tickFlyingBlocks(); - - if (level.isClientSide) - return; - - // Update Fuel and Paper - tickPaperPrinter(); - refillFuelIfPossible(); - - // Update Printer - skipsLeft = config().schematicannonSkips.get(); - blockSkipped = true; - - while (blockSkipped && skipsLeft-- > 0) - tickPrinter(); - - schematicProgress = 0; - if (blocksToPlace > 0) - schematicProgress = (float) blocksPlaced / blocksToPlace; - - // Update Client Tile - if (sendUpdate) { - sendUpdate = false; - level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 6); - } - } - - public CSchematics config() { - return AllConfigs.SERVER.schematics; - } - - protected void tickPrinter() { - ItemStack blueprint = inventory.getStackInSlot(0); - blockSkipped = false; - - // Skip if not Active - if (state == State.STOPPED) { - if (printer.isLoaded()) - resetPrinter(); - return; - } - - if (blueprint.isEmpty()) { - state = State.STOPPED; - statusMsg = "idle"; - sendUpdate = true; - return; - } - - if (state == State.PAUSED && !positionNotLoaded && missingItem == null && fuelLevel > getFuelUsageRate()) - return; - - // Initialize Printer - if (!printer.isLoaded()) { - initializePrinter(blueprint); - return; - } - - // Cooldown from last shot - if (printerCooldown > 0) { - printerCooldown--; - return; - } - - // Check Fuel - if (fuelLevel <= 0 && !hasCreativeCrate) { - fuelLevel = 0; - state = State.PAUSED; - statusMsg = "noGunpowder"; - sendUpdate = true; - return; - } - - if (hasCreativeCrate) { - if (missingItem != null) { - missingItem = null; - state = State.RUNNING; - } - } - - // Update Target - if (missingItem == null && !positionNotLoaded) { - if (!printer.advanceCurrentPos()) { - finishedPrinting(); - return; - } - sendUpdate = true; - } - - // Check block - if (!getLevel().isLoaded(printer.getCurrentTarget())) { - positionNotLoaded = true; - statusMsg = "targetNotLoaded"; - state = State.PAUSED; - return; - } else { - if (positionNotLoaded) { - positionNotLoaded = false; - state = State.RUNNING; - } - } - - // Get item requirement - ItemRequirement requirement = printer.getCurrentRequirement(); - if (requirement.isInvalid() || !printer.shouldPlaceCurrent(level, this::shouldPlace)) { - statusMsg = "searching"; - blockSkipped = true; - return; - } - - // Find item - List requiredItems = requirement.getRequiredItems(); - if (!requirement.isEmpty()) { - for (ItemRequirement.StackRequirement required : requiredItems) { - if (!grabItemsFromAttachedInventories(required, true)) { - if (skipMissing) { - statusMsg = "skipping"; - blockSkipped = true; - if (missingItem != null) { - missingItem = null; - state = State.RUNNING; - } - return; - } - - missingItem = required.stack; - state = State.PAUSED; - statusMsg = "missingBlock"; - return; - } - } - - for (ItemRequirement.StackRequirement required : requiredItems) - grabItemsFromAttachedInventories(required, false); - } - - // Success - state = State.RUNNING; - ItemStack icon = requirement.isEmpty() || requiredItems.isEmpty() ? ItemStack.EMPTY : requiredItems.get(0).stack; - printer.handleCurrentTarget((target, blockState, tile) -> { - // Launch block - statusMsg = blockState.getBlock() != Blocks.AIR ? "placing" : "clearing"; - launchBlockOrBelt(target, icon, blockState, tile); - }, (target, entity) -> { - // Launch entity - statusMsg = "placing"; - launchEntity(target, icon, entity); - }); - - printerCooldown = config().schematicannonDelay.get(); - fuelLevel -= getFuelUsageRate(); - sendUpdate = true; - missingItem = null; - } - - public double getFuelUsageRate() { - return hasCreativeCrate ? 0 : config().schematicannonFuelUsage.get() / 100f; - } - - protected void initializePrinter(ItemStack blueprint) { - if (!blueprint.hasTag()) { - state = State.STOPPED; - statusMsg = "schematicInvalid"; - sendUpdate = true; - return; - } - - if (!blueprint.getTag() - .getBoolean("Deployed")) { - state = State.STOPPED; - statusMsg = "schematicNotPlaced"; - sendUpdate = true; - return; - } - - // Load blocks into reader - printer.loadSchematic(blueprint, level, true); - - if (printer.isWorldEmpty()) { - state = State.STOPPED; - statusMsg = "schematicExpired"; - inventory.setStackInSlot(0, ItemStack.EMPTY); - inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_SCHEMATIC.get())); - printer.resetSchematic(); - return; - } - - if (!printer.getAnchor() - .closerThan(getBlockPos(), MAX_ANCHOR_DISTANCE)) { - state = State.STOPPED; - statusMsg = "targetOutsideRange"; - printer.resetSchematic(); - return; - } - - state = State.PAUSED; - statusMsg = "ready"; - updateChecklist(); - sendUpdate = true; - blocksToPlace += blocksPlaced; - } - - protected ItemStack getItemForBlock(BlockState blockState) { - Item item = BlockItem.BY_BLOCK.getOrDefault(blockState.getBlock(), Items.AIR); - return item == Items.AIR ? ItemStack.EMPTY : new ItemStack(item); - } - - protected boolean grabItemsFromAttachedInventories(ItemRequirement.StackRequirement required, boolean simulate) { - if (hasCreativeCrate) - return true; - - attachedInventories.removeIf(cap -> !cap.isPresent()); - - ItemUseType usage = required.usage; - - // Find and apply damage - if (usage == ItemUseType.DAMAGE) { - for (LazyOptional cap : attachedInventories) { - IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); - for (int slot = 0; slot < iItemHandler.getSlots(); slot++) { - ItemStack extractItem = iItemHandler.extractItem(slot, 1, true); - if (!required.matches(extractItem)) - continue; - if (!extractItem.isDamageableItem()) - continue; - - if (!simulate) { - ItemStack stack = iItemHandler.extractItem(slot, 1, false); - stack.setDamageValue(stack.getDamageValue() + 1); - if (stack.getDamageValue() <= stack.getMaxDamage()) { - if (iItemHandler.getStackInSlot(slot) - .isEmpty()) - iItemHandler.insertItem(slot, stack, false); - else - ItemHandlerHelper.insertItem(iItemHandler, stack, false); - } - } - - return true; - } - } - - return false; - } - - // Find and remove - boolean success = false; - int amountFound = 0; - for (LazyOptional cap : attachedInventories) { - IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); - amountFound += ItemHelper - .extract(iItemHandler, required::matches, ExtractionCountMode.UPTO, - required.stack.getCount(), true) - .getCount(); - - if (amountFound < required.stack.getCount()) - continue; - - success = true; - break; - } - - if (!simulate && success) { - amountFound = 0; - for (LazyOptional cap : attachedInventories) { - IItemHandler iItemHandler = cap.orElse(EmptyHandler.INSTANCE); - amountFound += ItemHelper - .extract(iItemHandler, required::matches, ExtractionCountMode.UPTO, - required.stack.getCount(), false) - .getCount(); - if (amountFound < required.stack.getCount()) - continue; - break; - } - } - - return success; - } - - public void finishedPrinting() { - inventory.setStackInSlot(0, ItemStack.EMPTY); - inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_SCHEMATIC.get(), inventory.getStackInSlot(1) - .getCount() + 1)); - state = State.STOPPED; - statusMsg = "finished"; - resetPrinter(); - AllSoundEvents.SCHEMATICANNON_FINISH.playOnServer(level, worldPosition); - sendUpdate = true; - } - - protected void resetPrinter() { - printer.resetSchematic(); - missingItem = null; - sendUpdate = true; - schematicProgress = 0; - blocksPlaced = 0; - blocksToPlace = 0; - } - - protected boolean shouldPlace(BlockPos pos, BlockState state, BlockEntity te, BlockState toReplace, - BlockState toReplaceOther, boolean isNormalCube) { - if (pos.closerThan(getBlockPos(), 2f)) - return false; - if (!replaceTileEntities - && (toReplace.hasBlockEntity() || (toReplaceOther != null && toReplaceOther.hasBlockEntity()))) - return false; - - if (shouldIgnoreBlockState(state, te)) - return false; - - boolean placingAir = state.isAir(); - - if (replaceMode == 3) - return true; - if (replaceMode == 2 && !placingAir) - return true; - if (replaceMode == 1 && (isNormalCube || (!toReplace.isRedstoneConductor(level, pos) - && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)))) && !placingAir) - return true; - if (replaceMode == 0 && !toReplace.isRedstoneConductor(level, pos) - && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)) && !placingAir) - return true; - - return false; - } - - protected boolean shouldIgnoreBlockState(BlockState state, BlockEntity te) { - // Block doesn't have a mapping (Water, lava, etc) - if (state.getBlock() == Blocks.STRUCTURE_VOID) - return true; - - ItemRequirement requirement = ItemRequirement.of(state, te); - if (requirement.isEmpty()) - return false; - if (requirement.isInvalid()) - return false; - - // Block doesn't need to be placed twice (Doors, beds, double plants) - if (state.hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF) - && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.UPPER) - return true; - if (state.hasProperty(BlockStateProperties.BED_PART) - && state.getValue(BlockStateProperties.BED_PART) == BedPart.HEAD) - return true; - if (state.getBlock() instanceof PistonHeadBlock) - return true; - if (AllBlocks.BELT.has(state)) - return state.getValue(BeltBlock.PART) == BeltPart.MIDDLE; - - return false; - } - - protected void tickFlyingBlocks() { - List toRemove = new LinkedList<>(); - for (LaunchedItem b : flyingBlocks) - if (b.update(level)) - toRemove.add(b); - flyingBlocks.removeAll(toRemove); - } - - protected void refillFuelIfPossible() { - if (hasCreativeCrate) - return; - if (1 - fuelLevel + 1 / 128f < getFuelAddedByGunPowder()) - return; - if (inventory.getStackInSlot(4) - .isEmpty()) - return; - - inventory.getStackInSlot(4) - .shrink(1); - fuelLevel += getFuelAddedByGunPowder(); - sendUpdate = true; - } - - public double getFuelAddedByGunPowder() { - return config().schematicannonGunpowderWorth.get() / 100f; - } - - protected void tickPaperPrinter() { - int BookInput = 2; - int BookOutput = 3; - - ItemStack blueprint = inventory.getStackInSlot(0); - ItemStack paper = inventory.extractItem(BookInput, 1, true); - boolean outputFull = inventory.getStackInSlot(BookOutput) - .getCount() == inventory.getSlotLimit(BookOutput); - - if (paper.isEmpty() || outputFull) { - if (bookPrintingProgress != 0) - sendUpdate = true; - bookPrintingProgress = 0; - dontUpdateChecklist = false; - return; - } - - if (!printer.isLoaded()) { - if (!blueprint.isEmpty()) - initializePrinter(blueprint); - return; - } - - if (bookPrintingProgress >= 1) { - bookPrintingProgress = 0; - - if (!dontUpdateChecklist) - updateChecklist(); - - dontUpdateChecklist = true; - inventory.extractItem(BookInput, 1, false); - ItemStack stack = checklist.createItem(); - stack.setCount(inventory.getStackInSlot(BookOutput) - .getCount() + 1); - inventory.setStackInSlot(BookOutput, stack); - sendUpdate = true; - return; - } - - bookPrintingProgress += 0.05f; - sendUpdate = true; - } - - public static BlockState stripBeltIfNotLast(BlockState blockState) { - BeltPart part = blockState.getValue(BeltBlock.PART); - if (part == BeltPart.MIDDLE) - return Blocks.AIR.defaultBlockState(); - - // is highest belt? - boolean isLastSegment = false; - Direction facing = blockState.getValue(BeltBlock.HORIZONTAL_FACING); - BeltSlope slope = blockState.getValue(BeltBlock.SLOPE); - boolean positive = facing.getAxisDirection() == AxisDirection.POSITIVE; - boolean start = part == BeltPart.START; - boolean end = part == BeltPart.END; - - switch (slope) { - case DOWNWARD: - isLastSegment = start; - break; - case UPWARD: - isLastSegment = end; - break; - default: - isLastSegment = positive && end || !positive && start; - } - if (isLastSegment) - return blockState; - - return AllBlocks.SHAFT.getDefaultState() - .setValue(AbstractSimpleShaftBlock.AXIS, slope == BeltSlope.SIDEWAYS ? Axis.Y : - facing.getClockWise() - .getAxis()); - } - - protected void launchBlockOrBelt(BlockPos target, ItemStack icon, BlockState blockState, BlockEntity tile) { - if (AllBlocks.BELT.has(blockState)) { - blockState = stripBeltIfNotLast(blockState); - if (tile instanceof BeltTileEntity && AllBlocks.BELT.has(blockState)) - launchBelt(target, blockState, ((BeltTileEntity) tile).beltLength); - else if (blockState != Blocks.AIR.defaultBlockState()) - launchBlock(target, icon, blockState, null); - } else { - CompoundTag data = null; - if (tile != null) { - if (AllBlockTags.SAFE_NBT.matches(blockState)) { - data = tile.saveWithFullMetadata(); - data = NBTProcessors.process(tile, data, true); - } else if (tile instanceof IPartialSafeNBT) { - data = new CompoundTag(); - ((IPartialSafeNBT) tile).writeSafe(data); - data = NBTProcessors.process(tile, data, true); - } - } - launchBlock(target, icon, blockState, data); - } - } - - protected void launchBelt(BlockPos target, BlockState state, int length) { - blocksPlaced++; - ItemStack connector = AllItems.BELT_CONNECTOR.asStack(); - flyingBlocks.add(new LaunchedItem.ForBelt(this.getBlockPos(), target, connector, state, length)); - playFiringSound(); - } - - protected void launchBlock(BlockPos target, ItemStack stack, BlockState state, @Nullable CompoundTag data) { - if (!state.isAir()) - blocksPlaced++; - flyingBlocks.add(new LaunchedItem.ForBlockState(this.getBlockPos(), target, stack, state, data)); - playFiringSound(); - } - - protected void launchEntity(BlockPos target, ItemStack stack, Entity entity) { - blocksPlaced++; - flyingBlocks.add(new LaunchedItem.ForEntity(this.getBlockPos(), target, stack, entity)); - playFiringSound(); - } - - public void playFiringSound() { - AllSoundEvents.SCHEMATICANNON_LAUNCH_BLOCK.playOnServer(level, worldPosition); - } - - public void sendToContainer(FriendlyByteBuf buffer) { - buffer.writeBlockPos(getBlockPos()); - buffer.writeNbt(getUpdateTag()); - } - - @Override - public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { - return SchematicannonContainer.create(id, inv, this); - } - - @Override - public Component getDisplayName() { - return CreateLang.translateDirect("gui.schematicannon.title"); - } - - public void updateChecklist() { - checklist.required.clear(); - checklist.damageRequired.clear(); - checklist.blocksNotLoaded = false; - - if (printer.isLoaded()) { - blocksToPlace = blocksPlaced; - blocksToPlace += printer.markAllBlockRequirements(checklist, level, this::shouldPlace); - printer.markAllEntityRequirements(checklist); - } - checklist.gathered.clear(); - findInventories(); - for (LazyOptional cap : attachedInventories) { - if (!cap.isPresent()) - continue; - IItemHandler inventory = cap.orElse(EmptyHandler.INSTANCE); - for (int slot = 0; slot < inventory.getSlots(); slot++) { - ItemStack stackInSlot = inventory.getStackInSlot(slot); - if (inventory.extractItem(slot, 1, true) - .isEmpty()) - continue; - checklist.collect(stackInSlot); - } - } - sendUpdate = true; - } - - @Override - public void addBehaviours(List behaviours) {} - - @Override - public void lazyTick() { - super.lazyTick(); - findInventories(); - } - - @Override - @OnlyIn(Dist.CLIENT) - public AABB getRenderBoundingBox() { - return INFINITE_EXTENT_AABB; - } - - public enum State { - STOPPED, PAUSED, RUNNING; - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/ConfigureSchematicannonPacket.java b/src/main/java/com/simibubi/create/content/schematics/cannon/ConfigureSchematicannonPacket.java new file mode 100644 index 0000000000..041e0ae155 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/ConfigureSchematicannonPacket.java @@ -0,0 +1,77 @@ +package com.simibubi.create.content.schematics.cannon; + +import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity.State; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ConfigureSchematicannonPacket extends SimplePacketBase { + + public static enum Option { + DONT_REPLACE, REPLACE_SOLID, REPLACE_ANY, REPLACE_EMPTY, SKIP_MISSING, SKIP_BLOCK_ENTITIES, PLAY, PAUSE, STOP; + } + + private Option option; + private boolean set; + + public ConfigureSchematicannonPacket(Option option, boolean set) { + this.option = option; + this.set = set; + } + + public ConfigureSchematicannonPacket(FriendlyByteBuf buffer) { + this(buffer.readEnum(Option.class), buffer.readBoolean()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeEnum(option); + buffer.writeBoolean(set); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null || !(player.containerMenu instanceof SchematicannonMenu)) + return; + + SchematicannonBlockEntity be = ((SchematicannonMenu) player.containerMenu).contentHolder; + switch (option) { + case DONT_REPLACE: + case REPLACE_ANY: + case REPLACE_EMPTY: + case REPLACE_SOLID: + be.replaceMode = option.ordinal(); + break; + case SKIP_MISSING: + be.skipMissing = set; + break; + case SKIP_BLOCK_ENTITIES: + be.replaceBlockEntities = set; + break; + + case PLAY: + be.state = State.RUNNING; + be.statusMsg = "running"; + break; + case PAUSE: + be.state = State.PAUSED; + be.statusMsg = "paused"; + break; + case STOP: + be.state = State.STOPPED; + be.statusMsg = "stopped"; + break; + default: + break; + } + + be.sendUpdate = true; + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/LaunchedItem.java b/src/main/java/com/simibubi/create/content/schematics/cannon/LaunchedItem.java similarity index 79% rename from src/main/java/com/simibubi/create/content/schematics/block/LaunchedItem.java rename to src/main/java/com/simibubi/create/content/schematics/cannon/LaunchedItem.java index 3990f5794c..7e919fa332 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/LaunchedItem.java +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/LaunchedItem.java @@ -1,13 +1,16 @@ -package com.simibubi.create.content.schematics.block; +package com.simibubi.create.content.schematics.cannon; +import java.util.Arrays; import java.util.Optional; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltPart; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorItem; -import com.simibubi.create.content.contraptions.relays.elementary.AbstractSimpleShaftBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity.CasingType; +import com.simibubi.create.content.kinetics.belt.BeltPart; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.belt.item.BeltConnectorItem; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock; import com.simibubi.create.foundation.utility.BlockHelper; import net.minecraft.core.BlockPos; @@ -15,6 +18,7 @@ import net.minecraft.core.Direction.Axis; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; +import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; @@ -126,6 +130,7 @@ public abstract class LaunchedItem { public static class ForBelt extends ForBlockState { public int length; + public CasingType[] casings; public ForBelt() {} @@ -133,18 +138,27 @@ public abstract class LaunchedItem { public CompoundTag serializeNBT() { CompoundTag serializeNBT = super.serializeNBT(); serializeNBT.putInt("Length", length); + serializeNBT.putIntArray("Casing", Arrays.stream(casings) + .map(CasingType::ordinal) + .toList()); return serializeNBT; } @Override void readNBT(CompoundTag nbt) { length = nbt.getInt("Length"); + int[] intArray = nbt.getIntArray("Casing"); + casings = new CasingType[length]; + for (int i = 0; i < casings.length; i++) + casings[i] = i >= intArray.length ? CasingType.NONE + : CasingType.values()[Mth.clamp(intArray[i], 0, CasingType.values().length - 1)]; super.readNBT(nbt); } - public ForBelt(BlockPos start, BlockPos target, ItemStack stack, BlockState state, int length) { + public ForBelt(BlockPos start, BlockPos target, ItemStack stack, BlockState state, CasingType[] casings) { super(start, target, stack, state, null); - this.length = length; + this.casings = casings; + this.length = casings.length; } @Override @@ -160,6 +174,15 @@ public abstract class LaunchedItem { .setValue(AbstractSimpleShaftBlock.AXIS, axis)); BeltConnectorItem.createBelts(world, target, target.offset(offset.getX() * i, offset.getY() * i, offset.getZ() * i)); + + for (int segment = 0; segment < length; segment++) { + if (casings[segment] == CasingType.NONE) + continue; + BlockPos casingTarget = + target.offset(offset.getX() * segment, offset.getY() * segment, offset.getZ() * segment); + if (world.getBlockEntity(casingTarget) instanceof BeltBlockEntity bbe) + bbe.setCasingType(casings[segment]); + } } } diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/MaterialChecklist.java b/src/main/java/com/simibubi/create/content/schematics/cannon/MaterialChecklist.java new file mode 100644 index 0000000000..5174e31967 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/MaterialChecklist.java @@ -0,0 +1,258 @@ +package com.simibubi.create.content.schematics.cannon; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import com.google.common.collect.Sets; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.equipment.clipboard.ClipboardEntry; +import com.simibubi.create.content.equipment.clipboard.ClipboardOverrides; +import com.simibubi.create.content.equipment.clipboard.ClipboardOverrides.ClipboardType; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.utility.CreateLang; + +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class MaterialChecklist { + + public static final int MAX_ENTRIES_PER_PAGE = 5; + public static final int MAX_ENTRIES_PER_CLIPBOARD_PAGE = 7; + + public Object2IntMap gathered = new Object2IntArrayMap<>(); + public Object2IntMap required = new Object2IntArrayMap<>(); + public Object2IntMap damageRequired = new Object2IntArrayMap<>(); + public boolean blocksNotLoaded; + + public void warnBlockNotLoaded() { + blocksNotLoaded = true; + } + + public void require(ItemRequirement requirement) { + if (requirement.isEmpty()) + return; + if (requirement.isInvalid()) + return; + + for (ItemRequirement.StackRequirement stack : requirement.getRequiredItems()) { + if (stack.usage == ItemUseType.DAMAGE) + putOrIncrement(damageRequired, stack.stack); + if (stack.usage == ItemUseType.CONSUME) + putOrIncrement(required, stack.stack); + } + } + + private void putOrIncrement(Object2IntMap map, ItemStack stack) { + Item item = stack.getItem(); + if (item == Items.AIR) + return; + if (map.containsKey(item)) + map.put(item, map.getInt(item) + stack.getCount()); + else + map.put(item, stack.getCount()); + } + + public void collect(ItemStack stack) { + Item item = stack.getItem(); + if (required.containsKey(item) || damageRequired.containsKey(item)) + if (gathered.containsKey(item)) + gathered.put(item, gathered.getInt(item) + stack.getCount()); + else + gathered.put(item, stack.getCount()); + } + + public ItemStack createWrittenBook() { + ItemStack book = new ItemStack(Items.WRITTEN_BOOK); + + CompoundTag tag = book.getOrCreateTag(); + ListTag pages = new ListTag(); + + int itemsWritten = 0; + MutableComponent textComponent; + + if (blocksNotLoaded) { + textComponent = Components.literal("\n" + ChatFormatting.RED); + textComponent = textComponent.append(CreateLang.translateDirect("materialChecklist.blocksNotLoaded")); + pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); + } + + List keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet())); + Collections.sort(keys, (item1, item2) -> { + Locale locale = Locale.ENGLISH; + String name1 = item1.getDescription() + .getString() + .toLowerCase(locale); + String name2 = item2.getDescription() + .getString() + .toLowerCase(locale); + return name1.compareTo(name2); + }); + + textComponent = Components.empty(); + List completed = new ArrayList<>(); + for (Item item : keys) { + int amount = getRequiredAmount(item); + if (gathered.containsKey(item)) + amount -= gathered.getInt(item); + + if (amount <= 0) { + completed.add(item); + continue; + } + + if (itemsWritten == MAX_ENTRIES_PER_PAGE) { + itemsWritten = 0; + textComponent.append(Components.literal("\n >>>") + .withStyle(ChatFormatting.BLUE)); + pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); + textComponent = Components.empty(); + } + + itemsWritten++; + textComponent.append(entry(new ItemStack(item), amount, true, true)); + } + + for (Item item : completed) { + if (itemsWritten == MAX_ENTRIES_PER_PAGE) { + itemsWritten = 0; + textComponent.append(Components.literal("\n >>>") + .withStyle(ChatFormatting.DARK_GREEN)); + pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); + textComponent = Components.empty(); + } + + itemsWritten++; + textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false, true)); + } + + pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); + + tag.put("pages", pages); + tag.putBoolean("readonly", true); + tag.putString("author", "Schematicannon"); + tag.putString("title", ChatFormatting.BLUE + "Material Checklist"); + textComponent = CreateLang.translateDirect("materialChecklist") + .setStyle(Style.EMPTY.withColor(ChatFormatting.BLUE) + .withItalic(Boolean.FALSE)); + book.getOrCreateTagElement("display") + .putString("Name", Component.Serializer.toJson(textComponent)); + book.setTag(tag); + + return book; + } + + public ItemStack createWrittenClipboard() { + ItemStack clipboard = AllBlocks.CLIPBOARD.asStack(); + CompoundTag tag = clipboard.getOrCreateTag(); + int itemsWritten = 0; + + List> pages = new ArrayList<>(); + List currentPage = new ArrayList<>(); + + if (blocksNotLoaded) { + currentPage.add(new ClipboardEntry(false, CreateLang.translateDirect("materialChecklist.blocksNotLoaded") + .withStyle(ChatFormatting.RED))); + } + + List keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet())); + Collections.sort(keys, (item1, item2) -> { + Locale locale = Locale.ENGLISH; + String name1 = item1.getDescription() + .getString() + .toLowerCase(locale); + String name2 = item2.getDescription() + .getString() + .toLowerCase(locale); + return name1.compareTo(name2); + }); + + List completed = new ArrayList<>(); + for (Item item : keys) { + int amount = getRequiredAmount(item); + if (gathered.containsKey(item)) + amount -= gathered.getInt(item); + + if (amount <= 0) { + completed.add(item); + continue; + } + + if (itemsWritten == MAX_ENTRIES_PER_CLIPBOARD_PAGE) { + itemsWritten = 0; + currentPage.add(new ClipboardEntry(false, Components.literal(">>>") + .withStyle(ChatFormatting.DARK_GRAY))); + pages.add(currentPage); + currentPage = new ArrayList<>(); + } + + itemsWritten++; + currentPage.add(new ClipboardEntry(false, entry(new ItemStack(item), amount, true, false)) + .displayItem(new ItemStack(item))); + } + + for (Item item : completed) { + if (itemsWritten == MAX_ENTRIES_PER_CLIPBOARD_PAGE) { + itemsWritten = 0; + currentPage.add(new ClipboardEntry(true, Components.literal(">>>") + .withStyle(ChatFormatting.DARK_GREEN))); + pages.add(currentPage); + currentPage = new ArrayList<>(); + } + + itemsWritten++; + currentPage.add(new ClipboardEntry(true, entry(new ItemStack(item), getRequiredAmount(item), false, false)) + .displayItem(new ItemStack(item))); + } + + pages.add(currentPage); + ClipboardEntry.saveAll(pages, clipboard); + ClipboardOverrides.switchTo(ClipboardType.WRITTEN, clipboard); + clipboard.getOrCreateTagElement("display") + .putString("Name", Component.Serializer.toJson(CreateLang.translateDirect("materialChecklist") + .setStyle(Style.EMPTY.withItalic(Boolean.FALSE)))); + tag.putBoolean("Readonly", true); + clipboard.setTag(tag); + return clipboard; + } + + public int getRequiredAmount(Item item) { + int amount = required.getOrDefault(item, 0); + if (damageRequired.containsKey(item)) + amount += Math.ceil(damageRequired.getInt(item) / (float) new ItemStack(item).getMaxDamage()); + return amount; + } + + private MutableComponent entry(ItemStack item, int amount, boolean unfinished, boolean forBook) { + int stacks = amount / 64; + int remainder = amount % 64; + MutableComponent tc = Components.empty(); + tc.append(Components.translatable(item.getDescriptionId()) + .setStyle(Style.EMPTY + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(item))))); + + if (!unfinished && forBook) + tc.append(" \u2714"); + if (!unfinished || forBook) + tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN); + return tc.append(Components.literal("\n" + " x" + amount) + .withStyle(ChatFormatting.BLACK)) + .append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + (forBook ? "\n" : "")) + .withStyle(ChatFormatting.GRAY)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlock.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlock.java new file mode 100644 index 0000000000..227481f8a7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlock.java @@ -0,0 +1,83 @@ +package com.simibubi.create.content.schematics.cannon; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllShapes; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.item.ItemHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.network.NetworkHooks; + +public class SchematicannonBlock extends Block implements IBE { + + public SchematicannonBlock(Properties properties) { + super(properties); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + return AllShapes.SCHEMATICANNON_SHAPE; + } + + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) { + if (entity != null) { + withBlockEntityDo(level, pos, be -> { + be.defaultYaw = (-Mth.floor((entity.getYRot() + (entity.isShiftKeyDown() ? 180.0F : 0.0F)) * 16.0F / 360.0F + 0.5F) & 15) * 360.0F / 16.0F; + }); + } + } + + @Override + public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn, + BlockHitResult hit) { + if (worldIn.isClientSide) + return InteractionResult.SUCCESS; + withBlockEntityDo(worldIn, pos, + be -> NetworkHooks.openGui((ServerPlayer) player, be, be::sendToMenu)); + return InteractionResult.SUCCESS; + } + + @Override + public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + withBlockEntityDo(worldIn, pos, be -> be.neighbourCheckCooldown = 0); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) + return; + + withBlockEntityDo(worldIn, pos, be -> ItemHelper.dropContents(worldIn, pos, be.inventory)); + worldIn.removeBlockEntity(pos); + } + + @Override + public Class getBlockEntityClass() { + return SchematicannonBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SCHEMATICANNON.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlockEntity.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlockEntity.java new file mode 100644 index 0000000000..69fb1dffcd --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonBlockEntity.java @@ -0,0 +1,864 @@ +package com.simibubi.create.content.schematics.cannon; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.belt.BeltBlock; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity; +import com.simibubi.create.content.kinetics.belt.BeltBlockEntity.CasingType; +import com.simibubi.create.content.kinetics.belt.BeltPart; +import com.simibubi.create.content.kinetics.belt.BeltSlope; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock; +import com.simibubi.create.content.schematics.SchematicPrinter; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; +import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CSchematics; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.piston.PistonHeadBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BedPart; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.EmptyHandler; + +public class SchematicannonBlockEntity extends SmartBlockEntity implements MenuProvider { + + public static final int NEIGHBOUR_CHECKING = 100; + public static final int MAX_ANCHOR_DISTANCE = 256; + + // Inventory + public SchematicannonInventory inventory; + + public boolean sendUpdate; + // Sync + public boolean dontUpdateChecklist; + public int neighbourCheckCooldown; + + // Printer + public SchematicPrinter printer; + public ItemStack missingItem; + public boolean positionNotLoaded; + public boolean hasCreativeCrate; + private int printerCooldown; + private int skipsLeft; + private boolean blockSkipped; + + public BlockPos previousTarget; + public LinkedHashSet> attachedInventories; + public List flyingBlocks; + public MaterialChecklist checklist; + + // Gui information + public float fuelLevel; + public float bookPrintingProgress; + public float schematicProgress; + public String statusMsg; + public State state; + public int blocksPlaced; + public int blocksToPlace; + + // Settings + public int replaceMode; + public boolean skipMissing; + public boolean replaceBlockEntities; + + // Render + public boolean firstRenderTick; + public float defaultYaw; + + public SchematicannonBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(30); + attachedInventories = new LinkedHashSet<>(); + flyingBlocks = new LinkedList<>(); + inventory = new SchematicannonInventory(this); + statusMsg = "idle"; + this.state = State.STOPPED; + replaceMode = 2; + checklist = new MaterialChecklist(); + printer = new SchematicPrinter(); + } + + public void findInventories() { + hasCreativeCrate = false; + attachedInventories.clear(); + for (Direction facing : Iterate.directions) { + + if (!level.isLoaded(worldPosition.relative(facing))) + continue; + + if (AllBlocks.CREATIVE_CRATE.has(level.getBlockState(worldPosition.relative(facing)))) + hasCreativeCrate = true; + + BlockEntity blockEntity = level.getBlockEntity(worldPosition.relative(facing)); + if (blockEntity != null) { + LazyOptional capability = + blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); + if (capability.isPresent()) { + attachedInventories.add(capability); + } + } + } + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + if (!clientPacket) { + inventory.deserializeNBT(compound.getCompound("Inventory")); + } + + // Gui information + statusMsg = compound.getString("Status"); + schematicProgress = compound.getFloat("Progress"); + bookPrintingProgress = compound.getFloat("PaperProgress"); + fuelLevel = compound.getFloat("Fuel"); + String stateString = compound.getString("State"); + state = stateString.isEmpty() ? State.STOPPED : State.valueOf(compound.getString("State")); + blocksPlaced = compound.getInt("AmountPlaced"); + blocksToPlace = compound.getInt("AmountToPlace"); + + missingItem = null; + if (compound.contains("MissingItem")) + missingItem = ItemStack.of(compound.getCompound("MissingItem")); + + // Settings + CompoundTag options = compound.getCompound("Options"); + replaceMode = options.getInt("ReplaceMode"); + skipMissing = options.getBoolean("SkipMissing"); + replaceBlockEntities = options.getBoolean("ReplaceTileEntities"); + + // Printer & Flying Blocks + if (compound.contains("Printer")) + printer.fromTag(compound.getCompound("Printer"), clientPacket); + if (compound.contains("FlyingBlocks")) + readFlyingBlocks(compound); + + defaultYaw = compound.getFloat("DefaultYaw"); + + super.read(compound, clientPacket); + } + + protected void readFlyingBlocks(CompoundTag compound) { + ListTag tagBlocks = compound.getList("FlyingBlocks", 10); + if (tagBlocks.isEmpty()) + flyingBlocks.clear(); + + boolean pastDead = false; + + for (int i = 0; i < tagBlocks.size(); i++) { + CompoundTag c = tagBlocks.getCompound(i); + LaunchedItem launched = LaunchedItem.fromNBT(c); + BlockPos readBlockPos = launched.target; + + // Always write to Server block entity + if (level == null || !level.isClientSide) { + flyingBlocks.add(launched); + continue; + } + + // Delete all Client side blocks that are now missing on the server + while (!pastDead && !flyingBlocks.isEmpty() && !flyingBlocks.get(0).target.equals(readBlockPos)) { + flyingBlocks.remove(0); + } + + pastDead = true; + + // Add new server side blocks + if (i >= flyingBlocks.size()) { + flyingBlocks.add(launched); + continue; + } + + // Don't do anything with existing + } + } + + @Override + public void write(CompoundTag compound, boolean clientPacket) { + if (!clientPacket) { + compound.put("Inventory", inventory.serializeNBT()); + if (state == State.RUNNING) { + compound.putBoolean("Running", true); + } + } + + // Gui information + compound.putFloat("Progress", schematicProgress); + compound.putFloat("PaperProgress", bookPrintingProgress); + compound.putFloat("Fuel", fuelLevel); + compound.putString("Status", statusMsg); + compound.putString("State", state.name()); + compound.putInt("AmountPlaced", blocksPlaced); + compound.putInt("AmountToPlace", blocksToPlace); + + if (missingItem != null) + compound.put("MissingItem", missingItem.serializeNBT()); + + // Settings + CompoundTag options = new CompoundTag(); + options.putInt("ReplaceMode", replaceMode); + options.putBoolean("SkipMissing", skipMissing); + options.putBoolean("ReplaceTileEntities", replaceBlockEntities); + compound.put("Options", options); + + // Printer & Flying Blocks + CompoundTag printerData = new CompoundTag(); + printer.write(printerData); + compound.put("Printer", printerData); + + ListTag tagFlyingBlocks = new ListTag(); + for (LaunchedItem b : flyingBlocks) + tagFlyingBlocks.add(b.serializeNBT()); + compound.put("FlyingBlocks", tagFlyingBlocks); + + compound.putFloat("DefaultYaw", defaultYaw); + + super.write(compound, clientPacket); + } + + @Override + public void tick() { + super.tick(); + + if (state != State.STOPPED && neighbourCheckCooldown-- <= 0) { + neighbourCheckCooldown = NEIGHBOUR_CHECKING; + findInventories(); + } + + firstRenderTick = true; + previousTarget = printer.getCurrentTarget(); + tickFlyingBlocks(); + + if (level.isClientSide) + return; + + // Update Fuel and Paper + tickPaperPrinter(); + refillFuelIfPossible(); + + // Update Printer + skipsLeft = 1000; + blockSkipped = true; + + while (blockSkipped && skipsLeft-- > 0) + tickPrinter(); + + schematicProgress = 0; + if (blocksToPlace > 0) + schematicProgress = (float) blocksPlaced / blocksToPlace; + + // Update Client block entity + if (sendUpdate) { + sendUpdate = false; + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 6); + } + } + + public CSchematics config() { + return AllConfigs.server().schematics; + } + + protected void tickPrinter() { + ItemStack blueprint = inventory.getStackInSlot(0); + blockSkipped = false; + + if (blueprint.isEmpty() && !statusMsg.equals("idle") && inventory.getStackInSlot(1) + .isEmpty()) { + state = State.STOPPED; + statusMsg = "idle"; + sendUpdate = true; + return; + } + + // Skip if not Active + if (state == State.STOPPED) { + if (printer.isLoaded()) + resetPrinter(); + return; + } + + if (state == State.PAUSED && !positionNotLoaded && missingItem == null && fuelLevel > getFuelUsageRate()) + return; + + // Initialize Printer + if (!printer.isLoaded()) { + initializePrinter(blueprint); + return; + } + + // Cooldown from last shot + if (printerCooldown > 0) { + printerCooldown--; + return; + } + + // Check Fuel + if (fuelLevel <= 0 && !hasCreativeCrate) { + fuelLevel = 0; + state = State.PAUSED; + statusMsg = "noGunpowder"; + sendUpdate = true; + return; + } + + if (hasCreativeCrate) { + if (missingItem != null) { + missingItem = null; + state = State.RUNNING; + } + } + + // Update Target + if (missingItem == null && !positionNotLoaded) { + if (!printer.advanceCurrentPos()) { + finishedPrinting(); + return; + } + sendUpdate = true; + } + + // Check block + if (!getLevel().isLoaded(printer.getCurrentTarget())) { + positionNotLoaded = true; + statusMsg = "targetNotLoaded"; + state = State.PAUSED; + return; + } else { + if (positionNotLoaded) { + positionNotLoaded = false; + state = State.RUNNING; + } + } + + // Get item requirement + ItemRequirement requirement = printer.getCurrentRequirement(); + if (requirement.isInvalid() || !printer.shouldPlaceCurrent(level, this::shouldPlace)) { + sendUpdate = !statusMsg.equals("searching"); + statusMsg = "searching"; + blockSkipped = true; + return; + } + + // Find item + List requiredItems = requirement.getRequiredItems(); + if (!requirement.isEmpty()) { + for (ItemRequirement.StackRequirement required : requiredItems) { + if (!grabItemsFromAttachedInventories(required, true)) { + if (skipMissing) { + statusMsg = "skipping"; + blockSkipped = true; + if (missingItem != null) { + missingItem = null; + state = State.RUNNING; + } + return; + } + + missingItem = required.stack; + state = State.PAUSED; + statusMsg = "missingBlock"; + return; + } + } + + for (ItemRequirement.StackRequirement required : requiredItems) + grabItemsFromAttachedInventories(required, false); + } + + // Success + state = State.RUNNING; + ItemStack icon = requirement.isEmpty() || requiredItems.isEmpty() ? ItemStack.EMPTY : requiredItems.get(0).stack; + printer.handleCurrentTarget((target, blockState, blockEntity) -> { + // Launch block + statusMsg = blockState.getBlock() != Blocks.AIR ? "placing" : "clearing"; + launchBlockOrBelt(target, icon, blockState, blockEntity); + }, (target, entity) -> { + // Launch entity + statusMsg = "placing"; + launchEntity(target, icon, entity); + }); + + printerCooldown = config().schematicannonDelay.get(); + fuelLevel -= getFuelUsageRate(); + sendUpdate = true; + missingItem = null; + } + + public double getFuelUsageRate() { + return hasCreativeCrate ? 0 : config().schematicannonFuelUsage.get() / 100f; + } + + protected void initializePrinter(ItemStack blueprint) { + if (!blueprint.hasTag()) { + state = State.STOPPED; + statusMsg = "schematicInvalid"; + sendUpdate = true; + return; + } + + if (!blueprint.getTag() + .getBoolean("Deployed")) { + state = State.STOPPED; + statusMsg = "schematicNotPlaced"; + sendUpdate = true; + return; + } + + // Load blocks into reader + printer.loadSchematic(blueprint, level, true); + + if (printer.isErrored()) { + state = State.STOPPED; + statusMsg = "schematicErrored"; + inventory.setStackInSlot(0, ItemStack.EMPTY); + inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_SCHEMATIC.get())); + printer.resetSchematic(); + sendUpdate = true; + return; + } + + if (printer.isWorldEmpty()) { + state = State.STOPPED; + statusMsg = "schematicExpired"; + inventory.setStackInSlot(0, ItemStack.EMPTY); + inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_SCHEMATIC.get())); + printer.resetSchematic(); + sendUpdate = true; + return; + } + + if (!printer.getAnchor() + .closerThan(getBlockPos(), MAX_ANCHOR_DISTANCE)) { + state = State.STOPPED; + statusMsg = "targetOutsideRange"; + printer.resetSchematic(); + sendUpdate = true; + return; + } + + state = State.PAUSED; + statusMsg = "ready"; + updateChecklist(); + sendUpdate = true; + blocksToPlace += blocksPlaced; + } + + protected ItemStack getItemForBlock(BlockState blockState) { + Item item = BlockItem.BY_BLOCK.getOrDefault(blockState.getBlock(), Items.AIR); + return item == Items.AIR ? ItemStack.EMPTY : new ItemStack(item); + } + + protected boolean grabItemsFromAttachedInventories(ItemRequirement.StackRequirement required, boolean simulate) { + if (hasCreativeCrate) + return true; + + attachedInventories.removeIf(cap -> !cap.isPresent()); + + ItemUseType usage = required.usage; + + // Find and apply damage + if (usage == ItemUseType.DAMAGE) { + for (LazyOptional cap : attachedInventories) { + IItemHandler itemHandler = cap.orElse(EmptyHandler.INSTANCE); + for (int slot = 0; slot < itemHandler.getSlots(); slot++) { + ItemStack extractItem = itemHandler.extractItem(slot, 1, true); + if (!required.matches(extractItem)) + continue; + if (!extractItem.isDamageableItem()) + continue; + + if (!simulate) { + ItemStack stack = itemHandler.extractItem(slot, 1, false); + stack.setDamageValue(stack.getDamageValue() + 1); + if (stack.getDamageValue() <= stack.getMaxDamage()) { + if (itemHandler.getStackInSlot(slot) + .isEmpty()) + itemHandler.insertItem(slot, stack, false); + else + ItemHandlerHelper.insertItem(itemHandler, stack, false); + } + } + + return true; + } + } + + return false; + } + + // Find and remove + boolean success = false; + int amountFound = 0; + for (LazyOptional cap : attachedInventories) { + IItemHandler itemHandler = cap.orElse(EmptyHandler.INSTANCE); + amountFound += ItemHelper + .extract(itemHandler, required::matches, ExtractionCountMode.UPTO, + required.stack.getCount(), true) + .getCount(); + + if (amountFound < required.stack.getCount()) + continue; + + success = true; + break; + } + + if (!simulate && success) { + amountFound = 0; + for (LazyOptional cap : attachedInventories) { + IItemHandler itemHandler = cap.orElse(EmptyHandler.INSTANCE); + amountFound += ItemHelper + .extract(itemHandler, required::matches, ExtractionCountMode.UPTO, + required.stack.getCount(), false) + .getCount(); + if (amountFound < required.stack.getCount()) + continue; + break; + } + } + + return success; + } + + public void finishedPrinting() { + inventory.setStackInSlot(0, ItemStack.EMPTY); + inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_SCHEMATIC.get(), inventory.getStackInSlot(1) + .getCount() + 1)); + state = State.STOPPED; + statusMsg = "finished"; + resetPrinter(); + AllSoundEvents.SCHEMATICANNON_FINISH.playOnServer(level, worldPosition); + sendUpdate = true; + } + + protected void resetPrinter() { + printer.resetSchematic(); + missingItem = null; + sendUpdate = true; + schematicProgress = 0; + blocksPlaced = 0; + blocksToPlace = 0; + } + + protected boolean shouldPlace(BlockPos pos, BlockState state, BlockEntity be, BlockState toReplace, + BlockState toReplaceOther, boolean isNormalCube) { + if (pos.closerThan(getBlockPos(), 2f)) + return false; + if (!replaceBlockEntities + && (toReplace.hasBlockEntity() || (toReplaceOther != null && toReplaceOther.hasBlockEntity()))) + return false; + + if (shouldIgnoreBlockState(state, be)) + return false; + + boolean placingAir = state.isAir(); + + if (replaceMode == 3) + return true; + if (replaceMode == 2 && !placingAir) + return true; + if (replaceMode == 1 && (isNormalCube || (!toReplace.isRedstoneConductor(level, pos) + && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)))) && !placingAir) + return true; + if (replaceMode == 0 && !toReplace.isRedstoneConductor(level, pos) + && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)) && !placingAir) + return true; + + return false; + } + + protected boolean shouldIgnoreBlockState(BlockState state, BlockEntity be) { + // Block doesn't have a mapping (Water, lava, etc) + if (state.getBlock() == Blocks.STRUCTURE_VOID) + return true; + + ItemRequirement requirement = ItemRequirement.of(state, be); + if (requirement.isEmpty()) + return false; + if (requirement.isInvalid()) + return false; + + // Block doesn't need to be placed twice (Doors, beds, double plants) + if (state.hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF) + && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.UPPER) + return true; + if (state.hasProperty(BlockStateProperties.BED_PART) + && state.getValue(BlockStateProperties.BED_PART) == BedPart.HEAD) + return true; + if (state.getBlock() instanceof PistonHeadBlock) + return true; + if (AllBlocks.BELT.has(state)) + return state.getValue(BeltBlock.PART) == BeltPart.MIDDLE; + + return false; + } + + protected void tickFlyingBlocks() { + List toRemove = new LinkedList<>(); + for (LaunchedItem b : flyingBlocks) + if (b.update(level)) + toRemove.add(b); + flyingBlocks.removeAll(toRemove); + } + + protected void refillFuelIfPossible() { + if (hasCreativeCrate) + return; + if (1 - fuelLevel + 1 / 128f < getFuelAddedByGunPowder()) + return; + if (inventory.getStackInSlot(4) + .isEmpty()) + return; + + inventory.getStackInSlot(4) + .shrink(1); + fuelLevel += getFuelAddedByGunPowder(); + if (statusMsg.equals("noGunpowder")) { + if (blocksPlaced > 0) + state = State.RUNNING; + statusMsg = "ready"; + } + sendUpdate = true; + } + + public double getFuelAddedByGunPowder() { + return config().schematicannonGunpowderWorth.get() / 100f; + } + + protected void tickPaperPrinter() { + int BookInput = 2; + int BookOutput = 3; + + ItemStack blueprint = inventory.getStackInSlot(0); + ItemStack paper = inventory.extractItem(BookInput, 1, true); + boolean outputFull = inventory.getStackInSlot(BookOutput) + .getCount() == inventory.getSlotLimit(BookOutput); + + if (printer.isErrored()) + return; + + if (!printer.isLoaded()) { + if (!blueprint.isEmpty()) + initializePrinter(blueprint); + return; + } + + if (paper.isEmpty() || outputFull) { + if (bookPrintingProgress != 0) + sendUpdate = true; + bookPrintingProgress = 0; + dontUpdateChecklist = false; + return; + } + + if (bookPrintingProgress >= 1) { + bookPrintingProgress = 0; + + if (!dontUpdateChecklist) + updateChecklist(); + + dontUpdateChecklist = true; + ItemStack extractItem = inventory.extractItem(BookInput, 1, false); + ItemStack stack = AllBlocks.CLIPBOARD.isIn(extractItem) ? checklist.createWrittenClipboard() + : checklist.createWrittenBook(); + stack.setCount(inventory.getStackInSlot(BookOutput) + .getCount() + 1); + inventory.setStackInSlot(BookOutput, stack); + sendUpdate = true; + return; + } + + bookPrintingProgress += 0.05f; + sendUpdate = true; + } + + public static BlockState stripBeltIfNotLast(BlockState blockState) { + BeltPart part = blockState.getValue(BeltBlock.PART); + if (part == BeltPart.MIDDLE) + return Blocks.AIR.defaultBlockState(); + + // is highest belt? + boolean isLastSegment = false; + Direction facing = blockState.getValue(BeltBlock.HORIZONTAL_FACING); + BeltSlope slope = blockState.getValue(BeltBlock.SLOPE); + boolean positive = facing.getAxisDirection() == AxisDirection.POSITIVE; + boolean start = part == BeltPart.START; + boolean end = part == BeltPart.END; + + switch (slope) { + case DOWNWARD: + isLastSegment = start; + break; + case UPWARD: + isLastSegment = end; + break; + default: + isLastSegment = positive && end || !positive && start; + } + if (isLastSegment) + return blockState; + + return AllBlocks.SHAFT.getDefaultState() + .setValue(AbstractSimpleShaftBlock.AXIS, slope == BeltSlope.SIDEWAYS ? Axis.Y + : facing.getClockWise() + .getAxis()); + } + + protected void launchBlockOrBelt(BlockPos target, ItemStack icon, BlockState blockState, BlockEntity blockEntity) { + if (AllBlocks.BELT.has(blockState)) { + blockState = stripBeltIfNotLast(blockState); + if (blockEntity instanceof BeltBlockEntity bbe && AllBlocks.BELT.has(blockState)) { + CasingType[] casings = new CasingType[bbe.beltLength]; + Arrays.fill(casings, CasingType.NONE); + BlockPos currentPos = target; + for (int i = 0; i < bbe.beltLength; i++) { + BlockState currentState = bbe.getLevel() + .getBlockState(currentPos); + if (!(currentState.getBlock() instanceof BeltBlock)) + break; + if (!(bbe.getLevel() + .getBlockEntity(currentPos) instanceof BeltBlockEntity beltAtSegment)) + break; + casings[i] = beltAtSegment.casing; + currentPos = BeltBlock.nextSegmentPosition(currentState, currentPos, + blockState.getValue(BeltBlock.PART) != BeltPart.END); + } + launchBelt(target, blockState, bbe.beltLength, casings); + } else if (blockState != Blocks.AIR.defaultBlockState()) + launchBlock(target, icon, blockState, null); + return; + } + + CompoundTag data = BlockHelper.prepareBlockEntityData(blockState, blockEntity); + launchBlock(target, icon, blockState, data); + } + + protected void launchBelt(BlockPos target, BlockState state, int length, CasingType[] casings) { + blocksPlaced++; + ItemStack connector = AllItems.BELT_CONNECTOR.asStack(); + flyingBlocks.add(new LaunchedItem.ForBelt(this.getBlockPos(), target, connector, state, casings)); + playFiringSound(); + } + + protected void launchBlock(BlockPos target, ItemStack stack, BlockState state, @Nullable CompoundTag data) { + if (!state.isAir()) + blocksPlaced++; + flyingBlocks.add(new LaunchedItem.ForBlockState(this.getBlockPos(), target, stack, state, data)); + playFiringSound(); + } + + protected void launchEntity(BlockPos target, ItemStack stack, Entity entity) { + blocksPlaced++; + flyingBlocks.add(new LaunchedItem.ForEntity(this.getBlockPos(), target, stack, entity)); + playFiringSound(); + } + + public void playFiringSound() { + AllSoundEvents.SCHEMATICANNON_LAUNCH_BLOCK.playOnServer(level, worldPosition); + } + + public void sendToMenu(FriendlyByteBuf buffer) { + buffer.writeBlockPos(getBlockPos()); + buffer.writeNbt(getUpdateTag()); + } + + @Override + public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { + return SchematicannonMenu.create(id, inv, this); + } + + @Override + public Component getDisplayName() { + return CreateLang.translateDirect("gui.schematicannon.title"); + } + + public void updateChecklist() { + checklist.required.clear(); + checklist.damageRequired.clear(); + checklist.blocksNotLoaded = false; + + if (printer.isLoaded() && !printer.isErrored()) { + blocksToPlace = blocksPlaced; + blocksToPlace += printer.markAllBlockRequirements(checklist, level, this::shouldPlace); + printer.markAllEntityRequirements(checklist); + } + + checklist.gathered.clear(); + findInventories(); + for (LazyOptional cap : attachedInventories) { + if (!cap.isPresent()) + continue; + IItemHandler inventory = cap.orElse(EmptyHandler.INSTANCE); + for (int slot = 0; slot < inventory.getSlots(); slot++) { + ItemStack stackInSlot = inventory.getStackInSlot(slot); + if (inventory.extractItem(slot, 1, true) + .isEmpty()) + continue; + checklist.collect(stackInSlot); + } + } + sendUpdate = true; + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void lazyTick() { + super.lazyTick(); + findInventories(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getRenderBoundingBox() { + return INFINITE_EXTENT_AABB; + } + + public enum State { + STOPPED, PAUSED, RUNNING; + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInstance.java similarity index 82% rename from src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java rename to src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInstance.java index 83d29c1d0d..6d88ae16ee 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInstance.java +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.schematics.block; +package com.simibubi.create.content.schematics.cannon; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; @@ -7,23 +7,23 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllPartialModels; import net.createmod.catnip.utility.AnimationTickHolder; import net.minecraft.core.Direction; -public class SchematicannonInstance extends BlockEntityInstance implements DynamicInstance { +public class SchematicannonInstance extends BlockEntityInstance implements DynamicInstance { private final ModelData connector; private final ModelData pipe; - public SchematicannonInstance(MaterialManager modelManager, SchematicannonTileEntity tile) { - super(modelManager, tile); + public SchematicannonInstance(MaterialManager materialManager, SchematicannonBlockEntity blockEntity) { + super(materialManager, blockEntity); Material mat = getTransformMaterial(); - connector = mat.getModel(AllBlockPartials.SCHEMATICANNON_CONNECTOR, blockState).createInstance(); - pipe = mat.getModel(AllBlockPartials.SCHEMATICANNON_PIPE, blockState).createInstance(); + connector = mat.getModel(AllPartialModels.SCHEMATICANNON_CONNECTOR, blockState).createInstance(); + pipe = mat.getModel(AllPartialModels.SCHEMATICANNON_PIPE, blockState).createInstance(); } @Override diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInventory.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInventory.java new file mode 100644 index 0000000000..9292e6fb4c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonInventory.java @@ -0,0 +1,42 @@ +package com.simibubi.create.content.schematics.cannon; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.items.ItemStackHandler; + +public class SchematicannonInventory extends ItemStackHandler { + private final SchematicannonBlockEntity blockEntity; + + public SchematicannonInventory(SchematicannonBlockEntity blockEntity) { + super(5); + this.blockEntity = blockEntity; + } + + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + blockEntity.setChanged(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + switch (slot) { + case 0: // Blueprint Slot + return AllItems.SCHEMATIC.isIn(stack); + case 1: // Blueprint output + return false; + case 2: // Book input + return AllBlocks.CLIPBOARD.isIn(stack) || stack.sameItem(new ItemStack(Items.BOOK)) + || stack.sameItem(new ItemStack(Items.WRITTEN_BOOK)); + case 3: // Material List output + return false; + case 4: // Gunpowder + return stack.sameItem(new ItemStack(Items.GUNPOWDER)); + default: + return super.isItemValid(slot, stack); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonMenu.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonMenu.java new file mode 100644 index 0000000000..a46b07696f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonMenu.java @@ -0,0 +1,82 @@ +package com.simibubi.create.content.schematics.cannon; + +import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.foundation.gui.menu.MenuBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.SlotItemHandler; + +public class SchematicannonMenu extends MenuBase { + + public SchematicannonMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf buffer) { + super(type, id, inv, buffer); + } + + public SchematicannonMenu(MenuType type, int id, Inventory inv, SchematicannonBlockEntity be) { + super(type, id, inv, be); + } + + public static SchematicannonMenu create(int id, Inventory inv, SchematicannonBlockEntity be) { + return new SchematicannonMenu(AllMenuTypes.SCHEMATICANNON.get(), id, inv, be); + } + + @Override + protected SchematicannonBlockEntity createOnClient(FriendlyByteBuf extraData) { + ClientLevel world = Minecraft.getInstance().level; + BlockEntity blockEntity = world.getBlockEntity(extraData.readBlockPos()); + if (blockEntity instanceof SchematicannonBlockEntity schematicannon) { + schematicannon.readClient(extraData.readNbt()); + return schematicannon; + } + return null; + } + + @Override + protected void initAndReadInventory(SchematicannonBlockEntity contentHolder) { + } + + @Override + protected void addSlots() { + int x = 0; + int y = 0; + + addSlot(new SlotItemHandler(contentHolder.inventory, 0, x + 15, y + 65)); + addSlot(new SlotItemHandler(contentHolder.inventory, 1, x + 171, y + 65)); + addSlot(new SlotItemHandler(contentHolder.inventory, 2, x + 134, y + 19)); + addSlot(new SlotItemHandler(contentHolder.inventory, 3, x + 174, y + 19)); + addSlot(new SlotItemHandler(contentHolder.inventory, 4, x + 15, y + 19)); + + addPlayerSlots(37, 161); + } + + @Override + protected void saveData(SchematicannonBlockEntity contentHolder) { + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + Slot clickedSlot = getSlot(index); + if (!clickedSlot.hasItem()) + return ItemStack.EMPTY; + ItemStack stack = clickedSlot.getItem(); + + if (index < 5) { + moveItemStackTo(stack, 5, slots.size(), false); + } else { + if (moveItemStackTo(stack, 0, 1, false) || moveItemStackTo(stack, 2, 3, false) + || moveItemStackTo(stack, 4, 5, false)) + ; + } + + return ItemStack.EMPTY; + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonRenderer.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonRenderer.java new file mode 100644 index 0000000000..cfc6479c49 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonRenderer.java @@ -0,0 +1,226 @@ +package com.simibubi.create.content.schematics.cannon; + +import java.util.Random; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.schematics.cannon.LaunchedItem.ForBelt; +import com.simibubi.create.content.schematics.cannon.LaunchedItem.ForBlockState; +import com.simibubi.create.content.schematics.cannon.LaunchedItem.ForEntity; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class SchematicannonRenderer extends SafeBlockEntityRenderer { + + public SchematicannonRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(SchematicannonBlockEntity blockEntity, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + boolean blocksLaunching = !blockEntity.flyingBlocks.isEmpty(); + if (blocksLaunching) + renderLaunchedBlocks(blockEntity, partialTicks, ms, buffer, light, overlay); + + if (Backend.canUseInstancing(blockEntity.getLevel())) + return; + + BlockPos pos = blockEntity.getBlockPos(); + BlockState state = blockEntity.getBlockState(); + + double[] cannonAngles = getCannonAngles(blockEntity, pos, partialTicks); + + double yaw = cannonAngles[0]; + double pitch = cannonAngles[1]; + + double recoil = getRecoil(blockEntity, partialTicks); + + ms.pushPose(); + + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + + SuperByteBuffer connector = CachedPartialBuffers.partial(AllPartialModels.SCHEMATICANNON_CONNECTOR, state); + connector.translate(.5f, 0, .5f); + connector.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); + connector.translate(-.5f, 0, -.5f); + connector.light(light) + .renderInto(ms, vb); + + SuperByteBuffer pipe = CachedPartialBuffers.partial(AllPartialModels.SCHEMATICANNON_PIPE, state); + pipe.translate(.5f, 15 / 16f, .5f); + pipe.rotate(Direction.UP, (float) ((yaw + 90) / 180 * Math.PI)); + pipe.rotate(Direction.SOUTH, (float) (pitch / 180 * Math.PI)); + pipe.translate(-.5f, -15 / 16f, -.5f); + pipe.translate(0, -recoil / 100, 0); + pipe.light(light) + .renderInto(ms, vb); + + ms.popPose(); + } + + public static double[] getCannonAngles(SchematicannonBlockEntity blockEntity, BlockPos pos, float partialTicks) { + double yaw; + double pitch; + + BlockPos target = blockEntity.printer.getCurrentTarget(); + if (target != null) { + + // Calculate Angle of Cannon + Vec3 diff = Vec3.atLowerCornerOf(target.subtract(pos)); + if (blockEntity.previousTarget != null) { + diff = (Vec3.atLowerCornerOf(blockEntity.previousTarget) + .add(Vec3.atLowerCornerOf(target.subtract(blockEntity.previousTarget)) + .scale(partialTicks))).subtract(Vec3.atLowerCornerOf(pos)); + } + + double diffX = diff.x(); + double diffZ = diff.z(); + yaw = Mth.atan2(diffX, diffZ); + yaw = yaw / Math.PI * 180; + + float distance = Mth.sqrt((float) (diffX * diffX + diffZ * diffZ)); + double yOffset = 0 + distance * 2f; + pitch = Mth.atan2(distance, diff.y() * 3 + yOffset); + pitch = pitch / Math.PI * 180 + 10; + + } else { + yaw = blockEntity.defaultYaw; + pitch = 40; + } + + return new double[] { yaw, pitch }; + } + + public static double getRecoil(SchematicannonBlockEntity blockEntity, float partialTicks) { + double recoil = 0; + + for (LaunchedItem launched : blockEntity.flyingBlocks) { + + if (launched.ticksRemaining == 0) + continue; + + // Apply Recoil if block was just launched + if ((launched.ticksRemaining + 1 - partialTicks) > launched.totalTicks - 10) + recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10); + } + + return recoil; + } + + private static void renderLaunchedBlocks(SchematicannonBlockEntity blockEntity, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + for (LaunchedItem launched : blockEntity.flyingBlocks) { + + if (launched.ticksRemaining == 0) + continue; + + // Calculate position of flying block + Vec3 start = Vec3.atCenterOf(blockEntity.getBlockPos() + .above()); + Vec3 target = Vec3.atCenterOf(launched.target); + Vec3 distance = target.subtract(start); + + double yDifference = target.y - start.y; + double throwHeight = Math.sqrt(distance.lengthSqr()) * .6f + yDifference; + Vec3 cannonOffset = distance.add(0, throwHeight, 0) + .normalize() + .scale(2); + start = start.add(cannonOffset); + yDifference = target.y - start.y; + + float progress = + ((float) launched.totalTicks - (launched.ticksRemaining + 1 - partialTicks)) / launched.totalTicks; + Vec3 blockLocationXZ = target.subtract(start) + .scale(progress) + .multiply(1, 0, 1); + + // Height is determined through a bezier curve + float t = progress; + double yOffset = 2 * (1 - t) * t * throwHeight + t * t * yDifference; + Vec3 blockLocation = blockLocationXZ.add(0.5, yOffset + 1.5, 0.5) + .add(cannonOffset); + + // Offset to position + ms.pushPose(); + ms.translate(blockLocation.x, blockLocation.y, blockLocation.z); + + ms.translate(.125f, .125f, .125f); + ms.mulPose(new Vector3f(0, 1, 0).rotationDegrees(360 * t)); + ms.mulPose(new Vector3f(1, 0, 0).rotationDegrees(360 * t)); + ms.translate(-.125f, -.125f, -.125f); + + if (launched instanceof ForBlockState) { + // Render the Block + BlockState state; + if (launched instanceof ForBelt) { + // Render a shaft instead of the belt + state = AllBlocks.SHAFT.getDefaultState(); + } else { + state = ((ForBlockState) launched).state; + } + float scale = .3f; + ms.scale(scale, scale, scale); + Minecraft.getInstance() + .getBlockRenderer() + .renderSingleBlock(state, ms, buffer, light, overlay, VirtualEmptyModelData.INSTANCE); + } else if (launched instanceof ForEntity) { + // Render the item + float scale = 1.2f; + ms.scale(scale, scale, scale); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(launched.stack, TransformType.GROUND, light, overlay, ms, buffer, 0); + } + + ms.popPose(); + + // Render particles for launch + if (launched.ticksRemaining == launched.totalTicks && blockEntity.firstRenderTick) { + start = start.subtract(.5, .5, .5); + blockEntity.firstRenderTick = false; + for (int i = 0; i < 10; i++) { + Random r = blockEntity.getLevel() + .getRandom(); + double sX = cannonOffset.x * .01f; + double sY = (cannonOffset.y + 1) * .01f; + double sZ = cannonOffset.z * .01f; + double rX = r.nextFloat() - sX * 40; + double rY = r.nextFloat() - sY * 40; + double rZ = r.nextFloat() - sZ * 40; + blockEntity.getLevel() + .addParticle(ParticleTypes.CLOUD, start.x + rX, start.y + rY, start.z + rZ, sX, sY, sZ); + } + } + + } + } + + @Override + public boolean shouldRenderOffScreen(SchematicannonBlockEntity blockEntity) { + return true; + } + + @Override + public int getViewDistance() { + return 128; + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonScreen.java similarity index 80% rename from src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java rename to src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonScreen.java index 0d9ceb736a..4e5f59bb00 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/cannon/SchematicannonScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.schematics.block; +package com.simibubi.create.content.schematics.cannon; import static net.minecraft.ChatFormatting.BLUE; import static net.minecraft.ChatFormatting.DARK_PURPLE; @@ -12,21 +12,19 @@ import java.util.Vector; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket; -import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket.Option; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.schematics.cannon.ConfigureSchematicannonPacket.Option; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Indicator; import com.simibubi.create.foundation.gui.widget.Indicator.State; -import com.simibubi.create.foundation.item.ItemDescription.Palette; import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.element.GuiGameElement; -import net.createmod.catnip.utility.FontHelper; +import net.createmod.catnip.utility.FontHelper.Palette; import net.createmod.catnip.utility.lang.Components; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.renderer.Rect2i; @@ -34,7 +32,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class SchematicannonScreen extends AbstractSimiContainerScreen { +public class SchematicannonScreen extends AbstractSimiContainerScreen { private static final AllGuiTextures BG_BOTTOM = AllGuiTextures.SCHEMATICANNON_BOTTOM; private static final AllGuiTextures BG_TOP = AllGuiTextures.SCHEMATICANNON_TOP; @@ -57,8 +55,8 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen extraAreas = Collections.emptyList(); - public SchematicannonScreen(SchematicannonContainer container, Inventory inventory, Component title) { - super(container, inventory, title); + public SchematicannonScreen(SchematicannonMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); placementSettingWidgets = new ArrayList<>(); } @@ -174,13 +172,13 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen { - sendOptionUpdate(Option.SKIP_TILES, !menu.contentHolder.replaceTileEntities); + skipBlockEntitiesButton = new IconButton(x + 129, y + 117, AllIcons.I_SKIP_BLOCK_ENTITIES); + skipBlockEntitiesButton.withCallback(() -> { + sendOptionUpdate(Option.SKIP_BLOCK_ENTITIES, !menu.contentHolder.replaceBlockEntities); }); - skipTilesButton.setToolTip(CreateLang.translateDirect("gui.schematicannon.option.skipTileEntities")); - skipTilesIndicator = new Indicator(x + 129, y + 111, Components.immutableEmpty()); - Collections.addAll(placementSettingWidgets, skipTilesButton, skipTilesIndicator); + skipBlockEntitiesButton.setToolTip(CreateLang.translateDirect("gui.schematicannon.option.skipBlockEntities")); + skipBlockEntitiesIndicator = new Indicator(x + 129, y + 111, Components.immutableEmpty()); + Collections.addAll(placementSettingWidgets, skipBlockEntitiesButton, skipBlockEntitiesIndicator); addRenderableWidgets(placementSettingWidgets); } @@ -193,22 +191,22 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen tip = button.getToolTip(); tip.add((enabled ? optionEnabled : optionDisabled).plainCopy() .withStyle(BLUE)); - tip.addAll(FontHelper - .cutTextComponent(CreateLang.translateDirect("gui.schematicannon.option." + tooltipKey + ".description"), GRAY, GRAY)); + tip.addAll(TooltipHelper + .cutTextComponent(CreateLang.translateDirect("gui.schematicannon.option." + tooltipKey + ".description"), Palette.ALL_GRAY)); } @Override @@ -283,12 +281,12 @@ public class SchematicannonScreen extends AbstractSimiContainerScreenat(x + 128, y + 49, 100) .scale(1) .render(ms); } font.drawShadow(ms, msg, x + 103 - stringWidth / 2, y + 53, 0xCCDDFF); + + if ("schematicErrored".equals(be.statusMsg)) + font.drawShadow(ms, CreateLang.translateDirect("schematicannon.status.schematicErroredCheckLogs"), + x + 103 - stringWidth / 2, y + 65, 0xCCDDFF); } protected void renderBlueprintHighlight(PoseStack matrixStack, int x, int y) { @@ -328,7 +330,7 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen= fuelX && mouseY >= fuelY && mouseX <= fuelX + AllGuiTextures.SCHEMATICANNON_FUEL.getWidth() && mouseY <= fuelY + AllGuiTextures.SCHEMATICANNON_FUEL.getHeight()) { - List tooltip = getFuelLevelTooltip(te); + List tooltip = getFuelLevelTooltip(be); renderComponentTooltip(matrixStack, tooltip, mouseX, mouseY); } if (hoveredSlot != null && !hoveredSlot.hasItem()) { if (hoveredSlot.index == 0) renderComponentTooltip(matrixStack, - FontHelper.cutTextComponent(CreateLang.translateDirect(_slotSchematic), GRAY, BLUE), mouseX, mouseY); + TooltipHelper.cutTextComponent(CreateLang.translateDirect(_slotSchematic), Palette.GRAY_AND_BLUE), mouseX, mouseY); if (hoveredSlot.index == 2) renderComponentTooltip(matrixStack, - FontHelper.cutTextComponent(CreateLang.translateDirect(_slotListPrinter), GRAY, BLUE), mouseX, mouseY); + TooltipHelper.cutTextComponent(CreateLang.translateDirect(_slotListPrinter), Palette.GRAY_AND_BLUE), mouseX, mouseY); if (hoveredSlot.index == 4) renderComponentTooltip(matrixStack, - FontHelper.cutTextComponent(CreateLang.translateDirect(_slotGunpowder), GRAY, BLUE), mouseX, mouseY); + TooltipHelper.cutTextComponent(CreateLang.translateDirect(_slotGunpowder), Palette.GRAY_AND_BLUE), mouseX, mouseY); } - if (te.missingItem != null) { + if (be.missingItem != null) { int missingBlockX = x + 128, missingBlockY = y + 49; if (mouseX >= missingBlockX && mouseY >= missingBlockY && mouseX <= missingBlockX + 16 && mouseY <= missingBlockY + 16) { - renderTooltip(matrixStack, te.missingItem, mouseX, mouseY); + renderTooltip(matrixStack, be.missingItem, mouseX, mouseY); } } @@ -382,14 +384,14 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen getFuelLevelTooltip(SchematicannonTileEntity te) { - double fuelUsageRate = te.getFuelUsageRate(); - int shotsLeft = (int) (te.fuelLevel / fuelUsageRate); - int shotsLeftWithItems = (int) (shotsLeft + te.inventory.getStackInSlot(4) - .getCount() * (te.getFuelAddedByGunPowder() / fuelUsageRate)); + protected List getFuelLevelTooltip(SchematicannonBlockEntity be) { + double fuelUsageRate = be.getFuelUsageRate(); + int shotsLeft = (int) (be.fuelLevel / fuelUsageRate); + int shotsLeftWithItems = (int) (shotsLeft + be.inventory.getStackInSlot(4) + .getCount() * (be.getFuelAddedByGunPowder() / fuelUsageRate)); List tooltip = new ArrayList<>(); - if (te.hasCreativeCrate) { + if (be.hasCreativeCrate) { tooltip.add(CreateLang.translateDirect(_gunpowderLevel, "" + 100)); tooltip.add(Components.literal("(").append(AllBlocks.CREATIVE_CRATE.get() .getName()) @@ -398,7 +400,7 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen maxSize * 1000) { LocalPlayer player = Minecraft.getInstance().player; if (player != null) { @@ -96,7 +96,7 @@ public class ClientSchematicLoader { private void continueUpload(String schematic) { if (activeUploads.containsKey(schematic)) { - Integer maxPacketSize = AllConfigs.SERVER.schematics.maxSchematicPacketSize.get(); + Integer maxPacketSize = AllConfigs.server().schematics.maxSchematicPacketSize.get(); byte[] data = new byte[maxPacketSize]; try { int status = activeUploads.get(schematic).read(data); @@ -105,7 +105,7 @@ public class ClientSchematicLoader { if (status < maxPacketSize) data = Arrays.copyOf(data, status); if (Minecraft.getInstance().level != null) - AllPackets.channel.sendToServer(SchematicUploadPacket.write(schematic, data)); + AllPackets.getChannel().sendToServer(SchematicUploadPacket.write(schematic, data)); else { activeUploads.remove(schematic); return; @@ -122,7 +122,7 @@ public class ClientSchematicLoader { private void finishUpload(String schematic) { if (activeUploads.containsKey(schematic)) { - AllPackets.channel.sendToServer(SchematicUploadPacket.finish(schematic)); + AllPackets.getChannel().sendToServer(SchematicUploadPacket.finish(schematic)); activeUploads.remove(schematic); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java index a75a8b970b..4162921f86 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicAndQuillHandler.java @@ -1,24 +1,18 @@ package com.simibubi.create.content.schematics.client; import java.io.IOException; -import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; - -import org.apache.commons.io.IOUtils; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.Create; -import com.simibubi.create.content.schematics.ClientSchematicLoader; -import com.simibubi.create.content.schematics.item.SchematicAndQuillItem; +import com.simibubi.create.content.schematics.SchematicExport; +import com.simibubi.create.content.schematics.SchematicExport.SchematicExportResult; import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; -import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; @@ -27,22 +21,17 @@ import net.createmod.catnip.gui.ScreenOpener; import net.createmod.catnip.utility.AnimationTickHolder; import net.createmod.catnip.utility.VecHelper; import net.createmod.catnip.utility.outliner.Outliner; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.Vec3i; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult.Type; @@ -52,8 +41,8 @@ public class SchematicAndQuillHandler { private Object outlineSlot = new Object(); - private BlockPos firstPos; - private BlockPos secondPos; + public BlockPos firstPos; + public BlockPos secondPos; private BlockPos selectedPos; private Direction selectedFace; private int range = 10; @@ -212,58 +201,31 @@ public class SchematicAndQuillHandler { } public void saveSchematic(String string, boolean convertImmediately) { - StructureTemplate t = new StructureTemplate(); - BoundingBox bb = BoundingBox.fromCorners(firstPos, secondPos); - BlockPos origin = new BlockPos(bb.minX(), bb.minY(), bb.minZ()); - BlockPos bounds = new BlockPos(bb.getXSpan(), bb.getYSpan(), bb.getZSpan()); - Level level = Minecraft.getInstance().level; - - t.fillFromWorld(level, origin, bounds, true, Blocks.AIR); - - if (string.isEmpty()) - string = CreateLang.translateDirect("schematicAndQuill.fallbackName") - .getString(); - - String folderPath = "schematics"; - FilesHelper.createFolderIfMissing(folderPath); - String filename = FilesHelper.findFirstValidFilename(string, folderPath, "nbt"); - String filepath = folderPath + "/" + filename; - - Path path = Paths.get(filepath); - OutputStream outputStream = null; - try { - outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE); - CompoundTag nbttagcompound = t.save(new CompoundTag()); - SchematicAndQuillItem.replaceStructureVoidWithAir(nbttagcompound); - SchematicAndQuillItem.clampGlueBoxes(level, new AABB(origin, origin.offset(bounds)), nbttagcompound); - NbtIo.writeCompressed(nbttagcompound, outputStream); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (outputStream != null) - IOUtils.closeQuietly(outputStream); + SchematicExportResult result = SchematicExport.saveSchematic( + SchematicExport.SCHEMATICS, string, false, + Minecraft.getInstance().level, firstPos, secondPos + ); + LocalPlayer player = Minecraft.getInstance().player; + if (result == null) { + CreateLang.translate("schematicAndQuill.failed") + .style(ChatFormatting.RED) + .sendStatus(player); + return; } + Path file = result.file(); + CreateLang.translate("schematicAndQuill.saved", file.getFileName()) + .sendStatus(player); firstPos = null; secondPos = null; - LocalPlayer player = Minecraft.getInstance().player; - CreateLang.translate("schematicAndQuill.saved", filepath) - .sendStatus(player); - if (!convertImmediately) return; - if (!Files.exists(path)) { - Create.LOGGER.fatal("Missing Schematic file: " + path.toString()); - return; - } try { - if (!ClientSchematicLoader.validateSizeLimitation(Files.size(path))) + if (!ClientSchematicLoader.validateSizeLimitation(Files.size(file))) return; - AllPackets.channel.sendToServer(new InstantSchematicPacket(filename, origin, bounds)); - + AllPackets.getChannel() + .sendToServer(new InstantSchematicPacket(result.fileName(), result.origin(), result.bounds())); } catch (IOException e) { - Create.LOGGER.fatal("Error finding Schematic file: " + path.toString()); - e.printStackTrace(); - return; + Create.LOGGER.error("Error instantly uploading Schematic file: " + file, e); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java index 477b2851f8..d1b332a040 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java @@ -8,13 +8,15 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.schematics.client.tools.Tools; -import com.simibubi.create.content.schematics.filtering.SchematicInstances; -import com.simibubi.create.content.schematics.item.SchematicItem; +import com.simibubi.create.AllPackets; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.schematics.SchematicInstances; +import com.simibubi.create.content.schematics.SchematicItem; +import com.simibubi.create.content.schematics.client.tools.ToolType; import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.render.SuperRenderTypeBuffer; import net.createmod.catnip.utility.AnimationTickHolder; @@ -43,6 +45,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlac import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.gui.ForgeIngameGui; import net.minecraftforge.client.gui.IIngameOverlay; @@ -53,7 +56,7 @@ public class SchematicHandler { private AABB bounds; private boolean deployed; private boolean active; - private Tools currentTool; + private ToolType currentTool; private static final int SYNC_DELAY = 10; private int syncCooldown; @@ -73,8 +76,8 @@ public class SchematicHandler { renderers.add(new SchematicRenderer()); overlay = new SchematicHotbarSlotOverlay(); - currentTool = Tools.Deploy; - selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + currentTool = ToolType.DEPLOY; + selectionScreen = new ToolSelectionScreen(ImmutableList.of(ToolType.DEPLOY), this::equip); transformation = new SchematicTransformation(); } @@ -132,14 +135,14 @@ public class SchematicHandler { active = true; if (deployed) { setupRenderer(); - Tools toolBefore = currentTool; - selectionScreen = new ToolSelectionScreen(Tools.getTools(player.isCreative()), this::equip); + ToolType toolBefore = currentTool; + selectionScreen = new ToolSelectionScreen(ToolType.getTools(player.isCreative()), this::equip); if (toolBefore != null) { selectionScreen.setSelectedElement(toolBefore); equip(toolBefore); } } else - selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + selectionScreen = new ToolSelectionScreen(ImmutableList.of(ToolType.DEPLOY), this::equip); } private void setupRenderer() { @@ -157,23 +160,31 @@ public class SchematicHandler { BlockPos pos; pos = BlockPos.ZERO; - schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS); + + try { + schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS); + } catch (Exception e) { + Minecraft.getInstance().player.displayClientMessage(CreateLang.translate("schematic.error") + .component(), false); + Create.LOGGER.error("Failed to load Schematic for Previewing", e); + return; + } placementSettings.setMirror(Mirror.FRONT_BACK); pos = BlockPos.ZERO.east(size.getX() - 1); schematic.placeInWorld(wMirroredFB, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS); transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE, placementSettings.getMirror()); - for (BlockEntity te : wMirroredFB.getRenderedTileEntities()) - transform.apply(te); + for (BlockEntity be : wMirroredFB.getRenderedBlockEntities()) + transform.apply(be); placementSettings.setMirror(Mirror.LEFT_RIGHT); pos = BlockPos.ZERO.south(size.getZ() - 1); schematic.placeInWorld(wMirroredLR, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS); transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE, placementSettings.getMirror()); - for (BlockEntity te : wMirroredLR.getRenderedTileEntities()) - transform.apply(te); + for (BlockEntity be : wMirroredLR.getRenderedBlockEntities()) + transform.apply(be); renderers.get(0) .display(w); @@ -183,7 +194,7 @@ public class SchematicHandler { .display(wMirroredLR); } - public void render(PoseStack ms, SuperRenderTypeBuffer buffer) { + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera) { boolean present = activeSchematicItem != null; if (!active && !present) return; @@ -191,12 +202,12 @@ public class SchematicHandler { if (active) { ms.pushPose(); currentTool.getTool() - .renderTool(ms, buffer); + .renderTool(ms, buffer, camera); ms.popPose(); } ms.pushPose(); - transformation.applyGLTransformations(ms); + transformation.applyTransformations(ms, camera); if (!renderers.isEmpty()) { float pt = AnimationTickHolder.getPartialTicks(); @@ -324,11 +335,11 @@ public class SchematicHandler { public void sync() { if (activeSchematicItem == null) return; - AllPackets.channel.sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(), + AllPackets.getChannel().sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(), transformation.getAnchor(), deployed)); } - public void equip(Tools tool) { + public void equip(ToolType tool) { this.currentTool = tool; currentTool.getTool() .init(); @@ -355,7 +366,7 @@ public class SchematicHandler { public void deploy() { if (!deployed) { - List tools = Tools.getTools(Minecraft.getInstance().player.isCreative()); + List tools = ToolType.getTools(Minecraft.getInstance().player.isCreative()); selectionScreen = new ToolSelectionScreen(tools, this::equip); } deployed = true; @@ -367,7 +378,7 @@ public class SchematicHandler { } public void printInstantly() { - AllPackets.channel.sendToServer(new SchematicPlacePacket(activeSchematicItem.copy())); + AllPackets.getChannel().sendToServer(new SchematicPlacePacket(activeSchematicItem.copy())); CompoundTag nbt = activeSchematicItem.getTag(); nbt.putBoolean("Deployed", false); activeSchematicItem.setTag(nbt); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java index 401e3ab7d7..1b3d43692e 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicPromptScreen.java @@ -109,5 +109,4 @@ public class SchematicPromptScreen extends AbstractSimiScreen { CreateClient.SCHEMATIC_AND_QUILL_HANDLER.saveSchematic(nameField.getValue(), convertImmediately); onClose(); } - } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java index 8f6db8993a..29b03102c2 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicRenderer.java @@ -5,15 +5,15 @@ import java.util.Map; import java.util.Random; import com.jozufozu.flywheel.core.model.ModelUtil; -import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder; +import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferedData; import com.jozufozu.flywheel.core.model.ShadeSeparatingVertexConsumer; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; -import com.simibubi.create.foundation.render.TileEntityRenderHelper; +import com.simibubi.create.foundation.render.BlockEntityRenderHelper; +import com.simibubi.create.foundation.render.FlwSuperByteBuffer; -import net.createmod.catnip.render.SuperBufferFactory; import net.createmod.catnip.render.SuperByteBuffer; import net.createmod.catnip.render.SuperRenderTypeBuffer; import net.createmod.catnip.utility.worldWrappers.SchematicWorld; @@ -76,15 +76,19 @@ public class SchematicRenderer { bufferCache.forEach((layer, buffer) -> { buffer.renderInto(ms, buffers.getBuffer(layer)); }); - TileEntityRenderHelper.renderTileEntities(schematic, schematic.getRenderedTileEntities(), ms, buffers); + BlockEntityRenderHelper.renderBlockEntities(schematic, schematic.getRenderedBlockEntities(), ms, buffers); } protected void redraw() { + bufferCache.forEach((layer, sbb) -> sbb.delete()); bufferCache.clear(); + for (RenderType layer : RenderType.chunkBufferLayers()) { SuperByteBuffer buffer = drawLayer(layer); if (!buffer.isEmpty()) bufferCache.put(layer, buffer); + else + buffer.delete(); } } @@ -100,12 +104,12 @@ public class SchematicRenderer { BoundingBox bounds = renderWorld.getBounds(); ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper; - ShadeSeparatedBufferBuilder builder = new ShadeSeparatedBufferBuilder(512); + BufferBuilder shadedBuilder = objects.shadedBuilder; BufferBuilder unshadedBuilder = objects.unshadedBuilder; - builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + shadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - shadeSeparatingWrapper.prepare(builder, unshadedBuilder); + shadeSeparatingWrapper.prepare(shadedBuilder, unshadedBuilder); ForgeHooksClient.setRenderType(layer); ModelBlockRenderer.enableCaching(); @@ -117,9 +121,9 @@ public class SchematicRenderer { poseStack.pushPose(); poseStack.translate(localPos.getX(), localPos.getY(), localPos.getZ()); - BlockEntity tileEntity = renderWorld.getBlockEntity(localPos); + BlockEntity blockEntity = renderWorld.getBlockEntity(localPos); dispatcher.renderBatched(state, pos, renderWorld, poseStack, shadeSeparatingWrapper, true, random, - tileEntity != null ? tileEntity.getModelData() : EmptyModelData.INSTANCE); + blockEntity != null ? blockEntity.getModelData() : EmptyModelData.INSTANCE); poseStack.popPose(); } @@ -128,13 +132,13 @@ public class SchematicRenderer { ForgeHooksClient.setRenderType(null); shadeSeparatingWrapper.clear(); - unshadedBuilder.end(); - builder.appendUnshadedVertices(unshadedBuilder); - builder.end(); + ShadeSeparatedBufferedData bufferedData = ModelUtil.endAndCombine(shadedBuilder, unshadedBuilder); renderWorld.renderMode = false; - return SuperBufferFactory.getInstance().create(builder); + SuperByteBuffer sbb = new FlwSuperByteBuffer(bufferedData); + bufferedData.release(); + return sbb; } private static int getLayerCount() { @@ -147,6 +151,7 @@ public class SchematicRenderer { public final Random random = new Random(); public final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer(); + public final BufferBuilder shadedBuilder = new BufferBuilder(512); public final BufferBuilder unshadedBuilder = new BufferBuilder(512); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java index 4195cff5b6..541cf59cbd 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicTransformation.java @@ -19,15 +19,19 @@ import net.minecraft.world.phys.Vec3; public class SchematicTransformation { - private LerpedFloat x, y, z, scaleFrontBack, scaleLeftRight; + private Vec3 chasingPos; + private Vec3 prevChasingPos; + private BlockPos target; + + private LerpedFloat scaleFrontBack, scaleLeftRight; private LerpedFloat rotation; private double xOrigin; private double zOrigin; public SchematicTransformation() { - x = LerpedFloat.linear(); - y = LerpedFloat.linear(); - z = LerpedFloat.linear(); + chasingPos = Vec3.ZERO; + prevChasingPos = Vec3.ZERO; + target = BlockPos.ZERO; scaleFrontBack = LerpedFloat.linear(); scaleLeftRight = LerpedFloat.linear(); rotation = LerpedFloat.angular(); @@ -48,20 +52,18 @@ public class SchematicTransformation { rotation.chase(0, 0.45f, Chaser.EXP) .startWithValue(r); - Vec3 vec = fromAnchor(anchor); - x.chase(0, 0.45f, Chaser.EXP) - .startWithValue((float) vec.x); - y.chase(0, 0.45f, Chaser.EXP) - .startWithValue((float) vec.y); - z.chase(0, 0.45f, Chaser.EXP) - .startWithValue((float) vec.z); + target = fromAnchor(anchor); + chasingPos = Vec3.atLowerCornerOf(target); + prevChasingPos = chasingPos; } - public void applyGLTransformations(PoseStack ms) { + public void applyTransformations(PoseStack ms, Vec3 camera) { float pt = AnimationTickHolder.getPartialTicks(); // Translation - ms.translate(x.getValue(pt), y.getValue(pt), z.getValue(pt)); + TransformStack.cast(ms) + .translate(VecHelper.lerp(pt, prevChasingPos, chasingPos) + .subtract(camera)); Vec3 rotationOffset = getRotationOffset(true); // Rotation & Mirror @@ -101,7 +103,7 @@ public class SchematicTransformation { float pt = AnimationTickHolder.getPartialTicks(); Vec3 rotationOffset = getRotationOffset(true); - vec = vec.subtract(x.getValue(pt), y.getValue(pt), z.getValue(pt)); + vec = vec.subtract(VecHelper.lerp(pt, prevChasingPos, chasingPos)); vec = vec.subtract(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); vec = VecHelper.rotate(vec, -rotation.getValue(pt), Axis.Y); vec = vec.add(rotationOffset.x, 0, rotationOffset.z); @@ -157,12 +159,11 @@ public class SchematicTransformation { vec = vec.multiply(getScaleFB().getChaseTarget(), 1, getScaleLR().getChaseTarget()); vec = VecHelper.rotate(vec, rotation.getChaseTarget(), Axis.Y); vec = vec.add(xOrigin, 0, zOrigin); - - vec = vec.add(x.getChaseTarget(), y.getChaseTarget(), z.getChaseTarget()); + vec = vec.add(target.getX(), target.getY(), target.getZ()); return new BlockPos(vec.x, vec.y, vec.z); } - public Vec3 fromAnchor(BlockPos pos) { + public BlockPos fromAnchor(BlockPos pos) { Vec3 vec = Vec3.ZERO.add(.5, 0, .5); Vec3 rotationOffset = getRotationOffset(false); vec = vec.subtract(xOrigin, 0, zOrigin); @@ -170,8 +171,7 @@ public class SchematicTransformation { vec = vec.multiply(getScaleFB().getChaseTarget(), 1, getScaleLR().getChaseTarget()); vec = VecHelper.rotate(vec, rotation.getChaseTarget(), Axis.Y); vec = vec.add(xOrigin, 0, zOrigin); - - return Vec3.atLowerCornerOf(pos.subtract(new BlockPos(vec.x, vec.y, vec.z))); + return pos.subtract(new BlockPos(vec.x, vec.y, vec.z)); } public int getRotationTarget() { @@ -190,9 +190,8 @@ public class SchematicTransformation { } public void tick() { - x.tickChaser(); - y.tickChaser(); - z.tickChaser(); + prevChasingPos = chasingPos; + chasingPos = VecHelper.lerp(0.45f, chasingPos, Vec3.atLowerCornerOf(target)); getScaleLR().tickChaser(); getScaleFB().tickChaser(); rotation.tickChaser(); @@ -209,25 +208,22 @@ public class SchematicTransformation { rotation.updateChaseTarget(rotation.getChaseTarget() + (clockwise ? -90 : 90)); } - public void move(float xIn, float yIn, float zIn) { - moveTo(x.getChaseTarget() + xIn, y.getChaseTarget() + yIn, z.getChaseTarget() + zIn); + public void move(int xIn, int yIn, int zIn) { + moveTo(target.offset(xIn, yIn, zIn)); } public void startAt(BlockPos pos) { - x.startWithValue(pos.getX()); - y.startWithValue(pos.getY() - 10); - z.startWithValue(pos.getZ()); + chasingPos = Vec3.atLowerCornerOf(pos); + prevChasingPos = chasingPos; moveTo(pos); } public void moveTo(BlockPos pos) { - moveTo(pos.getX(), pos.getY(), pos.getZ()); + target = pos; } - public void moveTo(float xIn, float yIn, float zIn) { - x.updateChaseTarget(xIn); - y.updateChaseTarget(yIn); - z.updateChaseTarget(zIn); + public void moveTo(int xIn, int yIn, int zIn) { + moveTo(new BlockPos(xIn, yIn, zIn)); } public LerpedFloat getScaleFB() { diff --git a/src/main/java/com/simibubi/create/content/schematics/client/ToolSelectionScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/ToolSelectionScreen.java index 0ab2dd226b..9c86cc58e3 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/ToolSelectionScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/ToolSelectionScreen.java @@ -7,7 +7,7 @@ import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllKeys; -import com.simibubi.create.content.schematics.client.tools.Tools; +import com.simibubi.create.content.schematics.client.tools.ToolType; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.utility.CreateLang; @@ -22,8 +22,8 @@ public class ToolSelectionScreen extends Screen { .getString(); public final String holdToFocus = "gui.toolmenu.focusKey"; - protected List tools; - protected Consumer callback; + protected List tools; + protected Consumer callback; public boolean focused; private float yOffset; protected int selection; @@ -32,7 +32,7 @@ public class ToolSelectionScreen extends Screen { protected int w; protected int h; - public ToolSelectionScreen(List tools, Consumer callback) { + public ToolSelectionScreen(List tools, Consumer callback) { super(Components.literal("Tool Selection")); this.minecraft = Minecraft.getInstance(); this.tools = tools; @@ -48,7 +48,7 @@ public class ToolSelectionScreen extends Screen { h = 30; } - public void setSelectedElement(Tools tool) { + public void setSelectedElement(ToolType tool) { if (!tools.contains(tool)) return; selection = tools.indexOf(tool); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java index 2a0338242b..e03761f277 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/DeployTool.java @@ -36,8 +36,8 @@ public class DeployTool extends PlacementToolBase { } @Override - public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer) { - super.renderTool(ms, buffer); + public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera) { + super.renderTool(ms, buffer, camera); if (selectedPos == null) return; @@ -58,7 +58,7 @@ public class DeployTool extends PlacementToolBase { double zOrigin = bounds.getZsize() / 2f; Vec3 origin = new Vec3(xOrigin, 0, zOrigin); - ms.translate(x - centerX, y, z - centerZ); + ms.translate(x - centerX - camera.x, y - camera.y, z - centerZ - camera.z); TransformStack.cast(ms) .translate(origin) .translate(rotationOffset) @@ -67,7 +67,7 @@ public class DeployTool extends PlacementToolBase { .translateBack(origin); AABBOutline outline = schematicHandler.getOutline(); - outline.render(ms, buffer, pt); + outline.render(ms, buffer, Vec3.ZERO, pt); outline.getParams() .clearTextures(); ms.popPose(); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java index 789a9fdcd2..978bf333da 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/FlipTool.java @@ -72,10 +72,10 @@ public class FlipTool extends PlacementToolBase { AllSpecialTextures tex = AllSpecialTextures.CHECKERED; outline.getParams() .lineWidth(1 / 16f) - .disableNormals() + .disableLineNormals() .colored(0xdddddd) .withFaceTextures(tex, tex); - outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()); + outline.render(ms, buffer, Vec3.ZERO, AnimationTickHolder.getPartialTicks()); super.renderOnSchematic(ms, buffer); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/ISchematicTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/ISchematicTool.java index df8083632a..dc0b0b0540 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/ISchematicTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/ISchematicTool.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.schematics.client.tools; import com.mojang.blaze3d.vertex.PoseStack; import net.createmod.catnip.render.SuperRenderTypeBuffer; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.gui.ForgeIngameGui; public interface ISchematicTool { @@ -13,7 +14,7 @@ public interface ISchematicTool { public boolean handleRightClick(); public boolean handleMouseWheel(double delta); - public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer); + public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera); public void renderOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, int height); public void renderOnSchematic(PoseStack ms, SuperRenderTypeBuffer buffer); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveTool.java index 9f30222873..f1b8a69bfd 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveTool.java @@ -28,7 +28,7 @@ public class MoveTool extends PlacementToolBase { Vec3 vec = Vec3.atLowerCornerOf(selectedFace.getNormal()).scale(-Math.signum(delta)); vec = vec.multiply(transformation.getMirrorModifier(Axis.X), 1, transformation.getMirrorModifier(Axis.Z)); vec = VecHelper.rotate(vec, transformation.getRotationTarget(), Axis.Y); - transformation.move((float) vec.x, 0, (float) vec.z); + transformation.move((int) vec.x, 0, (int) vec.z); schematicHandler.markDirty(); return true; diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveVerticalTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveVerticalTool.java index a3f8a6dbef..0f7c7d854b 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveVerticalTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/MoveVerticalTool.java @@ -1,11 +1,13 @@ package com.simibubi.create.content.schematics.client.tools; +import net.minecraft.util.Mth; + public class MoveVerticalTool extends PlacementToolBase { @Override public boolean handleMouseWheel(double delta) { if (schematicHandler.isDeployed()) { - schematicHandler.getTransformation().move(0, (float) Math.signum(delta), 0); + schematicHandler.getTransformation().move(0, Mth.sign(delta), 0); schematicHandler.markDirty(); } return true; diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/PlacementToolBase.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/PlacementToolBase.java index a51f9626a9..c58267d730 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/PlacementToolBase.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/PlacementToolBase.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.schematics.client.tools; import com.mojang.blaze3d.vertex.PoseStack; import net.createmod.catnip.render.SuperRenderTypeBuffer; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.gui.ForgeIngameGui; public abstract class PlacementToolBase extends SchematicToolBase { @@ -18,8 +19,8 @@ public abstract class PlacementToolBase extends SchematicToolBase { } @Override - public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer) { - super.renderTool(ms, buffer); + public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera) { + super.renderTool(ms, buffer, camera); } @Override diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java index ef1a5aaaec..83a7fe6f4a 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/RotateTool.java @@ -32,11 +32,11 @@ public class RotateTool extends PlacementToolBase { line.getParams() .disableCull() - .disableNormals() + .disableLineNormals() .colored(0xdddddd) .lineWidth(1 / 16f); line.set(start, end) - .render(ms, buffer, AnimationTickHolder.getPartialTicks()); + .render(ms, buffer, Vec3.ZERO, AnimationTickHolder.getPartialTicks()); super.renderOnSchematic(ms, buffer); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java index d4de72cdeb..bec43f0ba4 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/SchematicToolBase.java @@ -121,7 +121,7 @@ public abstract class SchematicToolBase implements ISchematicTool { } @Override - public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer) {} + public void renderTool(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera) {} @Override public void renderOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, int height) {} @@ -143,7 +143,7 @@ public abstract class SchematicToolBase implements ISchematicTool { .colored(0x6886c5) .withFaceTexture(AllSpecialTextures.CHECKERED) .lineWidth(1 / 16f); - outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()); + outline.render(ms, buffer, Vec3.ZERO, AnimationTickHolder.getPartialTicks()); outline.getParams() .clearTextures(); ms.popPose(); diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/ToolType.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/ToolType.java new file mode 100644 index 0000000000..4327acf138 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/client/tools/ToolType.java @@ -0,0 +1,55 @@ +package com.simibubi.create.content.schematics.client.tools; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Lang; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; + +public enum ToolType { + + DEPLOY(new DeployTool(), AllIcons.I_TOOL_DEPLOY), + MOVE(new MoveTool(), AllIcons.I_TOOL_MOVE_XZ), + MOVE_Y(new MoveVerticalTool(), AllIcons.I_TOOL_MOVE_Y), + ROTATE(new RotateTool(), AllIcons.I_TOOL_ROTATE), + FLIP(new FlipTool(), AllIcons.I_TOOL_MIRROR), + PRINT(new PlaceTool(), AllIcons.I_CONFIRM); + + private ISchematicTool tool; + private AllIcons icon; + + private ToolType(ISchematicTool tool, AllIcons icon) { + this.tool = tool; + this.icon = icon; + } + + public ISchematicTool getTool() { + return tool; + } + + public MutableComponent getDisplayName() { + return CreateLang.translateDirect("schematic.tool." + Lang.asId(name())); + } + + public AllIcons getIcon() { + return icon; + } + + public static List getTools(boolean creative) { + List tools = new ArrayList<>(); + Collections.addAll(tools, MOVE, MOVE_Y, DEPLOY, ROTATE, FLIP); + if (creative) + tools.add(PRINT); + return tools; + } + + public List getDescription() { + return CreateLang.translatedOptions("schematic.tool." + Lang.asId(name()) + ".description", "0", "1", "2", "3"); + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/client/tools/Tools.java b/src/main/java/com/simibubi/create/content/schematics/client/tools/Tools.java deleted file mode 100644 index eabd397107..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/client/tools/Tools.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.simibubi.create.content.schematics.client.tools; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.utility.CreateLang; - -import net.createmod.catnip.utility.lang.Lang; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; - -public enum Tools { - - Deploy(new DeployTool(), AllIcons.I_TOOL_DEPLOY), - Move(new MoveTool(), AllIcons.I_TOOL_MOVE_XZ), - MoveY(new MoveVerticalTool(), AllIcons.I_TOOL_MOVE_Y), - Rotate(new RotateTool(), AllIcons.I_TOOL_ROTATE), - Print(new PlaceTool(), AllIcons.I_CONFIRM), - Flip(new FlipTool(), AllIcons.I_TOOL_MIRROR); - - private ISchematicTool tool; - private AllIcons icon; - - private Tools(ISchematicTool tool, AllIcons icon) { - this.tool = tool; - this.icon = icon; - } - - public ISchematicTool getTool() { - return tool; - } - - public MutableComponent getDisplayName() { - return CreateLang.translateDirect("schematic.tool." + Lang.asId(name())); - } - - public AllIcons getIcon() { - return icon; - } - - public static List getTools(boolean creative) { - List tools = new ArrayList<>(); - Collections.addAll(tools, Move, MoveY, Deploy, Rotate, Flip); - if (creative) - tools.add(Print); - return tools; - } - - public List getDescription() { - return CreateLang.translatedOptions("schematic.tool." + Lang.asId(name()) + ".description", "0", "1", "2", "3"); - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java deleted file mode 100644 index ee02fb8d1f..0000000000 --- a/src/main/java/com/simibubi/create/content/schematics/packet/ConfigureSchematicannonPacket.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.simibubi.create.content.schematics.packet; - -import java.util.function.Supplier; - -import com.simibubi.create.content.schematics.block.SchematicannonContainer; -import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; -import com.simibubi.create.content.schematics.block.SchematicannonTileEntity.State; -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ConfigureSchematicannonPacket extends SimplePacketBase { - - public static enum Option { - DONT_REPLACE, REPLACE_SOLID, REPLACE_ANY, REPLACE_EMPTY, SKIP_MISSING, SKIP_TILES, PLAY, PAUSE, STOP; - } - - private Option option; - private boolean set; - - public ConfigureSchematicannonPacket(Option option, boolean set) { - this.option = option; - this.set = set; - } - - public ConfigureSchematicannonPacket(FriendlyByteBuf buffer) { - this(buffer.readEnum(Option.class), buffer.readBoolean()); - } - - public void write(FriendlyByteBuf buffer) { - buffer.writeEnum(option); - buffer.writeBoolean(set); - } - - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); - if (player == null || !(player.containerMenu instanceof SchematicannonContainer)) - return; - - SchematicannonTileEntity te = ((SchematicannonContainer) player.containerMenu).contentHolder; - switch (option) { - case DONT_REPLACE: - case REPLACE_ANY: - case REPLACE_EMPTY: - case REPLACE_SOLID: - te.replaceMode = option.ordinal(); - break; - case SKIP_MISSING: - te.skipMissing = set; - break; - case SKIP_TILES: - te.replaceTileEntities = set; - break; - - case PLAY: - te.state = State.RUNNING; - te.statusMsg = "running"; - break; - case PAUSE: - te.state = State.PAUSED; - te.statusMsg = "paused"; - break; - case STOP: - te.state = State.STOPPED; - te.statusMsg = "stopped"; - break; - default: - break; - } - - te.sendUpdate = true; - }); - context.get().setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java index 62d3f2abec..fc3757a186 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/InstantSchematicPacket.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.schematics.packet; -import java.util.function.Supplier; - import com.simibubi.create.Create; import com.simibubi.create.foundation.networking.SimplePacketBase; @@ -36,17 +34,14 @@ public class InstantSchematicPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - Create.SCHEMATIC_RECEIVER.handleInstantSchematic(player, name, player.level, origin, bounds); - }); - context.get() - .setPacketHandled(true); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + Create.SCHEMATIC_RECEIVER.handleInstantSchematic(player, name, player.level, origin, bounds); + }); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java index 2dc60cdb72..ffc8ad8360 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicPlacePacket.java @@ -1,11 +1,9 @@ package com.simibubi.create.content.schematics.packet; -import java.util.function.Supplier; - import com.simibubi.create.content.schematics.SchematicPrinter; -import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.utility.BlockHelper; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; @@ -26,41 +24,45 @@ public class SchematicPlacePacket extends SimplePacketBase { stack = buffer.readItem(); } + @Override public void write(FriendlyByteBuf buffer) { buffer.writeItem(stack); } - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) return; + if (!player.isCreative()) + return; Level world = player.getLevel(); SchematicPrinter printer = new SchematicPrinter(); printer.loadSchematic(stack, world, !player.canUseGameMasterBlocks()); - if (!printer.isLoaded()) + if (!printer.isLoaded() || printer.isErrored()) return; - boolean includeAir = AllConfigs.SERVER.schematics.creativePrintIncludesAir.get(); + boolean includeAir = AllConfigs.server().schematics.creativePrintIncludesAir.get(); while (printer.advanceCurrentPos()) { if (!printer.shouldPlaceCurrent(world)) continue; - printer.handleCurrentTarget((pos, state, tile) -> { + printer.handleCurrentTarget((pos, state, blockEntity) -> { boolean placingAir = state.isAir(); if (placingAir && !includeAir) return; - CompoundTag tileData = tile != null ? tile.saveWithFullMetadata() : null; - BlockHelper.placeSchematicBlock(world, state, pos, null, tileData); + CompoundTag data = BlockHelper.prepareBlockEntityData(state, blockEntity); + BlockHelper.placeSchematicBlock(world, state, pos, null, data); }, (pos, entity) -> { world.addFreshEntity(entity); }); } }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicSyncPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicSyncPacket.java index 6615b95466..9cdda50204 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicSyncPacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicSyncPacket.java @@ -1,9 +1,7 @@ package com.simibubi.create.content.schematics.packet; -import java.util.function.Supplier; - import com.simibubi.create.AllItems; -import com.simibubi.create.content.schematics.filtering.SchematicInstances; +import com.simibubi.create.content.schematics.SchematicInstances; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.core.BlockPos; @@ -52,9 +50,9 @@ public class SchematicSyncPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - context.get().enqueueWork(() -> { - ServerPlayer player = context.get().getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); if (player == null) return; ItemStack stack = ItemStack.EMPTY; @@ -73,7 +71,7 @@ public class SchematicSyncPacket extends SimplePacketBase { tag.putString("Mirror", mirror.name()); SchematicInstances.clearHash(stack); }); - context.get().setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java index 7ef4c5dd78..69c19a5c23 100644 --- a/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java +++ b/src/main/java/com/simibubi/create/content/schematics/packet/SchematicUploadPacket.java @@ -1,9 +1,7 @@ package com.simibubi.create.content.schematics.packet; -import java.util.function.Supplier; - import com.simibubi.create.Create; -import com.simibubi.create.content.schematics.block.SchematicTableContainer; +import com.simibubi.create.content.schematics.table.SchematicTableMenu; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.core.BlockPos; @@ -53,6 +51,7 @@ public class SchematicUploadPacket extends SimplePacketBase { data = buffer.readByteArray(); } + @Override public void write(FriendlyByteBuf buffer) { buffer.writeInt(code); buffer.writeUtf(schematic); @@ -63,25 +62,23 @@ public class SchematicUploadPacket extends SimplePacketBase { buffer.writeByteArray(data); } - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - if (code == BEGIN) { - BlockPos pos = ((SchematicTableContainer) player.containerMenu).contentHolder - .getBlockPos(); - Create.SCHEMATIC_RECEIVER.handleNewUpload(player, schematic, size, pos); - } - if (code == WRITE) - Create.SCHEMATIC_RECEIVER.handleWriteRequest(player, schematic, data); - if (code == FINISH) - Create.SCHEMATIC_RECEIVER.handleFinishedUpload(player, schematic); - }); - context.get() - .setPacketHandled(true); + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + if (code == BEGIN) { + BlockPos pos = ((SchematicTableMenu) player.containerMenu).contentHolder + .getBlockPos(); + Create.SCHEMATIC_RECEIVER.handleNewUpload(player, schematic, size, pos); + } + if (code == WRITE) + Create.SCHEMATIC_RECEIVER.handleWriteRequest(player, schematic, data); + if (code == FINISH) + Create.SCHEMATIC_RECEIVER.handleFinishedUpload(player, schematic); + }); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockEntityItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockEntityItemRequirement.java new file mode 100644 index 0000000000..3e2c9a2a55 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockEntityItemRequirement.java @@ -0,0 +1,9 @@ +package com.simibubi.create.content.schematics.requirement; + +import net.minecraft.world.level.block.state.BlockState; + +public interface ISpecialBlockEntityItemRequirement { + + public ItemRequirement getRequiredItems(BlockState state); + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockItemRequirement.java new file mode 100644 index 0000000000..f55d451215 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialBlockItemRequirement.java @@ -0,0 +1,10 @@ +package com.simibubi.create.content.schematics.requirement; + +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public interface ISpecialBlockItemRequirement { + + public ItemRequirement getRequiredItems(BlockState state, BlockEntity blockEntity); + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialEntityItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialEntityItemRequirement.java new file mode 100644 index 0000000000..3095009078 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/requirement/ISpecialEntityItemRequirement.java @@ -0,0 +1,7 @@ +package com.simibubi.create.content.schematics.requirement; + +public interface ISpecialEntityItemRequirement { + + public ItemRequirement getRequiredItems(); + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/requirement/ItemRequirement.java b/src/main/java/com/simibubi/create/content/schematics/requirement/ItemRequirement.java new file mode 100644 index 0000000000..bae83e898f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/requirement/ItemRequirement.java @@ -0,0 +1,181 @@ +package com.simibubi.create.content.schematics.requirement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import net.createmod.catnip.utility.NBTProcessors; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.AbstractBannerBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DirtPathBlock; +import net.minecraft.world.level.block.FarmBlock; +import net.minecraft.world.level.block.SeaPickleBlock; +import net.minecraft.world.level.block.SnowLayerBlock; +import net.minecraft.world.level.block.TurtleEggBlock; +import net.minecraft.world.level.block.entity.BannerBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.SlabType; + +public class ItemRequirement { + public static final ItemRequirement NONE = new ItemRequirement(Collections.emptyList()); + public static final ItemRequirement INVALID = new ItemRequirement(Collections.emptyList()); + + protected List requiredItems; + + public ItemRequirement(List requiredItems) { + this.requiredItems = requiredItems; + } + + public ItemRequirement(StackRequirement stackRequirement) { + this(List.of(stackRequirement)); + } + + public ItemRequirement(ItemUseType usage, ItemStack stack) { + this(new StackRequirement(stack, usage)); + } + + public ItemRequirement(ItemUseType usage, Item item) { + this(usage, new ItemStack(item)); + } + + public ItemRequirement(ItemUseType usage, List requiredItems) { + this(requiredItems.stream() + .map(req -> new StackRequirement(req, usage)) + .collect(Collectors.toList())); + } + + public static ItemRequirement of(BlockState state, BlockEntity be) { + Block block = state.getBlock(); + + ItemRequirement requirement; + if (block instanceof ISpecialBlockItemRequirement specialBlock) { + requirement = specialBlock.getRequiredItems(state, be); + } else { + requirement = defaultOf(state, be); + } + + if (be instanceof ISpecialBlockEntityItemRequirement specialBE) + requirement = requirement.union(specialBE.getRequiredItems(state)); + + return requirement; + } + + private static ItemRequirement defaultOf(BlockState state, BlockEntity be) { + Block block = state.getBlock(); + if (block == Blocks.AIR) + return NONE; + + Item item = block.asItem(); + if (item == Items.AIR) + return INVALID; + + // double slab needs two items + if (state.hasProperty(BlockStateProperties.SLAB_TYPE) + && state.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE) + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, 2)); + if (block instanceof TurtleEggBlock) + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(TurtleEggBlock.EGGS) + .intValue())); + if (block instanceof SeaPickleBlock) + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SeaPickleBlock.PICKLES) + .intValue())); + if (block instanceof SnowLayerBlock) + return new ItemRequirement(ItemUseType.CONSUME, new ItemStack(item, state.getValue(SnowLayerBlock.LAYERS) + .intValue())); + if (block instanceof FarmBlock || block instanceof DirtPathBlock) + return new ItemRequirement(ItemUseType.CONSUME, Items.DIRT); + if (block instanceof AbstractBannerBlock && be instanceof BannerBlockEntity bannerBE) + return new ItemRequirement(new StrictNbtStackRequirement(bannerBE.getItem(), ItemUseType.CONSUME)); + + return new ItemRequirement(ItemUseType.CONSUME, item); + } + + public static ItemRequirement of(Entity entity) { + if (entity instanceof ISpecialEntityItemRequirement specialEntity) + return specialEntity.getRequiredItems(); + + if (entity instanceof ItemFrame itemFrame) { + ItemStack frame = new ItemStack(Items.ITEM_FRAME); + ItemStack displayedItem = NBTProcessors.withUnsafeNBTDiscarded(itemFrame.getItem()); + if (displayedItem.isEmpty()) + return new ItemRequirement(ItemUseType.CONSUME, Items.ITEM_FRAME); + return new ItemRequirement(List.of(new ItemRequirement.StackRequirement(frame, ItemUseType.CONSUME), + new ItemRequirement.StrictNbtStackRequirement(displayedItem, ItemUseType.CONSUME))); + } + + if (entity instanceof ArmorStand armorStand) { + List requirements = new ArrayList<>(); + requirements.add(new StackRequirement(new ItemStack(Items.ARMOR_STAND), ItemUseType.CONSUME)); + armorStand.getAllSlots() + .forEach(s -> requirements + .add(new StrictNbtStackRequirement(NBTProcessors.withUnsafeNBTDiscarded(s), ItemUseType.CONSUME))); + return new ItemRequirement(requirements); + } + + return INVALID; + } + + public boolean isEmpty() { + return NONE == this; + } + + public boolean isInvalid() { + return INVALID == this; + } + + public List getRequiredItems() { + return requiredItems; + } + + public ItemRequirement union(ItemRequirement other) { + if (this.isInvalid() || other.isInvalid()) + return INVALID; + if (this.isEmpty()) + return other; + if (other.isEmpty()) + return this; + + return new ItemRequirement(Stream.concat(requiredItems.stream(), other.requiredItems.stream()) + .collect(Collectors.toList())); + } + + public enum ItemUseType { + CONSUME, DAMAGE + } + + public static class StackRequirement { + public final ItemStack stack; + public final ItemUseType usage; + + public StackRequirement(ItemStack stack, ItemUseType usage) { + this.stack = stack; + this.usage = usage; + } + + public boolean matches(ItemStack other) { + return stack.sameItem(other); + } + } + + public static class StrictNbtStackRequirement extends StackRequirement { + public StrictNbtStackRequirement(ItemStack stack, ItemUseType usage) { + super(stack, usage); + } + + @Override + public boolean matches(ItemStack other) { + return ItemStack.isSameItemSameTags(stack, other); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableBlock.java b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlock.java similarity index 80% rename from src/main/java/com/simibubi/create/content/schematics/block/SchematicTableBlock.java rename to src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlock.java index 7e54b4b8b5..21d6b01906 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableBlock.java +++ b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlock.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.schematics.block; +package com.simibubi.create.content.schematics.table; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.item.ItemHelper; import net.minecraft.core.BlockPos; @@ -25,7 +25,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.network.NetworkHooks; -public class SchematicTableBlock extends HorizontalDirectionalBlock implements ITE { +public class SchematicTableBlock extends HorizontalDirectionalBlock implements IBE { public SchematicTableBlock(Properties properties) { super(properties); @@ -64,8 +64,8 @@ public class SchematicTableBlock extends HorizontalDirectionalBlock implements I if (worldIn.isClientSide) return InteractionResult.SUCCESS; - withTileEntityDo(worldIn, pos, - te -> NetworkHooks.openGui((ServerPlayer) player, te, te::sendToContainer)); + withBlockEntityDo(worldIn, pos, + be -> NetworkHooks.openGui((ServerPlayer) player, be, be::sendToMenu)); return InteractionResult.SUCCESS; } @@ -74,18 +74,18 @@ public class SchematicTableBlock extends HorizontalDirectionalBlock implements I if (!state.hasBlockEntity() || state.getBlock() == newState.getBlock()) return; - withTileEntityDo(worldIn, pos, te -> ItemHelper.dropContents(worldIn, pos, te.inventory)); + withBlockEntityDo(worldIn, pos, be -> ItemHelper.dropContents(worldIn, pos, be.inventory)); worldIn.removeBlockEntity(pos); } @Override - public Class getTileEntityClass() { - return SchematicTableTileEntity.class; + public Class getBlockEntityClass() { + return SchematicTableBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.SCHEMATIC_TABLE.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.SCHEMATIC_TABLE.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlockEntity.java b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlockEntity.java new file mode 100644 index 0000000000..d4267d725d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableBlockEntity.java @@ -0,0 +1,131 @@ +package com.simibubi.create.content.schematics.table; + +import java.util.List; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.foundation.utility.IInteractionChecker; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.items.ItemStackHandler; + +public class SchematicTableBlockEntity extends SmartBlockEntity implements MenuProvider, IInteractionChecker { + + public SchematicTableInventory inventory; + public boolean isUploading; + public String uploadingSchematic; + public float uploadingProgress; + public boolean sendUpdate; + + public class SchematicTableInventory extends ItemStackHandler { + public SchematicTableInventory() { + super(2); + } + + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + setChanged(); + } + } + + public SchematicTableBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + inventory = new SchematicTableInventory(); + uploadingSchematic = null; + uploadingProgress = 0; + } + + public void sendToMenu(FriendlyByteBuf buffer) { + buffer.writeBlockPos(getBlockPos()); + buffer.writeNbt(getUpdateTag()); + } + + @Override + protected void read(CompoundTag compound, boolean clientPacket) { + inventory.deserializeNBT(compound.getCompound("Inventory")); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (compound.contains("Uploading")) { + isUploading = true; + uploadingSchematic = compound.getString("Schematic"); + uploadingProgress = compound.getFloat("Progress"); + } else { + isUploading = false; + uploadingSchematic = null; + uploadingProgress = 0; + } + } + + @Override + protected void write(CompoundTag compound, boolean clientPacket) { + compound.put("Inventory", inventory.serializeNBT()); + super.write(compound, clientPacket); + + if (clientPacket && isUploading) { + compound.putBoolean("Uploading", true); + compound.putString("Schematic", uploadingSchematic); + compound.putFloat("Progress", uploadingProgress); + } + } + + @Override + public void tick() { + // Update Client block entity + if (sendUpdate) { + sendUpdate = false; + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 6); + } + } + + public void startUpload(String schematic) { + isUploading = true; + uploadingProgress = 0; + uploadingSchematic = schematic; + sendUpdate = true; + inventory.setStackInSlot(0, ItemStack.EMPTY); + } + + public void finishUpload() { + isUploading = false; + uploadingProgress = 0; + uploadingSchematic = null; + sendUpdate = true; + } + + @Override + public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { + return SchematicTableMenu.create(id, inv, this); + } + + @Override + public Component getDisplayName() { + return CreateLang.translateDirect("gui.schematicTable.title"); + } + + @Override + public boolean canPlayerUse(Player player) { + if (level == null || level.getBlockEntity(worldPosition) != this) { + return false; + } + return player.distanceToSqr(worldPosition.getX() + 0.5D, worldPosition.getY() + 0.5D, + worldPosition.getZ() + 0.5D) <= 64.0D; + } + + @Override + public void addBehaviours(List behaviours) {} + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableMenu.java b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableMenu.java new file mode 100644 index 0000000000..ea6841b835 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableMenu.java @@ -0,0 +1,105 @@ +package com.simibubi.create.content.schematics.table; + +import com.simibubi.create.AllItems; +import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.foundation.gui.menu.MenuBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.items.SlotItemHandler; + +public class SchematicTableMenu extends MenuBase { + + private Slot inputSlot; + private Slot outputSlot; + + public SchematicTableMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public SchematicTableMenu(MenuType type, int id, Inventory inv, SchematicTableBlockEntity be) { + super(type, id, inv, be); + } + + public static SchematicTableMenu create(int id, Inventory inv, SchematicTableBlockEntity be) { + return new SchematicTableMenu(AllMenuTypes.SCHEMATIC_TABLE.get(), id, inv, be); + } + + public boolean canWrite() { + return inputSlot.hasItem() && !outputSlot.hasItem(); + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + Slot clickedSlot = getSlot(index); + if (!clickedSlot.hasItem()) + return ItemStack.EMPTY; + + ItemStack stack = clickedSlot.getItem(); + if (index < 2) + moveItemStackTo(stack, 2, slots.size(), false); + else + moveItemStackTo(stack, 0, 1, false); + + return ItemStack.EMPTY; + } + + @Override + protected SchematicTableBlockEntity createOnClient(FriendlyByteBuf extraData) { + ClientLevel world = Minecraft.getInstance().level; + BlockEntity blockEntity = world.getBlockEntity(extraData.readBlockPos()); + if (blockEntity instanceof SchematicTableBlockEntity schematicTable) { + schematicTable.readClient(extraData.readNbt()); + return schematicTable; + } + return null; + } + + @Override + protected void initAndReadInventory(SchematicTableBlockEntity contentHolder) { + } + + @Override + protected void addSlots() { + inputSlot = new SlotItemHandler(contentHolder.inventory, 0, 21, 57) { + @Override + public boolean mayPlace(ItemStack stack) { + return AllItems.EMPTY_SCHEMATIC.isIn(stack) || AllItems.SCHEMATIC_AND_QUILL.isIn(stack) + || AllItems.SCHEMATIC.isIn(stack); + } + }; + + outputSlot = new SlotItemHandler(contentHolder.inventory, 1, 166, 57) { + @Override + public boolean mayPlace(ItemStack stack) { + return false; + } + }; + + addSlot(inputSlot); + addSlot(outputSlot); + + // player Slots + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(player.getInventory(), col + row * 9 + 9, 38 + col * 18, 105 + row * 18)); + } + } + + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) { + this.addSlot(new Slot(player.getInventory(), hotbarSlot, 38 + hotbarSlot * 18, 163)); + } + } + + @Override + protected void saveData(SchematicTableBlockEntity contentHolder) { + } + +} diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableScreen.java similarity index 95% rename from src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java rename to src/main/java/com/simibubi/create/content/schematics/table/SchematicTableScreen.java index debaf8091c..673b71d656 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/table/SchematicTableScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.schematics.block; +package com.simibubi.create.content.schematics.table; import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; import static com.simibubi.create.foundation.gui.AllGuiTextures.SCHEMATIC_TABLE_PROGRESS; @@ -11,10 +11,10 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.schematics.ClientSchematicLoader; +import com.simibubi.create.content.schematics.client.ClientSchematicLoader; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.ScrollInput; @@ -30,7 +30,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -public class SchematicTableScreen extends AbstractSimiContainerScreen { +public class SchematicTableScreen extends AbstractSimiContainerScreen { private final Component uploading = CreateLang.translateDirect("gui.schematicTable.uploading"); private final Component finished = CreateLang.translateDirect("gui.schematicTable.finished"); @@ -55,9 +55,9 @@ public class SchematicTableScreen extends AbstractSimiContainerScreen extraAreas = Collections.emptyList(); - public SchematicTableScreen(SchematicTableContainer container, Inventory playerInventory, + public SchematicTableScreen(SchematicTableMenu menu, Inventory playerInventory, Component title) { - super(container, playerInventory, title); + super(menu, playerInventory, title); background = AllGuiTextures.SCHEMATIC_TABLE; } diff --git a/src/main/java/com/simibubi/create/content/trains/CameraDistanceModifier.java b/src/main/java/com/simibubi/create/content/trains/CameraDistanceModifier.java new file mode 100644 index 0000000000..f0eb5ff30b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/CameraDistanceModifier.java @@ -0,0 +1,36 @@ +package com.simibubi.create.content.trains; + +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.animation.LerpedFloat; + +public class CameraDistanceModifier { + + private static final LerpedFloat multiplier = LerpedFloat.linear().startWithValue(1); + + public static float getMultiplier() { + return getMultiplier(AnimationTickHolder.getPartialTicks()); + } + + public static float getMultiplier(float partialTicks) { + return multiplier.getValue(partialTicks); + } + + public static void tick() { + multiplier.tickChaser(); + } + + public static void reset() { + multiplier.chase(1, 0.1, LerpedFloat.Chaser.EXP); + } + + public static void zoomOut() { + zoomOut(AllConfigs.client().mountedZoomMultiplier.getF()); + } + + public static void zoomOut(float targetMultiplier) { + multiplier.chase(targetMultiplier, 0.075, LerpedFloat.Chaser.EXP); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java b/src/main/java/com/simibubi/create/content/trains/CubeParticle.java similarity index 98% rename from src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java rename to src/main/java/com/simibubi/create/content/trains/CubeParticle.java index 004aea5305..25f9c72896 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticle.java +++ b/src/main/java/com/simibubi/create/content/trains/CubeParticle.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.trains; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticleData.java b/src/main/java/com/simibubi/create/content/trains/CubeParticleData.java similarity index 96% rename from src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticleData.java rename to src/main/java/com/simibubi/create/content/trains/CubeParticleData.java index 7bb7e52171..e17553e1a2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/particle/CubeParticleData.java +++ b/src/main/java/com/simibubi/create/content/trains/CubeParticleData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.contraptions.particle; +package com.simibubi.create.content.trains; import java.util.Locale; @@ -7,6 +7,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllParticleTypes; +import com.simibubi.create.foundation.particle.ICustomParticleData; import net.minecraft.client.particle.ParticleProvider; import net.minecraft.core.particles.ParticleOptions; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/trains/GlobalRailwayManager.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java rename to src/main/java/com/simibubi/create/content/trains/GlobalRailwayManager.java index 994611bf42..b20f8b9f7f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/trains/GlobalRailwayManager.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains; import java.util.ArrayList; import java.util.Collections; @@ -14,13 +14,18 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableObject; +import com.simibubi.create.AllPackets; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainPacket; -import com.simibubi.create.content.logistics.trains.management.display.GlobalTrainDisplayData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.kinetics.KineticDebugger; +import com.simibubi.create.content.trains.display.GlobalTrainDisplayData; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainPacket; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphSync; +import com.simibubi.create.content.trains.graph.TrackGraphVisualizer; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -62,7 +67,7 @@ public class GlobalRailwayManager { .toList(), serverPlayer); for (Train train : trains.values()) - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer), + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> serverPlayer), new TrainPacket(train, true)); } } @@ -122,7 +127,7 @@ public class GlobalRailwayManager { public TrackGraph getOrCreateGraph(UUID graphID, int netId) { return trackNetworks.computeIfAbsent(graphID, uid -> { TrackGraph trackGraph = new TrackGraph(graphID); - trackGraph.netId = netId; + trackGraph.setNetId(netId); return trackGraph; }); } @@ -227,7 +232,7 @@ public class GlobalRailwayManager { if (train.invalid) { iterator.remove(); trains.remove(train.id); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, false)); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainPacket(train, false)); continue; } @@ -243,7 +248,7 @@ public class GlobalRailwayManager { if (train.invalid) { iterator.remove(); trains.remove(train.id); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, false)); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainPacket(train, false)); continue; } @@ -256,15 +261,23 @@ public class GlobalRailwayManager { } public void tickSignalOverlay() { - if (!KineticDebugger.isActive()) + if (!isTrackGraphDebugActive()) for (TrackGraph trackGraph : trackNetworks.values()) TrackGraphVisualizer.visualiseSignalEdgeGroups(trackGraph); } public void clientTick() { - if (KineticDebugger.isActive()) + if (isTrackGraphDebugActive()) for (TrackGraph trackGraph : trackNetworks.values()) - TrackGraphVisualizer.debugViewGraph(trackGraph); + TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended()); + } + + private static boolean isTrackGraphDebugActive() { + return KineticDebugger.isF3DebugModeActive() && AllConfigs.client().showTrackGraphOnF3.get(); + } + + private static boolean isTrackGraphDebugExtended() { + return AllConfigs.client().showExtendedTrackGraphOnF3.get(); } public GlobalRailwayManager sided(LevelAccessor level) { diff --git a/src/main/java/com/simibubi/create/content/trains/HonkPacket.java b/src/main/java/com/simibubi/create/content/trains/HonkPacket.java new file mode 100644 index 0000000000..b5f8c3f84d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/HonkPacket.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.trains; + +import java.util.UUID; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +public class HonkPacket extends SimplePacketBase { + + UUID trainId; + boolean isHonk; + + public HonkPacket() {} + + public HonkPacket(Train train, boolean isHonk) { + trainId = train.id; + this.isHonk = isHonk; + } + + public HonkPacket(FriendlyByteBuf buffer) { + trainId = buffer.readUUID(); + isHonk = buffer.readBoolean(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeUUID(trainId); + buffer.writeBoolean(isHonk); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + boolean clientSide = sender == null; + Train train = Create.RAILWAYS.sided(clientSide ? null : sender.level).trains.get(trainId); + if (train == null) + return; + + if (clientSide) { + if (isHonk) + train.honkTicks = train.honkTicks == 0 ? 20 : 13; + else + train.honkTicks = train.honkTicks > 5 ? 6 : 0; + } else { + AllAdvancements.TRAIN_WHISTLE.awardTo(sender); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new HonkPacket(train, isHonk)); + } + + }); + return true; + } + + public static class Serverbound extends HonkPacket { + + public Serverbound(FriendlyByteBuf buffer) { + super(buffer); + } + + public Serverbound(Train train, boolean isHonk) { + super(train, isHonk); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java b/src/main/java/com/simibubi/create/content/trains/RailwaySavedData.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java rename to src/main/java/com/simibubi/create/content/trains/RailwaySavedData.java index dfdad12b9d..b2b8a18d47 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java +++ b/src/main/java/com/simibubi/create/content/trains/RailwaySavedData.java @@ -1,14 +1,16 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains; import java.util.HashMap; import java.util.Map; import java.util.UUID; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java b/src/main/java/com/simibubi/create/content/trains/TrainHUD.java similarity index 86% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java rename to src/main/java/com/simibubi/create/content/trains/TrainHUD.java index 814dc8819b..dbb8682177 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java +++ b/src/main/java/com/simibubi/create/content/trains/TrainHUD.java @@ -1,13 +1,15 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.trains; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.AllPackets; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsHandler; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.AllGuiTextures; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.ControlsUtil; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; @@ -60,7 +62,7 @@ public class TrainHUD { Train train = carriage.train; double value = - Math.abs(train.speed) / (train.maxSpeed() * AllConfigs.SERVER.trains.manualTrainSpeedModifier.getF()); + Math.abs(train.speed) / (train.maxSpeed() * AllConfigs.server().trains.manualTrainSpeedModifier.getF()); value = Mth.clamp(value + 0.05f, 0, 1); displayedSpeed.chase((int) (value * 18) / 18f, .5f, Chaser.EXP); @@ -73,14 +75,14 @@ public class TrainHUD { if (isSprintKeyPressed && honkPacketCooldown-- <= 0) { train.determineHonk(mc.level); if (train.lowHonk != null) { - AllPackets.channel.sendToServer(new HonkPacket.Serverbound(train, true)); + AllPackets.getChannel().sendToServer(new HonkPacket.Serverbound(train, true)); honkPacketCooldown = 5; usedToHonk = true; } } if (!isSprintKeyPressed && usedToHonk) { - AllPackets.channel.sendToServer(new HonkPacket.Serverbound(train, false)); + AllPackets.getChannel().sendToServer(new HonkPacket.Serverbound(train, false)); honkPacketCooldown = 0; usedToHonk = false; } @@ -94,13 +96,13 @@ public class TrainHUD { } if (hudPacketCooldown-- <= 0) { - AllPackets.channel.sendToServer(new TrainHUDUpdatePacket.Serverbound(train, editedThrottle)); + AllPackets.getChannel().sendToServer(new TrainHUDUpdatePacket.Serverbound(train, editedThrottle)); hudPacketCooldown = 5; } } private static Carriage getCarriage() { - if (!(ControlsHandler.entityRef.get() instanceof CarriageContraptionEntity cce)) + if (!(ControlsHandler.getContraption() instanceof CarriageContraptionEntity cce)) return null; return cce.getCarriage(); } @@ -111,7 +113,7 @@ public class TrainHUD { if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) return; - if (!(ControlsHandler.entityRef.get() instanceof CarriageContraptionEntity cce)) + if (!(ControlsHandler.getContraption() instanceof CarriageContraptionEntity cce)) return; Carriage carriage = cce.getCarriage(); if (carriage == null) @@ -120,7 +122,7 @@ public class TrainHUD { .getCameraEntity(); if (cameraEntity == null) return; - BlockPos localPos = ControlsHandler.controlsPos; + BlockPos localPos = ControlsHandler.getControlsPos(); if (localPos == null) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java b/src/main/java/com/simibubi/create/content/trains/TrainHUDUpdatePacket.java similarity index 81% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java rename to src/main/java/com/simibubi/create/content/trains/TrainHUDUpdatePacket.java index d701802132..c0c97fceb2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java +++ b/src/main/java/com/simibubi/create/content/trains/TrainHUDUpdatePacket.java @@ -1,10 +1,9 @@ -package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; +package com.simibubi.create.content.trains; import java.util.UUID; -import java.util.function.Supplier; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.network.FriendlyByteBuf; @@ -47,10 +46,9 @@ public class TrainHUDUpdatePacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context c = context.get(); - c.enqueueWork(() -> { - ServerPlayer sender = c.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); boolean clientSide = sender == null; Train train = Create.RAILWAYS.sided(clientSide ? null : sender.level).trains.get(trainId); if (train == null) @@ -62,9 +60,8 @@ public class TrainHUDUpdatePacket extends SimplePacketBase { train.speed = speed; train.fuelTicks = fuelTicks; } - }); - c.setPacketHandled(true); + return true; } public static class Serverbound extends TrainHUDUpdatePacket { diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlock.java b/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlock.java new file mode 100644 index 0000000000..fb9ce7a252 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlock.java @@ -0,0 +1,365 @@ +package com.simibubi.create.content.trains.bogey; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Vector3f; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageBogey; +import com.simibubi.create.content.trains.entity.TravellingPoint; +import com.simibubi.create.content.trains.track.TrackMaterial; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.platform.CatnipServices; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.registries.ForgeRegistries; + +public abstract class AbstractBogeyBlock extends Block implements IBE, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { + public static final EnumProperty AXIS = BlockStateProperties.HORIZONTAL_AXIS; + static final List BOGEYS = new ArrayList<>(); + public BogeySizes.BogeySize size; + + + public AbstractBogeyBlock(Properties pProperties, BogeySizes.BogeySize size) { + super(pProperties); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + this.size = size; + } + + public boolean isOnIncompatibleTrack(Carriage carriage, boolean leading) { + TravellingPoint point = leading ? carriage.getLeadingPoint() : carriage.getTrailingPoint(); + CarriageBogey bogey = leading ? carriage.leadingBogey() : carriage.trailingBogey(); + return point.edge.getTrackMaterial().trackType != getTrackType(bogey.getStyle()); + } + + public Set getValidPathfindingTypes(BogeyStyle style) { + return ImmutableSet.of(getTrackType(style)); + } + + public abstract TrackMaterial.TrackType getTrackType(BogeyStyle style); + + /** + * Only for internal Create use. If you have your own style set, do not call this method + */ + @Deprecated + public static void registerStandardBogey(ResourceLocation block) { + BOGEYS.add(block); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AXIS, WATERLOGGED); + super.createBlockStateDefinition(builder); + } + + @Override + public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState, + LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) { + updateWater(pLevel, pState, pCurrentPos); + return pState; + } + + @Override + public FluidState getFluidState(BlockState pState) { + return fluidState(pState); + } + + static final EnumSet STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST); + static final EnumSet STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH); + + public EnumSet getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) { + return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Direction.Axis.X ? STICKY_X : STICKY_Z; + } + + public abstract double getWheelPointSpacing(); + + public abstract double getWheelRadius(); + + public Vec3 getConnectorAnchorOffset(boolean upsideDown) { + return getConnectorAnchorOffset(); + } + + /** + * This should be implemented, but not called directly + */ + protected abstract Vec3 getConnectorAnchorOffset(); + + public boolean allowsSingleBogeyCarriage() { + return true; + } + + public abstract BogeyStyle getDefaultStyle(); + + /** + * Legacy system doesn't capture bogey block entities when constructing a train + */ + public boolean captureBlockEntityForTrain() { + return false; + } + + @OnlyIn(Dist.CLIENT) + public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks, + MultiBufferSource buffers, int light, int overlay, BogeyStyle style, CompoundTag bogeyData) { + if (style == null) + style = getDefaultStyle(); + + final Optional commonRenderer + = style.getInWorldCommonRenderInstance(); + final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize()); + if (state != null) { + ms.translate(.5f, .5f, .5f); + if (state.getValue(AXIS) == Direction.Axis.X) + ms.mulPose(Vector3f.YP.rotationDegrees(90)); + } + ms.translate(0, -1.5 - 1 / 128f, 0); + VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped()); + if (bogeyData == null) + bogeyData = new CompoundTag(); + renderer.render(bogeyData, wheelAngle, ms, light, vb, state == null); + CompoundTag finalBogeyData = bogeyData; + commonRenderer.ifPresent(common -> + common.render(finalBogeyData, wheelAngle, ms, light, vb, state == null)); + } + + public BogeySizes.BogeySize getSize() { + return this.size; + } + + public Direction getBogeyUpDirection() { + return Direction.UP; + } + + public boolean isTrackAxisAlongFirstCoordinate(BlockState state) { + return state.getValue(AXIS) == Direction.Axis.X; + } + + @Nullable + public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) { + if (upDirection != Direction.UP) + return null; + return defaultBlockState().setValue(AXIS, axisAlongFirst ? Direction.Axis.X : Direction.Axis.Z); + } + + @Override + public final InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + if (level.isClientSide) + return InteractionResult.PASS; + ItemStack stack = player.getItemInHand(hand); + + if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem()) + && AllBogeyStyles.BOGEY_STYLES.size() > 1) { + + BlockEntity be = level.getBlockEntity(pos); + + if (!(be instanceof AbstractBogeyBlockEntity sbbe)) + return InteractionResult.FAIL; + + player.getCooldowns().addCooldown(stack.getItem(), 20); + BogeyStyle currentStyle = sbbe.getStyle(); + + BogeySizes.BogeySize size = getSize(); + + BogeyStyle style = this.getNextStyle(currentStyle); + if (style == currentStyle) + return InteractionResult.PASS; + + Set validSizes = style.validSizes(); + + for (int i = 0; i < BogeySizes.count(); i++) { + if (validSizes.contains(size)) break; + size = size.increment(); + } + + sbbe.setBogeyStyle(style); + + CompoundTag defaultData = style.defaultData; + sbbe.setBogeyData(sbbe.getBogeyData().merge(defaultData)); + + if (size == getSize()) { + player.displayClientMessage(CreateLang.translateDirect("bogey.style.updated_style") + .append(": ").append(style.displayName), true); + } else { + CompoundTag oldData = sbbe.getBogeyData(); + level.setBlock(pos, this.getStateOfSize(sbbe, size), 3); + BlockEntity newBlockEntity = level.getBlockEntity(pos); + if (!(newBlockEntity instanceof AbstractBogeyBlockEntity newBlockEntity1)) + return InteractionResult.FAIL; + newBlockEntity1.setBogeyData(oldData); + player.displayClientMessage(CreateLang.translateDirect("bogey.style.updated_style_and_size") + .append(": ").append(style.displayName), true); + } + + return InteractionResult.CONSUME; + } + + return onInteractWithBogey(state, level, pos, player, hand, hit); + } + + // Allows for custom interactions with bogey block to be added simply + protected InteractionResult onInteractWithBogey(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, + BlockHitResult hit) { + return InteractionResult.PASS; + } + + /** + * If, instead of using the style-based cycling system you prefer to use separate blocks, return them from this method + */ + protected List getBogeyBlockCycle() { + return BOGEYS; + } + + @Override + public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { + Block block = state.getBlock(); + List bogeyCycle = getBogeyBlockCycle(); + int indexOf = bogeyCycle.indexOf(CatnipServices.REGISTRIES.getKeyOrThrow(block)); + if (indexOf == -1) + return state; + int index = (indexOf + 1) % bogeyCycle.size(); + Direction bogeyUpDirection = getBogeyUpDirection(); + boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state); + + while (index != indexOf) { + ResourceLocation id = bogeyCycle.get(index); + Block newBlock = ForgeRegistries.BLOCKS.getValue(id); + if (newBlock instanceof AbstractBogeyBlock bogey) { + BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate); + if (matchingBogey != null) + return copyProperties(state, matchingBogey); + } + index = (index + 1) % bogeyCycle.size(); + } + + return state; + } + + public BlockState getNextSize(Level level, BlockPos pos) { + BlockEntity be = level.getBlockEntity(pos); + if (be instanceof AbstractBogeyBlockEntity sbbe) + return this.getNextSize(sbbe); + return level.getBlockState(pos); + } + + /** + * List of BlockState Properties to copy between sizes + */ + public List> propertiesToCopy() { + return ImmutableList.of(WATERLOGGED, AXIS); + } + + // generic method needed to satisfy Property and BlockState's generic requirements + private > BlockState copyProperty(BlockState source, BlockState target, Property property) { + if (source.hasProperty(property) && target.hasProperty(property)) { + return target.setValue(property, source.getValue(property)); + } + return target; + } + + private BlockState copyProperties(BlockState source, BlockState target) { + for (Property property : propertiesToCopy()) + target = copyProperty(source, target, property); + return target; + } + + public BlockState getNextSize(AbstractBogeyBlockEntity sbte) { + BogeySizes.BogeySize size = this.getSize(); + BogeyStyle style = sbte.getStyle(); + BlockState nextBlock = style.getNextBlock(size).defaultBlockState(); + nextBlock = copyProperties(sbte.getBlockState(), nextBlock); + return nextBlock; + } + + public BlockState getStateOfSize(AbstractBogeyBlockEntity sbte, BogeySizes.BogeySize size) { + BogeyStyle style = sbte.getStyle(); + BlockState state = style.getBlockOfSize(size).defaultBlockState(); + return copyProperties(sbte.getBlockState(), state); + } + + public BogeyStyle getNextStyle(Level level, BlockPos pos) { + BlockEntity te = level.getBlockEntity(pos); + if (te instanceof AbstractBogeyBlockEntity sbbe) + return this.getNextStyle(sbbe.getStyle()); + return getDefaultStyle(); + } + + public BogeyStyle getNextStyle(BogeyStyle style) { + Collection allStyles = style.getCycleGroup().values(); + if (allStyles.size() <= 1) + return style; + List list = new ArrayList<>(allStyles); + return Iterate.cycleValue(list, style); + } + + + @Override + public @NotNull BlockState rotate(@NotNull BlockState pState, Rotation pRotation) { + return switch (pRotation) { + case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS); + default -> pState; + }; + } + + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); + } + + public boolean canBeUpsideDown() { + return false; + } + + public boolean isUpsideDown(BlockState state) { + return false; + } + + public BlockState getVersion(BlockState base, boolean upsideDown) { + return base; + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlockEntity.java new file mode 100644 index 0000000000..0c12b6f64a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/AbstractBogeyBlockEntity.java @@ -0,0 +1,118 @@ +package com.simibubi.create.content.trains.bogey; + +import static com.simibubi.create.content.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.foundation.blockEntity.CachedRenderBBBlockEntity; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public abstract class AbstractBogeyBlockEntity extends CachedRenderBBBlockEntity { + public static final String BOGEY_STYLE_KEY = "BogeyStyle"; + public static final String BOGEY_DATA_KEY = "BogeyData"; + + private CompoundTag bogeyData; + + public AbstractBogeyBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + public abstract BogeyStyle getDefaultStyle(); + + public CompoundTag getBogeyData() { + if (this.bogeyData == null || !this.bogeyData.contains(BOGEY_STYLE_KEY)) + this.bogeyData = this.createBogeyData(); + return this.bogeyData; + } + + public void setBogeyData(@NotNull CompoundTag newData) { + if (!newData.contains(BOGEY_STYLE_KEY)) { + ResourceLocation style = getDefaultStyle().name; + NBTHelper.writeResourceLocation(newData, BOGEY_STYLE_KEY, style); + } + this.bogeyData = newData; + } + + public void setBogeyStyle(@NotNull BogeyStyle style) { + ResourceLocation location = style.name; + CompoundTag data = this.getBogeyData(); + NBTHelper.writeResourceLocation(data, BOGEY_STYLE_KEY, location); + markUpdated(); + } + + @NotNull + public BogeyStyle getStyle() { + CompoundTag data = this.getBogeyData(); + ResourceLocation currentStyle = NBTHelper.readResourceLocation(data, BOGEY_STYLE_KEY); + BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(currentStyle); + if (style == null) { + setBogeyStyle(getDefaultStyle()); + return getStyle(); + } + return style; + } + + @Override + protected void saveAdditional(@NotNull CompoundTag pTag) { + CompoundTag data = this.getBogeyData(); + if (data != null) pTag.put(BOGEY_DATA_KEY, data); // Now contains style + super.saveAdditional(pTag); + } + + @Override + public void load(CompoundTag pTag) { + if (pTag.contains(BOGEY_DATA_KEY)) + this.bogeyData = pTag.getCompound(BOGEY_DATA_KEY); + else + this.bogeyData = this.createBogeyData(); + super.load(pTag); + } + + private CompoundTag createBogeyData() { + CompoundTag nbt = new CompoundTag(); + NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, getDefaultStyle().name); + boolean upsideDown = false; + if (getBlockState().getBlock() instanceof AbstractBogeyBlock bogeyBlock) + upsideDown = bogeyBlock.isUpsideDown(getBlockState()); + nbt.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + return nbt; + } + + @Override + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); + } + + // Ponder + LerpedFloat virtualAnimation = LerpedFloat.angular(); + + public float getVirtualAngle(float partialTicks) { + return virtualAnimation.getValue(partialTicks); + } + + public void animate(float distanceMoved) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof AbstractBogeyBlock type)) + return; + double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); + double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360; + virtualAnimation.setValue(newWheelAngle); + } + + private void markUpdated() { + setChanged(); + Level level = getLevel(); + if (level != null) + getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3); + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BackupBogeyRenderer.java b/src/main/java/com/simibubi/create/content/trains/bogey/BackupBogeyRenderer.java new file mode 100644 index 0000000000..fd991fb043 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BackupBogeyRenderer.java @@ -0,0 +1,22 @@ +package com.simibubi.create.content.trains.bogey; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.trains.entity.CarriageBogey; + +import net.minecraft.nbt.CompoundTag; + +public class BackupBogeyRenderer extends BogeyRenderer.CommonRenderer { + public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer(); + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + + } + + @Override + public void initialiseContraptionModelData(MaterialManager materialManager, CarriageBogey carriageBogey) { + + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BogeyBlockEntityRenderer.java b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyBlockEntityRenderer.java new file mode 100644 index 0000000000..e570fa26b0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyBlockEntityRenderer.java @@ -0,0 +1,26 @@ +package com.simibubi.create.content.trains.bogey; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public class BogeyBlockEntityRenderer extends SafeBlockEntityRenderer { + + public BogeyBlockEntityRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + BlockState blockState = be.getBlockState(); + if (be instanceof AbstractBogeyBlockEntity sbbe) { + float angle = sbbe.getVirtualAngle(partialTicks); + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) + bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbbe.getStyle(), sbbe.getBogeyData()); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BogeyInstance.java b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyInstance.java new file mode 100644 index 0000000000..2af3224b57 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyInstance.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.trains.bogey; + +import java.util.Optional; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.util.AnimationTickHolder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.trains.entity.CarriageBogey; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.phys.Vec3; + +public final class BogeyInstance { + private final BogeySizes.BogeySize size; + private final BogeyStyle style; + + public final CarriageBogey bogey; + public final BogeyRenderer renderer; + public final Optional commonRenderer; + + public BogeyInstance(CarriageBogey bogey, BogeyStyle style, BogeySizes.BogeySize size, + MaterialManager materialManager) { + this.bogey = bogey; + this.size = size; + this.style = style; + + this.renderer = this.style.createRendererInstance(this.size); + this.commonRenderer = this.style.getNewCommonRenderInstance(); + + commonRenderer.ifPresent(bogeyRenderer -> bogeyRenderer.initialiseContraptionModelData(materialManager, bogey)); + renderer.initialiseContraptionModelData(materialManager, bogey); + } + + public void beginFrame(float wheelAngle, PoseStack ms) { + if (ms == null) { + renderer.emptyTransforms(); + return; + } + + commonRenderer.ifPresent(bogeyRenderer -> bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms)); + renderer.render(bogey.bogeyData, wheelAngle, ms); + } + + public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { + var lightPos = new BlockPos(getLightPos(entity)); + commonRenderer + .ifPresent(bogeyRenderer -> bogeyRenderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), + world.getBrightness(LightLayer.SKY, lightPos))); + renderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), + world.getBrightness(LightLayer.SKY, lightPos)); + } + + private Vec3 getLightPos(CarriageContraptionEntity entity) { + return bogey.getAnchorPosition() != null ? bogey.getAnchorPosition() + : entity.getLightProbePosition(AnimationTickHolder.getPartialTicks()); + } + + @FunctionalInterface + interface BogeyInstanceFactory { + BogeyInstance create(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager); + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BogeyRenderer.java b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyRenderer.java new file mode 100644 index 0000000000..64966f18b5 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyRenderer.java @@ -0,0 +1,395 @@ +package com.simibubi.create.content.trains.bogey; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.IntStream; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.materials.model.ModelData; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import com.mojang.math.Quaternion; +import com.simibubi.create.content.trains.entity.CarriageBogey; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.CachedBlockBuffers; +import net.createmod.catnip.render.SuperByteBuffer; +import net.createmod.catnip.utility.flw.Transform; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +/** + * This is a port of the bogey api from Extended Bogeys, If you are looking to implement your own bogeys you can find some helpful resources below: + *

+ * - Extended Bogeys (Examples) + * - Extended Bogeys (API documentation) + * - Steam n' Rails (Examples) + */ +public abstract class BogeyRenderer { + Map contraptionModelData = new HashMap<>(); + + /** + * A common interface for getting transform data for both in-world and in-contraption model data safely from a + * partial model + * + * @param model The key for the model data to instantiate or retrieve + * @param ms The posestack used for contraption model data + * @param inInstancedContraption The type of model needed + * @param size The amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public BogeyModelData[] getTransform(PartialModel model, PoseStack ms, boolean inInstancedContraption, int size) { + return (inInstancedContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size); + } + + /** + * A common interface for getting transform data for both in-world and in-contraption model data safely from a + * blockstate + * + * @param state The key for the model data to instantiate or retrieve + * @param ms The posestack used for contraption model data + * @param inContraption The type of model needed + * @param size The amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public BogeyModelData[] getTransform(BlockState state, PoseStack ms, boolean inContraption, int size) { + return inContraption ? transformContraptionModelData(keyFromModel(state), ms) : createModelData(state, size); + } + + /** + * Helper function to collect or create a single model from a partial model used for both in-world and + * in-contraption rendering + * + * @param model The key of the model to be collected or instantiated + * @param ms Posestack to bind the model to if it is within a contraption + * @param inInstancedContraption Type of rendering required + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public BogeyModelData getTransform(PartialModel model, PoseStack ms, boolean inInstancedContraption) { + return inInstancedContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms) + : BogeyModelData.from(model); + } + + /** + * A common interface for getting transform data for blockstates, for a single model + * + * @param state The state of the model to be collected or instantiated + * @param ms Posestack to bind the model to if it is within a contraption + * @param inContraption Type of model required + * @return A generic transform which can be used for both in-world and in-contraption models + */ + public BogeyModelData getTransform(BlockState state, PoseStack ms, boolean inContraption) { + return (inContraption) ? contraptionModelData.get(keyFromModel(state))[0].setTransform(ms) + : BogeyModelData.from(state); + } + + /** + * Used for calling both in-world and in-contraption rendering + * + * @param bogeyData Custom data stored on the bogey able to be used for rendering + * @param wheelAngle The angle of the wheel + * @param ms The posestack to render to + * @param light (Optional) Light used for in-world rendering + * @param vb (Optional) Vertex Consumer used for in-world rendering + */ + @OnlyIn(Dist.CLIENT) + public abstract void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, + VertexConsumer vb, boolean inContraption); + + /** + * Used for calling in-contraption rendering ensuring that falsey data is handled correctly + * + * @param bogeyData Custom data stored on the bogey able to be used for rendering + * @param wheelAngle The angle of the wheel + * @param ms The posestack to render to + */ + @OnlyIn(Dist.CLIENT) + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms) { + this.render(bogeyData, wheelAngle, ms, 0, null, true); + } + + public abstract BogeySizes.BogeySize getSize(); + + /** + * Used to collect Contraption Model Data for in-contraption rendering, should not be utilised directly when + * rendering to prevent render type mismatch + * + * @param key The key used to access the model + * @param ms Posestack of the contraption to bind the model data to + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private BogeyModelData[] transformContraptionModelData(String key, PoseStack ms) { + BogeyModelData[] modelData = contraptionModelData.get(key); + Arrays.stream(modelData).forEach(modelDataElement -> modelDataElement.setTransform(ms)); + return modelData; + } + + + /** + * Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response + * when rendering multiple models both in-world and in-contraption for example, with wheels + * + * @param model The partial model of the model data ot be made + * @param size The Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private BogeyModelData[] createModelData(PartialModel model, int size) { + BogeyModelData[] data = { BogeyModelData.from(model) }; + return expandArrayToLength(data, size); + } + + /** + * Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response + * when rendering multiple models both in-world and in-contraption for example, with wheels + * + * @param state The state of the model data to be made + * @param size Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private BogeyModelData[] createModelData(BlockState state, int size) { + BogeyModelData[] data = { BogeyModelData.from(state) }; + return expandArrayToLength(data, size); + } + + /** + * Utility function to clone in-world models to a set size to allow for common handling of rendering with multiple + * instances of the same model for example with wheels + * + * @param data An in-world model to be replicated + * @param size Amount of models needed + * @return A generic transform which can be used for both in-world and in-contraption models + */ + private BogeyModelData[] expandArrayToLength(BogeyModelData[] data, int size) { + return Arrays.stream(Collections.nCopies(size, data).toArray()) + .flatMap(inner -> Arrays.stream((BogeyModelData[]) inner)) + .toArray(BogeyModelData[]::new); + } + + /** + * Provides render implementations a point in setup to instantiate all model data to be needed + * + * @param materialManager The material manager + * @param carriageBogey The bogey to create data for + */ + @OnlyIn(Dist.CLIENT) + public abstract void initialiseContraptionModelData(MaterialManager materialManager, CarriageBogey carriageBogey); + + /** + * Creates instances of models for in-world rendering to a set length from a provided partial model + * + * @param materialManager The material manager + * @param model Partial model to be instanced + * @param count Amount of models neeeded + */ + public void createModelInstance(MaterialManager materialManager, PartialModel model, int count) { + BogeyModelData[] modelData = IntStream.range(0, count) + .mapToObj(i -> materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(model).createInstance()) + .map((ModelData transform) -> new BogeyModelData((Transform) transform))//TODO + .toArray(BogeyModelData[]::new); + contraptionModelData.put(keyFromModel(model), modelData); + } + + /** + * Creates instances of models for in-contraption rendering to a set length from a provided blockstate + * + * @param materialManager The material manager + * @param state Blockstate of the model to be created + * @param count Amount of models needed + */ + public void createModelInstance(MaterialManager materialManager, BlockState state, int count) { + BogeyModelData[] modelData = IntStream.range(0, count) + .mapToObj(i -> materialManager.defaultSolid() + .material(Materials.TRANSFORMED) + .getModel(state).createInstance()) + .map((ModelData transform) -> new BogeyModelData((Transform) transform))//TODO + .toArray(BogeyModelData[]::new); + contraptionModelData.put(keyFromModel(state), modelData); + } + + /** + * Creates a single instance of models for in-contraption rendering from a provided blockstate + * + * @param materialManager The material manager + * @param states Blockstates of the models to be created + */ + public void createModelInstance(MaterialManager materialManager, BlockState... states) { + for (BlockState state : states) + this.createModelInstance(materialManager, state, 1); + } + + /** + * Helper function to create a single model instance for in-contraption rendering + * + * @param materialManager The material manager + * @param models The type of model to create instances of + */ + public void createModelInstance(MaterialManager materialManager, PartialModel... models) { + for (PartialModel model : models) + createModelInstance(materialManager, model, 1); + } + + /** + * This method is deprecated, use BogeyModelData#render instead, left in + * to avoid existing usages from crashing + * + * @param b The model data itself + * @param ms Pose stack to render to + * @param light light level of the scene + * @param vb Vertex Consumber to render to + * @param Generic alias for both contraption and in-world model data + */ + + @Deprecated + public static > void finalize(B b, PoseStack ms, int light, @Nullable VertexConsumer vb) { + b.scale(1 - 1/512f); + if (b instanceof SuperByteBuffer byteBuf && vb != null) + byteBuf.light(light).renderInto(ms, vb); + } + + /** + * Automatic handling for setting empty transforms for all model data + * + */ + + public void emptyTransforms() { + for (BogeyModelData[] data : contraptionModelData.values()) + for (BogeyModelData model : data) + model.setEmptyTransform(); + } + + /** + * Automatic handling for updating all model data's light + * + * @param blockLight the blocklight to be applied + * @param skyLight the skylight to be applied + */ + + public void updateLight(int blockLight, int skyLight) { + for (BogeyModelData[] data : contraptionModelData.values()) + for (BogeyModelData model : data) + model.updateLight(blockLight, skyLight); + } + + /** + * Automatic handling for clearing all model data of a contraption + * + */ + + public void remove() { + for (BogeyModelData[] data : contraptionModelData.values()) + for (BogeyModelData model : data) + model.delete(); + contraptionModelData.clear(); + } + + /** + * Create a model key from a partial model, so it can be easily accessed + * + * @param partialModel the model we want a unique key for + * @return Key of the model + */ + + private String keyFromModel(PartialModel partialModel) { + return partialModel.getLocation().toString(); + } + + /** + * Create a model key from a blockstate, so it can be easily accessed + * + * @param state Blockstate of the model + * @return Key of the model + */ + + private String keyFromModel(BlockState state) { + return state.toString(); + } + + public static abstract class CommonRenderer extends BogeyRenderer { + @Override + public BogeySizes.BogeySize getSize() { + return null; + } + } + + public record BogeyModelData(Transform transform) implements Transform { + public static BogeyModelData from(PartialModel model) { + BlockState air = Blocks.AIR.defaultBlockState(); + return new BogeyModelData(CachedPartialBuffers.partial(model, air)); + } + public static BogeyModelData from(BlockState model) { + return new BogeyModelData(CachedBlockBuffers.block(model)); + } + public void render(PoseStack ms, int light, @Nullable VertexConsumer vb) { + transform.scale(1 - 1/512f); + if (transform instanceof SuperByteBuffer byteBuf && vb != null) + byteBuf.light(light).renderInto(ms, vb); + } + + public BogeyModelData setTransform(PoseStack ms) { + if (this.transform instanceof ModelData model) + model.setTransform(ms); + return this; + } + + public BogeyModelData setEmptyTransform() { + if (this.transform instanceof ModelData model) + model.setEmptyTransform(); + return this; + } + + public BogeyModelData delete() { + if (this.transform instanceof ModelData model) + model.delete(); + return this; + } + + public BogeyModelData updateLight(int blockLight, int skyLight) { + if (this.transform instanceof ModelData model) + model.setBlockLight(blockLight).setSkyLight(skyLight); + return this; + } + + @Override + public BogeyModelData mulPose(Matrix4f pose) { + this.transform.mulPose(pose); + return this; + } + + @Override + public BogeyModelData mulNormal(Matrix3f normal) { + this.transform.mulNormal(normal); + return this; + } + + @Override + public BogeyModelData multiply(Quaternion quaternion) { + this.transform.multiply(quaternion); + return this; + } + + @Override + public BogeyModelData scale(float factorX, float factorY, float factorZ) { + this.transform.scale(factorX, factorY, factorZ); + return this; + } + + @Override + public BogeyModelData translate(double x, double y, double z) { + this.transform.translate(x, y, z); + return this; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BogeySizes.java b/src/main/java/com/simibubi/create/content/trains/bogey/BogeySizes.java new file mode 100644 index 0000000000..e9bcc2d489 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BogeySizes.java @@ -0,0 +1,70 @@ +package com.simibubi.create.content.trains.bogey; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +import com.simibubi.create.Create; + +import net.minecraft.resources.ResourceLocation; + +public class BogeySizes { + private static final Collection BOGEY_SIZES = new HashSet<>(); + public static final BogeySize SMALL = new BogeySize(Create.ID, "small", 6.5f / 16f); + public static final BogeySize LARGE = new BogeySize(Create.ID, "large", 12.5f / 16f); + + static { + BOGEY_SIZES.add(SMALL); + BOGEY_SIZES.add(LARGE); + } + + public static BogeySize addSize(String modId, String name, float size) { + ResourceLocation location = new ResourceLocation(modId, name); + return addSize(location, size); + } + + public static BogeySize addSize(ResourceLocation location, float size) { + BogeySize customSize = new BogeySize(location, size); + BOGEY_SIZES.add(customSize); + return customSize; + } + + public static List getAllSizesSmallToLarge() { + return BOGEY_SIZES.stream() + .sorted(Comparator.comparing(BogeySize::wheelRadius)) + .collect(Collectors.toList()); + } + + public static List getAllSizesLargeToSmall() { + List sizes = getAllSizesSmallToLarge(); + Collections.reverse(sizes); + return sizes; + } + + public static int count() { + return BOGEY_SIZES.size(); + } + + public record BogeySize(ResourceLocation location, float wheelRadius) { + public BogeySize(String modId, String name, float wheelRadius) { + this(new ResourceLocation(modId, name), wheelRadius); + } + + public BogeySize increment() { + List values = getAllSizesSmallToLarge(); + int ordinal = values.indexOf(this); + return values.get((ordinal + 1) % values.size()); + } + + public boolean is(BogeySize size) { + return size.location == this.location; + } + } + + public static void init() { + + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/BogeyStyle.java b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyStyle.java new file mode 100644 index 0000000000..c1b63f7851 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/BogeyStyle.java @@ -0,0 +1,133 @@ +package com.simibubi.create.content.trains.bogey; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.jetbrains.annotations.NotNull; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.trains.bogey.BogeyRenderer.CommonRenderer; +import com.simibubi.create.content.trains.entity.CarriageBogey; + +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.registries.ForgeRegistries; + + +public class BogeyStyle { + + public final ResourceLocation name; + public final ResourceLocation cycleGroup; + public final Component displayName; + public final ResourceLocation soundType; + public final ParticleOptions contactParticle; + public final ParticleOptions smokeParticle; + public final CompoundTag defaultData; + + private Optional> commonRendererFactory; + private Map sizes; + + @OnlyIn(Dist.CLIENT) + private Map sizeRenderers; + + @OnlyIn(Dist.CLIENT) + private Optional commonRenderer; + + public BogeyStyle(ResourceLocation name, ResourceLocation cycleGroup, Component displayName, + ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle, + CompoundTag defaultData, Map sizes, + Map> sizeRenderers, + Optional> commonRenderer) { + + this.name = name; + this.cycleGroup = cycleGroup; + this.displayName = displayName; + this.soundType = soundType; + this.contactParticle = contactParticle; + this.smokeParticle = smokeParticle; + this.defaultData = defaultData; + this.sizes = sizes; + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + this.sizeRenderers = new HashMap<>(); + sizeRenderers.forEach((k, v) -> this.sizeRenderers.put(k, v.get())); + + this.commonRendererFactory = commonRenderer; + this.commonRenderer = commonRenderer.map(Supplier::get); + }); + } + + public Map getCycleGroup() { + return AllBogeyStyles.getCycleGroup(cycleGroup); + } + + public Block getNextBlock(BogeySizes.BogeySize currentSize) { + return Stream.iterate(currentSize.increment(), BogeySizes.BogeySize::increment) + .filter(sizes::containsKey) + .findFirst() + .map(this::getBlockOfSize) + .orElse(getBlockOfSize(currentSize)); + } + + public Block getBlockOfSize(BogeySizes.BogeySize size) { + return ForgeRegistries.BLOCKS.getValue(sizes.get(size)); + } + + public Set validSizes() { + return sizes.keySet(); + } + + @NotNull + public SoundEvent getSoundType() { + AllSoundEvents.SoundEntry entry = AllSoundEvents.ALL.get(this.soundType); + if (entry == null || entry.getMainEvent() == null) entry = AllSoundEvents.TRAIN2; + return entry.getMainEvent(); + } + + @OnlyIn(Dist.CLIENT) + public BogeyRenderer createRendererInstance(BogeySizes.BogeySize size) { + return this.sizeRenderers.get(size).createRenderInstance(); + } + + @OnlyIn(Dist.CLIENT) + public BogeyRenderer getInWorldRenderInstance(BogeySizes.BogeySize size) { + SizeRenderData sizeData = this.sizeRenderers.get(size); + return sizeData != null ? sizeData.getInWorldInstance() : BackupBogeyRenderer.INSTANCE; + } + + public Optional getInWorldCommonRenderInstance() { + return this.commonRenderer; + } + + public Optional getNewCommonRenderInstance() { + return this.commonRendererFactory.map(Supplier::get); + } + + public BogeyInstance createInstance(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager) { + return new BogeyInstance(bogey, this, size, materialManager); + } + + @OnlyIn(Dist.CLIENT) + public record SizeRenderData(Supplier rendererFactory, BogeyRenderer instance) { + public BogeyRenderer createRenderInstance() { + return rendererFactory.get(); + } + + public BogeyRenderer getInWorldInstance() { + return instance; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlock.java new file mode 100644 index 0000000000..b4bceecfae --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlock.java @@ -0,0 +1,69 @@ +package com.simibubi.create.content.trains.bogey; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.trains.track.TrackMaterial; +import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class StandardBogeyBlock extends AbstractBogeyBlock + implements IBE, ProperWaterloggedBlock, ISpecialBlockItemRequirement { + + public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) { + super(props, size); + registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); + } + + @Override + public TrackMaterial.TrackType getTrackType(BogeyStyle style) { + return TrackMaterial.TrackType.STANDARD; + } + + @Override + public double getWheelPointSpacing() { + return 2; + } + + @Override + public double getWheelRadius() { + return (size == BogeySizes.LARGE ? 12.5 : 6.5) / 16d; + } + + @Override + public Vec3 getConnectorAnchorOffset() { + return new Vec3(0, 7 / 32f, 1); + } + + @Override + public BogeyStyle getDefaultStyle() { + return AllBogeyStyles.STANDARD; + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, + Player player) { + return AllBlocks.RAILWAY_CASING.asStack(); + } + + @Override + public Class getBlockEntityClass() { + return StandardBogeyBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.BOGEY.get(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlockEntity.java new file mode 100644 index 0000000000..d60c88da68 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyBlockEntity.java @@ -0,0 +1,19 @@ +package com.simibubi.create.content.trains.bogey; + +import com.simibubi.create.AllBogeyStyles; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class StandardBogeyBlockEntity extends AbstractBogeyBlockEntity { + + public StandardBogeyBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public BogeyStyle getDefaultStyle() { + return AllBogeyStyles.STANDARD; + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyRenderer.java b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyRenderer.java new file mode 100644 index 0000000000..1310f57922 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/bogey/StandardBogeyRenderer.java @@ -0,0 +1,134 @@ +package com.simibubi.create.content.trains.bogey; + +import static com.simibubi.create.AllPartialModels.BOGEY_DRIVE; +import static com.simibubi.create.AllPartialModels.BOGEY_FRAME; +import static com.simibubi.create.AllPartialModels.BOGEY_PIN; +import static com.simibubi.create.AllPartialModels.BOGEY_PISTON; +import static com.simibubi.create.AllPartialModels.LARGE_BOGEY_WHEELS; +import static com.simibubi.create.AllPartialModels.SMALL_BOGEY_WHEELS; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock; +import com.simibubi.create.content.trains.entity.CarriageBogey; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; + +public class StandardBogeyRenderer { + public static class CommonStandardBogeyRenderer extends BogeyRenderer.CommonRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager, CarriageBogey carriageBogey) { + createModelInstance(materialManager, AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.Z), 2); + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + BogeyModelData[] shafts = getTransform(AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.Z), ms, inInstancedContraption, 2); + for (int i : Iterate.zeroAndOne) { + shafts[i].translate(-.5f, .25f, i * -1) + .centre() + .rotateZ(wheelAngle) + .unCentre() + .render(ms, light, vb); + } + } + } + + + public static class SmallStandardBogeyRenderer extends BogeyRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager, CarriageBogey carriageBogey) { + createModelInstance(materialManager, SMALL_BOGEY_WHEELS, 2); + createModelInstance(materialManager, BOGEY_FRAME); + } + + + @Override + public BogeySizes.BogeySize getSize() { + return BogeySizes.SMALL; + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + getTransform(BOGEY_FRAME, ms, inInstancedContraption) + .render(ms, light, vb); + + BogeyModelData[] wheels = getTransform(SMALL_BOGEY_WHEELS, ms, inInstancedContraption, 2); + for (int side : Iterate.positiveAndNegative) { + if (!inInstancedContraption) + ms.pushPose(); + wheels[(side + 1)/2] + .translate(0, 12 / 16f, side) + .rotateX(wheelAngle) + .render(ms, light, vb); + if (!inInstancedContraption) + ms.popPose(); + } + } + } + + public static class LargeStandardBogeyRenderer extends BogeyRenderer { + @Override + public void initialiseContraptionModelData(MaterialManager materialManager, CarriageBogey carriageBogey) { + createModelInstance(materialManager, LARGE_BOGEY_WHEELS, BOGEY_DRIVE, BOGEY_PISTON, BOGEY_PIN); + createModelInstance(materialManager, AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.X), 2); + } + + @Override + public BogeySizes.BogeySize getSize() { + return BogeySizes.LARGE; + } + + @Override + public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) { + boolean inInstancedContraption = vb == null; + + BogeyModelData[] secondaryShafts = getTransform(AllBlocks.SHAFT.getDefaultState() + .setValue(ShaftBlock.AXIS, Direction.Axis.X), ms, inInstancedContraption, 2); + + for (int i : Iterate.zeroAndOne) { + secondaryShafts[i] + .translate(-.5f, .25f, .5f + i * -2) + .centre() + .rotateX(wheelAngle) + .unCentre() + .render(ms, light, vb); + } + + getTransform(BOGEY_DRIVE, ms, inInstancedContraption) + .render(ms, light, vb); + + getTransform(BOGEY_PISTON, ms, inInstancedContraption) + .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))) + .render(ms, light, vb); + + if (!inInstancedContraption) + ms.pushPose(); + + getTransform(LARGE_BOGEY_WHEELS, ms, inInstancedContraption) + .translate(0, 1, 0) + .rotateX(wheelAngle) + .render(ms, light, vb); + + getTransform(BOGEY_PIN, ms, inInstancedContraption) + .translate(0, 1, 0) + .rotateX(wheelAngle) + .translate(0, 1 / 4f, 0) + .rotateX(-wheelAngle) + .render(ms, light, vb); + + if (!inInstancedContraption) + ms.popPose(); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlock.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java rename to src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlock.java index 176cd30746..162487ea2d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java +++ b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.display; +package com.simibubi.create.content.trains.display; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; @@ -6,16 +6,18 @@ import java.util.List; import java.util.Random; import java.util.function.Predicate; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.content.equipment.clipboard.ClipboardEntry; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.kinetics.base.HorizontalKineticBlock; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.content.kinetics.simpleRelays.ICogWheel; +import com.simibubi.create.foundation.block.IBE; import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.lang.Components; import net.createmod.catnip.utility.placement.IPlacementHelper; import net.createmod.catnip.utility.placement.PlacementHelpers; import net.createmod.catnip.utility.placement.PlacementOffset; @@ -27,6 +29,7 @@ import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; @@ -57,7 +60,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.ticks.LevelTickAccess; public class FlapDisplayBlock extends HorizontalKineticBlock - implements ITE, IWrenchable, ICogWheel, SimpleWaterloggedBlock { + implements IBE, IWrenchable, ICogWheel, SimpleWaterloggedBlock { public static final BooleanProperty UP = BooleanProperty.create("up"); public static final BooleanProperty DOWN = BooleanProperty.create("down"); @@ -127,12 +130,12 @@ public class FlapDisplayBlock extends HorizontalKineticBlock return placementHelper.getOffset(player, world, state, pos, ray) .placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); - FlapDisplayTileEntity flapTe = getTileEntity(world, pos); + FlapDisplayBlockEntity flapBE = getBlockEntity(world, pos); - if (flapTe == null) + if (flapBE == null) return InteractionResult.PASS; - flapTe = flapTe.getController(); - if (flapTe == null) + flapBE = flapBE.getController(); + if (flapBE == null) return InteractionResult.PASS; double yCoord = ray.getLocation() @@ -141,29 +144,30 @@ public class FlapDisplayBlock extends HorizontalKineticBlock .getNormal()) .scale(.125f)).y; - int lineIndex = flapTe.getLineIndexAt(yCoord); + int lineIndex = flapBE.getLineIndexAt(yCoord); if (heldItem.isEmpty()) { - if (!flapTe.isSpeedRequirementFulfilled()) + if (!flapBE.isSpeedRequirementFulfilled()) return InteractionResult.PASS; - flapTe.applyTextManually(lineIndex, null); + flapBE.applyTextManually(lineIndex, null); return InteractionResult.SUCCESS; } if (heldItem.getItem() == Items.GLOW_INK_SAC) { if (!world.isClientSide) { world.playSound(null, pos, SoundEvents.INK_SAC_USE, SoundSource.BLOCKS, 1.0F, 1.0F); - flapTe.setGlowing(lineIndex); + flapBE.setGlowing(lineIndex); } return InteractionResult.SUCCESS; } - boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName(); + boolean display = + heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllBlocks.CLIPBOARD.isIn(heldItem); DyeColor dye = DyeColor.getColor(heldItem); if (!display && dye == null) return InteractionResult.PASS; - if (dye == null && !flapTe.isSpeedRequirementFulfilled()) + if (dye == null && !flapBE.isSpeedRequirementFulfilled()) return InteractionResult.PASS; if (world.isClientSide) return InteractionResult.SUCCESS; @@ -171,11 +175,23 @@ public class FlapDisplayBlock extends HorizontalKineticBlock CompoundTag tag = heldItem.getTagElement("display"); String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null; - if (display) - flapTe.applyTextManually(lineIndex, tagElement); + if (display) { + if (AllBlocks.CLIPBOARD.isIn(heldItem)) { + List entries = ClipboardEntry.getLastViewedEntries(heldItem); + int line = lineIndex; + for (int i = 0; i < entries.size(); i++) { + for (String string : entries.get(i).text.getString() + .split("\n")) + flapBE.applyTextManually(line++, Component.Serializer.toJson(Components.literal(string))); + } + return InteractionResult.SUCCESS; + } + + flapBE.applyTextManually(lineIndex, tagElement); + } if (dye != null) { world.playSound(null, pos, SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F); - flapTe.setColour(lineIndex, dye); + flapBE.setColour(lineIndex, dye); } return InteractionResult.SUCCESS; @@ -187,13 +203,13 @@ public class FlapDisplayBlock extends HorizontalKineticBlock } @Override - public Class getTileEntityClass() { - return FlapDisplayTileEntity.class; + public Class getBlockEntityClass() { + return FlapDisplayBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.FLAP_DISPLAY.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.FLAP_DISPLAY.get(); } @Override @@ -257,8 +273,8 @@ public class FlapDisplayBlock extends HorizontalKineticBlock pPos.relative(Direction.fromAxisAndDirection(getConnectionAxis(pState), AxisDirection.NEGATIVE)); BlockState belowState = pLevel.getBlockState(belowPos); if (!canConnect(pState, belowState)) - KineticTileEntity.switchToBlockState(pLevel, pPos, updateColumn(pLevel, pPos, pState, true)); - withTileEntityDo(pLevel, pPos, FlapDisplayTileEntity::updateControllerStatus); + KineticBlockEntity.switchToBlockState(pLevel, pPos, updateColumn(pLevel, pPos, pState, true)); + withBlockEntityDo(pLevel, pPos, FlapDisplayBlockEntity::updateControllerStatus); } @Override @@ -308,15 +324,15 @@ public class FlapDisplayBlock extends HorizontalKineticBlock @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { - if (pState.hasBlockEntity() && (!pState.is(pNewState.getBlock()) || !pNewState.hasBlockEntity())) - pLevel.removeBlockEntity(pPos); + super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); if (pIsMoving || pNewState.getBlock() == this) return; for (Direction d : Iterate.directionsInAxis(getConnectionAxis(pState))) { BlockPos relative = pPos.relative(d); BlockState adjacent = pLevel.getBlockState(relative); if (canConnect(pState, adjacent)) - KineticTileEntity.switchToBlockState(pLevel, relative, updateColumn(pLevel, relative, adjacent, false)); + KineticBlockEntity.switchToBlockState(pLevel, relative, + updateColumn(pLevel, relative, adjacent, false)); } } diff --git a/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlockEntity.java new file mode 100644 index 0000000000..ba7f76e41a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayBlockEntity.java @@ -0,0 +1,334 @@ +package com.simibubi.create.content.trains.display; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.JsonElement; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.kinetics.base.KineticBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.DyeHelper; +import com.simibubi.create.foundation.utility.DynamicComponent; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class FlapDisplayBlockEntity extends KineticBlockEntity { + + public List lines; + public boolean isController; + public boolean isRunning; + public int xSize, ySize; + public DyeColor[] colour; + public boolean[] glowingLines; + public boolean[] manualLines; + + public FlapDisplayBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(10); + isController = false; + xSize = 1; + ySize = 1; + colour = new DyeColor[2]; + manualLines = new boolean[2]; + glowingLines = new boolean[2]; + } + + @Override + public void initialize() { + super.initialize(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + updateControllerStatus(); + } + + public void updateControllerStatus() { + if (level.isClientSide) + return; + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof FlapDisplayBlock)) + return; + + Direction leftDirection = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING) + .getClockWise(); + boolean shouldBeController = !blockState.getValue(FlapDisplayBlock.UP) + && level.getBlockState(worldPosition.relative(leftDirection)) != blockState; + + int newXSize = 1; + int newYSize = 1; + + if (shouldBeController) { + for (int xOffset = 1; xOffset < 32; xOffset++) { + if (level.getBlockState(worldPosition.relative(leftDirection.getOpposite(), xOffset)) != blockState) + break; + newXSize++; + } + for (int yOffset = 0; yOffset < 32; yOffset++) { + if (!level.getBlockState(worldPosition.relative(Direction.DOWN, yOffset)) + .getOptionalValue(FlapDisplayBlock.DOWN) + .orElse(false)) + break; + newYSize++; + } + } + + if (isController == shouldBeController && newXSize == xSize && newYSize == ySize) + return; + + isController = shouldBeController; + xSize = newXSize; + ySize = newYSize; + colour = Arrays.copyOf(colour, ySize * 2); + glowingLines = Arrays.copyOf(glowingLines, ySize * 2); + manualLines = new boolean[ySize * 2]; + lines = null; + sendData(); + } + + @Override + public void tick() { + super.tick(); + isRunning = super.isSpeedRequirementFulfilled(); + if ((!level.isClientSide || !isRunning) && !isVirtual()) + return; + int activeFlaps = 0; + boolean instant = getSpeed() > 128; + for (FlapDisplayLayout line : lines) + for (FlapDisplaySection section : line.getSections()) + activeFlaps += section.tick(instant); + if (activeFlaps == 0) + return; + + float volume = Mth.clamp(activeFlaps / 20f, 0.25f, 1.5f); + float bgVolume = Mth.clamp(activeFlaps / 40f, 0.25f, 1f); + BlockPos middle = worldPosition.relative(getDirection().getClockWise(), xSize / 2) + .relative(Direction.DOWN, ySize / 2); + AllSoundEvents.SCROLL_VALUE.playAt(level, middle, volume, 0.56f, false); + level.playLocalSound(middle.getX(), middle.getY(), middle.getZ(), SoundEvents.CALCITE_HIT, SoundSource.BLOCKS, + .35f * bgVolume, 1.95f, false); + } + + @Override + protected boolean isNoisy() { + return false; + } + + @Override + public boolean isSpeedRequirementFulfilled() { + return isRunning; + } + + public void applyTextManually(int lineIndex, String rawComponentText) { + List lines = getLines(); + if (lineIndex >= lines.size()) + return; + + FlapDisplayLayout layout = lines.get(lineIndex); + if (!layout.isLayout("Default")) + layout.loadDefault(getMaxCharCount()); + List sections = layout.getSections(); + + FlapDisplaySection flapDisplaySection = sections.get(0); + if (rawComponentText == null) { + manualLines[lineIndex] = false; + flapDisplaySection.setText(Components.immutableEmpty()); + notifyUpdate(); + return; + } + + JsonElement json = DynamicComponent.getJsonFromString(rawComponentText); + if (json == null) + return; + + manualLines[lineIndex] = true; + Component text = isVirtual() ? Component.Serializer.fromJson(rawComponentText) + : DynamicComponent.parseCustomText(level, worldPosition, json); + flapDisplaySection.setText(text); + if (isVirtual()) + flapDisplaySection.refresh(true); + else + notifyUpdate(); + } + + public void setColour(int lineIndex, DyeColor color) { + colour[lineIndex] = color == DyeColor.WHITE ? null : color; + notifyUpdate(); + } + + public void setGlowing(int lineIndex) { + glowingLines[lineIndex] = true; + notifyUpdate(); + } + + public List getLines() { + if (lines == null) + initDefaultSections(); + return lines; + } + + public void initDefaultSections() { + lines = new ArrayList<>(); + for (int i = 0; i < ySize * 2; i++) + lines.add(new FlapDisplayLayout(getMaxCharCount())); + } + + public int getMaxCharCount() { + return getMaxCharCount(0); + } + + public int getMaxCharCount(int gaps) { + return (int) ((xSize * 16f - 2f - 4f * gaps) / 3.5f); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + + tag.putBoolean("Controller", isController); + tag.putInt("XSize", xSize); + tag.putInt("YSize", ySize); + + for (int j = 0; j < manualLines.length; j++) + if (manualLines[j]) + NBTHelper.putMarker(tag, "CustomLine" + j); + + for (int j = 0; j < glowingLines.length; j++) + if (glowingLines[j]) + NBTHelper.putMarker(tag, "GlowingLine" + j); + + for (int j = 0; j < colour.length; j++) + if (colour[j] != null) + NBTHelper.writeEnum(tag, "Dye" + j, colour[j]); + + List lines = getLines(); + for (int i = 0; i < lines.size(); i++) + tag.put("Display" + i, lines.get(i) + .write()); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + boolean wasActive = isController; + int prevX = xSize; + int prevY = ySize; + + isController = tag.getBoolean("Controller"); + xSize = tag.getInt("XSize"); + ySize = tag.getInt("YSize"); + + manualLines = new boolean[ySize * 2]; + for (int i = 0; i < ySize * 2; i++) + manualLines[i] = tag.contains("CustomLine" + i); + + glowingLines = new boolean[ySize * 2]; + for (int i = 0; i < ySize * 2; i++) + glowingLines[i] = tag.contains("GlowingLine" + i); + + colour = new DyeColor[ySize * 2]; + for (int i = 0; i < ySize * 2; i++) + colour[i] = tag.contains("Dye" + i) ? NBTHelper.readEnum(tag, "Dye" + i, DyeColor.class) : null; + + if (clientPacket && wasActive != isController || prevX != xSize || prevY != ySize) { + invalidateRenderBoundingBox(); + lines = null; + } + + List lines = getLines(); + for (int i = 0; i < lines.size(); i++) + lines.get(i) + .read(tag.getCompound("Display" + i)); + } + + public int getLineIndexAt(double yCoord) { + return (int) Mth.clamp(Math.floor(2 * (worldPosition.getY() - yCoord + 1)), 0, ySize * 2); + } + + public FlapDisplayBlockEntity getController() { + if (isController) + return this; + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof FlapDisplayBlock)) + return null; + + MutableBlockPos pos = getBlockPos().mutable(); + Direction side = blockState.getValue(FlapDisplayBlock.HORIZONTAL_FACING) + .getClockWise(); + + for (int i = 0; i < 64; i++) { + BlockState other = level.getBlockState(pos); + + if (other.getOptionalValue(FlapDisplayBlock.UP) + .orElse(false)) { + pos.move(Direction.UP); + continue; + } + + if (!level.getBlockState(pos.relative(side)) + .getOptionalValue(FlapDisplayBlock.UP) + .orElse(true)) { + pos.move(side); + continue; + } + + BlockEntity found = level.getBlockEntity(pos); + if (found instanceof FlapDisplayBlockEntity flap && flap.isController) + return flap; + + break; + } + + return null; + } + + @Override + protected AABB createRenderBoundingBox() { + AABB aabb = new AABB(worldPosition); + if (!isController) + return aabb; + Vec3i normal = getDirection().getClockWise() + .getNormal(); + return aabb.expandTowards(normal.getX() * xSize, -ySize, normal.getZ() * xSize); + } + + public Direction getDirection() { + return getBlockState().getOptionalValue(FlapDisplayBlock.HORIZONTAL_FACING) + .orElse(Direction.SOUTH) + .getOpposite(); + } + + @Override + public void addBehaviours(List behaviours) {} + + public int getLineColor(int line) { + DyeColor color = colour[line]; + return color == null ? 0xFF_D3C6BA + : DyeHelper.DYE_TABLE.get(color) + .getFirst() | 0xFF_000000; + } + + public boolean isLineGlowing(int line) { + return glowingLines[line]; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayLayout.java b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayLayout.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayLayout.java rename to src/main/java/com/simibubi/create/content/trains/display/FlapDisplayLayout.java index f11707f073..b06daf4b7d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayLayout.java +++ b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayLayout.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.display; +package com.simibubi.create.content.trains.display; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayRenderer.java b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayRenderer.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayRenderer.java rename to src/main/java/com/simibubi/create/content/trains/display/FlapDisplayRenderer.java index aeaeb46810..eb4607b62c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayRenderer.java +++ b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplayRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.display; +package com.simibubi.create.content.trains.display; import java.util.List; @@ -8,9 +8,8 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack.Pose; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix4f; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer; import com.simibubi.create.foundation.render.CachedPartialBuffers; import net.createmod.catnip.render.SuperByteBuffer; @@ -34,34 +33,31 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class FlapDisplayRenderer extends KineticTileEntityRenderer { +public class FlapDisplayRenderer extends KineticBlockEntityRenderer { public FlapDisplayRenderer(BlockEntityRendererProvider.Context context) { super(context); } @Override - protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, + protected void renderSafe(FlapDisplayBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - super.renderSafe(te, partialTicks, ms, buffer, light, overlay); + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); Font fontRenderer = Minecraft.getInstance().font; FontSet fontSet = fontRenderer.getFontSet(Style.DEFAULT_FONT); float scale = 1 / 32f; - if (!(te instanceof FlapDisplayTileEntity flapTe)) + if (!be.isController) return; - if (!flapTe.isController) - return; - - List lines = flapTe.getLines(); + List lines = be.getLines(); ms.pushPose(); TransformStack.cast(ms) .centre() - .rotateY(AngleHelper.horizontalAngle(te.getBlockState() + .rotateY(AngleHelper.horizontalAngle(be.getBlockState() .getValue(FlapDisplayBlock.HORIZONTAL_FACING))) .unCentre() .translate(0, 0, -3 / 16f); @@ -74,22 +70,22 @@ public class FlapDisplayRenderer extends KineticTileEntityRenderer { for (int j = 0; j < lines.size(); j++) { List line = lines.get(j) .getSections(); - int color = flapTe.getLineColor(j); + int color = be.getLineColor(j); ms.pushPose(); float w = 0; for (FlapDisplaySection section : line) w += section.getSize() + (section.hasGap ? 8 : 1); - ms.translate(flapTe.xSize * 16 - w / 2 + 1, 4.5f, 0); + ms.translate(be.xSize * 16 - w / 2 + 1, 4.5f, 0); Pose transform = ms.last(); FlapDisplayRenderOutput renderOutput = new FlapDisplayRenderOutput(buffer, color, transform.pose(), light, - j, !te.isSpeedRequirementFulfilled(), te.getLevel(), flapTe.isLineGlowing(j)); + j, !be.isSpeedRequirementFulfilled(), be.getLevel(), be.isLineGlowing(j)); for (int i = 0; i < line.size(); i++) { FlapDisplaySection section = line.get(i); renderOutput.nextSection(section); - int ticks = WorldTickHolder.getTicks(te.getLevel()); + int ticks = WorldTickHolder.getTicks(be.getLevel()); String text = section.renderCharsIndividually() || !section.spinning[0] ? section.text : section.cyclingOptions[((ticks / 3) + i * 13) % section.cyclingOptions.length]; StringDecomposer.iterateFormatted(text, Style.EMPTY, renderOutput); @@ -231,14 +227,14 @@ public class FlapDisplayRenderer extends KineticTileEntityRenderer { } @Override - protected SuperByteBuffer getRotatedModel(KineticTileEntity te, BlockState state) { - return CachedPartialBuffers.partialFacingVertical(AllBlockPartials.SHAFTLESS_COGWHEEL, state, + protected SuperByteBuffer getRotatedModel(FlapDisplayBlockEntity be, BlockState state) { + return CachedPartialBuffers.partialFacingVertical(AllPartialModels.SHAFTLESS_COGWHEEL, state, state.getValue(FlapDisplayBlock.HORIZONTAL_FACING)); } @Override - public boolean shouldRenderOffScreen(KineticTileEntity pBlockEntity) { - return ((FlapDisplayTileEntity) pBlockEntity).isController; + public boolean shouldRenderOffScreen(FlapDisplayBlockEntity be) { + return be.isController; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplaySection.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java rename to src/main/java/com/simibubi/create/content/trains/display/FlapDisplaySection.java index 0405294ebc..cfb6e2095f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplaySection.java +++ b/src/main/java/com/simibubi/create/content/trains/display/FlapDisplaySection.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.trains.management.display; +package com.simibubi.create.content.trains.display; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Random; import com.google.common.base.Strings; -import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.NBTHelper; @@ -16,6 +16,7 @@ import net.minecraft.util.Mth; public class FlapDisplaySection { static final Map LOADED_FLAP_CYCLES = new HashMap<>(); + static Random r = new Random(); public static final float MONOSPACE = 7; public static final float WIDE_MONOSPACE = 9; @@ -83,7 +84,7 @@ public class FlapDisplaySection { spinningTicks = 0; } - public int tick() { + public int tick(boolean instant) { if (cyclingOptions == null) return 0; int max = Math.max(4, (int) (cyclingOptions.length * 1.75f)); @@ -97,13 +98,13 @@ public class FlapDisplaySection { int spinningFlaps = 0; for (int i = 0; i < spinning.length; i++) { int increasingChance = Mth.clamp(8 - spinningTicks, 1, 10); - boolean continueSpin = Create.RANDOM.nextInt(increasingChance * max / 4) != 0; + boolean continueSpin = !instant && r.nextInt(increasingChance * max / 4) != 0; continueSpin &= max > 5 || spinningTicks < 2; spinning[i] &= continueSpin; - if (i > 0 && Create.RANDOM.nextInt(3) > 0) + if (i > 0 && r.nextInt(3) > 0) spinning[i - 1] &= continueSpin; - if (i < spinning.length - 1 && Create.RANDOM.nextInt(3) > 0) + if (i < spinning.length - 1 && r.nextInt(3) > 0) spinning[i + 1] &= continueSpin; if (spinningTicks > max) spinning[i] = false; @@ -169,6 +170,10 @@ public class FlapDisplaySection { return !singleFlap; } + public Component getText() { + return component; + } + public static String[] getFlapCycle(String key) { return LOADED_FLAP_CYCLES.computeIfAbsent(key, k -> CreateLang.translateDirect("flap_display.cycles." + key) .getString() diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java b/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java rename to src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java index 605d6c03f7..dd8c622c07 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/GlobalTrainDisplayData.java +++ b/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.display; +package com.simibubi.create.content.trains.display; import java.util.ArrayList; import java.util.Collection; @@ -7,7 +7,7 @@ import java.util.List; import java.util.Map; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import net.minecraft.network.chat.MutableComponent; @@ -30,10 +30,11 @@ public class GlobalTrainDisplayData { } public static List prepare(String filter, int maxLines) { + String regex = filter.isBlank() ? filter : "\\Q" + filter.replace("*", "\\E.*\\Q") + "\\E"; return statusByDestination.entrySet() .stream() .filter(e -> e.getKey() - .matches(filter.replace("*", ".*"))) + .matches(regex)) .flatMap(e -> e.getValue() .stream()) .sorted() diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/ArrivalSoundQueue.java b/src/main/java/com/simibubi/create/content/trains/entity/ArrivalSoundQueue.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/ArrivalSoundQueue.java rename to src/main/java/com/simibubi/create/content/trains/entity/ArrivalSoundQueue.java index b8da7d418e..701dcfc772 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/ArrivalSoundQueue.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/ArrivalSoundQueue.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.HashMap; @@ -9,9 +9,9 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.Pair; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/trains/entity/Carriage.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java rename to src/main/java/com/simibubi/create/content/trains/entity/Carriage.java index e4143f889b..68bab3cffb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/Carriage.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.lang.ref.WeakReference; import java.util.HashMap; @@ -18,13 +18,13 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableDouble; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.minecart.TrainCargoManager; +import com.simibubi.create.content.trains.entity.TravellingPoint.IEdgePointListener; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; import com.simibubi.create.foundation.advancement.AllAdvancements; import net.createmod.catnip.utility.Couple; @@ -35,6 +35,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; @@ -84,6 +85,11 @@ public class Carriage { bogey2.carriage = this; } + public boolean isOnIncompatibleTrack() { + return leadingBogey().type.isOnIncompatibleTrack(this, true) + || trailingBogey().type.isOnIncompatibleTrack(this, false); + } + public void setTrain(Train train) { this.train = train; } @@ -102,7 +108,7 @@ public class Carriage { DimensionalCarriageEntity dimensional = getDimensional(level); dimensional.alignEntity(entity); - dimensional.removeAndSaveEntity(entity, false); + dimensional.removeAndSaveEntity(entity, true); } public DimensionalCarriageEntity getDimensional(Level level) { @@ -249,8 +255,11 @@ public class Carriage { boolean discard = !currentlyTraversedDimensions.isEmpty() && !currentlyTraversedDimensions.contains(entry.getKey()); - ServerLevel currentLevel = level.getServer() - .getLevel(entry.getKey()); + + MinecraftServer server = level.getServer(); + if (server == null) + continue; + ServerLevel currentLevel = server.getLevel(entry.getKey()); if (currentLevel == null) continue; @@ -302,6 +311,9 @@ public class Carriage { double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing(); double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing(); + boolean leadingUpsideDown = leadingBogey.isUpsideDown(); + boolean trailingUpsideDown = trailingBogey.isUpsideDown(); + for (boolean leading : Iterate.trueAndFalse) { TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint(); @@ -317,24 +329,31 @@ public class Carriage { dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2); + leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown); + + boolean backAnchorFlip = trailingBogey.isUpsideDown() ^ leadingBogey.isUpsideDown(); if (isOnTwoBogeys()) { dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2)); - dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() + leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); + dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip) : pivoted(dce, dimension, point, - leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); + leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2, + leadingUpsideDown, trailingUpsideDown)); } else { if (dimension.equals(otherDimension)) { - dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); + dce.rotationAnchors = leadingBogey.points.map(tp -> tp.getPosition(train.graph)); } else { - dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); - dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() - : pivoted(dce, dimension, point, leadingWheelSpacing)); + dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point + ? point.getPosition(train.graph) + : pivoted(dce, dimension, point, leadingWheelSpacing, leadingUpsideDown, trailingUpsideDown)); + dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point + ? point.getPosition(train.graph) + : pivoted(dce, dimension, point, leadingWheelSpacing, leadingUpsideDown, trailingUpsideDown)); } } @@ -352,15 +371,16 @@ public class Carriage { } private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey dimension, TravellingPoint start, - double offset) { + double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) { if (train.graph == null) return dce.pivot == null ? null : dce.pivot.getLocation(); TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint()); if (pivot == null) return null; - Vec3 startVec = start.getPosition(); + boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown); + Vec3 startVec = start.getPosition(train.graph, flipped); Vec3 portalVec = pivot.getLocation() - .add(0, 1, 0); + .add(0, leadingUpsideDown ? -1.0 : 1.0, 0); return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec); } @@ -719,8 +739,8 @@ public class Carriage { } - private void dismountPlayer(ServerLevel sLevel, ServerPlayer sp, Integer seat, boolean portal) { - if (!portal) { + private void dismountPlayer(ServerLevel sLevel, ServerPlayer sp, Integer seat, boolean capture) { + if (!capture) { sp.stopRiding(); return; } @@ -848,7 +868,7 @@ public class Carriage { train.carriageWaitingForChunks = id; return; } - + if (entity.getPassengers() .stream() .anyMatch(p -> p instanceof Player) diff --git a/src/main/java/com/simibubi/create/content/trains/entity/CarriageBogey.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageBogey.java new file mode 100644 index 0000000000..d2d6d273a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageBogey.java @@ -0,0 +1,227 @@ +package com.simibubi.create.content.trains.entity; + +import static com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity.BOGEY_DATA_KEY; +import static com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity.BOGEY_STYLE_KEY; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.simibubi.create.AllBogeyStyles; +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity; +import com.simibubi.create.content.trains.bogey.BogeyInstance; +import com.simibubi.create.content.trains.bogey.BogeyStyle; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.TrackGraph; + +import net.createmod.catnip.platform.CatnipServices; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.registries.ForgeRegistries; + +public class CarriageBogey { + + public static final String UPSIDE_DOWN_KEY = "UpsideDown"; + + public Carriage carriage; + boolean isLeading; + + public CompoundTag bogeyData; + + AbstractBogeyBlock type; + boolean upsideDown; + Couple points; + + LerpedFloat wheelAngle; + LerpedFloat yaw; + LerpedFloat pitch; + + public Couple couplingAnchors; + + int derailAngle; + + public CarriageBogey(AbstractBogeyBlock type, boolean upsideDown, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) { + this.type = type; + this.upsideDown = type.canBeUpsideDown() && upsideDown; + point.upsideDown = this.upsideDown; + point2.upsideDown = this.upsideDown; + if (bogeyData == null || bogeyData.isEmpty()) + bogeyData = this.createBogeyData(); // Prevent Crash When Updating + bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + this.bogeyData = bogeyData; + points = Couple.create(point, point2); + wheelAngle = LerpedFloat.angular(); + yaw = LerpedFloat.angular(); + pitch = LerpedFloat.angular(); + derailAngle = Create.RANDOM.nextInt(60) - 30; + couplingAnchors = Couple.create(null, null); + } + + public ResourceKey getDimension() { + TravellingPoint leading = leading(); + TravellingPoint trailing = trailing(); + if (leading.edge == null || trailing.edge == null) + return null; + if (leading.edge.isInterDimensional() || trailing.edge.isInterDimensional()) + return null; + ResourceKey dimension1 = leading.node1.getLocation().dimension; + ResourceKey dimension2 = trailing.node1.getLocation().dimension; + if (dimension1.equals(dimension2)) + return dimension1; + return null; + } + + public void updateAngles(CarriageContraptionEntity entity, double distanceMoved) { + double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius()); + + float xRot = 0; + float yRot = 0; + + if (leading().edge == null || carriage.train.derailed) { + yRot = -90 + entity.yaw - derailAngle; + } else if (!entity.level.dimension() + .equals(getDimension())) { + yRot = -90 + entity.yaw; + xRot = 0; + } else { + Vec3 positionVec = leading().getPosition(carriage.train.graph); + Vec3 coupledVec = trailing().getPosition(carriage.train.graph); + double diffX = positionVec.x - coupledVec.x; + double diffY = positionVec.y - coupledVec.y; + double diffZ = positionVec.z - coupledVec.z; + yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90; + xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ))); + } + + double newWheelAngle = (wheelAngle.getValue() - angleDiff) % 360; + + for (boolean twice : Iterate.trueAndFalse) { + if (twice && !entity.firstPositionUpdate) + continue; + wheelAngle.setValue(newWheelAngle); + pitch.setValue(xRot); + yaw.setValue(-yRot); + } + } + + public TravellingPoint leading() { + TravellingPoint point = points.getFirst(); + point.upsideDown = isUpsideDown(); + return point; + } + + public TravellingPoint trailing() { + TravellingPoint point = points.getSecond(); + point.upsideDown = isUpsideDown(); + return point; + } + + public double getStress() { + if (getDimension() == null) + return 0; + if (carriage.train.derailed) + return 0; + return type.getWheelPointSpacing() - leading().getPosition(carriage.train.graph) + .distanceTo(trailing().getPosition(carriage.train.graph)); + } + + @Nullable + public Vec3 getAnchorPosition() { + return getAnchorPosition(false); + } + + @Nullable + public Vec3 getAnchorPosition(boolean flipUpsideDown) { + if (leading().edge == null) + return null; + return points.getFirst() + .getPosition(carriage.train.graph, flipUpsideDown) + .add(points.getSecond() + .getPosition(carriage.train.graph, flipUpsideDown)) + .scale(.5); + } + + public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, + float partialTicks, boolean leading) { + boolean selfUpsideDown = isUpsideDown(); + boolean leadingUpsideDown = carriage.leadingBogey().isUpsideDown(); + Vec3 thisOffset = type.getConnectorAnchorOffset(selfUpsideDown); + thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1); + + thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X); + thisOffset = VecHelper.rotate(thisOffset, yaw.getValue(partialTicks), Axis.Y); + thisOffset = VecHelper.rotate(thisOffset, -entityYRot - 90, Axis.Y); + thisOffset = VecHelper.rotate(thisOffset, entityXRot, Axis.X); + thisOffset = VecHelper.rotate(thisOffset, -180, Axis.Y); + thisOffset = thisOffset.add(0, 0, leading ? 0 : -bogeySpacing); + thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y); + thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X); + thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y); + if (selfUpsideDown != leadingUpsideDown) + thisOffset = thisOffset.add(0, selfUpsideDown ? -2 : 2, 0); + + couplingAnchors.set(leading, entityPos.add(thisOffset)); + } + + public CompoundTag write(DimensionPalette dimensions) { + CompoundTag tag = new CompoundTag(); + tag.putString("Type", CatnipServices.REGISTRIES.getKeyOrThrow((Block) type) + .toString()); + tag.put("Points", points.serializeEach(tp -> tp.write(dimensions))); + tag.putBoolean("UpsideDown", upsideDown); + bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown); + NBTHelper.writeResourceLocation(bogeyData, BOGEY_STYLE_KEY, getStyle().name); + tag.put(BOGEY_DATA_KEY, bogeyData); + return tag; + } + + public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { + ResourceLocation location = new ResourceLocation(tag.getString("Type")); + AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); + boolean upsideDown = tag.getBoolean("UpsideDown"); + Couple points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), + c -> TravellingPoint.read(c, graph, dimensions)); + CompoundTag data = tag.getCompound(AbstractBogeyBlockEntity.BOGEY_DATA_KEY); + return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond()); + } + + public BogeyInstance createInstance(MaterialManager materialManager) { + return this.getStyle().createInstance(this, type.getSize(), materialManager); + } + + public BogeyStyle getStyle() { + ResourceLocation location = NBTHelper.readResourceLocation(this.bogeyData, BOGEY_STYLE_KEY); + BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(location); + return style != null ? style : AllBogeyStyles.STANDARD; // just for safety + } + + private CompoundTag createBogeyData() { + BogeyStyle style = type != null ? type.getDefaultStyle() : AllBogeyStyles.STANDARD; + CompoundTag nbt = style.defaultData != null ? style.defaultData : new CompoundTag(); + NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, style.name); + nbt.putBoolean(UPSIDE_DOWN_KEY, isUpsideDown()); + return nbt; + } + + void setLeading() { + isLeading = true; + } + + public boolean isUpsideDown() { + return type.canBeUpsideDown() && upsideDown; + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java index c0ea4b2721..52965bd3cc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraption.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.Collection; @@ -11,18 +11,18 @@ import java.util.Optional; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; -import com.simibubi.create.content.contraptions.components.structureMovement.MountedStorageManager; -import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter; -import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.contraptions.ContraptionType; +import com.simibubi.create.content.contraptions.MountedStorageManager; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.content.contraptions.minecart.TrainCargoManager; +import com.simibubi.create.content.contraptions.render.ContraptionLighter; +import com.simibubi.create.content.contraptions.render.NonStationaryLighter; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Couple; @@ -126,7 +126,7 @@ public class CarriageContraption extends Contraption { if (!blocks.containsKey(controlsPos)) return false; StructureBlockInfo info = blocks.get(controlsPos); - if (!AllBlocks.CONTROLS.has(info.state)) + if (!AllBlocks.TRAIN_CONTROLS.has(info.state)) return false; return info.state.getValue(ControlsBlock.FACING) == direction.getOpposite(); } @@ -162,18 +162,20 @@ public class CarriageContraption extends Contraption { .getStep(), toLocalPos(pos)); } - if (blockState.getBlock() instanceof IBogeyBlock) { + if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) { + boolean captureBE = bogey.captureBlockEntityForTrain(); bogeys++; if (bogeys == 2) secondBogeyPos = pos; - return Pair.of(new StructureBlockInfo(pos, blockState, null), null); + return Pair.of(new StructureBlockInfo(pos, blockState, captureBE ? getBlockEntityNBT(world, pos) : null), + captureBE ? world.getBlockEntity(pos) : null); } if (AllBlocks.BLAZE_BURNER.has(blockState) && blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != HeatLevel.NONE) assembledBlazeBurners.add(toLocalPos(pos)); - if (AllBlocks.CONTROLS.has(blockState)) { + if (AllBlocks.TRAIN_CONTROLS.has(blockState)) { Direction facing = blockState.getValue(ControlsBlock.FACING); if (facing.getAxis() != assemblyDirection.getAxis()) sidewaysControls = true; @@ -237,7 +239,7 @@ public class CarriageContraption extends Contraption { } @Override - protected ContraptionType getType() { + public ContraptionType getType() { return ContraptionType.CARRIAGE; } @@ -263,17 +265,17 @@ public class CarriageContraption extends Contraption { return secondBogeyPos; } - private Collection specialRenderedTEsOutsidePortal = new ArrayList<>(); + private Collection specialRenderedBEsOutsidePortal = new ArrayList<>(); @Override public Collection getRenderedBlocks() { if (notInPortal()) return super.getRenderedBlocks(); - specialRenderedTEsOutsidePortal = new ArrayList<>(); - specialRenderedTileEntities.stream() - .filter(te -> !isHiddenInPortal(te.getBlockPos())) - .forEach(specialRenderedTEsOutsidePortal::add); + specialRenderedBEsOutsidePortal = new ArrayList<>(); + specialRenderedBlockEntities.stream() + .filter(be -> !isHiddenInPortal(be.getBlockPos())) + .forEach(specialRenderedBEsOutsidePortal::add); Collection values = new ArrayList<>(); for (Entry entry : blocks.entrySet()) { @@ -290,7 +292,7 @@ public class CarriageContraption extends Contraption { public Collection getSpecialRenderedTEs() { if (notInPortal()) return super.getSpecialRenderedTEs(); - return specialRenderedTEsOutsidePortal; + return specialRenderedBEsOutsidePortal; } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntity.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntity.java index f5312a1b7c..8475ff3257 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.lang.ref.WeakReference; import java.util.Collection; @@ -11,22 +11,22 @@ import java.util.UUID; import com.google.common.base.Strings; import com.simibubi.create.AllEntityDataSerializers; import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionBlockChangedPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; -import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUDUpdatePacket; -import com.simibubi.create.content.contraptions.particle.CubeParticleData; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.contraptions.ContraptionBlockChangedPacket; +import com.simibubi.create.content.contraptions.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import com.simibubi.create.content.trains.CubeParticleData; +import com.simibubi.create.content.trains.TrainHUDUpdatePacket; +import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.station.GlobalStation; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.VecHelper; @@ -199,7 +199,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { carriage.forEachPresentEntity(cce -> { cce.contraption.getBlocks() .put(localPos, newInfo); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> cce), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> cce), new ContraptionBlockChangedPacket(cce.getId(), localPos, newInfo.state)); }); } @@ -387,7 +387,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { } @Override - protected void handleStallInformation(float x, float y, float z, float angle) {} + protected void handleStallInformation(double x, double y, double z, float angle) {} Vec3 derailParticleOffset = VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, 1.5f) .multiply(1, .25f, 1); @@ -562,7 +562,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { .equals(initialOrientation); if (hudPacketCooldown-- <= 0 && player instanceof ServerPlayer sp) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> sp), new TrainHUDUpdatePacket(carriage.train)); + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> sp), new TrainHUDUpdatePacket(carriage.train)); hudPacketCooldown = 5; } @@ -653,7 +653,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { carriage.train.manualSteer = targetSteer < 0 ? SteerDirection.RIGHT : targetSteer > 0 ? SteerDirection.LEFT : SteerDirection.NONE; - double topSpeed = carriage.train.maxSpeed() * AllConfigs.SERVER.trains.manualTrainSpeedModifier.getF(); + double topSpeed = carriage.train.maxSpeed() * AllConfigs.server().trains.manualTrainSpeedModifier.getF(); double cappedTopSpeed = topSpeed * carriage.train.throttle; if (carriage.getLeadingPoint().edge != null && carriage.getLeadingPoint().edge.isTurn() @@ -676,7 +676,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { private void sendPrompt(Player player, MutableComponent component, boolean shadow) { if (player instanceof ServerPlayer sp) - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> sp), new TrainPromptPacket(component, shadow)); + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> sp), new TrainPromptPacket(component, shadow)); } boolean stationMessage = false; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntityRenderer.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntityRenderer.java index 5de635e4ae..30e3f0a488 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionEntityRenderer.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.Objects; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.render.ContraptionEntityRenderer; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; @@ -37,7 +37,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer MultiBufferSource buffers, int overlay) { if (!entity.validForRender || entity.firstPositionUpdate) return; - + super.render(entity, yaw, partialTicks, ms, buffers, overlay); Carriage carriage = entity.getCarriage(); @@ -65,8 +65,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks); int light = getBogeyLightCoords(entity, bogey, partialTicks); + bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, - overlay); + overlay, bogey.getStyle(), bogey.bogeyData); ms.popPose(); } @@ -80,6 +81,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, float viewXRot, float partialTicks) { + boolean selfUpsideDown = bogey.isUpsideDown(); + boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown(); TransformStack.cast(ms) .rotateY(viewYRot + 90) .rotateX(-viewXRot) @@ -90,7 +93,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer .rotateY(-viewYRot - 90) .rotateY(bogey.yaw.getValue(partialTicks)) .rotateX(bogey.pitch.getValue(partialTicks)) - .translate(0, .5f, 0); + .translate(0, .5f, 0) + .rotateZ(selfUpsideDown ? 180 : 0) + .translateY(selfUpsideDown != leadingUpsideDown ? 2 : 0); } public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionInstance.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionInstance.java index f6252724f5..10528ace93 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionInstance.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageContraptionInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.instance.DynamicInstance; @@ -7,6 +7,8 @@ import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; +import com.simibubi.create.content.trains.bogey.BogeyInstance; +import com.simibubi.create.content.trains.bogey.BogeyRenderer; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -32,7 +34,8 @@ public class CarriageContraptionInstance extends EntityInstance + bogey.getStyle().createInstance(bogey, bogey.type.getSize(), manager), materialManager); updateLight(); } @@ -65,7 +68,7 @@ public class CarriageContraptionInstance extends EntityInstance { - if (instance != null) - instance.remove(); + if (instance != null) { + instance.commonRenderer.ifPresent(BogeyRenderer::remove); + instance.renderer.remove(); + } }); } diff --git a/src/main/java/com/simibubi/create/content/trains/entity/CarriageCouplingRenderer.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageCouplingRenderer.java new file mode 100644 index 0000000000..3ff1f022b1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageCouplingRenderer.java @@ -0,0 +1,131 @@ +package com.simibubi.create.content.trains.entity; + +import java.util.Collection; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class CarriageCouplingRenderer { + + public static void renderAll(PoseStack ms, MultiBufferSource buffer, Vec3 camera) { + Collection trains = CreateClient.RAILWAYS.trains.values(); + VertexConsumer vb = buffer.getBuffer(RenderType.solid()); + BlockState air = Blocks.AIR.defaultBlockState(); + float partialTicks = AnimationTickHolder.getPartialTicks(); + Level level = Minecraft.getInstance().level; + + for (Train train : trains) { + List carriages = train.carriages; + for (int i = 0; i < carriages.size() - 1; i++) { + Carriage carriage = carriages.get(i); + CarriageContraptionEntity entity = carriage.getDimensional(level).entity.get(); + Carriage carriage2 = carriages.get(i + 1); + CarriageContraptionEntity entity2 = carriage.getDimensional(level).entity.get(); + + if (entity == null || entity2 == null) + continue; + + CarriageBogey bogey1 = carriage.trailingBogey(); + CarriageBogey bogey2 = carriage2.leadingBogey(); + Vec3 anchor = bogey1.couplingAnchors.getSecond(); + Vec3 anchor2 = bogey2.couplingAnchors.getFirst(); + + if (anchor == null || anchor2 == null) + continue; + if (!anchor.closerThan(camera, 64)) + continue; + + int lightCoords = getPackedLightCoords(entity, partialTicks); + int lightCoords2 = getPackedLightCoords(entity2, partialTicks); + + double diffX = anchor2.x - anchor.x; + double diffY = anchor2.y - anchor.y; + double diffZ = anchor2.z - anchor.z; + float yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90; + float xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ))); + + Vec3 position = entity.getPosition(partialTicks); + Vec3 position2 = entity2.getPosition(partialTicks); + + ms.pushPose(); + + { + ms.pushPose(); + ms.translate(anchor.x - camera.x, anchor.y - camera.y, anchor.z - camera.z); + CachedPartialBuffers.partial(AllPartialModels.TRAIN_COUPLING_HEAD, air) + .rotateY(-yRot) + .rotateX(xRot) + .light(lightCoords) + .renderInto(ms, vb); + + float margin = 3 / 16f; + double couplingDistance = train.carriageSpacing.get(i) - 2 * margin + - bogey1.type.getConnectorAnchorOffset(bogey1.isUpsideDown()).z - bogey2.type.getConnectorAnchorOffset(bogey2.isUpsideDown()).z; + int couplingSegments = (int) Math.round(couplingDistance * 4); + double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; + for (int j = 0; j < couplingSegments; j++) { + CachedPartialBuffers.partial(AllPartialModels.TRAIN_COUPLING_CABLE, air) + .rotateY(-yRot + 180) + .rotateX(-xRot) + .translate(0, 0, margin + 2 / 16f) + .scale(1, 1, (float) stretch) + .translate(0, 0, j / 4f) + .light(lightCoords) + .renderInto(ms, vb); + } + ms.popPose(); + } + + { + ms.pushPose(); + Vec3 translation = position2.subtract(position) + .add(anchor2) + .subtract(camera); + ms.translate(translation.x, translation.y, translation.z); + CachedPartialBuffers.partial(AllPartialModels.TRAIN_COUPLING_HEAD, air) + .rotateY(-yRot + 180) + .rotateX(-xRot) + .light(lightCoords2) + .renderInto(ms, vb); + ms.popPose(); + } + + ms.popPose(); + } + } + + } + + public static int getPackedLightCoords(Entity pEntity, float pPartialTicks) { + BlockPos blockpos = new BlockPos(pEntity.getLightProbePosition(pPartialTicks)); + return LightTexture.pack(getBlockLightLevel(pEntity, blockpos), getSkyLightLevel(pEntity, blockpos)); + } + + protected static int getSkyLightLevel(Entity pEntity, BlockPos pPos) { + return pEntity.level.getBrightness(LightLayer.SKY, pPos); + } + + protected static int getBlockLightLevel(Entity pEntity, BlockPos pPos) { + return pEntity.isOnFire() ? 15 : pEntity.level.getBrightness(LightLayer.BLOCK, pPos); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageEntityHandler.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageEntityHandler.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageEntityHandler.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageEntityHandler.java index 3cc309af58..1d1baa1a6a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageEntityHandler.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageEntityHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageParticles.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageParticles.java index d7ec1b9b82..6b842db001 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageParticles.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageParticles.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.Random; -import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; @@ -10,7 +10,6 @@ import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction.Axis; -import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -110,7 +109,7 @@ public class CarriageParticles { m = m.add(contraptionMotion.scale(.75f)); - level.addParticle(spark ? ParticleTypes.CRIT : ParticleTypes.POOF, v.x, v.y, v.z, m.x, m.y, m.z); + level.addParticle(spark ? bogey.getStyle().contactParticle : bogey.getStyle().smokeParticle, v.x, v.y, v.z, m.x, m.y, m.z); } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSounds.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageSounds.java index fe1a1e1e68..6efcf1b8f4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSounds.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSounds.java @@ -1,9 +1,10 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents.SoundEntry; -import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; +import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; import net.minecraft.client.Minecraft; @@ -29,6 +30,9 @@ public class CarriageSounds { LoopingSound sharedWheelSoundSeated; LoopingSound sharedHonkSound; + Couple bogeySounds; + SoundEvent closestBogeySound; + boolean arrived; int tick; @@ -36,6 +40,10 @@ public class CarriageSounds { public CarriageSounds(CarriageContraptionEntity entity) { this.entity = entity; + bogeySounds = entity.getCarriage().bogeys.map(bogey -> + bogey != null && bogey.getStyle() != null ? bogey.getStyle().getSoundType() + : AllSoundEvents.TRAIN2.getMainEvent()); + closestBogeySound = bogeySounds.getFirst(); distanceFactor = LerpedFloat.linear(); speedFactor = LerpedFloat.linear(); approachFactor = LerpedFloat.linear(); @@ -79,6 +87,15 @@ public class CarriageSounds { double distance1 = toBogey1.length(); double distance2 = toBogey2.length(); + Couple bogeys = entity.getCarriage().bogeys; + CarriageBogey relevantBogey = bogeys.get(distance1 > distance2); + if (relevantBogey == null) { + relevantBogey = bogeys.getFirst(); + } + if (relevantBogey != null) { + closestBogeySound = relevantBogey.getStyle().getSoundType(); + } + Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1; double distance = Math.min(distance1, distance2); Vec3 soundLocation = cam.add(toCarriage); @@ -97,7 +114,7 @@ public class CarriageSounds { seatCrossfade.tickChaser(); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); - sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); + sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); float volume = Math.min(Math.min(speedFactor.getValue(), distanceFactor.getValue() / 100), @@ -205,7 +222,7 @@ public class CarriageSounds { public void submitSharedSoundVolume(Vec3 location, float volume) { Minecraft mc = Minecraft.getInstance(); minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent()); - sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent()); + sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound); sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent()); boolean approach = true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncData.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncData.java index 6ac5b517a5..96eb18ddb4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.HashSet; @@ -13,11 +13,11 @@ import java.util.Vector; import org.apache.commons.lang3.mutable.MutableBoolean; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackNode; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import net.createmod.catnip.utility.Couple; @@ -117,9 +117,7 @@ public class CarriageSyncData { TrackGraph graph = carriage.train.graph; if (graph == null) { - fallbackLocations = Pair.of(dce.positionAnchor, dce.rotationAnchors); - dce.pointsInitialised = true; - setDirty(true); + updateFallbackLocations(dce); return; } @@ -129,13 +127,19 @@ public class CarriageSyncData { for (boolean first : Iterate.trueAndFalse) { if (!first && !carriage.isOnTwoBogeys()) break; + CarriageBogey bogey = carriage.bogeys.get(first); for (boolean firstPoint : Iterate.trueAndFalse) { TravellingPoint point = bogey.points.get(firstPoint); int index = (first ? 0 : 2) + (firstPoint ? 0 : 1); - Pair, Float> pair = - Pair.of(Couple.create(point.node1.getNetId(), point.node2.getNetId()), (float) point.position); - wheelLocations.set(index, pair); + Couple nodes = Couple.create(point.node1, point.node2); + + if (nodes.either(Objects::isNull)) { + updateFallbackLocations(dce); + return; + } + + wheelLocations.set(index, Pair.of(nodes.map(TrackNode::getNetId), (float) point.position)); } } @@ -143,6 +147,12 @@ public class CarriageSyncData { setDirty(true); } + private void updateFallbackLocations(DimensionalCarriageEntity dce) { + fallbackLocations = Pair.of(dce.positionAnchor, dce.rotationAnchors); + dce.pointsInitialised = true; + setDirty(true); + } + public void apply(CarriageContraptionEntity entity, Carriage carriage) { DimensionalCarriageEntity dce = carriage.getDimensional(entity.level); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncDataSerializer.java b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncDataSerializer.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncDataSerializer.java rename to src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncDataSerializer.java index 762998b353..723685f750 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncDataSerializer.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/CarriageSyncDataSerializer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.syncher.EntityDataSerializer; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/trains/entity/Navigation.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java rename to src/main/java/com/simibubi/create/content/trains/entity/Navigation.java index b795bf8319..4f0cf1cb5e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/Navigation.java @@ -1,9 +1,10 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -18,19 +19,21 @@ import org.apache.commons.lang3.mutable.MutableDouble; import org.apache.commons.lang3.mutable.MutableObject; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.signal.SignalBlock.SignalType; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.TrackMaterial; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -200,6 +203,20 @@ public class Navigation { return false; }, (distance, edge) -> { + BezierConnection turn = edge.getTurn(); + double vDistance = Math.abs(turn.starts.getFirst().y - turn.starts.getSecond().y); + + // ignore turn if its a straight & mild slope + if (turn != null && vDistance > 1 / 16f) { + if (turn.axes.getFirst() + .multiply(1, 0, 1) + .distanceTo(turn.axes.getSecond() + .multiply(1, 0, 1) + .scale(-1)) < 1 / 64f + && vDistance / turn.getLength() < .225f) + return; + } + float current = curveDistanceTracker.floatValue(); if (current == -1 || distance < current) curveDistanceTracker.setValue(distance); @@ -540,6 +557,21 @@ public class Navigation { if (graph == null) return; + // Cache the list of track types that the train can travel on + Set validTypes = new HashSet<>(); + for (int i = 0; i < train.carriages.size(); i++) { + Carriage carriage = train.carriages.get(i); + if (i == 0) { + validTypes.addAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle())); + } else { + validTypes.retainAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle())); + } + if (carriage.isOnTwoBogeys()) + validTypes.retainAll(carriage.trailingBogey().type.getValidPathfindingTypes(carriage.trailingBogey().getStyle())); + } + if (validTypes.isEmpty()) // if there are no valid track types, a route can't be found + return; + Map penalties = new IdentityHashMap<>(); boolean costRelevant = maxCost >= 0; if (costRelevant) { @@ -577,6 +609,9 @@ public class Navigation { TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1; TrackEdge initialEdge = graph.getConnectionsFrom(initialNode1) .get(initialNode2); + if (initialEdge == null) + return; + double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position; frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge)); @@ -656,6 +691,8 @@ public class Navigation { continue; for (Entry target : validTargets) { + if (!validTypes.contains(target.getValue().getTrackMaterial().trackType)) + continue; TrackNode newNode = target.getKey(); TrackEdge newEdge = target.getValue(); double newDistance = newEdge.getLength() + distance; @@ -699,6 +736,9 @@ public class Navigation { CompoundTag tag = new CompoundTag(); if (destination == null) return tag; + + removeBrokenPathEntries(); + tag.putUUID("Destination", destination.id); tag.putDouble("DistanceToDestination", distanceToDestination); tag.putDouble("DistanceStartedAt", distanceStartedAt); @@ -736,6 +776,9 @@ public class Navigation { c -> currentPath.add(Couple .deserializeEach(c.getList("Nodes", Tag.TAG_COMPOUND), c2 -> TrackNodeLocation.read(c2, dimensions)) .map(graph::locateNode))); + + removeBrokenPathEntries(); + waitingForSignal = tag.contains("BlockingSignal") ? Pair.of(tag.getUUID("BlockingSignal"), tag.getBoolean("BlockingSignalSide")) : null; @@ -745,4 +788,25 @@ public class Navigation { ticksWaitingForSignal = tag.getInt("TicksWaitingForSignal"); } + private void removeBrokenPathEntries() { + /* + * Trains might load or save with null entries in their path, this method avoids + * that anomaly from causing NPEs. The underlying issue has not been found. + */ + + boolean nullEntriesPresent = false; + + for (Iterator> iterator = currentPath.iterator(); iterator.hasNext();) { + Couple couple = iterator.next(); + if (couple == null || couple.getFirst() == null || couple.getSecond() == null) { + iterator.remove(); + nullEntriesPresent = true; + } + } + + if (nullEntriesPresent) + Create.LOGGER.error("Found null values in path of train with name: " + train.name.getString() + ", id: " + + train.id.toString()); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/trains/entity/Train.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java rename to src/main/java/com/simibubi/create/content/trains/entity/Train.java index 6d84a33ffc..0ca1aee80b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/Train.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.Collection; @@ -21,31 +21,32 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.observer.TrackObserver; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime; -import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime.State; +import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity; +import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity; +import com.simibubi.create.content.trains.entity.TravellingPoint.IEdgePointListener; +import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.observer.TrackObserver; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime; +import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State; +import com.simibubi.create.content.trains.signal.SignalBlock.SignalType; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.content.trains.station.StationBlockEntity; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -66,6 +67,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Explosion.BlockInteraction; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fluids.FluidStack; @@ -86,6 +88,7 @@ public class Train { public boolean honk = false; public UUID id; + @Nullable public UUID owner; public TrackGraph graph; public Navigation navigation; @@ -277,7 +280,7 @@ public class Train { int carriageCount = carriages.size(); boolean stalled = false; double maxStress = 0; - + if (carriageWaitingForChunks != -1) distance = 0; @@ -313,7 +316,13 @@ public class Train { if (leadingAnchor == null || trailingAnchor == null) continue; - total += leadingAnchor.distanceTo(trailingAnchor); + double distanceTo = leadingAnchor.distanceToSqr(trailingAnchor); + if (carriage.leadingBogey().isUpsideDown() != previousCarriage.trailingBogey().isUpsideDown()) { + distanceTo = Math.sqrt(distanceTo - 4); + } else { + distanceTo = Math.sqrt(distanceTo); + } + total += distanceTo; entries++; } } @@ -375,7 +384,7 @@ public class Train { int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; double actualDistance = carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType); - blocked |= carriage.blocked; + blocked |= carriage.blocked || carriage.isOnIncompatibleTrack(); boolean onTwoBogeys = carriage.isOnTwoBogeys(); maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0); @@ -589,8 +598,8 @@ public class Train { if (!dimension.equals(trailingPoint.node1.getLocation().dimension)) return; - Vec3 start = (speed < 0 ? trailingPoint : leadingPoint).getPosition(); - Vec3 end = (speed < 0 ? leadingPoint : trailingPoint).getPosition(); + Vec3 start = (speed < 0 ? trailingPoint : leadingPoint).getPosition(graph); + Vec3 end = (speed < 0 ? leadingPoint : trailingPoint).getPosition(graph); Pair collision = findCollidingTrain(level, start, end, this, dimension); if (collision == null) @@ -632,8 +641,8 @@ public class Train { if (!otherDimension.equals(dimension)) continue; - Vec3 start2 = otherLeading.getPosition(); - Vec3 end2 = otherTrailing.getPosition(); + Vec3 start2 = otherLeading.getPosition(train.graph); + Vec3 end2 = otherTrailing.getPosition(train.graph); if (betweenBits) { end2 = start2; start2 = lastPoint; @@ -722,9 +731,20 @@ public class Train { if (entity.getContraption()instanceof CarriageContraption cc) cc.returnStorageForDisassembly(carriage.storage); entity.setPos(Vec3 - .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); + .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset).below(carriage.leadingBogey().isUpsideDown() ? 2 : 0))); entity.disassemble(); + for (CarriageBogey bogey : carriage.bogeys) { + if (bogey == null) + continue; + Vec3 bogeyPosition = bogey.getAnchorPosition(); + if (bogeyPosition == null) continue; + BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition)); + if (!(be instanceof AbstractBogeyBlockEntity sbbe)) + continue; + sbbe.setBogeyData(bogey.bogeyData); + } + offset += carriage.bogeySpacing; if (i < carriageSpacing.size()) @@ -734,13 +754,13 @@ public class Train { GlobalStation currentStation = getCurrentStation(); if (currentStation != null) { currentStation.cancelReservation(this); - BlockPos tilePos = currentStation.getTilePos(); - if (level.getBlockEntity(tilePos)instanceof StationTileEntity ste) - ste.lastDisassembledTrainName = name.copy(); + BlockPos blockEntityPos = currentStation.getBlockEntityPos(); + if (level.getBlockEntity(blockEntityPos) instanceof StationBlockEntity sbe) + sbe.lastDisassembledTrainName = name.copy(); } Create.RAILWAYS.removeTrain(id); - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false)); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false)); return true; } @@ -823,11 +843,11 @@ public class Train { } Set> entrySet = new HashSet<>(Create.RAILWAYS.trackNetworks.entrySet()); - Map> successfulMigrations = new HashMap<>(); + Map> successfulMigrations = new HashMap<>(); for (TrainMigration md : migratingPoints) { for (Iterator> iterator = entrySet.iterator(); iterator.hasNext();) { Entry entry = iterator.next(); - GraphLocation gl = md.tryMigratingTo(entry.getValue()); + TrackGraphLocation gl = md.tryMigratingTo(entry.getValue()); if (gl == null) { iterator.remove(); continue; @@ -846,7 +866,7 @@ public class Train { for (Entry entry : entrySet) { graph = entry.getValue(); - List locations = successfulMigrations.get(entry.getKey()); + List locations = successfulMigrations.get(entry.getKey()); forEachTravellingPoint(tp -> tp.migrateTo(locations)); migratingPoints.clear(); if (derailed) @@ -944,7 +964,7 @@ public class Train { occupiedObservers.clear(); cachedObserverFiltering.clear(); - TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); + TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false); Map allGroups = Create.RAILWAYS.signalEdgeGroups; MutableObject prevGroup = new MutableObject<>(null); @@ -1070,24 +1090,25 @@ public class Train { } public float maxSpeed() { - return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTopSpeed.getF() - : AllConfigs.SERVER.trains.trainTopSpeed.getF()) / 20; + return (fuelTicks > 0 ? AllConfigs.server().trains.poweredTrainTopSpeed.getF() + : AllConfigs.server().trains.trainTopSpeed.getF()) / 20; } public float maxTurnSpeed() { - return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTurningTopSpeed.getF() - : AllConfigs.SERVER.trains.trainTurningTopSpeed.getF()) / 20; + return (fuelTicks > 0 ? AllConfigs.server().trains.poweredTrainTurningTopSpeed.getF() + : AllConfigs.server().trains.trainTurningTopSpeed.getF()) / 20; } public float acceleration() { - return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainAcceleration.getF() - : AllConfigs.SERVER.trains.trainAcceleration.getF()) / 400; + return (fuelTicks > 0 ? AllConfigs.server().trains.poweredTrainAcceleration.getF() + : AllConfigs.server().trains.trainAcceleration.getF()) / 400; } public CompoundTag write(DimensionPalette dimensions) { CompoundTag tag = new CompoundTag(); tag.putUUID("Id", id); - tag.putUUID("Owner", owner); + if (owner != null) + tag.putUUID("Owner", owner); if (graph != null) tag.putUUID("Graph", graph.id); tag.put("Carriages", NBTHelper.writeCompoundList(carriages, c -> c.write(dimensions))); @@ -1133,7 +1154,7 @@ public class Train { public static Train read(CompoundTag tag, Map trackNetworks, DimensionPalette dimensions) { UUID id = tag.getUUID("Id"); - UUID owner = tag.getUUID("Owner"); + UUID owner = tag.contains("Owner") ? tag.getUUID("Owner") : null; UUID graphId = tag.contains("Graph") ? tag.getUUID("Graph") : null; TrackGraph graph = graphId == null ? null : trackNetworks.get(graphId); List carriages = new ArrayList<>(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainIconType.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainIconType.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainIconType.java rename to src/main/java/com/simibubi/create/content/trains/entity/TrainIconType.java index 3db2e38005..fa2d55bb59 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainIconType.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainIconType.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainMigration.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainMigration.java similarity index 83% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainMigration.java rename to src/main/java/com/simibubi/create/content/trains/entity/TrainMigration.java index e2069fb4c3..9e34d426d2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainMigration.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainMigration.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.Map.Entry; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.VecHelper; @@ -27,20 +27,20 @@ public class TrainMigration { public TrainMigration(TravellingPoint point) { double t = point.position / point.edge.getLength(); - fallback = point.edge.getPosition(t); + fallback = point.edge.getPosition(null, t); curve = point.edge.isTurn(); positionOnOldEdge = point.position; locations = Couple.create(point.node1.getLocation(), point.node2.getLocation()); } - public GraphLocation tryMigratingTo(TrackGraph graph) { + public TrackGraphLocation tryMigratingTo(TrackGraph graph) { TrackNode node1 = graph.locateNode(locations.getFirst()); TrackNode node2 = graph.locateNode(locations.getSecond()); if (node1 != null && node2 != null) { TrackEdge edge = graph.getConnectionsFrom(node1) .get(node2); if (edge != null) { - GraphLocation graphLocation = new GraphLocation(); + TrackGraphLocation graphLocation = new TrackGraphLocation(); graphLocation.graph = graph; graphLocation.edge = locations; graphLocation.position = positionOnOldEdge; @@ -88,7 +88,7 @@ public class TrainMigration { if (position > edgeLength) continue; - GraphLocation graphLocation = new GraphLocation(); + TrackGraphLocation graphLocation = new TrackGraphLocation(); graphLocation.graph = graph; graphLocation.edge = Couple.create(loc, newNode2.getLocation()); graphLocation.position = position; diff --git a/src/main/java/com/simibubi/create/content/trains/entity/TrainPacket.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainPacket.java new file mode 100644 index 0000000000..099784f633 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainPacket.java @@ -0,0 +1,122 @@ +package com.simibubi.create.content.trains.entity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.createmod.catnip.platform.CatnipServices; +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Iterate; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.registries.ForgeRegistries; + +public class TrainPacket extends SimplePacketBase { + + UUID trainId; + Train train; + boolean add; + + public TrainPacket(Train train, boolean add) { + this.train = train; + this.add = add; + } + + public TrainPacket(FriendlyByteBuf buffer) { + add = buffer.readBoolean(); + trainId = buffer.readUUID(); + + if (!add) + return; + + UUID owner = null; + if (buffer.readBoolean()) + owner = buffer.readUUID(); + + List carriages = new ArrayList<>(); + List carriageSpacing = new ArrayList<>(); + + int size = buffer.readVarInt(); + for (int i = 0; i < size; i++) { + Couple bogies = Couple.create(null, null); + for (boolean isFirst : Iterate.trueAndFalse) { + if (!isFirst && !buffer.readBoolean()) + continue; + AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); + boolean upsideDown = buffer.readBoolean(); + CompoundTag data = buffer.readNbt(); + bogies.set(isFirst, new CarriageBogey(type, upsideDown, data, new TravellingPoint(), new TravellingPoint())); + } + int spacing = buffer.readVarInt(); + carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); + } + + size = buffer.readVarInt(); + for (int i = 0; i < size; i++) + carriageSpacing.add(buffer.readVarInt()); + + boolean doubleEnded = buffer.readBoolean(); + train = new Train(trainId, owner, null, carriages, carriageSpacing, doubleEnded); + + train.name = Component.Serializer.fromJson(buffer.readUtf()); + train.icon = TrainIconType.byId(buffer.readResourceLocation()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBoolean(add); + buffer.writeUUID(train.id); + + if (!add) + return; + + buffer.writeBoolean(train.owner != null); + if (train.owner != null) + buffer.writeUUID(train.owner); + + buffer.writeVarInt(train.carriages.size()); + for (Carriage carriage : train.carriages) { + for (boolean first : Iterate.trueAndFalse) { + if (!first) { + boolean onTwoBogeys = carriage.isOnTwoBogeys(); + buffer.writeBoolean(onTwoBogeys); + if (!onTwoBogeys) + continue; + } + CarriageBogey bogey = carriage.bogeys.get(first); + buffer.writeResourceLocation(CatnipServices.REGISTRIES.getKeyOrThrow((Block) bogey.type)); + buffer.writeBoolean(bogey.upsideDown); + buffer.writeNbt(bogey.bogeyData); + } + buffer.writeVarInt(carriage.bogeySpacing); + } + + buffer.writeVarInt(train.carriageSpacing.size()); + train.carriageSpacing.forEach(buffer::writeVarInt); + + buffer.writeBoolean(train.doubleEnded); + buffer.writeUtf(Component.Serializer.toJson(train.name)); + buffer.writeResourceLocation(train.icon.id); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Map trains = CreateClient.RAILWAYS.trains; + if (add) + trains.put(train.id, train); + else + trains.remove(trainId); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/entity/TrainPromptPacket.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainPromptPacket.java new file mode 100644 index 0000000000..3e5acbcfd7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainPromptPacket.java @@ -0,0 +1,47 @@ +package com.simibubi.create.content.trains.entity; + +import com.simibubi.create.content.trains.TrainHUD; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class TrainPromptPacket extends SimplePacketBase { + + private Component text; + private boolean shadow; + + public TrainPromptPacket(Component text, boolean shadow) { + this.text = text; + this.shadow = shadow; + } + + public TrainPromptPacket(FriendlyByteBuf buffer) { + text = buffer.readComponent(); + shadow = buffer.readBoolean(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeComponent(text); + buffer.writeBoolean(shadow); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::apply)); + return true; + } + + @OnlyIn(Dist.CLIENT) + public void apply() { + TrainHUD.currentPrompt = text; + TrainHUD.currentPromptShadow = shadow; + TrainHUD.promptKeepAlive = 30; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainRelocationPacket.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java rename to src/main/java/com/simibubi/create/content/trains/entity/TrainRelocationPacket.java index 2ac648b29e..46388274de 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainRelocationPacket.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.UUID; -import java.util.function.Supplier; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRelocationPacket; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.contraptions.ContraptionRelocationPacket; +import com.simibubi.create.content.trains.track.BezierTrackPointLocation; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.utility.VecHelper; import net.minecraft.ChatFormatting; @@ -64,10 +64,9 @@ public class TrainRelocationPacket extends SimplePacketBase { } @Override - public void handle(Supplier context) { - Context ctx = context.get(); - ctx.enqueueWork(() -> { - ServerPlayer sender = ctx.getSender(); + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); Train train = Create.RAILWAYS.trains.get(trainId); Entity entity = sender.level.getEntity(entityId); @@ -83,13 +82,14 @@ public class TrainRelocationPacket extends SimplePacketBase { if (!train.id.equals(cce.trainId)) return; + int verifyDistance = AllConfigs.server().trains.maxTrackPlacementLength.get() * 2; if (!sender.position() - .closerThan(Vec3.atCenterOf(pos), 64)) { + .closerThan(Vec3.atCenterOf(pos), verifyDistance)) { Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from clicked pos"); return; } if (!sender.position() - .closerThan(cce.position(), 64 + cce.getBoundingBox() + .closerThan(cce.position(), verifyDistance + cce.getBoundingBox() .getXsize() / 2)) { Create.LOGGER.warn(messagePrefix + train.name.getString() + ": player too far from carriage entity"); return; @@ -100,16 +100,15 @@ public class TrainRelocationPacket extends SimplePacketBase { .withStyle(ChatFormatting.GREEN), true); train.carriages.forEach(c -> c.forEachPresentEntity(e -> { e.nonDamageTicks = 10; - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> e), + AllPackets.getChannel().send(PacketDistributor.TRACKING_ENTITY.with(() -> e), new ContraptionRelocationPacket(e.getId())); })); return; } Create.LOGGER.warn(messagePrefix + train.name.getString() + ": relocation failed server-side"); - }); - ctx.setPacketHandled(true); + return true; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainRelocator.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java rename to src/main/java/com/simibubi/create/content/trains/entity/TrainRelocator.java index 773934f74e..16e316db1b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainRelocator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -13,24 +13,24 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableInt; import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandlerClient; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackGraphHelper; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; +import com.simibubi.create.content.contraptions.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.ContraptionHandlerClient; +import com.simibubi.create.content.trains.entity.TravellingPoint.IEdgePointListener; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITrackSelector; +import com.simibubi.create.content.trains.entity.TravellingPoint.ITurnListener; +import com.simibubi.create.content.trains.entity.TravellingPoint.SteerDirection; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphHelper; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.track.BezierTrackPointLocation; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackBlockOutline; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.CatnipClient; @@ -115,20 +115,23 @@ public class TrainRelocator { BlockPos blockPos = blockhit.getBlockPos(); BezierTrackPointLocation hoveredBezier = null; + boolean upsideDown = relocating.carriages.get(0).leadingBogey().isUpsideDown(); + Vec3 offset = upsideDown ? new Vec3(0, -0.5, 0) : Vec3.ZERO; + if (simulate && toVisualise != null && lastHoveredResult != null) { for (int i = 0; i < toVisualise.size() - 1; i++) { - Vec3 vec1 = toVisualise.get(i); - Vec3 vec2 = toVisualise.get(i + 1); + Vec3 vec1 = toVisualise.get(i).add(offset); + Vec3 vec2 = toVisualise.get(i + 1).add(offset); CatnipClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0)) .colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B) - .disableNormals() + .disableLineNormals() .lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f); } } BezierPointSelection bezierSelection = TrackBlockOutline.result; if (bezierSelection != null) { - blockPos = bezierSelection.te() + blockPos = bezierSelection.blockEntity() .getBlockPos(); hoveredBezier = bezierSelection.loc(); } @@ -151,7 +154,7 @@ public class TrainRelocator { boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); if (!simulate && result) { relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10)); - AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, + AllPackets.getChannel().sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, direction, lookAngle, relocatingEntityId)); } @@ -165,7 +168,7 @@ public class TrainRelocator { return false; Pair nearestTrackAxis = track.getNearestTrackAxis(level, pos, blockState, lookAngle); - GraphLocation graphLocation = bezier != null + TrackGraphLocation graphLocation = bezier != null ? TrackGraphHelper.getBezierGraphLocationAt(level, pos, bezierDirection ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE, bezier) : TrackGraphHelper.getGraphLocationAt(level, pos, nearestTrackAxis.getSecond(), @@ -182,14 +185,14 @@ public class TrainRelocator { if (edge == null) return false; - TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position); + TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position, false); IEdgePointListener ignoreSignals = probe.ignoreEdgePoints(); ITurnListener ignoreTurns = probe.ignoreTurns(); List, Double>> recordedLocations = new ArrayList<>(); List recordedVecs = new ArrayList<>(); Consumer recorder = tp -> { recordedLocations.add(Pair.of(Couple.create(tp.node1, tp.node2), tp.position)); - recordedVecs.add(tp.getPosition()); + recordedVecs.add(tp.getPosition(graph)); }; ITrackSelector steer = probe.steer(SteerDirection.NONE, track.getUpNormal(level, pos, blockState)); MutableBoolean blocked = new MutableBoolean(false); @@ -269,7 +272,7 @@ public class TrainRelocator { public static void visualise(Train train, int i, Vec3 v1, Vec3 v2, boolean valid) { CatnipClient.OUTLINER.showLine(Pair.of(train, i), v1.add(0, -.825f, 0), v2.add(0, -.825f, 0)) .colored(valid ? 0x95CD41 : 0xEA5C2B) - .disableNormals() + .disableLineNormals() .lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java b/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java rename to src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java index a024af922d..1c57f23e11 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TrainStatus.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/trains/entity/TravellingPoint.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java rename to src/main/java/com/simibubi/create/content/trains/entity/TravellingPoint.java index 1d0b23bd5a..57d3960165 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/trains/entity/TravellingPoint.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.entity; +package com.simibubi.create.content.trains.entity; import java.util.ArrayList; import java.util.HashSet; @@ -16,14 +16,14 @@ import java.util.function.Predicate; import javax.annotation.Nullable; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Pair; @@ -38,6 +38,7 @@ public class TravellingPoint { public TrackEdge edge; public double position; public boolean blocked; + public boolean upsideDown; public static enum SteerDirection { NONE(0), LEFT(-1), RIGHT(1); @@ -64,11 +65,12 @@ public class TravellingPoint { public TravellingPoint() {} - public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) { + public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position, boolean upsideDown) { this.node1 = node1; this.node2 = node2; this.edge = edge; this.position = position; + this.upsideDown = upsideDown; } public IEdgePointListener ignoreEdgePoints() { @@ -358,7 +360,7 @@ public class TravellingPoint { return traveled; } - private Double edgeTraversedFrom(TrackGraph graph, boolean forward, IEdgePointListener edgePointListener, + protected Double edgeTraversedFrom(TrackGraph graph, boolean forward, IEdgePointListener edgePointListener, ITurnListener turnListener, double prevPos, double totalDistance) { if (edge.isTurn()) turnListener.accept(Math.max(0, totalDistance), edge); @@ -394,19 +396,23 @@ public class TravellingPoint { .get(node2); } - public Vec3 getPosition() { - return getPositionWithOffset(0); + public Vec3 getPosition(@Nullable TrackGraph trackGraph) { + return getPosition(trackGraph, false); } - public Vec3 getPositionWithOffset(double offset) { + public Vec3 getPosition(@Nullable TrackGraph trackGraph, boolean flipUpsideDown) { + return getPositionWithOffset(trackGraph, 0, flipUpsideDown); + } + + public Vec3 getPositionWithOffset(@Nullable TrackGraph trackGraph, double offset, boolean flipUpsideDown) { double t = (position + offset) / edge.getLength(); - return edge.getPosition(t) - .add(edge.getNormal(node1, node2, t) - .scale(1)); + return edge.getPosition(trackGraph, t) + .add(edge.getNormal(trackGraph, t) + .scale(upsideDown ^ flipUpsideDown ? -1 : 1)); } - public void migrateTo(List locations) { - GraphLocation location = locations.remove(0); + public void migrateTo(List locations) { + TrackGraphLocation location = locations.remove(0); TrackGraph graph = location.graph; node1 = graph.locateNode(location.edge.getFirst()); node2 = graph.locateNode(location.edge.getSecond()); @@ -423,12 +429,13 @@ public class TravellingPoint { tag.put("Nodes", nodes.map(TrackNode::getLocation) .serializeEach(loc -> loc.write(dimensions))); tag.putDouble("Position", position); + tag.putBoolean("UpsideDown", upsideDown); return tag; } public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { if (graph == null) - return new TravellingPoint(null, null, null, 0); + return new TravellingPoint(null, null, null, 0, false); Couple locs = tag.contains("Nodes") ? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions)) @@ -436,11 +443,11 @@ public class TravellingPoint { : Couple.create(null, null); if (locs.either(Objects::isNull)) - return new TravellingPoint(null, null, null, 0); + return new TravellingPoint(null, null, null, 0, false); double position = tag.getDouble("Position"); return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst()) - .get(locs.getSecond()), position); + .get(locs.getSecond()), position, tag.getBoolean("UpsideDown")); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/DimensionPalette.java b/src/main/java/com/simibubi/create/content/trains/graph/DimensionPalette.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/trains/DimensionPalette.java rename to src/main/java/com/simibubi/create/content/trains/graph/DimensionPalette.java index 381d9b66b6..3e69f024be 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/DimensionPalette.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/DimensionPalette.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java b/src/main/java/com/simibubi/create/content/trains/graph/EdgeData.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java rename to src/main/java/com/simibubi/create/content/trains/graph/EdgeData.java index ba4721181f..2482dfdaa0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/EdgeData.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.Iterator; @@ -10,14 +10,9 @@ import javax.annotation.Nullable; import com.google.common.base.Objects; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.NBTHelper; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointManager.java b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointManager.java similarity index 77% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointManager.java rename to src/main/java/com/simibubi/create/content/trains/graph/EdgePointManager.java index 5506ab6a1b..0644542bfd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointManager.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointManager.java @@ -1,11 +1,7 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.graph; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointStorage.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java rename to src/main/java/com/simibubi/create/content/trains/graph/EdgePointStorage.java index 0a0a2182e6..2efdd0fa0f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointStorage.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.graph; import java.util.Collection; import java.util.HashMap; @@ -7,9 +7,7 @@ import java.util.Map.Entry; import java.util.UUID; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/trains/graph/EdgePointType.java b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointType.java new file mode 100644 index 0000000000..411e278753 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/EdgePointType.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.observer.TrackObserver; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.station.GlobalStation; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; + +public class EdgePointType { + + public static final Map> TYPES = new HashMap<>(); + private ResourceLocation id; + private Supplier factory; + + public static final EdgePointType SIGNAL = + register(Create.asResource("signal"), SignalBoundary::new); + public static final EdgePointType STATION = + register(Create.asResource("station"), GlobalStation::new); + public static final EdgePointType OBSERVER = + register(Create.asResource("observer"), TrackObserver::new); + + public static EdgePointType register(ResourceLocation id, Supplier factory) { + EdgePointType type = new EdgePointType<>(id, factory); + TYPES.put(id, type); + return type; + } + + public EdgePointType(ResourceLocation id, Supplier factory) { + this.id = id; + this.factory = factory; + } + + public T create() { + T t = factory.get(); + t.setType(this); + return t; + } + + public ResourceLocation getId() { + return id; + } + + public static TrackEdgePoint read(FriendlyByteBuf buffer, DimensionPalette dimensions) { + ResourceLocation type = buffer.readResourceLocation(); + EdgePointType edgePointType = TYPES.get(type); + TrackEdgePoint point = edgePointType.create(); + point.read(buffer, dimensions); + return point; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackEdge.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackEdge.java new file mode 100644 index 0000000000..c664b5f743 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackEdge.java @@ -0,0 +1,253 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.TrackMaterial; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class TrackEdge { + + public TrackNode node1; + public TrackNode node2; + BezierConnection turn; + EdgeData edgeData; + boolean interDimensional; + TrackMaterial trackMaterial; + + public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn, TrackMaterial trackMaterial) { + this.interDimensional = !node1.location.dimension.equals(node2.location.dimension); + this.edgeData = new EdgeData(this); + this.node1 = node1; + this.node2 = node2; + this.turn = turn; + this.trackMaterial = trackMaterial; + } + + public TrackMaterial getTrackMaterial() { + return trackMaterial; + } + + public boolean isTurn() { + return turn != null; + } + + public boolean isInterDimensional() { + return interDimensional; + } + + public EdgeData getEdgeData() { + return edgeData; + } + + public BezierConnection getTurn() { + return turn; + } + + public Vec3 getDirection(boolean fromFirst) { + return getPosition(null, fromFirst ? 0.25f : 1).subtract(getPosition(null, fromFirst ? 0 : 0.75f)) + .normalize(); + } + + public Vec3 getDirectionAt(double t) { + double length = getLength(); + double step = .5f / length; + t /= length; + Vec3 ahead = getPosition(null, Math.min(1, t + step)); + Vec3 behind = getPosition(null, Math.max(0, t - step)); + return ahead.subtract(behind) + .normalize(); + } + + public boolean canTravelTo(TrackEdge other) { + if (isInterDimensional() || other.isInterDimensional()) + return true; + Vec3 newDirection = other.getDirection(true); + return getDirection(false).dot(newDirection) > 7 / 8f; + } + + public double getLength() { + return isInterDimensional() ? 0 + : isTurn() ? turn.getLength() + : node1.location.getLocation() + .distanceTo(node2.location.getLocation()); + } + + public double incrementT(double currentT, double distance) { + boolean tooFar = Math.abs(distance) > 5; + double length = getLength(); + distance = distance / (length == 0 ? 1 : length); + return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance; + } + + public Vec3 getPosition(@Nullable TrackGraph trackGraph, double t) { + if (isTurn()) + return turn.getPosition(Mth.clamp(t, 0, 1)); + if (trackGraph != null && (node1.location.yOffsetPixels != 0 || node2.location.yOffsetPixels != 0)) { + Vec3 positionSmoothed = getPositionSmoothed(trackGraph, t); + if (positionSmoothed != null) + return positionSmoothed; + } + return VecHelper.lerp((float) t, node1.location.getLocation(), node2.location.getLocation()); + } + + public Vec3 getNormal(@Nullable TrackGraph trackGraph, double t) { + if (isTurn()) + return turn.getNormal(Mth.clamp(t, 0, 1)); + if (trackGraph != null && (node1.location.yOffsetPixels != 0 || node2.location.yOffsetPixels != 0)) { + Vec3 normalSmoothed = getNormalSmoothed(trackGraph, t); + if (normalSmoothed != null) + return normalSmoothed; + } + return node1.getNormal(); + } + + @Nullable + public Vec3 getPositionSmoothed(TrackGraph trackGraph, double t) { + Vec3 node1Location = null; + Vec3 node2Location = null; + for (TrackEdge trackEdge : trackGraph.getConnectionsFrom(node1) + .values()) + if (trackEdge.isTurn()) + node1Location = trackEdge.getPosition(trackGraph, 0); + for (TrackEdge trackEdge : trackGraph.getConnectionsFrom(node2) + .values()) + if (trackEdge.isTurn()) + node2Location = trackEdge.getPosition(trackGraph, 0); + if (node1Location == null || node2Location == null) + return null; + return VecHelper.lerp((float) t, node1Location, node2Location); + } + + @Nullable + public Vec3 getNormalSmoothed(TrackGraph trackGraph, double t) { + Vec3 node1Normal = null; + Vec3 node2Normal = null; + for (TrackEdge trackEdge : trackGraph.getConnectionsFrom(node1) + .values()) + if (trackEdge.isTurn()) + node1Normal = trackEdge.getNormal(trackGraph, 0); + for (TrackEdge trackEdge : trackGraph.getConnectionsFrom(node2) + .values()) + if (trackEdge.isTurn()) + node2Normal = trackEdge.getNormal(trackGraph, 0); + if (node1Normal == null || node2Normal == null) + return null; + return VecHelper.lerp(0.5f, node1Normal, node2Normal); + } + + public Collection getIntersection(TrackNode node1, TrackNode node2, TrackEdge other, TrackNode other1, + TrackNode other2) { + Vec3 v1 = node1.location.getLocation(); + Vec3 v2 = node2.location.getLocation(); + Vec3 w1 = other1.location.getLocation(); + Vec3 w2 = other2.location.getLocation(); + + if (isInterDimensional() || other.isInterDimensional()) + return Collections.emptyList(); + if (v1.y != v2.y || v1.y != w1.y || v1.y != w2.y) + return Collections.emptyList(); + + if (!isTurn()) { + if (!other.isTurn()) + return ImmutableList.of(VecHelper.intersectRanged(v1, w1, v2, w2, Axis.Y)); + return other.getIntersection(other1, other2, this, node1, node2) + .stream() + .map(a -> new double[] { a[1], a[0] }) + .toList(); + } + + AABB bb = turn.getBounds(); + + if (!other.isTurn()) { + if (!bb.intersects(w1, w2)) + return Collections.emptyList(); + + Vec3 seg1 = v1; + Vec3 seg2 = null; + double t = 0; + + Collection intersections = new ArrayList<>(); + for (int i = 0; i < turn.getSegmentCount(); i++) { + double tOffset = t; + t += .5; + seg2 = getPosition(null, t / getLength()); + double[] intersection = VecHelper.intersectRanged(seg1, w1, seg2, w2, Axis.Y); + seg1 = seg2; + if (intersection == null) + continue; + intersection[0] += tOffset; + intersections.add(intersection); + } + + return intersections; + } + + if (!bb.intersects(other.turn.getBounds())) + return Collections.emptyList(); + + Vec3 seg1 = v1; + Vec3 seg2 = null; + double t = 0; + + Collection intersections = new ArrayList<>(); + for (int i = 0; i < turn.getSegmentCount(); i++) { + double tOffset = t; + t += .5; + seg2 = getPosition(null, t / getLength()); + + Vec3 otherSeg1 = w1; + Vec3 otherSeg2 = null; + double u = 0; + + for (int j = 0; j < other.turn.getSegmentCount(); j++) { + double uOffset = u; + u += .5; + otherSeg2 = other.getPosition(null, u / other.getLength()); + + double[] intersection = VecHelper.intersectRanged(seg1, otherSeg1, seg2, otherSeg2, Axis.Y); + otherSeg1 = otherSeg2; + + if (intersection == null) + continue; + + intersection[0] += tOffset; + intersection[1] += uOffset; + intersections.add(intersection); + } + + seg1 = seg2; + } + + return intersections; + } + + public CompoundTag write(DimensionPalette dimensions) { + CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); + baseCompound.put("Signals", edgeData.write(dimensions)); + baseCompound.putString("Material", getTrackMaterial().id.toString()); + return baseCompound; + } + + public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, + DimensionPalette dimensions) { + TrackEdge trackEdge = + new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null, + TrackMaterial.deserialize(tag.getString("Material"))); + trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions); + return trackEdge; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackEdgeIntersection.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackEdgeIntersection.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackEdgeIntersection.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackEdgeIntersection.java index 661c06d636..1c5bfb64f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackEdgeIntersection.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackEdgeIntersection.java @@ -1,10 +1,7 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.graph; import java.util.UUID; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; - import net.createmod.catnip.utility.Couple; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraph.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackGraph.java index eee4865961..b685d7f4c0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraph.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.Collection; @@ -19,15 +19,12 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointManager; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointStorage; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackEdgeIntersection; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.TrackMaterial; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.NBTHelper; @@ -393,14 +390,15 @@ public class TrackGraph { return connectionsFrom.get(nodes.getSecond()); } - public void connectNodes(LevelAccessor reader, TrackNodeLocation location, TrackNodeLocation location2, + public void connectNodes(LevelAccessor reader, DiscoveredLocation location, DiscoveredLocation location2, @Nullable BezierConnection turn) { TrackNode node1 = nodes.get(location); TrackNode node2 = nodes.get(location2); boolean bezier = turn != null; - TrackEdge edge = new TrackEdge(node1, node2, turn); - TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null); + TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA; + TrackEdge edge = new TrackEdge(node1, node2, turn, material); + TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null, material); for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) { for (TrackNode otherNode1 : graph.nodes.values()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphBounds.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphBounds.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphBounds.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackGraphBounds.java index 52e30d0f84..e2d06385ca 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphBounds.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphBounds.java @@ -1,9 +1,11 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.simibubi.create.content.trains.track.BezierConnection; + import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphHelper.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphHelper.java new file mode 100644 index 0000000000..1343277df9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphHelper.java @@ -0,0 +1,194 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.Nullable; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.BezierTrackPointLocation; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackBlockEntity; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class TrackGraphHelper { + + @Nullable + public static TrackGraphLocation getGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection, + Vec3 targetAxis) { + BlockState trackBlockState = level.getBlockState(pos); + if (!(trackBlockState.getBlock()instanceof ITrackBlock track)) + return null; + + Vec3 axis = targetAxis.scale(targetDirection.getStep()); + double length = axis.length(); + TrackGraph graph = null; + + // Case 1: Centre of block lies on a node + + TrackNodeLocation location = new TrackNodeLocation(Vec3.atBottomCenterOf(pos) + .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0)).in(level); + graph = Create.RAILWAYS.sided(level) + .getGraph(level, location); + if (graph != null) { + TrackNode node = graph.locateNode(location); + if (node != null) { + Map connectionsFrom = graph.getConnectionsFrom(node); + for (Entry entry : connectionsFrom.entrySet()) { + TrackNode backNode = entry.getKey(); + Vec3 direction = entry.getValue() + .getDirection(true); + if (direction.scale(length) + .distanceToSqr(axis.scale(-1)) > 1 / 4096f) + continue; + + TrackGraphLocation graphLocation = new TrackGraphLocation(); + graphLocation.edge = Couple.create(node.getLocation(), backNode.getLocation()); + graphLocation.position = 0; + graphLocation.graph = graph; + return graphLocation; + } + } + } + + // Case 2: Center of block is between two nodes + + Collection ends = track.getConnected(level, pos, trackBlockState, true, null); + Vec3 start = Vec3.atBottomCenterOf(pos) + .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0); + + TrackNode frontNode = null; + TrackNode backNode = null; + double position = 0; + boolean singleTrackPiece = true; + + for (DiscoveredLocation current : ends) { + Vec3 offset = current.getLocation() + .subtract(start) + .normalize() + .scale(length); + + Vec3 compareOffset = offset.multiply(1, 0, 1) + .normalize(); + boolean forward = compareOffset.distanceToSqr(axis.multiply(-1, 0, -1) + .normalize()) < 1 / 4096f; + boolean backwards = compareOffset.distanceToSqr(axis.multiply(1, 0, 1) + .normalize()) < 1 / 4096f; + + if (!forward && !backwards) + continue; + + DiscoveredLocation previous = null; + double distance = 0; + + for (int i = 0; i < 100 && distance < 32; i++) { + DiscoveredLocation loc = current; + if (graph == null) + graph = Create.RAILWAYS.sided(level) + .getGraph(level, loc); + + if (graph == null || graph.locateNode(loc) == null) { + singleTrackPiece = false; + Collection list = ITrackBlock.walkConnectedTracks(level, loc, true); + for (DiscoveredLocation discoveredLocation : list) { + if (discoveredLocation == previous) + continue; + Vec3 diff = discoveredLocation.getLocation() + .subtract(loc.getLocation()); + if ((forward ? axis.scale(-1) : axis).distanceToSqr(diff.normalize() + .scale(length)) > 1 / 4096f) + continue; + + previous = current; + current = discoveredLocation; + distance += diff.length(); + break; + } + continue; + } + + TrackNode node = graph.locateNode(loc); + if (forward) + frontNode = node; + if (backwards) { + backNode = node; + position = distance + axis.length() / 2; + } + break; + } + } + + if (frontNode == null || backNode == null) + return null; + + if (singleTrackPiece) + position = frontNode.getLocation() + .getLocation() + .distanceTo(backNode.getLocation() + .getLocation()) + / 2.0; + + TrackGraphLocation graphLocation = new TrackGraphLocation(); + graphLocation.edge = Couple.create(backNode.getLocation(), frontNode.getLocation()); + graphLocation.position = position; + graphLocation.graph = graph; + return graphLocation; + } + + @Nullable + public static TrackGraphLocation getBezierGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection, + BezierTrackPointLocation targetBezier) { + BlockState state = level.getBlockState(pos); + + if (!(state.getBlock() instanceof ITrackBlock track)) + return null; + if (!(level.getBlockEntity(pos) instanceof TrackBlockEntity trackBE)) + return null; + BezierConnection bc = trackBE.getConnections() + .get(targetBezier.curveTarget()); + if (bc == null || !bc.isPrimary()) + return null; + + TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond()).in(level); + if (bc.smoothing != null) + targetLoc.yOffsetPixels = bc.smoothing.getSecond(); + + for (DiscoveredLocation location : track.getConnected(level, pos, state, true, null)) { + TrackGraph graph = Create.RAILWAYS.sided(level) + .getGraph(level, location); + if (graph == null) + continue; + TrackNode targetNode = graph.locateNode(targetLoc); + if (targetNode == null) + continue; + TrackNode node = graph.locateNode(location); + TrackEdge edge = graph.getConnectionsFrom(node) + .get(targetNode); + if (edge == null) + continue; + + TrackGraphLocation graphLocation = new TrackGraphLocation(); + graphLocation.graph = graph; + graphLocation.edge = Couple.create(location, targetLoc); + graphLocation.position = (targetBezier.segment() + 1) / 2f; + if (targetDirection == AxisDirection.POSITIVE) { + graphLocation.edge = graphLocation.edge.swap(); + graphLocation.position = edge.getLength() - graphLocation.position; + } + + return graphLocation; + } + + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphLocation.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphLocation.java new file mode 100644 index 0000000000..8cd441d186 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphLocation.java @@ -0,0 +1,11 @@ +package com.simibubi.create.content.trains.graph; + +import net.createmod.catnip.utility.Couple; + +public class TrackGraphLocation { + + public TrackGraph graph; + public Couple edge; + public double position; + +} diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphPacket.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphPacket.java new file mode 100644 index 0000000000..8a2811761e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphPacket.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.UUID; + +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraftforge.network.NetworkEvent.Context; + +public abstract class TrackGraphPacket extends SimplePacketBase { + + public UUID graphId; + public int netId; + public boolean packetDeletesGraph; + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> handle(CreateClient.RAILWAYS, CreateClient.RAILWAYS.getOrCreateGraph(graphId, netId))); + return true; + } + + protected abstract void handle(GlobalRailwayManager manager, TrackGraph graph); + +} diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRequestPacket.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRequestPacket.java new file mode 100644 index 0000000000..982158f19f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRequestPacket.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.trains.graph; + +import com.simibubi.create.Create; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent.Context; + +public class TrackGraphRequestPacket extends SimplePacketBase { + + private int netId; + + public TrackGraphRequestPacket(int netId) { + this.netId = netId; + } + + public TrackGraphRequestPacket(FriendlyByteBuf buffer) { + netId = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(netId); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { + if (trackGraph.netId == netId) { + Create.RAILWAYS.sync.sendFullGraphTo(trackGraph, context.getSender()); + break; + } + } + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRollCallPacket.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRollCallPacket.java new file mode 100644 index 0000000000..f95e768e24 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphRollCallPacket.java @@ -0,0 +1,79 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent.Context; + +public class TrackGraphRollCallPacket extends SimplePacketBase { + + int[] ints; + + public TrackGraphRollCallPacket() { + GlobalRailwayManager manager = Create.RAILWAYS; + ints = new int[manager.trackNetworks.size() * 2]; + int i = 0; + for (TrackGraph trackGraph : manager.trackNetworks.values()) { + ints[i] = trackGraph.netId; + ints[i + 1] = trackGraph.getChecksum(); + i += 2; + } + } + + public TrackGraphRollCallPacket(FriendlyByteBuf buffer) { + ints = new int[buffer.readVarInt()]; + for (int i = 0; i < ints.length; i++) + ints[i] = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeVarInt(ints.length); + for (int i : ints) + buffer.writeInt(i); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + GlobalRailwayManager manager = Create.RAILWAYS.sided(null); + Set unusedIds = new HashSet<>(manager.trackNetworks.keySet()); + List failedIds = new ArrayList<>(); + Map idByNetId = new HashMap<>(); + manager.trackNetworks.forEach((uuid, g) -> idByNetId.put(g.netId, uuid)); + + for (int i = 0; i < ints.length; i += 2) { + UUID uuid = idByNetId.get(ints[i]); + if (uuid == null) { + failedIds.add(ints[i]); + continue; + } + unusedIds.remove(uuid); + TrackGraph trackGraph = manager.trackNetworks.get(uuid); + if (trackGraph.getChecksum() == ints[i + 1]) + continue; + Create.LOGGER.warn("Track network: " + uuid.toString() + .substring(0, 6) + " failed its checksum; Requesting refresh"); + failedIds.add(ints[i]); + } + + for (Integer failed : failedIds) + AllPackets.getChannel().sendToServer(new TrackGraphRequestPacket(failed)); + for (UUID unused : unusedIds) + manager.trackNetworks.remove(unused); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSync.java similarity index 79% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSync.java index 527b3d01d0..7db6d9123c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSync.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSync.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.Collections; @@ -9,12 +9,11 @@ import java.util.UUID; import javax.annotation.Nullable; import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.EdgeGroupColor; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroupPacket; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.content.trains.signal.EdgeGroupColor; +import com.simibubi.create.content.trains.signal.SignalEdgeGroupPacket; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Pair; @@ -33,7 +32,7 @@ public class TrackGraphSync { for (TrackGraphPacket packet : queuedPackets) { if (!packet.packetDeletesGraph && !Create.RAILWAYS.trackNetworks.containsKey(packet.graphId)) continue; - AllPackets.channel.send(PacketDistributor.ALL.noArg(), packet); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), packet); rollCallIn = 3; } @@ -54,22 +53,26 @@ public class TrackGraphSync { public void nodeAdded(TrackGraph graph, TrackNode node) { flushGraphPacket(graph); currentGraphSyncPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal())); + currentPayload++; } public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { flushGraphPacket(graph); currentGraphSyncPacket.addedEdges - .add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTurn())); + .add(Pair.of(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTrackMaterial()), edge.getTurn())); + currentPayload++; } public void pointAdded(TrackGraph graph, TrackEdgePoint point) { flushGraphPacket(graph); currentGraphSyncPacket.addedEdgePoints.add(point); + currentPayload++; } public void pointRemoved(TrackGraph graph, TrackEdgePoint point) { flushGraphPacket(graph); currentGraphSyncPacket.removedEdgePoints.add(point.getId()); + currentPayload++; } public void nodeRemoved(TrackGraph graph, TrackNode node) { @@ -78,7 +81,7 @@ public class TrackGraphSync { if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null) currentGraphSyncPacket.removedNodes.add(nodeId); currentGraphSyncPacket.addedEdges.removeIf(pair -> { - Couple ids = pair.getFirst(); + Couple ids = pair.getFirst().getFirst(); return ids.getFirst() .intValue() == nodeId || ids.getSecond() @@ -102,16 +105,16 @@ public class TrackGraphSync { // public void sendEdgeGroups(List ids, List colors, ServerPlayer player) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> player), new SignalEdgeGroupPacket(ids, colors, true)); } public void edgeGroupCreated(UUID id, EdgeGroupColor color) { - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(id, color)); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(id, color)); } public void edgeGroupRemoved(UUID id) { - AllPackets.channel.send(PacketDistributor.ALL.noArg(), + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), Collections.emptyList(), false)); } @@ -120,12 +123,14 @@ public class TrackGraphSync { public void edgeDataChanged(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { flushGraphPacket(graph); currentGraphSyncPacket.syncEdgeData(node1, node2, edge); + currentPayload++; } public void edgeDataChanged(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge, TrackEdge edge2) { flushGraphPacket(graph); currentGraphSyncPacket.syncEdgeData(node1, node2, edge); currentGraphSyncPacket.syncEdgeData(node2, node1, edge2); + currentPayload++; } public void sendFullGraphTo(TrackGraph graph, ServerPlayer player) { @@ -150,7 +155,7 @@ public class TrackGraphSync { graph.connectionsByNode.get(node) .forEach((node2, edge) -> { Couple key = Couple.create(node.getNetId(), node2.getNetId()); - currentPacket.addedEdges.add(Pair.of(key, edge.getTurn())); + currentPacket.addedEdges.add(Pair.of(Pair.of(key, edge.getTrackMaterial()), edge.getTurn())); currentPacket.syncEdgeData(node, node2, edge); }); @@ -178,11 +183,11 @@ public class TrackGraphSync { } private void sendRollCall() { - AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrackGraphRollCallPacket()); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrackGraphRollCallPacket()); } private TrackGraphSyncPacket flushAndCreateNew(TrackGraph graph, ServerPlayer player, TrackGraphSyncPacket packet) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet); + AllPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> player), packet); packet = new TrackGraphSyncPacket(graph.id, graph.netId); return packet; } @@ -190,6 +195,7 @@ public class TrackGraphSync { // private TrackGraphSyncPacket currentGraphSyncPacket; + private int currentPayload; private void flushGraphPacket() { flushGraphPacket(null, 0); @@ -201,14 +207,17 @@ public class TrackGraphSync { private void flushGraphPacket(@Nullable UUID graphId, int netId) { if (currentGraphSyncPacket != null) { - if (currentGraphSyncPacket.graphId.equals(graphId)) + if (currentGraphSyncPacket.graphId.equals(graphId) && currentPayload < 1000) return; queuedPackets.add(currentGraphSyncPacket); currentGraphSyncPacket = null; + currentPayload = 0; } - if (graphId != null) + if (graphId != null) { currentGraphSyncPacket = new TrackGraphSyncPacket(graphId, netId); + currentPayload = 0; + } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSyncPacket.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSyncPacket.java index 442e9da8e9..66e54fb3d0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphSyncPacket.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphSyncPacket.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.ArrayList; import java.util.HashMap; @@ -9,9 +9,10 @@ import java.util.Objects; import java.util.UUID; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.TrackMaterial; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Pair; @@ -22,7 +23,7 @@ import net.minecraft.world.phys.Vec3; public class TrackGraphSyncPacket extends TrackGraphPacket { Map> addedNodes; - List, BezierConnection>> addedEdges; + List, TrackMaterial>, BezierConnection>> addedEdges; List removedNodes; List addedEdgePoints; List removedEdgePoints; @@ -79,7 +80,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { size = buffer.readVarInt(); for (int i = 0; i < size; i++) addedEdges.add( - Pair.of(Couple.create(buffer::readVarInt), buffer.readBoolean() ? new BezierConnection(buffer) : null)); + Pair.of(Pair.of(Couple.create(buffer::readVarInt), TrackMaterial.deserialize(buffer.readUtf())), buffer.readBoolean() ? new BezierConnection(buffer) : null)); size = buffer.readVarInt(); for (int i = 0; i < size; i++) @@ -134,8 +135,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { buffer.writeVarInt(addedEdges.size()); addedEdges.forEach(pair -> { - pair.getFirst() + pair.getFirst().getFirst() .forEach(buffer::writeVarInt); + buffer.writeUtf(pair.getFirst().getSecond().id.toString()); BezierConnection turn = pair.getSecond(); buffer.writeBoolean(turn != null); if (turn != null) @@ -192,13 +194,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket { graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); } - for (Pair, BezierConnection> pair : addedEdges) { - Couple nodes = pair.getFirst() + for (Pair, TrackMaterial>, BezierConnection> pair : addedEdges) { + Couple nodes = pair.getFirst().getFirst() .map(graph::getNode); TrackNode node1 = nodes.getFirst(); TrackNode node2 = nodes.getSecond(); if (node1 != null && node2 != null) - graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond())); + graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond(), pair.getFirst().getSecond())); } for (TrackEdgePoint edgePoint : addedEdgePoints) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphVisualizer.java similarity index 78% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackGraphVisualizer.java index ab5195d679..d72f986b91 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphVisualizer.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackGraphVisualizer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import java.util.Iterator; import java.util.Map; @@ -9,10 +9,10 @@ import org.lwjgl.glfw.GLFW; import com.simibubi.create.AllKeys; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.signal.SignalBoundary; +import com.simibubi.create.content.trains.signal.SignalEdgeGroup; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.track.BezierConnection; import net.createmod.catnip.CatnipClient; import net.createmod.catnip.utility.Pair; @@ -37,7 +37,6 @@ public class TrackGraphVisualizer { Vec3 camera = cameraEntity.getEyePosition(); Outliner outliner = CatnipClient.OUTLINER; - boolean ctrl = false; // AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL); Map allGroups = Create.RAILWAYS.sided(null).signalEdgeGroups; float width = 1 / 8f; @@ -66,12 +65,13 @@ public class TrackGraphVisualizer { if (!edge.node1.location.dimension.equals(edge.node2.location.dimension)) continue; - if (other.hashCode() > hashCode && !ctrl) + if (other.hashCode() > hashCode && other.location.getLocation() + .distanceTo(camera) <= 50) continue; Vec3 yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 5) / 64f, 0); - Vec3 startPoint = edge.getPosition(0); - Vec3 endPoint = edge.getPosition(1); + Vec3 startPoint = edge.getPosition(graph, 0); + Vec3 endPoint = edge.getPosition(graph, 1); if (!edge.isTurn()) { @@ -90,11 +90,13 @@ public class TrackGraphVisualizer { group = allGroups.get(boundary.getGroup(node)); if (group != null) - outliner.showLine(Pair.of(boundary, edge), - edge.getPosition(prev + (prev == 0 ? 0 : 1 / 16f / length)) - .add(yOffset), - edge.getPosition((prev = boundary.getLocationOn(edge) / length) - 1 / 16f / length) - .add(yOffset)) + outliner + .showLine(Pair.of(boundary, edge), + edge.getPosition(graph, prev + (prev == 0 ? 0 : 1 / 16f / length)) + .add(yOffset), + edge.getPosition(graph, + (prev = boundary.getLocationOn(edge) / length) - 1 / 16f / length) + .add(yOffset)) .colored(group.color.get()) .lineWidth(width); @@ -103,7 +105,7 @@ public class TrackGraphVisualizer { if (prevBoundary != null) { group = allGroups.get(prevBoundary.getGroup(other)); if (group != null) - outliner.showLine(edge, edge.getPosition(prev + 1 / 16f / length) + outliner.showLine(edge, edge.getPosition(graph, prev + 1 / 16f / length) .add(yOffset), endPoint.add(yOffset)) .colored(group.color.get()) .lineWidth(width); @@ -153,16 +155,18 @@ public class TrackGraphVisualizer { for (int i = 0; i <= turn.getSegmentCount(); i++) { double f = i * 1f / turn.getSegmentCount(); double position = f * turn.getLength(); - Vec3 current = edge.getPosition(f); + Vec3 current = edge.getPosition(graph, f); if (previous != null) { if (currentBoundary != null && position > currentBoundaryPosition) { - current = edge.getPosition((currentBoundaryPosition - width) / turn.getLength()); + current = + edge.getPosition(graph, (currentBoundaryPosition - width) / turn.getLength()); outliner .showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset)) .colored(currentColour) .lineWidth(width); - current = edge.getPosition((currentBoundaryPosition + width) / turn.getLength()); + current = + edge.getPosition(graph, (currentBoundaryPosition + width) / turn.getLength()); previous = current; UUID newId = currentBoundary.getGroup(other); if (newId != null && allGroups.containsKey(newId)) @@ -196,7 +200,7 @@ public class TrackGraphVisualizer { Vec3 previous = null; BezierConnection turn = edge.getTurn(); for (int i = 0; i <= turn.getSegmentCount(); i++) { - Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); + Vec3 current = edge.getPosition(graph, i * 1f / turn.getSegmentCount()); if (previous != null) outliner.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset)) .colored(singleEdgeGroup.color.get()) @@ -208,7 +212,7 @@ public class TrackGraphVisualizer { } } - public static void debugViewGraph(TrackGraph graph) { + public static void debugViewGraph(TrackGraph graph, boolean extended) { Minecraft mc = Minecraft.getInstance(); Entity cameraEntity = mc.cameraEntity; if (cameraEntity == null) @@ -261,9 +265,20 @@ public class TrackGraphVisualizer { yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); if (!edge.isTurn()) { - CatnipClient.OUTLINER.showLine(edge, edge.getPosition(0) + if (extended) { + Vec3 materialPos = edge.getPosition(graph, 0.5) + .add(0, 1, 0); + CatnipClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, + edge.getTrackMaterial() + .asStack()); + CatnipClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, .25, 0, .25) + .move(0, -0.5, 0)) + .lineWidth(1 / 16f) + .colored(graph.color); + } + CatnipClient.OUTLINER.showLine(edge, edge.getPosition(graph, 0) .add(yOffset), - edge.getPosition(1) + edge.getPosition(graph, 1) .add(yOffset)) .colored(graph.color) .lineWidth(1 / 16f); @@ -272,8 +287,18 @@ public class TrackGraphVisualizer { Vec3 previous = null; BezierConnection turn = edge.getTurn(); + if (extended) { + Vec3 materialPos = edge.getPosition(graph, 0.5) + .add(0, 1, 0); + CatnipClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos, edge.getTrackMaterial() + .asStack()); + CatnipClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, .25, 0, .25) + .move(0, -0.5, 0)) + .lineWidth(1 / 16f) + .colored(graph.color); + } for (int i = 0; i <= turn.getSegmentCount(); i++) { - Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); + Vec3 current = edge.getPosition(graph, i * 1f / turn.getSegmentCount()); if (previous != null) CatnipClient.OUTLINER .showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset)) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNode.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackNode.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackNode.java rename to src/main/java/com/simibubi/create/content/trains/graph/TrackNode.java index 0944aaf642..3fc8312ebf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNode.java +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackNode.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.graph; import net.minecraft.world.phys.Vec3; diff --git a/src/main/java/com/simibubi/create/content/trains/graph/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/trains/graph/TrackNodeLocation.java new file mode 100644 index 0000000000..bec6b5233b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/graph/TrackNodeLocation.java @@ -0,0 +1,214 @@ +package com.simibubi.create.content.trains.graph; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import com.simibubi.create.content.trains.track.BezierConnection; +import com.simibubi.create.content.trains.track.TrackMaterial; + +import net.createmod.catnip.utility.Iterate; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class TrackNodeLocation extends Vec3i { + + public ResourceKey dimension; + public int yOffsetPixels; + + public TrackNodeLocation(Vec3 vec) { + this(vec.x, vec.y, vec.z); + } + + public TrackNodeLocation(double x, double y, double z) { + super(Math.round(x * 2), Math.floor(y) * 2, Math.round(z * 2)); + } + + public TrackNodeLocation in(Level level) { + return in(level.dimension()); + } + + public TrackNodeLocation in(ResourceKey dimension) { + this.dimension = dimension; + return this; + } + + private static TrackNodeLocation fromPackedPos(BlockPos bufferPos) { + return new TrackNodeLocation(bufferPos); + } + + private TrackNodeLocation(BlockPos readBlockPos) { + super(readBlockPos.getX(), readBlockPos.getY(), readBlockPos.getZ()); + } + + public Vec3 getLocation() { + return new Vec3(getX() / 2.0, getY() / 2.0 + yOffsetPixels / 16.0, getZ() / 2.0); + } + + public ResourceKey getDimension() { + return dimension; + } + + @Override + public boolean equals(Object pOther) { + return equalsIgnoreDim(pOther) && pOther instanceof TrackNodeLocation tnl + && Objects.equals(tnl.dimension, dimension); + } + + public boolean equalsIgnoreDim(Object pOther) { + return super.equals(pOther) && pOther instanceof TrackNodeLocation tnl && tnl.yOffsetPixels == yOffsetPixels; + } + + @Override + public int hashCode() { + return (getY() + ((getZ() + yOffsetPixels * 31) * 31 + dimension.hashCode()) * 31) * 31 + getX(); + } + + public CompoundTag write(DimensionPalette dimensions) { + CompoundTag c = NbtUtils.writeBlockPos(new BlockPos(this)); + if (dimensions != null) + c.putInt("D", dimensions.encode(dimension)); + if (yOffsetPixels != 0) + c.putInt("YO", yOffsetPixels); + return c; + } + + public static TrackNodeLocation read(CompoundTag tag, DimensionPalette dimensions) { + TrackNodeLocation location = fromPackedPos(NbtUtils.readBlockPos(tag)); + if (dimensions != null) + location.dimension = dimensions.decode(tag.getInt("D")); + location.yOffsetPixels = tag.getInt("YO"); + return location; + } + + public void send(FriendlyByteBuf buffer, DimensionPalette dimensions) { + buffer.writeVarInt(getX()); + buffer.writeShort(getY()); + buffer.writeVarInt(getZ()); + buffer.writeVarInt(yOffsetPixels); + buffer.writeVarInt(dimensions.encode(dimension)); + } + + public static TrackNodeLocation receive(FriendlyByteBuf buffer, DimensionPalette dimensions) { + TrackNodeLocation location = fromPackedPos(new BlockPos( + buffer.readVarInt(), + buffer.readShort(), + buffer.readVarInt() + )); + location.yOffsetPixels = buffer.readVarInt(); + location.dimension = dimensions.decode(buffer.readVarInt()); + return location; + } + + public Collection allAdjacent() { + Set set = new HashSet<>(); + Vec3 vec3 = getLocation().subtract(0, yOffsetPixels / 16.0, 0); + double step = 1 / 8f; + for (int x : Iterate.positiveAndNegative) + for (int y : Iterate.positiveAndNegative) + for (int z : Iterate.positiveAndNegative) + set.add(new BlockPos(vec3.add(x * step, y * step, z * step))); + return set; + } + + public static class DiscoveredLocation extends TrackNodeLocation { + + BezierConnection turn = null; + boolean forceNode = false; + Vec3 direction; + Vec3 normal; + TrackMaterial materialA; + TrackMaterial materialB; + + public DiscoveredLocation(Level level, double x, double y, double z) { + super(x, y, z); + in(level); + } + + public DiscoveredLocation(ResourceKey dimension, Vec3 vec) { + super(vec); + in(dimension); + } + + public DiscoveredLocation(Level level, Vec3 vec) { + this(level.dimension(), vec); + } + + public DiscoveredLocation materialA(TrackMaterial material) { + this.materialA = material; + return this; + } + + public DiscoveredLocation materialB(TrackMaterial material) { + this.materialB = material; + return this; + } + + public DiscoveredLocation materials(TrackMaterial materialA, TrackMaterial materialB) { + this.materialA = materialA; + this.materialB = materialB; + return this; + } + + public DiscoveredLocation viaTurn(BezierConnection turn) { + this.turn = turn; + if (turn != null) + forceNode(); + return this; + } + + public DiscoveredLocation forceNode() { + forceNode = true; + return this; + } + + public DiscoveredLocation withNormal(Vec3 normal) { + this.normal = normal; + return this; + } + + public DiscoveredLocation withYOffset(int yOffsetPixels) { + this.yOffsetPixels = yOffsetPixels; + return this; + } + + public DiscoveredLocation withDirection(Vec3 direction) { + this.direction = direction == null ? null : direction.normalize(); + return this; + } + + public boolean connectedViaTurn() { + return turn != null; + } + + public BezierConnection getTurn() { + return turn; + } + + public boolean shouldForceNode() { + return forceNode; + } + + public boolean differentMaterials() { + return materialA != materialB; + } + + public boolean notInLineWith(Vec3 direction) { + return this.direction != null + && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; + } + + public Vec3 getDirection() { + return direction; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java new file mode 100644 index 0000000000..fb599f296f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserver.java @@ -0,0 +1,111 @@ +package com.simibubi.create.content.trains.observer; + +import java.util.UUID; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.signal.SignalPropagator; +import com.simibubi.create.content.trains.signal.SingleBlockEntityEdgePoint; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + +public class TrackObserver extends SingleBlockEntityEdgePoint { + + private int activated; + private ItemStack filter; + private UUID currentTrain; + + public TrackObserver() { + activated = 0; + filter = ItemStack.EMPTY; + currentTrain = null; + } + + @Override + public void blockEntityAdded(BlockEntity blockEntity, boolean front) { + super.blockEntityAdded(blockEntity, front); + FilteringBehaviour filteringBehaviour = BlockEntityBehaviour.get(blockEntity, FilteringBehaviour.TYPE); + if (filteringBehaviour != null) + setFilterAndNotify(blockEntity.getLevel(), filteringBehaviour.getFilter()); + } + + @Override + public void tick(TrackGraph graph, boolean preTrains) { + super.tick(graph, preTrains); + if (isActivated()) + activated--; + if (!isActivated()) + currentTrain = null; + } + + public void setFilterAndNotify(Level level, ItemStack filter) { + this.filter = filter; + notifyTrains(level); + } + + private void notifyTrains(Level level) { + TrackGraph graph = Create.RAILWAYS.sided(level) + .getGraph(level, edgeLocation.getFirst()); + if (graph == null) + return; + TrackEdge edge = graph.getConnection(edgeLocation.map(graph::locateNode)); + if (edge == null) + return; + SignalPropagator.notifyTrains(graph, edge); + } + + public ItemStack getFilter() { + return filter; + } + + public UUID getCurrentTrain() { + return currentTrain; + } + + public boolean isActivated() { + return activated > 0; + } + + public void keepAlive(Train train) { + activated = 8; + currentTrain = train.id; + } + + @Override + public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { + super.read(nbt, migration, dimensions); + activated = nbt.getInt("Activated"); + filter = ItemStack.of(nbt.getCompound("Filter")); + if (nbt.contains("TrainId")) + currentTrain = nbt.getUUID("TrainId"); + } + + @Override + public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) { + super.read(buffer, dimensions); + } + + @Override + public void write(CompoundTag nbt, DimensionPalette dimensions) { + super.write(nbt, dimensions); + nbt.putInt("Activated", activated); + nbt.put("Filter", filter.serializeNBT()); + if (currentTrain != null) + nbt.putUUID("TrainId", currentTrain); + } + + @Override + public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) { + super.write(buffer, dimensions); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlock.java b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlock.java new file mode 100644 index 0000000000..efc99dc277 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlock.java @@ -0,0 +1,62 @@ +package com.simibubi.create.content.trains.observer; + +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; + +public class TrackObserverBlock extends Block implements IBE, IWrenchable { + + public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + + public TrackObserverBlock(Properties p_49795_) { + super(p_49795_); + registerDefaultState(defaultBlockState().setValue(POWERED, false)); + } + + @Override + protected void createBlockStateDefinition(Builder pBuilder) { + super.createBlockStateDefinition(pBuilder.add(POWERED)); + } + + @Override + public boolean isSignalSource(BlockState state) { + return true; + } + + @Override + public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { + return blockState.getValue(POWERED) ? 15 : 0; + } + + @Override + public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { + return true; + } + + @Override + public Class getBlockEntityClass() { + return TrackObserverBlockEntity.class; + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TRACK_OBSERVER.get(); + } + + @Override + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, worldIn, pos, newState); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlockEntity.java new file mode 100644 index 0000000000..e8a026ce4b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverBlockEntity.java @@ -0,0 +1,113 @@ +package com.simibubi.create.content.trains.observer; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +public class TrackObserverBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity { + + public TrackTargetingBehaviour edgePoint; + + private FilteringBehaviour filtering; + + public TrackObserverBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.OBSERVER)); + behaviours.add(filtering = createFilter().withCallback(this::onFilterChanged)); + filtering.setLabel(CreateLang.translateDirect("logistics.train_observer.cargo_filter")); + } + + private void onFilterChanged(ItemStack newFilter) { + if (level.isClientSide()) + return; + TrackObserver observer = getObserver(); + if (observer != null) + observer.setFilterAndNotify(level, newFilter); + } + + @Override + public void tick() { + super.tick(); + + if (level.isClientSide()) + return; + + boolean shouldBePowered = false; + TrackObserver observer = getObserver(); + if (observer != null) + shouldBePowered = observer.isActivated(); + if (isBlockPowered() == shouldBePowered) + return; + + BlockState blockState = getBlockState(); + if (blockState.hasProperty(TrackObserverBlock.POWERED)) + level.setBlock(worldPosition, blockState.setValue(TrackObserverBlock.POWERED, shouldBePowered), 3); + DisplayLinkBlock.notifyGatherers(level, worldPosition); + } + + @Nullable + public TrackObserver getObserver() { + return edgePoint.getEdgePoint(); + } + + public ItemStack getFilter() { + return filtering.getFilter(); + } + + public boolean isBlockPowered() { + return getBlockState().getOptionalValue(TrackObserverBlock.POWERED) + .orElse(false); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); + } + + @Override + public void transform(StructureTransform transform) { + edgePoint.transform(transform); + } + + public FilteringBehaviour createFilter() { + return new FilteringBehaviour(this, new ValueBoxTransform() { + + @Override + public void rotate(BlockState state, PoseStack ms) { + TransformStack.cast(ms) + .rotateX(90); + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + return new Vec3(0.5, 15.5 / 16d, 0.5); + } + + }); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverRenderer.java b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverRenderer.java new file mode 100644 index 0000000000..f553023964 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/observer/TrackObserverRenderer.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.trains.observer; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; +import com.simibubi.create.foundation.blockEntity.renderer.SmartBlockEntityRenderer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class TrackObserverRenderer extends SmartBlockEntityRenderer { + + public TrackObserverRenderer(Context context) { + super(context); + } + + @Override + protected void renderSafe(TrackObserverBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + super.renderSafe(be, partialTicks, ms, buffer, light, overlay); + BlockPos pos = be.getBlockPos(); + + TrackTargetingBehaviour target = be.edgePoint; + BlockPos targetPosition = target.getGlobalPosition(); + Level level = be.getLevel(); + BlockState trackState = level.getBlockState(targetPosition); + Block block = trackState.getBlock(); + + if (!(block instanceof ITrackBlock)) + return; + + ms.pushPose(); + TransformStack.cast(ms) + .translate(targetPosition.subtract(pos)); + RenderedTrackOverlayType type = RenderedTrackOverlayType.OBSERVER; + TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), ms, + buffer, light, overlay, type, 1); + ms.popPose(); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/DestinationSuggestions.java b/src/main/java/com/simibubi/create/content/trains/schedule/DestinationSuggestions.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/DestinationSuggestions.java rename to src/main/java/com/simibubi/create/content/trains/schedule/DestinationSuggestions.java index 59b410c452..84dfd1c0d7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/DestinationSuggestions.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/DestinationSuggestions.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java b/src/main/java/com/simibubi/create/content/trains/schedule/IScheduleInput.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java rename to src/main/java/com/simibubi/create/content/trains/schedule/IScheduleInput.java index c9b7a32efa..a614e9fe6c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/IScheduleInput.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/IScheduleInput.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.List; @@ -25,6 +25,8 @@ public interface IScheduleInput { public abstract CompoundTag getData(); + public abstract void setData(CompoundTag data); + public default int slotsTargeted() { return 0; } @@ -59,4 +61,3 @@ public interface IScheduleInput { } } - diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java b/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java new file mode 100644 index 0000000000..324a1d72ed --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/Schedule.java @@ -0,0 +1,100 @@ +package com.simibubi.create.content.trains.schedule; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.schedule.condition.FluidThresholdCondition; +import com.simibubi.create.content.trains.schedule.condition.IdleCargoCondition; +import com.simibubi.create.content.trains.schedule.condition.ItemThresholdCondition; +import com.simibubi.create.content.trains.schedule.condition.PlayerPassengerCondition; +import com.simibubi.create.content.trains.schedule.condition.RedstoneLinkCondition; +import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition; +import com.simibubi.create.content.trains.schedule.condition.ScheduledDelay; +import com.simibubi.create.content.trains.schedule.condition.StationPoweredCondition; +import com.simibubi.create.content.trains.schedule.condition.StationUnloadedCondition; +import com.simibubi.create.content.trains.schedule.condition.TimeOfDayCondition; +import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction; +import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction; +import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; +import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; + +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class Schedule { + + public static List>> INSTRUCTION_TYPES = + new ArrayList<>(); + public static List>> CONDITION_TYPES = + new ArrayList<>(); + + static { + registerInstruction("destination", DestinationInstruction::new); + registerInstruction("rename", ChangeTitleInstruction::new); + registerInstruction("throttle", ChangeThrottleInstruction::new); + registerCondition("delay", ScheduledDelay::new); + registerCondition("time_of_day", TimeOfDayCondition::new); + registerCondition("fluid_threshold", FluidThresholdCondition::new); + registerCondition("item_threshold", ItemThresholdCondition::new); + registerCondition("redstone_link", RedstoneLinkCondition::new); + registerCondition("player_count", PlayerPassengerCondition::new); + registerCondition("idle", IdleCargoCondition::new); + registerCondition("unloaded", StationUnloadedCondition::new); + registerCondition("powered", StationPoweredCondition::new); + } + + private static void registerInstruction(String name, Supplier factory) { + INSTRUCTION_TYPES.add(Pair.of(Create.asResource(name), factory)); + } + + private static void registerCondition(String name, Supplier factory) { + CONDITION_TYPES.add(Pair.of(Create.asResource(name), factory)); + } + + public static List getTypeOptions(List> list) { + String langSection = list.equals(INSTRUCTION_TYPES) ? "instruction." : "condition."; + return list.stream() + .map(Pair::getFirst) + .map(rl -> rl.getNamespace() + ".schedule." + langSection + rl.getPath()) + .map(Components::translatable) + .toList(); + } + + public List entries; + public boolean cyclic; + public int savedProgress; + + public Schedule() { + entries = new ArrayList<>(); + cyclic = true; + savedProgress = 0; + } + + public CompoundTag write() { + CompoundTag tag = new CompoundTag(); + ListTag list = NBTHelper.writeCompoundList(entries, ScheduleEntry::write); + tag.put("Entries", list); + tag.putBoolean("Cyclic", cyclic); + if (savedProgress > 0) + tag.putInt("Progress", savedProgress); + return tag; + } + + public static Schedule fromTag(CompoundTag tag) { + Schedule schedule = new Schedule(); + schedule.entries = NBTHelper.readCompoundList(tag.getList("Entries", Tag.TAG_COMPOUND), ScheduleEntry::fromTag); + schedule.cyclic = tag.getBoolean("Cyclic"); + if (tag.contains("Progress")) + schedule.savedProgress = tag.getInt("Progress"); + return schedule; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleDataEntry.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleDataEntry.java index 58b2eae7a6..4712df9608 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleDataEntry.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleDataEntry.java @@ -1,35 +1,41 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import net.minecraft.nbt.CompoundTag; public abstract class ScheduleDataEntry implements IScheduleInput { - + protected CompoundTag data; - + public ScheduleDataEntry() { data = new CompoundTag(); } - + @Override public CompoundTag getData() { return data; } - + + @Override + public void setData(CompoundTag data) { + this.data = data; + readAdditional(data); + } + protected void writeAdditional(CompoundTag tag) {}; protected void readAdditional(CompoundTag tag) {}; - + protected T enumData(String key, Class enumClass) { T[] enumConstants = enumClass.getEnumConstants(); return enumConstants[data.getInt(key) % enumConstants.length]; } - + protected String textData(String key) { return data.getString(key); } - + protected int intData(String key) { return data.getInt(key); } - + } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEditPacket.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEditPacket.java new file mode 100644 index 0000000000..33c062af93 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEditPacket.java @@ -0,0 +1,51 @@ +package com.simibubi.create.content.trains.schedule; + +import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ScheduleEditPacket extends SimplePacketBase { + + private Schedule schedule; + + public ScheduleEditPacket(Schedule schedule) { + this.schedule = schedule; + } + + public ScheduleEditPacket(FriendlyByteBuf buffer) { + schedule = Schedule.fromTag(buffer.readNbt()); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeNbt(schedule.write()); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + ItemStack mainHandItem = sender.getMainHandItem(); + if (!AllItems.SCHEDULE.isIn(mainHandItem)) + return; + + CompoundTag tag = mainHandItem.getOrCreateTag(); + if (schedule.entries.isEmpty()) { + tag.remove("Schedule"); + if (tag.isEmpty()) + mainHandItem.setTag(null); + } else + tag.put("Schedule", schedule.write()); + + sender.getCooldowns() + .addCooldown(mainHandItem.getItem(), 5); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEntry.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEntry.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEntry.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEntry.java index a759544aef..9251cd5d6b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleEntry.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleEntry.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction; +import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition; +import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItem.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItem.java similarity index 90% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItem.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItem.java index e62cc8e7a6..1a055589d5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItem.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItem.java @@ -1,14 +1,14 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.List; -import com.simibubi.create.AllContainerTypes; +import com.simibubi.create.AllMenuTypes; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.utility.CreateLang; @@ -161,7 +161,7 @@ public class ScheduleItem extends Item implements MenuProvider { @Override public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) { ItemStack heldItem = player.getMainHandItem(); - return new ScheduleContainer(AllContainerTypes.SCHEDULE.get(), id, inv, heldItem); + return new ScheduleMenu(AllMenuTypes.SCHEDULE.get(), id, inv, heldItem); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItemEntityInteraction.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItemEntityInteraction.java similarity index 89% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItemEntityInteraction.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItemEntityInteraction.java index 9031c36b6b..8519fce81c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleItemEntityInteraction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleItemEntityInteraction.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.contraptions.Contraption; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Couple; @@ -107,7 +107,7 @@ public class ScheduleItemEntityInteraction { if (onServer) { AllSoundEvents.playItemPickup(player); player.displayClientMessage( - CreateLang.translateDirect( + CreateLang.translateDirect( train.runtime.isAutoSchedule ? "schedule.auto_removed_from_train" : "schedule.removed_from_train"), true); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleMenu.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleMenu.java new file mode 100644 index 0000000000..14585c6cb4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleMenu.java @@ -0,0 +1,107 @@ +package com.simibubi.create.content.trains.schedule; + +import com.simibubi.create.foundation.gui.menu.GhostItemMenu; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; + +public class ScheduleMenu extends GhostItemMenu { + + public boolean slotsActive = true; + public int targetSlotsActive = 1; + + static final int slots = 2; + + public ScheduleMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + public ScheduleMenu(MenuType type, int id, Inventory inv, ItemStack contentHolder) { + super(type, id, inv, contentHolder); + } + + @Override + protected ItemStackHandler createGhostInventory() { + return new ItemStackHandler(slots); + } + + @Override + public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { + if (slotId != playerInventory.selected || clickTypeIn == ClickType.THROW) + super.clicked(slotId, dragType, clickTypeIn, player); + } + + @Override + protected boolean allowRepeats() { + return true; + } + + @Override + protected ItemStack createOnClient(FriendlyByteBuf extraData) { + return extraData.readItem(); + } + + @Override + protected void addSlots() { + addPlayerSlots(46, 140); + for (int i = 0; i < slots; i++) + addSlot(new InactiveItemHandlerSlot(ghostInventory, i, i, 54 + 20 * i, 88)); + } + + @Override + protected void addPlayerSlots(int x, int y) { + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) + this.addSlot(new InactiveSlot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 9; ++col) + this.addSlot(new InactiveSlot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); + } + + @Override + protected void saveData(ItemStack contentHolder) {} + + @Override + public boolean stillValid(Player player) { + return playerInventory.getSelected() == contentHolder; + } + + class InactiveSlot extends Slot { + + public InactiveSlot(Container pContainer, int pIndex, int pX, int pY) { + super(pContainer, pIndex, pX, pY); + } + + @Override + public boolean isActive() { + return slotsActive; + } + + } + + class InactiveItemHandlerSlot extends SlotItemHandler { + + private int targetIndex; + + public InactiveItemHandlerSlot(IItemHandler itemHandler, int targetIndex, int index, int xPosition, + int yPosition) { + super(itemHandler, index, xPosition, yPosition); + this.targetIndex = targetIndex; + } + + @Override + public boolean isActive() { + return slotsActive && targetIndex < targetSlotsActive; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleRuntime.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleRuntime.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java index d6d4d290e1..647e8465f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleRuntime.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleRuntime.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.ArrayList; import java.util.Collection; @@ -6,17 +6,17 @@ import java.util.List; import java.util.Objects; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.display.GlobalTrainDisplayData.TrainDeparturePrediction; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduledDelay; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ChangeThrottleInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ChangeTitleInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction; +import com.simibubi.create.content.trains.display.GlobalTrainDisplayData.TrainDeparturePrediction; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition; +import com.simibubi.create.content.trains.schedule.condition.ScheduledDelay; +import com.simibubi.create.content.trains.schedule.destination.ChangeThrottleInstruction; +import com.simibubi.create.content.trains.schedule.destination.ChangeTitleInstruction; +import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; +import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; +import com.simibubi.create.content.trains.station.GlobalStation; import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.lang.Components; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleScreen.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleScreen.java rename to src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java index 977d0c4faf..cbc40d61f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/ScheduleScreen.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import java.util.ArrayList; import java.util.Collections; @@ -18,27 +18,27 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; +import com.simibubi.create.AllPackets; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.GlobalRailwayManager; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition; -import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduledDelay; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.DestinationInstruction; -import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.schedule.condition.ScheduleWaitCondition; +import com.simibubi.create.content.trains.schedule.condition.ScheduledDelay; +import com.simibubi.create.content.trains.schedule.destination.DestinationInstruction; +import com.simibubi.create.content.trains.schedule.destination.ScheduleInstruction; +import com.simibubi.create.content.trains.station.GlobalStation; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.ModularGuiLine; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; -import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; -import com.simibubi.create.foundation.gui.container.GhostItemSubmitPacket; +import com.simibubi.create.foundation.gui.menu.AbstractSimiContainerScreen; +import com.simibubi.create.foundation.gui.menu.GhostItemSubmitPacket; import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.Indicator; import com.simibubi.create.foundation.gui.widget.Indicator.State; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.UIRenderHelper; @@ -64,7 +64,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.phys.Vec3; import net.minecraftforge.client.gui.GuiUtils; -public class ScheduleScreen extends AbstractSimiContainerScreen { +public class ScheduleScreen extends AbstractSimiContainerScreen { private static final int CARD_HEADER = 22; private static final int CARD_WIDTH = 195; @@ -94,14 +94,14 @@ public class ScheduleScreen extends AbstractSimiContainerScreen g.getPoints(EdgePointType.STATION) .stream()) - .filter(station -> station.tilePos != null) + .filter(station -> station.blockEntityPos != null) .filter(station -> visited.add(station.name)) - .map(station -> IntAttached.with((int) Vec3.atBottomCenterOf(station.tilePos) + .map(station -> IntAttached.with((int) Vec3.atBottomCenterOf(station.blockEntityPos) .distanceTo(position), station.name)) .toList(); } @@ -1070,7 +1070,7 @@ public class ScheduleScreen extends AbstractSimiContainerScreen ms.translate(0, -2.25f / 16f, 0); msr.rotateX(-8.5f); BlockState air = Blocks.AIR.defaultBlockState(); - CachedPartialBuffers.partial(AllBlockPartials.TRAIN_HAT, air) + CachedPartialBuffers.partial(AllPartialModels.TRAIN_HAT, air) .forEntityRender() .light(light) .renderInto(ms, buffer.getBuffer(renderType)); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java b/src/main/java/com/simibubi/create/content/trains/schedule/TrainHatOffsets.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java rename to src/main/java/com/simibubi/create/content/trains/schedule/TrainHatOffsets.java index f1f7ddc986..4d231ed4fa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/TrainHatOffsets.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule; +package com.simibubi.create.content.trains.schedule; import net.minecraft.client.model.AgeableListModel; import net.minecraft.client.model.AxolotlModel; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/CargoThresholdCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/CargoThresholdCondition.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/CargoThresholdCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/CargoThresholdCondition.java index 9d8c525631..bf6afd7631 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/CargoThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/CargoThresholdCondition.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.Arrays; import java.util.List; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java similarity index 86% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java index 758e4b99ca..8d56c27322 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/FluidThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/FluidThresholdCondition.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -69,7 +69,8 @@ public class FluidThresholdCondition extends CargoThresholdCondition { @Override protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); - compareStack = ItemStack.of(tag.getCompound("Bucket")); + if (tag.contains("Bucket")) + compareStack = ItemStack.of(tag.getCompound("Bucket")); } @Override @@ -82,9 +83,9 @@ public class FluidThresholdCondition extends CargoThresholdCondition { if (fluidStack != null) return fluidStack; fluidStack = FluidStack.EMPTY; - if (!EmptyingByBasin.canItemBeEmptied(Minecraft.getInstance().level, compareStack)) + if (!GenericItemEmptying.canItemBeEmptied(Minecraft.getInstance().level, compareStack)) return fluidStack; - FluidStack fluidInFilter = EmptyingByBasin.emptyItem(Minecraft.getInstance().level, compareStack, true) + FluidStack fluidInFilter = GenericItemEmptying.emptyItem(Minecraft.getInstance().level, compareStack, true) .getFirst(); if (fluidInFilter == null) return fluidStack; @@ -97,7 +98,7 @@ public class FluidThresholdCondition extends CargoThresholdCondition { CreateLang.translateDirect("schedule.condition.threshold.train_holds", CreateLang.translateDirect("schedule.condition.threshold." + Lang.asId(getOperator().name()))), CreateLang.translateDirect("schedule.condition.threshold.x_units_of_item", getThreshold(), - CreateLang.translateDirect("schedule.condition.threshold.buckets"), + CreateLang.translateDirect("schedule.condition.threshold.buckets"), compareStack.isEmpty() ? CreateLang.translateDirect("schedule.condition.threshold.anything") : compareStack.getItem() instanceof FilterItem ? CreateLang.translateDirect("schedule.condition.threshold.matching_content") diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/IdleCargoCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/IdleCargoCondition.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/IdleCargoCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/IdleCargoCondition.java index e661b1db98..f582eb1d7d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/IdleCargoCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/IdleCargoCondition.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java similarity index 92% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java index 6b4aee9e19..02c6adf1de 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ItemThresholdCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ItemThresholdCondition.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.item.filter.FilterItem; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -70,7 +70,8 @@ public class ItemThresholdCondition extends CargoThresholdCondition { @Override protected void readAdditional(CompoundTag tag) { super.readAdditional(tag); - stack = ItemStack.of(tag.getCompound("Item")); + if (tag.contains("Item")) + stack = ItemStack.of(tag.getCompound("Item")); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/LazyTickedScheduleCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/LazyTickedScheduleCondition.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/LazyTickedScheduleCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/LazyTickedScheduleCondition.java index ce17a254a2..6d2bce1812 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/LazyTickedScheduleCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/LazyTickedScheduleCondition.java @@ -1,6 +1,6 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.Level; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/PlayerPassengerCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/PlayerPassengerCondition.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/PlayerPassengerCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/PlayerPassengerCondition.java index e788ac1ff2..462b0ef549 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/PlayerPassengerCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/PlayerPassengerCondition.java @@ -1,11 +1,11 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -49,7 +49,7 @@ public class PlayerPassengerCondition extends ScheduleWaitCondition { public List getTitleAs(String type) { int target = getTarget(); return ImmutableList.of(CreateLang.translateDirect("schedule.condition.player_count.seated", - CreateLang.translateDirect("schedule.condition.player_count." + (target == 1 ? "summary" : "summary_plural"), + CreateLang.translateDirect("schedule.condition.player_count." + (target == 1 ? "summary" : "summary_plural"), Components.literal("" + target).withStyle(ChatFormatting.DARK_AQUA)))); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/RedstoneLinkCondition.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/RedstoneLinkCondition.java index 597dbadfc0..7f35b8dfd5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/RedstoneLinkCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/RedstoneLinkCondition.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; import com.google.common.collect.ImmutableList; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler.Frequency; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler.Frequency; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -107,7 +107,8 @@ public class RedstoneLinkCondition extends ScheduleWaitCondition { @Override protected void readAdditional(CompoundTag tag) { - freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c))); + if (tag.contains("Frequency")) + freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c))); } @Override diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduleWaitCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduleWaitCondition.java new file mode 100644 index 0000000000..ea9d235a82 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduleWaitCondition.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.trains.schedule.condition; + +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.schedule.ScheduleDataEntry; + +import net.createmod.catnip.utility.Pair; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; + +public abstract class ScheduleWaitCondition extends ScheduleDataEntry { + + public abstract boolean tickCompletion(Level level, Train train, CompoundTag context); + + protected void requestStatusToUpdate(CompoundTag context) { + context.putInt("StatusVersion", context.getInt("StatusVersion") + 1); + } + + public final CompoundTag write() { + CompoundTag tag = new CompoundTag(); + CompoundTag dataCopy = data.copy(); + writeAdditional(dataCopy); + tag.putString("Id", getId().toString()); + tag.put("Data", dataCopy); + return tag; + } + + public static ScheduleWaitCondition fromTag(CompoundTag tag) { + ResourceLocation location = new ResourceLocation(tag.getString("Id")); + Supplier supplier = null; + for (Pair> pair : Schedule.CONDITION_TYPES) + if (pair.getFirst() + .equals(location)) + supplier = pair.getSecond(); + + if (supplier == null) { + Create.LOGGER.warn("Could not parse waiting condition type: " + location); + return null; + } + + ScheduleWaitCondition condition = supplier.get(); + // Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag + condition.readAdditional(tag); + CompoundTag data = tag.getCompound("Data"); + condition.readAdditional(data); + condition.data = data; + return condition; + } + + public abstract MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag); + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduledDelay.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduledDelay.java similarity index 86% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduledDelay.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduledDelay.java index 8dec83f951..1246f273e3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/ScheduledDelay.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/ScheduledDelay.java @@ -1,7 +1,7 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationPoweredCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/StationPoweredCondition.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationPoweredCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/StationPoweredCondition.java index 52ed5839ce..bb0b5477bf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/StationPoweredCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/StationPoweredCondition.java @@ -1,8 +1,8 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.station.GlobalStation; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; @@ -28,8 +28,8 @@ public class StationPoweredCondition extends ScheduleWaitCondition { GlobalStation currentStation = train.getCurrentStation(); if (currentStation == null) return false; - BlockPos stationPos = currentStation.getTilePos(); - ResourceKey stationDim = currentStation.getTileDimension(); + BlockPos stationPos = currentStation.getBlockEntityPos(); + ResourceKey stationDim = currentStation.getBlockEntityDimension(); MinecraftServer server = level.getServer(); if (server == null) return false; diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/condition/StationUnloadedCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/StationUnloadedCondition.java new file mode 100644 index 0000000000..96484b27c3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/StationUnloadedCondition.java @@ -0,0 +1,56 @@ +package com.simibubi.create.content.trains.schedule.condition; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.station.GlobalStation; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Pair; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class StationUnloadedCondition extends ScheduleWaitCondition { + @Override + public Pair getSummary() { + return Pair.of(ItemStack.EMPTY, CreateLang.translateDirect("schedule.condition.unloaded")); + } + + @Override + public boolean tickCompletion(Level level, Train train, CompoundTag context) { + GlobalStation currentStation = train.getCurrentStation(); + if (currentStation == null) + return false; + ResourceKey stationDim = currentStation.getBlockEntityDimension(); + MinecraftServer server = level.getServer(); + if (server == null) + return false; + ServerLevel stationLevel = server.getLevel(stationDim); + if (stationLevel == null) { + return false; + } + return !stationLevel.isPositionEntityTicking(currentStation.getBlockEntityPos()); + } + + @Override + protected void writeAdditional(CompoundTag tag) {} + + @Override + protected void readAdditional(CompoundTag tag) {} + + @Override + public ResourceLocation getId() { + return Create.asResource("unloaded"); + } + + @Override + public MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag) { + return CreateLang.translateDirect("schedule.condition.unloaded.status"); + } +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimeOfDayCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/TimeOfDayCondition.java similarity index 97% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimeOfDayCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/TimeOfDayCondition.java index fe289216cf..04aaa4f422 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimeOfDayCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/TimeOfDayCondition.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; @@ -8,7 +8,7 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.gui.widget.Label; import com.simibubi.create.foundation.gui.widget.ScrollInput; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimedWaitCondition.java b/src/main/java/com/simibubi/create/content/trains/schedule/condition/TimedWaitCondition.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimedWaitCondition.java rename to src/main/java/com/simibubi/create/content/trains/schedule/condition/TimedWaitCondition.java index 63135c0814..34e52f8a58 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/condition/TimedWaitCondition.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/condition/TimedWaitCondition.java @@ -1,9 +1,9 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.condition; +package com.simibubi.create.content.trains.schedule.condition; import java.util.List; import com.google.common.collect.ImmutableList; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import com.simibubi.create.foundation.utility.CreateLang; @@ -67,7 +67,7 @@ public abstract class TimedWaitCondition extends ScheduleWaitCondition { public List getTitleAs(String type) { return ImmutableList.of( Components.translatable(getId().getNamespace() + ".schedule." + type + "." + getId().getPath()), - CreateLang.translateDirect("schedule.condition.for_x_time", formatTime(false)) + CreateLang.translateDirect("schedule.condition.for_x_time", formatTime(false)) .withStyle(ChatFormatting.DARK_AQUA)); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeThrottleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeThrottleInstruction.java rename to src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java index d4030a48c2..bafa5b3d1e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeThrottleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeThrottleInstruction.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.destination; +package com.simibubi.create.content.trains.schedule.destination; import java.util.List; @@ -73,7 +73,7 @@ public class ChangeThrottleInstruction extends ScheduleInstruction { } private ItemStack icon() { - return AllBlocks.CONTROLS.asStack(); + return AllBlocks.TRAIN_CONTROLS.asStack(); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeTitleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeTitleInstruction.java rename to src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java index 782f5548fb..f0e726cc49 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/ChangeTitleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ChangeTitleInstruction.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.destination; +package com.simibubi.create.content.trains.schedule.destination; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/DestinationInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java similarity index 95% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/DestinationInstruction.java rename to src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java index 5cab2377a6..b68c3d1587 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/DestinationInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.destination; +package com.simibubi.create.content.trains.schedule.destination; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java new file mode 100644 index 0000000000..fdd98715e2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.trains.schedule.destination; + +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.schedule.ScheduleDataEntry; + +import net.createmod.catnip.utility.Pair; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; + +public abstract class ScheduleInstruction extends ScheduleDataEntry { + + public abstract boolean supportsConditions(); + + public final CompoundTag write() { + CompoundTag tag = new CompoundTag(); + CompoundTag dataCopy = data.copy(); + writeAdditional(dataCopy); + tag.putString("Id", getId().toString()); + tag.put("Data", dataCopy); + return tag; + } + + public static ScheduleInstruction fromTag(CompoundTag tag) { + ResourceLocation location = new ResourceLocation(tag.getString("Id")); + Supplier supplier = null; + for (Pair> pair : Schedule.INSTRUCTION_TYPES) + if (pair.getFirst() + .equals(location)) + supplier = pair.getSecond(); + + if (supplier == null) { + Create.LOGGER.warn("Could not parse schedule instruction type: " + location); + return new DestinationInstruction(); + } + + ScheduleInstruction scheduleDestination = supplier.get(); + // Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag + scheduleDestination.readAdditional(tag); + CompoundTag data = tag.getCompound("Data"); + scheduleDestination.readAdditional(data); + scheduleDestination.data = data; + return scheduleDestination; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/TextScheduleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java similarity index 93% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/TextScheduleInstruction.java rename to src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java index b84929eefd..7634d4339d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/destination/TextScheduleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.schedule.destination; +package com.simibubi.create.content.trains.schedule.destination; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/EdgeGroupColor.java b/src/main/java/com/simibubi/create/content/trains/signal/EdgeGroupColor.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/EdgeGroupColor.java rename to src/main/java/com/simibubi/create/content/trains/signal/EdgeGroupColor.java index 0528181912..97971a226f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/EdgeGroupColor.java +++ b/src/main/java/com/simibubi/create/content/trains/signal/EdgeGroupColor.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; +package com.simibubi.create.content.trains.signal; import net.createmod.catnip.utility.theme.Color; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalBlock.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java rename to src/main/java/com/simibubi/create/content/trains/signal/SignalBlock.java index e702522f17..cdb0b53b82 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalBlock.java @@ -1,12 +1,12 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; +package com.simibubi.create.content.trains.signal; import java.util.Random; import javax.annotation.Nullable; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.lang.Lang; @@ -28,7 +28,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; -public class SignalBlock extends Block implements ITE, IWrenchable { +public class SignalBlock extends Block implements IBE, IWrenchable { public static final EnumProperty TYPE = EnumProperty.create("type", SignalType.class); public static final BooleanProperty POWERED = BlockStateProperties.POWERED; @@ -49,8 +49,8 @@ public class SignalBlock extends Block implements ITE, IWrench } @Override - public Class getTileEntityClass() { - return SignalTileEntity.class; + public Class getBlockEntityClass() { + return SignalBlockEntity.class; } @Override @@ -93,8 +93,13 @@ public class SignalBlock extends Block implements ITE, IWrench } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TRACK_SIGNAL.get(); + public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + IBE.onRemove(state, worldIn, pos, newState); + } + + @Override + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TRACK_SIGNAL.get(); } @Override @@ -103,7 +108,7 @@ public class SignalBlock extends Block implements ITE, IWrench BlockPos pos = context.getClickedPos(); if (level.isClientSide) return InteractionResult.SUCCESS; - withTileEntityDo(level, pos, ste -> { + withBlockEntityDo(level, pos, ste -> { SignalBoundary signal = ste.getSignal(); Player player = context.getPlayer(); if (signal != null) { @@ -124,7 +129,7 @@ public class SignalBlock extends Block implements ITE, IWrench @Override public int getAnalogOutputSignal(BlockState pState, Level blockAccess, BlockPos pPos) { - return getTileEntityOptional(blockAccess, pPos).filter(SignalTileEntity::isPowered) + return getBlockEntityOptional(blockAccess, pPos).filter(SignalBlockEntity::isPowered) .map($ -> 15) .orElse(0); } diff --git a/src/main/java/com/simibubi/create/content/trains/signal/SignalBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalBlockEntity.java new file mode 100644 index 0000000000..b1a3d3411b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalBlockEntity.java @@ -0,0 +1,167 @@ +package com.simibubi.create.content.trains.signal; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.signal.SignalBlock.SignalType; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.NBTHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; + +public class SignalBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity { + + public static enum OverlayState { + RENDER, SKIP, DUAL + } + + public static enum SignalState { + RED, YELLOW, GREEN, INVALID; + + public boolean isRedLight(float renderTime) { + return this == RED || this == INVALID && renderTime % 40 < 3; + } + + public boolean isYellowLight(float renderTime) { + return this == YELLOW; + } + + public boolean isGreenLight(float renderTime) { + return this == GREEN; + } + } + + public TrackTargetingBehaviour edgePoint; + + private SignalState state; + private OverlayState overlay; + private int switchToRedAfterTrainEntered; + private boolean lastReportedPower; + + public SignalBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + this.state = SignalState.INVALID; + this.overlay = OverlayState.SKIP; + this.lastReportedPower = false; + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + NBTHelper.writeEnum(tag, "State", state); + NBTHelper.writeEnum(tag, "Overlay", overlay); + tag.putBoolean("Power", lastReportedPower); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + state = NBTHelper.readEnum(tag, "State", SignalState.class); + overlay = NBTHelper.readEnum(tag, "Overlay", OverlayState.class); + lastReportedPower = tag.getBoolean("Power"); + invalidateRenderBoundingBox(); + } + + @Nullable + public SignalBoundary getSignal() { + return edgePoint.getEdgePoint(); + } + + public boolean isPowered() { + return state == SignalState.RED; + } + + @Override + public void addBehaviours(List behaviours) { + edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.SIGNAL); + behaviours.add(edgePoint); + } + + @Override + public void tick() { + super.tick(); + if (level.isClientSide) + return; + + SignalBoundary boundary = getSignal(); + if (boundary == null) { + enterState(SignalState.INVALID); + setOverlay(OverlayState.RENDER); + return; + } + + BlockState blockState = getBlockState(); + + blockState.getOptionalValue(SignalBlock.POWERED).ifPresent(powered -> { + if (lastReportedPower == powered) + return; + lastReportedPower = powered; + boundary.updateBlockEntityPower(this); + notifyUpdate(); + }); + + blockState.getOptionalValue(SignalBlock.TYPE) + .ifPresent(stateType -> { + SignalType targetType = boundary.getTypeFor(worldPosition); + if (stateType != targetType) { + level.setBlock(worldPosition, blockState.setValue(SignalBlock.TYPE, targetType), 3); + refreshBlockState(); + } + }); + + enterState(boundary.getStateFor(worldPosition)); + setOverlay(boundary.getOverlayFor(worldPosition)); + } + + public boolean getReportedPower() { + return lastReportedPower; + } + + public SignalState getState() { + return state; + } + + public OverlayState getOverlay() { + return overlay; + } + + public void setOverlay(OverlayState state) { + if (this.overlay == state) + return; + this.overlay = state; + notifyUpdate(); + } + + public void enterState(SignalState state) { + if (switchToRedAfterTrainEntered > 0) + switchToRedAfterTrainEntered--; + if (this.state == state) + return; + if (state == SignalState.RED && switchToRedAfterTrainEntered > 0) + return; + this.state = state; + switchToRedAfterTrainEntered = state == SignalState.GREEN || state == SignalState.YELLOW ? 15 : 0; + notifyUpdate(); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); + } + + @Override + public void transform(StructureTransform transform) { + edgePoint.transform(transform); + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalBoundary.java similarity index 86% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java rename to src/main/java/com/simibubi/create/content/trains/signal/SignalBoundary.java index 9727f2f894..dc6664b828 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalBoundary.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; +package com.simibubi.create.content.trains.signal; import java.util.HashMap; import java.util.Map; @@ -7,13 +7,13 @@ import java.util.UUID; import com.google.common.base.Objects; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.OverlayState; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.signal.SignalBlock.SignalType; +import com.simibubi.create.content.trains.signal.SignalBlockEntity.OverlayState; +import com.simibubi.create.content.trains.signal.SignalBlockEntity.SignalState; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; @@ -96,24 +96,24 @@ public class SignalBoundary extends TrackEdgePoint { } @Override - public void tileAdded(BlockEntity tile, boolean front) { - Map tilesOnSide = blockEntities.get(front); - if (tilesOnSide.isEmpty()) - tile.getBlockState() + public void blockEntityAdded(BlockEntity blockEntity, boolean front) { + Map blockEntitiesOnSide = blockEntities.get(front); + if (blockEntitiesOnSide.isEmpty()) + blockEntity.getBlockState() .getOptionalValue(SignalBlock.TYPE) .ifPresent(type -> types.set(front, type)); - tilesOnSide.put(tile.getBlockPos(), tile instanceof SignalTileEntity ste && ste.getReportedPower()); + blockEntitiesOnSide.put(blockEntity.getBlockPos(), blockEntity instanceof SignalBlockEntity ste && ste.getReportedPower()); } - public void updateTilePower(SignalTileEntity tile) { + public void updateBlockEntityPower(SignalBlockEntity blockEntity) { for (boolean front : Iterate.trueAndFalse) blockEntities.get(front) - .computeIfPresent(tile.getBlockPos(), (p, c) -> tile.getReportedPower()); + .computeIfPresent(blockEntity.getBlockPos(), (p, c) -> blockEntity.getReportedPower()); } @Override - public void tileRemoved(BlockPos tilePos, boolean front) { - blockEntities.forEach(s -> s.remove(tilePos)); + public void blockEntityRemoved(BlockPos blockEntityPos, boolean front) { + blockEntities.forEach(s -> s.remove(blockEntityPos)); if (blockEntities.both(Map::isEmpty)) removeFromAllGraphs(); } @@ -138,11 +138,11 @@ public class SignalBoundary extends TrackEdgePoint { .isEmpty(); } - public OverlayState getOverlayFor(BlockPos tile) { + public OverlayState getOverlayFor(BlockPos blockEntity) { for (boolean first : Iterate.trueAndFalse) { Map set = blockEntities.get(first); for (BlockPos blockPos : set.keySet()) { - if (blockPos.equals(tile)) + if (blockPos.equals(blockEntity)) return blockEntities.get(!first) .isEmpty() ? OverlayState.RENDER : OverlayState.DUAL; return OverlayState.SKIP; @@ -151,15 +151,15 @@ public class SignalBoundary extends TrackEdgePoint { return OverlayState.SKIP; } - public SignalType getTypeFor(BlockPos tile) { + public SignalType getTypeFor(BlockPos blockEntity) { return types.get(blockEntities.getFirst() - .containsKey(tile)); + .containsKey(blockEntity)); } - public SignalState getStateFor(BlockPos tile) { + public SignalState getStateFor(BlockPos blockEntity) { for (boolean first : Iterate.trueAndFalse) { Map set = blockEntities.get(first); - if (set.containsKey(tile)) + if (set.containsKey(blockEntity)) return cachedStates.get(first); } return SignalState.INVALID; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroup.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java rename to src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroup.java index 8f1e04e0da..d173e2d891 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroup.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; +package com.simibubi.create.content.trains.signal; import java.util.HashMap; import java.util.HashSet; @@ -12,7 +12,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import com.google.common.base.Predicates; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.content.trains.entity.Train; import net.createmod.catnip.utility.NBTHelper; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroupPacket.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroupPacket.java new file mode 100644 index 0000000000..4b6b2c9999 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalEdgeGroupPacket.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.trains.signal; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent.Context; + +public class SignalEdgeGroupPacket extends SimplePacketBase { + + List ids; + List colors; + boolean add; + + public SignalEdgeGroupPacket(UUID id, EdgeGroupColor color) { + this(ImmutableList.of(id), ImmutableList.of(color), true); + } + + public SignalEdgeGroupPacket(List ids, List colors, boolean add) { + this.ids = ids; + this.colors = colors; + this.add = add; + } + + public SignalEdgeGroupPacket(FriendlyByteBuf buffer) { + ids = new ArrayList<>(); + colors = new ArrayList<>(); + add = buffer.readBoolean(); + int size = buffer.readVarInt(); + for (int i = 0; i < size; i++) + ids.add(buffer.readUUID()); + size = buffer.readVarInt(); + for (int i = 0; i < size; i++) + colors.add(EdgeGroupColor.values()[buffer.readVarInt()]); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBoolean(add); + buffer.writeVarInt(ids.size()); + ids.forEach(buffer::writeUUID); + buffer.writeVarInt(colors.size()); + colors.forEach(c -> buffer.writeVarInt(c.ordinal())); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + Map signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups; + int i = 0; + for (UUID id : ids) { + if (!add) { + signalEdgeGroups.remove(id); + continue; + } + + SignalEdgeGroup group = new SignalEdgeGroup(id); + signalEdgeGroups.put(id, group); + if (colors.size() > i) + group.color = colors.get(i); + i++; + } + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalPropagator.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java rename to src/main/java/com/simibubi/create/content/trains/signal/SignalPropagator.java index a05c14f18c..bad8a28d5f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalPropagator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; +package com.simibubi.create.content.trains.signal; import java.util.ArrayList; import java.util.HashMap; @@ -12,14 +12,14 @@ import java.util.function.Predicate; import com.google.common.base.Predicates; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackGraphSync; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphSync; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; diff --git a/src/main/java/com/simibubi/create/content/trains/signal/SignalRenderer.java b/src/main/java/com/simibubi/create/content/trains/signal/SignalRenderer.java new file mode 100644 index 0000000000..4f22a1ac4d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/signal/SignalRenderer.java @@ -0,0 +1,66 @@ +package com.simibubi.create.content.trains.signal; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.trains.signal.SignalBlockEntity.OverlayState; +import com.simibubi.create.content.trains.signal.SignalBlockEntity.SignalState; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.ponder.utility.WorldTickHolder; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class SignalRenderer extends SafeBlockEntityRenderer { + + public SignalRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(SignalBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + BlockState blockState = be.getBlockState(); + SignalState signalState = be.getState(); + OverlayState overlayState = be.getOverlay(); + + float renderTime = WorldTickHolder.getRenderTime(be.getLevel()); + if (signalState.isRedLight(renderTime)) + CachedPartialBuffers.partial(AllPartialModels.SIGNAL_ON, blockState) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + else + CachedPartialBuffers.partial(AllPartialModels.SIGNAL_OFF, blockState) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.solid())); + + BlockPos pos = be.getBlockPos(); + TrackTargetingBehaviour target = be.edgePoint; + BlockPos targetPosition = target.getGlobalPosition(); + Level level = be.getLevel(); + BlockState trackState = level.getBlockState(targetPosition); + Block block = trackState.getBlock(); + + if (!(block instanceof ITrackBlock)) + return; + if (overlayState == OverlayState.SKIP) + return; + + ms.pushPose(); + TransformStack.cast(ms) + .translate(targetPosition.subtract(pos)); + RenderedTrackOverlayType type = + overlayState == OverlayState.DUAL ? RenderedTrackOverlayType.DUAL_SIGNAL : RenderedTrackOverlayType.SIGNAL; + TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), ms, + buffer, light, overlay, type, 1); + ms.popPose(); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/signal/SingleBlockEntityEdgePoint.java b/src/main/java/com/simibubi/create/content/trains/signal/SingleBlockEntityEdgePoint.java new file mode 100644 index 0000000000..096a03b908 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/signal/SingleBlockEntityEdgePoint.java @@ -0,0 +1,64 @@ +package com.simibubi.create.content.trains.signal; + +import com.simibubi.create.content.trains.graph.DimensionPalette; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class SingleBlockEntityEdgePoint extends TrackEdgePoint { + + public ResourceKey blockEntityDimension; + public BlockPos blockEntityPos; + + public BlockPos getBlockEntityPos() { + return blockEntityPos; + } + + public ResourceKey getBlockEntityDimension() { + return blockEntityDimension; + } + + @Override + public void blockEntityAdded(BlockEntity blockEntity, boolean front) { + this.blockEntityPos = blockEntity.getBlockPos(); + this.blockEntityDimension = blockEntity.getLevel() + .dimension(); + } + + @Override + public void blockEntityRemoved(BlockPos blockEntityPos, boolean front) { + removeFromAllGraphs(); + } + + @Override + public void invalidate(LevelAccessor level) { + invalidateAt(level, blockEntityPos); + } + + @Override + public boolean canMerge() { + return false; + } + + @Override + public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { + super.read(nbt, migration, dimensions); + if (migration) + return; + blockEntityPos = NbtUtils.readBlockPos(nbt.getCompound("TilePos")); + blockEntityDimension = dimensions.decode(nbt.contains("TileDimension") ? nbt.getInt("TileDimension") : -1); + } + + @Override + public void write(CompoundTag nbt, DimensionPalette dimensions) { + super.write(nbt, dimensions); + nbt.put("TilePos", NbtUtils.writeBlockPos(blockEntityPos)); + nbt.putInt("TileDimension", dimensions.encode(blockEntityDimension)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/signal/TrackEdgePoint.java b/src/main/java/com/simibubi/create/content/trains/signal/TrackEdgePoint.java new file mode 100644 index 0000000000..574b3aa5bb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/signal/TrackEdgePoint.java @@ -0,0 +1,126 @@ +package com.simibubi.create.content.trains.signal; + +import java.util.UUID; + +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Couple; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class TrackEdgePoint { + + public UUID id; + public Couple edgeLocation; + public double position; + private EdgePointType type; + + public void setId(UUID id) { + this.id = id; + } + + public UUID getId() { + return id; + } + + public void setType(EdgePointType type) { + this.type = type; + } + + public EdgePointType getType() { + return type; + } + + public abstract boolean canMerge(); + + public boolean canCoexistWith(EdgePointType otherType, boolean front) { + return false; + } + + public abstract void invalidate(LevelAccessor level); + + protected void invalidateAt(LevelAccessor level, BlockPos blockEntityPos) { + TrackTargetingBehaviour behaviour = BlockEntityBehaviour.get(level, blockEntityPos, TrackTargetingBehaviour.TYPE); + if (behaviour == null) + return; + CompoundTag migrationData = new CompoundTag(); + DimensionPalette dimensions = new DimensionPalette(); + write(migrationData, dimensions); + dimensions.write(migrationData); + behaviour.invalidateEdgePoint(migrationData); + } + + public abstract void blockEntityAdded(BlockEntity blockEntity, boolean front); + + public abstract void blockEntityRemoved(BlockPos blockEntityPos, boolean front); + + public void onRemoved(TrackGraph graph) {} + + public void setLocation(Couple nodes, double position) { + this.edgeLocation = nodes; + this.position = position; + } + + public double getLocationOn(TrackEdge edge) { + return isPrimary(edge.node1) ? edge.getLength() - position : position; + } + + public boolean canNavigateVia(TrackNode side) { + return true; + } + + public boolean isPrimary(TrackNode node1) { + return edgeLocation.getSecond() + .equals(node1.getLocation()); + } + + public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) { + if (migration) + return; + + id = nbt.getUUID("Id"); + position = nbt.getDouble("Position"); + edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND), + tag -> TrackNodeLocation.read(tag, dimensions)); + } + + public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) { + id = buffer.readUUID(); + edgeLocation = Couple.create(() -> TrackNodeLocation.receive(buffer, dimensions)); + position = buffer.readDouble(); + } + + public void write(CompoundTag nbt, DimensionPalette dimensions) { + nbt.putUUID("Id", id); + nbt.putDouble("Position", position); + nbt.put("Edge", edgeLocation.serializeEach(loc -> loc.write(dimensions))); + } + + public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) { + buffer.writeResourceLocation(type.getId()); + buffer.writeUUID(id); + edgeLocation.forEach(loc -> loc.send(buffer, dimensions)); + buffer.writeDouble(position); + } + + public void tick(TrackGraph graph, boolean preTrains) {} + + protected void removeFromAllGraphs() { + for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) + if (trackGraph.removePoint(getType(), id) != null) + return; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/AbstractStationScreen.java b/src/main/java/com/simibubi/create/content/trains/station/AbstractStationScreen.java new file mode 100644 index 0000000000..110ff6d666 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/AbstractStationScreen.java @@ -0,0 +1,131 @@ +package com.simibubi.create.content.trains.station; + +import java.lang.ref.WeakReference; +import java.util.List; + +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.CreateClient; +import com.simibubi.create.compat.computercraft.ComputerScreen; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainIconType; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.element.PartialModelGuiElement; +import com.simibubi.create.foundation.gui.widget.IconButton; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.element.GuiGameElement; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +public abstract class AbstractStationScreen extends AbstractSimiScreen { + + protected AllGuiTextures background; + protected StationBlockEntity blockEntity; + protected GlobalStation station; + + protected WeakReference displayedTrain; + + private IconButton confirmButton; + + public AbstractStationScreen(StationBlockEntity be, GlobalStation station) { + super(be.getBlockState() + .getBlock() + .getName()); + this.blockEntity = be; + this.station = station; + displayedTrain = new WeakReference<>(null); + } + + @Override + protected void init() { + if (blockEntity.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), + this::renderAdditional, this, blockEntity.computerBehaviour::hasAttachedComputer)); + + setWindowSize(background.getWidth(), background.getHeight()); + super.init(); + clearWidgets(); + + int x = guiLeft; + int y = guiTop; + + confirmButton = new IconButton(x + background.getWidth() - 33, y + background.getHeight() - 24, AllIcons.I_CONFIRM); + confirmButton.withCallback(this::onClose); + addRenderableWidget(confirmButton); + } + + public int getTrainIconWidth(Train train) { + TrainIconType icon = train.icon; + List carriages = train.carriages; + + int w = icon.getIconWidth(TrainIconType.ENGINE); + if (carriages.size() == 1) + return w; + + for (int i = 1; i < carriages.size(); i++) { + if (i == carriages.size() - 1 && train.doubleEnded) { + w += icon.getIconWidth(TrainIconType.FLIPPED_ENGINE) + 1; + break; + } + Carriage carriage = carriages.get(i); + w += icon.getIconWidth(carriage.bogeySpacing) + 1; + } + + return w; + } + + @Override + public void tick() { + super.tick(); + + if (blockEntity.computerBehaviour.hasAttachedComputer()) + minecraft.setScreen(new ComputerScreen(title, () -> Components.literal(station.name), + this::renderAdditional, this, blockEntity.computerBehaviour::hasAttachedComputer)); + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + + background.render(ms, x, y, this); + renderAdditional(ms, mouseX, mouseY, partialTicks, x, y, background); + } + + private void renderAdditional(PoseStack ms, int mouseX, int mouseY, float partialTicks, int guiLeft, int guiTop, AllGuiTextures background) { + ms.pushPose(); + TransformStack msr = TransformStack.cast(ms); + msr.pushPose() + .translate(guiLeft + background.getWidth() + 4, guiTop + background.getHeight() + 4, 100) + .scale(40) + .rotateX(-22) + .rotateY(63); + GuiGameElement.of(blockEntity.getBlockState() + .setValue(BlockStateProperties.WATERLOGGED, false)) + .render(ms); + + if (blockEntity.resolveFlagAngle()) { + msr.translate(1 / 16f, -19 / 16f, -12 / 16f); + StationRenderer.transformFlag(msr, blockEntity, partialTicks, 180, false); + PartialModelGuiElement.of(getFlag(partialTicks)) + .render(ms); + } + + ms.popPose(); + } + + protected abstract PartialModel getFlag(float partialTicks); + + protected Train getImminent() { + return blockEntity.imminentTrain == null ? null : CreateClient.RAILWAYS.trains.get(blockEntity.imminentTrain); + } + + protected boolean trainPresent() { + return blockEntity.trainPresent; + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/AssemblyScreen.java b/src/main/java/com/simibubi/create/content/trains/station/AssemblyScreen.java new file mode 100644 index 0000000000..5c306896a9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/AssemblyScreen.java @@ -0,0 +1,176 @@ +package com.simibubi.create.content.trains.station; + +import java.lang.ref.WeakReference; +import java.util.List; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainIconType; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.client.gui.components.Widget; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; + +public class AssemblyScreen extends AbstractStationScreen { + + private IconButton quitAssembly; + private IconButton toggleAssemblyButton; + private List iconTypes; + private ScrollInput iconTypeScroll; + + public AssemblyScreen(StationBlockEntity be, GlobalStation station) { + super(be, station); + background = AllGuiTextures.STATION_ASSEMBLING; + } + + @Override + protected void init() { + super.init(); + int x = guiLeft; + int y = guiTop; + int by = y + background.getHeight() - 24; + + Widget widget = renderables.get(0); + if (widget instanceof IconButton ib) { + ib.setIcon(AllIcons.I_PRIORITY_VERY_LOW); + ib.setToolTip(CreateLang.translateDirect("station.close")); + } + + iconTypes = TrainIconType.REGISTRY.keySet() + .stream() + .toList(); + iconTypeScroll = new ScrollInput(x + 4, y + 17, 184, 14).titled(CreateLang.translateDirect("station.icon_type")); + iconTypeScroll.withRange(0, iconTypes.size()); + iconTypeScroll.withStepFunction(ctx -> -iconTypeScroll.standardStep() + .apply(ctx)); + iconTypeScroll.calling(s -> { + Train train = displayedTrain.get(); + if (train != null) + train.icon = TrainIconType.byId(iconTypes.get(s)); + }); + iconTypeScroll.active = iconTypeScroll.visible = false; + addRenderableWidget(iconTypeScroll); + + toggleAssemblyButton = new WideIconButton(x + 94, by, AllGuiTextures.I_ASSEMBLE_TRAIN); + toggleAssemblyButton.active = false; + toggleAssemblyButton.setToolTip(CreateLang.translateDirect("station.assemble_train")); + toggleAssemblyButton.withCallback(() -> { + AllPackets.getChannel() + .sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); + }); + + quitAssembly = new IconButton(x + 73, by, AllIcons.I_DISABLE); + quitAssembly.active = true; + quitAssembly.setToolTip(CreateLang.translateDirect("station.cancel")); + quitAssembly.withCallback(() -> { + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); + minecraft.setScreen(new StationScreen(blockEntity, station)); + }); + + addRenderableWidget(toggleAssemblyButton); + addRenderableWidget(quitAssembly); + + tickTrainDisplay(); + } + + @Override + public void tick() { + super.tick(); + tickTrainDisplay(); + Train train = displayedTrain.get(); + toggleAssemblyButton.active = blockEntity.bogeyCount > 0 || train != null; + + if (train != null) { + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); + minecraft.setScreen(new StationScreen(blockEntity, station)); + for (Carriage carriage : train.carriages) + carriage.updateConductors(); + } + } + + private void tickTrainDisplay() { + if (getImminent() == null) { + displayedTrain = new WeakReference<>(null); + quitAssembly.active = true; + iconTypeScroll.active = iconTypeScroll.visible = false; + toggleAssemblyButton.setToolTip(CreateLang.translateDirect("station.assemble_train")); + toggleAssemblyButton.setIcon(AllGuiTextures.I_ASSEMBLE_TRAIN); + toggleAssemblyButton.withCallback(() -> { + AllPackets.getChannel() + .sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); + }); + } else { + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); + minecraft.setScreen(new StationScreen(blockEntity, station)); + } + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + super.renderWindow(ms, mouseX, mouseY, partialTicks); + int x = guiLeft; + int y = guiTop; + + MutableComponent header = CreateLang.translateDirect("station.assembly_title"); + font.draw(ms, header, x + background.getWidth() / 2 - font.width(header) / 2, y + 4, 0x0E2233); + + AssemblyException lastAssemblyException = blockEntity.lastException; + if (lastAssemblyException != null) { + MutableComponent text = CreateLang.translateDirect("station.failed"); + font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x775B5B); + int offset = 0; + if (blockEntity.failedCarriageIndex != -1) { + font.draw(ms, CreateLang.translateDirect("station.carriage_number", blockEntity.failedCarriageIndex), x + 30, + y + 67, 0x7A7A7A); + offset += 10; + } + font.drawWordWrap(lastAssemblyException.component, x + 30, y + 67 + offset, 134, 0x775B5B); + offset += font.split(lastAssemblyException.component, 134) + .size() * 9 + 5; + font.drawWordWrap(CreateLang.translateDirect("station.retry"), x + 30, y + 67 + offset, 134, 0x7A7A7A); + return; + } + + int bogeyCount = blockEntity.bogeyCount; + + MutableComponent text = CreateLang.translateDirect( + bogeyCount == 0 ? "station.no_bogeys" : bogeyCount == 1 ? "station.one_bogey" : "station.more_bogeys", + bogeyCount); + font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x7A7A7A); + + font.drawWordWrap(CreateLang.translateDirect("station.how_to"), x + 28, y + 62, 134, 0x7A7A7A); + font.drawWordWrap(CreateLang.translateDirect("station.how_to_1"), x + 28, y + 94, 134, 0x7A7A7A); + font.drawWordWrap(CreateLang.translateDirect("station.how_to_2"), x + 28, y + 117, 138, 0x7A7A7A); + } + + @Override + public void removed() { + super.removed(); + Train train = displayedTrain.get(); + if (train != null) { + ResourceLocation iconId = iconTypes.get(iconTypeScroll.getState()); + train.icon = TrainIconType.byId(iconId); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, "", iconId)); + } + } + + @Override + protected PartialModel getFlag(float partialTicks) { + return AllPartialModels.STATION_ASSEMBLE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/GlobalStation.java b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java similarity index 79% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/GlobalStation.java rename to src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java index d7db61a8f1..bc025316c6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/GlobalStation.java +++ b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java @@ -1,20 +1,20 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; +package com.simibubi.create.content.trains.station; import java.lang.ref.WeakReference; import javax.annotation.Nullable; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.signal.SingleBlockEntityEdgePoint; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -public class GlobalStation extends SingleTileEdgePoint { +public class GlobalStation extends SingleBlockEntityEdgePoint { public String name; public WeakReference nearestTrain; @@ -26,9 +26,9 @@ public class GlobalStation extends SingleTileEdgePoint { } @Override - public void tileAdded(BlockEntity tile, boolean front) { - super.tileAdded(tile, front); - BlockState state = tile.getBlockState(); + public void blockEntityAdded(BlockEntity blockEntity, boolean front) { + super.blockEntityAdded(blockEntity, front); + BlockState state = blockEntity.getBlockState(); assembling = state != null && state.hasProperty(StationBlock.ASSEMBLING) && state.getValue(StationBlock.ASSEMBLING); } @@ -47,7 +47,7 @@ public class GlobalStation extends SingleTileEdgePoint { name = buffer.readUtf(); assembling = buffer.readBoolean(); if (buffer.readBoolean()) - tilePos = buffer.readBlockPos(); + blockEntityPos = buffer.readBlockPos(); } @Override @@ -62,9 +62,9 @@ public class GlobalStation extends SingleTileEdgePoint { super.write(buffer, dimensions); buffer.writeUtf(name); buffer.writeBoolean(assembling); - buffer.writeBoolean(tilePos != null); - if (tilePos != null) - buffer.writeBlockPos(tilePos); + buffer.writeBoolean(blockEntityPos != null); + if (blockEntityPos != null) + buffer.writeBlockPos(blockEntityPos); } public boolean canApproachFrom(TrackNode side) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/NoShadowFontWrapper.java b/src/main/java/com/simibubi/create/content/trains/station/NoShadowFontWrapper.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/NoShadowFontWrapper.java rename to src/main/java/com/simibubi/create/content/trains/station/NoShadowFontWrapper.java index eb0144d9d8..e1f1913219 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/NoShadowFontWrapper.java +++ b/src/main/java/com/simibubi/create/content/trains/station/NoShadowFontWrapper.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; +package com.simibubi.create.content.trains.station; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlock.java b/src/main/java/com/simibubi/create/content/trains/station/StationBlock.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlock.java rename to src/main/java/com/simibubi/create/content/trains/station/StationBlock.java index 96823f11d0..ee7b7608d1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlock.java +++ b/src/main/java/com/simibubi/create/content/trains/station/StationBlock.java @@ -1,13 +1,13 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; +package com.simibubi.create.content.trains.station; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.logistics.block.depot.SharedDepotBlockMethods; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.logistics.depot.SharedDepotBlockMethods; import com.simibubi.create.foundation.advancement.AdvancementBehaviour; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.createmod.catnip.gui.ScreenOpener; @@ -43,7 +43,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -public class StationBlock extends Block implements ITE, IWrenchable, ProperWaterloggedBlock { +public class StationBlock extends Block implements IBE, IWrenchable, ProperWaterloggedBlock { public static final BooleanProperty ASSEMBLING = BooleanProperty.create("assembling"); @@ -88,7 +88,7 @@ public class StationBlock extends Block implements ITE, IWren @Override public int getAnalogOutputSignal(BlockState pState, Level pLevel, BlockPos pPos) { - return getTileEntityOptional(pLevel, pPos).map(ste -> ste.trainPresent ? 15 : 0) + return getBlockEntityOptional(pLevel, pPos).map(ste -> ste.trainPresent ? 15 : 0) .orElse(0); } @@ -100,7 +100,7 @@ public class StationBlock extends Block implements ITE, IWren @Override public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) { - SharedDepotBlockMethods.onReplaced(state, worldIn, pos, newState, isMoving); + IBE.onRemove(state, worldIn, pos, newState); } @Override @@ -120,7 +120,7 @@ public class StationBlock extends Block implements ITE, IWren return InteractionResult.PASS; if (itemInHand.getItem() == Items.FILLED_MAP) { - return onTileEntityUse(pLevel, pPos, station -> { + return onBlockEntityUse(pLevel, pPos, station -> { if (pLevel.isClientSide) return InteractionResult.SUCCESS; @@ -138,7 +138,7 @@ public class StationBlock extends Block implements ITE, IWren }); } - InteractionResult result = onTileEntityUse(pLevel, pPos, station -> { + InteractionResult result = onBlockEntityUse(pLevel, pPos, station -> { ItemStack autoSchedule = station.getAutoSchedule(); if (autoSchedule.isEmpty()) return InteractionResult.PASS; @@ -154,20 +154,20 @@ public class StationBlock extends Block implements ITE, IWren if (result == InteractionResult.PASS) DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> withTileEntityDo(pLevel, pPos, te -> this.displayScreen(te, pPlayer))); + () -> () -> withBlockEntityDo(pLevel, pPos, be -> this.displayScreen(be, pPlayer))); return InteractionResult.SUCCESS; } @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(StationTileEntity te, Player player) { + protected void displayScreen(StationBlockEntity be, Player player) { if (!(player instanceof LocalPlayer)) return; - GlobalStation station = te.getStation(); - BlockState blockState = te.getBlockState(); + GlobalStation station = be.getStation(); + BlockState blockState = be.getBlockState(); if (station == null || blockState == null) return; boolean assembling = blockState.getBlock() == this && blockState.getValue(ASSEMBLING); - ScreenOpener.open(assembling ? new AssemblyScreen(te, station) : new StationScreen(te, station)); + ScreenOpener.open(assembling ? new AssemblyScreen(be, station) : new StationScreen(be, station)); } @Override @@ -176,13 +176,13 @@ public class StationBlock extends Block implements ITE, IWren } @Override - public Class getTileEntityClass() { - return StationTileEntity.class; + public Class getBlockEntityClass() { + return StationBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TRACK_STATION.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TRACK_STATION.get(); } @Override diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java new file mode 100644 index 0000000000..07cc4c51c1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java @@ -0,0 +1,934 @@ +package com.simibubi.create.content.trains.station; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Consumer; + +import javax.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.Create; +import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour; +import com.simibubi.create.compat.computercraft.ComputerCraftProxy; +import com.simibubi.create.content.contraptions.AssemblyException; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.decoration.slidingDoor.DoorControlBehaviour; +import com.simibubi.create.content.logistics.depot.DepotBehaviour; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlockEntity; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.CarriageBogey; +import com.simibubi.create.content.trains.entity.CarriageContraption; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainPacket; +import com.simibubi.create.content.trains.entity.TravellingPoint; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.schedule.Schedule; +import com.simibubi.create.content.trains.schedule.ScheduleItem; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.WorldAttached; +import net.createmod.catnip.utility.animation.LerpedFloat; +import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.network.PacketDistributor; + +public class StationBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity { + + public TrackTargetingBehaviour edgePoint; + public DoorControlBehaviour doorControls; + public LerpedFloat flag; + + protected int failedCarriageIndex; + protected AssemblyException lastException; + protected DepotBehaviour depotBehaviour; + public AbstractComputerBehaviour computerBehaviour; + + // for display + UUID imminentTrain; + boolean trainPresent; + boolean trainBackwards; + boolean trainCanDisassemble; + boolean trainHasSchedule; + boolean trainHasAutoSchedule; + + int flagYRot = -1; + boolean flagFlipped; + + public Component lastDisassembledTrainName; + + public StationBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + setLazyTickRate(20); + lastException = null; + failedCarriageIndex = -1; + flag = LerpedFloat.linear() + .startWithValue(0); + } + + @Override + public void addBehaviours(List behaviours) { + behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.STATION)); + behaviours.add(doorControls = new DoorControlBehaviour(this)); + behaviours.add(depotBehaviour = new DepotBehaviour(this).onlyAccepts(AllItems.SCHEDULE::isIn) + .withCallback(s -> applyAutoSchedule())); + depotBehaviour.addSubBehaviours(behaviours); + registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS, AllAdvancements.TRAIN, + AllAdvancements.LONG_TRAIN, AllAdvancements.CONDUCTOR); + behaviours.add(computerBehaviour = ComputerCraftProxy.behaviour(this)); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + lastException = AssemblyException.read(tag); + failedCarriageIndex = tag.getInt("FailedCarriageIndex"); + super.read(tag, clientPacket); + invalidateRenderBoundingBox(); + + if (tag.contains("ForceFlag")) + trainPresent = tag.getBoolean("ForceFlag"); + if (tag.contains("PrevTrainName")) + lastDisassembledTrainName = Component.Serializer.fromJson(tag.getString("PrevTrainName")); + + if (!clientPacket) + return; + if (!tag.contains("ImminentTrain")) { + imminentTrain = null; + trainPresent = false; + trainCanDisassemble = false; + trainBackwards = false; + return; + } + + imminentTrain = tag.getUUID("ImminentTrain"); + trainPresent = tag.contains("TrainPresent"); + trainCanDisassemble = tag.contains("TrainCanDisassemble"); + trainBackwards = tag.contains("TrainBackwards"); + trainHasSchedule = tag.contains("TrainHasSchedule"); + trainHasAutoSchedule = tag.contains("TrainHasAutoSchedule"); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + AssemblyException.write(tag, lastException); + tag.putInt("FailedCarriageIndex", failedCarriageIndex); + + if (lastDisassembledTrainName != null) + tag.putString("PrevTrainName", Component.Serializer.toJson(lastDisassembledTrainName)); + + super.write(tag, clientPacket); + + if (!clientPacket) + return; + if (imminentTrain == null) + return; + + tag.putUUID("ImminentTrain", imminentTrain); + + if (trainPresent) + NBTHelper.putMarker(tag, "TrainPresent"); + if (trainCanDisassemble) + NBTHelper.putMarker(tag, "TrainCanDisassemble"); + if (trainBackwards) + NBTHelper.putMarker(tag, "TrainBackwards"); + if (trainHasSchedule) + NBTHelper.putMarker(tag, "TrainHasSchedule"); + if (trainHasAutoSchedule) + NBTHelper.putMarker(tag, "TrainHasAutoSchedule"); + } + + @Nullable + public GlobalStation getStation() { + return edgePoint.getEdgePoint(); + } + + // Train Assembly + + public static WorldAttached> assemblyAreas = new WorldAttached<>(w -> new HashMap<>()); + + Direction assemblyDirection; + int assemblyLength; + int[] bogeyLocations; + AbstractBogeyBlock[] bogeyTypes; + boolean[] upsideDownBogeys; + int bogeyCount; + + @Override + public void lazyTick() { + if (isAssembling() && !level.isClientSide) + refreshAssemblyInfo(); + super.lazyTick(); + } + + @Override + public void tick() { + if (isAssembling() && level.isClientSide) + refreshAssemblyInfo(); + super.tick(); + + if (level.isClientSide) { + float currentTarget = flag.getChaseTarget(); + if (currentTarget == 0 || flag.settled()) { + int target = trainPresent || isAssembling() ? 1 : 0; + if (target != currentTarget) { + flag.chase(target, 0.1f, Chaser.LINEAR); + if (target == 1) + AllSoundEvents.CONTRAPTION_ASSEMBLE.playAt(level, worldPosition, 1, 2, true); + } + } + boolean settled = flag.getValue() > .15f; + flag.tickChaser(); + if (currentTarget == 0 && settled != flag.getValue() > .15f) + AllSoundEvents.CONTRAPTION_DISASSEMBLE.playAt(level, worldPosition, 0.75f, 1.5f, true); + return; + } + + GlobalStation station = getStation(); + if (station == null) + return; + + Train imminentTrain = station.getImminentTrain(); + boolean trainPresent = imminentTrain != null && imminentTrain.getCurrentStation() == station; + boolean canDisassemble = trainPresent && imminentTrain.canDisassemble(); + UUID imminentID = imminentTrain != null ? imminentTrain.id : null; + boolean trainHasSchedule = trainPresent && imminentTrain.runtime.getSchedule() != null; + boolean trainHasAutoSchedule = trainHasSchedule && imminentTrain.runtime.isAutoSchedule; + boolean newlyArrived = this.trainPresent != trainPresent; + + if (trainPresent && imminentTrain.runtime.displayLinkUpdateRequested) { + DisplayLinkBlock.notifyGatherers(level, worldPosition); + imminentTrain.runtime.displayLinkUpdateRequested = false; + } + + if (newlyArrived) + applyAutoSchedule(); + + if (newlyArrived || this.trainCanDisassemble != canDisassemble + || !Objects.equals(imminentID, this.imminentTrain) || this.trainHasSchedule != trainHasSchedule + || this.trainHasAutoSchedule != trainHasAutoSchedule) { + + this.imminentTrain = imminentID; + this.trainPresent = trainPresent; + this.trainCanDisassemble = canDisassemble; + this.trainBackwards = imminentTrain != null && imminentTrain.currentlyBackwards; + this.trainHasSchedule = trainHasSchedule; + this.trainHasAutoSchedule = trainHasAutoSchedule; + + notifyUpdate(); + } + } + + public boolean trackClicked(Player player, InteractionHand hand, ITrackBlock track, BlockState state, + BlockPos pos) { + refreshAssemblyInfo(); + BoundingBox bb = assemblyAreas.get(level) + .get(worldPosition); + if (bb == null || !bb.isInside(pos)) + return false; + + BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); + BlockPos down = new BlockPos(track.getUpNormal(level, pos, state).scale(-1)); + int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; + + if (!isValidBogeyOffset(bogeyOffset)) { + for (boolean upsideDown : Iterate.falseAndTrue) { + for (int i = -1; i <= 1; i++) { + BlockPos bogeyPos = pos.relative(assemblyDirection, i) + .offset(upsideDown ? down : up); + BlockState blockState = level.getBlockState(bogeyPos); + if (!(blockState.getBlock() instanceof AbstractBogeyBlock bogey)) + continue; + BlockEntity be = level.getBlockEntity(bogeyPos); + if (!(be instanceof AbstractBogeyBlockEntity oldBE)) + continue; + CompoundTag oldData = oldBE.getBogeyData(); + BlockState newBlock = bogey.getNextSize(oldBE); + if (newBlock.getBlock() == bogey) + player.displayClientMessage(CreateLang.translateDirect("bogey.style.no_other_sizes") + .withStyle(ChatFormatting.RED), true); + level.setBlock(bogeyPos, newBlock, 3); + BlockEntity newEntity = level.getBlockEntity(bogeyPos); + if (!(newEntity instanceof AbstractBogeyBlockEntity newBE)) + continue; + newBE.setBogeyData(oldData); + bogey.playRotateSound(level, bogeyPos); + return true; + } + } + + return false; + } + + ItemStack handItem = player.getItemInHand(hand); + if (!player.isCreative() && !AllBlocks.RAILWAY_CASING.isIn(handItem)) { + player.displayClientMessage(CreateLang.translateDirect("train_assembly.requires_casing"), true); + return false; + } + + boolean upsideDown = (player.getViewXRot(1.0F) < 0 && (track.getBogeyAnchor(level, pos, state)).getBlock() instanceof AbstractBogeyBlock bogey && bogey.canBeUpsideDown()); + + BlockPos targetPos = upsideDown ? pos.offset(down) : pos.offset(up); + if (level.getBlockState(targetPos) + .getDestroySpeed(level, targetPos) == -1) { + return false; + } + + level.destroyBlock(targetPos, true); + + BlockState bogeyAnchor = track.getBogeyAnchor(level, pos, state); + if (bogeyAnchor.getBlock() instanceof AbstractBogeyBlock bogey) { + bogeyAnchor = bogey.getVersion(bogeyAnchor, upsideDown); + } + bogeyAnchor = ProperWaterloggedBlock.withWater(level, bogeyAnchor, pos); + level.setBlock(targetPos, bogeyAnchor, 3); + player.displayClientMessage(CreateLang.translateDirect("train_assembly.bogey_created"), true); + SoundType soundtype = bogeyAnchor.getBlock() + .getSoundType(state, level, pos, player); + level.playSound(null, pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, + soundtype.getPitch() * 0.8F); + + if (!player.isCreative()) { + ItemStack itemInHand = player.getItemInHand(hand); + itemInHand.shrink(1); + if (itemInHand.isEmpty()) + player.setItemInHand(hand, ItemStack.EMPTY); + } + + return true; + } + + public boolean enterAssemblyMode(@Nullable ServerPlayer sender) { + if (isAssembling()) + return false; + + tryDisassembleTrain(sender); + if (!tryEnterAssemblyMode()) + return false; + + BlockState newState = getBlockState().setValue(StationBlock.ASSEMBLING, true); + level.setBlock(getBlockPos(), newState, 3); + refreshBlockState(); + refreshAssemblyInfo(); + + updateStationState(station -> station.assembling = true); + GlobalStation station = getStation(); + if (station != null) { + for (Train train : Create.RAILWAYS.sided(level).trains.values()) { + if (train.navigation.destination != station) + continue; + + GlobalStation preferredDestination = train.runtime.startCurrentInstruction(); + train.navigation.startNavigation(preferredDestination != null ? preferredDestination : station, Double.MAX_VALUE, false); + } + } + + return true; + } + + public boolean exitAssemblyMode() { + if (!isAssembling()) + return false; + + cancelAssembly(); + BlockState newState = getBlockState().setValue(StationBlock.ASSEMBLING, false); + level.setBlock(getBlockPos(), newState, 3); + refreshBlockState(); + + return updateStationState(station -> station.assembling = false); + } + + public boolean tryDisassembleTrain(@Nullable ServerPlayer sender) { + GlobalStation station = getStation(); + if (station == null) + return false; + + Train train = station.getPresentTrain(); + if (train == null) + return false; + + BlockPos trackPosition = edgePoint.getGlobalPosition(); + if (!train.disassemble(getAssemblyDirection(), trackPosition.above())) + return false; + + dropSchedule(sender); + return true; + } + + public boolean isAssembling() { + BlockState state = getBlockState(); + return state.hasProperty(StationBlock.ASSEMBLING) && state.getValue(StationBlock.ASSEMBLING); + } + + public boolean tryEnterAssemblyMode() { + if (!edgePoint.hasValidTrack()) + return false; + + BlockPos targetPosition = edgePoint.getGlobalPosition(); + BlockState trackState = edgePoint.getTrackBlockState(); + ITrackBlock track = edgePoint.getTrack(); + Vec3 trackAxis = track.getTrackAxes(level, targetPosition, trackState) + .get(0); + + boolean axisFound = false; + for (Axis axis : Iterate.axes) { + if (trackAxis.get(axis) == 0) + continue; + if (axisFound) + return false; + axisFound = true; + } + + return true; + } + + public void dropSchedule(@Nullable ServerPlayer sender) { + GlobalStation station = getStation(); + if (station == null) + return; + + Train train = station.getPresentTrain(); + if (train == null) + return; + + ItemStack schedule = train.runtime.returnSchedule(); + if (schedule.isEmpty()) + return; + if (sender != null && sender.getMainHandItem().isEmpty()) { + sender.getInventory() + .placeItemBackInInventory(schedule); + return; + } + + Vec3 v = VecHelper.getCenterOf(getBlockPos()); + ItemEntity itemEntity = new ItemEntity(getLevel(), v.x, v.y, v.z, schedule); + itemEntity.setDeltaMovement(Vec3.ZERO); + getLevel().addFreshEntity(itemEntity); + } + + private boolean updateStationState(Consumer updateState) { + GlobalStation station = getStation(); + TrackGraphLocation graphLocation = edgePoint.determineGraphLocation(); + if (station == null || graphLocation == null) + return false; + + updateState.accept(station); + Create.RAILWAYS.sync.pointAdded(graphLocation.graph, station); + Create.RAILWAYS.markTracksDirty(); + return true; + } + + public void refreshAssemblyInfo() { + if (!edgePoint.hasValidTrack()) + return; + + if (!isVirtual()) { + GlobalStation station = getStation(); + if (station == null || station.getPresentTrain() != null) + return; + } + + int prevLength = assemblyLength; + BlockPos targetPosition = edgePoint.getGlobalPosition(); + BlockState trackState = edgePoint.getTrackBlockState(); + ITrackBlock track = edgePoint.getTrack(); + getAssemblyDirection(); + + MutableBlockPos currentPos = targetPosition.mutable(); + currentPos.move(assemblyDirection); + + BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, targetPosition, trackState)); + + int MAX_LENGTH = AllConfigs.server().trains.maxAssemblyLength.get(); + int MAX_BOGEY_COUNT = AllConfigs.server().trains.maxBogeyCount.get(); + + int bogeyIndex = 0; + int maxBogeyCount = MAX_BOGEY_COUNT; + if (bogeyLocations == null) + bogeyLocations = new int[maxBogeyCount]; + if (bogeyTypes == null) + bogeyTypes = new AbstractBogeyBlock[maxBogeyCount]; + if (upsideDownBogeys == null) + upsideDownBogeys = new boolean[maxBogeyCount]; + Arrays.fill(bogeyLocations, -1); + Arrays.fill(bogeyTypes, null); + Arrays.fill(upsideDownBogeys, false); + + for (int i = 0; i < MAX_LENGTH; i++) { + if (i == MAX_LENGTH - 1) { + assemblyLength = i; + break; + } + if (!track.trackEquals(trackState, level.getBlockState(currentPos))) { + assemblyLength = Math.max(0, i - 1); + break; + } + + BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); + BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ()); + if (bogeyIndex < bogeyLocations.length) { + if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock bogey && !bogey.isUpsideDown(potentialBogeyState)) { + bogeyTypes[bogeyIndex] = bogey; + bogeyLocations[bogeyIndex] = i; + upsideDownBogeys[bogeyIndex] = false; + bogeyIndex++; + } else if ((potentialBogeyState = level.getBlockState(upsideDownBogeyOffset.offset(currentPos))).getBlock() instanceof AbstractBogeyBlock bogey && bogey.isUpsideDown(potentialBogeyState)) { + bogeyTypes[bogeyIndex] = bogey; + bogeyLocations[bogeyIndex] = i; + upsideDownBogeys[bogeyIndex] = true; + bogeyIndex++; + } + } + + currentPos.move(assemblyDirection); + } + + bogeyCount = bogeyIndex; + + if (level.isClientSide) + return; + if (prevLength == assemblyLength) + return; + if (isVirtual()) + return; + + Map map = assemblyAreas.get(level); + BlockPos startPosition = targetPosition.relative(assemblyDirection); + BlockPos trackEnd = startPosition.relative(assemblyDirection, assemblyLength - 1); + map.put(worldPosition, BoundingBox.fromCorners(startPosition, trackEnd)); + } + + public boolean updateName(String name) { + if (!updateStationState(station -> station.name = name)) + return false; + notifyUpdate(); + + return true; + } + + public boolean isValidBogeyOffset(int i) { + if ((i < 3 || bogeyCount == 0) && i != 0) + return false; + for (int j : bogeyLocations) { + if (j == -1) + break; + if (i >= j - 2 && i <= j + 2) + return false; + } + return true; + } + + public Direction getAssemblyDirection() { + if (assemblyDirection != null) + return assemblyDirection; + if (!edgePoint.hasValidTrack()) + return null; + BlockPos targetPosition = edgePoint.getGlobalPosition(); + BlockState trackState = edgePoint.getTrackBlockState(); + ITrackBlock track = edgePoint.getTrack(); + AxisDirection axisDirection = edgePoint.getTargetDirection(); + Vec3 axis = track.getTrackAxes(level, targetPosition, trackState) + .get(0) + .normalize() + .scale(axisDirection.getStep()); + return assemblyDirection = Direction.getNearest(axis.x, axis.y, axis.z); + } + + @Override + public void remove() { + assemblyAreas.get(level) + .remove(worldPosition); + super.remove(); + } + + public void assemble(UUID playerUUID) { + refreshAssemblyInfo(); + + if (bogeyLocations == null) + return; + + if (bogeyLocations[0] != 0) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.frontmost_bogey_at_station")), -1); + return; + } + + if (!edgePoint.hasValidTrack()) + return; + + BlockPos trackPosition = edgePoint.getGlobalPosition(); + BlockState trackState = edgePoint.getTrackBlockState(); + ITrackBlock track = edgePoint.getTrack(); + BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, trackPosition, trackState)); + + TrackNodeLocation location = null; + Vec3 centre = Vec3.atBottomCenterOf(trackPosition) + .add(0, track.getElevationAtCenter(level, trackPosition, trackState), 0); + Collection ends = track.getConnected(level, trackPosition, trackState, true, null); + Vec3 targetOffset = Vec3.atLowerCornerOf(assemblyDirection.getNormal()); + for (DiscoveredLocation end : ends) + if (Mth.equal(0, targetOffset.distanceToSqr(end.getLocation() + .subtract(centre) + .normalize()))) + location = end; + if (location == null) + return; + + List pointOffsets = new ArrayList<>(); + int iPrevious = -100; + for (int i = 0; i < bogeyLocations.length; i++) { + int loc = bogeyLocations[i]; + if (loc == -1) + break; + + if (loc - iPrevious < 3) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.bogeys_too_close", i, i + 1)), -1); + return; + } + + double bogeySize = bogeyTypes[i].getWheelPointSpacing(); + pointOffsets.add(Double.valueOf(loc + .5 - bogeySize / 2)); + pointOffsets.add(Double.valueOf(loc + .5 + bogeySize / 2)); + iPrevious = loc; + } + + List points = new ArrayList<>(); + Vec3 directionVec = Vec3.atLowerCornerOf(assemblyDirection.getNormal()); + TrackGraph graph = null; + TrackNode secondNode = null; + + for (int j = 0; j < assemblyLength * 2 + 40; j++) { + double i = j / 2d; + if (points.size() == pointOffsets.size()) + break; + + TrackNodeLocation currentLocation = location; + location = new TrackNodeLocation(location.getLocation() + .add(directionVec.scale(.5))).in(location.dimension); + + if (graph == null) + graph = Create.RAILWAYS.getGraph(level, currentLocation); + if (graph == null) + continue; + TrackNode node = graph.locateNode(currentLocation); + if (node == null) + continue; + + for (int pointIndex = points.size(); pointIndex < pointOffsets.size(); pointIndex++) { + double offset = pointOffsets.get(pointIndex); + if (offset > i) + break; + double positionOnEdge = i - offset; + + Map connectionsFromNode = graph.getConnectionsFrom(node); + + if (secondNode == null) + for (Entry entry : connectionsFromNode.entrySet()) { + TrackEdge edge = entry.getValue(); + TrackNode otherNode = entry.getKey(); + if (edge.isTurn()) + continue; + Vec3 edgeDirection = edge.getDirection(true); + if (Mth.equal(edgeDirection.normalize() + .dot(directionVec), -1d)) + secondNode = otherNode; + } + + if (secondNode == null) { + Create.LOGGER.warn("Cannot assemble: No valid starting node found"); + return; + } + + TrackEdge edge = connectionsFromNode.get(secondNode); + + if (edge == null) { + Create.LOGGER.warn("Cannot assemble: Missing graph edge"); + return; + } + + points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false)); + } + + secondNode = node; + } + + if (points.size() != pointOffsets.size()) { + Create.LOGGER.warn("Cannot assemble: Not all Points created"); + return; + } + + if (points.size() == 0) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.no_bogeys")), -1); + return; + } + + List contraptions = new ArrayList<>(); + List carriages = new ArrayList<>(); + List spacing = new ArrayList<>(); + boolean atLeastOneForwardControls = false; + + for (int bogeyIndex = 0; bogeyIndex < bogeyCount; bogeyIndex++) { + int pointIndex = bogeyIndex * 2; + if (bogeyIndex > 0) + spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); + CarriageContraption contraption = new CarriageContraption(assemblyDirection); + BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); + BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ())); + + try { + int offset = bogeyLocations[bogeyIndex] + 1; + boolean success = contraption.assemble(level, upsideDownBogeys[bogeyIndex] ? upsideDownBogeyPosOffset.relative(assemblyDirection, offset) : bogeyPosOffset.relative(assemblyDirection, offset)); + atLeastOneForwardControls |= contraption.hasForwardControls(); + contraption.setSoundQueueOffset(offset); + if (!success) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.nothing_attached", bogeyIndex + 1)), + -1); + return; + } + } catch (AssemblyException e) { + exception(e, contraptions.size() + 1); + return; + } + + AbstractBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; + boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex]; + BlockPos firstBogeyPos = contraption.anchor; + AbstractBogeyBlockEntity firstBogeyBlockEntity = (AbstractBogeyBlockEntity) level.getBlockEntity(firstBogeyPos); + CarriageBogey firstBogey = + new CarriageBogey(typeOfFirstBogey, firstBogeyIsUpsideDown, firstBogeyBlockEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1)); + CarriageBogey secondBogey = null; + BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); + int bogeySpacing = 0; + + if (secondBogeyPos != null) { + if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos + .equals((upsideDownBogeys[bogeyIndex + 1] ? upsideDownBogeyPosOffset : bogeyPosOffset).relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.not_connected_in_order")), + contraptions.size() + 1); + return; + } + AbstractBogeyBlockEntity secondBogeyBlockEntity = + (AbstractBogeyBlockEntity) level.getBlockEntity(secondBogeyPos); + bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; + secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyBlockEntity.getBogeyData(), + points.get(pointIndex + 2), points.get(pointIndex + 3)); + bogeyIndex++; + + } else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.single_bogey_carriage")), + contraptions.size() + 1); + return; + } + + contraptions.add(contraption); + carriages.add(new Carriage(firstBogey, secondBogey, bogeySpacing)); + } + + if (!atLeastOneForwardControls) { + exception(new AssemblyException(CreateLang.translateDirect("train_assembly.no_controls")), -1); + return; + } + + for (CarriageContraption contraption : contraptions) { + contraption.removeBlocksFromWorld(level, BlockPos.ZERO); + contraption.expandBoundsAroundAxis(Axis.Y); + } + + Train train = new Train(UUID.randomUUID(), playerUUID, graph, carriages, spacing, contraptions.stream() + .anyMatch(CarriageContraption::hasBackwardControls)); + + if (lastDisassembledTrainName != null) { + train.name = lastDisassembledTrainName; + lastDisassembledTrainName = null; + } + + for (int i = 0; i < contraptions.size(); i++) { + CarriageContraption contraption = contraptions.get(i); + Carriage carriage = carriages.get(i); + carriage.setContraption(level, contraption); + if (contraption.containsBlockBreakers()) + award(AllAdvancements.CONTRAPTION_ACTORS); + } + + GlobalStation station = getStation(); + if (station != null) { + train.setCurrentStation(station); + station.reserveFor(train); + } + + train.collectInitiallyOccupiedSignalBlocks(); + Create.RAILWAYS.addTrain(train); + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainPacket(train, true)); + clearException(); + + award(AllAdvancements.TRAIN); + if (contraptions.size() >= 6) + award(AllAdvancements.LONG_TRAIN); + } + + public void cancelAssembly() { + assemblyLength = 0; + assemblyAreas.get(level) + .remove(worldPosition); + clearException(); + } + + private void clearException() { + exception(null, -1); + } + + private void exception(AssemblyException exception, int carriage) { + failedCarriageIndex = carriage; + lastException = exception; + sendData(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getRenderBoundingBox() { + if (isAssembling()) + return INFINITE_EXTENT_AABB; + return super.getRenderBoundingBox(); + } + + @Override + protected AABB createRenderBoundingBox() { + return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); + } + + public ItemStack getAutoSchedule() { + return depotBehaviour.getHeldItemStack(); + } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, Direction side) { + if (isItemHandlerCap(cap)) + return depotBehaviour.getItemCapability(cap, side); + if (computerBehaviour.isPeripheralCap(cap)) + return computerBehaviour.getPeripheralCapability(); + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + computerBehaviour.removePeripheral(); + } + + private void applyAutoSchedule() { + ItemStack stack = getAutoSchedule(); + if (!AllItems.SCHEDULE.isIn(stack)) + return; + Schedule schedule = ScheduleItem.getSchedule(stack); + if (schedule == null || schedule.entries.isEmpty()) + return; + GlobalStation station = getStation(); + if (station == null) + return; + Train imminentTrain = station.getImminentTrain(); + if (imminentTrain == null || imminentTrain.getCurrentStation() != station) + return; + + award(AllAdvancements.CONDUCTOR); + imminentTrain.runtime.setSchedule(schedule, true); + AllSoundEvents.CONFIRM.playOnServer(level, worldPosition, 1, 1); + + if (!(level instanceof ServerLevel server)) + return; + + Vec3 v = Vec3.atBottomCenterOf(worldPosition.above()); + server.sendParticles(ParticleTypes.HAPPY_VILLAGER, v.x, v.y, v.z, 8, 0.35, 0.05, 0.35, 1); + server.sendParticles(ParticleTypes.END_ROD, v.x, v.y + .25f, v.z, 10, 0.05, 1, 0.05, 0.005f); + } + + public boolean resolveFlagAngle() { + if (flagYRot != -1) + return true; + + BlockState target = edgePoint.getTrackBlockState(); + if (!(target.getBlock() instanceof ITrackBlock def)) + return false; + + Vec3 axis = null; + BlockPos trackPos = edgePoint.getGlobalPosition(); + for (Vec3 vec3 : def.getTrackAxes(level, trackPos, target)) + axis = vec3.scale(edgePoint.getTargetDirection() + .getStep()); + if (axis == null) + return false; + + Direction nearest = Direction.getNearest(axis.x, 0, axis.z); + flagYRot = (int) (-nearest.toYRot() - 90); + + Vec3 diff = Vec3.atLowerCornerOf(trackPos.subtract(worldPosition)) + .multiply(1, 0, 1); + if (diff.lengthSqr() == 0) + return true; + + flagFlipped = diff.dot(Vec3.atLowerCornerOf(nearest.getClockWise() + .getNormal())) > 0; + + return true; + } + + @Override + public void transform(StructureTransform transform) { + edgePoint.transform(transform); + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationEditPacket.java b/src/main/java/com/simibubi/create/content/trains/station/StationEditPacket.java new file mode 100644 index 0000000000..ca13624f99 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/StationEditPacket.java @@ -0,0 +1,137 @@ +package com.simibubi.create.content.trains.station; + +import com.simibubi.create.content.decoration.slidingDoor.DoorControl; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public class StationEditPacket extends BlockEntityConfigurationPacket { + + boolean dropSchedule; + boolean assemblyMode; + Boolean tryAssemble; + DoorControl doorControl; + String name; + + public static StationEditPacket dropSchedule(BlockPos pos) { + StationEditPacket packet = new StationEditPacket(pos); + packet.dropSchedule = true; + return packet; + } + + public static StationEditPacket tryAssemble(BlockPos pos) { + StationEditPacket packet = new StationEditPacket(pos); + packet.tryAssemble = true; + return packet; + } + + public static StationEditPacket tryDisassemble(BlockPos pos) { + StationEditPacket packet = new StationEditPacket(pos); + packet.tryAssemble = false; + return packet; + } + + public static StationEditPacket configure(BlockPos pos, boolean assemble, String name, DoorControl doorControl) { + StationEditPacket packet = new StationEditPacket(pos); + packet.assemblyMode = assemble; + packet.tryAssemble = null; + packet.name = name; + packet.doorControl = doorControl; + return packet; + } + + public StationEditPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + public StationEditPacket(BlockPos pos) { + super(pos); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeBoolean(dropSchedule); + if (dropSchedule) + return; + buffer.writeBoolean(doorControl != null); + if (doorControl != null) + buffer.writeVarInt(doorControl.ordinal()); + buffer.writeBoolean(tryAssemble != null); + if (tryAssemble != null) { + buffer.writeBoolean(tryAssemble); + return; + } + buffer.writeBoolean(assemblyMode); + buffer.writeUtf(name); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + if (buffer.readBoolean()) { + dropSchedule = true; + return; + } + if (buffer.readBoolean()) + doorControl = DoorControl.values()[Mth.clamp(buffer.readVarInt(), 0, DoorControl.values().length)]; + name = ""; + if (buffer.readBoolean()) { + tryAssemble = buffer.readBoolean(); + return; + } + assemblyMode = buffer.readBoolean(); + name = buffer.readUtf(256); + } + + @Override + protected void applySettings(ServerPlayer player, StationBlockEntity be) { + Level level = be.getLevel(); + BlockPos blockPos = be.getBlockPos(); + BlockState blockState = level.getBlockState(blockPos); + + if (dropSchedule) { + be.dropSchedule(player); + return; + } + + if (doorControl != null) + be.doorControls.set(doorControl); + + if (!name.isBlank()) + be.updateName(name); + + if (!(blockState.getBlock() instanceof StationBlock)) + return; + + Boolean isAssemblyMode = blockState.getValue(StationBlock.ASSEMBLING); + boolean assemblyComplete = false; + + if (tryAssemble != null) { + if (!isAssemblyMode) + return; + if (tryAssemble) { + be.assemble(player.getUUID()); + assemblyComplete = be.getStation() != null && be.getStation() + .getPresentTrain() != null; + } else { + if (be.tryDisassembleTrain(player) && be.tryEnterAssemblyMode()) + be.refreshAssemblyInfo(); + } + if (!assemblyComplete) + return; + } + + if (assemblyMode) + be.enterAssemblyMode(player); + else + be.exitAssemblyMode(); + } + + @Override + protected void applySettings(StationBlockEntity be) {} + +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationMapData.java b/src/main/java/com/simibubi/create/content/trains/station/StationMapData.java new file mode 100644 index 0000000000..308506ee80 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/StationMapData.java @@ -0,0 +1,12 @@ +package com.simibubi.create.content.trains.station; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.LevelAccessor; + +public interface StationMapData { + + boolean toggleStation(LevelAccessor level, BlockPos pos, StationBlockEntity stationBlockEntity); + + void addStationMarker(StationMarker marker); + +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationMarker.java b/src/main/java/com/simibubi/create/content/trains/station/StationMarker.java new file mode 100644 index 0000000000..0ec0db03f6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/StationMarker.java @@ -0,0 +1,168 @@ +package com.simibubi.create.content.trains.station; + +import java.util.Objects; +import java.util.Optional; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix4f; +import com.simibubi.create.AllBlockEntityTypes; +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.map.CustomRenderedMapDecoration; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.saveddata.maps.MapDecoration; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; + +public class StationMarker { + // Not MANSION or MONUMENT to allow map extending + public static final MapDecoration.Type TYPE = MapDecoration.Type.RED_MARKER; + + private final BlockPos source; + private final BlockPos target; + private final Component name; + private final String id; + + public StationMarker(BlockPos source, BlockPos target, Component name) { + this.source = source; + this.target = target; + this.name = name; + id = "create:station-" + target.getX() + "," + target.getY() + "," + target.getZ(); + } + + public static StationMarker load(CompoundTag tag) { + BlockPos source = NbtUtils.readBlockPos(tag.getCompound("source")); + BlockPos target = NbtUtils.readBlockPos(tag.getCompound("target")); + Component name = Component.Serializer.fromJson(tag.getString("name")); + if (name == null) name = Components.immutableEmpty(); + + return new StationMarker(source, target, name); + } + + public static StationMarker fromWorld(BlockGetter level, BlockPos pos) { + Optional stationOption = AllBlockEntityTypes.TRACK_STATION.get(level, pos); + + if (stationOption.isEmpty() || stationOption.get().getStation() == null) + return null; + + String name = stationOption.get() + .getStation().name; + return new StationMarker(pos, BlockEntityBehaviour.get(stationOption.get(), TrackTargetingBehaviour.TYPE) + .getPositionForMapMarker(), Components.literal(name)); + } + + public CompoundTag save() { + CompoundTag tag = new CompoundTag(); + tag.put("source", NbtUtils.writeBlockPos(source)); + tag.put("target", NbtUtils.writeBlockPos(target)); + tag.putString("name", Component.Serializer.toJson(name)); + + return tag; + } + + public BlockPos getSource() { + return source; + } + + public BlockPos getTarget() { + return target; + } + + public Component getName() { + return name; + } + + public String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StationMarker that = (StationMarker) o; + + if (!target.equals(that.target)) return false; + return name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(target, name); + } + + public static class Decoration extends MapDecoration implements CustomRenderedMapDecoration { + private static final ResourceLocation TEXTURE = Create.asResource("textures/gui/station_map_icon.png"); + + public Decoration(byte x, byte y, Component name) { + super(TYPE, x, y, (byte) 0, name); + } + + public static Decoration from(MapDecoration decoration) { + return new StationMarker.Decoration(decoration.getX(), decoration.getY(), decoration.getName()); + } + + @Override + public boolean renderOnFrame() { + return true; + } + + @Override + public void render(PoseStack poseStack, MultiBufferSource bufferSource, boolean active, int packedLight, MapItemSavedData mapData, int index) { + poseStack.pushPose(); + + poseStack.translate(getX() / 2D + 64.0, getY() / 2D + 64.0, -0.02D); + + poseStack.pushPose(); + + poseStack.translate(0.5f, 0f, 0); + poseStack.scale(4.5F, 4.5F, 3.0F); + + VertexConsumer buffer = bufferSource.getBuffer(RenderType.text(TEXTURE)); + Matrix4f mat = poseStack.last().pose(); + float zOffset = -0.001f; + buffer.vertex(mat, -1, -1, zOffset * index).color(255, 255, 255, 255).uv(0.0f , 0.0f ).uv2(packedLight).endVertex(); + buffer.vertex(mat, -1, 1, zOffset * index).color(255, 255, 255, 255).uv(0.0f , 0.0f + 1.0f).uv2(packedLight).endVertex(); + buffer.vertex(mat, 1, 1, zOffset * index).color(255, 255, 255, 255).uv(0.0f + 1.0f, 0.0f + 1.0f).uv2(packedLight).endVertex(); + buffer.vertex(mat, 1, -1, zOffset * index).color(255, 255, 255, 255).uv(0.0f + 1.0f, 0.0f ).uv2(packedLight).endVertex(); + + poseStack.popPose(); + + if (getName() != null) { + Font font = Minecraft.getInstance().font; + Component component = getName(); + float f6 = (float)font.width(component); +// float f7 = Mth.clamp(25.0F / f6, 0.0F, 6.0F / 9.0F); + poseStack.pushPose(); +// poseStack.translate((double)(0.0F + (float)getX() / 2.0F + 64.0F / 2.0F), (double)(0.0F + (float)getY() / 2.0F + 64.0F + 4.0F), (double)-0.025F); + poseStack.translate(0, 6.0D, -0.005F); + + poseStack.scale(0.8f, 0.8f, 1.0F); + poseStack.translate(-f6 / 2f + .5f, 0, 0); +// poseStack.scale(f7, f7, 1.0F); + font.drawInBatch(component, 0.0F, 0.0F, -1, false, poseStack.last().pose(), bufferSource, false, Integer.MIN_VALUE, 15728880); + poseStack.popPose(); + } + + poseStack.popPose(); + } + + @Override + public boolean render(int index) { + return true; + } + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationRenderer.java b/src/main/java/com/simibubi/create/content/trains/station/StationRenderer.java new file mode 100644 index 0000000000..29ccf28d83 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/StationRenderer.java @@ -0,0 +1,154 @@ +package com.simibubi.create.content.trains.station; + +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.util.transform.Transform; +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.logistics.depot.DepotRenderer; +import com.simibubi.create.content.trains.track.ITrackBlock; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.BlockPos.MutableBlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class StationRenderer extends SafeBlockEntityRenderer { + + public StationRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(StationBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + BlockPos pos = be.getBlockPos(); + TrackTargetingBehaviour target = be.edgePoint; + BlockPos targetPosition = target.getGlobalPosition(); + Level level = be.getLevel(); + + DepotRenderer.renderItemsOf(be, partialTicks, ms, buffer, light, overlay, be.depotBehaviour); + + BlockState trackState = level.getBlockState(targetPosition); + Block block = trackState.getBlock(); + if (!(block instanceof ITrackBlock)) + return; + + GlobalStation station = be.getStation(); + boolean isAssembling = be.getBlockState() + .getValue(StationBlock.ASSEMBLING); + + if (!isAssembling || (station == null || station.getPresentTrain() != null) && !be.isVirtual()) { + renderFlag( + be.flag.getValue(partialTicks) > 0.75f ? AllPartialModels.STATION_ON : AllPartialModels.STATION_OFF, be, + partialTicks, ms, buffer, light, overlay); + ms.pushPose(); + TransformStack.cast(ms) + .translate(targetPosition.subtract(pos)); + TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(), + ms, buffer, light, overlay, RenderedTrackOverlayType.STATION, 1); + ms.popPose(); + return; + } + + renderFlag(AllPartialModels.STATION_ASSEMBLE, be, partialTicks, ms, buffer, light, overlay); + + ITrackBlock track = (ITrackBlock) block; + Direction direction = be.assemblyDirection; + + if (be.isVirtual() && be.bogeyLocations == null) + be.refreshAssemblyInfo(); + + if (direction == null || be.assemblyLength == 0 || be.bogeyLocations == null) + return; + + ms.pushPose(); + BlockPos offset = targetPosition.subtract(pos); + ms.translate(offset.getX(), offset.getY(), offset.getZ()); + + MutableBlockPos currentPos = targetPosition.mutable(); + + PartialModel assemblyOverlay = track.prepareAssemblyOverlay(level, targetPosition, trackState, direction, ms); + int colorWhenValid = 0x96B5FF; + int colorWhenCarriage = 0xCAFF96; + VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); + + currentPos.move(direction, 1); + ms.translate(0, 0, 1); + + for (int i = 0; i < be.assemblyLength; i++) { + int valid = be.isValidBogeyOffset(i) ? colorWhenValid : -1; + + for (int j : be.bogeyLocations) + if (i == j) { + valid = colorWhenCarriage; + break; + } + + if (valid != -1) { + int lightColor = LevelRenderer.getLightColor(level, currentPos); + SuperByteBuffer sbb = CachedPartialBuffers.partial(assemblyOverlay, trackState); + sbb.color(valid); + sbb.light(lightColor); + sbb.renderInto(ms, vb); + } + ms.translate(0, 0, 1); + currentPos.move(direction); + } + + ms.popPose(); + } + + public static void renderFlag(PartialModel flag, StationBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + if (!be.resolveFlagAngle()) + return; + SuperByteBuffer flagBB = CachedPartialBuffers.partial(flag, be.getBlockState()); + //transformFlag(flagBB, be, partialTicks, be.flagYRot, be.flagFlipped);//TODO flw + flagBB.translate(0.5f / 16, 0, 0) + .rotateY(be.flagFlipped ? 0 : 180) + .translate(-0.5f / 16, 0, 0) + .light(light) + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + } + + public static void transformFlag(Transform flag, StationBlockEntity be, float partialTicks, int yRot, + boolean flipped) { + float value = be.flag.getValue(partialTicks); + float progress = (float) (Math.pow(Math.min(value * 5, 1), 2)); + if (be.flag.getChaseTarget() > 0 && !be.flag.settled() && progress == 1) { + float wiggleProgress = (value - .2f) / .8f; + progress += (Math.sin(wiggleProgress * (2 * Mth.PI) * 4) / 8f) / Math.max(1, 8f * wiggleProgress); + } + + float nudge = 1 / 512f; + flag.centre() + .rotateY(yRot) + .translate(nudge, 9.5f / 16f, flipped ? 14f / 16f - nudge : 2f / 16f + nudge) + .unCentre() + .rotateX((flipped ? 1 : -1) * (progress * 90 + 270)); + } + + @Override + public boolean shouldRenderOffScreen(StationBlockEntity pBlockEntity) { + return true; + } + + @Override + public int getViewDistance() { + return 96 * 2; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationScreen.java b/src/main/java/com/simibubi/create/content/trains/station/StationScreen.java similarity index 75% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationScreen.java rename to src/main/java/com/simibubi/create/content/trains/station/StationScreen.java index 36570d6439..0121cd4a42 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationScreen.java +++ b/src/main/java/com/simibubi/create/content/trains/station/StationScreen.java @@ -1,23 +1,29 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; +package com.simibubi.create.content.trains.station; import java.lang.ref.WeakReference; import java.util.List; import java.util.function.Consumer; import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.trains.entity.Carriage; -import com.simibubi.create.content.logistics.trains.entity.Train; -import com.simibubi.create.content.logistics.trains.entity.TrainIconType; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.decoration.slidingDoor.DoorControl; +import com.simibubi.create.content.trains.entity.Carriage; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainIconType; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.widget.IconButton; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.UIRenderHelper; +import net.createmod.catnip.utility.Pair; import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.lang.Components; import net.minecraft.ChatFormatting; @@ -36,16 +42,18 @@ public class StationScreen extends AbstractStationScreen { private int leavingAnimation; private LerpedFloat trainPosition; + private DoorControl doorControl; private boolean switchingToAssemblyMode; - public StationScreen(StationTileEntity te, GlobalStation station) { - super(te, station); + public StationScreen(StationBlockEntity be, GlobalStation station) { + super(be, station); background = AllGuiTextures.STATION; leavingAnimation = 0; trainPosition = LerpedFloat.linear() .startWithValue(0); switchingToAssemblyMode = false; + doorControl = be.doorControls.mode; } @Override @@ -61,7 +69,7 @@ public class StationScreen extends AbstractStationScreen { Components.literal(station.name)); nameBox.setBordered(false); nameBox.setMaxLength(25); - nameBox.setTextColor(0x442000); + nameBox.setTextColor(0x592424); nameBox.setValue(station.name); nameBox.changeFocus(false); nameBox.mouseClicked(0, 0, 0); @@ -71,7 +79,7 @@ public class StationScreen extends AbstractStationScreen { Runnable assemblyCallback = () -> { switchingToAssemblyMode = true; - minecraft.setScreen(new AssemblyScreen(te, station)); + minecraft.setScreen(new AssemblyScreen(blockEntity, station)); }; newTrainButton = new WideIconButton(x + 84, y + 65, AllGuiTextures.I_NEW_TRAIN); @@ -87,8 +95,8 @@ public class StationScreen extends AbstractStationScreen { dropScheduleButton = new IconButton(x + 73, y + 65, AllIcons.I_VIEW_SCHEDULE); dropScheduleButton.active = false; dropScheduleButton.visible = false; - dropScheduleButton - .withCallback(() -> AllPackets.channel.sendToServer(StationEditPacket.dropSchedule(te.getBlockPos()))); + dropScheduleButton.withCallback(() -> AllPackets.getChannel() + .sendToServer(StationEditPacket.dropSchedule(blockEntity.getBlockPos()))); addRenderableWidget(dropScheduleButton); onTextChanged = s -> trainNameBox.x = nameBoxX(s, trainNameBox); @@ -102,6 +110,11 @@ public class StationScreen extends AbstractStationScreen { trainNameBox.active = false; tickTrainDisplay(); + + Pair doorControlWidgets = + DoorControl.createWidget(x + 35, y + 102, mode -> doorControl = mode, doorControl); + addRenderableWidget(doorControlWidgets.getFirst()); + addRenderableWidget(doorControlWidgets.getSecond()); } @Override @@ -120,9 +133,9 @@ public class StationScreen extends AbstractStationScreen { super.tick(); - updateAssemblyTooltip(te.edgePoint.isOnCurve() ? "no_assembly_curve" - : !te.edgePoint.isOrthogonal() ? "no_assembly_diagonal" - : trainPresent() && !te.trainCanDisassemble ? "train_not_aligned" : null); + updateAssemblyTooltip(blockEntity.edgePoint.isOnCurve() ? "no_assembly_curve" + : !blockEntity.edgePoint.isOrthogonal() ? "no_assembly_diagonal" + : trainPresent() && !blockEntity.trainCanDisassemble ? "train_not_aligned" : null); } private void tickTrainDisplay() { @@ -135,7 +148,7 @@ public class StationScreen extends AbstractStationScreen { } leavingAnimation = 0; - newTrainButton.active = te.edgePoint.isOrthogonal(); + newTrainButton.active = blockEntity.edgePoint.isOrthogonal(); newTrainButton.visible = true; Train imminentTrain = getImminent(); @@ -145,7 +158,7 @@ public class StationScreen extends AbstractStationScreen { newTrainButton.visible = false; disassembleTrainButton.active = false; disassembleTrainButton.visible = true; - dropScheduleButton.active = te.trainHasSchedule; + dropScheduleButton.active = blockEntity.trainHasSchedule; dropScheduleButton.visible = true; trainNameBox.active = true; @@ -191,12 +204,13 @@ public class StationScreen extends AbstractStationScreen { } boolean trainAtStation = trainPresent(); - disassembleTrainButton.active = trainAtStation && te.trainCanDisassemble && te.edgePoint.isOrthogonal(); - dropScheduleButton.active = te.trainHasSchedule; + disassembleTrainButton.active = + trainAtStation && blockEntity.trainCanDisassemble && blockEntity.edgePoint.isOrthogonal(); + dropScheduleButton.active = blockEntity.trainHasSchedule; - if (te.trainHasSchedule) - dropScheduleButton.setToolTip( - CreateLang.translateDirect(te.trainHasAutoSchedule ? "station.remove_auto_schedule" : "station.remove_schedule")); + if (blockEntity.trainHasSchedule) + dropScheduleButton.setToolTip(CreateLang.translateDirect( + blockEntity.trainHasAutoSchedule ? "station.remove_auto_schedule" : "station.remove_schedule")); else dropScheduleButton.getToolTip() .clear(); @@ -236,6 +250,8 @@ public class StationScreen extends AbstractStationScreen { if (!nameBox.isFocused()) AllGuiTextures.STATION_EDIT_NAME.render(ms, nameBoxX(text, nameBox) + font.width(text) + 5, y + 1); + itemRenderer.renderGuiItem(AllBlocks.TRAIN_DOOR.asStack(), x + 14, y + 103); + Train train = displayedTrain.get(); if (train == null) { MutableComponent header = CreateLang.translateDirect("station.idle"); @@ -255,11 +271,7 @@ public class StationScreen extends AbstractStationScreen { for (int i = carriages.size() - 1; i > 0; i--) { RenderSystem.setShaderColor(1, 1, 1, Math.min(1f, Math.min((position + offset - 10) / 30f, (background.getWidth() - 40 - position - offset) / 30f))); -// if (i == carriages.size() - 1 && train.doubleEnded) { -// offset += icon.render(TrainIconType.FLIPPED_ENGINE, ms, x + offset, y + 20) + 1; -// continue; -// } - Carriage carriage = carriages.get(te.trainBackwards ? carriages.size() - i - 1 : i); + Carriage carriage = carriages.get(blockEntity.trainBackwards ? carriages.size() - i - 1 : i); offset += icon.render(carriage.bogeySpacing, ms, x + offset, y + 20) + 1; } @@ -271,8 +283,8 @@ public class StationScreen extends AbstractStationScreen { RenderSystem.setShaderColor(1, 1, 1, 1); - UIRenderHelper.drawStretched(ms, x + 21, y + 43, 150, 46, -100, AllGuiTextures.STATION_TEXTBOX_MIDDLE); AllGuiTextures.STATION_TEXTBOX_TOP.render(ms, x + 21, y + 42); + UIRenderHelper.drawStretched(ms, x + 21, y + 60, 150, 26, 0, AllGuiTextures.STATION_TEXTBOX_MIDDLE); AllGuiTextures.STATION_TEXTBOX_BOTTOM.render(ms, x + 21, y + 86); ms.pushPose(); @@ -310,7 +322,8 @@ public class StationScreen extends AbstractStationScreen { @Override public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { - boolean hitEnter = getFocused() instanceof EditBox && (pKeyCode == 257 || pKeyCode == 335); + boolean hitEnter = getFocused() instanceof EditBox + && (pKeyCode == InputConstants.KEY_RETURN || pKeyCode == InputConstants.KEY_NUMPADENTER); if (hitEnter && nameBox.isFocused()) { nameBox.setFocus(false); @@ -331,32 +344,40 @@ public class StationScreen extends AbstractStationScreen { Train train = displayedTrain.get(); if (train != null && !trainNameBox.getValue() .equals(train.name.getString())) - AllPackets.channel.sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); } private void syncStationName() { if (!nameBox.getValue() .equals(station.name)) - AllPackets.channel.sendToServer(StationEditPacket.configure(te.getBlockPos(), false, nameBox.getValue())); + AllPackets.getChannel() + .sendToServer( + StationEditPacket.configure(blockEntity.getBlockPos(), false, nameBox.getValue(), doorControl)); } @Override public void removed() { super.removed(); - AllPackets.channel - .sendToServer(StationEditPacket.configure(te.getBlockPos(), switchingToAssemblyMode, nameBox.getValue())); + if (nameBox == null || trainNameBox == null) + return; + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), switchingToAssemblyMode, + nameBox.getValue(), doorControl)); Train train = displayedTrain.get(); if (train == null) return; if (!switchingToAssemblyMode) - AllPackets.channel.sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); else - te.imminentTrain = null; + blockEntity.imminentTrain = null; } @Override protected PartialModel getFlag(float partialTicks) { - return te.flag.getValue(partialTicks) > 0.75f ? AllBlockPartials.STATION_ON : AllBlockPartials.STATION_OFF; + return blockEntity.flag.getValue(partialTicks) > 0.75f ? AllPartialModels.STATION_ON + : AllPartialModels.STATION_OFF; } } diff --git a/src/main/java/com/simibubi/create/content/trains/station/TrainEditPacket.java b/src/main/java/com/simibubi/create/content/trains/station/TrainEditPacket.java new file mode 100644 index 0000000000..8fedf42aa8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/station/TrainEditPacket.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.trains.station; + +import java.util.UUID; + +import com.simibubi.create.AllPackets; +import com.simibubi.create.Create; +import com.simibubi.create.content.trains.entity.Train; +import com.simibubi.create.content.trains.entity.TrainIconType; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraftforge.network.NetworkEvent.Context; +import net.minecraftforge.network.PacketDistributor; + +public class TrainEditPacket extends SimplePacketBase { + + private String name; + private UUID id; + private ResourceLocation iconType; + + public TrainEditPacket(UUID id, String name, ResourceLocation iconType) { + this.name = name; + this.id = id; + this.iconType = iconType; + } + + public TrainEditPacket(FriendlyByteBuf buffer) { + id = buffer.readUUID(); + name = buffer.readUtf(256); + iconType = buffer.readResourceLocation(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeUUID(id); + buffer.writeUtf(name); + buffer.writeResourceLocation(iconType); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + Level level = sender == null ? null : sender.level; + Train train = Create.RAILWAYS.sided(level).trains.get(id); + if (train == null) + return; + if (!name.isBlank()) + train.name = Components.literal(name); + train.icon = TrainIconType.byId(iconType); + if (sender != null) + AllPackets.getChannel().send(PacketDistributor.ALL.noArg(), new TrainEditReturnPacket(id, name, iconType)); + }); + return true; + } + + public static class TrainEditReturnPacket extends TrainEditPacket { + + public TrainEditReturnPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + public TrainEditReturnPacket(UUID id, String name, ResourceLocation iconType) { + super(id, name, iconType); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/WideIconButton.java b/src/main/java/com/simibubi/create/content/trains/station/WideIconButton.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/WideIconButton.java rename to src/main/java/com/simibubi/create/content/trains/station/WideIconButton.java index 90f21aa034..8b26ce55cc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/WideIconButton.java +++ b/src/main/java/com/simibubi/create/content/trains/station/WideIconButton.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint.station; +package com.simibubi.create.content.trains.station; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.foundation.gui.AllGuiTextures; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java b/src/main/java/com/simibubi/create/content/trains/track/BezierConnection.java similarity index 85% rename from src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java rename to src/main/java/com/simibubi/create/content/trains/track/BezierConnection.java index ff3eb942ce..b001a22b3d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java +++ b/src/main/java/com/simibubi/create/content/trains/track/BezierConnection.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.track; import java.util.Iterator; @@ -6,10 +6,10 @@ import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack.Pose; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.logistics.trains.track.TrackRenderer; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction.Axis; @@ -24,6 +24,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; @@ -37,8 +38,10 @@ public class BezierConnection implements Iterable { public Couple starts; public Couple axes; public Couple normals; + public Couple smoothing; public boolean primary; public boolean hasGirder; + protected TrackMaterial trackMaterial; // runtime @@ -55,19 +58,47 @@ public class BezierConnection implements Iterable { private AABB bounds; public BezierConnection(Couple positions, Couple starts, Couple axes, Couple normals, - boolean primary, boolean girder) { + boolean primary, boolean girder, TrackMaterial material) { tePositions = positions; this.starts = starts; this.axes = axes; this.normals = normals; this.primary = primary; this.hasGirder = girder; + this.trackMaterial = material; resolved = false; } public BezierConnection secondary() { - return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, - hasGirder); + BezierConnection bezierConnection = new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), + normals.swap(), !primary, hasGirder, trackMaterial); + if (smoothing != null) + bezierConnection.smoothing = smoothing.swap(); + return bezierConnection; + } + + public BezierConnection clone() { + return secondary().secondary(); + } + + private static boolean coupleEquals(Couple a, Couple b) { + return (a.getFirst() + .equals(b.getFirst()) + && a.getSecond() + .equals(b.getSecond())) + || (a.getFirst() instanceof Vec3 aFirst && a.getSecond() instanceof Vec3 aSecond + && b.getFirst() instanceof Vec3 bFirst && b.getSecond() instanceof Vec3 bSecond + && aFirst.closerThan(bFirst, 1e-6) && aSecond.closerThan(bSecond, 1e-6)); + } + + public boolean equalsSansMaterial(BezierConnection other) { + return equalsSansMaterialInner(other) || equalsSansMaterialInner(other.secondary()); + } + + private boolean equalsSansMaterialInner(BezierConnection other) { + return this == other || (other != null && coupleEquals(this.tePositions, other.tePositions) + && coupleEquals(this.starts, other.starts) && coupleEquals(this.axes, other.axes) + && coupleEquals(this.normals, other.normals) && this.hasGirder == other.hasGirder); } public BezierConnection(CompoundTag compound, BlockPos localTo) { @@ -77,7 +108,11 @@ public class BezierConnection implements Iterable { .map(v -> v.add(Vec3.atLowerCornerOf(localTo))), Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), - compound.getBoolean("Primary"), compound.getBoolean("Girder")); + compound.getBoolean("Primary"), compound.getBoolean("Girder"), TrackMaterial.deserialize(compound.getString("Material"))); + + if (compound.contains("Smoothing")) + smoothing = + Couple.deserializeEach(compound.getList("Smoothing", Tag.TAG_COMPOUND), NBTHelper::intFromCompound); } public CompoundTag write(BlockPos localTo) { @@ -91,13 +126,20 @@ public class BezierConnection implements Iterable { compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound)); compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound)); compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound)); + compound.putString("Material", getMaterial().id.toString()); + + if (smoothing != null) + compound.put("Smoothing", smoothing.serializeEach(NBTHelper::intToCompound)); + return compound; } public BezierConnection(FriendlyByteBuf buffer) { this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), - buffer.readBoolean(), buffer.readBoolean()); + buffer.readBoolean(), buffer.readBoolean(), TrackMaterial.deserialize(buffer.readUtf())); + if (buffer.readBoolean()) + smoothing = Couple.create(buffer::readVarInt); } public void write(FriendlyByteBuf buffer) { @@ -107,6 +149,10 @@ public class BezierConnection implements Iterable { normals.forEach(v -> VecHelper.write(v, buffer)); buffer.writeBoolean(primary); buffer.writeBoolean(hasGirder); + buffer.writeUtf(getMaterial().id.toString()); + buffer.writeBoolean(smoothing != null); + if (smoothing != null) + smoothing.forEach(buffer::writeVarInt); } public BlockPos getKey() { @@ -117,6 +163,16 @@ public class BezierConnection implements Iterable { return primary; } + public int yOffsetAt(Vec3 end) { + if (smoothing == null) + return 0; + if (TrackBlockEntityTilt.compareHandles(starts.getFirst(), end)) + return smoothing.getFirst(); + if (TrackBlockEntityTilt.compareHandles(starts.getSecond(), end)) + return smoothing.getSecond(); + return 0; + } + // Runtime information public double getLength() { @@ -300,7 +356,7 @@ public class BezierConnection implements Iterable { Inventory inv = player.getInventory(); int tracks = getTrackItemCost(); while (tracks > 0) { - inv.placeItemBackInInventory(AllBlocks.TRACK.asStack(Math.min(64, tracks))); + inv.placeItemBackInInventory(new ItemStack(getMaterial().getBlock(), Math.min(64, tracks))); tracks -= 64; } int girders = getGirderItemCost(); @@ -328,7 +384,7 @@ public class BezierConnection implements Iterable { continue; Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f) .add(origin); - ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, AllBlocks.TRACK.asStack()); + ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, getMaterial().asStack()); entity.setDefaultPickUpDelay(); level.addFreshEntity(entity); if (!hasGirder) @@ -342,7 +398,7 @@ public class BezierConnection implements Iterable { } public void spawnDestroyParticles(Level level) { - BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.TRACK.getDefaultState()); + BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getBlock().defaultBlockState()); BlockParticleOption girderData = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState()); if (!(level instanceof ServerLevel slevel)) @@ -360,6 +416,14 @@ public class BezierConnection implements Iterable { } } + public TrackMaterial getMaterial() { + return trackMaterial; + } + + public void setMaterial(TrackMaterial material) { + trackMaterial = material; + } + public static class Segment { public int index; @@ -500,7 +564,7 @@ public class BezierConnection implements Iterable { .rotateYRadians(anglesI.y) .rotateXRadians(anglesI.x) .rotateZRadians(anglesI.z) - .translate(0, -2 / 16f + (i % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, -1 / 32f) + .translate(0, -2 / 16f - 1 / 256f, -1 / 32f) .scale(1, 1, (float) diff.length() * scale); angles.railTransforms.set(first, poseStack.last()); } diff --git a/src/main/java/com/simibubi/create/content/trains/track/BezierTrackPointLocation.java b/src/main/java/com/simibubi/create/content/trains/track/BezierTrackPointLocation.java new file mode 100644 index 0000000000..67b9047b18 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/BezierTrackPointLocation.java @@ -0,0 +1,6 @@ +package com.simibubi.create.content.trains.track; + +import net.minecraft.core.BlockPos; + +public record BezierTrackPointLocation(BlockPos curveTarget, int segment) { +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackDestroyPacket.java b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackDestroyPacket.java new file mode 100644 index 0000000000..35282aad9a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackDestroyPacket.java @@ -0,0 +1,92 @@ +package com.simibubi.create.content.trains.track; + +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; + +public class CurvedTrackDestroyPacket extends BlockEntityConfigurationPacket { + + private BlockPos targetPos; + private BlockPos soundSource; + private boolean wrench; + + public CurvedTrackDestroyPacket(BlockPos pos, BlockPos targetPos, BlockPos soundSource, boolean wrench) { + super(pos); + this.targetPos = targetPos; + this.soundSource = soundSource; + this.wrench = wrench; + } + + public CurvedTrackDestroyPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeBlockPos(targetPos); + buffer.writeBlockPos(soundSource); + buffer.writeBoolean(wrench); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + targetPos = buffer.readBlockPos(); + soundSource = buffer.readBlockPos(); + wrench = buffer.readBoolean(); + } + + @Override + protected void applySettings(ServerPlayer player, TrackBlockEntity be) { + int verifyDistance = AllConfigs.server().trains.maxTrackPlacementLength.get() * 4; + if (!be.getBlockPos() + .closerThan(player.blockPosition(), verifyDistance)) { + Create.LOGGER.warn(player.getScoreboardName() + " too far away from destroyed Curve track"); + return; + } + + Level level = be.getLevel(); + BezierConnection bezierConnection = be.getConnections() + .get(targetPos); + + be.removeConnection(targetPos); + if (level.getBlockEntity(targetPos)instanceof TrackBlockEntity other) + other.removeConnection(pos); + + BlockState blockState = be.getBlockState(); + TrackPropagator.onRailRemoved(level, pos, blockState); + + if (wrench) { + AllSoundEvents.WRENCH_REMOVE.playOnServer(player.level, soundSource, 1, + Create.RANDOM.nextFloat() * .5f + .5f); + if (!player.isCreative() && bezierConnection != null) + bezierConnection.addItemsToPlayer(player); + } else if (!player.isCreative() && bezierConnection != null) + bezierConnection.spawnItems(level); + + bezierConnection.spawnDestroyParticles(level); + SoundType soundtype = blockState.getSoundType(level, pos, player); + if (soundtype == null) + return; + + level.playSound(null, soundSource, soundtype.getBreakSound(), SoundSource.BLOCKS, + (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); + } + + @Override + protected int maxRange() { + return 64; + } + + @Override + protected void applySettings(TrackBlockEntity be) {} + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackInteraction.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java rename to src/main/java/com/simibubi/create/content/trains/track/CurvedTrackInteraction.java index bdb77bd18c..1b12cfe08b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/CurvedTrackInteraction.java +++ b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackInteraction.java @@ -1,10 +1,9 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.VecHelper; @@ -44,7 +43,7 @@ public class CurvedTrackInteraction { return; if (mc.options.keyAttack.isDown() && result != null) { - breakPos = result.te() + breakPos = result.blockEntity() .getBlockPos(); BlockState blockState = level.getBlockState(breakPos); if (blockState.isAir()) { @@ -74,7 +73,7 @@ public class CurvedTrackInteraction { player.swing(InteractionHand.MAIN_HAND); if (breakProgress >= 1) { - AllPackets.channel.sendToServer(new CurvedTrackDestroyPacket(breakPos, result.loc() + AllPackets.getChannel().sendToServer(new CurvedTrackDestroyPacket(breakPos, result.loc() .curveTarget(), new BlockPos(result.vec()), false)); resetBreakProgress(); } @@ -117,7 +116,7 @@ public class CurvedTrackInteraction { if (event.isUseItem()) { ItemStack heldItem = player.getMainHandItem(); Item item = heldItem.getItem(); - if (AllBlocks.TRACK.isIn(heldItem)) { + if (AllTags.AllBlockTags.TRACKS.matches(heldItem)) { player.displayClientMessage(CreateLang.translateDirect("track.turn_start") .withStyle(ChatFormatting.RED), true); player.swing(InteractionHand.MAIN_HAND); @@ -128,7 +127,7 @@ public class CurvedTrackInteraction { return true; } if (AllItems.WRENCH.isIn(heldItem) && player.isSteppingCarefully()) { - AllPackets.channel.sendToServer(new CurvedTrackDestroyPacket(result.te() + AllPackets.getChannel().sendToServer(new CurvedTrackDestroyPacket(result.blockEntity() .getBlockPos(), result.loc() .curveTarget(), diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/CurvedTrackSelectionPacket.java b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackSelectionPacket.java similarity index 82% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/CurvedTrackSelectionPacket.java rename to src/main/java/com/simibubi/create/content/trains/track/CurvedTrackSelectionPacket.java index 958e1bc4a9..ba1fadb488 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/CurvedTrackSelectionPacket.java +++ b/src/main/java/com/simibubi/create/content/trains/track/CurvedTrackSelectionPacket.java @@ -1,13 +1,12 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.track; import org.apache.commons.lang3.mutable.MutableObject; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem.OverlapResult; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; -import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.track.TrackTargetingBlockItem.OverlapResult; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; import com.simibubi.create.foundation.utility.CreateLang; import net.minecraft.ChatFormatting; @@ -18,7 +17,7 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; -public class CurvedTrackSelectionPacket extends TileEntityConfigurationPacket { +public class CurvedTrackSelectionPacket extends BlockEntityConfigurationPacket { private BlockPos targetPos; private boolean front; @@ -54,7 +53,7 @@ public class CurvedTrackSelectionPacket extends TileEntityConfigurationPacket type, BlockPos pos, BlockState state) { + super(type, pos, state); + keepAlive(); + } + + public void randomTick() { + keepAlive--; + if (keepAlive > 0) + return; + level.removeBlock(worldPosition, false); + } + + public void keepAlive() { + keepAlive = 3; + } + + +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/ITrackBlock.java b/src/main/java/com/simibubi/create/content/trains/track/ITrackBlock.java new file mode 100644 index 0000000000..4af5f1c88d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/ITrackBlock.java @@ -0,0 +1,193 @@ +package com.simibubi.create.content.trains.track; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.core.PartialModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface ITrackBlock { + + public Vec3 getUpNormal(BlockGetter world, BlockPos pos, BlockState state); + + public List getTrackAxes(BlockGetter world, BlockPos pos, BlockState state); + + public Vec3 getCurveStart(BlockGetter world, BlockPos pos, BlockState state, Vec3 axis); + + public default int getYOffsetAt(BlockGetter world, BlockPos pos, BlockState state, Vec3 end) { + return 0; + } + + public BlockState getBogeyAnchor(BlockGetter world, BlockPos pos, BlockState state); // should be on bogey side + + public boolean trackEquals(BlockState state1, BlockState state2); + + public default BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) { + return existing; + } + + public default double getElevationAtCenter(BlockGetter world, BlockPos pos, BlockState state) { + return isSlope(world, pos, state) ? .5 : 0; + } + + public static Collection walkConnectedTracks(BlockGetter worldIn, TrackNodeLocation location, + boolean linear) { + BlockGetter world = location != null && worldIn instanceof ServerLevel sl ? sl.getServer() + .getLevel(location.dimension) : worldIn; + List list = new ArrayList<>(); + for (BlockPos blockPos : location.allAdjacent()) { + BlockState blockState = world.getBlockState(blockPos); + if (blockState.getBlock()instanceof ITrackBlock track) + list.addAll(track.getConnected(world, blockPos, blockState, linear, location)); + } + return list; + } + + public default Collection getConnected(BlockGetter worldIn, BlockPos pos, BlockState state, + boolean linear, @Nullable TrackNodeLocation connectedTo) { + BlockGetter world = connectedTo != null && worldIn instanceof ServerLevel sl ? sl.getServer() + .getLevel(connectedTo.dimension) : worldIn; + Vec3 center = Vec3.atBottomCenterOf(pos) + .add(0, getElevationAtCenter(world, pos, state), 0); + List list = new ArrayList<>(); + TrackShape shape = state.getValue(TrackBlock.SHAPE); + List trackAxes = getTrackAxes(world, pos, state); + + trackAxes.forEach(axis -> { + BiFunction offsetFactory = (d, b) -> axis.scale(b ? d : -d) + .add(center); + Function> dimensionFactory = + b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD; + Function yOffsetFactory = v -> getYOffsetAt(world, pos, state, v); + + addToListIfConnected(connectedTo, list, offsetFactory, b -> shape.getNormal(), dimensionFactory, + yOffsetFactory, axis, null, (b, v) -> getMaterialSimple(world, v)); + }); + + return list; + } + + public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos) { + return getMaterialSimple(world, pos, TrackMaterial.ANDESITE); + } + + public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos, TrackMaterial defaultMaterial) { + if (defaultMaterial == null) + defaultMaterial = TrackMaterial.ANDESITE; + if (world != null) { + Block block = world.getBlockState(new BlockPos(pos)).getBlock(); + if (block instanceof ITrackBlock track) { + return track.getMaterial(); + } + } + return defaultMaterial; + } + + public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection list, + BiFunction offsetFactory, Function normalFactory, + Function> dimensionFactory, Function yOffsetFactory, Vec3 axis, + BezierConnection viaTurn, BiFunction materialFactory) { + + Vec3 firstOffset = offsetFactory.apply(0.5d, true); + DiscoveredLocation firstLocation = + new DiscoveredLocation(dimensionFactory.apply(true), firstOffset).viaTurn(viaTurn) + .materialA(materialFactory.apply(true, offsetFactory.apply(0.0d, true))) + .materialB(materialFactory.apply(true, offsetFactory.apply(1.0d, true))) + .withNormal(normalFactory.apply(true)) + .withDirection(axis) + .withYOffset(yOffsetFactory.apply(firstOffset)); + + Vec3 secondOffset = offsetFactory.apply(0.5d, false); + DiscoveredLocation secondLocation = + new DiscoveredLocation(dimensionFactory.apply(false), secondOffset).viaTurn(viaTurn) + .materialA(materialFactory.apply(false, offsetFactory.apply(0.0d, false))) + .materialB(materialFactory.apply(false, offsetFactory.apply(1.0d, false))) + .withNormal(normalFactory.apply(false)) + .withDirection(axis) + .withYOffset(yOffsetFactory.apply(secondOffset)); + + if (!firstLocation.dimension.equals(secondLocation.dimension)) { + firstLocation.forceNode(); + secondLocation.forceNode(); + } + + boolean skipFirst = false; + boolean skipSecond = false; + + if (fromEnd != null) { + boolean equalsFirst = firstLocation.equals(fromEnd); + boolean equalsSecond = secondLocation.equals(fromEnd); + + // not reachable from this end + if (!equalsFirst && !equalsSecond) + return; + + if (equalsFirst) + skipFirst = true; + if (equalsSecond) + skipSecond = true; + } + + if (!skipFirst) + list.add(firstLocation); + if (!skipSecond) + list.add(secondLocation); + } + + @OnlyIn(Dist.CLIENT) + public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state, + BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack transform, + RenderedTrackOverlayType type); + + @OnlyIn(Dist.CLIENT) + public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction, + PoseStack ms); + + public default boolean isSlope(BlockGetter world, BlockPos pos, BlockState state) { + return getTrackAxes(world, pos, state).get(0).y != 0; + } + + public default Pair getNearestTrackAxis(BlockGetter world, BlockPos pos, BlockState state, + Vec3 lookVec) { + Vec3 best = null; + double bestDiff = Double.MAX_VALUE; + for (Vec3 vec3 : getTrackAxes(world, pos, state)) { + for (int opposite : Iterate.positiveAndNegative) { + double distanceTo = vec3.normalize() + .distanceTo(lookVec.scale(opposite)); + if (distanceTo > bestDiff) + continue; + bestDiff = distanceTo; + best = vec3; + } + } + return Pair.of(best, lookVec.dot(best.multiply(1, 0, 1) + .normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE); + } + + TrackMaterial getMaterial(); + +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/PlaceExtendedCurvePacket.java b/src/main/java/com/simibubi/create/content/trains/track/PlaceExtendedCurvePacket.java new file mode 100644 index 0000000000..6fe153c668 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/PlaceExtendedCurvePacket.java @@ -0,0 +1,48 @@ +package com.simibubi.create.content.trains.track; + +import com.simibubi.create.AllTags; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent.Context; + +public class PlaceExtendedCurvePacket extends SimplePacketBase { + + boolean mainHand; + boolean ctrlDown; + + public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) { + this.mainHand = mainHand; + this.ctrlDown = ctrlDown; + } + + public PlaceExtendedCurvePacket(FriendlyByteBuf buffer) { + mainHand = buffer.readBoolean(); + ctrlDown = buffer.readBoolean(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeBoolean(mainHand); + buffer.writeBoolean(ctrlDown); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer sender = context.getSender(); + ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); + if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag()) + return; + CompoundTag tag = stack.getTag(); + tag.putBoolean("ExtendCurve", true); + stack.setTag(tag); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java similarity index 77% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java index b9c2ac0bc8..13e0be652b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import static com.simibubi.create.AllShapes.TRACK_ASC; import static com.simibubi.create.AllShapes.TRACK_CROSS; @@ -11,40 +11,44 @@ import static com.simibubi.create.AllShapes.TRACK_ORTHO_LONG; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; +import java.util.Set; import java.util.function.Consumer; +import org.jetbrains.annotations.Nullable; + import com.google.common.base.Predicates; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; import com.simibubi.create.AllShapes; -import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.particle.CubeParticleData; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.content.curiosities.girder.GirderBlock; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.TrackPropagator; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; -import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; -import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.content.decoration.girder.GirderBlock; +import com.simibubi.create.content.equipment.wrench.IWrenchable; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement.ItemUseType; +import com.simibubi.create.content.trains.CubeParticleData; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; +import com.simibubi.create.foundation.block.IBE; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; -import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler; +import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler; import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; import com.simibubi.create.foundation.utility.CreateLang; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.createmod.catnip.utility.BlockFace; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.Pair; @@ -53,7 +57,6 @@ import net.createmod.catnip.utility.lang.Components; import net.createmod.catnip.utility.math.AngleHelper; import net.minecraft.ChatFormatting; import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; @@ -105,21 +108,24 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.IBlockRenderProperties; public class TrackBlock extends Block - implements ITE, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock { + implements IBE, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock { public static final EnumProperty SHAPE = EnumProperty.create("shape", TrackShape.class); - public static final BooleanProperty HAS_TE = BooleanProperty.create("turn"); + public static final BooleanProperty HAS_BE = BooleanProperty.create("turn"); - public TrackBlock(Properties p_49795_) { + protected final TrackMaterial material; + + public TrackBlock(Properties p_49795_, TrackMaterial material) { super(p_49795_); registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO) - .setValue(HAS_TE, false) + .setValue(HAS_BE, false) .setValue(WATERLOGGED, false)); + this.material = material; } @Override protected void createBlockStateDefinition(Builder p_49915_) { - super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED)); + super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_BE, WATERLOGGED)); } @Override @@ -203,15 +209,15 @@ public class TrackBlock extends Block return; if (!pPlayer.isCreative()) return; - withTileEntityDo(pLevel, pPos, te -> { - te.cancelDrops = true; - te.removeInboundConnections(); + withBlockEntityDo(pLevel, pPos, be -> { + be.cancelDrops = true; + be.removeInboundConnections(true); }); } @Override public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) { - if (pOldState.getBlock() == this && pState.setValue(HAS_TE, true) == pOldState.setValue(HAS_TE, true)) + if (pOldState.getBlock() == this && pState.setValue(HAS_BE, true) == pOldState.setValue(HAS_BE, true)) return; if (pLevel.isClientSide) return; @@ -224,12 +230,13 @@ public class TrackBlock extends Block @Override public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) { super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); - withTileEntityDo(pLevel, pPos, TrackTileEntity::validateConnections); + withBlockEntityDo(pLevel, pPos, TrackBlockEntity::validateConnections); } @Override public void tick(BlockState state, ServerLevel level, BlockPos pos, Random p_60465_) { TrackPropagator.onRailAdded(level, pos, state); + withBlockEntityDo(level, pos, tbe -> tbe.tilt.undoSmoothing()); if (!state.getValue(SHAPE) .isPortal()) connectToNether(level, pos, state); @@ -270,16 +277,16 @@ public class TrackBlock extends Block } level.setBlock(pos, state.setValue(SHAPE, TrackShape.asPortal(d)) - .setValue(HAS_TE, true), 3); - BlockEntity te = level.getBlockEntity(pos); - if (te instanceof TrackTileEntity tte) - tte.bind(otherLevel.dimension(), otherTrackPos); + .setValue(HAS_BE, true), 3); + BlockEntity be = level.getBlockEntity(pos); + if (be instanceof TrackBlockEntity tbe) + tbe.bind(otherLevel.dimension(), otherTrackPos); otherLevel.setBlock(otherTrackPos, state.setValue(SHAPE, TrackShape.asPortal(otherTrack.getFace())) - .setValue(HAS_TE, true), 3); - BlockEntity otherTe = otherLevel.getBlockEntity(otherTrackPos); - if (otherTe instanceof TrackTileEntity tte) - tte.bind(level.dimension(), pos); + .setValue(HAS_BE, true), 3); + BlockEntity otherBE = otherLevel.getBlockEntity(otherTrackPos); + if (otherBE instanceof TrackBlockEntity tbe) + tbe.bind(level.dimension(), pos); pop = false; } @@ -294,12 +301,14 @@ public class TrackBlock extends Block Player player = level.getNearestPlayer(pos.getX(), pos.getY(), pos.getZ(), 10, Predicates.alwaysTrue()); if (player == null) return; - player.displayClientMessage(Components.literal(" ").append(CreateLang.translateDirect("portal_track.failed")) + player.displayClientMessage(Components.literal(" ") + .append(CreateLang.translateDirect("portal_track.failed")) .withStyle(ChatFormatting.GOLD), false); - MutableComponent component = - failPos != null ? CreateLang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ()) - : CreateLang.translateDirect("portal_track." + fail); - player.displayClientMessage(Components.literal(" - ").withStyle(ChatFormatting.GRAY) + MutableComponent component = failPos != null + ? CreateLang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ()) + : CreateLang.translateDirect("portal_track." + fail); + player.displayClientMessage(Components.literal(" - ") + .withStyle(ChatFormatting.GRAY) .append(component.withStyle(st -> st.withColor(0xFFD3B4))), false); } @@ -358,6 +367,12 @@ public class TrackBlock extends Block return state; } + @Override + public int getYOffsetAt(BlockGetter world, BlockPos pos, BlockState state, Vec3 end) { + return getBlockEntityOptional(world, pos).map(tbe -> tbe.tilt.getYOffsetForAxisEnd(end)) + .orElse(0); + } + @Override public Collection getConnected(BlockGetter worldIn, BlockPos pos, BlockState state, boolean linear, TrackNodeLocation connectedTo) { @@ -375,36 +390,37 @@ public class TrackBlock extends Block ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) .add(center), - b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis, - null); + b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, v -> 0, + axis, null, (b, v) -> ITrackBlock.getMaterialSimple(world, v)); } else list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); - if (!state.getValue(HAS_TE)) + if (!state.getValue(HAS_BE)) return list; if (linear) return list; BlockEntity blockEntity = world.getBlockEntity(pos); - if (!(blockEntity instanceof TrackTileEntity trackTE)) + if (!(blockEntity instanceof TrackBlockEntity trackBE)) return list; - Map connections = trackTE.getConnections(); + Map connections = trackBE.getConnections(); connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, - b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc)); + b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, bc::yOffsetAt, null, bc, + (b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial()))); - if (trackTE.boundLocation == null || !(world instanceof ServerLevel level)) + if (trackBE.boundLocation == null || !(world instanceof ServerLevel level)) return list; - ResourceKey otherDim = trackTE.boundLocation.getFirst(); + ResourceKey otherDim = trackBE.boundLocation.getFirst(); ServerLevel otherLevel = level.getServer() .getLevel(otherDim); if (otherLevel == null) return list; - BlockPos boundPos = trackTE.boundLocation.getSecond(); + BlockPos boundPos = trackBE.boundLocation.getSecond(); BlockState boundState = otherLevel.getBlockState(boundPos); - if (!AllBlocks.TRACK.has(boundState)) + if (!AllTags.AllBlockTags.TRACKS.matches(boundState)) return list; Vec3 center = Vec3.atBottomCenterOf(pos) @@ -418,7 +434,8 @@ public class TrackBlock extends Block getTrackAxes(world, pos, state).forEach(axis -> { ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d) .add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(), - b -> b ? level.dimension() : otherLevel.dimension(), axis, null); + b -> b ? level.dimension() : otherLevel.dimension(), v -> 0, axis, null, + (b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v)); }); return list; @@ -438,17 +455,19 @@ public class TrackBlock extends Block @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { - boolean removeTE = false; - if (pState.getValue(HAS_TE) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TE))) { + boolean removeBE = false; + if (pState.getValue(HAS_BE) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_BE))) { BlockEntity blockEntity = pLevel.getBlockEntity(pPos); - if (blockEntity instanceof TrackTileEntity && !pLevel.isClientSide) - ((TrackTileEntity) blockEntity).removeInboundConnections(); - removeTE = true; + if (blockEntity instanceof TrackBlockEntity tbe && !pLevel.isClientSide) { + tbe.cancelDrops |= pNewState.getBlock() == this; + tbe.removeInboundConnections(true); + } + removeBE = true; } - if (pNewState.getBlock() != this || pState.setValue(HAS_TE, true) != pNewState.setValue(HAS_TE, true)) + if (pNewState.getBlock() != this || pState.setValue(HAS_BE, true) != pNewState.setValue(HAS_BE, true)) TrackPropagator.onRailRemoved(pLevel, pPos, pState); - if (removeTE) + if (removeBE) pLevel.removeBlockEntity(pPos); if (!pLevel.isClientSide) updateGirders(pState, pLevel, pPos, pLevel.getBlockTicks()); @@ -460,12 +479,12 @@ public class TrackBlock extends Block if (world.isClientSide) return InteractionResult.SUCCESS; - for (Entry entry : StationTileEntity.assemblyAreas.get(world) + for (Entry entry : StationBlockEntity.assemblyAreas.get(world) .entrySet()) { if (!entry.getValue() .isInside(pos)) continue; - if (world.getBlockEntity(entry.getKey()) instanceof StationTileEntity station) + if (world.getBlockEntity(entry.getKey()) instanceof StationBlockEntity station) if (station.trackClicked(player, hand, this, state, pos)) return InteractionResult.SUCCESS; } @@ -561,19 +580,19 @@ public class TrackBlock extends Block @Override public BlockEntity newBlockEntity(BlockPos p_153215_, BlockState state) { - if (!state.getValue(HAS_TE)) + if (!state.getValue(HAS_BE)) return null; - return AllTileEntities.TRACK.create(p_153215_, state); + return AllBlockEntityTypes.TRACK.create(p_153215_, state); } @Override - public Class getTileEntityClass() { - return TrackTileEntity.class; + public Class getBlockEntityClass() { + return TrackBlockEntity.class; } @Override - public BlockEntityType getTileEntityType() { - return AllTileEntities.TRACK.get(); + public BlockEntityType getBlockEntityType() { + return AllBlockEntityTypes.TRACK.get(); } @Override @@ -605,11 +624,11 @@ public class TrackBlock extends Block public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { Player player = context.getPlayer(); Level level = context.getLevel(); - if (!level.isClientSide && !player.isCreative() && state.getValue(HAS_TE)) { + if (!level.isClientSide && !player.isCreative() && state.getValue(HAS_BE)) { BlockEntity blockEntity = level.getBlockEntity(context.getClickedPos()); - if (blockEntity instanceof TrackTileEntity trackTE) { - trackTE.cancelDrops = true; - trackTE.connections.values() + if (blockEntity instanceof TrackBlockEntity trackBE) { + trackBE.cancelDrops = true; + trackBE.connections.values() .forEach(bc -> bc.addItemsToPlayer(player)); } } @@ -672,7 +691,7 @@ public class TrackBlock extends Block PoseStack ms) { TransformStack.cast(ms) .rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(direction))); - return AllBlockPartials.TRACK_ASSEMBLING_OVERLAY; + return AllPartialModels.TRACK_ASSEMBLING_OVERLAY; } @Override @@ -686,8 +705,8 @@ public class TrackBlock extends Block Vec3 normal = null; Vec3 offset = null; - if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackTileEntity trackTE) { - BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget()); + if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackBlockEntity trackBE) { + BezierConnection bc = trackBE.connections.get(bezierPoint.curveTarget()); if (bc != null) { double length = Mth.floor(bc.getLength() * 2); int seg = bezierPoint.segment() + 1; @@ -731,39 +750,63 @@ public class TrackBlock extends Block msr.rotateCentered(Direction.UP, Mth.PI); } + if (bezierPoint == null && world.getBlockEntity(pos) instanceof TrackBlockEntity trackTE + && trackTE.isTilted()) { + double yOffset = 0; + for (BezierConnection bc : trackTE.connections.values()) + yOffset += bc.starts.getFirst().y - pos.getY(); + msr.centre() + .rotateX(-direction.getStep() * trackTE.tilt.smoothingAngle.get()) + .unCentre() + .translate(0, yOffset / 2, 0); + } + return switch (type) { - case DUAL_SIGNAL -> AllBlockPartials.TRACK_SIGNAL_DUAL_OVERLAY; - case OBSERVER -> AllBlockPartials.TRACK_OBSERVER_OVERLAY; - case SIGNAL -> AllBlockPartials.TRACK_SIGNAL_OVERLAY; - case STATION -> AllBlockPartials.TRACK_STATION_OVERLAY; + case DUAL_SIGNAL -> AllPartialModels.TRACK_SIGNAL_DUAL_OVERLAY; + case OBSERVER -> AllPartialModels.TRACK_OBSERVER_OVERLAY; + case SIGNAL -> AllPartialModels.TRACK_SIGNAL_OVERLAY; + case STATION -> AllPartialModels.TRACK_STATION_OVERLAY; }; } @Override public boolean trackEquals(BlockState state1, BlockState state2) { return state1.getBlock() == this && state2.getBlock() == this - && state1.setValue(HAS_TE, false) == state2.setValue(HAS_TE, false); + && state1.setValue(HAS_BE, false) == state2.setValue(HAS_BE, false); } @Override - public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { - int trackAmount = 1; + public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) { + int sameTypeTrackAmount = 1; + Object2IntMap otherTrackAmounts = new Object2IntArrayMap<>(); int girderAmount = 0; - if (te instanceof TrackTileEntity track) { + if (be instanceof TrackBlockEntity track) { for (BezierConnection bezierConnection : track.getConnections() .values()) { if (!bezierConnection.isPrimary()) continue; - trackAmount += bezierConnection.getTrackItemCost(); + TrackMaterial material = bezierConnection.getMaterial(); + if (material == getMaterial()) { + sameTypeTrackAmount += bezierConnection.getTrackItemCost(); + } else { + otherTrackAmounts.put(material, otherTrackAmounts.getOrDefault(material, 0) + 1); + } girderAmount += bezierConnection.getGirderItemCost(); } } List stacks = new ArrayList<>(); - while (trackAmount > 0) { - stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64))); - trackAmount -= 64; + while (sameTypeTrackAmount > 0) { + stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 64))); + sameTypeTrackAmount -= 64; + } + for (TrackMaterial material : otherTrackAmounts.keySet()) { + int amt = otherTrackAmounts.getOrDefault(material, 0); + while (amt > 0) { + stacks.add(material.asStack(Math.min(amt, 64))); + amt -= 64; + } } while (girderAmount > 0) { stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64))); @@ -773,15 +816,20 @@ public class TrackBlock extends Block return new ItemRequirement(ItemUseType.CONSUME, stacks); } - public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler { + @Override + public TrackMaterial getMaterial() { + return material; + } + + public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler { @Override - public boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos, - int progress, BlockState blockState) { + @Nullable + public Set getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress) { BlockEntity blockEntity = level.getBlockEntity(pos); - if (blockEntity instanceof TrackTileEntity track) - for (BlockPos trackPos : track.connections.keySet()) - renderer.destroyBlockProgress(pos.hashCode(), trackPos, progress); - return false; + if (blockEntity instanceof TrackBlockEntity track) { + return new HashSet<>(track.connections.keySet()); + } + return null; } } diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntity.java new file mode 100644 index 0000000000..cc999f3b85 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntity.java @@ -0,0 +1,446 @@ +package com.simibubi.create.content.trains.track; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.contraptions.ITransformableBlockEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.trains.graph.TrackNodeLocation; +import com.simibubi.create.foundation.block.ProperWaterloggedBlock; +import com.simibubi.create.foundation.blockEntity.IMergeableBE; +import com.simibubi.create.foundation.blockEntity.RemoveBlockEntityPacket; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap; +import net.minecraftforge.fml.DistExecutor; + +public class TrackBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity, IMergeableBE { + + Map connections; + boolean cancelDrops; + + public Pair, BlockPos> boundLocation; + public TrackBlockEntityTilt tilt; + + public TrackBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + connections = new HashMap<>(); + setLazyTickRate(100); + tilt = new TrackBlockEntityTilt(this); + } + + public Map getConnections() { + return connections; + } + + @Override + public void initialize() { + super.initialize(); + if (!level.isClientSide && hasInteractableConnections()) + registerToCurveInteraction(); + } + + @Override + public void tick() { + super.tick(); + tilt.undoSmoothing(); + } + + @Override + public void lazyTick() { + for (BezierConnection connection : connections.values()) + if (connection.isPrimary()) + manageFakeTracksAlong(connection, false); + } + + public void validateConnections() { + Set invalid = new HashSet<>(); + + for (Entry entry : connections.entrySet()) { + BlockPos key = entry.getKey(); + BezierConnection bc = entry.getValue(); + + if (!key.equals(bc.getKey()) || !worldPosition.equals(bc.tePositions.getFirst())) { + invalid.add(key); + continue; + } + + BlockState blockState = level.getBlockState(key); + if (blockState.getBlock()instanceof ITrackBlock trackBlock && !blockState.getValue(TrackBlock.HAS_BE)) + for (Vec3 v : trackBlock.getTrackAxes(level, key, blockState)) { + Vec3 bcEndAxis = bc.axes.getSecond(); + if (v.distanceTo(bcEndAxis) < 1 / 1024f || v.distanceTo(bcEndAxis.scale(-1)) < 1 / 1024f) + level.setBlock(key, blockState.setValue(TrackBlock.HAS_BE, true), 3); + } + + BlockEntity blockEntity = level.getBlockEntity(key); + if (!(blockEntity instanceof TrackBlockEntity trackBE) || blockEntity.isRemoved()) { + invalid.add(key); + continue; + } + + if (!trackBE.connections.containsKey(worldPosition)) { + trackBE.addConnection(bc.secondary()); + trackBE.tilt.tryApplySmoothing(); + } + } + + for (BlockPos blockPos : invalid) + removeConnection(blockPos); + } + + public void addConnection(BezierConnection connection) { + // don't replace existing connections with different materials + if (connections.containsKey(connection.getKey()) && connection.equalsSansMaterial(connections.get(connection.getKey()))) + return; + connections.put(connection.getKey(), connection); + level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); + notifyUpdate(); + + if (connection.isPrimary()) + manageFakeTracksAlong(connection, false); + } + + public void removeConnection(BlockPos target) { + if (isTilted()) + tilt.captureSmoothingHandles(); + + BezierConnection removed = connections.remove(target); + notifyUpdate(); + + if (removed != null) + manageFakeTracksAlong(removed, true); + + if (!connections.isEmpty() || getBlockState().getOptionalValue(TrackBlock.SHAPE) + .orElse(TrackShape.NONE) + .isPortal()) + return; + + BlockState blockState = level.getBlockState(worldPosition); + if (blockState.hasProperty(TrackBlock.HAS_BE)) + level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_BE, false)); + AllPackets.getChannel().send(packetTarget(), new RemoveBlockEntityPacket(worldPosition)); + } + + public void removeInboundConnections(boolean dropAndDiscard) { + for (BezierConnection bezierConnection : connections.values()) { + if (!(level.getBlockEntity(bezierConnection.getKey())instanceof TrackBlockEntity tbe)) + return; + tbe.removeConnection(bezierConnection.tePositions.getFirst()); + if (!dropAndDiscard) + continue; + if (!cancelDrops) + bezierConnection.spawnItems(level); + bezierConnection.spawnDestroyParticles(level); + } + if (dropAndDiscard) + AllPackets.getChannel().send(packetTarget(), new RemoveBlockEntityPacket(worldPosition)); + } + + public void bind(ResourceKey boundDimension, BlockPos boundLocation) { + this.boundLocation = Pair.of(boundDimension, boundLocation); + setChanged(); + } + + public boolean isTilted() { + return tilt.smoothingAngle.isPresent(); + } + + @Override + public void writeSafe(CompoundTag tag) { + super.writeSafe(tag); + writeTurns(tag, true); + } + + @Override + protected void write(CompoundTag tag, boolean clientPacket) { + super.write(tag, clientPacket); + writeTurns(tag, false); + if (isTilted()) + tag.putDouble("Smoothing", tilt.smoothingAngle.get()); + if (boundLocation == null) + return; + tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond())); + tag.putString("BoundDimension", boundLocation.getFirst() + .location() + .toString()); + } + + private void writeTurns(CompoundTag tag, boolean restored) { + ListTag listTag = new ListTag(); + for (BezierConnection bezierConnection : connections.values()) + listTag.add((restored ? tilt.restoreToOriginalCurve(bezierConnection.clone()) : bezierConnection) + .write(worldPosition)); + tag.put("Connections", listTag); + } + + @Override + protected void read(CompoundTag tag, boolean clientPacket) { + super.read(tag, clientPacket); + connections.clear(); + for (Tag t : tag.getList("Connections", Tag.TAG_COMPOUND)) { + if (!(t instanceof CompoundTag)) + return; + BezierConnection connection = new BezierConnection((CompoundTag) t, worldPosition); + connections.put(connection.getKey(), connection); + } + + boolean smoothingPreviously = tilt.smoothingAngle.isPresent(); + tilt.smoothingAngle = Optional.ofNullable(tag.contains("Smoothing") ? tag.getDouble("Smoothing") : null); + if (smoothingPreviously != tilt.smoothingAngle.isPresent() && clientPacket) { + requestModelDataUpdate(); + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 16); + } + + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); + + if (hasInteractableConnections()) + registerToCurveInteraction(); + else + removeFromCurveInteraction(); + + if (tag.contains("BoundLocation")) + boundLocation = Pair.of( + ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(tag.getString("BoundDimension"))), + NbtUtils.readBlockPos(tag.getCompound("BoundLocation"))); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getRenderBoundingBox() { + return INFINITE_EXTENT_AABB; + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void accept(BlockEntity other) { + if (other instanceof TrackBlockEntity track) + connections.putAll(track.connections); + validateConnections(); + level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); + } + + public boolean hasInteractableConnections() { + for (BezierConnection connection : connections.values()) + if (connection.isPrimary()) + return true; + return false; + } + + @Override + public void transform(StructureTransform transform) { + Map restoredConnections = new HashMap<>(); + for (Entry entry : connections.entrySet()) + restoredConnections.put(entry.getKey(), + tilt.restoreToOriginalCurve(tilt.restoreToOriginalCurve(entry.getValue() + .secondary()) + .secondary())); + connections = restoredConnections; + tilt.smoothingAngle = Optional.empty(); + + if (transform.rotationAxis != Axis.Y) + return; + + Map transformedConnections = new HashMap<>(); + for (Entry entry : connections.entrySet()) { + BezierConnection newConnection = entry.getValue(); + newConnection.normals.replace(transform::applyWithoutOffsetUncentered); + newConnection.axes.replace(transform::applyWithoutOffsetUncentered); + + BlockPos diff = newConnection.tePositions.getSecond() + .subtract(newConnection.tePositions.getFirst()); + newConnection.tePositions.setSecond(new BlockPos(Vec3.atCenterOf(newConnection.tePositions.getFirst()) + .add(transform.applyWithoutOffsetUncentered(Vec3.atLowerCornerOf(diff))))); + + Vec3 beVec = Vec3.atLowerCornerOf(worldPosition); + Vec3 teCenterVec = beVec.add(0.5, 0.5, 0.5); + Vec3 start = newConnection.starts.getFirst(); + Vec3 startToBE = start.subtract(teCenterVec); + Vec3 endToStart = newConnection.starts.getSecond() + .subtract(start); + startToBE = transform.applyWithoutOffsetUncentered(startToBE) + .add(teCenterVec); + endToStart = transform.applyWithoutOffsetUncentered(endToStart) + .add(startToBE); + + newConnection.starts.setFirst(new TrackNodeLocation(startToBE).getLocation()); + newConnection.starts.setSecond(new TrackNodeLocation(endToStart).getLocation()); + + BlockPos newTarget = newConnection.getKey(); + transformedConnections.put(newTarget, newConnection); + } + + connections = transformedConnections; + } + + @Override + public void invalidate() { + super.invalidate(); + if (level.isClientSide) + removeFromCurveInteraction(); + } + + @Override + public void remove() { + super.remove(); + + for (BezierConnection connection : connections.values()) + manageFakeTracksAlong(connection, true); + + if (boundLocation != null && level instanceof ServerLevel) { + ServerLevel otherLevel = level.getServer() + .getLevel(boundLocation.getFirst()); + if (otherLevel == null) + return; + if (AllTags.AllBlockTags.TRACKS.matches(otherLevel.getBlockState(boundLocation.getSecond()))) + otherLevel.destroyBlock(boundLocation.getSecond(), false); + } + } + + private void registerToCurveInteraction() { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerToCurveInteractionUnsafe); + } + + private void removeFromCurveInteraction() { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::removeFromCurveInteractionUnsafe); + } + + @Override + public IModelData getModelData() { + if (!isTilted()) + return super.getModelData(); + return new ModelDataMap.Builder() + .withInitial(TrackBlockEntityTilt.ASCENDING_PROPERTY, tilt.smoothingAngle.get()) + .build(); + } + + @OnlyIn(Dist.CLIENT) + private void registerToCurveInteractionUnsafe() { + TrackBlockOutline.TRACKS_WITH_TURNS.get(level) + .put(worldPosition, this); + } + + @OnlyIn(Dist.CLIENT) + private void removeFromCurveInteractionUnsafe() { + TrackBlockOutline.TRACKS_WITH_TURNS.get(level) + .remove(worldPosition); + } + + public void manageFakeTracksAlong(BezierConnection bc, boolean remove) { + Map, Double> yLevels = new HashMap<>(); + BlockPos tePosition = bc.tePositions.getFirst(); + Vec3 end1 = bc.starts.getFirst() + .subtract(Vec3.atLowerCornerOf(tePosition)) + .add(0, 3 / 16f, 0); + Vec3 end2 = bc.starts.getSecond() + .subtract(Vec3.atLowerCornerOf(tePosition)) + .add(0, 3 / 16f, 0); + Vec3 axis1 = bc.axes.getFirst(); + Vec3 axis2 = bc.axes.getSecond(); + + double handleLength = bc.getHandleLength(); + + Vec3 finish1 = axis1.scale(handleLength) + .add(end1); + Vec3 finish2 = axis2.scale(handleLength) + .add(end2); + + Vec3 faceNormal1 = bc.normals.getFirst(); + Vec3 faceNormal2 = bc.normals.getSecond(); + + int segCount = bc.getSegmentCount(); + float[] lut = bc.getStepLUT(); + + for (int i = 0; i < segCount; i++) { + float t = i == segCount ? 1 : i * lut[i] / segCount; + t += 0.5f / segCount; + + Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t); + Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t) + .normalize(); + Vec3 faceNormal = + faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2); + Vec3 normal = faceNormal.cross(derivative) + .normalize(); + Vec3 below = result.add(faceNormal.scale(-.25f)); + Vec3 rail1 = below.add(normal.scale(.05f)); + Vec3 rail2 = below.subtract(normal.scale(.05f)); + Vec3 railMiddle = rail1.add(rail2) + .scale(.5); + + for (Vec3 vec : new Vec3[] { railMiddle }) { + BlockPos pos = new BlockPos(vec); + Pair key = Pair.of(pos.getX(), pos.getZ()); + if (!yLevels.containsKey(key) || yLevels.get(key) > vec.y) + yLevels.put(key, vec.y); + } + } + + for (Entry, Double> entry : yLevels.entrySet()) { + double yValue = entry.getValue(); + int floor = Mth.floor(yValue); + BlockPos targetPos = new BlockPos(entry.getKey() + .getFirst(), floor, + entry.getKey() + .getSecond()); + targetPos = targetPos.offset(tePosition) + .above(1); + + BlockState stateAtPos = level.getBlockState(targetPos); + boolean present = AllBlocks.FAKE_TRACK.has(stateAtPos); + + if (remove) { + if (present) + level.removeBlock(targetPos, false); + continue; + } + + FluidState fluidState = stateAtPos.getFluidState(); + if (!fluidState.isEmpty() && !fluidState.isSourceOfType(Fluids.WATER)) + continue; + + if (!present && stateAtPos.getMaterial() + .isReplaceable()) + level.setBlock(targetPos, + ProperWaterloggedBlock.withWater(level, AllBlocks.FAKE_TRACK.getDefaultState(), targetPos), 3); + FakeTrackBlock.keepAlive(level, targetPos); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntityTilt.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntityTilt.java new file mode 100644 index 0000000000..1dab9b71b8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockEntityTilt.java @@ -0,0 +1,231 @@ +package com.simibubi.create.content.trains.track; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import com.simibubi.create.content.trains.graph.TrackNodeLocation; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.Pair; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.data.ModelProperty; + +public class TrackBlockEntityTilt { + + public static final ModelProperty ASCENDING_PROPERTY = new ModelProperty<>(); + + public Optional smoothingAngle; + private Couple> previousSmoothingHandles; + + private TrackBlockEntity blockEntity; + + public TrackBlockEntityTilt(TrackBlockEntity blockEntity) { + this.blockEntity = blockEntity; + smoothingAngle = Optional.empty(); + } + + public void tryApplySmoothing() { + if (smoothingAngle.isPresent()) + return; + + Couple discoveredSlopes = Couple.create(null, null); + Vec3 axis = null; + + BlockState blockState = blockEntity.getBlockState(); + BlockPos worldPosition = blockEntity.getBlockPos(); + Level level = blockEntity.getLevel(); + + if (!(blockState.getBlock()instanceof ITrackBlock itb)) + return; + List axes = itb.getTrackAxes(level, worldPosition, blockState); + if (axes.size() != 1) + return; + if (axes.get(0).y != 0) + return; + if (blockEntity.boundLocation != null) + return; + + for (BezierConnection bezierConnection : blockEntity.connections.values()) { + if (bezierConnection.starts.getFirst().y == bezierConnection.starts.getSecond().y) + continue; + Vec3 normedAxis = bezierConnection.axes.getFirst() + .normalize(); + + if (axis != null) { + if (discoveredSlopes.getSecond() != null) + return; + if (normedAxis.dot(axis) > -1 + 1 / 64.0) + return; + discoveredSlopes.setSecond(bezierConnection); + continue; + } + + axis = normedAxis; + discoveredSlopes.setFirst(bezierConnection); + } + + if (discoveredSlopes.either(Objects::isNull)) + return; + if (discoveredSlopes.getFirst().starts.getSecond().y > discoveredSlopes.getSecond().starts.getSecond().y) + discoveredSlopes = discoveredSlopes.swap(); + + Couple lowStarts = discoveredSlopes.getFirst().starts; + Couple highStarts = discoveredSlopes.getSecond().starts; + Vec3 lowestPoint = lowStarts.getSecond(); + Vec3 highestPoint = highStarts.getSecond(); + + if (lowestPoint.y > lowStarts.getFirst().y) + return; + if (highestPoint.y < highStarts.getFirst().y) + return; + + blockEntity.removeInboundConnections(false); + blockEntity.connections.clear(); + TrackPropagator.onRailRemoved(level, worldPosition, blockState); + + double hDistance = discoveredSlopes.getFirst() + .getLength() + + discoveredSlopes.getSecond() + .getLength(); + Vec3 baseAxis = discoveredSlopes.getFirst().axes.getFirst(); + double baseAxisLength = baseAxis.x != 0 && baseAxis.z != 0 ? Math.sqrt(2) : 1; + double vDistance = highestPoint.y - lowestPoint.y; + double m = vDistance / (hDistance); + + Vec3 diff = highStarts.getFirst() + .subtract(lowStarts.getFirst()); + boolean flipRotation = diff.dot(new Vec3(1, 0, 2).normalize()) <= 0; + smoothingAngle = Optional.of(Math.toDegrees(Mth.atan2(m, 1)) * (flipRotation ? -1 : 1)); + + int smoothingParam = Mth.clamp((int) (m * baseAxisLength * 16), 0, 15); + + Couple smoothingResult = Couple.create(0, smoothingParam); + Vec3 raisedOffset = diff.normalize() + .add(0, Mth.clamp(m, 0, 1 - 1 / 512.0), 0) + .normalize() + .scale(baseAxisLength); + + highStarts.setFirst(lowStarts.getFirst() + .add(raisedOffset)); + + boolean first = true; + for (BezierConnection bezierConnection : discoveredSlopes) { + int smoothingToApply = smoothingResult.get(first); + + if (bezierConnection.smoothing == null) + bezierConnection.smoothing = Couple.create(0, 0); + bezierConnection.smoothing.setFirst(smoothingToApply); + bezierConnection.axes.setFirst(bezierConnection.axes.getFirst() + .add(0, (first ? 1 : -1) * -m, 0) + .normalize()); + + first = false; + BlockPos otherPosition = bezierConnection.getKey(); + BlockState otherState = level.getBlockState(otherPosition); + if (!(otherState.getBlock() instanceof TrackBlock)) + continue; + level.setBlockAndUpdate(otherPosition, otherState.setValue(TrackBlock.HAS_BE, true)); + BlockEntity otherBE = level.getBlockEntity(otherPosition); + if (otherBE instanceof TrackBlockEntity tbe) { + blockEntity.addConnection(bezierConnection); + tbe.addConnection(bezierConnection.secondary()); + } + } + } + + public void captureSmoothingHandles() { + boolean first = true; + previousSmoothingHandles = Couple.create(null, null); + for (BezierConnection bezierConnection : blockEntity.connections.values()) { + previousSmoothingHandles.set(first, Pair.of(bezierConnection.starts.getFirst(), + bezierConnection.smoothing == null ? 0 : bezierConnection.smoothing.getFirst())); + first = false; + } + } + + public void undoSmoothing() { + if (smoothingAngle.isEmpty()) + return; + if (previousSmoothingHandles == null) + return; + if (blockEntity.connections.size() == 2) + return; + + BlockState blockState = blockEntity.getBlockState(); + BlockPos worldPosition = blockEntity.getBlockPos(); + Level level = blockEntity.getLevel(); + + List validConnections = new ArrayList<>(); + for (BezierConnection bezierConnection : blockEntity.connections.values()) { + BlockPos otherPosition = bezierConnection.getKey(); + BlockEntity otherBE = level.getBlockEntity(otherPosition); + if (otherBE instanceof TrackBlockEntity tbe && tbe.connections.containsKey(worldPosition)) + validConnections.add(bezierConnection); + } + + blockEntity.removeInboundConnections(false); + TrackPropagator.onRailRemoved(level, worldPosition, blockState); + blockEntity.connections.clear(); + smoothingAngle = Optional.empty(); + + for (BezierConnection bezierConnection : validConnections) { + blockEntity.addConnection(restoreToOriginalCurve(bezierConnection)); + + BlockPos otherPosition = bezierConnection.getKey(); + BlockState otherState = level.getBlockState(otherPosition); + if (!(otherState.getBlock() instanceof TrackBlock)) + continue; + level.setBlockAndUpdate(otherPosition, otherState.setValue(TrackBlock.HAS_BE, true)); + BlockEntity otherBE = level.getBlockEntity(otherPosition); + if (otherBE instanceof TrackBlockEntity tbe) + tbe.addConnection(bezierConnection.secondary()); + } + + blockEntity.notifyUpdate(); + previousSmoothingHandles = null; + TrackPropagator.onRailAdded(level, worldPosition, blockState); + } + + public BezierConnection restoreToOriginalCurve(BezierConnection bezierConnection) { + if (bezierConnection.smoothing != null) { + bezierConnection.smoothing.setFirst(0); + if (bezierConnection.smoothing.getFirst() == 0 && bezierConnection.smoothing.getSecond() == 0) + bezierConnection.smoothing = null; + } + Vec3 raisedStart = bezierConnection.starts.getFirst(); + bezierConnection.starts.setFirst(new TrackNodeLocation(raisedStart).getLocation()); + bezierConnection.axes.setFirst(bezierConnection.axes.getFirst() + .multiply(1, 0, 1) + .normalize()); + return bezierConnection; + } + + public int getYOffsetForAxisEnd(Vec3 end) { + if (smoothingAngle.isEmpty()) + return 0; + for (BezierConnection bezierConnection : blockEntity.connections.values()) + if (compareHandles(bezierConnection.starts.getFirst(), end)) + return bezierConnection.yOffsetAt(end); + if (previousSmoothingHandles == null) + return 0; + for (Pair handle : previousSmoothingHandles) + if (handle != null && compareHandles(handle.getFirst(), end)) + return handle.getSecond(); + return 0; + } + + public static boolean compareHandles(Vec3 handle1, Vec3 handle2) { + return new TrackNodeLocation(handle1).getLocation() + .multiply(1, 0, 1) + .distanceToSqr(new TrackNodeLocation(handle2).getLocation() + .multiply(1, 0, 1)) < 1 / 512f; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockItem.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackBlockItem.java index 9baf8a7285..0bc9af615c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockItem.java @@ -1,10 +1,10 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; -import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Pair; @@ -59,7 +59,7 @@ public class TrackBlockItem extends BlockItem { Vec3 lookAngle = player.getLookAngle(); if (!isFoil(stack)) { - if (state.getBlock()instanceof TrackBlock track && track.getTrackAxes(level, pos, state) + if (state.getBlock() instanceof TrackBlock track && track.getTrackAxes(level, pos, state) .size() > 1) { if (!level.isClientSide) player.displayClientMessage(CreateLang.translateDirect("track.junction_start") @@ -67,6 +67,13 @@ public class TrackBlockItem extends BlockItem { return InteractionResult.SUCCESS; } + if (level.getBlockEntity(pos) instanceof TrackBlockEntity tbe && tbe.isTilted()) { + if (!level.isClientSide) + player.displayClientMessage(CreateLang.translateDirect("track.turn_start") + .withStyle(ChatFormatting.RED), true); + return InteractionResult.SUCCESS; + } + if (select(level, pos, lookAngle, stack)) { level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1); return InteractionResult.SUCCESS; @@ -111,7 +118,7 @@ public class TrackBlockItem extends BlockItem { return InteractionResult.SUCCESS; stack = player.getMainHandItem(); - if (AllBlocks.TRACK.isIn(stack)) { + if (AllTags.AllBlockTags.TRACKS.matches(stack)) { stack.setTag(null); player.setItemInHand(pContext.getHand(), stack); } @@ -154,10 +161,10 @@ public class TrackBlockItem extends BlockItem { @OnlyIn(Dist.CLIENT) public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) { ItemStack stack = event.getItemStack(); - if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag()) + if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag()) return; if (Minecraft.getInstance().options.keySprint.isDown()) - AllPackets.channel + AllPackets.getChannel() .sendToServer(new PlaceExtendedCurvePacket(event.getHand() == InteractionHand.MAIN_HAND, true)); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockOutline.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackBlockOutline.java index 14baafb25b..6ebbb89c91 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockOutline.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockOutline.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import java.util.HashMap; import java.util.Map; @@ -8,9 +8,8 @@ import java.util.function.Consumer; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; -import com.simibubi.create.content.logistics.trains.BezierConnection; +import com.simibubi.create.AllTags; import com.simibubi.create.foundation.utility.RaycastHelper; import net.createmod.catnip.utility.Iterate; @@ -44,7 +43,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @EventBusSubscriber(Dist.CLIENT) public class TrackBlockOutline { - public static WorldAttached> TRACKS_WITH_TURNS = + public static WorldAttached> TRACKS_WITH_TURNS = new WorldAttached<>(w -> new HashMap<>()); public static BezierPointSelection result; @@ -66,10 +65,10 @@ public class TrackBlockOutline { AttributeInstance range = player.getAttribute(ForgeMod.REACH_DISTANCE.get()); Vec3 target = RaycastHelper.getTraceTarget(player, Math.min(maxRange, range.getValue()) + 1, origin); - Map turns = TRACKS_WITH_TURNS.get(mc.level); + Map turns = TRACKS_WITH_TURNS.get(mc.level); - for (TrackTileEntity te : turns.values()) { - for (BezierConnection bc : te.connections.values()) { + for (TrackBlockEntity be : turns.values()) { + for (BezierConnection bc : be.connections.values()) { if (!bc.isPrimary()) continue; @@ -125,7 +124,7 @@ public class TrackBlockOutline { .distanceToSqr(0, 0.25f, 0); BezierTrackPointLocation location = new BezierTrackPointLocation(bc.getKey(), i); - result = new BezierPointSelection(te, location, anchor, angles, diff.normalize()); + result = new BezierPointSelection(be, location, anchor, angles, diff.normalize()); } if (bestSegment != -1) @@ -142,7 +141,7 @@ public class TrackBlockOutline { } } - public static void drawCurveSelection(PoseStack ms, MultiBufferSource buffer) { + public static void drawCurveSelection(PoseStack ms, MultiBufferSource buffer, Vec3 camera) { Minecraft mc = Minecraft.getInstance(); if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) return; @@ -152,7 +151,8 @@ public class TrackBlockOutline { return; VertexConsumer vb = buffer.getBuffer(RenderType.lines()); - Vec3 vec = result.vec(); + Vec3 vec = result.vec() + .subtract(camera); Vec3 angles = result.angles(); TransformStack.cast(ms) .pushPose() @@ -161,7 +161,7 @@ public class TrackBlockOutline { .rotateXRadians(angles.x) .translate(-.5, -.125f, -.5); - boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); + boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem()); renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null); ms.popPose(); } @@ -189,18 +189,20 @@ public class TrackBlockOutline { ms.pushPose(); ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z); - boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem()); + boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem()); TrackShape shape = blockstate.getValue(TrackBlock.SHAPE); - boolean isJunction = shape.isJunction(); + boolean canConnectFrom = !shape.isJunction() + && !(mc.level.getBlockEntity(pos)instanceof TrackBlockEntity tbe && tbe.isTilted()); + walkShapes(shape, TransformStack.cast(ms), s -> { - renderShape(s, ms, vb, holdingTrack ? !isJunction : null); + renderShape(s, ms, vb, holdingTrack ? canConnectFrom : null); event.setCanceled(true); }); ms.popPose(); } - private static void renderShape(VoxelShape s, PoseStack ms, VertexConsumer vb, Boolean valid) { + public static void renderShape(VoxelShape s, PoseStack ms, VertexConsumer vb, Boolean valid) { PoseStack.Pose transform = ms.last(); s.forAllEdges((x1, y1, z1, x2, y2, z2) -> { float xDiff = (float) (x2 - x1); @@ -288,8 +290,8 @@ public class TrackBlockOutline { renderer.accept(LONG_ORTHO); } - public static record BezierPointSelection(TrackTileEntity te, BezierTrackPointLocation loc, Vec3 vec, Vec3 angles, - Vec3 direction) { + public static record BezierPointSelection(TrackBlockEntity blockEntity, BezierTrackPointLocation loc, Vec3 vec, + Vec3 angles, Vec3 direction) { } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockStateGenerator.java similarity index 94% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackBlockStateGenerator.java index a14da5a73a..81e1931c1d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlockStateGenerator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import com.simibubi.create.Create; import com.simibubi.create.foundation.data.SpecialBlockStateGen; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java b/src/main/java/com/simibubi/create/content/trains/track/TrackInstance.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackInstance.java index 1cc112a620..ca01799a1b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackInstance.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import java.util.ArrayList; import java.util.List; @@ -16,21 +16,20 @@ import com.jozufozu.flywheel.util.box.ImmutableBox; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack.Pose; -import com.simibubi.create.AllBlockPartials; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; -import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.content.trains.track.BezierConnection.GirderAngles; +import com.simibubi.create.content.trains.track.BezierConnection.SegmentAngles; import net.createmod.catnip.utility.Couple; import net.createmod.catnip.utility.Iterate; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; -public class TrackInstance extends BlockEntityInstance { +public class TrackInstance extends BlockEntityInstance { private List instances; - public TrackInstance(MaterialManager materialManager, TrackTileEntity track) { + public TrackInstance(MaterialManager materialManager, TrackBlockEntity track) { super(materialManager, track); update(); @@ -97,9 +96,7 @@ public class TrackInstance extends BlockEntityInstance { PoseStack pose = new PoseStack(); TransformStack.cast(pose) - .translate(getInstancePosition()) - .nudge((int) bc.tePositions.getFirst() - .asLong()); + .translate(getInstancePosition()); var mat = materialManager.cutout(RenderType.cutoutMipped()) .material(Materials.TRANSFORMED); @@ -112,11 +109,13 @@ public class TrackInstance extends BlockEntityInstance { leftLightPos = new BlockPos[segCount]; rightLightPos = new BlockPos[segCount]; - mat.getModel(AllBlockPartials.TRACK_TIE) + TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder(); + + mat.getModel(modelHolder.tie()) .createInstances(ties); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT) + mat.getModel(modelHolder.segment_left()) .createInstances(left); - mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT) + mat.getModel(modelHolder.segment_right()) .createInstances(right); SegmentAngles[] segments = bc.getBakedSegments(); @@ -184,9 +183,9 @@ public class TrackInstance extends BlockEntityInstance { beams = Couple.create(() -> new ModelData[segCount]); beamCaps = Couple.create(() -> Couple.create(() -> new ModelData[segCount])); lightPos = new BlockPos[segCount]; - beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_MIDDLE)::createInstances); - beamCaps.forEachWithContext((c, top) -> c.forEach(mat.getModel(top ? AllBlockPartials.GIRDER_SEGMENT_TOP - : AllBlockPartials.GIRDER_SEGMENT_BOTTOM)::createInstances)); + beams.forEach(mat.getModel(AllPartialModels.GIRDER_SEGMENT_MIDDLE)::createInstances); + beamCaps.forEachWithContext((c, top) -> c.forEach(mat.getModel(top ? AllPartialModels.GIRDER_SEGMENT_TOP + : AllPartialModels.GIRDER_SEGMENT_BOTTOM)::createInstances)); GirderAngles[] bakedGirders = bc.getBakedGirders(); for (int i = 1; i < bakedGirders.length; i++) { diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackMaterial.java b/src/main/java/com/simibubi/create/content/trains/track/TrackMaterial.java new file mode 100644 index 0000000000..0c8a3a10cf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackMaterial.java @@ -0,0 +1,170 @@ +package com.simibubi.create.content.trains.track; + +import static com.simibubi.create.content.trains.track.TrackMaterialFactory.make; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPartialModels; +import com.simibubi.create.Create; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class TrackMaterial { + public static final Map ALL = new HashMap<>(); + + public static final TrackMaterial ANDESITE = make(Create.asResource("andesite")) + .lang("Andesite") + .block(NonNullSupplier.lazy(() -> AllBlocks.TRACK)) + .particle(Create.asResource("block/palettes/stone_types/polished/andesite_cut_polished")) + .defaultModels() + .build(); + + public final ResourceLocation id; + public final String langName; + public final NonNullSupplier> trackBlock; + public final Ingredient sleeperIngredient; + public final Ingredient railsIngredient; + public final ResourceLocation particle; + public final TrackType trackType; + + @Nullable + private final TrackMaterial.TrackType.TrackBlockFactory customFactory; + + @OnlyIn(Dist.CLIENT) + protected TrackModelHolder modelHolder; + + @OnlyIn(Dist.CLIENT) + public TrackModelHolder getModelHolder() { + return modelHolder; + } + + public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier> trackBlock, + ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, + TrackType trackType, Supplier> modelHolder) { + this(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, modelHolder, null); + } + + public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier> trackBlock, + ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient, + TrackType trackType, Supplier> modelHolder, + @Nullable TrackType.TrackBlockFactory customFactory) { + this.id = id; + this.langName = langName; + this.trackBlock = trackBlock; + this.sleeperIngredient = sleeperIngredient; + this.railsIngredient = railsIngredient; + this.particle = particle; + this.trackType = trackType; + this.customFactory = customFactory; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = modelHolder.get().get()); + ALL.put(this.id, this); + } + + public NonNullSupplier getBlockSupplier() { + return this.trackBlock.get(); + } + + public TrackBlock getBlock() { + return getBlockSupplier().get(); + } + + public ItemStack asStack() { + return asStack(1); + } + + public ItemStack asStack(int count) { + return new ItemStack(getBlock(), count); + } + + public TrackBlock createBlock(BlockBehaviour.Properties properties) { + return (this.customFactory != null ? this.customFactory : this.trackType.factory) + .create(properties, this); + } + + public boolean isFromMod(String modId) { + return this.id.getNamespace().equals(modId); + } + + public static List allFromMod(String modid) { + return ALL.values().stream().filter(tm -> tm.isFromMod(modid)).toList(); + } + + public static List> allBlocksFromMod(String modid) { + List> list = new ArrayList<>(); + for (TrackMaterial material : allFromMod(modid)) { + list.add(material.getBlockSupplier()); + } + return list; + } + + public static List> allBlocks() { + List> list = new ArrayList<>(); + for (TrackMaterial material : ALL.values()) { + list.add(material.getBlockSupplier()); + } + return list; + } + + public String resourceName() { + return this.id.getPath(); + } + + public static TrackMaterial deserialize(String serializedName) { + if (serializedName.isBlank()) // Data migrating from 0.5 + return ANDESITE; + + ResourceLocation id = ResourceLocation.tryParse(serializedName); + if (ALL.containsKey(id)) + return ALL.get(id); + + Create.LOGGER.error("Failed to locate serialized track material: " + serializedName); + return ANDESITE; + } + + public static class TrackType { + @FunctionalInterface + public interface TrackBlockFactory { + TrackBlock create(BlockBehaviour.Properties properties, TrackMaterial material); + } + + public static final TrackType STANDARD = new TrackType(Create.asResource("standard"), TrackBlock::new); + + public final ResourceLocation id; + protected final TrackBlockFactory factory; + + public TrackType(ResourceLocation id, TrackBlockFactory factory) { + this.id = id; + this.factory = factory; + } + } + + public static TrackMaterial fromItem(Item item) { + if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ITrackBlock trackBlock) + return trackBlock.getMaterial(); + return TrackMaterial.ANDESITE; + } + + @OnlyIn(Dist.CLIENT) + public record TrackModelHolder(PartialModel tie, PartialModel segment_left, PartialModel segment_right) { + static final TrackModelHolder DEFAULT = new TrackModelHolder(AllPartialModels.TRACK_TIE, + AllPartialModels.TRACK_SEGMENT_LEFT, AllPartialModels.TRACK_SEGMENT_RIGHT); + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackMaterialFactory.java b/src/main/java/com/simibubi/create/content/trains/track/TrackMaterialFactory.java new file mode 100644 index 0000000000..67e048caa8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackMaterialFactory.java @@ -0,0 +1,141 @@ +package com.simibubi.create.content.trains.track; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.core.PartialModel; +import com.simibubi.create.AllTags; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.ItemLike; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; + +public class TrackMaterialFactory { + private final ResourceLocation id; + private String langName; + private NonNullSupplier> trackBlock; + private Ingredient sleeperIngredient = Ingredient.EMPTY; + private Ingredient railsIngredient = Ingredient.fromValues(Stream.of(new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/iron")), new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/zinc")))); + private ResourceLocation particle; + private TrackMaterial.TrackType trackType = TrackMaterial.TrackType.STANDARD; + + @Nullable + private TrackMaterial.TrackType.TrackBlockFactory customFactory = null; + + @OnlyIn(Dist.CLIENT) + private TrackMaterial.TrackModelHolder modelHolder; + @OnlyIn(Dist.CLIENT) + private PartialModel tieModel; + @OnlyIn(Dist.CLIENT) + private PartialModel leftSegmentModel; + @OnlyIn(Dist.CLIENT) + private PartialModel rightSegmentModel; + + public TrackMaterialFactory(ResourceLocation id) { + this.id = id; + } + + public static TrackMaterialFactory make(ResourceLocation id) { // Convenience function for static import + return new TrackMaterialFactory(id); + } + + public TrackMaterialFactory lang(String langName) { + this.langName = langName; + return this; + } + + public TrackMaterialFactory block(NonNullSupplier> trackBlock) { + this.trackBlock = trackBlock; + return this; + } + + public TrackMaterialFactory defaultModels() { // was setBuiltin + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = TrackMaterial.TrackModelHolder.DEFAULT); + return this; + } + + public TrackMaterialFactory sleeper(Ingredient sleeperIngredient) { + this.sleeperIngredient = sleeperIngredient; + return this; + } + + public TrackMaterialFactory sleeper(ItemLike... items) { + this.sleeperIngredient = Ingredient.of(items); + return this; + } + + public TrackMaterialFactory rails(Ingredient railsIngredient) { + this.railsIngredient = railsIngredient; + return this; + } + + public TrackMaterialFactory rails(ItemLike... items) { + this.railsIngredient = Ingredient.of(items); + return this; + } + + public TrackMaterialFactory noRecipeGen() { + this.railsIngredient = Ingredient.EMPTY; + this.sleeperIngredient = Ingredient.EMPTY; + return this; + } + + public TrackMaterialFactory particle(ResourceLocation particle) { + this.particle = particle; + return this; + } + + public TrackMaterialFactory trackType(TrackMaterial.TrackType trackType) { + this.trackType = trackType; + return this; + } + + public TrackMaterialFactory standardModels() { // was defaultModels + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + String namespace = id.getNamespace(); + String prefix = "block/track/" + id.getPath() + "/"; + tieModel = new PartialModel(new ResourceLocation(namespace, prefix + "tie")); + leftSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_left")); + rightSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_right")); + }); + return this; + } + + public TrackMaterialFactory customModels(Supplier> tieModel, Supplier> leftSegmentModel, Supplier> rightSegmentModel) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + this.tieModel = tieModel.get().get(); + this.leftSegmentModel = leftSegmentModel.get().get(); + this.rightSegmentModel = rightSegmentModel.get().get(); + }); + return this; + } + + public TrackMaterialFactory customBlockFactory(TrackMaterial.TrackType.TrackBlockFactory factory) { + this.customFactory = factory; + return this; + } + + public TrackMaterial build() { + assert trackBlock != null; + assert langName != null; + assert particle != null; + assert trackType != null; + assert sleeperIngredient != null; + assert railsIngredient != null; + assert id != null; + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { + assert modelHolder != null; + if (tieModel != null || leftSegmentModel != null || rightSegmentModel != null) { + assert tieModel != null && leftSegmentModel != null && rightSegmentModel != null; + modelHolder = new TrackMaterial.TrackModelHolder(tieModel, leftSegmentModel, rightSegmentModel); + } + }); + return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder, customFactory); + } +} diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackModel.java b/src/main/java/com/simibubi/create/content/trains/track/TrackModel.java new file mode 100644 index 0000000000..7214da05ca --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackModel.java @@ -0,0 +1,78 @@ +package com.simibubi.create.content.trains.track; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.function.UnaryOperator; + +import com.simibubi.create.foundation.model.BakedQuadHelper; + +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.BakedModelWrapper; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.ModelDataMap; + +public class TrackModel extends BakedModelWrapper { + + public TrackModel(BakedModel originalModel) { + super(originalModel); + } + + @Override + public List getQuads(BlockState state, Direction side, Random rand, IModelData extraData) { + List templateQuads = super.getQuads(state, side, rand, extraData); + if (templateQuads.isEmpty()) + return templateQuads; + if (!(extraData instanceof ModelDataMap mdm) || !mdm.hasProperty(TrackBlockEntityTilt.ASCENDING_PROPERTY)) + return templateQuads; + + double angleIn = mdm.getData(TrackBlockEntityTilt.ASCENDING_PROPERTY); + double angle = Math.abs(angleIn); + boolean flip = angleIn < 0; + + TrackShape trackShape = state.getValue(TrackBlock.SHAPE); + double hAngle = switch (trackShape) { + case XO -> 0; + case PD -> 45; + case ZO -> 90; + case ND -> 135; + default -> 0; + }; + + Vec3 verticalOffset = new Vec3(0, -0.25, 0); + Vec3 diagonalRotationPoint = + (trackShape == TrackShape.ND || trackShape == TrackShape.PD) ? new Vec3((Mth.SQRT_OF_TWO - 1) / 2, 0, 0) + : Vec3.ZERO; + + UnaryOperator transform = v -> { + v = v.add(verticalOffset); + v = VecHelper.rotateCentered(v, hAngle, Axis.Y); + v = v.add(diagonalRotationPoint); + v = VecHelper.rotate(v, angle, Axis.Z); + v = v.subtract(diagonalRotationPoint); + v = VecHelper.rotateCentered(v, -hAngle + (flip ? 180 : 0), Axis.Y); + v = v.subtract(verticalOffset); + return v; + }; + + int size = templateQuads.size(); + List quads = new ArrayList<>(); + for (int i = 0; i < size; i++) { + BakedQuad quad = BakedQuadHelper.clone(templateQuads.get(i)); + int[] vertexData = quad.getVertices(); + for (int j = 0; j < 4; j++) + BakedQuadHelper.setXYZ(vertexData, j, transform.apply(BakedQuadHelper.getXYZ(vertexData, j))); + quads.add(quad); + } + + return quads; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java b/src/main/java/com/simibubi/create/content/trains/track/TrackPaver.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackPaver.java index ffa2745329..4c484379ac 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackPaver.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import java.util.HashMap; import java.util.HashSet; @@ -7,8 +7,7 @@ import java.util.Map.Entry; import java.util.Set; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.curiosities.girder.GirderBlock; -import com.simibubi.create.content.logistics.trains.BezierConnection; +import com.simibubi.create.content.decoration.girder.GirderBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import net.createmod.catnip.utility.Iterate; @@ -124,7 +123,7 @@ public class TrackPaver { float[] lut = bc.getStepLUT(); for (int i = 0; i < segCount; i++) { - float t = i * lut[i] / segCount; + float t = i == segCount ? 1 : i * lut[i] / segCount; t += 0.5f / segCount; Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/trains/track/TrackPlacement.java similarity index 88% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackPlacement.java index 5aae156624..b61d08d0b8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackPlacement.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import java.util.ArrayList; import java.util.Collection; @@ -7,14 +7,12 @@ import java.util.List; import java.util.Set; import com.jozufozu.flywheel.util.Color; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSpecialTextures; -import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.foundation.advancement.AllAdvancements; +import com.simibubi.create.AllTags; +import com.simibubi.create.content.equipment.blueprint.BlueprintOverlayRenderer; import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.CatnipClient; import net.createmod.catnip.utility.Couple; @@ -46,6 +44,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult.Type; @@ -57,6 +56,11 @@ import net.minecraftforge.items.ItemHandlerHelper; public class TrackPlacement { public static class PlacementInfo { + + public PlacementInfo(TrackMaterial material) { + this.trackMaterial = material; + } + BezierConnection curve = null; boolean valid = false; int end1Extent = 0; @@ -68,6 +72,7 @@ public class TrackPlacement { public int requiredPavement = 0; public boolean hasRequiredPavement = false; + public final TrackMaterial trackMaterial; // for visualisation Vec3 end1; @@ -97,16 +102,19 @@ public class TrackPlacement { static int hoveringAngle; static ItemStack lastItem; + static int extraTipWarmup; + public static PlacementInfo tryConnect(Level level, Player player, BlockPos pos2, BlockState state2, ItemStack stack, boolean girder, boolean maximiseTurn) { Vec3 lookVec = player.getLookAngle(); int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8; + int maxLength = AllConfigs.server().trains.maxTrackPlacementLength.get(); if (level.isClientSide && cached != null && pos2.equals(hoveringPos) && stack.equals(lastItem) && hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle) return cached; - PlacementInfo info = new PlacementInfo(); + PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem())); hoveringMaxed = maximiseTurn; hoveringAngle = lookAngle; hoveringPos = pos2; @@ -143,11 +151,13 @@ public class TrackPlacement { if (pos1.equals(pos2)) return info.withMessage("second_point"); - if (pos1.distSqr(pos2) > 32 * 32) + if (pos1.distSqr(pos2) > maxLength * maxLength) return info.withMessage("too_far") .tooJumbly(); - if (!state1.hasProperty(TrackBlock.HAS_TE)) + if (!state1.hasProperty(TrackBlock.HAS_BE)) return info.withMessage("original_missing"); + if (level.getBlockEntity(pos2) instanceof TrackBlockEntity tbe && tbe.isTilted()) + return info.withMessage("turn_start"); if (axis1.dot(end2.subtract(end1)) < 0) { axis1 = axis1.scale(-1); @@ -190,7 +200,7 @@ public class TrackPlacement { BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z); info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), true, girder); + Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem())); } // S curve or Straight @@ -215,7 +225,7 @@ public class TrackPlacement { info.end1Extent = (int) Math.round((dist + 1) / axis1.length()); } else { - if (!Mth.equal(ascend, 0)) + if (!Mth.equal(ascend, 0) || normedAxis1.y != 0) return info.withMessage("ascending_s_curve"); double targetT = u <= 1 ? 3 : u * 2; @@ -350,7 +360,7 @@ public class TrackPlacement { info.curve = skipCurve ? null : new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), true, girder); + Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem())); info.valid = true; @@ -395,7 +405,7 @@ public class TrackPlacement { continue; ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i); - boolean isTrack = AllBlocks.TRACK.isIn(stackInSlot); + boolean isTrack = AllTags.AllBlockTags.TRACKS.matches(stackInSlot) && stackInSlot.is(stack.getItem()); if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem())) continue; if (isTrack ? foundTracks >= tracks : foundPavement >= pavement) @@ -443,10 +453,6 @@ public class TrackPlacement { BlockItem paveItem = (BlockItem) offhandItem.getItem(); paveTracks(level, info, paveItem, false); } - - if (info.curve != null && info.curve.getLength() > 29) - AllAdvancements.LONG_BEND.awardTo(player); - return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false); } @@ -472,6 +478,18 @@ public class TrackPlacement { info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited); } + private static BlockState copyProperties(BlockState from, BlockState onto) { + for (Property property : onto.getProperties()) { + if (from.hasProperty(property)) + onto = onto.setValue(property, from.getValue(property)); + } + return onto; + } + + private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) { + return keepFrom ? from : copyProperties(from, onto); + } + private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2, BlockPos targetPos1, BlockPos targetPos2, boolean simulate) { info.requiredTracks = 0; @@ -481,8 +499,8 @@ public class TrackPlacement { Vec3 axis = first ? info.axis1 : info.axis2; BlockPos pos = first ? info.pos1 : info.pos2; BlockState state = first ? state1 : state2; - if (state.hasProperty(TrackBlock.HAS_TE) && !simulate) - state = state.setValue(TrackBlock.HAS_TE, false); + if (state.hasProperty(TrackBlock.HAS_BE) && !simulate) + state = state.setValue(TrackBlock.HAS_BE, false); switch (state.getValue(TrackBlock.SHAPE)) { case TE, TW: @@ -499,7 +517,8 @@ public class TrackPlacement { Vec3 offset = axis.scale(i); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockState stateAtPos = level.getBlockState(offsetPos); - BlockState toPlace = state; + // copy over all shared properties from the shaped state to the correct track material block + BlockState toPlace = copyProperties(state, info.trackMaterial.getBlock().defaultBlockState()); boolean canPlace = stateAtPos.getMaterial() .isReplaceable(); @@ -522,28 +541,29 @@ public class TrackPlacement { return info; if (!simulate) { + BlockState onto = info.trackMaterial.getBlock().defaultBlockState(); BlockState stateAtPos = level.getBlockState(targetPos1); level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TE, true), - targetPos1), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto)) + .setValue(TrackBlock.HAS_BE, true), targetPos1), 3); stateAtPos = level.getBlockState(targetPos2); level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level, - (stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TE, true), - targetPos2), 3); + (AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto)) + .setValue(TrackBlock.HAS_BE, true), targetPos2), 3); } BlockEntity te1 = level.getBlockEntity(targetPos1); BlockEntity te2 = level.getBlockEntity(targetPos2); int requiredTracksForTurn = (info.curve.getSegmentCount() + 1) / 2; - if (!(te1 instanceof TrackTileEntity) || !(te2 instanceof TrackTileEntity)) { + if (!(te1 instanceof TrackBlockEntity) || !(te2 instanceof TrackBlockEntity)) { info.requiredTracks += requiredTracksForTurn; return info; } - TrackTileEntity tte1 = (TrackTileEntity) te1; - TrackTileEntity tte2 = (TrackTileEntity) te2; + TrackBlockEntity tte1 = (TrackBlockEntity) te1; + TrackBlockEntity tte2 = (TrackBlockEntity) te2; if (!tte1.getConnections() .containsKey(tte2.getBlockPos())) @@ -554,6 +574,8 @@ public class TrackPlacement { tte1.addConnection(info.curve); tte2.addConnection(info.curve.secondary()); + tte1.tilt.tryApplySmoothing(); + tte2.tilt.tryApplySmoothing(); return info; } @@ -570,6 +592,8 @@ public class TrackPlacement { LocalPlayer player = Minecraft.getInstance().player; ItemStack stack = player.getMainHandItem(); HitResult hitResult = Minecraft.getInstance().hitResult; + int restoreWarmup = extraTipWarmup; + extraTipWarmup = 0; if (hitResult == null) return; @@ -577,10 +601,10 @@ public class TrackPlacement { return; InteractionHand hand = InteractionHand.MAIN_HAND; - if (!AllBlocks.TRACK.isIn(stack)) { + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) { stack = player.getOffhandItem(); hand = InteractionHand.OFF_HAND; - if (!AllBlocks.TRACK.isIn(stack)) + if (!AllTags.AllBlockTags.TRACKS.matches(stack)) return; } @@ -603,8 +627,14 @@ public class TrackPlacement { if (!(hitState.getBlock() instanceof TrackBlock)) return; + extraTipWarmup = restoreWarmup; boolean maxTurns = Minecraft.getInstance().options.keySprint.isDown(); PlacementInfo info = tryConnect(level, player, pos, hitState, stack, false, maxTurns); + if (extraTipWarmup < 20) + extraTipWarmup++; + if (!info.valid || !hoveringMaxed && (info.end1Extent == 0 || info.end2Extent == 0)) + extraTipWarmup = 0; + if (!player.isCreative() && (info.valid || !info.hasRequiredTracks || !info.hasRequiredPavement)) BlueprintOverlayRenderer.displayTrackRequirements(info, player.getOffhandItem()); @@ -724,13 +754,13 @@ public class TrackPlacement { .showLine(Pair.of(key, i * 2), VecHelper.lerp(s, middle1, previous1), VecHelper.lerp(s, middle1, rail1)) .colored(railcolor) - .disableNormals() + .disableLineNormals() .lineWidth(lw); CatnipClient.OUTLINER .showLine(Pair.of(key, i * 2 + 1), VecHelper.lerp(s, middle2, previous2), VecHelper.lerp(s, middle2, rail2)) .colored(railcolor) - .disableNormals() + .disableLineNormals() .lineWidth(lw); } @@ -751,7 +781,7 @@ public class TrackPlacement { int color = Color.mixColors(0xEA5C2B, 0x95CD41, animation.getValue()); CatnipClient.OUTLINER.showLine(Pair.of("start", id), v1.subtract(o1), v1.add(ex)) .lineWidth(1 / 8f) - .disableNormals() + .disableLineNormals() .colored(color); } diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackPlacementOverlay.java b/src/main/java/com/simibubi/create/content/trains/track/TrackPlacementOverlay.java new file mode 100644 index 0000000000..58b40da4f4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackPlacementOverlay.java @@ -0,0 +1,57 @@ +package com.simibubi.create.content.trains.track; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; +import net.minecraft.world.level.GameType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.gui.ForgeIngameGui; +import net.minecraftforge.client.gui.IIngameOverlay; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; + +public class TrackPlacementOverlay { + + @OnlyIn(Dist.CLIENT) + public static final IIngameOverlay OVERLAY = TrackPlacementOverlay::renderOverlay; + + @OnlyIn(Dist.CLIENT) + public static void renderOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, + int height) { + Minecraft mc = Minecraft.getInstance(); + if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) + return; + if (TrackPlacement.hoveringPos == null) + return; + if (TrackPlacement.cached == null || TrackPlacement.cached.curve == null || !TrackPlacement.cached.valid) + return; + if (TrackPlacement.extraTipWarmup < 4) + return; + + if (ObfuscationReflectionHelper.getPrivateValue(Gui.class, gui, + "f_92993_") instanceof Integer toolHighlightTimer && toolHighlightTimer > 0) + return; + + boolean active = mc.options.keySprint.isDown(); + MutableComponent text = CreateLang.translateDirect("track.hold_for_smooth_curve", Components.keybind("key.sprint") + .withStyle(active ? ChatFormatting.WHITE : ChatFormatting.GRAY)); + + Window window = mc.getWindow(); + int x = (window.getGuiScaledWidth() - gui.getFont() + .width(text)) / 2; + int y = window.getGuiScaledHeight() - 61; + Color color = new Color(0x4ADB4A).setAlpha(Mth.clamp((TrackPlacement.extraTipWarmup - 4) / 3f, 0.1f, 1)); + gui.getFont() + .draw(poseStack, text, x, y, color.getRGB()); + + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/trains/track/TrackPropagator.java similarity index 91% rename from src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackPropagator.java index 02cbba4c1d..c94c8014e4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackPropagator.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains; +package com.simibubi.create.content.trains.track; import java.util.ArrayList; import java.util.Collection; @@ -8,14 +8,20 @@ import java.util.List; import java.util.Set; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalPropagator; +import com.simibubi.create.api.event.TrackGraphMergeEvent; +import com.simibubi.create.content.trains.GlobalRailwayManager; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphSync; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation; +import com.simibubi.create.content.trains.signal.SignalPropagator; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; public class TrackPropagator { @@ -32,7 +38,7 @@ public class TrackPropagator { } public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) { - if (!(state.getBlock()instanceof ITrackBlock track)) + if (!(state.getBlock() instanceof ITrackBlock track)) return; Collection ends = track.getConnected(reader, pos, state, false, null); @@ -135,6 +141,7 @@ public class TrackPropagator { if (graph == null) graph = other; else { + MinecraftForge.EVENT_BUS.post(new TrackGraphMergeEvent(other, graph)); other.transferAll(graph); manager.removeGraphAndGroup(other); sync.graphRemoved(other); @@ -234,11 +241,13 @@ public class TrackPropagator { return true; if (location.shouldForceNode()) return true; + if (location.differentMaterials()) + return true; if (next.stream() .anyMatch(DiscoveredLocation::shouldForceNode)) return true; - - Vec3 direction = location.direction; + + Vec3 direction = location.getDirection(); if (direction != null && next.stream() .anyMatch(dl -> dl.notInLineWith(direction))) return true; diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackRenderer.java b/src/main/java/com/simibubi/create/content/trains/track/TrackRenderer.java new file mode 100644 index 0000000000..0a1fe075ad --- /dev/null +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackRenderer.java @@ -0,0 +1,146 @@ +package com.simibubi.create.content.trains.track; + +import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_BOTTOM; +import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_MIDDLE; +import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_TOP; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.PoseStack.Pose; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.trains.track.BezierConnection.GirderAngles; +import com.simibubi.create.content.trains.track.BezierConnection.SegmentAngles; +import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import com.simibubi.create.foundation.render.CachedPartialBuffers; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.math.AngleHelper; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class TrackRenderer extends SafeBlockEntityRenderer { + + public TrackRenderer(BlockEntityRendererProvider.Context context) {} + + @Override + protected void renderSafe(TrackBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + Level level = be.getLevel(); + if (Backend.canUseInstancing(level)) + return; + VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); + be.connections.values() + .forEach(bc -> renderBezierTurn(level, bc, ms, vb)); + } + + public static void renderBezierTurn(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb) { + if (!bc.isPrimary()) + return; + + ms.pushPose(); + BlockPos tePosition = bc.tePositions.getFirst(); + BlockState air = Blocks.AIR.defaultBlockState(); + SegmentAngles[] segments = bc.getBakedSegments(); + + renderGirder(level, bc, ms, vb, tePosition); + + for (int i = 1; i < segments.length; i++) { + SegmentAngles segment = segments[i]; + int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); + + TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder(); + + CachedPartialBuffers.partial(modelHolder.tie(), air) + .mulPose(segment.tieTransform.pose()) + .mulNormal(segment.tieTransform.normal()) + .light(light) + .renderInto(ms, vb); + + for (boolean first : Iterate.trueAndFalse) { + Pose transform = segment.railTransforms.get(first); + CachedPartialBuffers.partial(first ? modelHolder.segment_left() : modelHolder.segment_right(), air) + .mulPose(transform.pose()) + .mulNormal(transform.normal()) + .light(light) + .renderInto(ms, vb); + } + } + + ms.popPose(); + } + + private static void renderGirder(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb, + BlockPos tePosition) { + if (!bc.hasGirder) + return; + + BlockState air = Blocks.AIR.defaultBlockState(); + GirderAngles[] girders = bc.getBakedGirders(); + + for (int i = 1; i < girders.length; i++) { + GirderAngles segment = girders[i]; + int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); + + for (boolean first : Iterate.trueAndFalse) { + Pose beamTransform = segment.beams.get(first); + CachedPartialBuffers.partial(GIRDER_SEGMENT_MIDDLE, air) + .mulPose(beamTransform.pose()) + .mulNormal(beamTransform.normal()) + .light(light) + .renderInto(ms, vb); + + for (boolean top : Iterate.trueAndFalse) { + Pose beamCapTransform = segment.beamCaps.get(top) + .get(first); + CachedPartialBuffers.partial(top ? GIRDER_SEGMENT_TOP : GIRDER_SEGMENT_BOTTOM, air) + .mulPose(beamCapTransform.pose()) + .mulNormal(beamCapTransform.normal()) + .light(light) + .renderInto(ms, vb); + } + } + } + } + + public static Vec3 getModelAngles(Vec3 normal, Vec3 diff) { + double diffX = diff.x(); + double diffY = diff.y(); + double diffZ = diff.z(); + double len = Mth.sqrt((float) (diffX * diffX + diffZ * diffZ)); + double yaw = Mth.atan2(diffX, diffZ); + double pitch = Mth.atan2(len, diffY) - Math.PI * .5; + + Vec3 yawPitchNormal = VecHelper.rotate(VecHelper.rotate(new Vec3(0, 1, 0), AngleHelper.deg(pitch), Axis.X), + AngleHelper.deg(yaw), Axis.Y); + + double signum = Math.signum(yawPitchNormal.dot(normal)); + if (Math.abs(signum) < 0.5f) + signum = yawPitchNormal.distanceToSqr(normal) < 0.5f ? -1 : 1; + double dot = diff.cross(normal) + .normalize() + .dot(yawPitchNormal); + double roll = Math.acos(Mth.clamp(dot, -1, 1)) * signum; + return new Vec3(pitch, yaw, roll); + } + + @Override + public boolean shouldRenderOffScreen(TrackBlockEntity pBlockEntity) { + return true; + } + + @Override + public int getViewDistance() { + return 96 * 2; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java b/src/main/java/com/simibubi/create/content/trains/track/TrackShape.java similarity index 98% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackShape.java index 8567a7d961..56c8756d88 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackShape.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import java.util.EnumMap; import java.util.List; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBehaviour.java similarity index 81% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBehaviour.java index 240a8eded9..54c47a3c0c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.track; import java.util.List; import java.util.UUID; @@ -8,23 +8,21 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.core.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; -import com.simibubi.create.content.logistics.trains.BezierConnection; -import com.simibubi.create.content.logistics.trains.DimensionPalette; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.TrackGraphHelper; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; +import com.simibubi.create.content.contraptions.StructureTransform; +import com.simibubi.create.content.trains.graph.DimensionPalette; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraph; +import com.simibubi.create.content.trains.graph.TrackGraphHelper; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.signal.SingleBlockEntityEdgePoint; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.render.CachedPartialBuffers; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.VecHelper; @@ -48,7 +46,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class TrackTargetingBehaviour extends TileEntityBehaviour { +public class TrackTargetingBehaviour extends BlockEntityBehaviour { public static final BehaviourType> TYPE = new BehaviourType<>(); @@ -65,8 +63,8 @@ public class TrackTargetingBehaviour extends TileEntit private T edgePoint; private boolean orthogonal; - public TrackTargetingBehaviour(SmartTileEntity te, EdgePointType edgePointType) { - super(te); + public TrackTargetingBehaviour(SmartBlockEntity be, EdgePointType edgePointType) { + super(be); this.edgePointType = edgePointType; targetDirection = AxisDirection.POSITIVE; targetTrack = BlockPos.ZERO; @@ -133,7 +131,7 @@ public class TrackTargetingBehaviour extends TileEntit public void invalidateEdgePoint(CompoundTag migrationData) { this.migrationData = migrationData; edgePoint = null; - tileEntity.sendData(); + blockEntity.sendData(); } @Override @@ -159,7 +157,7 @@ public class TrackTargetingBehaviour extends TileEntit return null; if (!hasValidTrack()) return null; - GraphLocation loc = determineGraphLocation(); + TrackGraphLocation loc = determineGraphLocation(); if (loc == null) return null; @@ -214,9 +212,9 @@ public class TrackTargetingBehaviour extends TileEntit } if (!otherPoint.canMerge()) return null; - otherPoint.tileAdded(tileEntity, front); + otherPoint.blockEntityAdded(blockEntity, front); id = otherPoint.getId(); - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); return (T) otherPoint; } } @@ -225,19 +223,19 @@ public class TrackTargetingBehaviour extends TileEntit point.read(data, true, DimensionPalette.read(data)); point.setId(id); - boolean reverseEdge = front || point instanceof SingleTileEdgePoint; + boolean reverseEdge = front || point instanceof SingleBlockEntityEdgePoint; point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position); - point.tileAdded(tileEntity, front); + point.blockEntityAdded(blockEntity, front); loc.graph.addPoint(edgePointType, point); - tileEntity.sendData(); + blockEntity.sendData(); return point; } @Override - public void remove() { + public void destroy() { + super.destroy(); if (edgePoint != null && !getWorld().isClientSide) - edgePoint.tileRemoved(getPos(), getTargetDirection() == AxisDirection.POSITIVE); - super.remove(); + edgePoint.blockEntityRemoved(getPos(), getTargetDirection() == AxisDirection.POSITIVE); } @Override @@ -266,13 +264,13 @@ public class TrackTargetingBehaviour extends TileEntit } public BlockPos getGlobalPosition() { - return targetTrack.offset(tileEntity.getBlockPos()); + return targetTrack.offset(blockEntity.getBlockPos()); } public BlockPos getPositionForMapMarker() { - BlockPos target = targetTrack.offset(tileEntity.getBlockPos()); - if (targetBezier != null && getWorld().getBlockEntity(target) instanceof TrackTileEntity tte) { - BezierConnection bc = tte.getConnections() + BlockPos target = targetTrack.offset(blockEntity.getBlockPos()); + if (targetBezier != null && getWorld().getBlockEntity(target) instanceof TrackBlockEntity tbe) { + BezierConnection bc = tbe.getConnections() .get(targetBezier.curveTarget()); if (bc == null) return target; @@ -292,7 +290,7 @@ public class TrackTargetingBehaviour extends TileEntit return targetBezier; } - public GraphLocation determineGraphLocation() { + public TrackGraphLocation determineGraphLocation() { Level level = getWorld(); BlockPos pos = getGlobalPosition(); BlockState state = getTrackBlockState(); @@ -322,8 +320,6 @@ public class TrackTargetingBehaviour extends TileEntit return; ms.pushPose(); - ms.translate(pos.getX(), pos.getY(), pos.getZ()); - ITrackBlock track = (ITrackBlock) block; PartialModel partial = track.prepareTrackOverlay(level, pos, trackState, bezier, direction, ms, type); if (partial != null) @@ -333,7 +329,6 @@ public class TrackTargetingBehaviour extends TileEntit .translate(-.5, 0, -.5) .light(LevelRenderer.getLightColor(level, pos)) .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); - ms.popPose(); } @@ -346,7 +341,7 @@ public class TrackTargetingBehaviour extends TileEntit targetBezier = new BezierTrackPointLocation(transform.applyWithoutOffset(targetBezier.curveTarget() .subtract(getPos())) .offset(getPos()), targetBezier.segment()); - tileEntity.notifyUpdate(); + blockEntity.notifyUpdate(); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBlockItem.java b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBlockItem.java similarity index 87% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBlockItem.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBlockItem.java index 2ca763953d..0a57e2c97a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBlockItem.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingBlockItem.java @@ -1,22 +1,21 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.track; import java.util.List; import java.util.function.BiConsumer; import org.apache.commons.lang3.mutable.MutableObject; +import com.simibubi.create.AllPackets; import com.simibubi.create.AllSoundEvents; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackEdge; -import com.simibubi.create.content.logistics.trains.TrackGraphHelper; -import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; +import com.simibubi.create.content.trains.graph.EdgeData; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackEdge; +import com.simibubi.create.content.trains.graph.TrackGraphHelper; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.graph.TrackNode; +import com.simibubi.create.content.trains.signal.TrackEdgePoint; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.CreateLang; import com.tterrag.registrate.util.nullness.NonNullBiFunction; @@ -156,12 +155,12 @@ public class TrackTargetingBlockItem extends BlockItem { public boolean useOnCurve(BezierPointSelection selection, ItemStack stack) { Minecraft mc = Minecraft.getInstance(); LocalPlayer player = mc.player; - TrackTileEntity te = selection.te(); + TrackBlockEntity be = selection.blockEntity(); BezierTrackPointLocation loc = selection.loc(); boolean front = player.getLookAngle() .dot(selection.direction()) < 0; - AllPackets.channel.sendToServer(new CurvedTrackSelectionPacket(te.getBlockPos(), loc.curveTarget(), + AllPackets.getChannel().sendToServer(new CurvedTrackSelectionPacket(be.getBlockPos(), loc.curveTarget(), loc.segment(), front, player.getInventory().selected)); return true; } @@ -185,7 +184,7 @@ public class TrackTargetingBlockItem extends BlockItem { public static void withGraphLocation(Level level, BlockPos pos, boolean front, BezierTrackPointLocation targetBezier, EdgePointType type, - BiConsumer callback) { + BiConsumer callback) { BlockState state = level.getBlockState(pos); @@ -201,7 +200,7 @@ public class TrackTargetingBlockItem extends BlockItem { } AxisDirection targetDirection = front ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE; - GraphLocation location = + TrackGraphLocation location = targetBezier != null ? TrackGraphHelper.getBezierGraphLocationAt(level, pos, targetDirection, targetBezier) : TrackGraphHelper.getGraphLocationAt(level, pos, targetDirection, trackAxes.get(0)); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingClient.java b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingClient.java similarity index 84% rename from src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingClient.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackTargetingClient.java index d804d8f2cd..87ba3823b8 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingClient.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackTargetingClient.java @@ -1,15 +1,14 @@ -package com.simibubi.create.content.logistics.trains.management.edgePoint; +package com.simibubi.create.content.trains.track; import com.google.common.base.Objects; +import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.GraphLocation; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem.OverlapResult; -import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; +import com.simibubi.create.content.trains.graph.EdgePointType; +import com.simibubi.create.content.trains.graph.TrackGraphLocation; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; +import com.simibubi.create.content.trains.track.TrackTargetingBehaviour.RenderedTrackOverlayType; +import com.simibubi.create.content.trains.track.TrackTargetingBlockItem.OverlapResult; import net.createmod.catnip.render.SuperRenderTypeBuffer; import net.minecraft.client.Minecraft; @@ -35,7 +34,7 @@ public class TrackTargetingClient { static BezierTrackPointLocation lastHoveredBezierSegment; static OverlapResult lastResult; - static GraphLocation lastLocation; + static TrackGraphLocation lastLocation; public static void clientTick() { Minecraft mc = Minecraft.getInstance(); @@ -72,7 +71,7 @@ public class TrackTargetingClient { } } else if (bezierSelection != null) { - hovered = bezierSelection.te() + hovered = bezierSelection.blockEntity() .getBlockPos(); hoveredBezier = bezierSelection.loc(); direction = lookAngle.dot(bezierSelection.direction()) < 0; @@ -116,7 +115,7 @@ public class TrackTargetingClient { }); } - public static void render(PoseStack ms, SuperRenderTypeBuffer buffer) { + public static void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera) { if (lastLocation == null || lastResult.feedback != null) return; @@ -128,8 +127,13 @@ public class TrackTargetingClient { RenderedTrackOverlayType type = lastType == EdgePointType.SIGNAL ? RenderedTrackOverlayType.SIGNAL : lastType == EdgePointType.OBSERVER ? RenderedTrackOverlayType.OBSERVER : RenderedTrackOverlayType.STATION; + ms.pushPose(); + TransformStack.cast(ms) + .translate(Vec3.atLowerCornerOf(pos) + .subtract(camera)); TrackTargetingBehaviour.render(mc.level, pos, direction, lastHoveredBezierSegment, ms, buffer, light, OverlayTexture.NO_OVERLAY, type, 1 + 1 / 16f); + ms.popPose(); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackVoxelShapes.java b/src/main/java/com/simibubi/create/content/trains/track/TrackVoxelShapes.java similarity index 96% rename from src/main/java/com/simibubi/create/content/logistics/trains/track/TrackVoxelShapes.java rename to src/main/java/com/simibubi/create/content/trains/track/TrackVoxelShapes.java index 653de6e45c..38bdd23506 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackVoxelShapes.java +++ b/src/main/java/com/simibubi/create/content/trains/track/TrackVoxelShapes.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.logistics.trains.track; +package com.simibubi.create.content.trains.track; import net.minecraft.world.level.block.Block; import net.minecraft.world.phys.shapes.BooleanOp; diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java deleted file mode 100644 index 6b7253f0ac..0000000000 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ /dev/null @@ -1,390 +0,0 @@ -package com.simibubi.create.events; - -import java.util.ArrayList; -import java.util.List; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import com.simibubi.create.AllFluids; -import com.simibubi.create.AllItems; -import com.simibubi.create.Create; -import com.simibubi.create.CreateClient; -import com.simibubi.create.content.contraptions.KineticDebugger; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.components.fan.AirCurrent; -import com.simibubi.create.content.contraptions.components.steam.SteamEngineBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; -import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingRenderer; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe; -import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler; -import com.simibubi.create.content.curiosities.armor.CopperBacktankArmorLayer; -import com.simibubi.create.content.curiosities.girder.GirderWrenchBehavior; -import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient; -import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; -import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler; -import com.simibubi.create.content.curiosities.zapper.ZapperItem; -import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler; -import com.simibubi.create.content.logistics.block.depot.EjectorTargetHandler; -import com.simibubi.create.content.logistics.block.display.DisplayLinkBlockItem; -import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler; -import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler; -import com.simibubi.create.content.logistics.trains.CameraDistanceModifier; -import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.CarriageCouplingRenderer; -import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; -import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingClient; -import com.simibubi.create.content.logistics.trains.management.schedule.TrainHatArmorLayer; -import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction; -import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline; -import com.simibubi.create.content.logistics.trains.track.TrackPlacement; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.fluid.FluidHelper; -import com.simibubi.create.foundation.item.ItemDescription; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.networking.LeftClickPacket; -import com.simibubi.create.foundation.sound.SoundScapes; -import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer; -import com.simibubi.create.foundation.utility.CameraAngleAnimationService; -import com.simibubi.create.foundation.utility.ServerSpeedProvider; - -import net.createmod.catnip.config.ui.BaseConfigScreen; -import net.createmod.catnip.render.DefaultSuperRenderTypeBufferImpl; -import net.createmod.catnip.render.SuperRenderTypeBuffer; -import net.createmod.catnip.utility.AnimationTickHolder; -import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.worldWrappers.WrappedClientWorld; -import net.minecraft.client.Camera; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.entity.EntityRenderDispatcher; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.ConfigGuiHandler; -import net.minecraftforge.client.event.ClientPlayerNetworkEvent; -import net.minecraftforge.client.event.EntityRenderersEvent; -import net.minecraftforge.client.event.EntityViewRenderEvent; -import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; -import net.minecraftforge.client.event.RenderLevelLastEvent; -import net.minecraftforge.event.TickEvent.ClientTickEvent; -import net.minecraftforge.event.TickEvent.Phase; -import net.minecraftforge.event.TickEvent.RenderTickEvent; -import net.minecraftforge.event.entity.EntityMountEvent; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.event.world.WorldEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModContainer; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; - -@EventBusSubscriber(Dist.CLIENT) -public class ClientEvents { - - private static final String ITEM_PREFIX = "item." + Create.ID; - private static final String BLOCK_PREFIX = "block." + Create.ID; - - @SubscribeEvent - public static void onTick(ClientTickEvent event) { - if (!isGameActive()) - return; - - Level world = Minecraft.getInstance().level; - if (event.phase == Phase.START) { - LinkedControllerClientHandler.tick(); - ControlsHandler.tick(); - AirCurrent.tickClientPlayerSounds(); - return; - } - - SoundScapes.tick(); - ScrollValueHandler.tick(); - - CreateClient.SCHEMATIC_SENDER.tick(); - CreateClient.SCHEMATIC_AND_QUILL_HANDLER.tick(); - CreateClient.GLUE_HANDLER.tick(); - CreateClient.SCHEMATIC_HANDLER.tick(); - CreateClient.ZAPPER_RENDER_HANDLER.tick(); - CreateClient.POTATO_CANNON_RENDER_HANDLER.tick(); - CreateClient.SOUL_PULSE_EFFECT_HANDLER.tick(world); - CreateClient.RAILWAYS.clientTick(); - - ContraptionHandler.tick(world); - CapabilityMinecartController.tick(world); - CouplingPhysics.tick(world); - - ServerSpeedProvider.clientTick(); - BeltConnectorHandler.tick(); -// BeltSlicer.tickHoveringInformation(); - FilteringRenderer.tick(); - LinkRenderer.tick(); - ScrollValueRenderer.tick(); - ChassisRangeDisplay.tick(); - EdgeInteractionRenderer.tick(); - GirderWrenchBehavior.tick(); - WorldshaperRenderHandler.tick(); - CouplingHandlerClient.tick(); - CouplingRenderer.tickDebugModeRenders(); - KineticDebugger.tick(); - ExtendoGripRenderHandler.tick(); - // CollisionDebugger.tick(); - ArmInteractionPointHandler.tick(); - EjectorTargetHandler.tick(); - ContraptionRenderDispatcher.tick(world); - BlueprintOverlayRenderer.tick(); - ToolboxHandlerClient.clientTick(); - TrackTargetingClient.clientTick(); - TrackPlacement.clientTick(); - TrainRelocator.clientTick(); - DisplayLinkBlockItem.clientTick(); - CurvedTrackInteraction.clientTick(); - CameraDistanceModifier.tick(); - CameraAngleAnimationService.tick(); - TrainHUD.tick(); - } - - @SubscribeEvent - public static void onJoin(ClientPlayerNetworkEvent.LoggedInEvent event) { - CreateClient.checkGraphicsFanciness(); - } - - @SubscribeEvent - public static void onLeave(ClientPlayerNetworkEvent.LoggedOutEvent event) { - CreateClient.RAILWAYS.cleanUp(); - } - - @SubscribeEvent - public static void onLoadWorld(WorldEvent.Load event) { - LevelAccessor world = event.getWorld(); - if (world.isClientSide() && world instanceof ClientLevel && !(world instanceof WrappedClientWorld)) { - CreateClient.invalidateRenderers(); - } - } - - @SubscribeEvent - public static void onUnloadWorld(WorldEvent.Unload event) { - if (!event.getWorld() - .isClientSide()) - return; - CreateClient.invalidateRenderers(); - CreateClient.SOUL_PULSE_EFFECT_HANDLER.refresh(); - ControlsHandler.levelUnloaded(event.getWorld()); - } - - @SubscribeEvent - public static void onRenderWorld(RenderLevelLastEvent event) { - Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition(); - float pt = AnimationTickHolder.getPartialTicks(); - - PoseStack ms = event.getPoseStack(); - ms.pushPose(); - ms.translate(-cameraPos.x(), -cameraPos.y(), -cameraPos.z()); - SuperRenderTypeBuffer buffer = DefaultSuperRenderTypeBufferImpl.getInstance(); - - TrackBlockOutline.drawCurveSelection(ms, buffer); - TrackTargetingClient.render(ms, buffer); - CouplingRenderer.renderAll(ms, buffer); - CarriageCouplingRenderer.renderAll(ms, buffer); - CreateClient.SCHEMATIC_HANDLER.render(ms, buffer); - - buffer.draw(); - RenderSystem.enableCull(); - - ms.popPose(); - } - - @SubscribeEvent - public static void onCameraSetup(EntityViewRenderEvent.CameraSetup event) { - float partialTicks = AnimationTickHolder.getPartialTicks(); - - if (CameraAngleAnimationService.isYawAnimating()) - event.setYaw(CameraAngleAnimationService.getYaw(partialTicks)); - - if (CameraAngleAnimationService.isPitchAnimating()) - event.setPitch(CameraAngleAnimationService.getPitch(partialTicks)); - } - - @SubscribeEvent - public static void addToItemTooltip(ItemTooltipEvent event) { - if (!AllConfigs.CLIENT.tooltips.get()) - return; - if (event.getPlayer() == null) - return; - - ItemStack stack = event.getItemStack(); - String translationKey = stack.getItem() - .getDescriptionId(stack); - - if (translationKey.startsWith(ITEM_PREFIX) || translationKey.startsWith(BLOCK_PREFIX)) - if (TooltipHelper.hasTooltip(stack, event.getPlayer())) { - List itemTooltip = event.getToolTip(); - List toolTip = new ArrayList<>(); - toolTip.add(itemTooltip.remove(0)); - TooltipHelper.getTooltip(stack) - .addInformation(toolTip); - itemTooltip.addAll(0, toolTip); - } - - if (stack.getItem() instanceof BlockItem) { - BlockItem item = (BlockItem) stack.getItem(); - if (item.getBlock() instanceof IRotate || item.getBlock() instanceof SteamEngineBlock) { - List kineticStats = ItemDescription.getKineticStats(item.getBlock()); - if (!kineticStats.isEmpty()) { - event.getToolTip() - .add(Components.immutableEmpty()); - event.getToolTip() - .addAll(kineticStats); - } - } - } - - SequencedAssemblyRecipe.addToTooltip(event.getToolTip(), stack); - } - - @SubscribeEvent - public static void onRenderTick(RenderTickEvent event) { - if (!isGameActive()) - return; - TurntableHandler.gameRenderTick(); - } - - @SubscribeEvent - public static void onMount(EntityMountEvent event) { - if (event.getEntityMounting() != Minecraft.getInstance().player) - return; - - if (event.isDismounting()) { - CameraDistanceModifier.reset(); - return; - } - - if (!event.isMounting() || !(event.getEntityBeingMounted() instanceof CarriageContraptionEntity carriage)) { - return; - } - - CameraDistanceModifier.zoomOut(); - } - - protected static boolean isGameActive() { - return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null); - } - - @SubscribeEvent - public static void getFogDensity(EntityViewRenderEvent.RenderFogEvent event) { - Camera info = event.getCamera(); - Level level = Minecraft.getInstance().level; - BlockPos blockPos = info.getBlockPosition(); - FluidState fluidState = level.getFluidState(blockPos); - if (info.getPosition().y > blockPos.getY() + fluidState.getHeight(level, blockPos)) - return; - - Fluid fluid = fluidState.getType(); - - if (AllFluids.CHOCOLATE.get() - .isSame(fluid)) { - event.scaleFarPlaneDistance(1f/32f); - event.setCanceled(true); - return; - } - - if (AllFluids.HONEY.get() - .isSame(fluid)) { - event.scaleFarPlaneDistance(1f/8f); - event.setCanceled(true); - return; - } - - if (FluidHelper.isWater(fluid) && AllItems.DIVING_HELMET.get() - .isWornBy(Minecraft.getInstance().cameraEntity)) { - event.scaleFarPlaneDistance(6.25f); - event.setCanceled(true); - return; - } - } - - @SubscribeEvent - public static void getFogColor(EntityViewRenderEvent.FogColors event) { - Camera info = event.getCamera(); - Level level = Minecraft.getInstance().level; - BlockPos blockPos = info.getBlockPosition(); - FluidState fluidState = level.getFluidState(blockPos); - if (info.getPosition().y > blockPos.getY() + fluidState.getHeight(level, blockPos)) - return; - - Fluid fluid = fluidState.getType(); - - if (AllFluids.CHOCOLATE.get() - .isSame(fluid)) { - event.setRed(98 / 255f); - event.setGreen(32 / 255f); - event.setBlue(32 / 255f); - return; - } - - if (AllFluids.HONEY.get() - .isSame(fluid)) { - event.setRed(234 / 255f); - event.setGreen(174 / 255f); - event.setBlue(47 / 255f); - return; - } - } - - @SubscribeEvent - public static void leftClickEmpty(PlayerInteractEvent.LeftClickEmpty event) { - ItemStack stack = event.getItemStack(); - if (stack.getItem() instanceof ZapperItem) { - AllPackets.channel.sendToServer(new LeftClickPacket()); - } - } - - @EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD) - public static class ModBusEvents { - - @SubscribeEvent - public static void registerClientReloadListeners(RegisterClientReloadListenersEvent event) { - event.registerReloadListener(CreateClient.RESOURCE_RELOAD_LISTENER); - } - - @SubscribeEvent - public static void addEntityRendererLayers(EntityRenderersEvent.AddLayers event) { - EntityRenderDispatcher dispatcher = Minecraft.getInstance() - .getEntityRenderDispatcher(); - CopperBacktankArmorLayer.registerOnAll(dispatcher); - TrainHatArmorLayer.registerOnAll(dispatcher); - } - - @SubscribeEvent - public static void onLoadComplete(FMLLoadCompleteEvent event) { - ModContainer createContainer = ModList.get() - .getModContainerById(Create.ID) - .orElseThrow(() -> new IllegalStateException("Create mod container missing on LoadComplete")); - createContainer.registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class, - () -> new ConfigGuiHandler.ConfigGuiFactory( - (mc, previousScreen) -> new BaseConfigScreen(previousScreen, Create.ID))); - } - - } - -} diff --git a/src/main/java/com/simibubi/create/events/InputEvents.java b/src/main/java/com/simibubi/create/events/InputEvents.java deleted file mode 100644 index 0e688c6696..0000000000 --- a/src/main/java/com/simibubi/create/events/InputEvents.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.simibubi.create.events; - -import org.lwjgl.glfw.GLFW; - -import com.simibubi.create.CreateClient; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; -import com.simibubi.create.content.contraptions.wrench.RadialWrenchHandler; -import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient; -import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler; -import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; -import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringHandler; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler; - -import net.minecraft.client.KeyMapping; -import net.minecraft.client.Minecraft; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.InputEvent.ClickInputEvent; -import net.minecraftforge.client.event.InputEvent.KeyInputEvent; -import net.minecraftforge.client.event.InputEvent.MouseInputEvent; -import net.minecraftforge.client.event.InputEvent.MouseScrollEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; - -@EventBusSubscriber(Dist.CLIENT) -public class InputEvents { - - @SubscribeEvent - public static void onKeyInput(KeyInputEvent event) { - if (Minecraft.getInstance().screen != null) - return; - - int key = event.getKey(); - boolean pressed = event.getAction() != GLFW.GLFW_RELEASE; - - CreateClient.SCHEMATIC_HANDLER.onKeyInput(key, pressed); - ToolboxHandlerClient.onKeyInput(key, pressed); - RadialWrenchHandler.onKeyInput(key, pressed); - } - - @SubscribeEvent - public static void onMouseScrolled(MouseScrollEvent event) { - if (Minecraft.getInstance().screen != null) - return; - - double delta = event.getScrollDelta(); -// CollisionDebugger.onScroll(delta); - boolean cancelled = CreateClient.SCHEMATIC_HANDLER.mouseScrolled(delta) - || CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || FilteringHandler.onScroll(delta) - || ScrollValueHandler.onScroll(delta) || TrainHUD.onScroll(delta); - event.setCanceled(cancelled); - } - - @SubscribeEvent - public static void onMouseInput(MouseInputEvent event) { - if (Minecraft.getInstance().screen != null) - return; - - int button = event.getButton(); - boolean pressed = !(event.getAction() == 0); - - CreateClient.SCHEMATIC_HANDLER.onMouseInput(button, pressed); - CreateClient.SCHEMATIC_AND_QUILL_HANDLER.onMouseInput(button, pressed); - } - - @SubscribeEvent - public static void onClickInput(ClickInputEvent event) { - Minecraft mc = Minecraft.getInstance(); - if (mc.screen != null) - return; - - if (CurvedTrackInteraction.onClickInput(event)) { - event.setCanceled(true); - return; - } - - KeyMapping key = event.getKeyMapping(); - - if (key == mc.options.keyUse || key == mc.options.keyAttack) { - if (CreateClient.GLUE_HANDLER.onMouseInput(key == mc.options.keyAttack)) - event.setCanceled(true); - } - - if (key == mc.options.keyPickItem) { - if (ToolboxHandlerClient.onPickItem()) - event.setCanceled(true); - return; - } - - if (!event.isUseItem()) - return; - - LinkedControllerClientHandler.deactivateInLectern(); - TrainRelocator.onClicked(event); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/advancement/AdvancementBehaviour.java b/src/main/java/com/simibubi/create/foundation/advancement/AdvancementBehaviour.java index 1729f37829..f52bd14538 100644 --- a/src/main/java/com/simibubi/create/foundation/advancement/AdvancementBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/advancement/AdvancementBehaviour.java @@ -4,9 +4,9 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -18,15 +18,15 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.util.FakePlayer; -public class AdvancementBehaviour extends TileEntityBehaviour { +public class AdvancementBehaviour extends BlockEntityBehaviour { public static final BehaviourType TYPE = new BehaviourType<>(); private UUID playerId; private Set advancements; - public AdvancementBehaviour(SmartTileEntity te, CreateAdvancement... advancements) { - super(te); + public AdvancementBehaviour(SmartBlockEntity be, CreateAdvancement... advancements) { + super(be); this.advancements = new HashSet<>(); add(advancements); } @@ -46,7 +46,7 @@ public class AdvancementBehaviour extends TileEntityBehaviour { return; playerId = id; removeAwarded(); - tileEntity.setChanged(); + blockEntity.setChanged(); } @Override @@ -62,7 +62,7 @@ public class AdvancementBehaviour extends TileEntityBehaviour { advancements.removeIf(c -> c.isAlreadyAwardedTo(player)); if (advancements.isEmpty()) { playerId = null; - tileEntity.setChanged(); + blockEntity.setChanged(); } } @@ -114,13 +114,13 @@ public class AdvancementBehaviour extends TileEntityBehaviour { } public static void tryAward(BlockGetter reader, BlockPos pos, CreateAdvancement advancement) { - AdvancementBehaviour behaviour = TileEntityBehaviour.get(reader, pos, AdvancementBehaviour.TYPE); + AdvancementBehaviour behaviour = BlockEntityBehaviour.get(reader, pos, AdvancementBehaviour.TYPE); if (behaviour != null) behaviour.awardPlayer(advancement); } public static void setPlacedBy(Level worldIn, BlockPos pos, LivingEntity placer) { - AdvancementBehaviour behaviour = TileEntityBehaviour.get(worldIn, pos, TYPE); + AdvancementBehaviour behaviour = BlockEntityBehaviour.get(worldIn, pos, TYPE); if (behaviour == null) return; if (placer instanceof FakePlayer) diff --git a/src/main/java/com/simibubi/create/foundation/advancement/AllAdvancements.java b/src/main/java/com/simibubi/create/foundation/advancement/AllAdvancements.java index ebd3113370..d667b0f423 100644 --- a/src/main/java/com/simibubi/create/foundation/advancement/AllAdvancements.java +++ b/src/main/java/com/simibubi/create/foundation/advancement/AllAdvancements.java @@ -13,13 +13,13 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.UnaryOperator; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; import com.google.common.collect.Sets; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; +import com.mojang.logging.LogUtils; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllFluids; import com.simibubi.create.AllItems; @@ -270,7 +270,7 @@ public class AllAdvancements implements DataProvider { .description("Create a Copper Backtank and make it accumulate air pressure") .after(STEAM_WHISTLE)), - DIVING_SUIT = create("diving_suit", b -> b.icon(AllItems.DIVING_HELMET) + DIVING_SUIT = create("diving_suit", b -> b.icon(AllItems.COPPER_DIVING_HELMET) .title("Ready for the Depths") .description("Equip a Diving Helmet and a Copper Backtank, then jump into water") .after(BACKTANK)), @@ -331,7 +331,7 @@ public class AllAdvancements implements DataProvider { // Copper - Hidden - DIVING_SUIT_LAVA = create("diving_suit_lava", b -> b.icon(AllItems.DIVING_HELMET) + DIVING_SUIT_LAVA = create("diving_suit_lava", b -> b.icon(AllItems.COPPER_DIVING_HELMET) .title("Swimming with the Striders") .description("Attempt to take a dive in lava with your diving gear") .after(BACKTANK) @@ -565,16 +565,10 @@ public class AllAdvancements implements DataProvider { .after(STURDY_SHEET) .special(EXPERT)), - LONG_BEND = create("long_bend", b -> b.icon(AllBlocks.TRACK) - .title("The Longest Bend") - .description("Create a curved track section that spans more than 30 blocks in length") - .after(TRACK_CRAFTING) - .special(EXPERT)), - LONG_TRAIN = create("long_train", b -> b.icon(Items.MINECART) .title("Ambitious Endeavours") .description("Create a Train with at least 6 carriages") - .after(LONG_BEND) + .after(TRACK_CRAFTING) .special(EXPERT)), LONG_TRAVEL = create("long_travel", b -> b.icon(AllBlocks.SEATS.get(DyeColor.GREEN)) @@ -618,8 +612,8 @@ public class AllAdvancements implements DataProvider { // Datagen - private static final Logger LOGGER = LogManager.getLogger(); - private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting() + private static final Logger LOGGER = LogUtils.getLogger(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting() .create(); private final DataGenerator generator; diff --git a/src/main/java/com/simibubi/create/foundation/block/BigOutlines.java b/src/main/java/com/simibubi/create/foundation/block/BigOutlines.java index e10d4b671a..ad6175cd1f 100644 --- a/src/main/java/com/simibubi/create/foundation/block/BigOutlines.java +++ b/src/main/java/com/simibubi/create/foundation/block/BigOutlines.java @@ -1,7 +1,7 @@ package com.simibubi.create.foundation.block; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlock; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.trains.track.TrackBlock; import com.simibubi.create.foundation.utility.RaycastHelper; import net.createmod.catnip.utility.VecHelper; diff --git a/src/main/java/com/simibubi/create/foundation/block/CopperBlockSet.java b/src/main/java/com/simibubi/create/foundation/block/CopperBlockSet.java index 1cac8ccc30..da3020179a 100644 --- a/src/main/java/com/simibubi/create/foundation/block/CopperBlockSet.java +++ b/src/main/java/com/simibubi/create/foundation/block/CopperBlockSet.java @@ -9,7 +9,7 @@ import java.util.function.Supplier; import org.apache.commons.lang3.ArrayUtils; -import com.simibubi.create.AllTags; +import com.simibubi.create.foundation.data.TagGen; import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.providers.DataGenContext; @@ -126,7 +126,7 @@ public class CopperBlockSet { .loot((lt, block) -> variant.generateLootTable(lt, block, this, state, waxed)) .blockstate((ctx, prov) -> variant.generateBlockState(ctx, prov, this, state, waxed)) .recipe((c, p) -> variant.generateRecipes(entries.get(BlockVariant.INSTANCE)[state.ordinal()], c, p)) - .transform(AllTags.pickaxeOnly()) + .transform(TagGen.pickaxeOnly()) .tag(BlockTags.NEEDS_STONE_TOOL) .simpleItem(); diff --git a/src/main/java/com/simibubi/create/foundation/block/IBE.java b/src/main/java/com/simibubi/create/foundation/block/IBE.java new file mode 100644 index 0000000000..b616490d45 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/block/IBE.java @@ -0,0 +1,83 @@ +package com.simibubi.create.foundation.block; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntityTicker; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public interface IBE extends EntityBlock { + + Class getBlockEntityClass(); + + BlockEntityType getBlockEntityType(); + + default void withBlockEntityDo(BlockGetter world, BlockPos pos, Consumer action) { + getBlockEntityOptional(world, pos).ifPresent(action); + } + + default InteractionResult onBlockEntityUse(BlockGetter world, BlockPos pos, Function action) { + return getBlockEntityOptional(world, pos).map(action) + .orElse(InteractionResult.PASS); + } + + /** + * if the IBE is bound to a SmartBlockEntity, which implements destroy(),
+ * call this method in BlockBehaviour::onRemove (replace super call) + */ + public static void onRemove(BlockState blockState, Level level, BlockPos pos, BlockState newBlockState) { + if (!blockState.hasBlockEntity()) + return; + if (blockState.is(newBlockState.getBlock()) && newBlockState.hasBlockEntity()) + return; + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof SmartBlockEntity sbe) + sbe.destroy(); + level.removeBlockEntity(pos); + } + + default Optional getBlockEntityOptional(BlockGetter world, BlockPos pos) { + return Optional.ofNullable(getBlockEntity(world, pos)); + } + + @Override + default BlockEntity newBlockEntity(BlockPos p_153215_, BlockState p_153216_) { + return getBlockEntityType().create(p_153215_, p_153216_); + } + + @Override + default BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, + BlockEntityType p_153214_) { + if (SmartBlockEntity.class.isAssignableFrom(getBlockEntityClass())) + return new SmartBlockEntityTicker<>(); + return null; + } + + @Nullable + @SuppressWarnings("unchecked") + default T getBlockEntity(BlockGetter worldIn, BlockPos pos) { + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + Class expectedClass = getBlockEntityClass(); + + if (blockEntity == null) + return null; + if (!expectedClass.isInstance(blockEntity)) + return null; + + return (T) blockEntity; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/block/ITE.java b/src/main/java/com/simibubi/create/foundation/block/ITE.java deleted file mode 100644 index e6debdd82e..0000000000 --- a/src/main/java/com/simibubi/create/foundation/block/ITE.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.simibubi.create.foundation.block; - -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; - -import javax.annotation.Nullable; - -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.SmartTileEntityTicker; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public interface ITE extends EntityBlock { - - Class getTileEntityClass(); - - BlockEntityType getTileEntityType(); - - default void withTileEntityDo(BlockGetter world, BlockPos pos, Consumer action) { - getTileEntityOptional(world, pos).ifPresent(action); - } - - default InteractionResult onTileEntityUse(BlockGetter world, BlockPos pos, Function action) { - return getTileEntityOptional(world, pos).map(action) - .orElse(InteractionResult.PASS); - } - - default Optional getTileEntityOptional(BlockGetter world, BlockPos pos) { - return Optional.ofNullable(getTileEntity(world, pos)); - } - - @Override - default BlockEntity newBlockEntity(BlockPos p_153215_, BlockState p_153216_) { - return getTileEntityType().create(p_153215_, p_153216_); - } - - @Override - default BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, - BlockEntityType p_153214_) { - if (SmartTileEntity.class.isAssignableFrom(getTileEntityClass())) - return new SmartTileEntityTicker<>(); - return null; - } - - @Nullable - @SuppressWarnings("unchecked") - default T getTileEntity(BlockGetter worldIn, BlockPos pos) { - BlockEntity tileEntity = worldIn.getBlockEntity(pos); - Class expectedClass = getTileEntityClass(); - - if (tileEntity == null) - return null; - if (!expectedClass.isInstance(tileEntity)) - return null; - - return (T) tileEntity; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/block/ProperWaterloggedBlock.java b/src/main/java/com/simibubi/create/foundation/block/ProperWaterloggedBlock.java index e6439e5fd2..b455f1656c 100644 --- a/src/main/java/com/simibubi/create/foundation/block/ProperWaterloggedBlock.java +++ b/src/main/java/com/simibubi/create/foundation/block/ProperWaterloggedBlock.java @@ -38,9 +38,11 @@ public interface ProperWaterloggedBlock extends SimpleWaterloggedBlock { static BlockState withWater(LevelAccessor level, BlockState placementState, BlockPos pos) { if (placementState == null) return null; + FluidState ifluidstate = level.getFluidState(pos); + if (placementState.isAir()) + return ifluidstate.getType() == Fluids.WATER ? ifluidstate.createLegacyBlock() : placementState; if (!(placementState.getBlock() instanceof SimpleWaterloggedBlock)) return placementState; - FluidState ifluidstate = level.getFluidState(pos); return placementState.setValue(BlockStateProperties.WATERLOGGED, ifluidstate.getType() == Fluids.WATER); } diff --git a/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java b/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java index 7d8820886c..03edbb8d48 100644 --- a/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java +++ b/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java @@ -1,6 +1,6 @@ package com.simibubi.create.foundation.block; -import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.equipment.wrench.IWrenchable; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java b/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java deleted file mode 100644 index 2cc9605652..0000000000 --- a/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.simibubi.create.foundation.block.connected; - -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.BakedModelWrapper; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.data.ModelDataMap; -import net.minecraftforge.client.model.data.ModelDataMap.Builder; - -public abstract class BakedModelWrapperWithData extends BakedModelWrapper { - - public BakedModelWrapperWithData(BakedModel originalModel) { - super(originalModel); - } - - @Override - public final IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state, IModelData tileData) { - Builder builder = new ModelDataMap.Builder(); - if (originalModel instanceof BakedModelWrapperWithData) - ((BakedModelWrapperWithData) originalModel).gatherModelData(builder, world, pos, state); - return gatherModelData(builder, world, pos, state).build(); - } - - protected abstract ModelDataMap.Builder gatherModelData(ModelDataMap.Builder builder, BlockAndTintGetter world, - BlockPos pos, BlockState state); - -} diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/CTModel.java b/src/main/java/com/simibubi/create/foundation/block/connected/CTModel.java index f9aac18227..5c4ba46d36 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/CTModel.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/CTModel.java @@ -5,8 +5,10 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import com.simibubi.create.content.decoration.copycat.CopycatBlock; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext; -import com.simibubi.create.foundation.block.render.QuadHelper; +import com.simibubi.create.foundation.model.BakedModelWrapperWithData; +import com.simibubi.create.foundation.model.BakedQuadHelper; import net.createmod.catnip.utility.Iterate; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -33,18 +35,22 @@ public class CTModel extends BakedModelWrapperWithData { } @Override - protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) { - return builder.withInitial(CT_PROPERTY, createCTData(world, pos, state)); + protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, + IModelData blockEntityData) { + builder.withInitial(CT_PROPERTY, createCTData(world, pos, state)); } protected CTData createCTData(BlockAndTintGetter world, BlockPos pos, BlockState state) { CTData data = new CTData(); MutableBlockPos mutablePos = new MutableBlockPos(); for (Direction face : Iterate.directions) { + BlockState actualState = world.getBlockState(pos); if (!behaviour.buildContextForOccludedDirections() - && !Block.shouldRenderFace(state, world, pos, face, mutablePos.setWithOffset(pos, face))) + && !Block.shouldRenderFace(state, world, pos, face, mutablePos.setWithOffset(pos, face)) + && !(actualState.getBlock()instanceof CopycatBlock ufb + && !ufb.canFaceBeOccluded(actualState, face))) continue; - CTType dataType = behaviour.getDataType(state, face); + CTType dataType = behaviour.getDataType(world, pos, state, face); if (dataType == null) continue; CTContext context = behaviour.buildContext(world, pos, state, face, dataType.getContextRequirement()); @@ -75,14 +81,14 @@ public class CTModel extends BakedModelWrapperWithData { if (quad.getSprite() != spriteShift.getOriginal()) continue; - BakedQuad newQuad = QuadHelper.clone(quad); + BakedQuad newQuad = BakedQuadHelper.clone(quad); int[] vertexData = newQuad.getVertices(); for (int vertex = 0; vertex < 4; vertex++) { - float u = QuadHelper.getU(vertexData, vertex); - float v = QuadHelper.getV(vertexData, vertex); - QuadHelper.setU(vertexData, vertex, spriteShift.getTargetU(u, index)); - QuadHelper.setV(vertexData, vertex, spriteShift.getTargetV(v, index)); + float u = BakedQuadHelper.getU(vertexData, vertex); + float v = BakedQuadHelper.getV(vertexData, vertex); + BakedQuadHelper.setU(vertexData, vertex, spriteShift.getTargetU(u, index)); + BakedQuadHelper.setV(vertexData, vertex, spriteShift.getTargetV(v, index)); } quads.set(i, newQuad); diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShifter.java b/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShifter.java index 3e106b2c84..b0c5cc8c0b 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShifter.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/CTSpriteShifter.java @@ -1,16 +1,19 @@ package com.simibubi.create.foundation.block.connected; +import java.util.HashMap; +import java.util.Map; + import net.createmod.catnip.render.SpriteShifter; import net.minecraft.resources.ResourceLocation; public class CTSpriteShifter extends SpriteShifter { - //private static final Map ENTRY_CACHE = new HashMap<>(); + private static final Map ENTRY_CACHE = new HashMap<>(); public static CTSpriteShiftEntry getCT(CTType type, ResourceLocation blockTexture, ResourceLocation connectedTexture) { String key = blockTexture + "->" + connectedTexture + "+" + type.getId(); if (ENTRY_CACHE.containsKey(key)) - return (CTSpriteShiftEntry) ENTRY_CACHE.get(key); + return ENTRY_CACHE.get(key); CTSpriteShiftEntry entry = new CTSpriteShiftEntry(type, blockTexture, connectedTexture); ENTRY_CACHE.put(key, entry); diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java b/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java index 906273a801..3629795009 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/ConnectedTextureBehaviour.java @@ -3,6 +3,8 @@ package com.simibubi.create.foundation.block.connected; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.simibubi.create.content.decoration.copycat.CopycatBlock; + import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -14,11 +16,12 @@ import net.minecraft.world.level.block.state.BlockState; public abstract class ConnectedTextureBehaviour { @Nullable - public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, @NotNull TextureAtlasSprite sprite); + public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, + @NotNull TextureAtlasSprite sprite); // TODO: allow more than one data type per state/face? @Nullable - public abstract CTType getDataType(BlockState state, Direction direction); + public abstract CTType getDataType(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction direction); public boolean buildContextForOccludedDirections() { return false; @@ -27,10 +30,18 @@ public abstract class ConnectedTextureBehaviour { protected boolean isBeingBlocked(BlockState state, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos, Direction face) { BlockPos blockingPos = otherPos.relative(face); + BlockState blockState = reader.getBlockState(pos); + + if (blockState.getBlock() instanceof CopycatBlock ufb + && ufb.isUnblockableConnectivitySide(reader, blockState, face, pos, otherPos)) + return false; + return face.getAxis() .choose(pos.getX(), pos.getY(), pos.getZ()) == face.getAxis() .choose(otherPos.getX(), otherPos.getY(), otherPos.getZ()) - && connectsTo(state, reader.getBlockState(blockingPos), reader, pos, blockingPos, face); + && connectsTo(state, + getCTBlockState(reader, blockState, face.getOpposite(), pos.relative(face), blockingPos), reader, pos, + blockingPos, face); } public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, @@ -47,10 +58,27 @@ public abstract class ConnectedTextureBehaviour { final Direction horizontal, final Direction vertical, int sh, int sv) { BlockPos p = pos.relative(horizontal, sh) .relative(vertical, sv); - boolean test = connectsTo(state, reader.getBlockState(p), reader, pos, p, face, + BlockState blockState = reader.getBlockState(pos); + + if (blockState.getBlock() instanceof CopycatBlock ufb + && ufb.isIgnoredConnectivitySide(reader, blockState, face, pos, p)) + return false; + + return connectsTo(state, getCTBlockState(reader, blockState, face, pos, p), reader, pos, p, face, sh == 0 ? null : sh == -1 ? horizontal.getOpposite() : horizontal, sv == 0 ? null : sv == -1 ? vertical.getOpposite() : vertical); - return test; + } + + public BlockState getCTBlockState(BlockAndTintGetter reader, BlockState reference, Direction face, BlockPos fromPos, + BlockPos toPos) { + BlockState blockState = reader.getBlockState(toPos); + + if (blockState.getBlock() instanceof CopycatBlock ufb) { + BlockState connectiveMaterial = ufb.getConnectiveMaterial(reader, reference, face, fromPos, toPos); + return connectiveMaterial == null ? blockState : connectiveMaterial; + } + + return blockState; } protected boolean reverseUVs(BlockState state, Direction face) { @@ -75,7 +103,8 @@ public abstract class ConnectedTextureBehaviour { return axis == Axis.X ? Direction.SOUTH : Direction.WEST; } - public CTContext buildContext(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face, ContextRequirement requirement) { + public CTContext buildContext(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face, + ContextRequirement requirement) { boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE; Direction h = getRightDirection(reader, pos, state, face); Direction v = getUpDirection(reader, pos, state, face); @@ -139,7 +168,8 @@ public abstract class ConnectedTextureBehaviour { public final boolean up, down, left, right; public final boolean topLeft, topRight, bottomLeft, bottomRight; - public ContextRequirement(boolean up, boolean down, boolean left, boolean right, boolean topLeft, boolean topRight, boolean bottomLeft, boolean bottomRight) { + public ContextRequirement(boolean up, boolean down, boolean left, boolean right, boolean topLeft, + boolean topRight, boolean bottomLeft, boolean bottomRight) { this.up = up; this.down = down; this.left = left; @@ -239,11 +269,12 @@ public abstract class ConnectedTextureBehaviour { public static abstract class Base extends ConnectedTextureBehaviour { @Override @Nullable - public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite); + public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, + @Nullable TextureAtlasSprite sprite); @Override @Nullable - public CTType getDataType(BlockState state, Direction direction) { + public CTType getDataType(BlockAndTintGetter world, BlockPos pos, BlockState state, Direction direction) { CTSpriteShiftEntry shift = getShift(state, direction, null); if (shift == null) { return null; diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/RotatedPillarCTBehaviour.java b/src/main/java/com/simibubi/create/foundation/block/connected/RotatedPillarCTBehaviour.java index 55611e2bfc..b6e5e70ae7 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/RotatedPillarCTBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/RotatedPillarCTBehaviour.java @@ -1,7 +1,8 @@ package com.simibubi.create.foundation.block.connected; -import com.simibubi.create.content.palettes.ConnectedPillarBlock; -import com.simibubi.create.content.palettes.LayeredBlock; +import com.simibubi.create.content.decoration.copycat.CopycatBlock; +import com.simibubi.create.content.decoration.palettes.ConnectedPillarBlock; +import com.simibubi.create.content.decoration.palettes.LayeredBlock; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; @@ -27,6 +28,10 @@ public class RotatedPillarCTBehaviour extends HorizontalCTBehaviour { return false; if (isBeingBlocked(state, reader, pos, otherPos, face)) return false; + if (reader.getBlockState(pos).getBlock() instanceof CopycatBlock) + return true; + if (reader.getBlockState(otherPos).getBlock() instanceof CopycatBlock) + return true; if (primaryOffset != null && primaryOffset.getAxis() != stateAxis && !ConnectedPillarBlock.getConnection(state, primaryOffset)) return false; diff --git a/src/main/java/com/simibubi/create/foundation/block/render/BlockDestructionProgressExtension.java b/src/main/java/com/simibubi/create/foundation/block/render/BlockDestructionProgressExtension.java new file mode 100644 index 0000000000..2a7bca863f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/block/render/BlockDestructionProgressExtension.java @@ -0,0 +1,14 @@ +package com.simibubi.create.foundation.block.render; + +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.core.BlockPos; + +public interface BlockDestructionProgressExtension { + @Nullable + Set getExtraPositions(); + + void setExtraPositions(@Nullable Set positions); +} diff --git a/src/main/java/com/simibubi/create/foundation/block/render/CustomBlockModels.java b/src/main/java/com/simibubi/create/foundation/block/render/CustomBlockModels.java index 8dc43b692c..a6abf01012 100644 --- a/src/main/java/com/simibubi/create/foundation/block/render/CustomBlockModels.java +++ b/src/main/java/com/simibubi/create/foundation/block/render/CustomBlockModels.java @@ -16,7 +16,8 @@ import net.minecraftforge.registries.ForgeRegistries; public class CustomBlockModels { private final Multimap> modelFuncs = MultimapBuilder.hashKeys().arrayListValues().build(); - private final Map> finalModelFunc = new IdentityHashMap<>(); + private final Map> finalModelFuncs = new IdentityHashMap<>(); + private boolean funcsLoaded = false; public void register(ResourceLocation block, NonNullFunction func) { modelFuncs.put(block, func); @@ -24,16 +25,18 @@ public class CustomBlockModels { public void forEach(NonNullBiConsumer> consumer) { loadEntriesIfMissing(); - finalModelFunc.forEach(consumer); + finalModelFuncs.forEach(consumer); } private void loadEntriesIfMissing() { - if (finalModelFunc.isEmpty()) + if (!funcsLoaded) { loadEntries(); + funcsLoaded = true; + } } private void loadEntries() { - finalModelFunc.clear(); + finalModelFuncs.clear(); modelFuncs.asMap().forEach((location, funcList) -> { Block block = ForgeRegistries.BLOCKS.getValue(location); if (block == null) { @@ -49,7 +52,7 @@ public class CustomBlockModels { } } - finalModelFunc.put(block, finalFunc); + finalModelFuncs.put(block, finalFunc); }); } diff --git a/src/main/java/com/simibubi/create/foundation/block/render/DestroyProgressRenderingHandler.java b/src/main/java/com/simibubi/create/foundation/block/render/DestroyProgressRenderingHandler.java deleted file mode 100644 index e077bad1b4..0000000000 --- a/src/main/java/com/simibubi/create/foundation/block/render/DestroyProgressRenderingHandler.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.simibubi.create.foundation.block.render; - -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.IBlockRenderProperties; - -public interface DestroyProgressRenderingHandler extends IBlockRenderProperties { - /** - * Called before the default block breaking progress overlay is rendered. - * - * @return if the default rendering should be cancelled or not - */ - boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos, int progress, BlockState blockState); -} diff --git a/src/main/java/com/simibubi/create/foundation/block/render/MultiPosDestructionHandler.java b/src/main/java/com/simibubi/create/foundation/block/render/MultiPosDestructionHandler.java new file mode 100644 index 0000000000..38176411e1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/block/render/MultiPosDestructionHandler.java @@ -0,0 +1,17 @@ +package com.simibubi.create.foundation.block.render; + +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; + +public interface MultiPosDestructionHandler { + /** + * Returned set must be mutable and must not be changed after it is returned. + */ + @Nullable + Set getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress); +} diff --git a/src/main/java/com/simibubi/create/foundation/block/render/QuadHelper.java b/src/main/java/com/simibubi/create/foundation/block/render/QuadHelper.java deleted file mode 100644 index 8c59fccc34..0000000000 --- a/src/main/java/com/simibubi/create/foundation/block/render/QuadHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.simibubi.create.foundation.block.render; - -import java.util.Arrays; - -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; - -import net.minecraft.client.renderer.block.model.BakedQuad; - -public final class QuadHelper { - - public static final VertexFormat FORMAT = DefaultVertexFormat.BLOCK; - public static final int VERTEX_STRIDE = FORMAT.getIntegerSize(); - - public static final int X_OFFSET = 0; - public static final int Y_OFFSET = 1; - public static final int Z_OFFSET = 2; - public static final int COLOR_OFFSET = 3; - public static final int U_OFFSET = 4; - public static final int V_OFFSET = 5; - public static final int LIGHT_OFFSET = 6; - public static final int NORMAL_OFFSET = 7; - - private QuadHelper() {} - - public static BakedQuad clone(BakedQuad quad) { - return new BakedQuad(Arrays.copyOf(quad.getVertices(), quad.getVertices().length), - quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade()); - } - - public static float getU(int[] vertexData, int vertex) { - return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + U_OFFSET]); - } - - public static float getV(int[] vertexData, int vertex) { - return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + V_OFFSET]); - } - - public static void setU(int[] vertexData, int vertex, float u) { - vertexData[vertex * VERTEX_STRIDE + U_OFFSET] = Float.floatToRawIntBits(u); - } - - public static void setV(int[] vertexData, int vertex, float v) { - vertexData[vertex * VERTEX_STRIDE + V_OFFSET] = Float.floatToRawIntBits(v); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/CachedRenderBBBlockEntity.java b/src/main/java/com/simibubi/create/foundation/blockEntity/CachedRenderBBBlockEntity.java new file mode 100644 index 0000000000..d8cd7d6411 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/CachedRenderBBBlockEntity.java @@ -0,0 +1,35 @@ +package com.simibubi.create.foundation.blockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class CachedRenderBBBlockEntity extends SyncedBlockEntity { + + private AABB renderBoundingBox; + + public CachedRenderBBBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + @OnlyIn(Dist.CLIENT) + public AABB getRenderBoundingBox() { + if (renderBoundingBox == null) { + renderBoundingBox = createRenderBoundingBox(); + } + return renderBoundingBox; + } + + protected void invalidateRenderBoundingBox() { + renderBoundingBox = null; + } + + protected AABB createRenderBoundingBox() { + return super.getRenderBoundingBox(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/ComparatorUtil.java b/src/main/java/com/simibubi/create/foundation/blockEntity/ComparatorUtil.java new file mode 100644 index 0000000000..344e1f46ee --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/ComparatorUtil.java @@ -0,0 +1,27 @@ +package com.simibubi.create.foundation.blockEntity; + +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.fluid.SmartFluidTank; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockGetter; + +public class ComparatorUtil { + + public static int fractionToRedstoneLevel(double frac) { + return Mth.floor(Mth.clamp(frac * 14 + (frac > 0 ? 1 : 0), 0, 15)); + } + + public static int levelOfSmartFluidTank(BlockGetter world, BlockPos pos) { + SmartFluidTankBehaviour fluidBehaviour = BlockEntityBehaviour.get(world, pos, SmartFluidTankBehaviour.TYPE); + if (fluidBehaviour == null) + return 0; + SmartFluidTank primaryHandler = fluidBehaviour.getPrimaryHandler(); + double fillFraction = (double) primaryHandler.getFluid() + .getAmount() / primaryHandler.getCapacity(); + return fractionToRedstoneLevel(fillFraction); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/IMergeableBE.java b/src/main/java/com/simibubi/create/foundation/blockEntity/IMergeableBE.java new file mode 100644 index 0000000000..d96340cb17 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/IMergeableBE.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.blockEntity; + +import net.minecraft.world.level.block.entity.BlockEntity; + +public interface IMergeableBE { + + public void accept(BlockEntity other); + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/IMultiBlockEntityContainer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/IMultiBlockEntityContainer.java new file mode 100644 index 0000000000..7fc3e8dd09 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/IMultiBlockEntityContainer.java @@ -0,0 +1,75 @@ +package com.simibubi.create.foundation.blockEntity; + +import javax.annotation.Nullable; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; + +public interface IMultiBlockEntityContainer { + + BlockPos getController(); + T getControllerBE (); + boolean isController(); + void setController(BlockPos pos); + void removeController (boolean keepContents); + BlockPos getLastKnownPos(); + + void preventConnectivityUpdate (); + void notifyMultiUpdated (); + + // only used for FluidTank windows at present. Might be useful for similar properties on other things? + default void setExtraData (@Nullable Object data) {} + @Nullable + default Object getExtraData () { return null; } + default Object modifyExtraData (Object data) { return data; } + + // multiblock structural information + Direction.Axis getMainConnectionAxis(); + default Direction.Axis getMainAxisOf (BlockEntity be) { // this feels redundant, but it gives us a default to use when defining ::getMainConnectionAxis + BlockState state = be.getBlockState(); + + Direction.Axis axis; + if (state.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) { + axis = state.getValue(BlockStateProperties.HORIZONTAL_AXIS); + } + else if (state.hasProperty(BlockStateProperties.FACING)) { + axis = state.getValue(BlockStateProperties.FACING).getAxis(); + } + else if (state.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) { + axis = state.getValue(BlockStateProperties.HORIZONTAL_FACING).getAxis(); + } + else axis = Direction.Axis.Y; + + return axis; + } + + int getMaxLength (Direction.Axis longAxis, int width); + int getMaxWidth (); + + int getHeight (); + void setHeight (int height); + int getWidth (); + void setWidth (int width); + + public interface Inventory extends IMultiBlockEntityContainer { + default boolean hasInventory() { return false; } + } + + public interface Fluid extends IMultiBlockEntityContainer { + // done here rather than through the Capability to allow greater flexibility + default boolean hasTank() { return false; } + + default int getTankSize(int tank) { return 0; } + + default void setTankSize(int tank, int blocks) {} + + default IFluidTank getTank(int tank) { return null; } + + default FluidStack getFluid(int tank) { return FluidStack.EMPTY; } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/RemoveBlockEntityPacket.java b/src/main/java/com/simibubi/create/foundation/blockEntity/RemoveBlockEntityPacket.java new file mode 100644 index 0000000000..8cd7ce215d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/RemoveBlockEntityPacket.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.blockEntity; + +import com.simibubi.create.foundation.networking.BlockEntityDataPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class RemoveBlockEntityPacket extends BlockEntityDataPacket { + + public RemoveBlockEntityPacket(BlockPos pos) { + super(pos); + } + + public RemoveBlockEntityPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeData(FriendlyByteBuf buffer) {} + + @Override + protected void handlePacket(SyncedBlockEntity be) { + if (!be.hasLevel()) { + be.setRemoved(); + return; + } + + be.getLevel() + .removeBlockEntity(pos); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java new file mode 100644 index 0000000000..0e3931ad00 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntity.java @@ -0,0 +1,269 @@ +package com.simibubi.create.foundation.blockEntity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import com.simibubi.create.api.event.BlockEntityBehaviourEvent; +import com.simibubi.create.content.schematics.requirement.ISpecialBlockEntityItemRequirement; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.advancement.AdvancementBehaviour; +import com.simibubi.create.foundation.advancement.CreateAdvancement; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.utility.IInteractionChecker; +import com.simibubi.create.foundation.utility.IPartialSafeNBT; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; + +public abstract class SmartBlockEntity extends CachedRenderBBBlockEntity + implements IPartialSafeNBT, IInteractionChecker, ISpecialBlockEntityItemRequirement { + + private final Map, BlockEntityBehaviour> behaviours = new HashMap<>(); + private boolean initialized = false; + private boolean firstNbtRead = true; + protected int lazyTickRate; + protected int lazyTickCounter; + private boolean chunkUnloaded; + + // Used for simulating this BE in a client-only setting + private boolean virtualMode; + + public SmartBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + + setLazyTickRate(10); + + ArrayList list = new ArrayList<>(); + addBehaviours(list); + list.forEach(b -> behaviours.put(b.getType(), b)); + } + + public abstract void addBehaviours(List behaviours); + + /** + * Gets called just before reading block entity data for behaviours. Register + * anything here that depends on your custom BE data. + */ + public void addBehavioursDeferred(List behaviours) {} + + public void initialize() { + if (firstNbtRead) { + firstNbtRead = false; + MinecraftForge.EVENT_BUS.post(new BlockEntityBehaviourEvent<>(this, behaviours)); + } + + forEachBehaviour(BlockEntityBehaviour::initialize); + lazyTick(); + } + + public void tick() { + if (!initialized && hasLevel()) { + initialize(); + initialized = true; + } + + if (lazyTickCounter-- <= 0) { + lazyTickCounter = lazyTickRate; + lazyTick(); + } + + forEachBehaviour(BlockEntityBehaviour::tick); + } + + public void lazyTick() {} + + /** + * Hook only these in future subclasses of STE + */ + protected void write(CompoundTag tag, boolean clientPacket) { + super.saveAdditional(tag); + forEachBehaviour(tb -> tb.write(tag, clientPacket)); + } + + @Override + public void writeSafe(CompoundTag tag) { + super.saveAdditional(tag); + forEachBehaviour(tb -> { + if (tb.isSafeNBT()) + tb.write(tag, false); + }); + } + + /** + * Hook only these in future subclasses of STE + */ + protected void read(CompoundTag tag, boolean clientPacket) { + if (firstNbtRead) { + firstNbtRead = false; + ArrayList list = new ArrayList<>(); + addBehavioursDeferred(list); + list.forEach(b -> behaviours.put(b.getType(), b)); + MinecraftForge.EVENT_BUS.post(new BlockEntityBehaviourEvent<>(this, behaviours)); + } + super.load(tag); + forEachBehaviour(tb -> tb.read(tag, clientPacket)); + } + + @Override + public final void load(CompoundTag tag) { + read(tag, false); + } + + @Override + public void onChunkUnloaded() { + super.onChunkUnloaded(); + chunkUnloaded = true; + } + + @Override + public final void setRemoved() { + super.setRemoved(); + if (!chunkUnloaded) + remove(); + invalidate(); + } + + /** + * Block destroyed or Chunk unloaded. Usually invalidates capabilities + */ + public void invalidate() { + forEachBehaviour(BlockEntityBehaviour::unload); + } + + /** + * Block destroyed or picked up by a contraption. Usually detaches kinetics + */ + public void remove() {} + + /** + * Block destroyed or replaced. Requires Block to call IBE::onRemove + */ + public void destroy() { + forEachBehaviour(BlockEntityBehaviour::destroy); + } + + @Override + public final void saveAdditional(CompoundTag tag) { + write(tag, false); + } + + @Override + public final void readClient(CompoundTag tag) { + read(tag, true); + } + + @Override + public final CompoundTag writeClient(CompoundTag tag) { + write(tag, true); + return tag; + } + + @SuppressWarnings("unchecked") + public T getBehaviour(BehaviourType type) { + return (T) behaviours.get(type); + } + + public void forEachBehaviour(Consumer action) { + getAllBehaviours().forEach(action); + } + + public Collection getAllBehaviours() { + return behaviours.values(); + } + + protected void attachBehaviourLate(BlockEntityBehaviour behaviour) { + behaviours.put(behaviour.getType(), behaviour); + behaviour.initialize(); + } + + public ItemRequirement getRequiredItems(BlockState state) { + return getAllBehaviours().stream() + .reduce(ItemRequirement.NONE, (r, b) -> r.union(b.getRequiredItems()), (r, r1) -> r.union(r1)); + } + + protected void removeBehaviour(BehaviourType type) { + BlockEntityBehaviour remove = behaviours.remove(type); + if (remove != null) { + remove.unload(); + } + } + + public void setLazyTickRate(int slowTickRate) { + this.lazyTickRate = slowTickRate; + this.lazyTickCounter = slowTickRate; + } + + public void markVirtual() { + virtualMode = true; + } + + public boolean isVirtual() { + return virtualMode; + } + + public boolean isChunkUnloaded() { + return chunkUnloaded; + } + + @Override + public boolean canPlayerUse(Player player) { + if (level == null || level.getBlockEntity(worldPosition) != this) + return false; + return player.distanceToSqr(worldPosition.getX() + 0.5D, worldPosition.getY() + 0.5D, + worldPosition.getZ() + 0.5D) <= 64.0D; + } + + public void sendToMenu(FriendlyByteBuf buffer) { + buffer.writeBlockPos(getBlockPos()); + buffer.writeNbt(getUpdateTag()); + } + + @SuppressWarnings("deprecation") + public void refreshBlockState() { + setBlockState(getLevel().getBlockState(getBlockPos())); + } + + protected boolean isItemHandlerCap(Capability cap) { + return cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + } + + protected boolean isFluidHandlerCap(Capability cap) { + return cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY; + } + + public void registerAwardables(List behaviours, CreateAdvancement... advancements) { + for (BlockEntityBehaviour behaviour : behaviours) { + if (behaviour instanceof AdvancementBehaviour ab) { + ab.add(advancements); + return; + } + } + behaviours.add(new AdvancementBehaviour(this, advancements)); + } + + public void award(CreateAdvancement advancement) { + AdvancementBehaviour behaviour = getBehaviour(AdvancementBehaviour.TYPE); + if (behaviour != null) + behaviour.awardPlayer(advancement); + } + + public void awardIfNear(CreateAdvancement advancement, int range) { + AdvancementBehaviour behaviour = getBehaviour(AdvancementBehaviour.TYPE); + if (behaviour != null) + behaviour.awardPlayerIfNear(advancement, range); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntityTicker.java b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntityTicker.java new file mode 100644 index 0000000000..7485e7f856 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/SmartBlockEntityTicker.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.blockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.state.BlockState; + +public class SmartBlockEntityTicker implements BlockEntityTicker { + + @Override + public void tick(Level p_155253_, BlockPos p_155254_, BlockState p_155255_, T p_155256_) { + if (!p_155256_.hasLevel()) + p_155256_.setLevel(p_155253_); + ((SmartBlockEntity) p_155256_).tick(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/SyncedBlockEntity.java b/src/main/java/com/simibubi/create/foundation/blockEntity/SyncedBlockEntity.java new file mode 100644 index 0000000000..842077a842 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/SyncedBlockEntity.java @@ -0,0 +1,74 @@ +package com.simibubi.create.foundation.blockEntity; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraftforge.network.PacketDistributor; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public abstract class SyncedBlockEntity extends BlockEntity { + + public SyncedBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Override + public CompoundTag getUpdateTag() { + return writeClient(new CompoundTag()); + } + + @Override + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public void handleUpdateTag(CompoundTag tag) { + readClient(tag); + } + + @Override + public void onDataPacket(Connection connection, ClientboundBlockEntityDataPacket packet) { + CompoundTag tag = packet.getTag(); + readClient(tag == null ? new CompoundTag() : tag); + } + + // Special handling for client update packets + public void readClient(CompoundTag tag) { + load(tag); + } + + // Special handling for client update packets + public CompoundTag writeClient(CompoundTag tag) { + saveAdditional(tag); + return tag; + } + + public void sendData() { + if (level instanceof ServerLevel serverLevel) + serverLevel.getChunkSource().blockChanged(getBlockPos()); + } + + public void notifyUpdate() { + setChanged(); + sendData(); + } + + public PacketDistributor.PacketTarget packetTarget() { + return PacketDistributor.TRACKING_CHUNK.with(this::containedChunk); + } + + public LevelChunk containedChunk() { + return level.getChunkAt(worldPosition); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BehaviourType.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BehaviourType.java new file mode 100644 index 0000000000..4ef84aa6e4 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BehaviourType.java @@ -0,0 +1,23 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +public class BehaviourType { + + private String name; + + public BehaviourType(String name) { + this.name = name; + } + + public BehaviourType() { + this(""); + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + return super.hashCode() * 31 * 493286711; // Better hash table distribution + } +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BlockEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BlockEntityBehaviour.java new file mode 100644 index 0000000000..d52125dea1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/BlockEntityBehaviour.java @@ -0,0 +1,109 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import java.util.ConcurrentModificationException; + +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public abstract class BlockEntityBehaviour { + + public SmartBlockEntity blockEntity; + private int lazyTickRate; + private int lazyTickCounter; + + public BlockEntityBehaviour(SmartBlockEntity be) { + blockEntity = be; + setLazyTickRate(10); + } + + public abstract BehaviourType getType(); + + public void initialize() { + + } + + public void tick() { + if (lazyTickCounter-- <= 0) { + lazyTickCounter = lazyTickRate; + lazyTick(); + } + + } + + public void read(CompoundTag nbt, boolean clientPacket) { + + } + + public void write(CompoundTag nbt, boolean clientPacket) { + + } + + public boolean isSafeNBT() { + return false; + } + + public ItemRequirement getRequiredItems() { + return ItemRequirement.NONE; + } + + public void onBlockChanged(BlockState oldState) { + + } + + public void onNeighborChanged(BlockPos neighborPos) { + + } + + /** + * Block destroyed or Chunk unloaded. Usually invalidates capabilities + */ + public void unload() {} + + /** + * Block destroyed or removed. Requires block to call ITE::onRemove + */ + public void destroy() {} + + public void setLazyTickRate(int slowTickRate) { + this.lazyTickRate = slowTickRate; + this.lazyTickCounter = slowTickRate; + } + + public void lazyTick() { + + } + + public BlockPos getPos() { + return blockEntity.getBlockPos(); + } + + public Level getWorld() { + return blockEntity.getLevel(); + } + + public static T get(BlockGetter reader, BlockPos pos, BehaviourType type) { + BlockEntity be; + try { + be = reader.getBlockEntity(pos); + } catch (ConcurrentModificationException e) { + be = null; + } + return get(be, type); + } + + public static T get(BlockEntity be, BehaviourType type) { + if (be == null) + return null; + if (!(be instanceof SmartBlockEntity)) + return null; + SmartBlockEntity ste = (SmartBlockEntity) be; + return ste.getBehaviour(type); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/CenteredSideValueBoxTransform.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/CenteredSideValueBoxTransform.java similarity index 88% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/CenteredSideValueBoxTransform.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/CenteredSideValueBoxTransform.java index f042b42e37..bc03190861 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/CenteredSideValueBoxTransform.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/CenteredSideValueBoxTransform.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.tileEntity.behaviour; +package com.simibubi.create.foundation.blockEntity.behaviour; import java.util.function.BiPredicate; @@ -21,7 +21,7 @@ public class CenteredSideValueBoxTransform extends ValueBoxTransform.Sided { @Override protected Vec3 getSouthLocation() { - return VecHelper.voxelSpace(8, 8, 16); + return VecHelper.voxelSpace(8, 8, 15.5); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java new file mode 100644 index 0000000000..d8ce3e0614 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBox.java @@ -0,0 +1,239 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.gui.AllIcons; + +import net.createmod.catnip.render.SuperRenderTypeBuffer; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.outliner.ChasingAABBOutline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.ItemMultiLayerBakedModel; + +public class ValueBox extends ChasingAABBOutline { + + protected Component label; + protected Component sublabel = Components.immutableEmpty(); + protected Component scrollTooltip = Components.immutableEmpty(); + protected Vec3 labelOffset = Vec3.ZERO; + + public int overrideColor = -1; + + public boolean isPassive; + + protected BlockPos pos; + protected ValueBoxTransform transform; + protected BlockState blockState; + + protected AllIcons outline = AllIcons.VALUE_BOX_HOVER_4PX; + + public ValueBox(Component label, AABB bb, BlockPos pos) { + this(label, bb, pos, Minecraft.getInstance().level.getBlockState(pos)); + } + + public ValueBox(Component label, AABB bb, BlockPos pos, BlockState state) { + super(bb); + this.label = label; + this.pos = pos; + this.blockState = state; + } + + public ValueBox transform(ValueBoxTransform transform) { + this.transform = transform; + return this; + } + + public ValueBox wideOutline() { + this.outline = AllIcons.VALUE_BOX_HOVER_6PX; + return this; + } + + public ValueBox passive(boolean passive) { + this.isPassive = passive; + return this; + } + + public ValueBox withColor(int color) { + this.overrideColor = color; + return this; + } + + @Override + public void render(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, float pt) { + boolean hasTransform = transform != null; + if (transform instanceof Sided && params.getHighlightedFace() != null) + ((Sided) transform).fromSide(params.getHighlightedFace()); + if (hasTransform && !transform.shouldRender(blockState)) + return; + + ms.pushPose(); + ms.translate(pos.getX() - camera.x, pos.getY() - camera.y, pos.getZ() - camera.z); + if (hasTransform) + transform.transform(blockState, ms); + + if (!isPassive) { + ms.pushPose(); + ms.scale(-2.01f, -2.01f, 2.01f); + ms.translate(-8 / 16.0, -8 / 16.0, -.5 / 16.0); + getOutline().render(ms, buffer, 0xffffff); + ms.popPose(); + } + + float fontScale = hasTransform ? -transform.getFontScale() : -1 / 64f; + ms.scale(fontScale, fontScale, fontScale); + renderContents(ms, buffer); + + ms.popPose(); + } + + public AllIcons getOutline() { + return outline; + } + + public void renderContents(PoseStack ms, MultiBufferSource buffer) {} + + public static class ItemValueBox extends ValueBox { + ItemStack stack; + int count; + boolean upTo; + + public ItemValueBox(Component label, AABB bb, BlockPos pos, ItemStack stack, int count, boolean upTo) { + super(label, bb, pos); + this.stack = stack; + this.count = count; + this.upTo = upTo; + } + + @Override + public AllIcons getOutline() { + if (!stack.isEmpty()) + return AllIcons.VALUE_BOX_HOVER_6PX; + return super.getOutline(); + } + + @Override + public void renderContents(PoseStack ms, MultiBufferSource buffer) { + super.renderContents(ms, buffer); + if (count == -1) + return; + + Font font = Minecraft.getInstance().font; + boolean wildcard = count == 0 || upTo && count == stack.getMaxStackSize(); + Component countString = Components.literal(wildcard ? "*" : count + ""); + ms.translate(17.5f, -5f, 7f); + + boolean isFilter = stack.getItem() instanceof FilterItem; + boolean isEmpty = stack.isEmpty(); + + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + BakedModel modelWithOverrides = itemRenderer.getModel(stack, null, null, 0); + boolean blockItem = + modelWithOverrides.isGui3d() && !(modelWithOverrides instanceof ItemMultiLayerBakedModel); + + float scale = 1.5f; + ms.translate(-font.width(countString), 0, 0); + + if (isFilter) + ms.translate(-5, 8, 7.25f); + else if (isEmpty) { + ms.translate(-15, -1f, -2.75f); + scale = 1.65f; + } else + ms.translate(-7, 10, blockItem ? 10 + 1 / 4f : 0); + + if (wildcard) + ms.translate(-1, 3f, 0); + + ms.scale(scale, scale, scale); + drawString(ms, buffer, countString, 0, 0, isFilter ? 0xFFFFFF : 0xEDEDED); + ms.translate(0, 0, -1 / 16f); + drawString(ms, buffer, countString, 1 - 1 / 8f, 1 - 1 / 8f, 0x4F4F4F); + } + + } + + public static class TextValueBox extends ValueBox { + Component text; + + public TextValueBox(Component label, AABB bb, BlockPos pos, Component text) { + super(label, bb, pos); + this.text = text; + } + + public TextValueBox(Component label, AABB bb, BlockPos pos, BlockState state, Component text) { + super(label, bb, pos, state); + this.text = text; + } + + @Override + public void renderContents(PoseStack ms, MultiBufferSource buffer) { + super.renderContents(ms, buffer); + Font font = Minecraft.getInstance().font; + float scale = 3; + ms.scale(scale, scale, 1); + ms.translate(-4, -3.75, 5); + + int stringWidth = font.width(text); + float numberScale = (float) font.lineHeight / stringWidth; + boolean singleDigit = stringWidth < 10; + if (singleDigit) + numberScale = numberScale / 2; + float verticalMargin = (stringWidth - font.lineHeight) / 2f; + + ms.scale(numberScale, numberScale, numberScale); + ms.translate(singleDigit ? stringWidth / 2 : 0, singleDigit ? -verticalMargin : verticalMargin, 0); + + int overrideColor = transform.getOverrideColor(); + renderHoveringText(ms, buffer, text, overrideColor != -1 ? overrideColor : 0xEDEDED); + } + + } + + public static class IconValueBox extends ValueBox { + AllIcons icon; + + public IconValueBox(Component label, INamedIconOptions iconValue, AABB bb, BlockPos pos) { + super(label, bb, pos); + icon = iconValue.getIcon(); + } + + @Override + public void renderContents(PoseStack ms, MultiBufferSource buffer) { + super.renderContents(ms, buffer); + float scale = 2 * 16; + ms.scale(scale, scale, scale); + ms.translate(-.5f, -.5f, 5 / 32f); + + int overrideColor = transform.getOverrideColor(); + icon.render(ms, buffer, overrideColor != -1 ? overrideColor : 0xFFFFFF); + } + + } + + protected void renderHoveringText(PoseStack ms, MultiBufferSource buffer, Component text, int color) { + ms.pushPose(); + drawString(ms, buffer, text, 0, 0, color); + ms.popPose(); + } + + private static void drawString(PoseStack ms, MultiBufferSource buffer, Component text, float x, float y, + int color) { + Minecraft.getInstance().font.drawInBatch(text, x, y, color, false, ms.last() + .pose(), buffer, false, 0, LightTexture.FULL_BRIGHT); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxRenderer.java new file mode 100644 index 0000000000..7fb84b09bd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxRenderer.java @@ -0,0 +1,96 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix3f; +import com.simibubi.create.content.kinetics.simpleRelays.AbstractSimpleShaftBlock; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.FenceBlock; +import net.minecraftforge.client.model.ItemMultiLayerBakedModel; + +public class ValueBoxRenderer { + + public static void renderItemIntoValueBox(ItemStack filter, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + ItemRenderer itemRenderer = Minecraft.getInstance() + .getItemRenderer(); + BakedModel modelWithOverrides = itemRenderer.getModel(filter, null, null, 0); + boolean blockItem = modelWithOverrides.isGui3d() && !(modelWithOverrides instanceof ItemMultiLayerBakedModel); + float scale = (!blockItem ? .5f : 1f) + 1 / 64f; + float zOffset = (!blockItem ? -.15f : 0) + customZOffset(filter.getItem()); + ms.scale(scale, scale, scale); + ms.translate(0, 0, zOffset); + itemRenderer.renderStatic(filter, TransformType.FIXED, light, overlay, ms, buffer, 0); + } + + public static void renderFlatItemIntoValueBox(ItemStack filter, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + if (filter.isEmpty()) + return; + + int bl = light >> 4 & 0xf; + int sl = light >> 20 & 0xf; + int itemLight = Mth.floor(sl + .5) << 20 | (Mth.floor(bl + .5) & 0xf) << 4; + + ms.pushPose(); + TransformStack.cast(ms) + .rotateX(230); + Matrix3f copy = ms.last() + .normal() + .copy(); + ms.popPose(); + + ms.pushPose(); + TransformStack.cast(ms) + .translate(0, 0, -1 / 4f) + .translate(0, 0, 1 / 32f + .001) + .rotateY(180); + + PoseStack squashedMS = new PoseStack(); + squashedMS.last() + .pose() + .multiply(ms.last() + .pose()); + squashedMS.scale(.5f, .5f, 1 / 1024f); + squashedMS.last() + .normal() + .load(copy); + Minecraft.getInstance() + .getItemRenderer() + .renderStatic(filter, TransformType.GUI, itemLight, OverlayTexture.NO_OVERLAY, squashedMS, buffer, 0); + + ms.popPose(); + } + + @SuppressWarnings("deprecation") + private static float customZOffset(Item item) { + float nudge = -.1f; + if (item instanceof BlockItem) { + Block block = ((BlockItem) item).getBlock(); + if (block instanceof AbstractSimpleShaftBlock) + return nudge; + if (block instanceof FenceBlock) + return nudge; + if (block.builtInRegistryHolder() + .is(BlockTags.BUTTONS)) + return nudge; + if (block == Blocks.END_ROD) + return nudge; + } + return 0; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBoxTransform.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxTransform.java similarity index 89% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBoxTransform.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxTransform.java index bd63ddc223..867ac26fae 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/ValueBoxTransform.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueBoxTransform.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.tileEntity.behaviour; +package com.simibubi.create.foundation.blockEntity.behaviour; import java.util.function.Function; @@ -20,9 +20,9 @@ public abstract class ValueBoxTransform { protected float scale = getScale(); - protected abstract Vec3 getLocalOffset(BlockState state); + public abstract Vec3 getLocalOffset(BlockState state); - protected abstract void rotate(BlockState state, PoseStack ms); + public abstract void rotate(BlockState state, PoseStack ms); public boolean testHit(BlockState state, Vec3 localHit) { Vec3 offset = getLocalOffset(state); @@ -44,6 +44,10 @@ public abstract class ValueBoxTransform { return state.getMaterial() != Material.AIR && getLocalOffset(state) != null; } + public int getOverrideColor() { + return -1; + } + protected Vec3 rotateHorizontally(BlockState state, Vec3 vec) { float yRot = 0; if (state.hasProperty(BlockStateProperties.FACING)) @@ -53,11 +57,11 @@ public abstract class ValueBoxTransform { return VecHelper.rotateCentered(vec, yRot, Axis.Y); } - protected float getScale() { - return .4f; + public float getScale() { + return .5f; } - protected float getFontScale() { + public float getFontScale() { return 1 / 64f; } @@ -96,7 +100,7 @@ public abstract class ValueBoxTransform { } @Override - protected Vec3 getLocalOffset(BlockState state) { + public Vec3 getLocalOffset(BlockState state) { Vec3 location = getSouthLocation(); location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Axis.Y); location = VecHelper.rotateCentered(location, AngleHelper.verticalAngle(getSide()), Axis.X); @@ -106,7 +110,7 @@ public abstract class ValueBoxTransform { protected abstract Vec3 getSouthLocation(); @Override - protected void rotate(BlockState state, PoseStack ms) { + public void rotate(BlockState state, PoseStack ms) { float yRot = AngleHelper.horizontalAngle(getSide()) + 180; float xRot = getSide() == Direction.UP ? 90 : getSide() == Direction.DOWN ? 270 : 0; TransformStack.cast(ms) diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBehaviour.java new file mode 100644 index 0000000000..762179bd3d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBehaviour.java @@ -0,0 +1,85 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import com.simibubi.create.content.equipment.clipboard.ClipboardCloneable; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; + +public interface ValueSettingsBehaviour extends ClipboardCloneable { + + public static record ValueSettings(int row, int value) { + + public MutableComponent format() { + return CreateLang.number(value) + .component(); + } + + }; + + public boolean testHit(Vec3 hit); + + public boolean isActive(); + + default boolean onlyVisibleWithWrench() { + return false; + } + + default void newSettingHovered(ValueSettings valueSetting) {} + + public ValueBoxTransform getSlotPositioning(); + + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult); + + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown); + + public ValueSettings getValueSettings(); + + default boolean acceptsValueSettings() { + return true; + } + + @Override + default String getClipboardKey() { + return "Settings"; + } + + @Override + default boolean writeToClipboard(CompoundTag tag, Direction side) { + if (!acceptsValueSettings()) + return false; + ValueSettings valueSettings = getValueSettings(); + tag.putInt("Value", valueSettings.value()); + tag.putInt("Row", valueSettings.row()); + return true; + } + + @Override + default boolean readFromClipboard(CompoundTag tag, Player player, Direction side, boolean simulate) { + if (!acceptsValueSettings()) + return false; + if (!tag.contains("Value") || !tag.contains("Row")) + return false; + if (simulate) + return true; + setValueSettings(player, new ValueSettings(tag.getInt("Row"), tag.getInt("Value")), false); + return true; + } + + default void playFeedbackSound(BlockEntityBehaviour origin) { + origin.getWorld() + .playSound(null, origin.getPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.25f, 2f); + origin.getWorld() + .playSound(null, origin.getPos(), SoundEvents.NOTE_BLOCK_IRON_XYLOPHONE, SoundSource.BLOCKS, 0.03f, 1.125f); + } + + default void onShortInteract(Player player, InteractionHand hand, Direction side) {} + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBoard.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBoard.java new file mode 100644 index 0000000000..625e64e225 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsBoard.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import java.util.List; + +import net.minecraft.network.chat.Component; + +public record ValueSettingsBoard(Component title, int maxValue, int milestoneInterval, List rows, + ValueSettingsFormatter formatter) { +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsClient.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsClient.java new file mode 100644 index 0000000000..3197341c31 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsClient.java @@ -0,0 +1,143 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllPackets; + +import net.createmod.catnip.gui.ScreenOpener; +import net.createmod.catnip.utility.theme.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraftforge.client.gui.ForgeIngameGui; +import net.minecraftforge.client.gui.IIngameOverlay; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; + +public class ValueSettingsClient implements IIngameOverlay { + + private Minecraft mc; + + public int interactHeldTicks = -1; + public BlockPos interactHeldPos = null; + public BehaviourType interactHeldBehaviour = null; + public InteractionHand interactHeldHand = null; + public Direction interactHeldFace = null; + + public List lastHoverTip; + public int hoverTicks; + public int hoverWarmup; + + public ValueSettingsClient() { + mc = Minecraft.getInstance(); + } + + public void cancelIfWarmupAlreadyStarted(PlayerInteractEvent.RightClickBlock event) { + if (interactHeldTicks != -1 && event.getPos() + .equals(interactHeldPos)) { + event.setCanceled(true); + event.setCancellationResult(InteractionResult.FAIL); + } + } + + public void startInteractionWith(BlockPos pos, BehaviourType behaviourType, InteractionHand hand, + Direction side) { + interactHeldTicks = 0; + interactHeldPos = pos; + interactHeldBehaviour = behaviourType; + interactHeldHand = hand; + interactHeldFace = side; + } + + public void cancelInteraction() { + interactHeldTicks = -1; + } + + public void tick() { + if (hoverWarmup > 0) + hoverWarmup--; + if (hoverTicks > 0) + hoverTicks--; + if (interactHeldTicks == -1) + return; + Player player = mc.player; + + if (!ValueSettingsInputHandler.canInteract(player) || AllBlocks.CLIPBOARD.isIn(player.getMainHandItem())) { + cancelInteraction(); + return; + } + HitResult hitResult = mc.hitResult; + if (!(hitResult instanceof BlockHitResult blockHitResult) || !blockHitResult.getBlockPos() + .equals(interactHeldPos)) { + cancelInteraction(); + return; + } + BlockEntityBehaviour behaviour = BlockEntityBehaviour.get(mc.level, interactHeldPos, interactHeldBehaviour); + if (!(behaviour instanceof ValueSettingsBehaviour valueSettingBehaviour) + || !valueSettingBehaviour.testHit(blockHitResult.getLocation())) { + cancelInteraction(); + return; + } + if (!mc.options.keyUse.isDown()) { + AllPackets.getChannel() + .sendToServer( + new ValueSettingsPacket(interactHeldPos, 0, 0, interactHeldHand, interactHeldFace, false)); + cancelInteraction(); + return; + } + + if (interactHeldTicks > 3) + player.swinging = false; + if (interactHeldTicks++ < 5) + return; + ScreenOpener + .open(new ValueSettingsScreen(interactHeldPos, valueSettingBehaviour.createBoard(player, blockHitResult), + valueSettingBehaviour.getValueSettings(), valueSettingBehaviour::newSettingHovered)); + interactHeldTicks = -1; + } + + public void showHoverTip(List tip) { + if (mc.screen != null) + return; + if (hoverWarmup < 6) { + hoverWarmup += 2; + return; + } else + hoverWarmup++; + hoverTicks = hoverTicks == 0 ? 11 : Math.max(hoverTicks, 6); + lastHoverTip = tip; + } + + @Override + public void render(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, int height) { + Minecraft mc = Minecraft.getInstance(); + if (mc.options.hideGui || !ValueSettingsInputHandler.canInteract(mc.player)) + return; + if (hoverTicks == 0 || lastHoverTip == null) + return; + + int x = width / 2; + int y = height - 75 - lastHoverTip.size() * 12; + float alpha = hoverTicks > 5 ? (11 - hoverTicks) / 5f : Math.min(1, hoverTicks / 5f); + + Color color = new Color(0xffffff); + Color titleColor = new Color(0xFBDC7D); + color.setAlpha(alpha); + titleColor.setAlpha(alpha); + + for (int i = 0; i < lastHoverTip.size(); i++) { + MutableComponent mutableComponent = lastHoverTip.get(i); + mc.font.drawShadow(poseStack, mutableComponent, x - mc.font.width(mutableComponent) / 2, y, + (i == 0 ? titleColor : color).getRGB()); + y += 12; + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsFormatter.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsFormatter.java new file mode 100644 index 0000000000..d5f168da4a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsFormatter.java @@ -0,0 +1,39 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import java.util.function.Function; + +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.INamedIconOptions; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.network.chat.MutableComponent; + +public class ValueSettingsFormatter { + + private Function formatter; + + public ValueSettingsFormatter(Function formatter) { + this.formatter = formatter; + } + + public MutableComponent format(ValueSettings valueSettings) { + return formatter.apply(valueSettings); + } + + public static class ScrollOptionSettingsFormatter extends ValueSettingsFormatter { + + private INamedIconOptions[] options; + + public ScrollOptionSettingsFormatter(INamedIconOptions[] options) { + super(v -> CreateLang.translateDirect(options[v.value()].getTranslationKey())); + this.options = options; + } + + public AllIcons getIcon(ValueSettings valueSettings) { + return options[valueSettings.value()].getIcon(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsInputHandler.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsInputHandler.java new file mode 100644 index 0000000000..9da85bbd78 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsInputHandler.java @@ -0,0 +1,98 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllTags.AllItemTags; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.SidedFilteringBehaviour; +import com.simibubi.create.foundation.utility.RaycastHelper; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.LogicalSide; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class ValueSettingsInputHandler { + + @SubscribeEvent + public static void onBlockActivated(PlayerInteractEvent.RightClickBlock event) { + Level world = event.getWorld(); + BlockPos pos = event.getPos(); + Player player = event.getPlayer(); + InteractionHand hand = event.getHand(); + + if (!canInteract(player)) + return; + if (AllBlocks.CLIPBOARD.isIn(player.getMainHandItem())) + return; + if (!(world.getBlockEntity(pos)instanceof SmartBlockEntity sbe)) + return; + + if (event.getSide() == LogicalSide.CLIENT) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> CreateClient.VALUE_SETTINGS_HANDLER.cancelIfWarmupAlreadyStarted(event)); + + if (event.isCanceled()) + return; + + for (BlockEntityBehaviour behaviour : sbe.getAllBehaviours()) { + if (!(behaviour instanceof ValueSettingsBehaviour valueSettingsBehaviour)) + continue; + + BlockHitResult ray = RaycastHelper.rayTraceRange(world, player, 10); + if (ray == null) + return; + if (behaviour instanceof SidedFilteringBehaviour) { + behaviour = ((SidedFilteringBehaviour) behaviour).get(ray.getDirection()); + if (behaviour == null) + continue; + } + + if (!valueSettingsBehaviour.isActive()) + continue; + if (valueSettingsBehaviour.onlyVisibleWithWrench() + && !AllItemTags.WRENCH.matches(player.getItemInHand(hand))) + continue; + if (valueSettingsBehaviour.getSlotPositioning()instanceof ValueBoxTransform.Sided sidedSlot) { + if (!sidedSlot.isSideActive(sbe.getBlockState(), ray.getDirection())) + continue; + sidedSlot.fromSide(ray.getDirection()); + } + + boolean fakePlayer = player instanceof FakePlayer; + if (!valueSettingsBehaviour.testHit(ray.getLocation()) && !fakePlayer) + continue; + + event.setCanceled(true); + event.setCancellationResult(InteractionResult.SUCCESS); + + if (!valueSettingsBehaviour.acceptsValueSettings() || fakePlayer) { + valueSettingsBehaviour.onShortInteract(player, hand, ray.getDirection()); + return; + } + + if (event.getSide() == LogicalSide.CLIENT) { + BehaviourType type = behaviour.getType(); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.VALUE_SETTINGS_HANDLER + .startInteractionWith(pos, type, hand, ray.getDirection())); + } + + return; + } + } + + public static boolean canInteract(Player player) { + return player != null && !player.isSpectator() && !player.isShiftKeyDown(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsPacket.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsPacket.java new file mode 100644 index 0000000000..27638e80dd --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsPacket.java @@ -0,0 +1,77 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings; +import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; + +public class ValueSettingsPacket extends BlockEntityConfigurationPacket { + + private int row; + private int value; + private InteractionHand interactHand; + private Direction side; + private boolean ctrlDown; + + public ValueSettingsPacket(BlockPos pos, int row, int value, @Nullable InteractionHand interactHand, Direction side, + boolean ctrlDown) { + super(pos); + this.row = row; + this.value = value; + this.interactHand = interactHand; + this.side = side; + this.ctrlDown = ctrlDown; + } + + public ValueSettingsPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeSettings(FriendlyByteBuf buffer) { + buffer.writeVarInt(value); + buffer.writeVarInt(row); + buffer.writeBoolean(interactHand != null); + if (interactHand != null) + buffer.writeBoolean(interactHand == InteractionHand.MAIN_HAND); + buffer.writeVarInt(side.ordinal()); + buffer.writeBoolean(ctrlDown); + } + + @Override + protected void readSettings(FriendlyByteBuf buffer) { + value = buffer.readVarInt(); + row = buffer.readVarInt(); + if (buffer.readBoolean()) + interactHand = buffer.readBoolean() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + side = Direction.values()[buffer.readVarInt()]; + ctrlDown = buffer.readBoolean(); + } + + @Override + protected void applySettings(ServerPlayer player, SmartBlockEntity be) { + for (BlockEntityBehaviour behaviour : be.getAllBehaviours()) { + if (!(behaviour instanceof ValueSettingsBehaviour valueSettingsBehaviour)) + continue; + if (!valueSettingsBehaviour.acceptsValueSettings()) + continue; + if (interactHand != null) { + valueSettingsBehaviour.onShortInteract(player, interactHand, side); + return; + } + valueSettingsBehaviour.setValueSettings(player, new ValueSettings(row, value), ctrlDown); + return; + } + } + + @Override + protected void applySettings(SmartBlockEntity be) {} + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsScreen.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsScreen.java new file mode 100644 index 0000000000..d1a381501d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/ValueSettingsScreen.java @@ -0,0 +1,332 @@ +package com.simibubi.create.foundation.blockEntity.behaviour; + +import java.util.function.Consumer; + +import org.lwjgl.glfw.GLFW; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllKeys; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour.ValueSettings; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter.ScrollOptionSettingsFormatter; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueHandler; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.gui.AbstractSimiScreen; +import net.createmod.catnip.gui.UIRenderHelper; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec2; + +public class ValueSettingsScreen extends AbstractSimiScreen { + + private int ticksOpen; + private ValueSettingsBoard board; + private int maxLabelWidth; + private int valueBarWidth; + private BlockPos pos; + private ValueSettings initialSettings; + private ValueSettings lastHovered = new ValueSettings(-1, -1); + private Consumer onHover; + private boolean iconMode; + private int milestoneSize; + private int soundCoolDown; + + public ValueSettingsScreen(BlockPos pos, ValueSettingsBoard board, ValueSettings valueSettings, + Consumer onHover) { + this.pos = pos; + this.board = board; + this.initialSettings = valueSettings; + this.onHover = onHover; + this.iconMode = board.formatter() instanceof ScrollOptionSettingsFormatter; + this.milestoneSize = iconMode ? 8 : 4; + } + + @Override + protected void init() { + int maxValue = board.maxValue(); + maxLabelWidth = 0; + int milestoneCount = maxValue / board.milestoneInterval() + 1; + int scale = maxValue > 128 ? 1 : 2; + + for (Component component : board.rows()) + maxLabelWidth = Math.max(maxLabelWidth, font.width(component)); + if (iconMode) + maxLabelWidth = -18; + + valueBarWidth = (maxValue + 1) * scale + 1 + milestoneCount * milestoneSize; + int width = (maxLabelWidth + 14) + (valueBarWidth + 10); + int height = (board.rows() + .size() * 11); + + setWindowSize(width, height); + super.init(); + + Vec2 coordinateOfValue = getCoordinateOfValue(initialSettings.row(), initialSettings.value()); + setCursor(coordinateOfValue); + } + + private void setCursor(Vec2 coordinateOfValue) { + double guiScale = minecraft.getWindow() + .getGuiScale(); + GLFW.glfwSetCursorPos(minecraft.getWindow() + .getWindow(), coordinateOfValue.x * guiScale, coordinateOfValue.y * guiScale); + } + + public ValueSettings getClosestCoordinate(int mouseX, int mouseY) { + int row = 0; + int column = 0; + boolean milestonesOnly = hasShiftDown(); + + double bestDiff = Double.MAX_VALUE; + for (; row < board.rows() + .size(); row++) { + Vec2 coord = getCoordinateOfValue(row, 0); + double diff = Math.abs(coord.y - mouseY); + if (bestDiff < diff) + break; + bestDiff = diff; + } + row -= 1; + + bestDiff = Double.MAX_VALUE; + for (; column <= board.maxValue(); column++) { + Vec2 coord = getCoordinateOfValue(row, milestonesOnly ? column * board.milestoneInterval() : column); + double diff = Math.abs(coord.x - mouseX); + if (bestDiff < diff) + break; + bestDiff = diff; + } + column -= 1; + + return new ValueSettings(row, + milestonesOnly ? Math.min(column * board.milestoneInterval(), board.maxValue()) : column); + } + + public Vec2 getCoordinateOfValue(int row, int column) { + int scale = board.maxValue() > 128 ? 1 : 2; + float xOut = + guiLeft + ((Math.max(1, column) - 1) / board.milestoneInterval()) * milestoneSize + column * scale + 1.5f; + xOut += maxLabelWidth + 14 + 4; + + if (column % board.milestoneInterval() == 0) + xOut += milestoneSize / 2; + if (column > 0) + xOut += milestoneSize; + + float yOut = guiTop + (row + .5f) * 11 - .5f; + return new Vec2(xOut, yOut); + } + + @Override + protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) { + int x = guiLeft; + int y = guiTop; + int milestoneCount = board.maxValue() / board.milestoneInterval() + 1; + int blitOffset = getBlitOffset(); + int scale = board.maxValue() > 128 ? 1 : 2; + + Component title = board.title(); + Component tip = CreateLang.translateDirect("gui.value_settings.release_to_confirm", Components.keybind("key.use")); + double fadeIn = Math.pow(Mth.clamp((ticksOpen + partialTicks) / 4.0, 0, 1), 1); + + int fattestLabel = Math.max(font.width(tip), font.width(title)); + if (iconMode) + for (int i = 0; i <= board.maxValue(); i++) + fattestLabel = Math.max(fattestLabel, font.width(board.formatter() + .format(new ValueSettings(0, i)))); + + int fatTipOffset = Math.max(0, fattestLabel + 10 - (windowWidth + 13)) / 2; + int bgWidth = Math.max((windowWidth + 13), fattestLabel + 10); + int fadeInWidth = (int) (bgWidth * fadeIn); + int fadeInStart = (bgWidth - fadeInWidth) / 2 - fatTipOffset; + int additionalHeight = iconMode ? 46 : 33; + + UIRenderHelper.drawStretched(ms, x - 11 + fadeInStart, y - 17, fadeInWidth, windowHeight + additionalHeight, + blitOffset, AllGuiTextures.VALUE_SETTINGS_OUTER_BG); + UIRenderHelper.drawStretched(ms, x - 10 + fadeInStart, y - 18, fadeInWidth - 2, 1, blitOffset, + AllGuiTextures.VALUE_SETTINGS_OUTER_BG); + UIRenderHelper.drawStretched(ms, x - 10 + fadeInStart, y - 17 + windowHeight + additionalHeight, + fadeInWidth - 2, 1, blitOffset, AllGuiTextures.VALUE_SETTINGS_OUTER_BG); + + if (fadeInWidth > fattestLabel) { + int textX = x - 11 - fatTipOffset + bgWidth / 2; + font.draw(ms, title, textX - font.width(title) / 2, y - 14, 0xdddddd); + font.draw(ms, tip, textX - font.width(tip) / 2, y + windowHeight + additionalHeight - 27, 0xdddddd); + } + + renderBrassFrame(ms, x + maxLabelWidth + 14, y - 3, valueBarWidth + 8, board.rows() + .size() * 11 + 5); + UIRenderHelper.drawStretched(ms, x + maxLabelWidth + 17, y, valueBarWidth + 2, board.rows() + .size() * 11 - 1, blitOffset, AllGuiTextures.VALUE_SETTINGS_BAR_BG); + + int originalY = y; + for (Component component : board.rows()) { + int valueBarX = x + maxLabelWidth + 14 + 4; + + if (!iconMode) { + UIRenderHelper.drawCropped(ms, x - 4, y, maxLabelWidth + 8, 11, blitOffset, + AllGuiTextures.VALUE_SETTINGS_LABEL_BG); + for (int w = 0; w < valueBarWidth; w += AllGuiTextures.VALUE_SETTINGS_BAR.getWidth() - 1) + UIRenderHelper.drawCropped(ms, valueBarX + w, y + 1, + Math.min(AllGuiTextures.VALUE_SETTINGS_BAR.getWidth() - 1, valueBarWidth - w), 8, blitOffset, + AllGuiTextures.VALUE_SETTINGS_BAR); + font.draw(ms, component, x, y + 1, 0x442000); + } + + int milestoneX = valueBarX; + for (int milestone = 0; milestone < milestoneCount; milestone++) { + if (iconMode) + AllGuiTextures.VALUE_SETTINGS_WIDE_MILESTONE.render(ms, milestoneX, y + 1); + else + AllGuiTextures.VALUE_SETTINGS_MILESTONE.render(ms, milestoneX, y + 1); + milestoneX += milestoneSize + board.milestoneInterval() * scale; + } + + y += 11; + } + + if (!iconMode) + renderBrassFrame(ms, x - 7, originalY - 3, maxLabelWidth + 14, board.rows() + .size() * 11 + 5); + + if (ticksOpen < 1) + return; + + ValueSettings closest = getClosestCoordinate(mouseX, mouseY); + + if (!closest.equals(lastHovered)) { + onHover.accept(closest); + if (soundCoolDown == 0) { + float pitch = (closest.value()) / (float) (board.maxValue()); + pitch = Mth.lerp(pitch, 1.15f, 1.5f); + minecraft.getSoundManager() + .play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), pitch, 0.25F)); + ScrollValueHandler.wrenchCog.bump(3, -(closest.value() - lastHovered.value()) * 10); + soundCoolDown = 1; + } + } + lastHovered = closest; + + Vec2 coordinate = getCoordinateOfValue(closest.row(), closest.value()); + Component cursorText = board.formatter() + .format(closest); + + AllIcons cursorIcon = null; + if (board.formatter() instanceof ScrollOptionSettingsFormatter sosf) + cursorIcon = sosf.getIcon(closest); + + int cursorWidth = ((cursorIcon != null ? 16 : font.width(cursorText)) / 2) * 2 + 3; + int cursorX = ((int) (coordinate.x)) - cursorWidth / 2; + int cursorY = ((int) (coordinate.y)) - 7; + + if (cursorIcon != null) { + AllGuiTextures.VALUE_SETTINGS_CURSOR_ICON.render(ms, cursorX - 2, cursorY - 3); + RenderSystem.setShaderColor(0.265625f, 0.125f, 0, 1); + cursorIcon.render(ms, cursorX + 1, cursorY - 1); + RenderSystem.setShaderColor(1, 1, 1, 1); + if (fadeInWidth > fattestLabel) + font.draw(ms, cursorText, x - 11 - fatTipOffset + (bgWidth - font.width(cursorText)) / 2, + originalY + windowHeight + additionalHeight - 40, 0xFBDC7D); + return; + } + + AllGuiTextures.VALUE_SETTINGS_CURSOR_LEFT.render(ms, cursorX - 3, cursorY); + UIRenderHelper.drawCropped(ms, cursorX, cursorY, cursorWidth, 14, blitOffset, + AllGuiTextures.VALUE_SETTINGS_CURSOR); + AllGuiTextures.VALUE_SETTINGS_CURSOR_RIGHT.render(ms, cursorX + cursorWidth, cursorY); + + font.draw(ms, cursorText, cursorX + 2, cursorY + 3, 0x442000); + } + + protected void renderBrassFrame(PoseStack ms, int x, int y, int w, int h) { + AllGuiTextures.BRASS_FRAME_TL.render(ms, x, y); + AllGuiTextures.BRASS_FRAME_TR.render(ms, x + w - 4, y); + AllGuiTextures.BRASS_FRAME_BL.render(ms, x, y + h - 4); + AllGuiTextures.BRASS_FRAME_BR.render(ms, x + w - 4, y + h - 4); + + if (h > 8) { + UIRenderHelper.drawStretched(ms, x, y + 4, 3, h - 8, getBlitOffset(), AllGuiTextures.BRASS_FRAME_LEFT); + UIRenderHelper.drawStretched(ms, x + w - 3, y + 4, 3, h - 8, getBlitOffset(), + AllGuiTextures.BRASS_FRAME_RIGHT); + } + + if (w > 8) { + UIRenderHelper.drawCropped(ms, x + 4, y, w - 8, 3, getBlitOffset(), AllGuiTextures.BRASS_FRAME_TOP); + UIRenderHelper.drawCropped(ms, x + 4, y + h - 3, w - 8, 3, getBlitOffset(), + AllGuiTextures.BRASS_FRAME_BOTTOM); + } + + } + + @Override + public void renderBackground(PoseStack p_238651_1_, int p_238651_2_) { + int a = ((int) (0x50 * Math.min(1, (ticksOpen + AnimationTickHolder.getPartialTicks()) / 20f))) << 24; + fillGradient(p_238651_1_, 0, 0, this.width, this.height, 0x101010 | a, 0x101010 | a); + } + + @Override + public void tick() { + ticksOpen++; + if (soundCoolDown > 0) + soundCoolDown--; + super.tick(); + } + + @Override + public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) { + ValueSettings closest = getClosestCoordinate((int) pMouseX, (int) pMouseY); + int column = closest.value() + ((int) Math.signum(pDelta)) * (hasShiftDown() ? board.milestoneInterval() : 1); + column = Mth.clamp(column, 0, board.maxValue()); + if (column == closest.value()) + return false; + setCursor(getCoordinateOfValue(closest.row(), column)); + return true; + } + + @Override + public boolean keyReleased(int pKeyCode, int pScanCode, int pModifiers) { + if (minecraft.options.keyUse.matches(pKeyCode, pScanCode)) { + Window window = minecraft.getWindow(); + double x = minecraft.mouseHandler.xpos() * window.getGuiScaledWidth() / window.getScreenWidth(); + double y = minecraft.mouseHandler.ypos() * window.getGuiScaledHeight() / window.getScreenHeight(); + saveAndClose(x, y); + return true; + } + return super.keyReleased(pKeyCode, pScanCode, pModifiers); + } + + @Override + public boolean mouseReleased(double pMouseX, double pMouseY, int pButton) { + if (minecraft.options.keyUse.matchesMouse(pButton)) { + saveAndClose(pMouseX, pMouseY); + return true; + } + return super.mouseReleased(pMouseX, pMouseY, pButton); + } + + protected void saveAndClose(double pMouseX, double pMouseY) { + ValueSettings closest = getClosestCoordinate((int) pMouseX, (int) pMouseY); + // FIXME: value settings may be face-sensitive on future components + AllPackets.getChannel() + .sendToServer(new ValueSettingsPacket(pos, closest.row(), closest.value(), null, Direction.UP, + AllKeys.ctrlDown())); + onClose(); + } + + @Override + public void onClose() { + super.onClose(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionBehaviour.java new file mode 100644 index 0000000000..9adb39e0c0 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionBehaviour.java @@ -0,0 +1,54 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction; + +import java.util.Optional; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; + +public class EdgeInteractionBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + ConnectionCallback connectionCallback; + ConnectivityPredicate connectivityPredicate; + Optional requiredItem; + + public EdgeInteractionBehaviour(SmartBlockEntity be, ConnectionCallback callback) { + super(be); + this.connectionCallback = callback; + requiredItem = Optional.empty(); + connectivityPredicate = (world, pos, face, face2) -> true; + } + + public EdgeInteractionBehaviour connectivity(ConnectivityPredicate pred) { + this.connectivityPredicate = pred; + return this; + } + + public EdgeInteractionBehaviour require(Item item) { + this.requiredItem = Optional.of(item); + return this; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + @FunctionalInterface + public interface ConnectionCallback { + public void apply(Level world, BlockPos clicked, BlockPos neighbour); + } + + @FunctionalInterface + public interface ConnectivityPredicate { + public boolean test(Level world, BlockPos pos, Direction selectedFace, Direction connectedFace); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java similarity index 92% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java index 96cb61e8a4..9d8007e18e 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionHandler.java @@ -1,9 +1,9 @@ -package com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction; +package com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.RaycastHelper; @@ -39,7 +39,7 @@ public class EdgeInteractionHandler { if (player.isShiftKeyDown() || player.isSpectator()) return; - EdgeInteractionBehaviour behaviour = TileEntityBehaviour.get(world, pos, EdgeInteractionBehaviour.TYPE); + EdgeInteractionBehaviour behaviour = BlockEntityBehaviour.get(world, pos, EdgeInteractionBehaviour.TYPE); if (behaviour == null) return; if (behaviour.requiredItem.isPresent() && behaviour.requiredItem.get() != heldItem.getItem()) @@ -96,7 +96,7 @@ public class EdgeInteractionHandler { int x = vec.getX(); int y = vec.getY(); int z = vec.getZ(); - double margin = 12 / 16f; + double margin = 10 / 16f; double absX = Math.abs(x) * margin; double absY = Math.abs(y) * margin; double absZ = Math.abs(z) * margin; diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionRenderer.java new file mode 100644 index 0000000000..1b31417490 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/edgeInteraction/EdgeInteractionRenderer.java @@ -0,0 +1,121 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.kinetics.crafter.CrafterHelper; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class EdgeInteractionRenderer { + + public static void tick() { + Minecraft mc = Minecraft.getInstance(); + HitResult target = mc.hitResult; + if (target == null || !(target instanceof BlockHitResult)) + return; + + BlockHitResult result = (BlockHitResult) target; + ClientLevel world = mc.level; + BlockPos pos = result.getBlockPos(); + Player player = mc.player; + ItemStack heldItem = player.getMainHandItem(); + + if (player.isShiftKeyDown()) + return; + EdgeInteractionBehaviour behaviour = BlockEntityBehaviour.get(world, pos, EdgeInteractionBehaviour.TYPE); + if (behaviour == null) + return; + if (behaviour.requiredItem.orElse(heldItem.getItem()) != heldItem.getItem()) + return; + + Direction face = result.getDirection(); + List connectiveSides = EdgeInteractionHandler.getConnectiveSides(world, pos, face, behaviour); + if (connectiveSides.isEmpty()) + return; + + Direction closestEdge = connectiveSides.get(0); + double bestDistance = Double.MAX_VALUE; + Vec3 center = VecHelper.getCenterOf(pos); + for (Direction direction : connectiveSides) { + double distance = Vec3.atLowerCornerOf(direction.getNormal()) + .subtract(target.getLocation() + .subtract(center)) + .length(); + if (distance > bestDistance) + continue; + bestDistance = distance; + closestEdge = direction; + } + + AABB bb = EdgeInteractionHandler.getBB(pos, closestEdge); + boolean hit = bb.contains(target.getLocation()); + Vec3 offset = Vec3.atLowerCornerOf(closestEdge.getNormal()) + .scale(.5) + .add(Vec3.atLowerCornerOf(face.getNormal()) + .scale(.469)) + .add(VecHelper.CENTER_OF_ORIGIN); + + ValueBox box = new ValueBox(Components.immutableEmpty(), bb, pos).passive(!hit) + .transform(new EdgeValueBoxTransform(offset)) + .wideOutline(); + CatnipClient.OUTLINER.showOutline("edge", box) + .highlightFace(face); + + if (!hit) + return; + + List tip = new ArrayList<>(); + tip.add(CreateLang.translateDirect("logistics.crafter.connected")); + tip.add(CreateLang.translateDirect(CrafterHelper.areCraftersConnected(world, pos, pos.relative(closestEdge)) + ? "logistics.crafter.click_to_separate" + : "logistics.crafter.click_to_merge")); + CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip); + } + + static class EdgeValueBoxTransform extends ValueBoxTransform.Sided { + + private Vec3 add; + + public EdgeValueBoxTransform(Vec3 add) { + this.add = add; + } + + @Override + protected Vec3 getSouthLocation() { + return Vec3.ZERO; + } + + @Override + public Vec3 getLocalOffset(BlockState state) { + return add; + } + + @Override + public void rotate(BlockState state, PoseStack ms) { + super.rotate(state, ms); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java new file mode 100644 index 0000000000..1df4171076 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringBehaviour.java @@ -0,0 +1,385 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.filtering; + +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.InvWrapper; + +public class FilteringBehaviour extends BlockEntityBehaviour implements ValueSettingsBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + public MutableComponent customLabel; + ValueBoxTransform slotPositioning; + boolean showCount; + + private ItemStack filter; + public int count; + public boolean upTo; + private Predicate predicate; + private Consumer callback; + private Supplier isActive; + private Supplier showCountPredicate; + + boolean recipeFilter; + boolean fluidFilter; + + public FilteringBehaviour(SmartBlockEntity be, ValueBoxTransform slot) { + super(be); + filter = ItemStack.EMPTY; + slotPositioning = slot; + showCount = false; + callback = stack -> { + }; + predicate = stack -> true; + isActive = () -> true; + count = 64; + showCountPredicate = () -> showCount; + recipeFilter = false; + fluidFilter = false; + upTo = true; + } + + @Override + public boolean isSafeNBT() { + return true; + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + nbt.put("Filter", getFilter().serializeNBT()); + nbt.putInt("FilterAmount", count); + nbt.putBoolean("UpTo", upTo); + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + filter = ItemStack.of(nbt.getCompound("Filter")); + count = nbt.getInt("FilterAmount"); + upTo = nbt.getBoolean("UpTo"); + + // Migrate from previous behaviour + if (count == 0) { + upTo = true; + count = filter.getMaxStackSize(); + } + + super.read(nbt, clientPacket); + } + + public FilteringBehaviour withCallback(Consumer filterCallback) { + callback = filterCallback; + return this; + } + + public FilteringBehaviour withPredicate(Predicate filterPredicate) { + predicate = filterPredicate; + return this; + } + + public FilteringBehaviour forRecipes() { + recipeFilter = true; + return this; + } + + public FilteringBehaviour forFluids() { + fluidFilter = true; + return this; + } + + public FilteringBehaviour onlyActiveWhen(Supplier condition) { + isActive = condition; + return this; + } + + public FilteringBehaviour showCountWhen(Supplier condition) { + showCountPredicate = condition; + return this; + } + + public FilteringBehaviour showCount() { + showCount = true; + return this; + } + + public boolean setFilter(Direction face, ItemStack stack) { + return setFilter(stack); + } + + public void setLabel(MutableComponent label) { + this.customLabel = label; + } + + public boolean setFilter(ItemStack stack) { + ItemStack filter = stack.copy(); + if (!filter.isEmpty() && !predicate.test(filter)) + return false; + this.filter = filter; + if (!upTo) + count = Math.min(count, stack.getMaxStackSize()); + callback.accept(filter); + blockEntity.setChanged(); + blockEntity.sendData(); + return true; + } + + @Override + public void setValueSettings(Player player, ValueSettings settings, boolean ctrlDown) { + if (getValueSettings().equals(settings)) + return; + count = Mth.clamp(settings.value(), 1, filter.getMaxStackSize()); + upTo = settings.row() == 0; + blockEntity.setChanged(); + blockEntity.sendData(); + playFeedbackSound(this); + } + + @Override + public ValueSettings getValueSettings() { + return new ValueSettings(upTo ? 0 : 1, count == 0 ? filter.getMaxStackSize() : count); + } + + @Override + public void destroy() { + if (filter.getItem() instanceof FilterItem) { + Vec3 pos = VecHelper.getCenterOf(getPos()); + Level world = getWorld(); + world.addFreshEntity(new ItemEntity(world, pos.x, pos.y, pos.z, filter.copy())); + } + super.destroy(); + } + + @Override + public ItemRequirement getRequiredItems() { + Item filterItem = filter.getItem(); + if (filterItem instanceof FilterItem) + return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, filterItem); + + return ItemRequirement.NONE; + } + + public ItemStack getFilter(Direction side) { + return getFilter(); + } + + public ItemStack getFilter() { + return filter.copy(); + } + + public boolean isCountVisible() { + return showCountPredicate.get() && filter.getMaxStackSize() > 1; + } + + public boolean test(ItemStack stack) { + return !isActive() || filter.isEmpty() || FilterItem.test(blockEntity.getLevel(), stack, filter); + } + + public boolean test(FluidStack stack) { + return !isActive() || filter.isEmpty() || FilterItem.test(blockEntity.getLevel(), stack, filter); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + @Override + public boolean testHit(Vec3 hit) { + BlockState state = blockEntity.getBlockState(); + Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos())); + return slotPositioning.testHit(state, localHit); + } + + public int getAmount() { + return count; + } + + public boolean anyAmount() { + return count == 0; + } + + @Override + public boolean acceptsValueSettings() { + return isCountVisible(); + } + + @Override + public boolean isActive() { + return isActive.get(); + } + + @Override + public ValueBoxTransform getSlotPositioning() { + return slotPositioning; + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + ItemStack filter = getFilter(hitResult.getDirection()); + int maxAmount = (filter.getItem() instanceof FilterItem) ? 64 : filter.getMaxStackSize(); + return new ValueSettingsBoard(CreateLang.translateDirect("logistics.filter.extracted_amount"), maxAmount, 16, + CreateLang.translatedOptions("logistics.filter", "up_to", "exactly"), + new ValueSettingsFormatter(this::formatValue)); + } + + public MutableComponent formatValue(ValueSettings value) { + if (value.row() == 0 && value.value() == filter.getMaxStackSize()) + return CreateLang.translateDirect("logistics.filter.any_amount_short"); + return Components.literal(((value.row() == 0) ? "\u2264" : "=") + Math.max(1, value.value())); + } + + @Override + public void onShortInteract(Player player, InteractionHand hand, Direction side) { + Level level = getWorld(); + BlockPos pos = getPos(); + ItemStack itemInHand = player.getItemInHand(hand); + ItemStack toApply = itemInHand.copy(); + + if (AllItems.WRENCH.isIn(toApply)) + return; + if (AllBlocks.MECHANICAL_ARM.isIn(toApply)) + return; + if (level.isClientSide()) + return; + + if (getFilter(side).getItem() instanceof FilterItem) { + if (!player.isCreative() || ItemHelper + .extract(new InvWrapper(player.getInventory()), + stack -> ItemHandlerHelper.canItemStacksStack(stack, getFilter(side)), true) + .isEmpty()) + player.getInventory() + .placeItemBackInInventory(getFilter(side)); + } + + if (toApply.getItem() instanceof FilterItem) + toApply.setCount(1); + + if (!setFilter(side, toApply)) { + player.displayClientMessage(CreateLang.translateDirect("logistics.filter.invalid_item"), true); + AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1); + return; + } + + if (!player.isCreative()) { + if (toApply.getItem() instanceof FilterItem) { + if (itemInHand.getCount() == 1) + player.setItemInHand(hand, ItemStack.EMPTY); + else + itemInHand.shrink(1); + } + } + + level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .25f, .1f); + } + + public MutableComponent getLabel() { + if (customLabel != null) + return customLabel; + return CreateLang.translateDirect( + recipeFilter ? "logistics.recipe_filter" : fluidFilter ? "logistics.fluid_filter" : "logistics.filter"); + } + + @Override + public String getClipboardKey() { + return "Filtering"; + } + + @Override + public boolean writeToClipboard(CompoundTag tag, Direction side) { + ValueSettingsBehaviour.super.writeToClipboard(tag, side); + ItemStack filter = getFilter(side); + tag.put("Filter", filter.serializeNBT()); + return true; + } + + @Override + public boolean readFromClipboard(CompoundTag tag, Player player, Direction side, boolean simulate) { + boolean upstreamResult = ValueSettingsBehaviour.super.readFromClipboard(tag, player, side, simulate); + if (!tag.contains("Filter")) + return upstreamResult; + if (simulate) + return true; + if (getWorld().isClientSide) + return true; + + ItemStack refund = ItemStack.EMPTY; + if (getFilter(side).getItem() instanceof FilterItem && !player.isCreative()) + refund = getFilter(side).copy(); + + ItemStack copied = ItemStack.of(tag.getCompound("Filter")); + + if (copied.getItem() instanceof FilterItem filterType && !player.isCreative()) { + InvWrapper inv = new InvWrapper(player.getInventory()); + + for (boolean preferStacksWithoutData : Iterate.trueAndFalse) { + if (refund.getItem() != filterType && ItemHelper + .extract(inv, stack -> stack.getItem() == filterType && preferStacksWithoutData != stack.hasTag(), + 1, false) + .isEmpty()) + continue; + + if (!refund.isEmpty() && refund.getItem() != filterType) + player.getInventory() + .placeItemBackInInventory(refund); + + setFilter(side, copied); + return true; + } + + player.displayClientMessage(CreateLang + .translate("logistics.filter.requires_item_in_inventory", copied.getHoverName() + .copy() + .withStyle(ChatFormatting.WHITE)) + .style(ChatFormatting.RED) + .component(), true); + AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1); + return false; + } + + if (!refund.isEmpty()) + player.getInventory() + .placeItemBackInInventory(refund); + + return setFilter(side, copied); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringRenderer.java new file mode 100644 index 0000000000..c5a3912b39 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/FilteringRenderer.java @@ -0,0 +1,163 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.filtering; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.logistics.filter.FilterItem; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox.ItemValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxRenderer; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.utility.Iterate; +import net.createmod.catnip.utility.Pair; +import net.createmod.catnip.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class FilteringRenderer { + + public static void tick() { + Minecraft mc = Minecraft.getInstance(); + HitResult target = mc.hitResult; + if (target == null || !(target instanceof BlockHitResult)) + return; + + BlockHitResult result = (BlockHitResult) target; + ClientLevel world = mc.level; + BlockPos pos = result.getBlockPos(); + BlockState state = world.getBlockState(pos); + + FilteringBehaviour behaviour = BlockEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE); + if (mc.player.isShiftKeyDown()) + return; + + ItemStack mainhandItem = mc.player.getItemInHand(InteractionHand.MAIN_HAND); + if (behaviour == null) + return; + if (behaviour instanceof SidedFilteringBehaviour) { + behaviour = ((SidedFilteringBehaviour) behaviour).get(result.getDirection()); + if (behaviour == null) + return; + } + if (!behaviour.isActive()) + return; + if (behaviour.slotPositioning instanceof ValueBoxTransform.Sided) + ((Sided) behaviour.slotPositioning).fromSide(result.getDirection()); + if (!behaviour.slotPositioning.shouldRender(state)) + return; + + ItemStack filter = behaviour.getFilter(); + boolean isFilterSlotted = filter.getItem() instanceof FilterItem; + boolean showCount = behaviour.isCountVisible(); + Component label = behaviour.getLabel(); + boolean hit = behaviour.slotPositioning.testHit(state, target.getLocation() + .subtract(Vec3.atLowerCornerOf(pos))); + + AABB emptyBB = new AABB(Vec3.ZERO, Vec3.ZERO); + AABB bb = isFilterSlotted ? emptyBB.inflate(.45f, .31f, .2f) : emptyBB.inflate(.25f); + + ValueBox box = new ItemValueBox(label, bb, pos, filter, showCount ? behaviour.count : -1, behaviour.upTo); + box.passive(!hit || AllBlocks.CLIPBOARD.isIn(mainhandItem)); + + CatnipClient.OUTLINER.showOutline(Pair.of("filter", pos), box.transform(behaviour.slotPositioning)) + .lineWidth(1 / 64f) + .withFaceTexture(hit ? AllSpecialTextures.THIN_CHECKERED : null) + .highlightFace(result.getDirection()); + + if (!hit) + return; + + List tip = new ArrayList<>(); + tip.add(label.copy()); + tip.add(CreateLang + .translateDirect(filter.isEmpty() ? "logistics.filter.click_to_set" : "logistics.filter.click_to_replace")); + if (showCount) + tip.add(CreateLang.translateDirect("logistics.filter.hold_to_set_amount")); + + CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip); + } + + public static void renderOnBlockEntity(SmartBlockEntity be, float partialTicks, PoseStack ms, + MultiBufferSource buffer, int light, int overlay) { + + if (be == null || be.isRemoved()) + return; + + if (!be.isVirtual()) { + Entity cameraEntity = Minecraft.getInstance().cameraEntity; + if (cameraEntity != null && be.getLevel() == cameraEntity.getLevel()) { + float max = AllConfigs.client().filterItemRenderDistance.getF(); + if (cameraEntity.position() + .distanceToSqr(VecHelper.getCenterOf(be.getBlockPos())) > (max * max)) { + return; + } + } + } + + FilteringBehaviour behaviour = be.getBehaviour(FilteringBehaviour.TYPE); + if (behaviour == null) + return; + if (!behaviour.isActive()) + return; + if (behaviour.getFilter() + .isEmpty() && !(behaviour instanceof SidedFilteringBehaviour)) + return; + + ValueBoxTransform slotPositioning = behaviour.slotPositioning; + BlockState blockState = be.getBlockState(); + + if (slotPositioning instanceof ValueBoxTransform.Sided) { + ValueBoxTransform.Sided sided = (ValueBoxTransform.Sided) slotPositioning; + Direction side = sided.getSide(); + for (Direction d : Iterate.directions) { + ItemStack filter = behaviour.getFilter(d); + if (filter.isEmpty()) + continue; + + sided.fromSide(d); + if (!slotPositioning.shouldRender(blockState)) + continue; + + ms.pushPose(); + slotPositioning.transform(blockState, ms); + if (AllBlocks.CONTRAPTION_CONTROLS.has(blockState)) + ValueBoxRenderer.renderFlatItemIntoValueBox(filter, ms, buffer, light, overlay); + else + ValueBoxRenderer.renderItemIntoValueBox(filter, ms, buffer, light, overlay); + ms.popPose(); + } + sided.fromSide(side); + return; + } else if (slotPositioning.shouldRender(blockState)) { + ms.pushPose(); + slotPositioning.transform(blockState, ms); + ValueBoxRenderer.renderItemIntoValueBox(behaviour.getFilter(), ms, buffer, light, overlay); + ms.popPose(); + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/SidedFilteringBehaviour.java similarity index 82% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/SidedFilteringBehaviour.java index f2c2db89e2..9ca8966153 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/filtering/SidedFilteringBehaviour.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.tileEntity.behaviour.filtering; +package com.simibubi.create.foundation.blockEntity.behaviour.filtering; import java.util.HashSet; import java.util.IdentityHashMap; @@ -7,10 +7,10 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Predicate; -import com.simibubi.create.content.schematics.ItemRequirement; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; -import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform.Sided; +import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform.Sided; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.NBTHelper; @@ -27,10 +27,10 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { private BiFunction filterFactory; private Predicate validDirections; - public SidedFilteringBehaviour(SmartTileEntity te, ValueBoxTransform.Sided sidedSlot, + public SidedFilteringBehaviour(SmartBlockEntity be, ValueBoxTransform.Sided sidedSlot, BiFunction filterFactory, Predicate validDirections) { - super(te, sidedSlot); + super(be, sidedSlot); this.filterFactory = filterFactory; this.validDirections = validDirections; sidedFilters = new IdentityHashMap<>(); @@ -54,7 +54,7 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { for (Direction d : Iterate.directions) if (valid.contains(d)) { if (!sidedFilters.containsKey(d)) - sidedFilters.put(d, filterFactory.apply(d, new FilteringBehaviour(tileEntity, slotPositioning))); + sidedFilters.put(d, filterFactory.apply(d, new FilteringBehaviour(blockEntity, slotPositioning))); } else if (sidedFilters.containsKey(d)) removeFilter(d); } @@ -91,11 +91,12 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { } @Override - public void setFilter(Direction side, ItemStack stack) { + public boolean setFilter(Direction side, ItemStack stack) { if (!sidedFilters.containsKey(side)) - return; + return true; sidedFilters.get(side) .setFilter(stack); + return true; } @Override @@ -138,8 +139,8 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { public boolean testHit(Direction direction, Vec3 hit) { ValueBoxTransform.Sided sidedPositioning = (Sided) slotPositioning; - BlockState state = tileEntity.getBlockState(); - Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(tileEntity.getBlockPos())); + BlockState state = blockEntity.getBlockState(); + Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos())); return sidedPositioning.fromSide(direction) .testHit(state, localHit); } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/fluid/SmartFluidTankBehaviour.java similarity index 89% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/fluid/SmartFluidTankBehaviour.java index 648f65d823..b8ca154d4b 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/fluid/SmartFluidTankBehaviour.java @@ -1,18 +1,18 @@ -package com.simibubi.create.foundation.tileEntity.behaviour.fluid; +package com.simibubi.create.foundation.blockEntity.behaviour.fluid; import java.util.function.Consumer; import org.apache.commons.lang3.mutable.MutableInt; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; import com.simibubi.create.foundation.fluid.SmartFluidTank; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; + import net.createmod.catnip.utility.NBTHelper; import net.createmod.catnip.utility.animation.LerpedFloat; import net.createmod.catnip.utility.animation.LerpedFloat.Chaser; - import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -20,7 +20,7 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; -public class SmartFluidTankBehaviour extends TileEntityBehaviour { +public class SmartFluidTankBehaviour extends BlockEntityBehaviour { public static final BehaviourType @@ -38,13 +38,13 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { private BehaviourType behaviourType; - public static SmartFluidTankBehaviour single(SmartTileEntity te, int capacity) { - return new SmartFluidTankBehaviour(TYPE, te, 1, capacity, false); + public static SmartFluidTankBehaviour single(SmartBlockEntity be, int capacity) { + return new SmartFluidTankBehaviour(TYPE, be, 1, capacity, false); } - public SmartFluidTankBehaviour(BehaviourType type, SmartTileEntity te, int tanks, + public SmartFluidTankBehaviour(BehaviourType type, SmartBlockEntity be, int tanks, int tankCapacity, boolean enforceVariety) { - super(te); + super(be); insertionAllowed = true; extractionAllowed = true; behaviourType = type; @@ -106,8 +106,8 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { updateFluids(); } - forEach(te -> { - LerpedFloat fluidLevel = te.getFluidLevel(); + forEach(be -> { + LerpedFloat fluidLevel = be.getFluidLevel(); if (fluidLevel != null) fluidLevel.tickChaser(); }); @@ -131,13 +131,13 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { protected void updateFluids() { fluidUpdateCallback.run(); - tileEntity.sendData(); - tileEntity.setChanged(); + blockEntity.sendData(); + blockEntity.setChanged(); } @Override - public void remove() { - super.remove(); + public void unload() { + super.unload(); capability.invalidate(); } @@ -239,12 +239,12 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { } public void onFluidStackChanged() { - if (!tileEntity.hasLevel()) + if (!blockEntity.hasLevel()) return; fluidLevel.chase(tank.getFluidAmount() / (float) tank.getCapacity(), .25, Chaser.EXP); if (!getWorld().isClientSide) sendDataLazily(); - if (tileEntity.isVirtual() && !tank.getFluid() + if (blockEntity.isVirtual() && !tank.getFluid() .isEmpty()) renderedFluid = tank.getFluid(); } diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/CapManipulationBehaviourBase.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/CapManipulationBehaviourBase.java new file mode 100644 index 0000000000..cfa4cd438b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/CapManipulationBehaviourBase.java @@ -0,0 +1,152 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.inventory; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; + +import net.createmod.catnip.utility.BlockFace; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +public abstract class CapManipulationBehaviourBase> + extends BlockEntityBehaviour { + + protected InterfaceProvider target; + protected LazyOptional targetCapability; + protected boolean simulateNext; + protected boolean bypassSided; + private boolean findNewNextTick; + + public CapManipulationBehaviourBase(SmartBlockEntity be, InterfaceProvider target) { + super(be); + setLazyTickRate(5); + this.target = target; + targetCapability = LazyOptional.empty(); + simulateNext = false; + bypassSided = false; + } + + protected abstract Capability capability(); + + @Override + public void initialize() { + super.initialize(); + findNewNextTick = true; + } + + @Override + public void onNeighborChanged(BlockPos neighborPos) { + BlockFace targetBlockFace = target.getTarget(getWorld(), blockEntity.getBlockPos(), blockEntity.getBlockState()); + if (targetBlockFace.getConnectedPos() + .equals(neighborPos)) + onHandlerInvalidated(targetCapability); + } + + @SuppressWarnings("unchecked") + public S bypassSidedness() { + bypassSided = true; + return (S) this; + } + + /** + * Only simulate the upcoming operation + */ + @SuppressWarnings("unchecked") + public S simulate() { + simulateNext = true; + return (S) this; + } + + public boolean hasInventory() { + return targetCapability.isPresent(); + } + + @Nullable + public T getInventory() { + return targetCapability.orElse(null); + } + + protected void onHandlerInvalidated(LazyOptional handler) { + findNewNextTick = true; + targetCapability = LazyOptional.empty(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + if (!targetCapability.isPresent()) + findNewCapability(); + } + + @Override + public void tick() { + super.tick(); + if (findNewNextTick || getWorld().getGameTime() % 64 == 0) { + findNewNextTick = false; + findNewCapability(); + } + } + + public int getAmountFromFilter() { + int amount = -1; + FilteringBehaviour filter = blockEntity.getBehaviour(FilteringBehaviour.TYPE); + if (filter != null && !filter.anyAmount()) + amount = filter.getAmount(); + return amount; + } + + public ExtractionCountMode getModeFromFilter() { + ExtractionCountMode mode = ExtractionCountMode.UPTO; + FilteringBehaviour filter = blockEntity.getBehaviour(FilteringBehaviour.TYPE); + if (filter != null && !filter.upTo) + mode = ExtractionCountMode.EXACTLY; + return mode; + } + + public void findNewCapability() { + Level world = getWorld(); + BlockFace targetBlockFace = target.getTarget(world, blockEntity.getBlockPos(), blockEntity.getBlockState()) + .getOpposite(); + BlockPos pos = targetBlockFace.getPos(); + + targetCapability = LazyOptional.empty(); + + if (!world.isLoaded(pos)) + return; + BlockEntity invBE = world.getBlockEntity(pos); + if (invBE == null) + return; + Capability capability = capability(); + targetCapability = + bypassSided ? invBE.getCapability(capability) : invBE.getCapability(capability, targetBlockFace.getFace()); + if (targetCapability.isPresent()) + targetCapability.addListener(this::onHandlerInvalidated); + } + + @FunctionalInterface + public interface InterfaceProvider { + + public static InterfaceProvider towardBlockFacing() { + return (w, p, s) -> new BlockFace(p, + s.hasProperty(BlockStateProperties.FACING) ? s.getValue(BlockStateProperties.FACING) + : s.getValue(BlockStateProperties.HORIZONTAL_FACING)); + } + + public static InterfaceProvider oppositeOfBlockFacing() { + return (w, p, s) -> new BlockFace(p, + (s.hasProperty(BlockStateProperties.FACING) ? s.getValue(BlockStateProperties.FACING) + : s.getValue(BlockStateProperties.HORIZONTAL_FACING)).getOpposite()); + } + + public BlockFace getTarget(Level world, BlockPos pos, BlockState blockState); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/InvManipulationBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/InvManipulationBehaviour.java new file mode 100644 index 0000000000..f1083ba1fb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/InvManipulationBehaviour.java @@ -0,0 +1,97 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.inventory; + +import java.util.function.Predicate; + +import com.google.common.base.Predicates; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +public class InvManipulationBehaviour extends CapManipulationBehaviourBase { + + // Extra types available for multibehaviour + public static final BehaviourType + + TYPE = new BehaviourType<>(), EXTRACT = new BehaviourType<>(), INSERT = new BehaviourType<>(); + + private BehaviourType behaviourType; + + public static InvManipulationBehaviour forExtraction(SmartBlockEntity be, InterfaceProvider target) { + return new InvManipulationBehaviour(EXTRACT, be, target); + } + + public static InvManipulationBehaviour forInsertion(SmartBlockEntity be, InterfaceProvider target) { + return new InvManipulationBehaviour(INSERT, be, target); + } + + public InvManipulationBehaviour(SmartBlockEntity be, InterfaceProvider target) { + this(TYPE, be, target); + } + + private InvManipulationBehaviour(BehaviourType type, SmartBlockEntity be, + InterfaceProvider target) { + super(be, target); + behaviourType = type; + } + + @Override + protected Capability capability() { + return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; + } + + public ItemStack extract() { + return extract(getModeFromFilter(), getAmountFromFilter()); + } + + public ItemStack extract(ExtractionCountMode mode, int amount) { + return extract(mode, amount, Predicates.alwaysTrue()); + } + + public ItemStack extract(ExtractionCountMode mode, int amount, Predicate filter) { + boolean shouldSimulate = simulateNext; + simulateNext = false; + + if (getWorld().isClientSide) + return ItemStack.EMPTY; + IItemHandler inventory = targetCapability.orElse(null); + if (inventory == null) + return ItemStack.EMPTY; + + Predicate test = getFilterTest(filter); + ItemStack simulatedItems = ItemHelper.extract(inventory, test, mode, amount, true); + if (shouldSimulate || simulatedItems.isEmpty()) + return simulatedItems; + return ItemHelper.extract(inventory, test, mode, amount, false); + } + + public ItemStack insert(ItemStack stack) { + boolean shouldSimulate = simulateNext; + simulateNext = false; + IItemHandler inventory = targetCapability.orElse(null); + if (inventory == null) + return stack; + return ItemHandlerHelper.insertItemStacked(inventory, stack, shouldSimulate); + } + + protected Predicate getFilterTest(Predicate customFilter) { + Predicate test = customFilter; + FilteringBehaviour filter = blockEntity.getBehaviour(FilteringBehaviour.TYPE); + if (filter != null) + test = customFilter.and(filter::test); + return test; + } + + @Override + public BehaviourType getType() { + return behaviourType; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/TankManipulationBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/TankManipulationBehaviour.java similarity index 76% rename from src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/TankManipulationBehaviour.java rename to src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/TankManipulationBehaviour.java index 42a77735f7..aab7b1261c 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/TankManipulationBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/inventory/TankManipulationBehaviour.java @@ -1,11 +1,11 @@ -package com.simibubi.create.foundation.tileEntity.behaviour.inventory; +package com.simibubi.create.foundation.blockEntity.behaviour.inventory; import java.util.function.Predicate; import com.google.common.base.Predicates; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; -import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fluids.FluidStack; @@ -18,13 +18,13 @@ public class TankManipulationBehaviour extends CapManipulationBehaviourBase OBSERVE = new BehaviourType<>(); private BehaviourType behaviourType; - public TankManipulationBehaviour(SmartTileEntity te, InterfaceProvider target) { - this(OBSERVE, te, target); + public TankManipulationBehaviour(SmartBlockEntity be, InterfaceProvider target) { + this(OBSERVE, be, target); } - private TankManipulationBehaviour(BehaviourType type, SmartTileEntity te, + private TankManipulationBehaviour(BehaviourType type, SmartBlockEntity be, InterfaceProvider target) { - super(te, target); + super(be, target); behaviourType = type; } @@ -50,7 +50,7 @@ public class TankManipulationBehaviour extends CapManipulationBehaviourBase getFilterTest(Predicate customFilter) { Predicate test = customFilter; - FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE); + FilteringBehaviour filter = blockEntity.getBehaviour(FilteringBehaviour.TYPE); if (filter != null) test = customFilter.and(filter::test); return test; diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/BulkScrollValueBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/BulkScrollValueBehaviour.java new file mode 100644 index 0000000000..685c24beda --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/BulkScrollValueBehaviour.java @@ -0,0 +1,41 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + +import java.util.List; +import java.util.function.Function; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; + +public class BulkScrollValueBehaviour extends ScrollValueBehaviour { + + Function> groupGetter; + + public BulkScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot, + Function> groupGetter) { + super(label, be, slot); + this.groupGetter = groupGetter; + } + + @Override + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown) { + if (!ctrlDown) { + super.setValueSettings(player, valueSetting, ctrlDown); + return; + } + if (!valueSetting.equals(getValueSettings())) + playFeedbackSound(this); + for (SmartBlockEntity be : getBulk()) { + ScrollValueBehaviour other = be.getBehaviour(ScrollValueBehaviour.TYPE); + if (other != null) + other.setValue(valueSetting.value()); + } + } + + public List getBulk() { + return groupGetter.apply(blockEntity); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/INamedIconOptions.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/INamedIconOptions.java new file mode 100644 index 0000000000..821d3ec2a1 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/INamedIconOptions.java @@ -0,0 +1,8 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + +import com.simibubi.create.foundation.gui.AllIcons; + +public interface INamedIconOptions { + AllIcons getIcon(); + String getTranslationKey(); +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollOptionBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollOptionBehaviour.java new file mode 100644 index 0000000000..feafc6adb8 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollOptionBehaviour.java @@ -0,0 +1,43 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter.ScrollOptionSettingsFormatter; + +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.BlockHitResult; + +public class ScrollOptionBehaviour & INamedIconOptions> extends ScrollValueBehaviour { + + private E[] options; + + public ScrollOptionBehaviour(Class enum_, Component label, SmartBlockEntity be, ValueBoxTransform slot) { + super(label, be, slot); + options = enum_.getEnumConstants(); + between(0, options.length - 1); + } + + INamedIconOptions getIconForSelected() { + return get(); + } + + public E get() { + return options[value]; + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + return new ValueSettingsBoard(label, max, 1, ImmutableList.of(Components.literal("Select")), + new ScrollOptionSettingsFormatter(options)); + } + + @Override + public String getClipboardKey() { + return options[0].getClass().getSimpleName(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueBehaviour.java new file mode 100644 index 0000000000..fa201ff676 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueBehaviour.java @@ -0,0 +1,190 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsBoard; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueSettingsFormatter; + +import net.createmod.catnip.utility.VecHelper; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.FakePlayer; + +public class ScrollValueBehaviour extends BlockEntityBehaviour implements ValueSettingsBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + ValueBoxTransform slotPositioning; + Vec3 textShift; + + int min = 0; + protected int max = 1; + public int value; + public Component label; + Consumer callback; + Consumer clientCallback; + Function formatter; + private Supplier isActive; + boolean needsWrench; + + public ScrollValueBehaviour(Component label, SmartBlockEntity be, ValueBoxTransform slot) { + super(be); + this.setLabel(label); + slotPositioning = slot; + callback = i -> { + }; + clientCallback = i -> { + }; + formatter = i -> Integer.toString(i); + value = 0; + isActive = () -> true; + } + + @Override + public boolean isSafeNBT() { + return true; + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + nbt.putInt("ScrollValue", value); + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + value = nbt.getInt("ScrollValue"); + super.read(nbt, clientPacket); + } + + public ScrollValueBehaviour withClientCallback(Consumer valueCallback) { + clientCallback = valueCallback; + return this; + } + + public ScrollValueBehaviour withCallback(Consumer valueCallback) { + callback = valueCallback; + return this; + } + + public ScrollValueBehaviour between(int min, int max) { + this.min = min; + this.max = max; + return this; + } + + public ScrollValueBehaviour requiresWrench() { + this.needsWrench = true; + return this; + } + + public ScrollValueBehaviour withFormatter(Function formatter) { + this.formatter = formatter; + return this; + } + + public ScrollValueBehaviour onlyActiveWhen(Supplier condition) { + isActive = condition; + return this; + } + + public void setValue(int value) { + value = Mth.clamp(value, min, max); + if (value == this.value) + return; + this.value = value; + callback.accept(value); + blockEntity.setChanged(); + blockEntity.sendData(); + } + + public int getValue() { + return value; + } + + public String formatValue() { + return formatter.apply(value); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + @Override + public boolean isActive() { + return isActive.get(); + } + + @Override + public boolean testHit(Vec3 hit) { + BlockState state = blockEntity.getBlockState(); + Vec3 localHit = hit.subtract(Vec3.atLowerCornerOf(blockEntity.getBlockPos())); + return slotPositioning.testHit(state, localHit); + } + + public void setLabel(Component label) { + this.label = label; + } + + public static class StepContext { + public int currentValue; + public boolean forward; + public boolean shift; + public boolean control; + } + + @Override + public ValueBoxTransform getSlotPositioning() { + return slotPositioning; + } + + @Override + public ValueSettingsBoard createBoard(Player player, BlockHitResult hitResult) { + return new ValueSettingsBoard(label, max, 10, ImmutableList.of(Components.literal("Value")), + new ValueSettingsFormatter(ValueSettings::format)); + } + + @Override + public void setValueSettings(Player player, ValueSettings valueSetting, boolean ctrlDown) { + if (valueSetting.equals(getValueSettings())) + return; + setValue(valueSetting.value()); + playFeedbackSound(this); + } + + @Override + public ValueSettings getValueSettings() { + return new ValueSettings(0, value); + } + + @Override + public boolean onlyVisibleWithWrench() { + return needsWrench; + } + + @Override + public void onShortInteract(Player player, InteractionHand hand, Direction side) { + if (player instanceof FakePlayer) + blockEntity.getBlockState() + .use(getWorld(), player, hand, + new BlockHitResult(VecHelper.getCenterOf(getPos()), side, getPos(), true)); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueHandler.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueHandler.java new file mode 100644 index 0000000000..5eb292b7a2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueHandler.java @@ -0,0 +1,32 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + + +import net.createmod.catnip.utility.animation.PhysicalFloat; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class ScrollValueHandler { + + private static float lastPassiveScroll = 0.0f; + private static float passiveScroll = 0.0f; + private static float passiveScrollDirection = 1f; + public static final PhysicalFloat wrenchCog = PhysicalFloat.create() + .withDrag(0.3); + + public static float getScroll(float partialTicks) { + return wrenchCog.getValue(partialTicks) + Mth.lerp(partialTicks, lastPassiveScroll, passiveScroll); + } + + @OnlyIn(Dist.CLIENT) + public static void tick() { + if (!Minecraft.getInstance() + .isPaused()) { + lastPassiveScroll = passiveScroll; + wrenchCog.tick(); + passiveScroll += passiveScrollDirection * 0.5; + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueRenderer.java new file mode 100644 index 0000000000..0d51d8ae8b --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/scrollValue/ScrollValueRenderer.java @@ -0,0 +1,98 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.scrollValue; + +import java.util.ArrayList; +import java.util.List; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllKeys; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox.IconValueBox; +import com.simibubi.create.foundation.blockEntity.behaviour.ValueBox.TextValueBox; +import com.simibubi.create.foundation.utility.CreateLang; + +import net.createmod.catnip.CatnipClient; +import net.createmod.catnip.utility.lang.Components; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class ScrollValueRenderer { + + public static void tick() { + Minecraft mc = Minecraft.getInstance(); + HitResult target = mc.hitResult; + if (target == null || !(target instanceof BlockHitResult)) + return; + + BlockHitResult result = (BlockHitResult) target; + ClientLevel world = mc.level; + BlockPos pos = result.getBlockPos(); + Direction face = result.getDirection(); + + ScrollValueBehaviour behaviour = BlockEntityBehaviour.get(world, pos, ScrollValueBehaviour.TYPE); + if (behaviour == null) + return; + if (!behaviour.isActive()) { + CatnipClient.OUTLINER.remove(pos); + return; + } + ItemStack mainhandItem = mc.player.getItemInHand(InteractionHand.MAIN_HAND); + boolean clipboard = AllBlocks.CLIPBOARD.isIn(mainhandItem); + if (behaviour.needsWrench && !AllItems.WRENCH.isIn(mainhandItem) && !clipboard) + return; + boolean highlight = behaviour.testHit(target.getLocation()) && !clipboard; + + if (behaviour instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) { + BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) behaviour; + for (SmartBlockEntity smartBlockEntity : bulkScrolling.getBulk()) { + ScrollValueBehaviour other = smartBlockEntity.getBehaviour(ScrollValueBehaviour.TYPE); + if (other != null) + addBox(world, smartBlockEntity.getBlockPos(), face, other, highlight); + } + } else + addBox(world, pos, face, behaviour, highlight); + + if (!highlight) + return; + + List tip = new ArrayList<>(); + tip.add(behaviour.label.copy()); + tip.add(CreateLang.translateDirect("gui.value_settings.hold_to_edit")); + CreateClient.VALUE_SETTINGS_HANDLER.showHoverTip(tip); + } + + protected static void addBox(ClientLevel world, BlockPos pos, Direction face, ScrollValueBehaviour behaviour, + boolean highlight) { + AABB bb = new AABB(Vec3.ZERO, Vec3.ZERO).inflate(.5f) + .contract(0, 0, -.5f) + .move(0, 0, -.125f); + Component label = behaviour.label; + ValueBox box; + + if (behaviour instanceof ScrollOptionBehaviour) { + box = new IconValueBox(label, ((ScrollOptionBehaviour) behaviour).getIconForSelected(), bb, pos); + } else { + box = new TextValueBox(label, bb, pos, Components.literal(behaviour.formatValue())); + } + + box.passive(!highlight) + .wideOutline(); + + CatnipClient.OUTLINER.showOutline(pos, box.transform(behaviour.slotPositioning)) + .highlightFace(face); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/simple/DeferralBehaviour.java b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/simple/DeferralBehaviour.java new file mode 100644 index 0000000000..3e23d96e1c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/behaviour/simple/DeferralBehaviour.java @@ -0,0 +1,54 @@ +package com.simibubi.create.foundation.blockEntity.behaviour.simple; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; + +import net.minecraft.nbt.CompoundTag; + +public class DeferralBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + private boolean needsUpdate; + private Supplier callback; + + public DeferralBehaviour(SmartBlockEntity be, Supplier callback) { + super(be); + this.callback = callback; + } + + @Override + public boolean isSafeNBT() { return true; } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + nbt.putBoolean("NeedsUpdate", needsUpdate); + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + needsUpdate = nbt.getBoolean("NeedsUpdate"); + super.read(nbt, clientPacket); + } + + @Override + public void tick() { + super.tick(); + if (needsUpdate && callback.get()) + needsUpdate = false; + } + + public void scheduleUpdate() { + needsUpdate = true; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/ColoredOverlayBlockEntityRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/ColoredOverlayBlockEntityRenderer.java new file mode 100644 index 0000000000..94fa132e0c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/ColoredOverlayBlockEntityRenderer.java @@ -0,0 +1,35 @@ +package com.simibubi.create.foundation.blockEntity.renderer; + +import com.jozufozu.flywheel.backend.Backend; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.createmod.catnip.render.SuperByteBuffer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class ColoredOverlayBlockEntityRenderer extends SafeBlockEntityRenderer { + + public ColoredOverlayBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, + int light, int overlay) { + + if (Backend.canUseInstancing(be.getLevel())) return; + + SuperByteBuffer render = render(getOverlayBuffer(be), getColor(be, partialTicks), light); + render.renderInto(ms, buffer.getBuffer(RenderType.solid())); + } + + protected abstract int getColor(T be, float partialTicks); + + protected abstract SuperByteBuffer getOverlayBuffer(T be); + + public static SuperByteBuffer render(SuperByteBuffer buffer, int color, int light) { + return buffer.color(color).light(light); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SafeBlockEntityRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SafeBlockEntityRenderer.java new file mode 100644 index 0000000000..1ecb77e29d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SafeBlockEntityRenderer.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.blockEntity.renderer; + +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; + +public abstract class SafeBlockEntityRenderer implements BlockEntityRenderer { + @Override + public final void render(T be, float partialTicks, PoseStack ms, MultiBufferSource bufferSource, int light, + int overlay) { + if (isInvalid(be)) + return; + renderSafe(be, partialTicks, ms, bufferSource, light, overlay); + } + + protected abstract void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource bufferSource, int light, + int overlay); + + public boolean isInvalid(T be) { + return !be.hasLevel() || be.getBlockState() + .getBlock() == Blocks.AIR; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SmartBlockEntityRenderer.java b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SmartBlockEntityRenderer.java new file mode 100644 index 0000000000..041c97d170 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/blockEntity/renderer/SmartBlockEntityRenderer.java @@ -0,0 +1,23 @@ +package com.simibubi.create.foundation.blockEntity.renderer; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.redstone.link.LinkRenderer; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringRenderer; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; + +public class SmartBlockEntityRenderer extends SafeBlockEntityRenderer { + + public SmartBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + } + + @Override + protected void renderSafe(T blockEntity, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, + int overlay) { + FilteringRenderer.renderOnBlockEntity(blockEntity, partialTicks, ms, buffer, light, overlay); + LinkRenderer.renderOnBlockEntity(blockEntity, partialTicks, ms, buffer, light, overlay); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/collision/Matrix3d.java b/src/main/java/com/simibubi/create/foundation/collision/Matrix3d.java index 0778f8d0da..fe9fff215a 100644 --- a/src/main/java/com/simibubi/create/foundation/collision/Matrix3d.java +++ b/src/main/java/com/simibubi/create/foundation/collision/Matrix3d.java @@ -40,8 +40,8 @@ public class Matrix3d { double s = Mth.sin(radians); double c = Mth.cos(radians); m00 = m22 = c; - m20 = s; - m02 = -s; + m02 = s; + m20 = -s; return this; } diff --git a/src/main/java/com/simibubi/create/foundation/command/CameraDistanceCommand.java b/src/main/java/com/simibubi/create/foundation/command/CameraDistanceCommand.java deleted file mode 100644 index 24ae3ef810..0000000000 --- a/src/main/java/com/simibubi/create/foundation/command/CameraDistanceCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.simibubi.create.foundation.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.arguments.FloatArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; - -import net.createmod.catnip.net.ClientboundSimpleActionPacket; -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.server.level.ServerPlayer; - -public class CameraDistanceCommand { - - public static ArgumentBuilder register() { - return Commands.literal("camera") - .then(Commands.literal("reset") - .executes(ctx -> { - ServerPlayer player = ctx.getSource().getPlayerOrException(); - CatnipServices.NETWORK.sendToPlayer( - player, - new ClientboundSimpleActionPacket("zoomMultiplier", "")); - - return Command.SINGLE_SUCCESS; - }) - ).then(Commands.argument("multiplier", FloatArgumentType.floatArg(0)) - .executes(ctx -> { - float multiplier = FloatArgumentType.getFloat(ctx, "multiplier"); - ServerPlayer player = ctx.getSource().getPlayerOrException(); - CatnipServices.NETWORK.sendToPlayer( - player, - new ClientboundSimpleActionPacket("zoomMultiplier", String.valueOf(multiplier))); - - return Command.SINGLE_SUCCESS; - }) - ); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java b/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java deleted file mode 100644 index 180036856b..0000000000 --- a/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.simibubi.create.foundation.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.builder.ArgumentBuilder; - -import net.createmod.catnip.net.ClientboundSimpleActionPacket; -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.server.level.ServerPlayer; - -public class FabulousWarningCommand { - - public static ArgumentBuilder register() { - return Commands.literal("dismissFabulousWarning") - .requires(AllCommands.SOURCE_IS_PLAYER) - .executes(ctx -> { - ServerPlayer player = ctx.getSource() - .getPlayerOrException(); - - CatnipServices.NETWORK.sendToPlayer( - player, - new ClientboundSimpleActionPacket("fabulousWarning", "")); - - return Command.SINGLE_SUCCESS; - }); - - } -} diff --git a/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java b/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java deleted file mode 100644 index 480b7960b5..0000000000 --- a/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.simibubi.create.foundation.command; - -import com.mojang.brigadier.builder.ArgumentBuilder; - -import net.createmod.catnip.net.ClientboundSimpleActionPacket; -import net.createmod.catnip.platform.CatnipServices; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; - -public class FixLightingCommand { - - static ArgumentBuilder register() { - return Commands.literal("fixLighting") - .requires(cs -> cs.hasPermission(0)) - .executes(ctx -> { - CatnipServices.NETWORK.sendToPlayer( - ctx.getSource().getPlayerOrException(), - new ClientboundSimpleActionPacket("fixLighting", String.valueOf(true))); - - ctx.getSource() - .sendSuccess( - Components.literal("Forge's experimental block rendering pipeline is now enabled."), true); - - return 1; - }); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java b/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java deleted file mode 100644 index a3bbd49e44..0000000000 --- a/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.simibubi.create.foundation.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.builder.ArgumentBuilder; - -import net.createmod.catnip.net.ClientboundSimpleActionPacket; -import net.createmod.catnip.platform.CatnipServices; -import net.createmod.catnip.utility.lang.Components; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.world.entity.player.Player; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; - -public class OverlayConfigCommand { - - public static ArgumentBuilder register() { - return Commands.literal("overlay") - .requires(cs -> cs.hasPermission(0)) - .then(Commands.literal("reset") - .executes(ctx -> { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SimpleCreateActions.overlayReset("")); - - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - CatnipServices.NETWORK.sendToPlayer( - (Player) ctx.getSource().getEntity(), - new ClientboundSimpleActionPacket("overlayReset", ""))); - - ctx.getSource() - .sendSuccess(Components.literal("reset overlay offset"), true); - - return Command.SINGLE_SUCCESS; - }) - ) - .executes(ctx -> { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SimpleCreateActions.overlayScreen("")); - - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> - CatnipServices.NETWORK.sendToPlayer( - (Player) ctx.getSource().getEntity(), - new ClientboundSimpleActionPacket("overlayScreen", ""))); - - ctx.getSource() - .sendSuccess(Components.literal("window opened"), true); - - return Command.SINGLE_SUCCESS; - }); - - } -} diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java deleted file mode 100644 index 6873824fa9..0000000000 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.simibubi.create.foundation.command; - -import net.createmod.catnip.net.ClientboundSimpleActionPacket; -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.server.level.ServerPlayer; - -public class ToggleDebugCommand extends ConfigureConfigCommand { - - public ToggleDebugCommand() { - super("rainbowDebug"); - } - - @Override - protected void sendPacket(ServerPlayer player, String option) { - CatnipServices.NETWORK.sendToPlayer( - player, - new ClientboundSimpleActionPacket("rainbowDebug", option) - ); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java b/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java deleted file mode 100644 index 9c8d663f4f..0000000000 --- a/src/main/java/com/simibubi/create/foundation/config/CCuriosities.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.simibubi.create.foundation.config; - -import net.createmod.catnip.config.ConfigBase; - -public class CCuriosities extends ConfigBase { - - public final ConfigInt maxSymmetryWandRange = i(50, 10, "maxSymmetryWandRange", Comments.symmetryRange); - public final ConfigInt placementAssistRange = i(12, 3, "placementAssistRange", Comments.placementRange); - public final ConfigInt toolboxRange = i(10, 1, "toolboxRange", Comments.toolboxRange); - public final ConfigInt airInBacktank = i(900, 1, "airInBacktank", Comments.maxAirInBacktank); - public final ConfigInt enchantedBacktankCapacity = i(300, 1, "enchantedBacktankCapacity", Comments.enchantedBacktankCapacity); - - public final ConfigInt maxExtendoGripActions = i(1000, 0, "maxExtendoGripActions", Comments.maxExtendoGripActions); - public final ConfigInt maxPotatoCannonShots = i(200, 0, "maxPotatoCannonShots", Comments.maxPotatoCannonShots); - -// public ConfigInt zapperUndoLogLength = i(10, 0, "zapperUndoLogLength", Comments.zapperUndoLogLength); NYI - - @Override - public String getName() { - return "curiosities"; - } - - private static class Comments { - static String symmetryRange = "The Maximum Distance to an active mirror for the symmetry wand to trigger."; - static String maxAirInBacktank = - "The Maximum volume of Air that can be stored in a backtank = Seconds of underwater breathing"; - static String enchantedBacktankCapacity = - "The volume of Air added by each level of the backtanks Capacity Enchantment"; - static String placementRange = - "The Maximum Distance a Block placed by Create's placement assist will have to its interaction point."; - static String toolboxRange = - "The Maximum Distance at which a Toolbox can interact with Players' Inventories."; - static String maxExtendoGripActions = - "Amount of free Extendo Grip actions provided by one filled Copper Backtank. Set to 0 makes Extendo Grips unbreakable"; - static String maxPotatoCannonShots = - "Amount of free Potato Cannon shots provided by one filled Copper Backtank. Set to 0 makes Potato Cannons unbreakable"; -// static String zapperUndoLogLength = "The maximum amount of operations a blockzapper can remember for undoing. (0 to disable undo)"; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java b/src/main/java/com/simibubi/create/foundation/config/CLogistics.java deleted file mode 100644 index 90e813ef4a..0000000000 --- a/src/main/java/com/simibubi/create/foundation/config/CLogistics.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.simibubi.create.foundation.config; - -import net.createmod.catnip.config.ConfigBase; - -public class CLogistics extends ConfigBase { - - public final ConfigInt defaultExtractionLimit = - i(64, 1, 64, "defaultExtractionLimit", Comments.defaultExtractionLimit); - public final ConfigInt defaultExtractionTimer = i(8, 1, "defaultExtractionTimer", Comments.defaultExtractionTimer); - public final ConfigInt psiTimeout = i(20, 1, "psiTimeout", Comments.psiTimeout); - public final ConfigInt mechanicalArmRange = i(5, 1, "mechanicalArmRange", Comments.mechanicalArmRange); - public final ConfigInt linkRange = i(256, 1, "linkRange", Comments.linkRange); - public final ConfigInt displayLinkRange = i(64, 1, "displayLinkRange", Comments.displayLinkRange); - public final ConfigInt vaultCapacity = i(20, 1, "vaultCapacity", Comments.vaultCapacity); - - @Override - public String getName() { - return "logistics"; - } - - private static class Comments { - static String defaultExtractionLimit = - "The maximum amount of items a funnel pulls at a time without an applied filter."; - static String defaultExtractionTimer = - "The amount of ticks a funnel waits between item transferrals, when it is not re-activated by redstone."; - static String linkRange = "Maximum possible range in blocks of redstone link connections."; - static String displayLinkRange = - "Maximum possible distance in blocks between data gatherers and their target."; - static String psiTimeout = - "The amount of ticks a portable storage interface waits for transfers until letting contraptions move along."; - static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across."; - static String vaultCapacity = "The total amount of stacks a vault can hold per block in size."; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/config/ContraptionMovementSetting.java b/src/main/java/com/simibubi/create/foundation/config/ContraptionMovementSetting.java deleted file mode 100644 index 5aca81cdbe..0000000000 --- a/src/main/java/com/simibubi/create/foundation/config/ContraptionMovementSetting.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.foundation.config; - -import java.util.Collection; -import java.util.function.Supplier; - -import javax.annotation.Nullable; - -import com.simibubi.create.foundation.utility.CreateRegistry; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.common.extensions.IForgeBlock; -import net.minecraftforge.registries.ForgeRegistries; - -public enum ContraptionMovementSetting { - MOVABLE, NO_PICKUP, UNMOVABLE; - - private static final CreateRegistry> SETTING_SUPPLIERS = new CreateRegistry<>(ForgeRegistries.BLOCKS); - - public static void register(ResourceLocation block, Supplier settingSupplier) { - SETTING_SUPPLIERS.register(block, settingSupplier); - } - - public static void register(Block block, Supplier settingSupplier) { - SETTING_SUPPLIERS.register(block, settingSupplier); - } - - @Nullable - public static ContraptionMovementSetting get(Block block) { - if (block instanceof IMovementSettingProvider provider) - return provider.getContraptionMovementSetting(); - Supplier supplier = SETTING_SUPPLIERS.get(block); - if (supplier == null) - return null; - return supplier.get(); - } - - public static boolean allAre(Collection blocks, ContraptionMovementSetting are) { - return blocks.stream().anyMatch(b -> get(b.state.getBlock()) == are); - } - - public static boolean isNoPickup(Collection blocks) { - return allAre(blocks, ContraptionMovementSetting.NO_PICKUP); - } - - public static void registerDefaults() { - register(Blocks.SPAWNER, () -> AllConfigs.SERVER.kinetics.spawnerMovement.get()); - register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.SERVER.kinetics.amethystMovement.get()); - register(Blocks.OBSIDIAN, () -> AllConfigs.SERVER.kinetics.obsidianMovement.get()); - register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.SERVER.kinetics.obsidianMovement.get()); - register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.SERVER.kinetics.obsidianMovement.get()); - } - - public interface IMovementSettingProvider extends IForgeBlock { - ContraptionMovementSetting getContraptionMovementSetting(); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java b/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java index 8ed068b2e2..e41c9ef903 100644 --- a/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java +++ b/src/main/java/com/simibubi/create/foundation/data/AllLangPartials.java @@ -5,12 +5,11 @@ import com.google.gson.JsonElement; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; import com.simibubi.create.foundation.advancement.AllAdvancements; -import com.simibubi.create.foundation.utility.FilesHelper; import net.createmod.catnip.utility.lang.Lang; import net.createmod.ponder.foundation.PonderLocalization; -public enum AllLangPartials { +public enum AllLangPartials implements LangPartial { ADVANCEMENTS("Advancements", AllAdvancements::provideLangEntries), INTERFACE("UI & Messages"), @@ -20,34 +19,28 @@ public enum AllLangPartials { ; - private String display; - private Supplier provider; + private final String displayName; + private final Supplier provider; - private AllLangPartials(String display) { - this.display = display; - this.provider = this::fromResource; + private AllLangPartials(String displayName) { + this.displayName = displayName; + String fileName = Lang.asId(name()); + this.provider = () -> LangPartial.fromResource(Create.ID, fileName); } - private AllLangPartials(String display, Supplier customProvider) { - this.display = display; - this.provider = customProvider; + private AllLangPartials(String displayName, Supplier provider) { + this.displayName = displayName; + this.provider = provider; } - public String getDisplay() { - return display; + @Override + public String getDisplayName() { + return displayName; } + @Override public JsonElement provide() { return provider.get(); } - private JsonElement fromResource() { - String fileName = Lang.asId(name()); - String filepath = "assets/" + Create.ID + "/lang/default/" + fileName + ".json"; - JsonElement element = FilesHelper.loadJsonResource(filepath); - if (element == null) - throw new IllegalStateException(String.format("Could not find default lang file: %s", filepath)); - return element; - } - } diff --git a/src/main/java/com/simibubi/create/foundation/data/BlockStateGen.java b/src/main/java/com/simibubi/create/foundation/data/BlockStateGen.java index 8210a8867f..fa67a24cfb 100644 --- a/src/main/java/com/simibubi/create/foundation/data/BlockStateGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/BlockStateGen.java @@ -14,20 +14,21 @@ import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleBlock.WhistleSize; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock; -import com.simibubi.create.content.contraptions.components.steam.whistle.WhistleExtenderBlock.WhistleExtenderShape; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.RadialChassisBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssembleRailType; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock; -import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; -import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; +import com.simibubi.create.content.contraptions.chassis.LinearChassisBlock; +import com.simibubi.create.content.contraptions.chassis.RadialChassisBlock; +import com.simibubi.create.content.contraptions.mounted.CartAssembleRailType; +import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock.WhistleSize; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock; +import com.simibubi.create.content.decoration.steamWhistle.WhistleExtenderBlock.WhistleExtenderShape; +import com.simibubi.create.content.fluids.pipes.EncasedPipeBlock; +import com.simibubi.create.content.fluids.pipes.FluidPipeBlock; +import com.simibubi.create.content.kinetics.base.DirectionalAxisKineticBlock; +import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; import com.tterrag.registrate.util.nullness.NonNullBiConsumer; +import com.tterrag.registrate.util.nullness.NonnullType; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.Pointing; @@ -333,6 +334,21 @@ public class BlockStateGen { }; } + public static

NonNullBiConsumer, RegistrateBlockstateProvider> naturalStoneTypeBlock( + String type) { + return (c, p) -> { + ConfiguredModel[] variants = new ConfiguredModel[4]; + for (int i = 0; i < variants.length; i++) + variants[i] = ConfiguredModel.builder() + .modelFile(p.models() + .cubeAll(type + "_natural_" + i, p.modLoc("block/palettes/stone_types/natural/" + type + "_" + i))) + .buildLast(); + p.getVariantBuilder(c.get()) + .partialState() + .setModels(variants); + }; + } + public static

NonNullBiConsumer, RegistrateBlockstateProvider> encasedPipe() { return (c, p) -> { ModelFile open = AssetLookup.partialBaseModel(c, p, "open"); @@ -522,4 +538,11 @@ public class BlockStateGen { .end(); } + public static Function mapToAir(@NonnullType RegistrateBlockstateProvider p) { + return state -> ConfiguredModel.builder() + .modelFile(p.models() + .getExistingFile(p.mcLoc("block/air"))) + .build(); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java index 12e09dc793..d68a356ceb 100644 --- a/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java +++ b/src/main/java/com/simibubi/create/foundation/data/BuilderTransformers.java @@ -2,11 +2,11 @@ package com.simibubi.create.foundation.data; import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour; import static com.simibubi.create.AllMovementBehaviours.movementBehaviour; -import static com.simibubi.create.AllTags.axeOrPickaxe; -import static com.simibubi.create.AllTags.pickaxeOnly; import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; import static com.simibubi.create.foundation.data.CreateRegistrate.casingConnectivity; import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; +import static com.simibubi.create.foundation.data.TagGen.axeOrPickaxe; +import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly; import java.util.HashMap; import java.util.Map; @@ -18,24 +18,28 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.base.CasingBlock; -import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.DoorMovingInteraction; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.TrapdoorMovingInteraction; -import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonGenerator; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCTBehaviour; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogCTBehaviour; -import com.simibubi.create.content.contraptions.relays.encased.EncasedCogwheelBlock; -import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; -import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock; -import com.simibubi.create.content.curiosities.deco.SlidingDoorMovementBehaviour; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape; -import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem; -import com.simibubi.create.content.logistics.trains.IBogeyBlock; -import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock; -import com.simibubi.create.foundation.block.BlockStressDefaults; +import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction; +import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction; +import com.simibubi.create.content.contraptions.piston.MechanicalPistonGenerator; +import com.simibubi.create.content.decoration.MetalScaffoldingBlock; +import com.simibubi.create.content.decoration.MetalScaffoldingBlockItem; +import com.simibubi.create.content.decoration.MetalScaffoldingCTBehaviour; +import com.simibubi.create.content.decoration.copycat.CopycatBlock; +import com.simibubi.create.content.decoration.encasing.CasingBlock; +import com.simibubi.create.content.decoration.encasing.EncasedCTBehaviour; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorBlock; +import com.simibubi.create.content.decoration.slidingDoor.SlidingDoorMovementBehaviour; +import com.simibubi.create.content.kinetics.BlockStressDefaults; +import com.simibubi.create.content.kinetics.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.kinetics.crank.ValveHandleBlock; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogCTBehaviour; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedCogwheelBlock; +import com.simibubi.create.content.kinetics.simpleRelays.encased.EncasedShaftBlock; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelBlock.Shape; +import com.simibubi.create.content.logistics.tunnel.BeltTunnelItem; +import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; +import com.simibubi.create.content.trains.bogey.StandardBogeyBlock; import com.simibubi.create.foundation.block.ItemUseOverrides; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour; @@ -62,6 +66,17 @@ import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.PistonType; import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.MaterialColor; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.LootTable.Builder; +import net.minecraft.world.level.storage.loot.entries.LootItem; +import net.minecraft.world.level.storage.loot.functions.CopyNameFunction; +import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction; +import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider; +import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import net.minecraftforge.client.model.generators.ConfiguredModel; import net.minecraftforge.client.model.generators.ModelFile; @@ -80,6 +95,7 @@ public class BuilderTransformers { .build(); } + @SuppressWarnings("deprecation") public static NonNullUnaryOperator> bogey() { return b -> b.initialProperties(SharedProperties::softMetal) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) @@ -88,7 +104,22 @@ public class BuilderTransformers { .blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models() .getExistingFile(p.modLoc("block/track/bogey/top")))) .loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get())) - .onRegister(block -> IBogeyBlock.register(CatnipServices.REGISTRIES.getKeyOrThrow(block))); + .onRegister(block -> AbstractBogeyBlock.registerStandardBogey(CatnipServices.REGISTRIES.getKeyOrThrow(block))); + } + + public static NonNullUnaryOperator> copycat() { + return b -> b.initialProperties(SharedProperties::softMetal) + .blockstate((c, p) -> p.simpleBlock(c.get(), p.models() + .getExistingFile(p.mcLoc("air")))) + .initialProperties(SharedProperties::softMetal) + .properties(p -> p.noOcclusion() + .color(MaterialColor.NONE)) + .addLayer(() -> RenderType::solid) + .addLayer(() -> RenderType::cutout) + .addLayer(() -> RenderType::cutoutMipped) + .addLayer(() -> RenderType::translucent) + .color(() -> CopycatBlock::wrappedColor) + .transform(TagGen.axeOrPickaxe()); } public static NonNullUnaryOperator> trapdoor(boolean orientable) { @@ -129,6 +160,7 @@ public class BuilderTransformers { .loot((lr, block) -> lr.add(block, BlockLoot.createDoorTable(block))) .item() .tag(ItemTags.DOORS) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .model((c, p) -> p.blockSprite(c, p.modLoc("item/" + type + "_door"))) .build(); } @@ -149,6 +181,7 @@ public class BuilderTransformers { String encasedSuffix = "_encased_cogwheel_side" + (large ? "_connected" : ""); String blockFolder = large ? "encased_large_cogwheel" : "encased_cogwheel"; String wood = casing.equals("brass") ? "dark_oak" : "spruce"; + String gearbox = casing.equals("brass") ? "brass_gearbox" : "gearbox"; return encasedBase(b, drop).addLayer(() -> RenderType::cutoutMipped) .onRegister(CreateRegistrate.casingConnectivity((block, cc) -> cc.make(block, casingShift.get(), (s, f) -> f.getAxis() == s.getValue(EncasedCogwheelBlock.AXIS) @@ -161,12 +194,15 @@ public class BuilderTransformers { return p.models() .withExistingParent(modelName, p.modLoc("block/" + blockFolder + "/block" + suffix)) .texture("casing", Create.asResource("block/" + casing + "_casing")) + .texture("particle", Create.asResource("block/" + casing + "_casing")) + .texture("4", Create.asResource("block/" + gearbox)) .texture("1", new ResourceLocation("block/stripped_" + wood + "_log_top")) .texture("side", Create.asResource("block/" + casing + encasedSuffix)); }, false)) .item() .model((c, p) -> p.withExistingParent(c.getName(), p.modLoc("block/" + blockFolder + "/item")) .texture("casing", Create.asResource("block/" + casing + "_casing")) + .texture("particle", Create.asResource("block/" + casing + "_casing")) .texture("1", new ResourceLocation("block/stripped_" + wood + "_log_top")) .texture("side", Create.asResource("block/" + casing + encasedSuffix))) .build(); @@ -191,8 +227,9 @@ public class BuilderTransformers { } public static NonNullUnaryOperator> ladder(String name, - Supplier ingredient) { + Supplier ingredient, MaterialColor color) { return b -> b.initialProperties(() -> Blocks.LADDER) + .properties(p -> p.color(color)) .addLayer(() -> RenderType::cutout) .blockstate((c, p) -> p.horizontalBlock(c.get(), p.models() .withExistingParent(c.getName(), p.modLoc("block/ladder")) @@ -203,15 +240,41 @@ public class BuilderTransformers { .transform(pickaxeOnly()) .tag(BlockTags.CLIMBABLE) .item() - .recipe((c, p) -> { - if (name.equals("andesite")) - return; - p.stonecutting(ingredient.get(), c::get, 2); - }) + .recipe((c, p) -> p.stonecutting(ingredient.get(), c::get, 2)) .model((c, p) -> p.blockSprite(c::get, p.modLoc("block/ladder_" + name))) .build(); } + public static NonNullUnaryOperator> scaffold(String name, + Supplier ingredient, MaterialColor color, CTSpriteShiftEntry scaffoldShift, + CTSpriteShiftEntry scaffoldInsideShift, CTSpriteShiftEntry casingShift) { + return b -> b.initialProperties(() -> Blocks.SCAFFOLDING) + .properties(p -> p.sound(SoundType.COPPER) + .color(color)) + .addLayer(() -> RenderType::cutout) + .blockstate((c, p) -> p.getVariantBuilder(c.get()) + .forAllStatesExcept(s -> { + String suffix = s.getValue(MetalScaffoldingBlock.BOTTOM) ? "_horizontal" : ""; + return ConfiguredModel.builder() + .modelFile(p.models() + .withExistingParent(c.getName() + suffix, p.modLoc("block/scaffold/block" + suffix)) + .texture("top", p.modLoc("block/funnel/" + name + "_funnel_frame")) + .texture("inside", p.modLoc("block/scaffold/" + name + "_scaffold_inside")) + .texture("side", p.modLoc("block/scaffold/" + name + "_scaffold")) + .texture("casing", p.modLoc("block/" + name + "_casing")) + .texture("particle", p.modLoc("block/scaffold/" + name + "_scaffold"))) + .build(); + }, MetalScaffoldingBlock.WATERLOGGED, MetalScaffoldingBlock.DISTANCE)) + .onRegister(connectedTextures( + () -> new MetalScaffoldingCTBehaviour(scaffoldShift, scaffoldInsideShift, casingShift))) + .transform(pickaxeOnly()) + .tag(BlockTags.CLIMBABLE) + .item(MetalScaffoldingBlockItem::new) + .recipe((c, p) -> p.stonecutting(ingredient.get(), c::get, 2)) + .model((c, p) -> p.withExistingParent(c.getName(), p.modLoc("block/" + c.getName()))) + .build(); + } + public static NonNullUnaryOperator> valveHandle( @Nullable DyeColor color) { return b -> b.initialProperties(SharedProperties::copperMetal) @@ -222,7 +285,6 @@ public class BuilderTransformers { .texture("3", p.modLoc("block/valve_handle/valve_handle_" + variant))); }) .tag(AllBlockTags.BRITTLE.tag, AllBlockTags.VALVE_HANDLES.tag) - .transform(BlockStressDefaults.setCapacity(8.0)) .transform(BlockStressDefaults.setGeneratorSpeed(ValveHandleBlock::getSpeedRange)) .onRegister(ItemUseOverrides::addBlock) .item() @@ -263,33 +325,37 @@ public class BuilderTransformers { public static NonNullUnaryOperator> beltTunnel( String type, ResourceLocation particleTexture) { + String prefix = "block/tunnel/" + type + "_tunnel"; + String funnel_prefix = "block/funnel/" + type + "_funnel"; return b -> b.initialProperties(SharedProperties::stone) .addLayer(() -> RenderType::cutoutMipped) .properties(BlockBehaviour.Properties::noOcclusion) .transform(pickaxeOnly()) .blockstate((c, p) -> p.getVariantBuilder(c.get()) .forAllStates(state -> { - String id = "block/" + type + "_tunnel"; Shape shape = state.getValue(BeltTunnelBlock.SHAPE); + String window = shape == Shape.WINDOW ? "_window" : ""; if (shape == BeltTunnelBlock.Shape.CLOSED) shape = BeltTunnelBlock.Shape.STRAIGHT; String shapeName = shape.getSerializedName(); return ConfiguredModel.builder() .modelFile(p.models() - .withExistingParent(id + "/" + shapeName, p.modLoc("block/belt_tunnel/" + shapeName)) - .texture("1", p.modLoc(id + "_top")) - .texture("2", p.modLoc(id)) - .texture("3", p.modLoc(id + "_top_window")) + .withExistingParent(prefix + "/" + shapeName, p.modLoc("block/belt_tunnel/" + shapeName)) + .texture("top", p.modLoc(prefix + "_top" + window)) + .texture("tunnel", p.modLoc(prefix)) + .texture("direction", p.modLoc(funnel_prefix + "_neutral")) + .texture("frame", p.modLoc(funnel_prefix + "_frame")) .texture("particle", particleTexture)) .rotationY(state.getValue(BeltTunnelBlock.HORIZONTAL_AXIS) == Axis.X ? 0 : 90) .build(); })) .item(BeltTunnelItem::new) .model((c, p) -> { - String id = type + "_tunnel"; - p.withExistingParent("item/" + id, p.modLoc("block/belt_tunnel/item")) - .texture("1", p.modLoc("block/" + id + "_top")) - .texture("2", p.modLoc("block/" + id)) + p.withExistingParent("item/" + type + "_tunnel", p.modLoc("block/belt_tunnel/item")) + .texture("top", p.modLoc(prefix + "_top")) + .texture("tunnel", p.modLoc(prefix)) + .texture("direction", p.modLoc(funnel_prefix + "_neutral")) + .texture("frame", p.modLoc(funnel_prefix + "_frame")) .texture("particle", particleTexture); }) .build(); @@ -306,12 +372,10 @@ public class BuilderTransformers { } public static NonNullUnaryOperator> bearing(String prefix, - String backTexture, boolean woodenTop) { + String backTexture) { ResourceLocation baseBlockModelLocation = Create.asResource("block/bearing/block"); ResourceLocation baseItemModelLocation = Create.asResource("block/bearing/item"); - ResourceLocation topTextureLocation = Create.asResource("block/bearing_top" + (woodenTop ? "_wooden" : "")); - ResourceLocation nookTextureLocation = - Create.asResource("block/" + (woodenTop ? "andesite" : "brass") + "_casing"); + ResourceLocation topTextureLocation = Create.asResource("block/bearing_top"); ResourceLocation sideTextureLocation = Create.asResource("block/" + prefix + "_bearing_side"); ResourceLocation backTextureLocation = Create.asResource("block/" + backTexture); return b -> b.initialProperties(SharedProperties::stone) @@ -319,7 +383,6 @@ public class BuilderTransformers { .blockstate((c, p) -> p.directionalBlock(c.get(), p.models() .withExistingParent(c.getName(), baseBlockModelLocation) .texture("side", sideTextureLocation) - .texture("nook", nookTextureLocation) .texture("back", backTextureLocation))) .item() .model((c, p) -> p.withExistingParent(c.getName(), baseItemModelLocation) @@ -360,6 +423,26 @@ public class BuilderTransformers { .transform(ModelGen.customItemModel("crate", type, "single")); } + public static NonNullUnaryOperator> backtank(Supplier drop) { + return b -> b.blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) + .transform(pickaxeOnly()) + .addLayer(() -> RenderType::cutoutMipped) + .transform(BlockStressDefaults.setImpact(4.0)) + .loot((lt, block) -> { + Builder builder = LootTable.lootTable(); + LootItemCondition.Builder survivesExplosion = ExplosionCondition.survivesExplosion(); + lt.add(block, builder.withPool(LootPool.lootPool() + .when(survivesExplosion) + .setRolls(ConstantValue.exactly(1)) + .add(LootItem.lootTableItem(drop.get()) + .apply(CopyNameFunction.copyName(CopyNameFunction.NameSource.BLOCK_ENTITY)) + .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY) + .copy("Air", "Air")) + .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY) + .copy("Enchantments", "Enchantments"))))); + }); + } + public static NonNullUnaryOperator> bell() { return b -> b.initialProperties(SharedProperties::softMetal) .properties(p -> p.noOcclusion() @@ -375,6 +458,7 @@ public class BuilderTransformers { })) .item() .model((c, p) -> p.withExistingParent(c.getName(), p.modLoc("block/" + c.getName()))) + .tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) .build(); } diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateBlockEntityBuilder.java b/src/main/java/com/simibubi/create/foundation/data/CreateBlockEntityBuilder.java new file mode 100644 index 0000000000..cdf40b42db --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/CreateBlockEntityBuilder.java @@ -0,0 +1,98 @@ +package com.simibubi.create.foundation.data; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; +import com.tterrag.registrate.AbstractRegistrate; +import com.tterrag.registrate.builders.BlockEntityBuilder; +import com.tterrag.registrate.builders.BuilderCallback; +import com.tterrag.registrate.util.OneTimeEventReceiver; +import com.tterrag.registrate.util.nullness.NonNullSupplier; + +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.util.NonNullPredicate; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; + +public class CreateBlockEntityBuilder extends BlockEntityBuilder { + + @Nullable + private NonNullSupplier>> instanceFactory; + private NonNullPredicate renderNormally; + + private Collection>>> deferredValidBlocks = + new ArrayList<>(); + + public static BlockEntityBuilder create(AbstractRegistrate owner, P parent, + String name, BuilderCallback callback, BlockEntityFactory factory) { + return new CreateBlockEntityBuilder<>(owner, parent, name, callback, factory); + } + + protected CreateBlockEntityBuilder(AbstractRegistrate owner, P parent, String name, BuilderCallback callback, + BlockEntityFactory factory) { + super(owner, parent, name, callback, factory); + } + + public CreateBlockEntityBuilder validBlocksDeferred( + NonNullSupplier>> blocks) { + deferredValidBlocks.add(blocks); + return this; + } + + @Override + protected BlockEntityType createEntry() { + deferredValidBlocks.stream() + .map(Supplier::get) + .flatMap(Collection::stream) + .forEach(this::validBlock); + return super.createEntry(); + } + + public CreateBlockEntityBuilder instance( + NonNullSupplier>> instanceFactory) { + return instance(instanceFactory, true); + } + + public CreateBlockEntityBuilder instance( + NonNullSupplier>> instanceFactory, + boolean renderNormally) { + return instance(instanceFactory, be -> renderNormally); + } + + public CreateBlockEntityBuilder instance( + NonNullSupplier>> instanceFactory, + NonNullPredicate renderNormally) { + if (this.instanceFactory == null) { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerInstance); + } + + this.instanceFactory = instanceFactory; + this.renderNormally = renderNormally; + + return this; + } + + protected void registerInstance() { + OneTimeEventReceiver.addModListener(FMLClientSetupEvent.class, $ -> { + NonNullSupplier>> instanceFactory = + this.instanceFactory; + if (instanceFactory != null) { + NonNullPredicate renderNormally = this.renderNormally; + InstancedRenderRegistry.configure(getEntry()) + .factory(instanceFactory.get()) + .skipRender(be -> !renderNormally.test(be)) + .apply(); + } + }); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java index 3b12125f62..ca2cd1ebe2 100644 --- a/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java +++ b/src/main/java/com/simibubi/create/foundation/data/CreateRegistrate.java @@ -1,23 +1,21 @@ package com.simibubi.create.foundation.data; -import static com.simibubi.create.AllTags.pickaxeOnly; +import static com.simibubi.create.foundation.data.TagGen.pickaxeOnly; -import java.util.Collection; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Map.Entry; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; + +import org.jetbrains.annotations.Nullable; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; -import com.simibubi.create.content.AllSections; -import com.simibubi.create.content.contraptions.fluids.VirtualFluid; -import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; +import com.simibubi.create.content.decoration.encasing.CasingConnectivity; +import com.simibubi.create.content.fluids.VirtualFluid; import com.simibubi.create.foundation.block.connected.CTModel; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; +import com.simibubi.create.foundation.item.TooltipModifier; import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.builders.BlockEntityBuilder.BlockEntityFactory; @@ -45,82 +43,62 @@ import net.minecraft.world.level.block.state.BlockBehaviour.Properties; import net.minecraft.world.level.material.Fluid; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fluids.FluidAttributes; import net.minecraftforge.fluids.ForgeFlowingFluid; import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.IForgeRegistryEntry; import net.minecraftforge.registries.RegistryObject; public class CreateRegistrate extends AbstractRegistrate { + @Nullable + protected Function currentTooltipModifierFactory; protected CreateRegistrate(String modid) { super(modid); } - public static NonNullSupplier lazy(String modid) { - return NonNullSupplier - .lazy(() -> new CreateRegistrate(modid).registerEventListeners(FMLJavaModLoadingContext.get() - .getModEventBus())); + public static CreateRegistrate create(String modid) { + return new CreateRegistrate(modid); } - /* Section Tracking */ - - private static Map, AllSections> sectionLookup = new IdentityHashMap<>(); - private AllSections section; - - public CreateRegistrate startSection(AllSections section) { - this.section = section; - return this; + public CreateRegistrate setTooltipModifierFactory(@Nullable Function factory) { + currentTooltipModifierFactory = factory; + return self(); } - public AllSections currentSection() { - return section; + @Nullable + public Function getTooltipModifierFactory() { + return currentTooltipModifierFactory; } @Override - protected , T extends R> RegistryEntry accept(String name, - ResourceKey> type, Builder builder, NonNullSupplier creator, - NonNullFunction, ? extends RegistryEntry> entryFactory) { - RegistryEntry ret = super.accept(name, type, builder, creator, entryFactory); - sectionLookup.put(ret, currentSection()); - return ret; + public CreateRegistrate registerEventListeners(IEventBus bus) { + return super.registerEventListeners(bus); } - public void addToSection(RegistryEntry entry, AllSections section) { - sectionLookup.put(entry, section); + @Override + protected , T extends R> RegistryEntry accept(String name, ResourceKey> type, Builder builder, NonNullSupplier creator, NonNullFunction, ? extends RegistryEntry> entryFactory) { + RegistryEntry entry = super.accept(name, type, builder, creator, entryFactory); + if (type.equals(Registry.ITEM_REGISTRY)) { + if (currentTooltipModifierFactory != null) { + TooltipModifier.REGISTRY.registerDeferred(entry.getId(), currentTooltipModifierFactory); + } + } + return entry; } - public AllSections getSection(RegistryEntry entry) { - return sectionLookup.getOrDefault(entry, AllSections.UNASSIGNED); - } - - public AllSections getSection(IForgeRegistryEntry entry) { - return sectionLookup.entrySet() - .stream() - .filter(e -> e.getKey().get() == entry) - .map(Entry::getValue) - .findFirst() - .orElse(AllSections.UNASSIGNED); - } - - public > Collection> getAll(AllSections section, - ResourceKey> registryType) { - return this.getAll(registryType) - .stream() - .filter(e -> getSection(e) == section) - .collect(Collectors.toList()); - } - - public CreateTileEntityBuilder tileEntity(String name, + @Override + public CreateBlockEntityBuilder blockEntity(String name, BlockEntityFactory factory) { - return this.tileEntity(this.self(), name, factory); + return blockEntity(self(), name, factory); } - public CreateTileEntityBuilder tileEntity(P parent, String name, + @Override + public CreateBlockEntityBuilder blockEntity(P parent, String name, BlockEntityFactory factory) { - return (CreateTileEntityBuilder) this.entry(name, - (callback) -> CreateTileEntityBuilder.create(this, parent, name, callback, factory)); + return (CreateBlockEntityBuilder) entry(name, + (callback) -> CreateBlockEntityBuilder.create(this, parent, name, callback, factory)); } @Override @@ -140,10 +118,11 @@ public class CreateRegistrate extends AbstractRegistrate { /* Palettes */ public BlockBuilder paletteStoneBlock(String name, - NonNullFunction factory, NonNullSupplier propertiesFrom, boolean worldGenStone) { + NonNullFunction factory, NonNullSupplier propertiesFrom, boolean worldGenStone, + boolean hasNaturalVariants) { BlockBuilder builder = super.block(name, factory).initialProperties(propertiesFrom) .transform(pickaxeOnly()) - .blockstate((c, p) -> { + .blockstate(hasNaturalVariants ? BlockStateGen.naturalStoneTypeBlock(name) : (c, p) -> { final String location = "block/palettes/stone_types/" + c.getName(); p.simpleBlock(c.get(), p.models() .cubeAll(c.getName(), p.modLoc(location))); @@ -153,13 +132,16 @@ public class CreateRegistrate extends AbstractRegistrate { .tag(BlockTags.MOSS_REPLACEABLE) .tag(BlockTags.LUSH_GROUND_REPLACEABLE) .item() + .model((c, p) -> p.cubeAll(c.getName(), + p.modLoc(hasNaturalVariants ? "block/palettes/stone_types/natural/" + name + "_1" + : "block/palettes/stone_types/" + c.getName()))) .build(); return builder; } public BlockBuilder paletteStoneBlock(String name, NonNullSupplier propertiesFrom, - boolean worldGenStone) { - return paletteStoneBlock(name, Block::new, propertiesFrom, worldGenStone); + boolean worldGenStone, boolean hasNaturalVariants) { + return paletteStoneBlock(name, Block::new, propertiesFrom, worldGenStone, hasNaturalVariants); } /* Fluids */ @@ -254,5 +236,4 @@ public class CreateRegistrate extends AbstractRegistrate { CreateClient.MODEL_SWAPPER.getCustomBlockModels() .register(CatnipServices.REGISTRIES.getKeyOrThrow(entry), model -> new CTModel(model, behavior)); } - } diff --git a/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java b/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java deleted file mode 100644 index d336936a85..0000000000 --- a/src/main/java/com/simibubi/create/foundation/data/CreateTileEntityBuilder.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.simibubi.create.foundation.data; - -import java.util.function.BiFunction; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; -import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; -import com.tterrag.registrate.AbstractRegistrate; -import com.tterrag.registrate.builders.BlockEntityBuilder; -import com.tterrag.registrate.builders.BuilderCallback; -import com.tterrag.registrate.util.OneTimeEventReceiver; -import com.tterrag.registrate.util.nullness.NonNullSupplier; - -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.util.NonNullPredicate; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; - -public class CreateTileEntityBuilder extends BlockEntityBuilder { - - @Nullable - private NonNullSupplier>> instanceFactory; - private NonNullPredicate renderNormally; - - public static BlockEntityBuilder create(AbstractRegistrate owner, P parent, - String name, BuilderCallback callback, BlockEntityFactory factory) { - return new CreateTileEntityBuilder<>(owner, parent, name, callback, factory); - } - - protected CreateTileEntityBuilder(AbstractRegistrate owner, P parent, String name, BuilderCallback callback, - BlockEntityFactory factory) { - super(owner, parent, name, callback, factory); - } - - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory) { - return instance(instanceFactory, true); - } - - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory, boolean renderNormally) { - return instance(instanceFactory, be -> renderNormally); - } - - public CreateTileEntityBuilder instance(NonNullSupplier>> instanceFactory, NonNullPredicate renderNormally) { - if (this.instanceFactory == null) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerInstance); - } - - this.instanceFactory = instanceFactory; - this.renderNormally = renderNormally; - - return this; - } - - protected void registerInstance() { - OneTimeEventReceiver.addModListener(FMLClientSetupEvent.class, $ -> { - NonNullSupplier>> instanceFactory = this.instanceFactory; - if (instanceFactory != null) { - NonNullPredicate renderNormally = this.renderNormally; - InstancedRenderRegistry.configure(getEntry()) - .factory(instanceFactory.get()) - .skipRender(be -> !renderNormally.test(be)) - .apply(); - } - }); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/data/DirectionalAxisBlockStateGen.java b/src/main/java/com/simibubi/create/foundation/data/DirectionalAxisBlockStateGen.java index 0905608cc2..3103cf4d5f 100644 --- a/src/main/java/com/simibubi/create/foundation/data/DirectionalAxisBlockStateGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/DirectionalAxisBlockStateGen.java @@ -1,6 +1,6 @@ package com.simibubi.create.foundation.data; -import com.simibubi.create.content.contraptions.relays.gauge.GaugeBlock; +import com.simibubi.create.content.kinetics.gauge.GaugeBlock; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; diff --git a/src/main/java/com/simibubi/create/foundation/data/LangMerger.java b/src/main/java/com/simibubi/create/foundation/data/LangMerger.java index b6c759e0bc..ac750539ea 100644 --- a/src/main/java/com/simibubi/create/foundation/data/LangMerger.java +++ b/src/main/java/com/simibubi/create/foundation/data/LangMerger.java @@ -3,27 +3,18 @@ package com.simibubi.create.foundation.data; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; -import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.commons.lang3.tuple.Pair; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.simibubi.create.Create; -import com.simibubi.create.foundation.utility.FilesHelper; import net.createmod.ponder.foundation.PonderScene; import net.minecraft.data.DataGenerator; @@ -33,31 +24,30 @@ import net.minecraft.util.GsonHelper; public class LangMerger implements DataProvider { - private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting() + private static final Gson GSON = new GsonBuilder().setPrettyPrinting() .disableHtmlEscaping() .create(); - static final String CATEGORY_HEADER = "\t\"_\": \"->------------------------] %s [------------------------<-\","; + private static final String CATEGORY_HEADER = "\t\"_\": \"->------------------------] %s [------------------------<-\","; private DataGenerator gen; + private final String modid; + private final String displayName; + private final LangPartial[] langPartials; private List mergedLangData; - private Map> populatedLangData; - private Map> allLocalizedEntries; - private Map missingTranslationTally; - private List langIgnore; - public LangMerger(DataGenerator gen) { + public LangMerger(DataGenerator gen, String modid, String displayName, T[] langPartials) { this.gen = gen; + this.modid = modid; + this.displayName = displayName; + this.langPartials = langPartials; this.mergedLangData = new ArrayList<>(); this.langIgnore = new ArrayList<>(); - this.allLocalizedEntries = new HashMap<>(); - this.populatedLangData = new HashMap<>(); - this.missingTranslationTally = new HashMap<>(); populateLangIgnore(); } - private void populateLangIgnore() { + protected void populateLangIgnore() { // Key prefixes added here will NOT be transferred to lang templates langIgnore.add("create.ponder.debug_"); // Ponder debug scene text langIgnore.add("create.gui.chromatic_projector"); @@ -72,50 +62,19 @@ public class LangMerger implements DataProvider { @Override public String getName() { - return "Lang merger"; + return displayName + "'s lang merger"; } @Override public void run(HashCache cache) throws IOException { Path path = this.gen.getOutputFolder() - .resolve("assets/" + Create.ID + "/lang/" + "en_us.json"); - - for (Pair pair : getAllLocalizationFiles()) { - if (!pair.getRight() - .isJsonObject()) - continue; - Map localizedEntries = new HashMap<>(); - JsonObject jsonobject = pair.getRight() - .getAsJsonObject(); - jsonobject.entrySet() - .stream() - .forEachOrdered(entry -> { - String key = entry.getKey(); - if (key.startsWith("_")) - return; - String value = entry.getValue() - .getAsString(); - localizedEntries.put(key, value); - }); - String key = pair.getKey(); - allLocalizedEntries.put(key, localizedEntries); - populatedLangData.put(key, new ArrayList<>()); - missingTranslationTally.put(key, new MutableInt(0)); - } + .resolve("assets/" + modid + "/lang/" + "en_us.json"); collectExistingEntries(path); collectEntries(); if (mergedLangData.isEmpty()) return; - - save(cache, mergedLangData, -1, path, "Merging en_us.json with hand-written lang entries..."); - for (Entry> localization : populatedLangData.entrySet()) { - String key = localization.getKey(); - Path populatedLangPath = this.gen.getOutputFolder() - .resolve("assets/" + Create.ID + "/lang/unfinished/" + key); - save(cache, localization.getValue(), missingTranslationTally.get(key) - .intValue(), populatedLangPath, "Populating " + key + " with missing entries..."); - } + save(cache, mergedLangData, path, "Merging en_us.json with hand-written lang entries..."); } private void collectExistingEntries(Path path) throws IOException { @@ -161,26 +120,17 @@ public class LangMerger implements DataProvider { private void writeData(String data) { mergedLangData.add(data); - populatedLangData.values() - .forEach(l -> l.add(data)); } private void writeEntry(String key, String value) { mergedLangData.add(new LangEntry(key, value)); - populatedLangData.forEach((k, l) -> { - ForeignLangEntry entry = new ForeignLangEntry(key, value, allLocalizedEntries.get(k)); - if (entry.isMissing()) - missingTranslationTally.get(k) - .increment(); - l.add(entry); - }); } protected boolean shouldAddLineBreak(String key, String previousKey) { // Always put tooltips and ponder scenes in their own paragraphs if (key.endsWith(".tooltip")) return true; - if (key.startsWith("create.ponder") && key.endsWith(PonderScene.TITLE_KEY)) + if (key.startsWith(modid + ".ponder") && key.endsWith(PonderScene.TITLE_KEY)) return true; key = key.replaceFirst("\\.", ""); @@ -195,40 +145,15 @@ public class LangMerger implements DataProvider { return !split[0].equals(split2[0]); } - private List> getAllLocalizationFiles() { - ArrayList> list = new ArrayList<>(); - - String filepath = "assets/" + Create.ID + "/lang/"; - try (InputStream resourceStream = ClassLoader.getSystemResourceAsStream(filepath)) { - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resourceStream)); - while (true) { - String readLine = bufferedReader.readLine(); - if (readLine == null) - break; - if (!readLine.endsWith(".json")) - continue; - if (readLine.startsWith("en_us") || readLine.startsWith("en_ud")) - continue; - list.add(Pair.of(readLine, FilesHelper.loadJsonResource(filepath + readLine))); - } - } catch (IOException | NullPointerException e) { - e.printStackTrace(); - } - - return list; - } - private void collectEntries() { - for (AllLangPartials partial : AllLangPartials.values()) - addAll(partial.getDisplay(), partial.provide() + for (LangPartial partial : langPartials) + addAll(partial.getDisplayName(), partial.provide() .getAsJsonObject()); } - private void save(HashCache cache, List dataIn, int missingKeys, Path target, String message) + private void save(HashCache cache, List dataIn, Path target, String message) throws IOException { - String data = createString(dataIn, missingKeys); -// data = JavaUnicodeEscaper.outsideOf(0, 0x7f) -// .translate(data); + String data = createString(dataIn); String hash = DataProvider.SHA1.hashUnencodedChars(data) .toString(); if (!Objects.equals(cache.getHash(target), hash) || !Files.exists(target)) { @@ -237,20 +162,17 @@ public class LangMerger implements DataProvider { try (BufferedWriter bufferedwriter = Files.newBufferedWriter(target)) { Create.LOGGER.info(message); bufferedwriter.write(data); - bufferedwriter.close(); } } cache.putNew(target, hash); } - protected String createString(List data, int missingKeys) { + protected String createString(List data) { StringBuilder builder = new StringBuilder(); builder.append("{\n"); - if (missingKeys != -1) - builder.append("\t\"_\": \"Missing Localizations: " + missingKeys + "\",\n"); data.forEach(builder::append); - builder.append("\t\"_\": \"Thank you for translating Create!\"\n\n"); + builder.append("\t\"_\": \"Thank you for translating ").append(displayName).append("!\"\n\n"); builder.append("}"); return builder.toString(); } @@ -273,19 +195,4 @@ public class LangMerger implements DataProvider { } - private class ForeignLangEntry extends LangEntry { - - private boolean missing; - - ForeignLangEntry(String key, String value, Map localizationMap) { - super(key, localizationMap.getOrDefault(key, "UNLOCALIZED: " + value)); - missing = !localizationMap.containsKey(key); - } - - public boolean isMissing() { - return missing; - } - - } - } diff --git a/src/main/java/com/simibubi/create/foundation/data/LangPartial.java b/src/main/java/com/simibubi/create/foundation/data/LangPartial.java new file mode 100644 index 0000000000..a818075887 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/LangPartial.java @@ -0,0 +1,18 @@ +package com.simibubi.create.foundation.data; + +import com.google.gson.JsonElement; +import com.simibubi.create.foundation.utility.FilesHelper; + +public interface LangPartial { + String getDisplayName(); + + JsonElement provide(); + + static JsonElement fromResource(String namespace, String fileName) { + String path = "assets/" + namespace + "/lang/default/" + fileName + ".json"; + JsonElement element = FilesHelper.loadJsonResource(path); + if (element == null) + throw new IllegalStateException(String.format("Could not find default lang file: %s", path)); + return element; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/data/MetalBarsGen.java b/src/main/java/com/simibubi/create/foundation/data/MetalBarsGen.java new file mode 100644 index 0000000000..e5889287c9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/MetalBarsGen.java @@ -0,0 +1,147 @@ +package com.simibubi.create.foundation.data; + +import static com.simibubi.create.Create.REGISTRATE; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.EAST; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.NORTH; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.SOUTH; +import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WEST; + +import java.util.function.Supplier; + +import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.Create; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateBlockstateProvider; +import com.tterrag.registrate.util.DataIngredient; +import com.tterrag.registrate.util.entry.BlockEntry; +import com.tterrag.registrate.util.nullness.NonNullBiConsumer; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.material.MaterialColor; +import net.minecraftforge.client.model.generators.ModelFile; + +public class MetalBarsGen { + + public static

NonNullBiConsumer, RegistrateBlockstateProvider> barsBlockState( + String name, boolean specialEdge) { + return (c, p) -> { + + ModelFile post_ends = barsSubModel(p, name, "post_ends", specialEdge); + ModelFile post = barsSubModel(p, name, "post", specialEdge); + ModelFile cap = barsSubModel(p, name, "cap", specialEdge); + ModelFile cap_alt = barsSubModel(p, name, "cap_alt", specialEdge); + ModelFile side = barsSubModel(p, name, "side", specialEdge); + ModelFile side_alt = barsSubModel(p, name, "side_alt", specialEdge); + + p.getMultipartBuilder(c.get()) + .part() + .modelFile(post_ends) + .addModel() + .end() + .part() + .modelFile(post) + .addModel() + .condition(NORTH, false) + .condition(EAST, false) + .condition(SOUTH, false) + .condition(WEST, false) + .end() + .part() + .modelFile(cap) + .addModel() + .condition(NORTH, true) + .condition(EAST, false) + .condition(SOUTH, false) + .condition(WEST, false) + .end() + .part() + .modelFile(cap) + .rotationY(90) + .addModel() + .condition(NORTH, false) + .condition(EAST, true) + .condition(SOUTH, false) + .condition(WEST, false) + .end() + .part() + .modelFile(cap_alt) + .addModel() + .condition(NORTH, false) + .condition(EAST, false) + .condition(SOUTH, true) + .condition(WEST, false) + .end() + .part() + .modelFile(cap_alt) + .rotationY(90) + .addModel() + .condition(NORTH, false) + .condition(EAST, false) + .condition(SOUTH, false) + .condition(WEST, true) + .end() + .part() + .modelFile(side) + .addModel() + .condition(NORTH, true) + .end() + .part() + .modelFile(side) + .rotationY(90) + .addModel() + .condition(EAST, true) + .end() + .part() + .modelFile(side_alt) + .addModel() + .condition(SOUTH, true) + .end() + .part() + .modelFile(side_alt) + .rotationY(90) + .addModel() + .condition(WEST, true) + .end(); + }; + } + + private static ModelFile barsSubModel(RegistrateBlockstateProvider p, String name, String suffix, + boolean specialEdge) { + ResourceLocation barsTexture = p.modLoc("block/bars/" + name + "_bars"); + ResourceLocation edgeTexture = specialEdge ? p.modLoc("block/bars/" + name + "_bars_edge") : barsTexture; + return p.models() + .withExistingParent(name + "_" + suffix, p.modLoc("block/bars/" + suffix)) + .texture("bars", barsTexture) + .texture("particle", barsTexture) + .texture("edge", edgeTexture); + } + + public static BlockEntry createBars(String name, boolean specialEdge, + Supplier ingredient, MaterialColor color) { + return REGISTRATE.block(name + "_bars", IronBarsBlock::new) + .addLayer(() -> RenderType::cutoutMipped) + .initialProperties(() -> Blocks.IRON_BARS) + .properties(p -> p.sound(SoundType.COPPER) + .color(color)) + .tag(AllBlockTags.WRENCH_PICKUP.tag) + .tag(AllBlockTags.FAN_TRANSPARENT.tag) + .transform(TagGen.pickaxeOnly()) + .blockstate(barsBlockState(name, specialEdge)) + .item() + .model((c, p) -> { + ResourceLocation barsTexture = p.modLoc("block/bars/" + name + "_bars"); + p.withExistingParent(c.getName(), Create.asResource("item/bars")) + .texture("bars", barsTexture) + .texture("edge", specialEdge ? p.modLoc("block/bars/" + name + "_bars_edge") : barsTexture); + }) + .recipe((c, p) -> p.stonecutting(ingredient.get(), c::get, 4)) + .build() + .register(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/data/SharedProperties.java b/src/main/java/com/simibubi/create/foundation/data/SharedProperties.java index f1838c4704..256aafed44 100644 --- a/src/main/java/com/simibubi/create/foundation/data/SharedProperties.java +++ b/src/main/java/com/simibubi/create/foundation/data/SharedProperties.java @@ -15,6 +15,10 @@ public class SharedProperties { public static final Material CRUSHING_WHEEL_CONTROLLER_MATERIAL = new Material(MaterialColor.NONE, false, false, true, true, false, false, PushReaction.BLOCK); + public static Block wooden() { + return Blocks.STRIPPED_SPRUCE_WOOD; + } + public static Block stone() { return Blocks.ANDESITE; } @@ -22,12 +26,12 @@ public class SharedProperties { public static Block softMetal() { return Blocks.GOLD_BLOCK; } - + public static Block copperMetal() { return Blocks.COPPER_BLOCK; } - public static Block wooden() { - return Blocks.STRIPPED_SPRUCE_WOOD; + public static Block netheriteMetal() { + return Blocks.NETHERITE_BLOCK; } } diff --git a/src/main/java/com/simibubi/create/foundation/data/TagGen.java b/src/main/java/com/simibubi/create/foundation/data/TagGen.java new file mode 100644 index 0000000000..0fe706f4e7 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/data/TagGen.java @@ -0,0 +1,262 @@ +package com.simibubi.create.foundation.data; + +import com.simibubi.create.AllTags; +import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.AllTags.AllEntityTags; +import com.simibubi.create.AllTags.AllFluidTags; +import com.simibubi.create.AllTags.AllItemTags; +import com.simibubi.create.Create; +import com.simibubi.create.foundation.data.recipe.Mods; +import com.tterrag.registrate.builders.BlockBuilder; +import com.tterrag.registrate.builders.ItemBuilder; +import com.tterrag.registrate.providers.ProviderType; +import com.tterrag.registrate.providers.RegistrateTagsProvider; +import com.tterrag.registrate.util.nullness.NonNullFunction; + +import net.minecraft.data.tags.TagsProvider.TagAppender; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.common.Tags; + +public class TagGen { + public static NonNullFunction, BlockBuilder> axeOrPickaxe() { + return b -> b.tag(BlockTags.MINEABLE_WITH_AXE) + .tag(BlockTags.MINEABLE_WITH_PICKAXE); + } + + public static NonNullFunction, BlockBuilder> axeOnly() { + return b -> b.tag(BlockTags.MINEABLE_WITH_AXE); + } + + public static NonNullFunction, BlockBuilder> pickaxeOnly() { + return b -> b.tag(BlockTags.MINEABLE_WITH_PICKAXE); + } + + public static NonNullFunction, ItemBuilder>> tagBlockAndItem( + String... path) { + return b -> { + for (String p : path) + b.tag(AllTags.forgeBlockTag(p)); + ItemBuilder> item = b.item(); + for (String p : path) + item.tag(AllTags.forgeItemTag(p)); + return item; + }; + } + + public static > T addOptional(T appender, Mods mod, String id) { + appender.addOptional(mod.asResource(id)); + return appender; + } + + public static > T addOptional(T appender, Mods mod, String... ids) { + for (String id : ids) { + appender.addOptional(mod.asResource(id)); + } + return appender; + } + + public static void datagen() { + Create.REGISTRATE.addDataGenerator(ProviderType.BLOCK_TAGS, TagGen::genBlockTags); + Create.REGISTRATE.addDataGenerator(ProviderType.ITEM_TAGS, TagGen::genItemTags); + Create.REGISTRATE.addDataGenerator(ProviderType.FLUID_TAGS, TagGen::genFluidTags); + Create.REGISTRATE.addDataGenerator(ProviderType.ENTITY_TAGS, TagGen::genEntityTags); + } + + private static void genBlockTags(RegistrateTagsProvider prov) { + prov.tag(AllBlockTags.BRITTLE.tag) + .add(Blocks.BELL, Blocks.COCOA, Blocks.FLOWER_POT) + .addTag(BlockTags.BEDS) + .addTag(BlockTags.DOORS); + + prov.tag(AllBlockTags.MOVABLE_EMPTY_COLLIDER.tag) + .add(Blocks.COBWEB, Blocks.POWDER_SNOW, Blocks.TRIPWIRE, Blocks.TRIPWIRE_HOOK) + .addTag(BlockTags.FENCE_GATES); + + prov.tag(AllBlockTags.FAN_TRANSPARENT.tag) + .add(Blocks.IRON_BARS) + .addTag(BlockTags.CAMPFIRES) + .addTag(BlockTags.FENCES) + .addTag(BlockTags.LEAVES); + + prov.tag(AllBlockTags.ORE_OVERRIDE_STONE.tag) + .addTag(BlockTags.STONE_ORE_REPLACEABLES); + + prov.tag(AllBlockTags.PASSIVE_BOILER_HEATERS.tag) + .add(Blocks.MAGMA_BLOCK, Blocks.LAVA) + .addTag(BlockTags.CAMPFIRES) + .addTag(BlockTags.FIRE); + + prov.tag(AllBlockTags.SAFE_NBT.tag) + .addTag(BlockTags.BANNERS) + .addTag(BlockTags.SIGNS); + + prov.tag(AllBlockTags.TREE_ATTACHMENTS.tag) + .add(Blocks.BEE_NEST, Blocks.COCOA, Blocks.MOSS_CARPET, Blocks.SHROOMLIGHT, Blocks.VINE); + + prov.tag(AllBlockTags.WINDMILL_SAILS.tag) + .addTag(BlockTags.WOOL); + + prov.tag(AllBlockTags.WRENCH_PICKUP.tag) + .add(Blocks.REDSTONE_WIRE, Blocks.REDSTONE_TORCH, Blocks.REPEATER, Blocks.LEVER, + Blocks.COMPARATOR, Blocks.OBSERVER, Blocks.REDSTONE_WALL_TORCH, Blocks.PISTON, Blocks.STICKY_PISTON, + Blocks.TRIPWIRE, Blocks.TRIPWIRE_HOOK, Blocks.DAYLIGHT_DETECTOR, Blocks.TARGET, Blocks.HOPPER) + .addTag(BlockTags.BUTTONS) + .addTag(BlockTags.PRESSURE_PLATES) + .addTag(BlockTags.RAILS); + + prov.tag(AllBlockTags.COPYCAT_ALLOW.tag) + .add(Blocks.BARREL); + prov.tag(AllBlockTags.COPYCAT_DENY.tag) + .addTag(BlockTags.CAULDRONS) + .addTag(BlockTags.SAPLINGS) + .addTag(BlockTags.CLIMBABLE); + + // COMPAT + + addOptional(prov.tag(AllBlockTags.NON_MOVABLE.tag), Mods.IE, + "connector_lv", "connector_lv_relay", "connector_mv", "connector_mv_relay", + "connector_hv", "connector_hv_relay", "connector_bundled", "connector_structural", + "connector_redstone", "connector_probe", "breaker_switch"); + + // VALIDATE + + for (AllBlockTags tag : AllBlockTags.values()) { + if (tag.alwaysDatagen) { + prov.getOrCreateRawBuilder(tag.tag); + } + } + } + + private static void genItemTags(RegistrateTagsProvider prov) { + prov.tag(AllItemTags.SLEEPERS.tag) + .add(Items.STONE_SLAB, Items.SMOOTH_STONE_SLAB, Items.ANDESITE_SLAB); + + prov.tag(AllItemTags.STRIPPED_LOGS.tag) + .addTag(AllItemTags.VANILLA_STRIPPED_LOGS.tag) + .addTag(AllItemTags.MODDED_STRIPPED_LOGS.tag); + + prov.tag(AllItemTags.STRIPPED_WOOD.tag) + .addTag(AllItemTags.VANILLA_STRIPPED_WOOD.tag) + .addTag(AllItemTags.MODDED_STRIPPED_WOOD.tag); + + prov.tag(AllItemTags.DEPLOYABLE_DRINK.tag) + .add(Items.MILK_BUCKET, Items.POTION); + + prov.tag(AllItemTags.UPRIGHT_ON_BELT.tag) + .add(Items.GLASS_BOTTLE, Items.POTION, Items.SPLASH_POTION, Items.LINGERING_POTION, + Items.HONEY_BOTTLE, Items.CAKE); + + prov.tag(AllItemTags.CONTRAPTION_CONTROLLED.tag) + .add(Items.BELL, Items.CAMPFIRE, Items.SOUL_CAMPFIRE, Items.DISPENSER, Items.DROPPER); + + prov.tag(AllItemTags.VANILLA_STRIPPED_LOGS.tag) + .add(Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_BIRCH_LOG, Items.STRIPPED_CRIMSON_STEM, + Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_OAK_LOG, + Items.STRIPPED_SPRUCE_LOG, Items.STRIPPED_WARPED_STEM); + + prov.tag(AllItemTags.VANILLA_STRIPPED_WOOD.tag) + .add(Items.STRIPPED_ACACIA_WOOD, Items.STRIPPED_BIRCH_WOOD, + Items.STRIPPED_CRIMSON_HYPHAE, Items.STRIPPED_DARK_OAK_WOOD, Items.STRIPPED_JUNGLE_WOOD, + Items.STRIPPED_OAK_WOOD, Items.STRIPPED_SPRUCE_WOOD, Items.STRIPPED_WARPED_HYPHAE); + + prov.tag(ItemTags.BEACON_PAYMENT_ITEMS) + .addTag(AllItemTags.CREATE_INGOTS.tag); + + prov.tag(Tags.Items.INGOTS) + .addTag(AllItemTags.CREATE_INGOTS.tag); + + // COMPAT + + genStrippedWood(prov); + + // VALIDATE + + for (AllItemTags tag : AllItemTags.values()) { + if (tag.alwaysDatagen) { + prov.getOrCreateRawBuilder(tag.tag); + } + } + } + + private static void genStrippedWood(RegistrateTagsProvider prov) { + TagAppender logAppender = prov.tag(AllItemTags.MODDED_STRIPPED_LOGS.tag); + TagAppender woodAppender = prov.tag(AllItemTags.MODDED_STRIPPED_WOOD.tag); + StrippedWoodHelper helper = new StrippedWoodHelper(logAppender, woodAppender); + + helper.add(Mods.ARS_N, "blue_archwood", "purple_archwood", "green_archwood", "red_archwood"); + helper.add(Mods.BTN, "livingwood", "dreamwood"); + helper.add(Mods.FA, "cherrywood", "mysterywood"); + helper.add(Mods.HEX, "akashic"); + helper.add(Mods.ID, "menril"); + helper.add(Mods.BYG, "aspen", "baobab", "enchanted", "cherry", "cika", "cypress", "ebony", "ether", + "fir", "green_enchanted", "holly", "jacaranda", "lament", "mahogany", "mangrove", "maple", "nightshade", + "palm", "palo_verde", "pine", "rainbow_eucalyptus", "redwood", "skyris", "willow", "witch_hazel", + "zelkova"); + helper.add(Mods.SG, "netherwood"); + helper.add(Mods.TF, "twilight_oak", "canopy", "mangrove", "dark", "time", "transformation", "mining", + "sorting"); + helper.add(Mods.TIC, "greenheart", "skyroot", "bloodshroom"); + helper.add(Mods.AP, "twisted"); + helper.add(Mods.Q, "azalea", "blossom"); + helper.add(Mods.ECO, "coconut", "walnut", "azalea"); + helper.add(Mods.BOP, "fir", "redwood", "cherry", "mahogany", "jacaranda", "palm", "willow", "dead", + "magic", "umbran", "hellbark"); + helper.add(Mods.BSK, "bluebright", "starlit", "frostbright", "lunar", "dusk", "maple", "cherry"); + + addOptional(logAppender, Mods.BYG, "stripped_bulbis_stem"); + addOptional(woodAppender, Mods.BYG, "stripped_bulbis_wood"); + } + + private static void genFluidTags(RegistrateTagsProvider prov) { + prov.tag(AllFluidTags.BOTTOMLESS_ALLOW.tag) + .add(Fluids.WATER, Fluids.LAVA); + + // VALIDATE + + for (AllFluidTags tag : AllFluidTags.values()) { + if (tag.alwaysDatagen) { + prov.getOrCreateRawBuilder(tag.tag); + } + } + } + + private static void genEntityTags(RegistrateTagsProvider> prov) { + + // VALIDATE + + for (AllEntityTags tag : AllEntityTags.values()) { + if (tag.alwaysDatagen) { + prov.getOrCreateRawBuilder(tag.tag); + } + } + } + + private static class StrippedWoodHelper { + protected final TagAppender logAppender; + protected final TagAppender woodAppender; + + public StrippedWoodHelper(TagAppender logAppender, TagAppender woodAppender) { + this.logAppender = logAppender; + this.woodAppender = woodAppender; + } + + public void add(Mods mod, String... woodTypes) { + for (String type : woodTypes) { + String strippedPre = mod.strippedIsSuffix ? "" : "stripped_"; + String strippedPost = mod.strippedIsSuffix ? "_stripped" : ""; + addOptional(logAppender, mod, strippedPre + type + "_log" + strippedPost); + addOptional(woodAppender, mod, strippedPre + type + (mod.omitWoodSuffix ? "" : "_wood") + strippedPost); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/data/WindowGen.java b/src/main/java/com/simibubi/create/foundation/data/WindowGen.java index 312ac90646..799fd85fcb 100644 --- a/src/main/java/com/simibubi/create/foundation/data/WindowGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/WindowGen.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.data; +import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; import java.util.function.Function; @@ -7,10 +8,10 @@ import java.util.function.Supplier; import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.Create; -import com.simibubi.create.content.palettes.ConnectedGlassBlock; -import com.simibubi.create.content.palettes.ConnectedGlassPaneBlock; -import com.simibubi.create.content.palettes.GlassPaneBlock; -import com.simibubi.create.content.palettes.WindowBlock; +import com.simibubi.create.content.decoration.palettes.ConnectedGlassBlock; +import com.simibubi.create.content.decoration.palettes.ConnectedGlassPaneBlock; +import com.simibubi.create.content.decoration.palettes.GlassPaneBlock; +import com.simibubi.create.content.decoration.palettes.WindowBlock; import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour; import com.simibubi.create.foundation.block.connected.GlassPaneCTBehaviour; @@ -43,8 +44,6 @@ import net.minecraftforge.common.Tags; public class WindowGen { - private static final CreateRegistrate REGISTRATE = Create.registrate(); - private static Properties glassProperties(Properties p) { return p.isValidSpawn(WindowGen::never) .isRedstoneConductor(WindowGen::never) diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/CreateRecipeProvider.java b/src/main/java/com/simibubi/create/foundation/data/recipe/CreateRecipeProvider.java index 4c9b734ef4..9f5342ffad 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/CreateRecipeProvider.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/CreateRecipeProvider.java @@ -16,6 +16,7 @@ import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; import net.minecraftforge.common.Tags; @@ -184,5 +185,9 @@ public abstract class CreateRecipeProvider extends RecipeProvider { return AllItems.SHADOW_STEEL.get(); } + static Ingredient netherite() { + return Ingredient.of(AllTags.forgeItemTag("ingots/netherite")); + } + } } diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/CrushingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/CrushingRecipeGen.java index 634003601d..f09f3ba051 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/CrushingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/CrushingRecipeGen.java @@ -17,9 +17,9 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.content.palettes.AllPaletteStoneTypes; +import com.simibubi.create.content.decoration.palettes.AllPaletteStoneTypes; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; import net.createmod.catnip.utility.lang.Lang; import net.minecraft.data.DataGenerator; @@ -225,7 +225,7 @@ public class CrushingRecipeGen extends ProcessingRecipeGen { float extra = expectedAmount - Mth.floor(expectedAmount); if (extra > 0) builder.output(extra, raw.get(), 1); - builder.output(.75f, AllItems.EXP_NUGGET.get(), 1); + builder.output(.75f, AllItems.EXP_NUGGET.get(), raw.get() == AllItems.CRUSHED_GOLD.get() ? 2 : 1); return builder.output(.125f, stoneType); }); } @@ -233,7 +233,7 @@ public class CrushingRecipeGen extends ProcessingRecipeGen { protected GeneratedRecipe rawOre(Supplier input, Supplier result, int amount) { return create(input, b -> b.duration(400) .output(result.get(), amount) - .output(.75f, AllItems.EXP_NUGGET.get(), amount)); + .output(.75f, AllItems.EXP_NUGGET.get(), (result.get() == AllItems.CRUSHED_GOLD.get() ? 2 : 1) * amount)); } protected GeneratedRecipe moddedRawOre(CompatMetals metal, Supplier result, int amount) { diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java index 3cdbdc8310..dbcd606b00 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/FillingRecipeGen.java @@ -4,7 +4,7 @@ import com.simibubi.create.AllFluids; import com.simibubi.create.AllItems; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags.AllFluidTags; -import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler; +import com.simibubi.create.content.fluids.potion.PotionFluidHandler; import net.minecraft.data.DataGenerator; import net.minecraft.world.item.Items; diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/LogStrippingFakeRecipes.java b/src/main/java/com/simibubi/create/foundation/data/recipe/LogStrippingFakeRecipes.java index 94647e2a88..f63b74167e 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/LogStrippingFakeRecipes.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/LogStrippingFakeRecipes.java @@ -3,10 +3,10 @@ package com.simibubi.create.foundation.data.recipe; import java.util.ArrayList; import java.util.List; -import com.simibubi.create.content.contraptions.components.deployer.ManualApplicationRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.content.kinetics.deployer.ManualApplicationRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.resources.ResourceLocation; @@ -29,7 +29,7 @@ public class LogStrippingFakeRecipes { public static List createRecipes() { List recipes = new ArrayList<>(); - if (!AllConfigs.SERVER.recipes.displayLogStrippingRecipes.get()) + if (!AllConfigs.server().recipes.displayLogStrippingRecipes.get()) return recipes; ItemStack axe = new ItemStack(Items.IRON_AXE); diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java index e38f21d165..4119fe74cc 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/MixingRecipeGen.java @@ -3,7 +3,7 @@ package com.simibubi.create.foundation.data.recipe; import com.simibubi.create.AllFluids; import com.simibubi.create.AllItems; import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.content.contraptions.processing.HeatCondition; +import com.simibubi.create.content.processing.recipe.HeatCondition; import net.minecraft.data.DataGenerator; import net.minecraft.tags.ItemTags; diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java index f0ef40c056..a1aaeaddcc 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java @@ -7,10 +7,10 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; -import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; -import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo; +import com.simibubi.create.content.processing.recipe.ProcessingRecipe; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeBuilder; +import com.simibubi.create.content.processing.recipe.ProcessingRecipeSerializer; +import com.simibubi.create.foundation.recipe.IRecipeTypeInfo; import net.createmod.catnip.platform.CatnipServices; import net.minecraft.data.DataGenerator; @@ -74,11 +74,11 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider { Supplier singleIngredient, UnaryOperator> transform) { ProcessingRecipeSerializer serializer = getSerializer(); GeneratedRecipe generatedRecipe = c -> { - ItemLike iItemProvider = singleIngredient.get(); + ItemLike itemLike = singleIngredient.get(); transform .apply(new ProcessingRecipeBuilder<>(serializer.getFactory(), - new ResourceLocation(namespace, CatnipServices.REGISTRIES.getKeyOrThrow(iItemProvider.asItem()) - .getPath())).withItemIngredients(Ingredient.of(iItemProvider))) + new ResourceLocation(namespace, CatnipServices.REGISTRIES.getKeyOrThrow(itemLike.asItem()) + .getPath())).withItemIngredients(Ingredient.of(itemLike))) .build(c); }; all.add(generatedRecipe); diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/SequencedAssemblyRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/SequencedAssemblyRecipeGen.java index 8a26855b5a..fdfbae03db 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/SequencedAssemblyRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/SequencedAssemblyRecipeGen.java @@ -7,10 +7,10 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.deployer.DeployerApplicationRecipe; -import com.simibubi.create.content.contraptions.components.press.PressingRecipe; -import com.simibubi.create.content.contraptions.fluids.actors.FillingRecipe; -import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipeBuilder; +import com.simibubi.create.content.fluids.transfer.FillingRecipe; +import com.simibubi.create.content.kinetics.deployer.DeployerApplicationRecipe; +import com.simibubi.create.content.kinetics.press.PressingRecipe; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipeBuilder; import net.minecraft.data.DataGenerator; import net.minecraft.world.item.Items; diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java index 4aec0950d2..4d42cf9755 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java @@ -24,15 +24,13 @@ import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllTags; import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.Create; -import com.simibubi.create.content.AllSections; -import com.simibubi.create.content.palettes.AllPaletteBlocks; -import com.simibubi.create.content.palettes.AllPaletteStoneTypes; +import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks; +import com.simibubi.create.content.decoration.palettes.AllPaletteStoneTypes; import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.entry.ItemEntry; import com.tterrag.registrate.util.entry.ItemProviderEntry; import net.createmod.catnip.platform.CatnipServices; -import net.createmod.catnip.utility.lang.Lang; import net.minecraft.advancements.critereon.ItemPredicate; import net.minecraft.data.DataGenerator; import net.minecraft.data.recipes.FinishedRecipe; @@ -40,6 +38,7 @@ import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; import net.minecraft.data.recipes.SimpleCookingRecipeBuilder; import net.minecraft.data.recipes.SpecialRecipeBuilder; +import net.minecraft.data.recipes.UpgradeRecipeBuilder; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; @@ -68,7 +67,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { * (Ctrl-o) in Eclipse */ - private Marker MATERIALS = enterSection(AllSections.MATERIALS); + private Marker MATERIALS = enterFolder("materials"); GeneratedRecipe @@ -92,6 +91,28 @@ public class StandardRecipeGen extends CreateRecipeProvider { .pattern("CCC") .pattern("CCC")), + ANDESITE_ALLOY_FROM_BLOCK = create(AllItems.ANDESITE_ALLOY).withSuffix("_from_block") + .returns(9) + .unlockedBy(I::andesite) + .viaShapeless(b -> b.requires(AllBlocks.ANDESITE_ALLOY_BLOCK.get())), + + ANDESITE_ALLOY_BLOCK = create(AllBlocks.ANDESITE_ALLOY_BLOCK).unlockedBy(I::andesite) + .viaShaped(b -> b.define('C', I.andesite()) + .pattern("CCC") + .pattern("CCC") + .pattern("CCC")), + + EXPERIENCE_FROM_BLOCK = create(AllItems.EXP_NUGGET).withSuffix("_from_block") + .returns(9) + .unlockedBy(AllItems.EXP_NUGGET::get) + .viaShapeless(b -> b.requires(AllBlocks.EXPERIENCE_BLOCK.get())), + + EXPERIENCE_BLOCK = create(AllBlocks.EXPERIENCE_BLOCK).unlockedBy(AllItems.EXP_NUGGET::get) + .viaShaped(b -> b.define('C', AllItems.EXP_NUGGET.get()) + .pattern("CCC") + .pattern("CCC") + .pattern("CCC")), + BRASS_COMPACTING = metalCompacting(ImmutableList.of(AllItems.BRASS_NUGGET, AllItems.BRASS_INGOT, AllBlocks.BRASS_BLOCK), ImmutableList.of(I::brassNugget, I::brass, I::brassBlock)), @@ -136,7 +157,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { ; - private Marker CURIOSITIES = enterSection(AllSections.CURIOSITIES); + private Marker CURIOSITIES = enterFolder("curiosities"); GeneratedRecipe @@ -175,19 +196,12 @@ public class StandardRecipeGen extends CreateRecipeProvider { ; - private Marker KINETICS = enterSection(AllSections.KINETICS); + private Marker KINETICS = enterFolder("kinetics"); - GeneratedRecipe ANDESITE_LADDER = create(AllBlocks.ANDESITE_LADDER).returns(4) - .unlockedBy(I::andesite) + GeneratedRecipe BASIN = create(AllBlocks.BASIN).unlockedBy(I::andesite) .viaShaped(b -> b.define('A', I.andesite()) .pattern("A A") - .pattern("AAA") - .pattern("A A")), - - BASIN = create(AllBlocks.BASIN).unlockedBy(I::andesite) - .viaShaped(b -> b.define('A', I.andesite()) - .pattern("A A") - .pattern("AAA")), + .pattern("AAA")), GOGGLES = create(AllItems.GOGGLES).unlockedBy(I::andesite) .viaShaped(b -> b.define('G', Tags.Items.GLASS) @@ -241,14 +255,21 @@ public class StandardRecipeGen extends CreateRecipeProvider { .requires(I.planks()) .requires(I.planks())), - LARGE_COGWHEEL_FROM_LITTLE = create(AllBlocks.LARGE_COGWHEEL).withSuffix("from_little") + LARGE_COGWHEEL_FROM_LITTLE = create(AllBlocks.LARGE_COGWHEEL).withSuffix("_from_little") .unlockedBy(I::andesite) .viaShapeless(b -> b.requires(I.cog()) .requires(I.planks())), WATER_WHEEL = create(AllBlocks.WATER_WHEEL).unlockedBy(I::andesite) - .viaShaped(b -> b.define('S', ItemTags.WOODEN_SLABS) - .define('C', AllBlocks.LARGE_COGWHEEL.get()) + .viaShaped(b -> b.define('S', I.planks()) + .define('C', I.shaft()) + .pattern("SSS") + .pattern("SCS") + .pattern("SSS")), + + LARGE_WATER_WHEEL = create(AllBlocks.LARGE_WATER_WHEEL).unlockedBy(AllBlocks.WATER_WHEEL::get) + .viaShaped(b -> b.define('S', I.planks()) + .define('C', AllBlocks.WATER_WHEEL.get()) .pattern("SSS") .pattern("SCS") .pattern("SSS")), @@ -325,14 +346,29 @@ public class StandardRecipeGen extends CreateRecipeProvider { .requires(I.brassSheet())), TRAIN_DOOR = create(AllBlocks.TRAIN_DOOR).returns(1) - .unlockedByTag(() -> I.brass()) + .unlockedBy(() -> I.railwayCasing()) .viaShapeless(b -> b.requires(ItemTags.WOODEN_DOORS) - .requires(I.brassSheet())), + .requires(I.railwayCasing())), + + ANDESITE_DOOR = create(AllBlocks.ANDESITE_DOOR).returns(1) + .unlockedBy(() -> I.andesiteCasing()) + .viaShapeless(b -> b.requires(ItemTags.WOODEN_DOORS) + .requires(I.andesiteCasing())), + + BRASS_DOOR = create(AllBlocks.BRASS_DOOR).returns(1) + .unlockedBy(() -> I.brassCasing()) + .viaShapeless(b -> b.requires(ItemTags.WOODEN_DOORS) + .requires(I.brassCasing())), + + COPPER_DOOR = create(AllBlocks.COPPER_DOOR).returns(1) + .unlockedBy(() -> I.copperCasing()) + .viaShapeless(b -> b.requires(ItemTags.WOODEN_DOORS) + .requires(I.copperCasing())), TRAIN_TRAPDOOR = create(AllBlocks.TRAIN_TRAPDOOR).returns(1) - .unlockedByTag(() -> I.brass()) + .unlockedBy(() -> I.railwayCasing()) .viaShapeless(b -> b.requires(ItemTags.WOODEN_TRAPDOORS) - .requires(I.brassSheet())), + .requires(I.railwayCasing())), FRAMED_GLASS_DOOR = create(AllBlocks.FRAMED_GLASS_DOOR).returns(1) .unlockedBy(AllPaletteBlocks.FRAMED_GLASS::get) @@ -593,7 +629,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { .viaShapeless(b -> b.requires(I.railwayCasing()) .requires(Items.COMPASS)), - TRAIN_CONTROLS = create(AllBlocks.CONTROLS).unlockedBy(I::railwayCasing) + TRAIN_CONTROLS = create(AllBlocks.TRAIN_CONTROLS).unlockedBy(I::railwayCasing) .viaShaped(b -> b.define('I', I.precisionMechanism()) .define('B', Items.LEVER) .define('C', I.railwayCasing()) @@ -633,6 +669,22 @@ public class StandardRecipeGen extends CreateRecipeProvider { .pattern("C") .pattern("I")), + ELEVATOR_PULLEY = create(AllBlocks.ELEVATOR_PULLEY).unlockedByTag(I::brass) + .viaShaped(b -> b.define('B', I.brassCasing()) + .define('C', Items.DRIED_KELP_BLOCK) + .define('I', I.ironSheet()) + .pattern("B") + .pattern("C") + .pattern("I")), + + CONTRAPTION_CONTROLS = create(AllBlocks.CONTRAPTION_CONTROLS).unlockedBy(I::andesite) + .viaShaped(b -> b.define('B', ItemTags.BUTTONS) + .define('C', I.andesiteCasing()) + .define('I', I.electronTube()) + .pattern("B") + .pattern("C") + .pattern("I")), + EMPTY_BLAZE_BURNER = create(AllItems.EMPTY_BLAZE_BURNER).unlockedByTag(I::iron) .viaShaped(b -> b.define('A', Tags.Items.NETHERRACK) .define('I', I.ironSheet()) @@ -814,6 +866,14 @@ public class StandardRecipeGen extends CreateRecipeProvider { .pattern("AAA") .pattern(" C ")), + MECHANICAL_ROLLER = create(AllBlocks.MECHANICAL_ROLLER).unlockedBy(I::andesiteCasing) + .viaShaped(b -> b.define('C', I.andesiteCasing()) + .define('A', I.electronTube()) + .define('I', AllBlocks.CRUSHING_WHEEL.get()) + .pattern("A") + .pattern("C") + .pattern("I")), + MECHANICAL_DRILL = create(AllBlocks.MECHANICAL_DRILL).unlockedBy(I::andesiteCasing) .viaShaped(b -> b.define('C', I.andesiteCasing()) .define('A', I.andesite()) @@ -829,7 +889,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { ; - private Marker LOGISTICS = enterSection(AllSections.LOGISTICS); + private Marker LOGISTICS = enterFolder("logistics"); GeneratedRecipe @@ -874,15 +934,21 @@ public class StandardRecipeGen extends CreateRecipeProvider { .pattern("AA") .pattern("KK")), - CONTENT_OBSERVER = create(AllBlocks.CONTENT_OBSERVER).unlockedBy(AllItems.BELT_CONNECTOR::get) + SMART_OBSERVER = create(AllBlocks.SMART_OBSERVER).unlockedBy(I::brassCasing) + .viaShaped(b -> b.define('B', I.brassCasing()) + .define('R', I.electronTube()) + .define('I', Blocks.OBSERVER) + .pattern("R") + .pattern("B") + .pattern("I")), + + THRESHOLD_SWITCH = create(AllBlocks.THRESHOLD_SWITCH).unlockedBy(I::brassCasing) .viaShaped(b -> b.define('B', I.brassCasing()) .define('R', I.electronTube()) .define('I', Blocks.COMPARATOR) - .pattern("I") + .pattern("R") .pattern("B") - .pattern("R")), - - OBSERVER_CYCLE = conversionCycle(ImmutableList.of(AllBlocks.CONTENT_OBSERVER, AllBlocks.STOCKPILE_SWITCH)), + .pattern("I")), PULSE_EXTENDER = create(AllBlocks.PULSE_EXTENDER).unlockedByTag(I::redstone) .viaShaped(b -> b.define('T', Blocks.REDSTONE_TORCH) @@ -935,7 +1001,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { ; - private Marker SCHEMATICS = enterSection(AllSections.SCHEMATICS); + private Marker SCHEMATICS = enterFolder("schematics"); GeneratedRecipe @@ -965,7 +1031,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { ; - private Marker PALETTES = enterSection(AllSections.PALETTES); + private Marker PALETTES = enterFolder("palettes"); GeneratedRecipe @@ -988,7 +1054,18 @@ public class StandardRecipeGen extends CreateRecipeProvider { .viaShapeless(b -> b.requires(I.wheatFlour()) .requires(Items.WATER_BUCKET)), - DIVING_HELMET = create(AllItems.DIVING_HELMET).unlockedBy(I::copper) + CLIPBOARD = create(AllBlocks.CLIPBOARD).unlockedBy(I::andesite) + .viaShaped(b -> b.define('G', I.planks()) + .define('P', Items.PAPER) + .define('A', I.andesite()) + .pattern("A") + .pattern("P") + .pattern("G")), + + CLIPBOARD_CLEAR = clearData(AllBlocks.CLIPBOARD), SCHEDULE_CLEAR = clearData(AllItems.SCHEDULE), + FILTER_CLEAR = clearData(AllItems.FILTER), ATTRIBUTE_FILTER_CLEAR = clearData(AllItems.ATTRIBUTE_FILTER), + + DIVING_HELMET = create(AllItems.COPPER_DIVING_HELMET).unlockedBy(I::copper) .viaShaped(b -> b.define('G', Tags.Items.GLASS) .define('P', I.copper()) .pattern("PPP") @@ -1003,7 +1080,7 @@ public class StandardRecipeGen extends CreateRecipeProvider { .pattern("PBP") .pattern(" P ")), - DIVING_BOOTS = create(AllItems.DIVING_BOOTS).unlockedBy(I::copper) + DIVING_BOOTS = create(AllItems.COPPER_DIVING_BOOTS).unlockedBy(I::copper) .viaShaped(b -> b.define('G', I.andesite()) .define('P', I.copper()) .pattern("P P") @@ -1030,7 +1107,21 @@ public class StandardRecipeGen extends CreateRecipeProvider { .viaShapeless(b -> b.requires(Ingredient.of(ItemTags.SMALL_FLOWERS), 2) .requires(Ingredient.of(Items.HORN_CORAL, Items.BRAIN_CORAL, Items.TUBE_CORAL, Items.BUBBLE_CORAL, Items.FIRE_CORAL)) - .requires(Items.BONE_MEAL)) + .requires(Items.BONE_MEAL)), + + NETHERITE_DIVING_HELMET = + create(AllItems.NETHERITE_DIVING_HELMET).viaSmithing(AllItems.COPPER_DIVING_HELMET::get, I::netherite), + NETHERITE_BACKTANK = + create(AllItems.NETHERITE_BACKTANK).viaSmithing(AllItems.COPPER_BACKTANK::get, I::netherite), + NETHERITE_DIVING_BOOTS = + create(AllItems.NETHERITE_DIVING_BOOTS).viaSmithing(AllItems.COPPER_DIVING_BOOTS::get, I::netherite), + + NETHERITE_DIVING_HELMET_2 = create(AllItems.NETHERITE_DIVING_HELMET).withSuffix("_from_netherite") + .viaSmithing(() -> Items.NETHERITE_HELMET, () -> Ingredient.of(AllItems.COPPER_DIVING_HELMET.get())), + NETHERITE_BACKTANK_2 = create(AllItems.NETHERITE_BACKTANK).withSuffix("_from_netherite") + .viaSmithing(() -> Items.NETHERITE_CHESTPLATE, () -> Ingredient.of(AllItems.COPPER_BACKTANK.get())), + NETHERITE_DIVING_BOOTS_2 = create(AllItems.NETHERITE_DIVING_BOOTS).withSuffix("_from_netherite") + .viaSmithing(() -> Items.NETHERITE_BOOTS, () -> Ingredient.of(AllItems.COPPER_DIVING_BOOTS.get())) ; @@ -1086,11 +1177,6 @@ public class StandardRecipeGen extends CreateRecipeProvider { String currentFolder = ""; - Marker enterSection(AllSections section) { - currentFolder = Lang.asId(section.name()); - return new Marker(); - } - Marker enterFolder(String folder) { currentFolder = folder; return new Marker(); @@ -1190,6 +1276,12 @@ public class StandardRecipeGen extends CreateRecipeProvider { return result; } + GeneratedRecipe clearData(ItemProviderEntry item) { + return create(item).withSuffix("_clear") + .unlockedBy(item::get) + .viaShapeless(b -> b.requires(item.get())); + } + class GeneratedRecipeBuilder { private String path; @@ -1273,6 +1365,18 @@ public class StandardRecipeGen extends CreateRecipeProvider { }); } + GeneratedRecipe viaSmithing(Supplier base, Supplier upgradeMaterial) { + return register(consumer -> { + UpgradeRecipeBuilder b = + UpgradeRecipeBuilder.smithing(Ingredient.of(base.get()), upgradeMaterial.get(), result.get() + .asItem()); + b.unlocks("has_item", inventoryTrigger(ItemPredicate.Builder.item() + .of(base.get()) + .build())); + b.save(consumer, createLocation("crafting")); + }); + } + private ResourceLocation createSimpleLocation(String recipeType) { return Create.asResource(recipeType + "/" + getRegistryName().getPath() + suffix); } diff --git a/src/main/java/com/simibubi/create/foundation/events/ClientEvents.java b/src/main/java/com/simibubi/create/foundation/events/ClientEvents.java new file mode 100644 index 0000000000..43b0c86417 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/events/ClientEvents.java @@ -0,0 +1,380 @@ +package com.simibubi.create.foundation.events; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllFluids; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.Create; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.ContraptionHandler; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsHandler; +import com.simibubi.create.content.contraptions.chassis.ChassisRangeDisplay; +import com.simibubi.create.content.contraptions.minecart.CouplingHandlerClient; +import com.simibubi.create.content.contraptions.minecart.CouplingPhysics; +import com.simibubi.create.content.contraptions.minecart.CouplingRenderer; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher; +import com.simibubi.create.content.decoration.girder.GirderWrenchBehavior; +import com.simibubi.create.content.equipment.armor.BacktankArmorLayer; +import com.simibubi.create.content.equipment.armor.DivingHelmetItem; +import com.simibubi.create.content.equipment.armor.NetheriteBacktankFirstPersonRenderer; +import com.simibubi.create.content.equipment.blueprint.BlueprintOverlayRenderer; +import com.simibubi.create.content.equipment.clipboard.ClipboardValueSettingsHandler; +import com.simibubi.create.content.equipment.extendoGrip.ExtendoGripRenderHandler; +import com.simibubi.create.content.equipment.toolbox.ToolboxHandlerClient; +import com.simibubi.create.content.equipment.zapper.ZapperItem; +import com.simibubi.create.content.equipment.zapper.terrainzapper.WorldshaperRenderHandler; +import com.simibubi.create.content.kinetics.KineticDebugger; +import com.simibubi.create.content.kinetics.belt.item.BeltConnectorHandler; +import com.simibubi.create.content.kinetics.fan.AirCurrent; +import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointHandler; +import com.simibubi.create.content.kinetics.turntable.TurntableHandler; +import com.simibubi.create.content.logistics.depot.EjectorTargetHandler; +import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; +import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockItem; +import com.simibubi.create.content.redstone.link.LinkRenderer; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerClientHandler; +import com.simibubi.create.content.trains.CameraDistanceModifier; +import com.simibubi.create.content.trains.TrainHUD; +import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.trains.entity.CarriageCouplingRenderer; +import com.simibubi.create.content.trains.entity.TrainRelocator; +import com.simibubi.create.content.trains.schedule.TrainHatArmorLayer; +import com.simibubi.create.content.trains.track.CurvedTrackInteraction; +import com.simibubi.create.content.trains.track.TrackBlockOutline; +import com.simibubi.create.content.trains.track.TrackPlacement; +import com.simibubi.create.content.trains.track.TrackTargetingClient; +import com.simibubi.create.foundation.blockEntity.behaviour.edgeInteraction.EdgeInteractionRenderer; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringRenderer; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueHandler; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueRenderer; +import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.foundation.item.TooltipModifier; +import com.simibubi.create.foundation.networking.LeftClickPacket; +import com.simibubi.create.foundation.sound.SoundScapes; +import com.simibubi.create.foundation.utility.CameraAngleAnimationService; +import com.simibubi.create.foundation.utility.ServerSpeedProvider; +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.config.ui.BaseConfigScreen; +import net.createmod.catnip.render.DefaultSuperRenderTypeBufferImpl; +import net.createmod.catnip.render.SuperRenderTypeBuffer; +import net.createmod.catnip.utility.AnimationTickHolder; +import net.createmod.catnip.utility.worldWrappers.WrappedClientWorld; +import net.createmod.ponder.foundation.PonderTooltipHandler; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.ConfigGuiHandler; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; +import net.minecraftforge.client.event.EntityRenderersEvent; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; +import net.minecraftforge.client.event.RenderLevelLastEvent; +import net.minecraftforge.event.TickEvent.ClientTickEvent; +import net.minecraftforge.event.TickEvent.Phase; +import net.minecraftforge.event.TickEvent.RenderTickEvent; +import net.minecraftforge.event.entity.EntityMountEvent; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; + +@EventBusSubscriber(Dist.CLIENT) +public class ClientEvents { + + @SubscribeEvent + public static void onTick(ClientTickEvent event) { + if (!isGameActive()) + return; + + Level world = Minecraft.getInstance().level; + if (event.phase == Phase.START) { + LinkedControllerClientHandler.tick(); + ControlsHandler.tick(); + AirCurrent.tickClientPlayerSounds(); + return; + } + + SoundScapes.tick(); + AnimationTickHolder.tick(); + + CreateClient.SCHEMATIC_SENDER.tick(); + CreateClient.SCHEMATIC_AND_QUILL_HANDLER.tick(); + CreateClient.GLUE_HANDLER.tick(); + CreateClient.SCHEMATIC_HANDLER.tick(); + CreateClient.ZAPPER_RENDER_HANDLER.tick(); + CreateClient.POTATO_CANNON_RENDER_HANDLER.tick(); + CreateClient.SOUL_PULSE_EFFECT_HANDLER.tick(world); + CreateClient.RAILWAYS.clientTick(); + + ContraptionHandler.tick(world); + CapabilityMinecartController.tick(world); + CouplingPhysics.tick(world); + + PonderTooltipHandler.tick(); + // ScreenOpener.tick(); + ServerSpeedProvider.clientTick(); + BeltConnectorHandler.tick(); +// BeltSlicer.tickHoveringInformation(); + FilteringRenderer.tick(); + LinkRenderer.tick(); + ScrollValueRenderer.tick(); + ChassisRangeDisplay.tick(); + EdgeInteractionRenderer.tick(); + GirderWrenchBehavior.tick(); + WorldshaperRenderHandler.tick(); + CouplingHandlerClient.tick(); + CouplingRenderer.tickDebugModeRenders(); + KineticDebugger.tick(); + ExtendoGripRenderHandler.tick(); + // CollisionDebugger.tick(); + ArmInteractionPointHandler.tick(); + EjectorTargetHandler.tick(); + ContraptionRenderDispatcher.tick(world); + BlueprintOverlayRenderer.tick(); + ToolboxHandlerClient.clientTick(); + TrackTargetingClient.clientTick(); + TrackPlacement.clientTick(); + TrainRelocator.clientTick(); + DisplayLinkBlockItem.clientTick(); + CurvedTrackInteraction.clientTick(); + CameraDistanceModifier.tick(); + CameraAngleAnimationService.tick(); + TrainHUD.tick(); + ClipboardValueSettingsHandler.clientTick(); + CreateClient.VALUE_SETTINGS_HANDLER.tick(); + ScrollValueHandler.tick(); + NetheriteBacktankFirstPersonRenderer.clientTick(); + } + + @SubscribeEvent + public static void onJoin(ClientPlayerNetworkEvent.LoggedInEvent event) { + CreateClient.checkGraphicsFanciness(); + } + + @SubscribeEvent + public static void onLeave(ClientPlayerNetworkEvent.LoggedOutEvent event) { + CreateClient.RAILWAYS.cleanUp(); + } + + @SubscribeEvent + public static void onLoadWorld(WorldEvent.Load event) { + LevelAccessor world = event.getWorld(); + if (world.isClientSide() && world instanceof ClientLevel && !(world instanceof WrappedClientWorld)) { + CreateClient.invalidateRenderers(); + AnimationTickHolder.reset(); + } + } + + @SubscribeEvent + public static void onUnloadWorld(WorldEvent.Unload event) { + if (!event.getWorld() + .isClientSide()) + return; + CreateClient.invalidateRenderers(); + CreateClient.SOUL_PULSE_EFFECT_HANDLER.refresh(); + AnimationTickHolder.reset(); + ControlsHandler.levelUnloaded(event.getWorld()); + } + + @SubscribeEvent + public static void onRenderWorld(RenderLevelLastEvent event) { + PoseStack ms = event.getPoseStack(); + ms.pushPose(); + SuperRenderTypeBuffer buffer = DefaultSuperRenderTypeBufferImpl.getInstance(); + float partialTicks = AnimationTickHolder.getPartialTicks(); + Vec3 camera = Minecraft.getInstance().gameRenderer.getMainCamera() + .getPosition(); + + TrackBlockOutline.drawCurveSelection(ms, buffer, camera); + TrackTargetingClient.render(ms, buffer, camera); + CouplingRenderer.renderAll(ms, buffer, camera); + CarriageCouplingRenderer.renderAll(ms, buffer, camera); + CreateClient.SCHEMATIC_HANDLER.render(ms, buffer, camera); + + buffer.draw(); + RenderSystem.enableCull(); + ms.popPose(); + } + + @SubscribeEvent + public static void onCameraSetup(EntityViewRenderEvent.CameraSetup event) { + float partialTicks = AnimationTickHolder.getPartialTicks(); + + if (CameraAngleAnimationService.isYawAnimating()) + event.setYaw(CameraAngleAnimationService.getYaw(partialTicks)); + + if (CameraAngleAnimationService.isPitchAnimating()) + event.setPitch(CameraAngleAnimationService.getPitch(partialTicks)); + } + + @SubscribeEvent + public static void addToItemTooltip(ItemTooltipEvent event) { + if (!AllConfigs.client().tooltips.get()) + return; + if (event.getPlayer() == null) + return; + + Item item = event.getItemStack().getItem(); + TooltipModifier modifier = TooltipModifier.REGISTRY.get(item); + if (modifier != null && modifier != TooltipModifier.EMPTY) { + modifier.modify(event); + } + + SequencedAssemblyRecipe.addToTooltip(event); + } + + @SubscribeEvent + public static void onRenderTick(RenderTickEvent event) { + if (!isGameActive()) + return; + TurntableHandler.gameRenderTick(); + } + + @SubscribeEvent + public static void onMount(EntityMountEvent event) { + if (event.getEntityMounting() != Minecraft.getInstance().player) + return; + + if (event.isDismounting()) { + CameraDistanceModifier.reset(); + return; + } + + if (!event.isMounting() || !(event.getEntityBeingMounted() instanceof CarriageContraptionEntity carriage)) { + return; + } + + CameraDistanceModifier.zoomOut(); + } + + protected static boolean isGameActive() { + return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null); + } + + @SubscribeEvent + public static void getFogDensity(EntityViewRenderEvent.RenderFogEvent event) { + Camera camera = event.getCamera(); + Level level = Minecraft.getInstance().level; + BlockPos blockPos = camera.getBlockPosition(); + FluidState fluidState = level.getFluidState(blockPos); + if (camera.getPosition().y >= blockPos.getY() + fluidState.getHeight(level, blockPos)) + return; + + Fluid fluid = fluidState.getType(); + Entity entity = camera.getEntity(); + + if (AllFluids.CHOCOLATE.get() + .isSame(fluid)) { + event.scaleFarPlaneDistance(1f / 32f * AllConfigs.client().chocolateTransparencyMultiplier.getF()); + event.setCanceled(true); + return; + } + + if (AllFluids.HONEY.get() + .isSame(fluid)) { + event.scaleFarPlaneDistance(1f / 8f * AllConfigs.client().honeyTransparencyMultiplier.getF()); + event.setCanceled(true); + return; + } + + if (entity.isSpectator()) + return; + + ItemStack divingHelmet = DivingHelmetItem.getWornItem(entity); + if (!divingHelmet.isEmpty()) { + if (FluidHelper.isWater(fluid)) { + event.scaleFarPlaneDistance(6.25f); + event.setCanceled(true); + return; + } else if (FluidHelper.isLava(fluid) && AllItems.NETHERITE_DIVING_HELMET.isIn(divingHelmet)) { + event.setNearPlaneDistance(-4.0f); + event.setFarPlaneDistance(20.0f); + event.setCanceled(true); + return; + } + } + } + + @SubscribeEvent + public static void getFogColor(EntityViewRenderEvent.FogColors event) { + Camera info = event.getCamera(); + Level level = Minecraft.getInstance().level; + BlockPos blockPos = info.getBlockPosition(); + FluidState fluidState = level.getFluidState(blockPos); + if (info.getPosition().y > blockPos.getY() + fluidState.getHeight(level, blockPos)) + return; + + Fluid fluid = fluidState.getType(); + + if (AllFluids.CHOCOLATE.get() + .isSame(fluid)) { + event.setRed(98 / 255f); + event.setGreen(32 / 255f); + event.setBlue(32 / 255f); + return; + } + + if (AllFluids.HONEY.get() + .isSame(fluid)) { + event.setRed(234 / 255f); + event.setGreen(174 / 255f); + event.setBlue(47 / 255f); + return; + } + } + + @SubscribeEvent + public static void leftClickEmpty(PlayerInteractEvent.LeftClickEmpty event) { + ItemStack stack = event.getItemStack(); + if (stack.getItem() instanceof ZapperItem) { + AllPackets.getChannel().sendToServer(new LeftClickPacket()); + } + } + + @EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD) + public static class ModBusEvents { + + @SubscribeEvent + public static void registerClientReloadListeners(RegisterClientReloadListenersEvent event) { + event.registerReloadListener(CreateClient.RESOURCE_RELOAD_LISTENER); + } + + @SubscribeEvent + public static void addEntityRendererLayers(EntityRenderersEvent.AddLayers event) { + EntityRenderDispatcher dispatcher = Minecraft.getInstance() + .getEntityRenderDispatcher(); + BacktankArmorLayer.registerOnAll(dispatcher); + TrainHatArmorLayer.registerOnAll(dispatcher); + } + + @SubscribeEvent + public static void onLoadComplete(FMLLoadCompleteEvent event) { + ModContainer createContainer = ModList.get() + .getModContainerById(Create.ID) + .orElseThrow(() -> new IllegalStateException("Create mod container missing on LoadComplete")); + createContainer.registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class, + () -> new ConfigGuiHandler.ConfigGuiFactory( + (mc, previousScreen) -> new BaseConfigScreen(previousScreen, Create.ID))); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/events/CommonEvents.java b/src/main/java/com/simibubi/create/foundation/events/CommonEvents.java similarity index 86% rename from src/main/java/com/simibubi/create/events/CommonEvents.java rename to src/main/java/com/simibubi/create/foundation/events/CommonEvents.java index 306201825b..0c6564119f 100644 --- a/src/main/java/com/simibubi/create/events/CommonEvents.java +++ b/src/main/java/com/simibubi/create/foundation/events/CommonEvents.java @@ -1,24 +1,24 @@ -package com.simibubi.create.events; +package com.simibubi.create.foundation.events; import com.simibubi.create.AllFluids; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsServerHandler; -import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.wrench.WrenchItem; -import com.simibubi.create.content.curiosities.toolbox.ToolboxHandler; -import com.simibubi.create.content.curiosities.weapons.PotatoProjectileTypeManager; -import com.simibubi.create.content.curiosities.zapper.ZapperInteractionHandler; -import com.simibubi.create.content.curiosities.zapper.ZapperItem; -import com.simibubi.create.content.logistics.item.LinkedControllerServerHandler; -import com.simibubi.create.content.logistics.trains.entity.CarriageEntityHandler; +import com.simibubi.create.content.contraptions.ContraptionHandler; +import com.simibubi.create.content.contraptions.actors.trainControls.ControlsServerHandler; +import com.simibubi.create.content.contraptions.minecart.CouplingPhysics; +import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController; +import com.simibubi.create.content.equipment.potatoCannon.PotatoProjectileTypeManager; +import com.simibubi.create.content.equipment.toolbox.ToolboxHandler; +import com.simibubi.create.content.equipment.wrench.WrenchItem; +import com.simibubi.create.content.equipment.zapper.ZapperInteractionHandler; +import com.simibubi.create.content.equipment.zapper.ZapperItem; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerServerHandler; +import com.simibubi.create.content.trains.entity.CarriageEntityHandler; import com.simibubi.create.foundation.ModFilePackResources; -import com.simibubi.create.foundation.command.AllCommands; import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.foundation.recipe.RecipeFinder; import com.simibubi.create.foundation.utility.ServerSpeedProvider; -import com.simibubi.create.foundation.utility.recipe.RecipeFinder; -import com.simibubi.create.foundation.worldgen.AllOreFeatureConfigEntries; +import com.simibubi.create.infrastructure.command.AllCommands; +import com.simibubi.create.infrastructure.worldgen.AllOreFeatureConfigEntries; import net.createmod.catnip.utility.Iterate; import net.createmod.catnip.utility.WorldAttached; @@ -60,6 +60,7 @@ import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.forgespi.language.IModFileInfo; @@ -120,9 +121,11 @@ public class CommonEvents { } @SubscribeEvent - public static void onWorldTick(WorldTickEvent event) { + public static void onServerWorldTick(WorldTickEvent event) { if (event.phase == Phase.START) return; + if (event.side == LogicalSide.CLIENT) + return; Level world = event.world; ContraptionHandler.tick(world); CapabilityMinecartController.tick(world); @@ -245,7 +248,5 @@ public class CommonEvents { }); } } - } - } diff --git a/src/main/java/com/simibubi/create/foundation/events/InputEvents.java b/src/main/java/com/simibubi/create/foundation/events/InputEvents.java new file mode 100644 index 0000000000..75217167eb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/events/InputEvents.java @@ -0,0 +1,92 @@ +package com.simibubi.create.foundation.events; + +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.elevator.ElevatorControlsHandler; +import com.simibubi.create.content.equipment.toolbox.ToolboxHandlerClient; +import com.simibubi.create.content.redstone.link.controller.LinkedControllerClientHandler; +import com.simibubi.create.content.trains.TrainHUD; +import com.simibubi.create.content.trains.entity.TrainRelocator; +import com.simibubi.create.content.trains.track.CurvedTrackInteraction; + +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent.ClickInputEvent; +import net.minecraftforge.client.event.InputEvent.KeyInputEvent; +import net.minecraftforge.client.event.InputEvent.MouseInputEvent; +import net.minecraftforge.client.event.InputEvent.MouseScrollEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber(Dist.CLIENT) +public class InputEvents { + + @SubscribeEvent + public static void onKeyInput(KeyInputEvent event) { + if (Minecraft.getInstance().screen != null) + return; + + int key = event.getKey(); + boolean pressed = !(event.getAction() == 0); + + CreateClient.SCHEMATIC_HANDLER.onKeyInput(key, pressed); + ToolboxHandlerClient.onKeyInput(key, pressed); + } + + @SubscribeEvent + public static void onMouseScrolled(MouseScrollEvent event) { + if (Minecraft.getInstance().screen != null) + return; + + double delta = event.getScrollDelta(); +// CollisionDebugger.onScroll(delta); + boolean cancelled = CreateClient.SCHEMATIC_HANDLER.mouseScrolled(delta) + || CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || TrainHUD.onScroll(delta) + || ElevatorControlsHandler.onScroll(delta); + event.setCanceled(cancelled); + } + + @SubscribeEvent + public static void onMouseInput(MouseInputEvent event) { + if (Minecraft.getInstance().screen != null) + return; + + int button = event.getButton(); + boolean pressed = !(event.getAction() == 0); + + CreateClient.SCHEMATIC_HANDLER.onMouseInput(button, pressed); + CreateClient.SCHEMATIC_AND_QUILL_HANDLER.onMouseInput(button, pressed); + } + + @SubscribeEvent + public static void onClickInput(ClickInputEvent event) { + Minecraft mc = Minecraft.getInstance(); + if (mc.screen != null) + return; + + if (CurvedTrackInteraction.onClickInput(event)) { + event.setCanceled(true); + return; + } + + KeyMapping key = event.getKeyMapping(); + + if (key == mc.options.keyUse || key == mc.options.keyAttack) { + if (CreateClient.GLUE_HANDLER.onMouseInput(key == mc.options.keyAttack)) + event.setCanceled(true); + } + + if (key == mc.options.keyPickItem) { + if (ToolboxHandlerClient.onPickItem()) + event.setCanceled(true); + return; + } + + if (!event.isUseItem()) + return; + + LinkedControllerClientHandler.deactivateInLectern(); + TrainRelocator.onClicked(event); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java index b74c28320d..12a87c322f 100644 --- a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java +++ b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java @@ -7,10 +7,10 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling; -import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity; -import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; -import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.content.fluids.tank.CreativeFluidTankBlockEntity; +import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; +import com.simibubi.create.content.fluids.transfer.GenericItemFilling; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.utility.Pair; @@ -133,13 +133,13 @@ public class FluidHelper { return stack; } - public static boolean tryEmptyItemIntoTE(Level worldIn, Player player, InteractionHand handIn, ItemStack heldItem, - SmartTileEntity te) { - if (!EmptyingByBasin.canItemBeEmptied(worldIn, heldItem)) + public static boolean tryEmptyItemIntoBE(Level worldIn, Player player, InteractionHand handIn, ItemStack heldItem, + SmartBlockEntity be) { + if (!GenericItemEmptying.canItemBeEmptied(worldIn, heldItem)) return false; - Pair emptyingResult = EmptyingByBasin.emptyItem(worldIn, heldItem, true); - LazyOptional capability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + Pair emptyingResult = GenericItemEmptying.emptyItem(worldIn, heldItem, true); + LazyOptional capability = be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); IFluidHandler tank = capability.orElse(null); FluidStack fluidStack = emptyingResult.getFirst(); @@ -149,10 +149,10 @@ public class FluidHelper { return true; ItemStack copyOfHeld = heldItem.copy(); - emptyingResult = EmptyingByBasin.emptyItem(worldIn, copyOfHeld, false); + emptyingResult = GenericItemEmptying.emptyItem(worldIn, copyOfHeld, false); tank.fill(fluidStack, FluidAction.EXECUTE); - if (!player.isCreative() && !(te instanceof CreativeFluidTankTileEntity)) { + if (!player.isCreative() && !(be instanceof CreativeFluidTankBlockEntity)) { if (copyOfHeld.isEmpty()) player.setItemInHand(handIn, emptyingResult.getSecond()); else { @@ -163,12 +163,12 @@ public class FluidHelper { return true; } - public static boolean tryFillItemFromTE(Level world, Player player, InteractionHand handIn, ItemStack heldItem, - SmartTileEntity te) { + public static boolean tryFillItemFromBE(Level world, Player player, InteractionHand handIn, ItemStack heldItem, + SmartBlockEntity be) { if (!GenericItemFilling.canItemBeFilled(world, heldItem)) return false; - LazyOptional capability = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + LazyOptional capability = be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); IFluidHandler tank = capability.orElse(null); if (tank == null) @@ -187,7 +187,7 @@ public class FluidHelper { if (world.isClientSide) return true; - if (player.isCreative() || te instanceof CreativeFluidTankTileEntity) + if (player.isCreative() || be instanceof CreativeFluidTankBlockEntity) heldItem = heldItem.copy(); ItemStack out = GenericItemFilling.fillItem(world, requiredAmountForItem, heldItem, fluid.copy()); @@ -197,7 +197,7 @@ public class FluidHelper { if (!player.isCreative()) player.getInventory().placeItemBackInInventory(out); - te.notifyUpdate(); + be.notifyUpdate(); return true; } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index 78c1cbae31..9dcca887e9 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -41,20 +41,16 @@ public enum AllGuiTextures implements ScreenElement, TextureSheetSegment { SCHEMATICANNON_FUEL("schematics_2", 28, 222, 47, 16), SCHEMATICANNON_FUEL_CREATIVE("schematics_2", 28, 239, 47, 16), - STOCKSWITCH("logistics", 182, 93), + STOCKSWITCH("logistics", 182, 95), STOCKSWITCH_ARROW_UP("logistics", 191, 0, 7, 24), STOCKSWITCH_ARROW_DOWN("logistics", 198, 0, 7, 24), STOCKSWITCH_CURSOR("logistics", 206, 0, 7, 16), - STOCKSWITCH_INTERVAL("logistics", 0, 93, 100, 18), - STOCKSWITCH_UNPOWERED_LANE("logistics", 36, 18, 102, 18), - STOCKSWITCH_POWERED_LANE("logistics", 36, 40, 102, 18), + STOCKSWITCH_INTERVAL("logistics", 0, 95, 100, 18), + STOCKSWITCH_UNPOWERED_LANE("logistics", 37, 20, 100, 18), + STOCKSWITCH_POWERED_LANE("logistics", 37, 42, 100, 18), - ADJUSTABLE_CRATE("logistics_2", 124, 127), - ADJUSTABLE_DOUBLE_CRATE("logistics_2", 0, 127, 196, 127), - ADJUSTABLE_CRATE_LOCKED_SLOT("logistics_2", 125, 109, 18, 18), - - FILTER("filters", 214, 97), - ATTRIBUTE_FILTER("filters", 0, 97, 241, 83), + FILTER("filters", 214, 99), + ATTRIBUTE_FILTER("filters", 0, 99, 241, 85), TOOLBOX("toolbox", 188, 171), TOOLBELT_SLOT("minecraft", "widgets", 24, 23, 22, 22), @@ -68,21 +64,17 @@ public enum AllGuiTextures implements ScreenElement, TextureSheetSegment { TOOLBELT_SELECTED_OFF("widgets", 0, 155, 22, 22), TOOLBELT_SELECTED_ON("widgets", 22, 155, 22, 22), - SEQUENCER("sequencer", 173, 159), - SEQUENCER_INSTRUCTION("sequencer", 0, 14, 162, 22), - SEQUENCER_DELAY("sequencer", 0, 58, 162, 22), - SEQUENCER_END("sequencer", 0, 80, 162, 22), - SEQUENCER_EMPTY("sequencer", 0, 102, 162, 22), - SEQUENCER_AWAIT("sequencer", 0, 160, 162, 22), + SEQUENCER("sequencer", 173, 161), + SEQUENCER_INSTRUCTION("sequencer", 0, 16, 162, 22), + SEQUENCER_DELAY("sequencer", 0, 60, 162, 22), + SEQUENCER_END("sequencer", 0, 82, 162, 22), + SEQUENCER_EMPTY("sequencer", 0, 104, 162, 22), + SEQUENCER_AWAIT("sequencer", 0, 162, 162, 22), LINKED_CONTROLLER("curiosities_2", 179, 109), BLUEPRINT("curiosities_2", 0, 109, 179, 109), - PROJECTOR("projector", 235, 185), - PROJECTOR_FILTER_STRENGTH("projector", 0, 14, 162, 22), - PROJECTOR_FILTER("projector", 0, 36, 162, 22), - PROJECTOR_END("projector", 0, 58, 162, 22), - PROJECTOR_EMPTY("projector", 0, 80, 162, 22), + CLIPBOARD("clipboard", 0, 0, 256, 256), DATA_GATHERER("display_link", 235, 162), DATA_AREA_START("display_link", 0, 163, 2, 18), @@ -133,6 +125,28 @@ public enum AllGuiTextures implements ScreenElement, TextureSheetSegment { I_DISASSEMBLE_TRAIN("schedule_2", 39, 239, 24, 16), I_ASSEMBLE_TRAIN("schedule_2", 64, 239, 24, 16), + ELEVATOR_CONTACT("display_link", 20, 172, 233, 82), + + BRASS_FRAME_TL("value_settings", 65, 9, 4, 4), + BRASS_FRAME_TR("value_settings", 70, 9, 4, 4), + BRASS_FRAME_BL("value_settings", 65, 19, 4, 4), + BRASS_FRAME_BR("value_settings", 70, 19, 4, 4), + BRASS_FRAME_LEFT("value_settings", 65, 14, 3, 4), + BRASS_FRAME_RIGHT("value_settings", 71, 14, 3, 4), + BRASS_FRAME_TOP("value_settings", 0, 24, 256, 3), + BRASS_FRAME_BOTTOM("value_settings", 0, 27, 256, 3), + + VALUE_SETTINGS_MILESTONE("value_settings", 0, 0, 7, 8), + VALUE_SETTINGS_WIDE_MILESTONE("value_settings", 75, 14, 13, 8), + VALUE_SETTINGS_BAR("value_settings", 7, 0, 249, 8), + VALUE_SETTINGS_BAR_BG("value_settings", 75, 9, 1, 1), + VALUE_SETTINGS_OUTER_BG("value_settings", 80, 9, 1, 1), + VALUE_SETTINGS_CURSOR_LEFT("value_settings", 0, 9, 3, 14), + VALUE_SETTINGS_CURSOR("value_settings", 4, 9, 56, 14), + VALUE_SETTINGS_CURSOR_RIGHT("value_settings", 61, 9, 3, 14), + VALUE_SETTINGS_CURSOR_ICON("value_settings", 0, 44, 22, 20), + VALUE_SETTINGS_LABEL_BG("value_settings", 0, 31, 81, 11), + // JEI JEI_SLOT("jei/widgets", 18, 18), JEI_CHANCE_SLOT("jei/widgets", 20, 156, 18, 18), @@ -175,6 +189,9 @@ public enum AllGuiTextures implements ScreenElement, TextureSheetSegment { TRAIN_PROMPT_R("widgets", 11, 209, 3, 16), TRAIN_PROMPT("widgets", 0, 230, 256, 16), + // ComputerCraft + COMPUTER("computer", 200, 102); + ; public static final int FONT_COLOR = 0x575F7A; diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index 310956648f..de0b629a5e 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -82,7 +82,7 @@ public class AllIcons implements ScreenElement { public static final AllIcons I_TOOL_DEPLOY = newRow(), I_SKIP_MISSING = next(), - I_SKIP_TILES = next(), + I_SKIP_BLOCK_ENTITIES = next(), I_DICE = next(), I_TUNNEL_SPLIT = next(), I_TUNNEL_FORCED_SPLIT = next(), @@ -104,6 +104,10 @@ public class AllIcons implements ScreenElement { I_ADD_INVERTED_ATTRIBUTE = next(), I_FLIP = next(), + + I_ROLLER_PAVE = next(), + I_ROLLER_FILL = next(), + I_ROLLER_WIDE_FILL = next(), I_PLAY = newRow(), I_PAUSE = next(), @@ -123,9 +127,14 @@ public class AllIcons implements ScreenElement { I_PATTERN_CHANCE_75 = next(), I_FOLLOW_DIAGONAL = next(), I_FOLLOW_MATERIAL = next(), + + I_CLEAR_CHECKED = next(), I_SCHEMATIC = newRow(), I_SEQ_REPEAT = next(), + VALUE_BOX_HOVER_6PX = next(), + VALUE_BOX_HOVER_4PX = next(), + VALUE_BOX_HOVER_8PX = next(), I_MTD_LEFT = newRow(), I_MTD_CLOSE = next(), @@ -187,7 +196,7 @@ public class AllIcons implements ScreenElement { @OnlyIn(Dist.CLIENT) public void render(PoseStack ms, MultiBufferSource buffer, int color) { - VertexConsumer builder = buffer.getBuffer(RenderType.textSeeThrough(ICON_ATLAS)); + VertexConsumer builder = buffer.getBuffer(RenderType.text(ICON_ATLAS)); Matrix4f matrix = ms.last().pose(); Color rgb = new Color(color); int light = LightTexture.FULL_BRIGHT; diff --git a/src/main/java/com/simibubi/create/foundation/gui/CreateTheme.java b/src/main/java/com/simibubi/create/foundation/gui/CreateTheme.java new file mode 100644 index 0000000000..d6d5e97f48 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/CreateTheme.java @@ -0,0 +1,24 @@ +package com.simibubi.create.foundation.gui; + +import net.createmod.catnip.utility.theme.Color; +import net.createmod.catnip.utility.theme.Theme; + +public class CreateTheme extends Theme { + + public static final CreateTheme CREATE_THEME = addTheme(new CreateTheme()); + + @Override + protected void init() { + + put(Key.STANDARD_TOOLTIP, new Color(0xff_c9974c), new Color(0xff_f1dd79)); + + } + + public static void loadClass() {} + + public static class Key { + + public static final Theme.Key STANDARD_TOOLTIP = new Theme.Key(); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/ClearContainerPacket.java b/src/main/java/com/simibubi/create/foundation/gui/container/ClearContainerPacket.java deleted file mode 100644 index 1fb21351c3..0000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/container/ClearContainerPacket.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.simibubi.create.foundation.gui.container; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent.Context; - -public class ClearContainerPacket extends SimplePacketBase { - - public ClearContainerPacket() {} - - public ClearContainerPacket(FriendlyByteBuf buffer) {} - - @Override - public void write(FriendlyByteBuf buffer) {} - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - if (!(player.containerMenu instanceof IClearableContainer)) - return; - ((IClearableContainer) player.containerMenu).clearContents(); - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/ContainerBase.java b/src/main/java/com/simibubi/create/foundation/gui/container/ContainerBase.java deleted file mode 100644 index f3632f10e6..0000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/container/ContainerBase.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.simibubi.create.foundation.gui.container; - -import com.simibubi.create.foundation.utility.IInteractionChecker; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public abstract class ContainerBase extends AbstractContainerMenu { - - public Player player; - public Inventory playerInventory; - public T contentHolder; - - protected ContainerBase(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id); - init(inv, createOnClient(extraData)); - } - - protected ContainerBase(MenuType type, int id, Inventory inv, T contentHolder) { - super(type, id); - init(inv, contentHolder); - } - - protected void init(Inventory inv, T contentHolderIn) { - player = inv.player; - playerInventory = inv; - contentHolder = contentHolderIn; - initAndReadInventory(contentHolder); - addSlots(); - broadcastChanges(); - } - - @OnlyIn(Dist.CLIENT) - protected abstract T createOnClient(FriendlyByteBuf extraData); - - protected abstract void initAndReadInventory(T contentHolder); - - protected abstract void addSlots(); - - protected abstract void saveData(T contentHolder); - - protected void addPlayerSlots(int x, int y) { - for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) - this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); - for (int row = 0; row < 3; ++row) - for (int col = 0; col < 9; ++col) - this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); - } - - @Override - public void removed(Player playerIn) { - super.removed(playerIn); - saveData(contentHolder); - } - - @Override - public boolean stillValid(Player player) { - if (contentHolder == null) - return false; - if (contentHolder instanceof IInteractionChecker) - return ((IInteractionChecker) contentHolder).canPlayerUse(player); - return true; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemContainer.java b/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemContainer.java deleted file mode 100644 index bb42dfd2aa..0000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemContainer.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.simibubi.create.foundation.gui.container; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; - -public abstract class GhostItemContainer extends ContainerBase implements IClearableContainer { - - public ItemStackHandler ghostInventory; - - protected GhostItemContainer(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { - super(type, id, inv, extraData); - } - - protected GhostItemContainer(MenuType type, int id, Inventory inv, T contentHolder) { - super(type, id, inv, contentHolder); - } - - protected abstract ItemStackHandler createGhostInventory(); - - protected abstract boolean allowRepeats(); - - @Override - protected void initAndReadInventory(T contentHolder) { - ghostInventory = createGhostInventory(); - } - - @Override - public void clearContents() { - for (int i = 0; i < ghostInventory.getSlots(); i++) - ghostInventory.setStackInSlot(i, ItemStack.EMPTY); - } - - @Override - public boolean canTakeItemForPickAll(ItemStack stack, Slot slotIn) { - return slotIn.container == playerInventory; - } - - @Override - public boolean canDragTo(Slot slotIn) { - if (allowRepeats()) - return true; - return slotIn.container == playerInventory; - } - - @Override - public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { - if (slotId < 36) { - super.clicked(slotId, dragType, clickTypeIn, player); - return; - } - if (clickTypeIn == ClickType.THROW) - return; - - ItemStack held = getCarried(); - int slot = slotId - 36; - if (clickTypeIn == ClickType.CLONE) { - if (player.isCreative() && held.isEmpty()) { - ItemStack stackInSlot = ghostInventory.getStackInSlot(slot) - .copy(); - stackInSlot.setCount(stackInSlot.getMaxStackSize()); - setCarried(stackInSlot); - return; - } - return; - } - - ItemStack insert; - if (held.isEmpty()) { - insert = ItemStack.EMPTY; - } else { - insert = held.copy(); - insert.setCount(1); - } - ghostInventory.setStackInSlot(slot, insert); - getSlot(slotId).setChanged(); - } - - @Override - public ItemStack quickMoveStack(Player playerIn, int index) { - if (index < 36) { - ItemStack stackToInsert = playerInventory.getItem(index); - for (int i = 0; i < ghostInventory.getSlots(); i++) { - ItemStack stack = ghostInventory.getStackInSlot(i); - if (!allowRepeats() && ItemHandlerHelper.canItemStacksStack(stack, stackToInsert)) - break; - if (stack.isEmpty()) { - ItemStack copy = stackToInsert.copy(); - copy.setCount(1); - ghostInventory.insertItem(i, copy, false); - getSlot(i + 36).setChanged(); - break; - } - } - } else { - ghostInventory.extractItem(index - 36, 1, false); - getSlot(index).setChanged(); - } - return ItemStack.EMPTY; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemSubmitPacket.java b/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemSubmitPacket.java deleted file mode 100644 index eb18137030..0000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/container/GhostItemSubmitPacket.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.simibubi.create.foundation.gui.container; - -import java.util.function.Supplier; - -import com.simibubi.create.foundation.networking.SimplePacketBase; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent.Context; - -public class GhostItemSubmitPacket extends SimplePacketBase { - - private final ItemStack item; - private final int slot; - - public GhostItemSubmitPacket(ItemStack item, int slot) { - this.item = item; - this.slot = slot; - } - - public GhostItemSubmitPacket(FriendlyByteBuf buffer) { - item = buffer.readItem(); - slot = buffer.readInt(); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeItem(item); - buffer.writeInt(slot); - } - - @Override - public void handle(Supplier context) { - context.get() - .enqueueWork(() -> { - ServerPlayer player = context.get() - .getSender(); - if (player == null) - return; - - if (player.containerMenu instanceof GhostItemContainer) { - GhostItemContainer c = (GhostItemContainer) player.containerMenu; - c.ghostInventory.setStackInSlot(slot, item); - c.getSlot(36 + slot).setChanged(); - } - - }); - context.get() - .setPacketHandled(true); - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/IClearableContainer.java b/src/main/java/com/simibubi/create/foundation/gui/container/IClearableContainer.java deleted file mode 100644 index d0d0da14e0..0000000000 --- a/src/main/java/com/simibubi/create/foundation/gui/container/IClearableContainer.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.simibubi.create.foundation.gui.container; - -import com.simibubi.create.foundation.networking.AllPackets; - -public interface IClearableContainer { - - default void sendClearPacket() { - AllPackets.channel.sendToServer(new ClearContainerPacket()); - } - - public void clearContents(); - -} diff --git a/src/main/java/com/simibubi/create/foundation/gui/container/AbstractSimiContainerScreen.java b/src/main/java/com/simibubi/create/foundation/gui/menu/AbstractSimiContainerScreen.java similarity index 99% rename from src/main/java/com/simibubi/create/foundation/gui/container/AbstractSimiContainerScreen.java rename to src/main/java/com/simibubi/create/foundation/gui/menu/AbstractSimiContainerScreen.java index 9d8732cccc..22d921fa7a 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/container/AbstractSimiContainerScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/AbstractSimiContainerScreen.java @@ -1,4 +1,4 @@ -package com.simibubi.create.foundation.gui.container; +package com.simibubi.create.foundation.gui.menu; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/com/simibubi/create/foundation/gui/menu/ClearMenuPacket.java b/src/main/java/com/simibubi/create/foundation/gui/menu/ClearMenuPacket.java new file mode 100644 index 0000000000..ba0a12eeb7 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/ClearMenuPacket.java @@ -0,0 +1,31 @@ +package com.simibubi.create.foundation.gui.menu; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ClearMenuPacket extends SimplePacketBase { + + public ClearMenuPacket() {} + + public ClearMenuPacket(FriendlyByteBuf buffer) {} + + @Override + public void write(FriendlyByteBuf buffer) {} + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + if (!(player.containerMenu instanceof IClearableMenu)) + return; + ((IClearableMenu) player.containerMenu).clearContents(); + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemMenu.java b/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemMenu.java new file mode 100644 index 0000000000..b7d619cb82 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemMenu.java @@ -0,0 +1,108 @@ +package com.simibubi.create.foundation.gui.menu; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; + +public abstract class GhostItemMenu extends MenuBase implements IClearableMenu { + + public ItemStackHandler ghostInventory; + + protected GhostItemMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id, inv, extraData); + } + + protected GhostItemMenu(MenuType type, int id, Inventory inv, T contentHolder) { + super(type, id, inv, contentHolder); + } + + protected abstract ItemStackHandler createGhostInventory(); + + protected abstract boolean allowRepeats(); + + @Override + protected void initAndReadInventory(T contentHolder) { + ghostInventory = createGhostInventory(); + } + + @Override + public void clearContents() { + for (int i = 0; i < ghostInventory.getSlots(); i++) + ghostInventory.setStackInSlot(i, ItemStack.EMPTY); + } + + @Override + public boolean canTakeItemForPickAll(ItemStack stack, Slot slotIn) { + return slotIn.container == playerInventory; + } + + @Override + public boolean canDragTo(Slot slotIn) { + if (allowRepeats()) + return true; + return slotIn.container == playerInventory; + } + + @Override + public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) { + if (slotId < 36) { + super.clicked(slotId, dragType, clickTypeIn, player); + return; + } + if (clickTypeIn == ClickType.THROW) + return; + + ItemStack held = getCarried(); + int slot = slotId - 36; + if (clickTypeIn == ClickType.CLONE) { + if (player.isCreative() && held.isEmpty()) { + ItemStack stackInSlot = ghostInventory.getStackInSlot(slot) + .copy(); + stackInSlot.setCount(stackInSlot.getMaxStackSize()); + setCarried(stackInSlot); + return; + } + return; + } + + ItemStack insert; + if (held.isEmpty()) { + insert = ItemStack.EMPTY; + } else { + insert = held.copy(); + insert.setCount(1); + } + ghostInventory.setStackInSlot(slot, insert); + getSlot(slotId).setChanged(); + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + if (index < 36) { + ItemStack stackToInsert = playerInventory.getItem(index); + for (int i = 0; i < ghostInventory.getSlots(); i++) { + ItemStack stack = ghostInventory.getStackInSlot(i); + if (!allowRepeats() && ItemHandlerHelper.canItemStacksStack(stack, stackToInsert)) + break; + if (stack.isEmpty()) { + ItemStack copy = stackToInsert.copy(); + copy.setCount(1); + ghostInventory.insertItem(i, copy, false); + getSlot(i + 36).setChanged(); + break; + } + } + } else { + ghostInventory.extractItem(index - 36, 1, false); + getSlot(index).setChanged(); + } + return ItemStack.EMPTY; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemSubmitPacket.java b/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemSubmitPacket.java new file mode 100644 index 0000000000..234b87d4bb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/GhostItemSubmitPacket.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.gui.menu; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent.Context; + +public class GhostItemSubmitPacket extends SimplePacketBase { + + private final ItemStack item; + private final int slot; + + public GhostItemSubmitPacket(ItemStack item, int slot) { + this.item = item; + this.slot = slot; + } + + public GhostItemSubmitPacket(FriendlyByteBuf buffer) { + item = buffer.readItem(); + slot = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeItem(item); + buffer.writeInt(slot); + } + + @Override + public boolean handle(Context context) { + context.enqueueWork(() -> { + ServerPlayer player = context.getSender(); + if (player == null) + return; + + if (player.containerMenu instanceof GhostItemMenu menu) { + menu.ghostInventory.setStackInSlot(slot, item); + menu.getSlot(36 + slot).setChanged(); + } + }); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/menu/IClearableMenu.java b/src/main/java/com/simibubi/create/foundation/gui/menu/IClearableMenu.java new file mode 100644 index 0000000000..b9d8431bed --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/IClearableMenu.java @@ -0,0 +1,13 @@ +package com.simibubi.create.foundation.gui.menu; + +import com.simibubi.create.AllPackets; + +public interface IClearableMenu { + + default void sendClearPacket() { + AllPackets.getChannel().sendToServer(new ClearMenuPacket()); + } + + public void clearContents(); + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/menu/MenuBase.java b/src/main/java/com/simibubi/create/foundation/gui/menu/MenuBase.java new file mode 100644 index 0000000000..9781f17d74 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/menu/MenuBase.java @@ -0,0 +1,71 @@ +package com.simibubi.create.foundation.gui.menu; + +import com.simibubi.create.foundation.utility.IInteractionChecker; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public abstract class MenuBase extends AbstractContainerMenu { + + public Player player; + public Inventory playerInventory; + public T contentHolder; + + protected MenuBase(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + super(type, id); + init(inv, createOnClient(extraData)); + } + + protected MenuBase(MenuType type, int id, Inventory inv, T contentHolder) { + super(type, id); + init(inv, contentHolder); + } + + protected void init(Inventory inv, T contentHolderIn) { + player = inv.player; + playerInventory = inv; + contentHolder = contentHolderIn; + initAndReadInventory(contentHolder); + addSlots(); + broadcastChanges(); + } + + @OnlyIn(Dist.CLIENT) + protected abstract T createOnClient(FriendlyByteBuf extraData); + + protected abstract void initAndReadInventory(T contentHolder); + + protected abstract void addSlots(); + + protected abstract void saveData(T contentHolder); + + protected void addPlayerSlots(int x, int y) { + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) + this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58)); + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 9; ++col) + this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18)); + } + + @Override + public void removed(Player playerIn) { + super.removed(playerIn); + saveData(contentHolder); + } + + @Override + public boolean stillValid(Player player) { + if (contentHolder == null) + return false; + if (contentHolder instanceof IInteractionChecker) + return ((IInteractionChecker) contentHolder).canPlayerUse(player); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java index a1dd8ceb58..be76f50523 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java @@ -4,12 +4,15 @@ import java.util.function.Consumer; import java.util.function.Function; import com.simibubi.create.AllKeys; -import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour.StepContext; +import com.simibubi.create.AllSoundEvents; +import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour.StepContext; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.gui.widget.AbstractSimiWidget; import net.createmod.catnip.utility.lang.Components; import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; @@ -20,8 +23,10 @@ public class ScrollInput extends AbstractSimiWidget { protected Component title = CreateLang.translateDirect("gui.scrollInput.defaultTitle"); protected final Component scrollToModify = CreateLang.translateDirect("gui.scrollInput.scrollToModify"); protected final Component shiftScrollsFaster = CreateLang.translateDirect("gui.scrollInput.shiftScrollsFaster"); + protected Component hint = null; protected Label displayLabel; protected boolean inverted; + protected boolean soundPlayed; protected Function formatter; protected int min, max; @@ -36,6 +41,7 @@ public class ScrollInput extends AbstractSimiWidget { shiftStep = 5; step = standardStep(); formatter = i -> Components.literal(String.valueOf(i)); + soundPlayed = false; } public Function standardStep() { @@ -74,6 +80,12 @@ public class ScrollInput extends AbstractSimiWidget { return this; } + public ScrollInput addHint(MutableComponent hint) { + this.hint = hint; + updateTooltip(); + return this; + } + public ScrollInput withStepFunction(Function step) { this.step = step; return this; @@ -86,6 +98,12 @@ public class ScrollInput extends AbstractSimiWidget { return this; } + @Override + public void tick() { + super.tick(); + soundPlayed = false; + } + public int getState() { return state; } @@ -125,8 +143,15 @@ public class ScrollInput extends AbstractSimiWidget { clampState(); - if (priorState != state) + if (priorState != state) { + if (!soundPlayed) + Minecraft.getInstance() + .getSoundManager() + .play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), + 1.5f + 0.1f * (state - min) / (max - min))); + soundPlayed = true; onChanged(); + } return priorState != state; } @@ -156,6 +181,9 @@ public class ScrollInput extends AbstractSimiWidget { return; toolTip.add(title.plainCopy() .withStyle(s -> s.withColor(HEADER_RGB))); + if (hint != null) + toolTip.add(hint.plainCopy() + .withStyle(s -> s.withColor(HINT_RGB))); toolTip.add(scrollToModify.plainCopy() .withStyle(ChatFormatting.ITALIC, ChatFormatting.DARK_GRAY)); toolTip.add(shiftScrollsFaster.plainCopy() diff --git a/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java index 47d66034c4..798bfaebce 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java @@ -43,7 +43,8 @@ public class SelectionScrollInput extends ScrollInput { if (this.min + 1 == min) min--; if (min > this.min) - toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY)); + toolTip.add(Components.literal("> ...") + .withStyle(ChatFormatting.GRAY)); if (this.max - 1 == max) max++; for (int i = min; i < max; i++) { @@ -59,8 +60,12 @@ public class SelectionScrollInput extends ScrollInput { .withStyle(ChatFormatting.GRAY)); } if (max < this.max) - toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY)); + toolTip.add(Components.literal("> ...") + .withStyle(ChatFormatting.GRAY)); + if (hint != null) + toolTip.add(hint.plainCopy() + .withStyle(s -> s.withColor(HINT_RGB))); toolTip.add(scrollToSelect.plainCopy() .withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC)); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/CombustibleItem.java b/src/main/java/com/simibubi/create/foundation/item/CombustibleItem.java similarity index 90% rename from src/main/java/com/simibubi/create/content/curiosities/CombustibleItem.java rename to src/main/java/com/simibubi/create/foundation/item/CombustibleItem.java index 0ec2684433..95330e6091 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/CombustibleItem.java +++ b/src/main/java/com/simibubi/create/foundation/item/CombustibleItem.java @@ -1,4 +1,4 @@ -package com.simibubi.create.content.curiosities; +package com.simibubi.create.foundation.item; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/foundation/item/CountedItemStackList.java b/src/main/java/com/simibubi/create/foundation/item/CountedItemStackList.java index 9da37a03d7..5a259b001a 100644 --- a/src/main/java/com/simibubi/create/foundation/item/CountedItemStackList.java +++ b/src/main/java/com/simibubi/create/foundation/item/CountedItemStackList.java @@ -7,9 +7,9 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; -import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; -import net.createmod.catnip.utility.IntAttached; +import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour; +import net.createmod.catnip.utility.IntAttached; import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/com/simibubi/create/foundation/item/CreateItemGroupBase.java b/src/main/java/com/simibubi/create/foundation/item/CreateItemGroupBase.java deleted file mode 100644 index 56f6ae5661..0000000000 --- a/src/main/java/com/simibubi/create/foundation/item/CreateItemGroupBase.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.simibubi.create.foundation.item; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.stream.Collectors; - -import com.simibubi.create.Create; -import com.simibubi.create.content.AllSections; -import com.tterrag.registrate.util.entry.RegistryEntry; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.NonNullList; -import net.minecraft.core.Registry; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.Block; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public abstract class CreateItemGroupBase extends CreativeModeTab { - - public CreateItemGroupBase(String id) { - super(Create.ID + "." + id); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void fillItemList(NonNullList items) { - addItems(items, true); - addBlocks(items); - addItems(items, false); - } - - @OnlyIn(Dist.CLIENT) - public void addBlocks(NonNullList items) { - for (RegistryEntry entry : getBlocks()) { - Block def = entry.get(); - Item item = def.asItem(); - if (item != Items.AIR) - def.fillItemCategory(this, items); - } - } - - @OnlyIn(Dist.CLIENT) - public void addItems(NonNullList items, boolean specialItems) { - ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); - - for (RegistryEntry entry : getItems()) { - Item item = entry.get(); - if (item instanceof BlockItem) - continue; - ItemStack stack = new ItemStack(item); - BakedModel model = itemRenderer.getModel(stack, null, null, 0); - if (model.isGui3d() != specialItems) - continue; - item.fillItemCategory(this, items); - } - } - - protected Collection> getBlocks() { - return getSections().stream() - .flatMap(s -> Create.registrate() - .getAll(s, Registry.BLOCK_REGISTRY) - .stream()) - .collect(Collectors.toList()); - } - - protected Collection> getItems() { - return getSections().stream() - .flatMap(s -> Create.registrate() - .getAll(s, Registry.ITEM_REGISTRY) - .stream()) - .collect(Collectors.toList()); - } - - protected EnumSet getSections() { - return EnumSet.allOf(AllSections.class); - } -} diff --git a/src/main/java/com/simibubi/create/foundation/item/CustomArmPoseItem.java b/src/main/java/com/simibubi/create/foundation/item/CustomArmPoseItem.java new file mode 100644 index 0000000000..fbf092e4e2 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/item/CustomArmPoseItem.java @@ -0,0 +1,13 @@ +package com.simibubi.create.foundation.item; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.model.HumanoidModel.ArmPose; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; + +public interface CustomArmPoseItem { + @Nullable + ArmPose getArmPose(ItemStack stack, AbstractClientPlayer player, InteractionHand hand); +} diff --git a/src/main/java/com/simibubi/create/foundation/item/CustomRenderedArmorItem.java b/src/main/java/com/simibubi/create/foundation/item/CustomRenderedArmorItem.java new file mode 100644 index 0000000000..3f8744044c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/item/CustomRenderedArmorItem.java @@ -0,0 +1,17 @@ +package com.simibubi.create.foundation.item; + +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface CustomRenderedArmorItem { + @OnlyIn(Dist.CLIENT) + void renderArmorPiece(HumanoidArmorLayer layer, PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light, HumanoidModel originalModel, ItemStack stack); +} diff --git a/src/main/java/com/simibubi/create/foundation/item/IItemHandlerModifiableIntermediate.java b/src/main/java/com/simibubi/create/foundation/item/IItemHandlerModifiableIntermediate.java deleted file mode 100644 index 8b5545a486..0000000000 --- a/src/main/java/com/simibubi/create/foundation/item/IItemHandlerModifiableIntermediate.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.simibubi.create.foundation.item; - -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.IItemHandlerModifiable; - -interface IItemHandlerModifiableIntermediate extends IItemHandlerModifiable { - - @Override - public default ItemStack getStackInSlot(int slot) { - return getStackInSlotIntermediate(slot); - } - - public ItemStack getStackInSlotIntermediate(int slot); - -} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java b/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java index 804ec00381..2de8299a3b 100644 --- a/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java +++ b/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java @@ -1,290 +1,254 @@ package com.simibubi.create.foundation.item; -import static net.createmod.catnip.utility.FontHelper.cutStringTextComponent; -import static net.createmod.catnip.utility.FontHelper.cutTextComponent; -import static net.minecraft.ChatFormatting.AQUA; -import static net.minecraft.ChatFormatting.BLUE; import static net.minecraft.ChatFormatting.DARK_GRAY; -import static net.minecraft.ChatFormatting.DARK_GREEN; -import static net.minecraft.ChatFormatting.DARK_PURPLE; -import static net.minecraft.ChatFormatting.DARK_RED; -import static net.minecraft.ChatFormatting.GOLD; import static net.minecraft.ChatFormatting.GRAY; -import static net.minecraft.ChatFormatting.GREEN; -import static net.minecraft.ChatFormatting.LIGHT_PURPLE; -import static net.minecraft.ChatFormatting.RED; -import static net.minecraft.ChatFormatting.STRIKETHROUGH; import static net.minecraft.ChatFormatting.WHITE; -import static net.minecraft.ChatFormatting.YELLOW; import java.util.ArrayList; import java.util.Arrays; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; +import java.util.function.Supplier; -import com.simibubi.create.content.contraptions.base.IRotate; -import com.simibubi.create.content.contraptions.base.IRotate.StressImpact; -import com.simibubi.create.content.contraptions.goggles.GogglesItem; -import com.simibubi.create.foundation.block.BlockStressValues; -import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.config.CKinetics; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +import com.mojang.bridge.game.Language; import com.simibubi.create.foundation.utility.CreateLang; -import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.FontHelper; import net.createmod.catnip.utility.lang.Components; -import net.createmod.catnip.utility.lang.Lang; -import net.createmod.catnip.utility.lang.LangBuilder; -import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.level.block.Block; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.ItemLike; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; -public class ItemDescription { +public record ItemDescription(ImmutableList lines, ImmutableList linesOnShift, ImmutableList linesOnCtrl) { + private static final Map> CUSTOM_TOOLTIP_KEYS = new IdentityHashMap<>(); - public static final ItemDescription MISSING = new ItemDescription(null); - public static Component trim = Components.literal(" ").withStyle(WHITE, STRIKETHROUGH); + @Nullable + public static ItemDescription create(Item item, FontHelper.Palette palette) { + return create(getTooltipTranslationKey(item), palette); + } - public enum Palette { - - Blue(BLUE, AQUA), - Green(DARK_GREEN, GREEN), - Yellow(GOLD, YELLOW), - Red(DARK_RED, RED), - Purple(DARK_PURPLE, LIGHT_PURPLE), - Gray(DARK_GRAY, GRAY), - - ; - - private Palette(ChatFormatting primary, ChatFormatting highlight) { - color = primary; - hColor = highlight; + @Nullable + public static ItemDescription create(String translationKey, FontHelper.Palette palette) { + if (!canFillBuilder(translationKey)) { + return null; } - public ChatFormatting color; - public ChatFormatting hColor; + Builder builder = new Builder(palette); + fillBuilder(builder, translationKey); + return builder.build(); } - private List lines; - private List linesOnShift; - private List linesOnCtrl; - private Palette palette; - - public ItemDescription(Palette palette) { - this.palette = palette; - lines = new ArrayList<>(); - linesOnShift = new ArrayList<>(); - linesOnCtrl = new ArrayList<>(); + public static boolean canFillBuilder(String translationKey) { + return I18n.exists(translationKey); } - public ItemDescription withSummary(Component summary) { - addStrings(linesOnShift, cutTextComponent(summary, palette.color, palette.hColor)); - return this; - } - - public static List getKineticStats(Block block) { - List list = new ArrayList<>(); - - CKinetics config = AllConfigs.SERVER.kinetics; - LangBuilder rpmUnit = CreateLang.translate("generic.unit.rpm"); - LangBuilder suUnit = CreateLang.translate("generic.unit.stress"); - - boolean hasGoggles = GogglesItem.isWearingGoggles(Minecraft.getInstance().player); - - boolean showStressImpact; - if (!(block instanceof IRotate)) { - showStressImpact = true; - } else { - showStressImpact = !((IRotate) block).hideStressImpact(); + public static void fillBuilder(Builder builder, String translationKey) { + // Summary + String summaryKey = translationKey + ".summary"; + if (I18n.exists(summaryKey)) { + builder.addSummary(I18n.get(summaryKey)); } - boolean hasStressImpact = - StressImpact.isEnabled() && showStressImpact && BlockStressValues.getImpact(block) > 0; - boolean hasStressCapacity = StressImpact.isEnabled() && BlockStressValues.hasCapacity(block); - - if (hasStressImpact) { - CreateLang.translate("tooltip.stressImpact") - .style(GRAY) - .addTo(list); - - double impact = BlockStressValues.getImpact(block); - StressImpact impactId = impact >= config.highStressImpact.get() ? StressImpact.HIGH - : (impact >= config.mediumStressImpact.get() ? StressImpact.MEDIUM : StressImpact.LOW); - LangBuilder builder = CreateLang.builder() - .add(CreateLang.text(makeProgressBar(3, impactId.ordinal() + 1)) - .style(impactId.getAbsoluteColor())); - - if (hasGoggles) { - builder.add(CreateLang.number(impact)) - .text("x ") - .add(rpmUnit) - .addTo(list); - } else - builder.translate("tooltip.stressImpact." + Lang.asId(impactId.name())) - .addTo(list); + // Behaviours + for (int i = 1; i < 100; i++) { + String conditionKey = translationKey + ".condition" + i; + String behaviourKey = translationKey + ".behaviour" + i; + if (!I18n.exists(conditionKey)) + break; + builder.addBehaviour(I18n.get(conditionKey), I18n.get(behaviourKey)); } - if (hasStressCapacity) { - CreateLang.translate("tooltip.capacityProvided") - .style(GRAY) - .addTo(list); - - double capacity = BlockStressValues.getCapacity(block); - BlockStressValues.IStressValueProvider stressProvider = BlockStressValues.getProvider(block); - Couple generatedRPM = stressProvider != null ? - stressProvider.getGeneratedRPM(block) - : null; - - StressImpact impactId = capacity >= config.highCapacity.get() ? StressImpact.HIGH - : (capacity >= config.mediumCapacity.get() ? StressImpact.MEDIUM : StressImpact.LOW); - StressImpact opposite = StressImpact.values()[StressImpact.values().length - 2 - impactId.ordinal()]; - LangBuilder builder = CreateLang.builder() - .add(CreateLang.text(makeProgressBar(3, impactId.ordinal() + 1)) - .style(opposite.getAbsoluteColor())); - - if (hasGoggles) { - builder.add(CreateLang.number(capacity)) - .text("x ") - .add(rpmUnit) - .addTo(list); - - if (generatedRPM != null) { - LangBuilder amount = CreateLang.number(capacity * generatedRPM.getSecond()) - .add(suUnit); - CreateLang.text(" -> ") - .add(!generatedRPM.getFirst() - .equals(generatedRPM.getSecond()) ? CreateLang.translate("tooltip.up_to", amount) : amount) - .style(DARK_GRAY) - .addTo(list); - } - } else - builder.translate("tooltip.capacityProvided." + Lang.asId(impactId.name())) - .addTo(list); + // Actions + for (int i = 1; i < 100; i++) { + String controlKey = translationKey + ".control" + i; + String actionKey = translationKey + ".action" + i; + if (!I18n.exists(controlKey)) + break; + builder.addAction(I18n.get(controlKey), I18n.get(actionKey)); } - - return list; } - public static String makeProgressBar(int length, int filledLength) { - String bar = " "; - int emptySpaces = length - filledLength; - for (int i = 0; i < filledLength; i++) - bar += "\u2588"; - for (int i = 0; i < emptySpaces; i++) - bar += "\u2592"; - return bar + " "; + public static void useKey(Item item, Supplier supplier) { + CUSTOM_TOOLTIP_KEYS.put(item, supplier); } - public ItemDescription withBehaviour(String condition, String behaviour) { - add(linesOnShift, Components.literal(condition).withStyle(GRAY)); - addStrings(linesOnShift, cutStringTextComponent(behaviour, palette.color, palette.hColor, 1)); - return this; + public static void useKey(ItemLike item, String string) { + useKey(item.asItem(), () -> string); } - public ItemDescription withControl(String condition, String action) { - add(linesOnCtrl, Components.literal(condition).withStyle(GRAY)); - addStrings(linesOnCtrl, cutStringTextComponent(action, palette.color, palette.hColor, 1)); - return this; + public static void referKey(ItemLike item, Supplier otherItem) { + useKey(item.asItem(), () -> otherItem.get() + .asItem() + .getDescriptionId()); } - public ItemDescription createTabs() { - boolean hasDescription = !linesOnShift.isEmpty(); - boolean hasControls = !linesOnCtrl.isEmpty(); - - if (hasDescription || hasControls) { - String[] holdDesc = CreateLang.translateDirect("tooltip.holdForDescription", "$") - .getString() - .split("\\$"); - String[] holdCtrl = CreateLang.translateDirect("tooltip.holdForControls", "$") - .getString() - .split("\\$"); - MutableComponent keyShift = CreateLang.translateDirect("tooltip.keyShift"); - MutableComponent keyCtrl = CreateLang.translateDirect("tooltip.keyCtrl"); - for (List list : Arrays.asList(lines, linesOnShift, linesOnCtrl)) { - boolean shift = list == linesOnShift; - boolean ctrl = list == linesOnCtrl; - - if (holdDesc.length != 2 || holdCtrl.length != 2) { - list.add(0, Components.literal("Invalid lang formatting!")); - continue; - } - - if (hasControls) { - MutableComponent tabBuilder = Components.empty(); - tabBuilder.append(Components.literal(holdCtrl[0]).withStyle(DARK_GRAY)); - tabBuilder.append(keyCtrl.plainCopy() - .withStyle(ctrl ? WHITE : GRAY)); - tabBuilder.append(Components.literal(holdCtrl[1]).withStyle(DARK_GRAY)); - list.add(0, tabBuilder); - } - - if (hasDescription) { - MutableComponent tabBuilder = Components.empty(); - tabBuilder.append(Components.literal(holdDesc[0]).withStyle(DARK_GRAY)); - tabBuilder.append(keyShift.plainCopy() - .withStyle(shift ? WHITE : GRAY)); - tabBuilder.append(Components.literal(holdDesc[1]).withStyle(DARK_GRAY)); - list.add(0, tabBuilder); - } - - if (shift || ctrl) - list.add(hasDescription && hasControls ? 2 : 1, Components.immutableEmpty()); - } + public static String getTooltipTranslationKey(Item item) { + if (CUSTOM_TOOLTIP_KEYS.containsKey(item)) { + return CUSTOM_TOOLTIP_KEYS.get(item).get() + ".tooltip"; } - - if (!hasDescription) - linesOnShift = lines; - if (!hasControls) - linesOnCtrl = lines; - - return this; + return item.getDescriptionId() + ".tooltip"; } - public static String hightlight(String s, Palette palette) { - return palette.hColor + s + palette.color; - } - - public static void addStrings(List infoList, List textLines) { - textLines.forEach(s -> add(infoList, s)); - } - - public static void add(List infoList, List textLines) { - infoList.addAll(textLines); - } - - public static void add(List infoList, Component line) { - infoList.add(line); - } - - public Palette getPalette() { - return palette; - } - - public List addInformation(List tooltip) { + public ImmutableList getCurrentLines() { if (Screen.hasShiftDown()) { - tooltip.addAll(linesOnShift); - return tooltip; + return linesOnShift; + } else if (Screen.hasControlDown()) { + return linesOnCtrl; + } else { + return lines; + } + } + + public static class Builder { + protected final FontHelper.Palette palette; + protected final List summary = new ArrayList<>(); + protected final List> behaviours = new ArrayList<>(); + protected final List> actions = new ArrayList<>(); + + public Builder(FontHelper.Palette palette) { + this.palette = palette; } - if (Screen.hasControlDown()) { - tooltip.addAll(linesOnCtrl); - return tooltip; + public Builder addSummary(String summaryLine) { + summary.add(summaryLine); + return this; } - tooltip.addAll(lines); - return tooltip; + public Builder addBehaviour(String condition, String behaviour) { + behaviours.add(Pair.of(condition, behaviour)); + return this; + } + + public Builder addAction(String condition, String action) { + actions.add(Pair.of(condition, action)); + return this; + } + + public ItemDescription build() { + List lines = new ArrayList<>(); + List linesOnShift = new ArrayList<>(); + List linesOnCtrl = new ArrayList<>(); + + for (String summaryLine : summary) { + linesOnShift.addAll(TooltipHelper.cutStringTextComponent(summaryLine, palette)); + } + + if (!behaviours.isEmpty()) { + linesOnShift.add(Components.immutableEmpty()); + } + + for (Pair behaviourPair : behaviours) { + String condition = behaviourPair.getLeft(); + String behaviour = behaviourPair.getRight(); + linesOnShift.add(Components.literal(condition).withStyle(GRAY)); + linesOnShift.addAll(TooltipHelper.cutStringTextComponent(behaviour, palette.primary(), palette.highlight(), 1)); + } + + for (Pair actionPair : actions) { + String condition = actionPair.getLeft(); + String action = actionPair.getRight(); + linesOnCtrl.add(Components.literal(condition).withStyle(GRAY)); + linesOnCtrl.addAll(TooltipHelper.cutStringTextComponent(action, palette.primary(), palette.highlight(), 1)); + } + + boolean hasDescription = !linesOnShift.isEmpty(); + boolean hasControls = !linesOnCtrl.isEmpty(); + + if (hasDescription || hasControls) { + String[] holdDesc = CreateLang.translateDirect("tooltip.holdForDescription", "$") + .getString() + .split("\\$"); + String[] holdCtrl = CreateLang.translateDirect("tooltip.holdForControls", "$") + .getString() + .split("\\$"); + MutableComponent keyShift = CreateLang.translateDirect("tooltip.keyShift"); + MutableComponent keyCtrl = CreateLang.translateDirect("tooltip.keyCtrl"); + for (List list : Arrays.asList(lines, linesOnShift, linesOnCtrl)) { + boolean shift = list == linesOnShift; + boolean ctrl = list == linesOnCtrl; + + if (holdDesc.length != 2 || holdCtrl.length != 2) { + list.add(0, Components.literal("Invalid lang formatting!")); + continue; + } + + if (hasControls) { + MutableComponent tabBuilder = Components.empty(); + tabBuilder.append(Components.literal(holdCtrl[0]).withStyle(DARK_GRAY)); + tabBuilder.append(keyCtrl.plainCopy() + .withStyle(ctrl ? WHITE : GRAY)); + tabBuilder.append(Components.literal(holdCtrl[1]).withStyle(DARK_GRAY)); + list.add(0, tabBuilder); + } + + if (hasDescription) { + MutableComponent tabBuilder = Components.empty(); + tabBuilder.append(Components.literal(holdDesc[0]).withStyle(DARK_GRAY)); + tabBuilder.append(keyShift.plainCopy() + .withStyle(shift ? WHITE : GRAY)); + tabBuilder.append(Components.literal(holdDesc[1]).withStyle(DARK_GRAY)); + list.add(0, tabBuilder); + } + + if (shift || ctrl) + list.add(hasDescription && hasControls ? 2 : 1, Components.immutableEmpty()); + } + } + + if (!hasDescription) { + linesOnCtrl.clear(); + linesOnShift.addAll(lines); + } + if (!hasControls) { + linesOnCtrl.clear(); + linesOnCtrl.addAll(lines); + } + + return new ItemDescription(ImmutableList.copyOf(lines), ImmutableList.copyOf(linesOnShift), ImmutableList.copyOf(linesOnCtrl)); + } } - public List getLines() { - return lines; - } + public static class Modifier implements TooltipModifier { + protected final Item item; + protected final FontHelper.Palette palette; + protected Language cachedLanguage; + protected ItemDescription description; - public List getLinesOnCtrl() { - return linesOnCtrl; - } + public Modifier(Item item, FontHelper.Palette palette) { + this.item = item; + this.palette = palette; + } - public List getLinesOnShift() { - return linesOnShift; - } + @Override + public void modify(ItemTooltipEvent context) { + if (checkLocale()) { + description = create(item, palette); + } + if (description == null) { + return; + } + context.getToolTip().addAll(1, description.getCurrentLines()); + } + protected boolean checkLocale() { + Language currentLanguage = Minecraft.getInstance() + .getLanguageManager() + .getSelected(); + if (cachedLanguage != currentLanguage) { + cachedLanguage = currentLanguage; + return true; + } + return false; + } + } } diff --git a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java index aab5514a9b..b2a2ae5e4b 100644 --- a/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java +++ b/src/main/java/com/simibubi/create/foundation/item/ItemHelper.java @@ -9,8 +9,6 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableInt; -import com.simibubi.create.foundation.config.AllConfigs; - import net.createmod.catnip.utility.Pair; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; @@ -148,8 +146,7 @@ public class ItemHelper { } public static ItemStack extract(IItemHandler inv, Predicate test, boolean simulate) { - return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.defaultExtractionLimit.get(), - simulate); + return extract(inv, test, ExtractionCountMode.UPTO, 64, simulate); } public static ItemStack extract(IItemHandler inv, Predicate test, int exactAmount, boolean simulate) { @@ -224,7 +221,7 @@ public class ItemHelper { public static ItemStack extract(IItemHandler inv, Predicate test, Function amountFunction, boolean simulate) { ItemStack extracting = ItemStack.EMPTY; - int maxExtractionCount = AllConfigs.SERVER.logistics.defaultExtractionLimit.get(); + int maxExtractionCount = 64; for (int slot = 0; slot < inv.getSlots(); slot++) { if (extracting.isEmpty()) { diff --git a/src/main/java/com/simibubi/create/foundation/item/KineticStats.java b/src/main/java/com/simibubi/create/foundation/item/KineticStats.java new file mode 100644 index 0000000000..b72496c705 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/item/KineticStats.java @@ -0,0 +1,143 @@ +package com.simibubi.create.foundation.item; + +import static net.minecraft.ChatFormatting.DARK_GRAY; +import static net.minecraft.ChatFormatting.GRAY; + +import java.util.ArrayList; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.equipment.goggles.GogglesItem; +import com.simibubi.create.content.kinetics.BlockStressValues; +import com.simibubi.create.content.kinetics.base.IRotate; +import com.simibubi.create.content.kinetics.base.IRotate.StressImpact; +import com.simibubi.create.content.kinetics.crank.ValveHandleBlock; +import com.simibubi.create.content.kinetics.steamEngine.SteamEngineBlock; +import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; +import com.simibubi.create.infrastructure.config.CKinetics; + +import net.createmod.catnip.utility.Couple; +import net.createmod.catnip.utility.lang.Components; +import net.createmod.catnip.utility.lang.Lang; +import net.createmod.catnip.utility.lang.LangBuilder; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; + +public class KineticStats implements TooltipModifier { + protected final Block block; + + public KineticStats(Block block) { + this.block = block; + } + + @Nullable + public static KineticStats create(Item item) { + if (item instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); + if (block instanceof IRotate || block instanceof SteamEngineBlock) { + return new KineticStats(block); + } + } + return null; + } + + @Override + public void modify(ItemTooltipEvent context) { + List kineticStats = getKineticStats(block, context.getPlayer()); + if (!kineticStats.isEmpty()) { + List tooltip = context.getToolTip(); + tooltip.add(Components.immutableEmpty()); + tooltip.addAll(kineticStats); + } + } + + public static List getKineticStats(Block block, Player player) { + List list = new ArrayList<>(); + + CKinetics config = AllConfigs.server().kinetics; + LangBuilder rpmUnit = CreateLang.translate("generic.unit.rpm"); + LangBuilder suUnit = CreateLang.translate("generic.unit.stress"); + + boolean hasGoggles = GogglesItem.isWearingGoggles(player); + + boolean showStressImpact; + if (block instanceof IRotate) { + showStressImpact = !((IRotate) block).hideStressImpact(); + } else { + showStressImpact = true; + } + + if (block instanceof ValveHandleBlock) + block = AllBlocks.COPPER_VALVE_HANDLE.get(); + + boolean hasStressImpact = + StressImpact.isEnabled() && showStressImpact && BlockStressValues.getImpact(block) > 0; + boolean hasStressCapacity = StressImpact.isEnabled() && BlockStressValues.hasCapacity(block); + + if (hasStressImpact) { + CreateLang.translate("tooltip.stressImpact") + .style(GRAY) + .addTo(list); + + double impact = BlockStressValues.getImpact(block); + StressImpact impactId = impact >= config.highStressImpact.get() ? StressImpact.HIGH + : (impact >= config.mediumStressImpact.get() ? StressImpact.MEDIUM : StressImpact.LOW); + LangBuilder builder = CreateLang.builder() + .add(CreateLang.text(TooltipHelper.makeProgressBar(3, impactId.ordinal() + 1)) + .style(impactId.getAbsoluteColor())); + + if (hasGoggles) { + builder.add(CreateLang.number(impact)) + .text("x ") + .add(rpmUnit) + .addTo(list); + } else + builder.translate("tooltip.stressImpact." + Lang.asId(impactId.name())) + .addTo(list); + } + + if (hasStressCapacity) { + CreateLang.translate("tooltip.capacityProvided") + .style(GRAY) + .addTo(list); + + double capacity = BlockStressValues.getCapacity(block); + Couple generatedRPM = BlockStressValues.getGeneratedRPM(block); + + StressImpact impactId = capacity >= config.highCapacity.get() ? StressImpact.HIGH + : (capacity >= config.mediumCapacity.get() ? StressImpact.MEDIUM : StressImpact.LOW); + StressImpact opposite = StressImpact.values()[StressImpact.values().length - 2 - impactId.ordinal()]; + LangBuilder builder = CreateLang.builder() + .add(CreateLang.text(TooltipHelper.makeProgressBar(3, impactId.ordinal() + 1)) + .style(opposite.getAbsoluteColor())); + + if (hasGoggles) { + builder.add(CreateLang.number(capacity)) + .text("x ") + .add(rpmUnit) + .addTo(list); + + if (generatedRPM != null) { + LangBuilder amount = CreateLang.number(capacity * generatedRPM.getSecond()) + .add(suUnit); + CreateLang.text(" -> ") + .add(!generatedRPM.getFirst() + .equals(generatedRPM.getSecond()) ? CreateLang.translate("tooltip.up_to", amount) : amount) + .style(DARK_GRAY) + .addTo(list); + } + } else + builder.translate("tooltip.capacityProvided." + Lang.asId(impactId.name())) + .addTo(list); + } + + return list; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/item/LayeredArmorItem.java b/src/main/java/com/simibubi/create/foundation/item/LayeredArmorItem.java new file mode 100644 index 0000000000..487a147d1f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/item/LayeredArmorItem.java @@ -0,0 +1,53 @@ +package com.simibubi.create.foundation.item; + +import java.util.Map; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.foundation.mixin.accessor.HumanoidArmorLayerAccessor; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface LayeredArmorItem extends CustomRenderedArmorItem { + @OnlyIn(Dist.CLIENT) + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + default void renderArmorPiece(HumanoidArmorLayer layer, PoseStack poseStack, + MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot slot, int light, + HumanoidModel originalModel, ItemStack stack) { + if (!(stack.getItem() instanceof ArmorItem item)) { + return; + } + if (item.getSlot() != slot) { + return; + } + + HumanoidArmorLayerAccessor accessor = (HumanoidArmorLayerAccessor) layer; + Map locationCache = HumanoidArmorLayerAccessor.create$getArmorLocationCache(); + boolean glint = stack.hasFoil(); + + HumanoidModel innerModel = accessor.create$getInnerModel(); + layer.getParentModel().copyPropertiesTo((HumanoidModel) innerModel); + accessor.create$callSetPartVisibility(innerModel, slot); + String locationStr2 = getArmorTextureLocation(entity, slot, stack, 2); + ResourceLocation location2 = locationCache.computeIfAbsent(locationStr2, ResourceLocation::new); + accessor.create$callRenderModel(poseStack, bufferSource, light, glint, innerModel, 1.0F, 1.0F, 1.0F, location2); + + HumanoidModel outerModel = accessor.create$getOuterModel(); + layer.getParentModel().copyPropertiesTo((HumanoidModel) outerModel); + accessor.create$callSetPartVisibility(outerModel, slot); + String locationStr1 = getArmorTextureLocation(entity, slot, stack, 1); + ResourceLocation location1 = locationCache.computeIfAbsent(locationStr1, ResourceLocation::new); + accessor.create$callRenderModel(poseStack, bufferSource, light, glint, outerModel, 1.0F, 1.0F, 1.0F, location1); + } + + String getArmorTextureLocation(LivingEntity entity, EquipmentSlot slot, ItemStack stack, int layer); +} diff --git a/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java b/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java index 1fcd6d6973..d9d5a3b44d 100644 --- a/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java +++ b/src/main/java/com/simibubi/create/foundation/item/SmartInventory.java @@ -4,16 +4,17 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; -import com.simibubi.create.foundation.tileEntity.SyncedTileEntity; +import com.simibubi.create.foundation.blockEntity.SyncedBlockEntity; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.wrapper.RecipeWrapper; public class SmartInventory extends RecipeWrapper - implements IItemHandlerModifiableIntermediate, INBTSerializable { + implements IItemHandlerModifiable, INBTSerializable { protected boolean extractionAllowed; protected boolean insertionAllowed; @@ -21,12 +22,12 @@ public class SmartInventory extends RecipeWrapper protected SyncedStackHandler wrapped; protected int stackSize; - public SmartInventory(int slots, SyncedTileEntity te) { - this(slots, te, 64, false); + public SmartInventory(int slots, SyncedBlockEntity be) { + this(slots, be, 64, false); } - public SmartInventory(int slots, SyncedTileEntity te, int stackSize, boolean stackNonStackables) { - super(new SyncedStackHandler(slots, te, stackNonStackables, stackSize)); + public SmartInventory(int slots, SyncedBlockEntity be, int stackSize, boolean stackNonStackables) { + super(new SyncedStackHandler(slots, be, stackNonStackables, stackSize)); this.stackNonStackables = stackNonStackables; insertionAllowed = true; extractionAllowed = true; @@ -100,13 +101,13 @@ public class SmartInventory extends RecipeWrapper } @Override - public void setStackInSlot(int slot, ItemStack stack) { - inv.setStackInSlot(slot, stack); + public ItemStack getStackInSlot(int slot) { + return inv.getStackInSlot(slot); } @Override - public ItemStack getItem(int slot) { - return super.getItem(slot); + public void setStackInSlot(int slot, ItemStack stack) { + inv.setStackInSlot(slot, stack); } public int getStackLimit(int slot, @Nonnull ItemStack stack) { @@ -129,14 +130,14 @@ public class SmartInventory extends RecipeWrapper private static class SyncedStackHandler extends ItemStackHandler { - private SyncedTileEntity te; + private SyncedBlockEntity blockEntity; private boolean stackNonStackables; private int stackSize; private Consumer updateCallback; - public SyncedStackHandler(int slots, SyncedTileEntity te, boolean stackNonStackables, int stackSize) { + public SyncedStackHandler(int slots, SyncedBlockEntity be, boolean stackNonStackables, int stackSize) { super(slots); - this.te = te; + this.blockEntity = be; this.stackNonStackables = stackNonStackables; this.stackSize = stackSize; } @@ -146,7 +147,7 @@ public class SmartInventory extends RecipeWrapper super.onContentsChanged(slot); if (updateCallback != null) updateCallback.accept(slot); - te.notifyUpdate(); + blockEntity.notifyUpdate(); } @Override @@ -160,9 +161,4 @@ public class SmartInventory extends RecipeWrapper } - @Override - public ItemStack getStackInSlotIntermediate(int slot) { - return getItem(slot); - } - } diff --git a/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java b/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java index 5bddecf2e4..270173d94b 100644 --- a/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java +++ b/src/main/java/com/simibubi/create/foundation/item/TooltipHelper.java @@ -2,18 +2,11 @@ package com.simibubi.create.foundation.item; import java.text.BreakIterator; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.function.Supplier; import com.google.common.base.Strings; -import com.mojang.bridge.game.Language; -import com.simibubi.create.content.AllSections; -import com.simibubi.create.content.contraptions.goggles.GogglesItem; -import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; -import com.simibubi.create.foundation.item.ItemDescription.Palette; +import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; import com.simibubi.create.foundation.utility.CreateLang; import net.createmod.catnip.utility.Couple; @@ -22,23 +15,16 @@ import net.createmod.catnip.utility.lang.Components; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; -import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ItemLike; +import net.minecraft.network.chat.Style; import net.minecraftforge.client.MinecraftForgeClient; public class TooltipHelper { - public static final Map cachedTooltips = new HashMap<>(); - public static Language cachedLanguage; - private static boolean gogglesMode; - private static final Map> tooltipReferrals = new HashMap<>(); + public static final int MAX_WIDTH_PER_LINE = 200; - public static MutableComponent holdShift(Palette color, boolean highlighted) { + public static MutableComponent holdShift(FontHelper.Palette palette, boolean highlighted) { return CreateLang.translateDirect("tooltip.holdForDescription", CreateLang.translateDirect("tooltip.keyShift") .withStyle(ChatFormatting.GRAY)) .withStyle(ChatFormatting.DARK_GRAY); @@ -50,87 +36,64 @@ public class TooltipHelper { .append(CreateLang.translateDirect(hintKey + ".title")) .withStyle(ChatFormatting.GOLD)); Component hint = CreateLang.translateDirect(hintKey); - List cutComponent = FontHelper.cutTextComponent(hint, ChatFormatting.GRAY, ChatFormatting.WHITE); + List cutComponent = cutTextComponent(hint, FontHelper.Palette.GRAY_AND_WHITE); for (Component component : cutComponent) tooltip.add(spacing.plainCopy() .append(component)); } - public static void referTo(ItemLike item, Supplier itemWithTooltip) { - tooltipReferrals.put(item.asItem(), () -> itemWithTooltip.get() - .asItem() - .getDescriptionId()); + public static String makeProgressBar(int length, int filledLength) { + String bar = " "; + int emptySpaces = length - filledLength; + for (int i = 0; i < filledLength; i++) + bar += "\u2588"; + for (int i = 0; i < emptySpaces; i++) + bar += "\u2592"; + return bar + " "; } - public static void referTo(ItemLike item, String string) { - tooltipReferrals.put(item.asItem(), () -> string); + public static Style styleFromColor(ChatFormatting color) { + return Style.EMPTY.applyFormat(color); } - @Deprecated - public static List cutString(Component s, ChatFormatting defaultColor, ChatFormatting highlightColor) { - return cutString(s.getString(), defaultColor, highlightColor, 0); + public static Style styleFromColor(int hex) { + return Style.EMPTY.withColor(hex); } - @Deprecated - public static List cutString(String s, ChatFormatting defaultColor, ChatFormatting highlightColor, - int indent) { - // Apply markup - String markedUp = s.replaceAll("_([^_]+)_", highlightColor + "$1" + defaultColor); - - // Split words - List words = new LinkedList<>(); - BreakIterator iterator = BreakIterator.getLineInstance(MinecraftForgeClient.getLocale()); - iterator.setText(markedUp); - int start = iterator.first(); - for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { - String word = markedUp.substring(start, end); - words.add(word); - } - - Font font = Minecraft.getInstance().font; - List lines = FontHelper.cutString(font, markedUp, FontHelper.maxWidthPerLine); - - // Format - String lineStart = Strings.repeat(" ", indent); - List formattedLines = new ArrayList<>(lines.size()); - String format = defaultColor.toString(); - for (String line : lines) { - String formattedLine = format + lineStart + line; - formattedLines.add(formattedLine); -// format = TextFormatting.getFormatString(formattedLine); - } - return formattedLines; + public static List cutStringTextComponent(String s, FontHelper.Palette palette) { + return cutTextComponent(Components.literal(s), palette); } - public static List cutStringTextComponent(String c, ChatFormatting defaultColor, - ChatFormatting highlightColor) { - return cutTextComponent(Components.literal(c), defaultColor, highlightColor, 0); + public static List cutTextComponent(Component c, FontHelper.Palette palette) { + return cutTextComponent(c, palette.primary(), palette.highlight()); } - public static List cutTextComponent(Component c, ChatFormatting defaultColor, - ChatFormatting highlightColor) { - return cutTextComponent(c, defaultColor, highlightColor, 0); + public static List cutStringTextComponent(String s, Style primaryStyle, + Style highlightStyle) { + return cutTextComponent(Components.literal(s), primaryStyle, highlightStyle); } - public static List cutStringTextComponent(String c, ChatFormatting defaultColor, - ChatFormatting highlightColor, int indent) { - return cutTextComponent(Components.literal(c), defaultColor, highlightColor, indent); + public static List cutTextComponent(Component c, Style primaryStyle, + Style highlightStyle) { + return cutTextComponent(c, primaryStyle, highlightStyle, 0); } - public static List cutTextComponent(Component c, ChatFormatting defaultColor, - ChatFormatting highlightColor, int indent) { + public static List cutStringTextComponent(String c, Style primaryStyle, + Style highlightStyle, int indent) { + return cutTextComponent(Components.literal(c), primaryStyle, highlightStyle, indent); + } + + public static List cutTextComponent(Component c, Style primaryStyle, + Style highlightStyle, int indent) { String s = c.getString(); - // Apply markup - String markedUp = s;// .replaceAll("_([^_]+)_", highlightColor + "$1" + defaultColor); - // Split words List words = new LinkedList<>(); BreakIterator iterator = BreakIterator.getLineInstance(MinecraftForgeClient.getLocale()); - iterator.setText(markedUp); + iterator.setText(s); int start = iterator.first(); for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next()) { - String word = markedUp.substring(start, end); + String word = s.substring(start, end); words.add(word); } @@ -141,7 +104,7 @@ public class TooltipHelper { int width = 0; for (String word : words) { int newWidth = font.width(word.replaceAll("_", "")); - if (width + newWidth > FontHelper.maxWidthPerLine) { + if (width + newWidth > MAX_WIDTH_PER_LINE) { if (width > 0) { String line = currentLine.toString(); lines.add(line); @@ -161,16 +124,16 @@ public class TooltipHelper { // Format MutableComponent lineStart = Components.literal(Strings.repeat(" ", indent)); - lineStart.withStyle(defaultColor); + lineStart.withStyle(primaryStyle); List formattedLines = new ArrayList<>(lines.size()); - Couple f = Couple.create(highlightColor, defaultColor); + Couple